Line data Source code
1 : /*
2 : Copyright 2018-2024, Barcelona Supercomputing Center (BSC), Spain
3 : Copyright 2015-2024, Johannes Gutenberg Universitaet Mainz, Germany
4 :
5 : This software was partially supported by the
6 : EC H2020 funded project NEXTGenIO (Project ID: 671951, www.nextgenio.eu).
7 :
8 : This software was partially supported by the
9 : ADA-FS project under the SPPEXA project funded by the DFG.
10 :
11 : This file is part of GekkoFS.
12 :
13 : GekkoFS is free software: you can redistribute it and/or modify
14 : it under the terms of the GNU General Public License as published by
15 : the Free Software Foundation, either version 3 of the License, or
16 : (at your option) any later version.
17 :
18 : GekkoFS is distributed in the hope that it will be useful,
19 : but WITHOUT ANY WARRANTY; without even the implied warranty of
20 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 : GNU General Public License for more details.
22 :
23 : You should have received a copy of the GNU General Public License
24 : along with GekkoFS. If not, see <https://www.gnu.org/licenses/>.
25 :
26 : SPDX-License-Identifier: GPL-3.0-or-later
27 : */
28 :
29 : /* C++ includes */
30 : #include <CLI/CLI.hpp>
31 : #include <nlohmann/json.hpp>
32 : #include <memory>
33 : #include <fmt/format.h>
34 : #include <commands.hpp>
35 : #include <reflection.hpp>
36 : #include <serialize.hpp>
37 : #include <binary_buffer.hpp>
38 : #include <random>
39 : #include <climits>
40 :
41 : /* C includes */
42 : #include <sys/types.h>
43 : #include <fcntl.h>
44 : #include <unistd.h>
45 :
46 : #ifndef CHAR_BIT
47 : #define CHAR_BIT 8
48 : #endif
49 : constexpr int seed = 42;
50 :
51 : using json = nlohmann::json;
52 :
53 536 : struct write_random_options {
54 : bool verbose{};
55 : std::string pathname{};
56 : ::size_t count{};
57 :
58 : REFL_DECL_STRUCT(write_random_options, REFL_DECL_MEMBER(bool, verbose),
59 : REFL_DECL_MEMBER(std::string, pathname),
60 : REFL_DECL_MEMBER(::size_t, count));
61 : };
62 :
63 : struct write_random_output {
64 : ::ssize_t retval;
65 : int errnum;
66 :
67 : REFL_DECL_STRUCT(write_random_output, REFL_DECL_MEMBER(::size_t, retval),
68 : REFL_DECL_MEMBER(int, errnum));
69 : };
70 :
71 : void
72 4 : to_json(json& record, const write_random_output& out) {
73 4 : record = serialize(out);
74 4 : }
75 :
76 : /**
77 : * Writes `count` random bytes to file
78 : * @param opts
79 : */
80 : void
81 4 : write_random_exec(const write_random_options& opts) {
82 :
83 4 : auto fd = ::open(opts.pathname.c_str(), O_WRONLY);
84 :
85 4 : if(fd == -1) {
86 0 : if(opts.verbose) {
87 0 : fmt::print("open(pathname=\"{}\", count={}) = {}, errno: {} [{}]\n",
88 0 : opts.pathname, opts.count, fd, errno, ::strerror(errno));
89 0 : return;
90 : }
91 :
92 0 : json out = write_random_output{fd, errno};
93 0 : fmt::print("{}\n", out.dump(2));
94 0 : return;
95 : }
96 : // random number generator with seed
97 4 : std::independent_bits_engine<std::default_random_engine, CHAR_BIT,
98 : unsigned char>
99 4 : engine{seed};
100 : // create buffer for opts.count
101 8 : std::vector<uint8_t> data(opts.count);
102 4 : std::generate(begin(data), end(data), std::ref(engine));
103 : // pass data to buffer
104 8 : io::buffer buf(data);
105 :
106 4 : int rv = ::write(fd, buf.data(), opts.count);
107 :
108 4 : if(opts.verbose) {
109 0 : fmt::print("write(pathname=\"{}\", count={}) = {}, errno: {} [{}]\n",
110 0 : opts.pathname, opts.count, rv, errno, ::strerror(errno));
111 0 : return;
112 : }
113 :
114 8 : json out = write_random_output{rv, errno};
115 8 : fmt::print("{}\n", out.dump(2));
116 : }
117 :
118 : void
119 268 : write_random_init(CLI::App& app) {
120 :
121 : // Create the option and subcommand objects
122 268 : auto opts = std::make_shared<write_random_options>();
123 536 : auto* cmd = app.add_subcommand("write_random",
124 536 : "Execute the write() system call ");
125 :
126 : // Add options to cmd, binding them to opts
127 268 : cmd->add_flag("-v,--verbose", opts->verbose,
128 536 : "Produce human writeable output");
129 :
130 536 : cmd->add_option("pathname", opts->pathname, "File name")
131 : ->required()
132 536 : ->type_name("");
133 :
134 536 : cmd->add_option("count", opts->count, "Number of random bytes to write")
135 : ->required()
136 536 : ->type_name("");
137 :
138 1076 : cmd->callback([opts]() { write_random_exec(*opts); });
139 268 : }
|