commit: 6fd30de56d2db6dc6147a48155299b363cb8db8c
Author: Michał Górny <mgorny <AT> gentoo <DOT> org>
AuthorDate: Sat Nov 22 19:58:45 2025 +0000
Commit: Michał Górny <mgorny <AT> gentoo <DOT> org>
CommitDate: Sat Nov 22 20:02:11 2025 +0000
URL: https://gitweb.gentoo.org/proj/steve.git/commit/?id=6fd30de5
Rewrite argument parsing using getopt_long()
Signed-off-by: Michał Górny <mgorny <AT> gentoo.org>
meson.build | 6 ++-
steve.cxx | 128 ++++++++++++++++++++++++++++++------------------------------
2 files changed, 68 insertions(+), 66 deletions(-)
diff --git a/meson.build b/meson.build
index 693c753..d5dad75 100644
--- a/meson.build
+++ b/meson.build
@@ -1,8 +1,12 @@
-project('steve', 'cpp')
+project('steve', 'cpp',
+ version : '0')
+
+version = meson.project_version()
fuse3 = dependency('fuse3')
libevent = dependency('libevent', version: '>= 2')
executable('steve', ['steve.cxx'],
+ cpp_args : [f'-DSTEVE_VERSION="@version@"'],
dependencies: [fuse3, libevent],
install : true)
diff --git a/steve.cxx b/steve.cxx
index b00072e..d666f5c 100644
--- a/steve.cxx
+++ b/steve.cxx
@@ -14,6 +14,7 @@
#include <cstdio>
#include <cstdlib>
#include <cerrno>
+#include <climits>
#include <csignal>
#include <deque>
#include <functional>
@@ -21,6 +22,7 @@
#include <string>
#include <unordered_map>
+#include <getopt.h>
#include <sys/poll.h>
#include <sys/syscall.h>
#include <unistd.h>
@@ -31,16 +33,6 @@
#include <fuse.h>
#include <fuse_opt.h>
-static const char *usage =
-"usage: steve [options]\n"
-"\n"
-"options:\n"
-" --help|-h print this help message\n"
-" --jobs=JOBS|-j JOBS jobs to use (default: nproc)\n"
-" --verbose|-v enable verbose logging\n"
-" -d -o debug enable debug output (implies -f)\n"
-"\n";
-
struct steve_read_waiter {
fuse_req_t req;
uint64_t pid;
@@ -82,45 +74,6 @@ struct steve_state {
struct event_base *evb;
};
-enum steve_arg_keys {
- STEVE_HELP,
- STEVE_VERBOSE,
-};
-
-#define STEVE_OPT(t, p) { t, offsetof(steve_state, p), 1 }
-
-static const struct fuse_opt steve_opts[] = {
- STEVE_OPT("-j %u", jobs),
- STEVE_OPT("--jobs=%u", jobs),
- FUSE_OPT_KEY("-v", STEVE_VERBOSE),
- FUSE_OPT_KEY("--verbose", STEVE_VERBOSE),
- FUSE_OPT_KEY("-h", STEVE_HELP),
- FUSE_OPT_KEY("--help", STEVE_HELP),
- FUSE_OPT_END
-};
-
-static int steve_process_arg(
- void *userdata, const char *arg, int key, struct fuse_args *outargs)
-{
- steve_state *state = static_cast<steve_state *>(userdata);
-
- (void) outargs;
- (void) arg;
-
- switch (key) {
- case STEVE_HELP:
- fprintf(stderr, "%s", usage);
- return fuse_opt_add_arg(outargs, "-ho");
- case STEVE_VERBOSE:
- state->verbose = true;
- break;
- default:
- return 1;
- }
-
- return 0;
-}
-
static void steve_wake_waiters(steve_state *state)
{
while (state->tokens > 0 && !state->read_waiters.empty()) {
@@ -360,10 +313,63 @@ static void steve_handle_cuse(evutil_socket_t, short,
void *userdata) {
fuse_session_process_buf(session, &buf);
}
+static const char *steve_usage =
+"usage: %s [options]\n"
+"\n"
+"options:\n"
+" --help, -h print this help message\n"
+" --version, -V print version\n"
+" --jobs=JOBS, -j JOBS jobs to use (default: nproc)\n"
+" --verbose, -v enable verbose logging\n"
+" --debug, -d enable FUSE debug output\n";
+
+static const struct option steve_opts[] = {
+ { "help", no_argument, 0, 'h' },
+ { "version", no_argument, 0, 'V' },
+ { "jobs", required_argument, 0, 'j' },
+ { "verbose", no_argument, 0, 'v' },
+ { "debug", no_argument, 0, 'd' },
+ { 0 },
+};
+
int main(int argc, char **argv)
{
steve_state state = { 0 };
+ int opt;
+ bool debug = false;
+ while ((opt = getopt_long(argc, argv, "hVj:vd", steve_opts, nullptr))
!= -1) {
+ switch (opt) {
+ case 'h':
+ printf(steve_usage, argv[0]);
+ return 0;
+ case 'V':
+ printf("steve %s\n", STEVE_VERSION);
+ return 0;
+ case 'j':
+ {
+ char *endptr;
+ errno = 0;
+ long jobs_arg = strtol(optarg, &endptr,
10);
+ if (*endptr || errno == ERANGE ||
jobs_arg < 0 || jobs_arg > INT_MAX) {
+ fprintf(stderr, "invalid job
number: %s\n", optarg);
+ return 1;
+ }
+ state.jobs = jobs_arg;
+ }
+ break;
+ case 'v':
+ state.verbose = true;
+ break;
+ case 'd':
+ debug = true;
+ break;
+ default:
+ fprintf(stderr, steve_usage, argv[0]);
+ return 1;
+ }
+ }
+
std::unique_ptr<struct event_base, std::function<void(struct
event_base*)>>
evb{event_base_new(), event_base_free};
if (!evb) {
@@ -372,17 +378,9 @@ int main(int argc, char **argv)
}
state.evb = evb.get();
- struct fuse_args args = FUSE_ARGS_INIT(argc, argv);
- if (fuse_opt_parse(&args, &state, steve_opts, steve_process_arg)) {
- fprintf(stderr, "failed to parse option\n");
- fuse_opt_free_args(&args);
- return 1;
- }
-
int cuse_fd = open("/dev/cuse", O_RDWR);
if (cuse_fd == -1) {
perror("unable to open /dev/cuse");
- fuse_opt_free_args(&args);
return 1;
}
@@ -394,12 +392,18 @@ int main(int argc, char **argv)
if (state.jobs == 0)
state.jobs = sysconf(_SC_NPROCESSORS_ONLN);
+ struct fuse_args args = FUSE_ARGS_INIT(0, nullptr);
+ std::unique_ptr<struct fuse_args, std::function<void(struct
fuse_args*)>>
+ args_ptr{&args, fuse_opt_free_args};
+ fuse_opt_add_arg(args_ptr.get(), argv[0]);
+ if (debug)
+ fuse_opt_add_arg(args_ptr.get(), "-d");
+
std::unique_ptr<struct fuse_session, std::function<void(struct
fuse_session*)>> session{
- cuse_lowlevel_new(&args, &ci, &steve_ops, &state),
fuse_session_destroy};
+ cuse_lowlevel_new(args_ptr.get(), &ci, &steve_ops, &state),
fuse_session_destroy};
if (!session) {
fprintf(stderr, "failed to initialize FUSE");
close(cuse_fd);
- fuse_opt_free_args(&args);
return 1;
}
@@ -408,13 +412,11 @@ int main(int argc, char **argv)
if (!cuse_event) {
fprintf(stderr, "failed to initialize CUSE handler");
close(cuse_fd);
- fuse_opt_free_args(&args);
return 1;
}
if (event_add(cuse_event.get(), nullptr) == -1) {
fprintf(stderr, "failed to enable CUSE handler");
close(cuse_fd);
- fuse_opt_free_args(&args);
return 1;
}
@@ -423,13 +425,11 @@ int main(int argc, char **argv)
if (!sigusr1_event) {
fprintf(stderr, "failed to initialize SIGUSR1 handler");
close(cuse_fd);
- fuse_opt_free_args(&args);
return 1;
}
if (event_add(sigusr1_event.get(), nullptr) == -1) {
fprintf(stderr, "failed to enable SIGUSR1 handler");
close(cuse_fd);
- fuse_opt_free_args(&args);
return 1;
}
@@ -437,13 +437,11 @@ int main(int argc, char **argv)
if (fuse_session_mount(session.get(), mountpoint.c_str()) == -1) {
fprintf(stderr, "failed to mount the filesystem");
close(cuse_fd);
- fuse_opt_free_args(&args);
return 1;
}
event_base_dispatch(evb.get());
fuse_session_unmount(session.get());
close(cuse_fd);
- fuse_opt_free_args(&args);
return 0;
}