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 :
39 : /* C includes */
40 : #include <sys/types.h>
41 : #include <sys/stat.h>
42 : #include <sys/uio.h>
43 : #include <fcntl.h>
44 : #include <unistd.h>
45 :
46 : using json = nlohmann::json;
47 :
48 494 : struct readv_options {
49 : bool verbose{};
50 : std::string pathname;
51 : ::size_t count_0;
52 : ::size_t count_1;
53 :
54 : REFL_DECL_STRUCT(readv_options, REFL_DECL_MEMBER(bool, verbose),
55 : REFL_DECL_MEMBER(std::string, pathname),
56 : REFL_DECL_MEMBER(::size_t, count_0),
57 : REFL_DECL_MEMBER(::size_t, count_1));
58 : };
59 :
60 1 : struct readv_output {
61 : ::ssize_t retval;
62 : io::buffer buf_0;
63 : io::buffer buf_1;
64 : int errnum;
65 :
66 : REFL_DECL_STRUCT(readv_output, REFL_DECL_MEMBER(::size_t, retval),
67 : REFL_DECL_MEMBER(void*, buf_0),
68 : REFL_DECL_MEMBER(void*, buf_1),
69 : REFL_DECL_MEMBER(int, errnum));
70 : };
71 :
72 : void
73 1 : to_json(json& record, const readv_output& out) {
74 1 : record = serialize(out);
75 1 : }
76 :
77 : void
78 1 : readv_exec(const readv_options& opts) {
79 :
80 1 : auto fd = ::open(opts.pathname.c_str(), O_RDONLY);
81 :
82 1 : if(fd == -1) {
83 0 : if(opts.verbose) {
84 0 : fmt::print(
85 : "readv(pathname=\"{}\", count_0={}, count_1={}) = {}, errno: {} [{}]\n",
86 0 : opts.pathname, opts.count_0, opts.count_1, fd, errno,
87 0 : ::strerror(errno));
88 0 : return;
89 : }
90 :
91 0 : json out = readv_output{fd, nullptr, nullptr, errno};
92 0 : fmt::print("{}\n", out.dump(2));
93 :
94 0 : return;
95 : }
96 :
97 2 : io::buffer buf_0(opts.count_0);
98 2 : io::buffer buf_1(opts.count_1);
99 :
100 1 : struct iovec iov[2];
101 :
102 1 : iov[0].iov_base = buf_0.data();
103 1 : iov[1].iov_base = buf_1.data();
104 :
105 1 : iov[0].iov_len = opts.count_0;
106 1 : iov[1].iov_len = opts.count_1;
107 :
108 1 : auto rv = ::readv(fd, iov, 2);
109 :
110 1 : if(opts.verbose) {
111 0 : fmt::print(
112 : "readv(pathname=\"{}\", count_0={}, count_1={}) = {}, errno: {} [{}]\n",
113 0 : opts.pathname, opts.count_0, opts.count_1, rv, errno,
114 0 : ::strerror(errno));
115 0 : return;
116 : }
117 :
118 1 : json out = readv_output{rv, (rv != -1 ? buf_0 : nullptr),
119 3 : (rv != -1 ? buf_1 : nullptr), errno};
120 2 : fmt::print("{}\n", out.dump(2));
121 : }
122 :
123 : void
124 247 : readv_init(CLI::App& app) {
125 :
126 : // Create the option and subcommand objects
127 247 : auto opts = std::make_shared<readv_options>();
128 247 : auto* cmd = app.add_subcommand("readv", "Execute the readv() system call");
129 :
130 : // Add options to cmd, binding them to opts
131 247 : cmd->add_flag("-v,--verbose", opts->verbose,
132 494 : "Produce human readable output");
133 :
134 494 : cmd->add_option("pathname", opts->pathname, "Directory name")
135 : ->required()
136 494 : ->type_name("");
137 :
138 247 : cmd->add_option("count_0", opts->count_0,
139 494 : "Number of bytes to read to buffer 0")
140 : ->required()
141 494 : ->type_name("");
142 :
143 247 : cmd->add_option("count_1", opts->count_1,
144 494 : "Number of bytes to read to buffer 1")
145 : ->required()
146 494 : ->type_name("");
147 :
148 989 : cmd->callback([opts]() { readv_exec(*opts); });
149 247 : }
|