From: Stefano Brivio <sbrivio@redhat.com>
To: David Gibson <david@gibson.dropbear.id.au>
Cc: passt-dev@passt.top
Subject: Re: [PATCH v3 14/25] pesto: Add command line option parsing and debug messages
Date: Wed, 25 Mar 2026 01:55:07 +0100 (CET) [thread overview]
Message-ID: <20260325015506.201d9ca0@elisabeth> (raw)
In-Reply-To: <20260323073732.3158468-15-david@gibson.dropbear.id.au>
On Mon, 23 Mar 2026 18:37:21 +1100
David Gibson <david@gibson.dropbear.id.au> wrote:
> Add basic command line option parsing using getopt_long() to pesto.
> Implement --help, --version, --quiet and --verbose options, along with a
Two questions:
- do we really need --quiet?
- shouldn't we stick to the passt(1) convention where we avoided -v
altogether to avoid confusion, and we just have --version and -d /
--debug?
> debug() macro to print debugging messages when given the verbose option.
>
> Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
> ---
> common.h | 8 ++++++
> conf.c | 45 +++++++++++++++++----------------
> passt.h | 12 ++++-----
> pesto.c | 77 ++++++++++++++++++++++++++++++++++++++++++++++++++------
> util.h | 8 ------
> 5 files changed, 108 insertions(+), 42 deletions(-)
>
> diff --git a/common.h b/common.h
> index 76a95609..927d20a4 100644
> --- a/common.h
> +++ b/common.h
> @@ -8,6 +8,14 @@
> #ifndef COMMON_H
> #define COMMON_H
>
> +#define VERSION_BLOB \
> + VERSION "\n" \
> + "Copyright Red Hat\n" \
> + "GNU General Public License, version 2 or later\n" \
> + " <https://www.gnu.org/licenses/old-licenses/gpl-2.0.html>\n" \
> + "This is free software: you are free to change and redistribute it.\n" \
> + "There is NO WARRANTY, to the extent permitted by law.\n\n"
> +
> /* FPRINTF() intentionally silences cert-err33-c clang-tidy warnings */
> #define FPRINTF(f, ...) (void)fprintf(f, __VA_ARGS__)
>
> diff --git a/conf.c b/conf.c
> index 5e8bc665..7b960fe9 100644
> --- a/conf.c
> +++ b/conf.c
> @@ -1140,6 +1140,9 @@ static void conf_print(const struct ctx *c)
> char bufmac[ETH_ADDRSTRLEN], ifn[IFNAMSIZ];
> int i;
>
> + if (c->fd_control_listen >= 0)
> + info("Configuration socket: %s", c->control_path);
> +
> if (c->ifi4 > 0 || c->ifi6 > 0) {
> info("Template interface: %s%s%s%s%s",
> c->ifi4 > 0 ? if_indextoname(c->ifi4, ifn) : "",
> @@ -1432,15 +1435,15 @@ static void conf_open_files(struct ctx *c)
> die_perror("Couldn't open PID file %s", c->pidfile);
> }
>
> - c->fd_conf = -1;
> - if (*c->conf_path) {
> - c->fd_conf_listen = sock_unix(c->conf_path);
> - if (c->fd_conf_listen < 0) {
> + c->fd_control = -1;
> + if (*c->control_path) {
For later: maybe I guess we should squash the renaming of this file
descriptor with the earlier patch adding it.
> + c->fd_control_listen = sock_unix(c->control_path);
> + if (c->fd_control_listen < 0) {
> die_perror("Couldn't open control socket %s",
> - c->conf_path);
> + c->control_path);
> }
> } else {
> - c->fd_conf_listen = -1;
> + c->fd_control_listen = -1;
> }
> }
>
> @@ -1485,13 +1488,13 @@ static void conf_sock_listen(const struct ctx *c)
> {
> union epoll_ref ref = { .type = EPOLL_TYPE_CONF_LISTEN };
>
> - if (c->fd_conf_listen < 0)
> + if (c->fd_control_listen < 0)
> return;
>
> - if (listen(c->fd_conf_listen, 0))
> + if (listen(c->fd_control_listen, 0))
> die_perror("Couldn't listen on configuration socket");
>
> - ref.fd = c->fd_conf_listen;
> + ref.fd = c->fd_control_listen;
> if (epoll_add(c->epollfd, EPOLLIN | EPOLLET, ref))
> die_perror("Couldn't add configuration socket to epoll");
> }
> @@ -1846,11 +1849,11 @@ void conf(struct ctx *c, int argc, char **argv)
> c->fd_tap = -1;
> break;
> case 'c':
> - ret = snprintf(c->conf_path, sizeof(c->conf_path), "%s",
> - optarg);
> + ret = snprintf(c->control_path, sizeof(c->control_path),
> + "%s", optarg);
> if (ret <= 0 || ret >= (int)sizeof(c->sock_path))
> die("Invalid configuration path: %s", optarg);
> - c->fd_conf_listen = c->fd_conf = -1;
> + c->fd_control_listen = c->fd_control = -1;
> break;
> case 'F':
> errno = 0;
> @@ -2294,10 +2297,10 @@ void conf(struct ctx *c, int argc, char **argv)
> FWD_SCAN);
> }
>
> + conf_sock_listen(c);
> +
> if (!c->quiet)
> conf_print(c);
> -
> - conf_sock_listen(c);
> }
>
> /**
> @@ -2321,7 +2324,7 @@ void conf_listen_handler(struct ctx *c, uint32_t events)
> return;
> }
>
> - fd = accept4(c->fd_conf_listen, NULL, NULL, SOCK_NONBLOCK);
> + fd = accept4(c->fd_control_listen, NULL, NULL, SOCK_NONBLOCK);
> if (fd < 0) {
> warn_perror("accept4() on configuration listening socket");
> return;
> @@ -2331,7 +2334,7 @@ void conf_listen_handler(struct ctx *c, uint32_t events)
> warn_perror("Can't get configuration client credentials");
>
> /* Another client is already connected: accept and close right away. */
> - if (c->fd_conf != -1) {
> + if (c->fd_control != -1) {
> info("Discarding configuration client, PID %i", uc.pid);
> goto fail;
> }
> @@ -2349,7 +2352,7 @@ void conf_listen_handler(struct ctx *c, uint32_t events)
> goto fail;
> }
>
> - c->fd_conf = fd;
> + c->fd_control = fd;
> info("Accepted configuration client, PID %i", uc.pid);
> if (!PESTO_PROTOCOL_VERSION) {
> warn(
> @@ -2374,7 +2377,7 @@ void conf_handler(struct ctx *c, uint32_t events)
> ssize_t n;
>
> do {
> - n = read(c->fd_conf, discard, sizeof(discard));
> + n = read(c->fd_control, discard, sizeof(discard));
> if (n > 0)
> debug("Discarded %zd bytes of config data", n);
> } while (n > 0);
> @@ -2397,7 +2400,7 @@ void conf_handler(struct ctx *c, uint32_t events)
>
> close:
> debug("Closing configuration socket");
> - epoll_ctl(c->epollfd, EPOLL_CTL_DEL, c->fd_conf, NULL);
> - close(c->fd_conf);
> - c->fd_conf = -1;
> + epoll_ctl(c->epollfd, EPOLL_CTL_DEL, c->fd_control, NULL);
> + close(c->fd_control);
> + c->fd_control = -1;
> }
> diff --git a/passt.h b/passt.h
> index c38bb5ae..b3f049de 100644
> --- a/passt.h
> +++ b/passt.h
> @@ -158,7 +158,7 @@ struct ip6_ctx {
> * @foreground: Run in foreground, don't log to stderr by default
> * @nofile: Maximum number of open files (ulimit -n)
> * @sock_path: Path for UNIX domain socket
> - * @conf_path: Path for configuration UNIX domain socket
> + * @control_path: Path for control/configuration UNIX domain socket
> * @repair_path: TCP_REPAIR helper path, can be "none", empty for default
> * @pcap: Path for packet capture file
> * @pidfile: Path to PID file, empty string if not configured
> @@ -170,8 +170,8 @@ struct ip6_ctx {
> * @epollfd: File descriptor for epoll instance
> * @fd_tap_listen: File descriptor for listening AF_UNIX socket, if any
> * @fd_tap: AF_UNIX socket, tuntap device, or pre-opened socket
> - * @fd_conf_listen: Listening configuration socket, if any
> - * @fd_conf: Configuration socket, if any
> + * @fd_control_listen: Listening control/configuration socket, if any
> + * @fd_control: Control/configuration socket, if any
> * @fd_repair_listen: File descriptor for listening TCP_REPAIR socket, if any
> * @fd_repair: Connected AF_UNIX socket for TCP_REPAIR helper
> * @our_tap_mac: Pasta/passt's MAC on the tap link
> @@ -226,7 +226,7 @@ struct ctx {
> int foreground;
> int nofile;
> char sock_path[UNIX_PATH_MAX];
> - char conf_path[UNIX_PATH_MAX];
> + char control_path[UNIX_PATH_MAX];
> char repair_path[UNIX_PATH_MAX];
> char pcap[PATH_MAX];
>
> @@ -244,8 +244,8 @@ struct ctx {
> int epollfd;
> int fd_tap_listen;
> int fd_tap;
> - int fd_conf_listen;
> - int fd_conf;
> + int fd_control_listen;
> + int fd_control;
> int fd_repair_listen;
> int fd_repair;
> unsigned char our_tap_mac[ETH_ALEN];
> diff --git a/pesto.c b/pesto.c
> index 6d066084..f8c9e01d 100644
> --- a/pesto.c
> +++ b/pesto.c
> @@ -15,6 +15,7 @@
> #include <sys/socket.h>
> #include <sys/un.h>
> #include <errno.h>
> +#include <getopt.h>
> #include <inttypes.h>
> #include <stdbool.h>
> #include <stddef.h>
> @@ -42,6 +43,32 @@
> exit(EXIT_FAILURE); \
> } while (0)
>
> +#define debug(...) \
> + do { \
> + if (verbosity > 1) { \
> + FPRINTF(stderr, __VA_ARGS__); \
> + FPRINTF(stderr, "\n"); \
> + } \
> + } while (0)
> +
> +/**
> + * usage() - Print usage, exit with given status code
> + * @name: Executable name
> + * @f: Stream to print usage info to
> + * @status: Status code for exit(2)
> + */
> +static void usage(const char *name, FILE *f, int status)
> +{
> + FPRINTF(f, "Usage: %s [OPTION]... PATH\n", name);
> + FPRINTF(f,
> + "\n"
> + " -v, --verbose Be more verbose\n"
> + " -q, --quiet Be less verbose\n"
> + " -h, --help Display this help message and exit\n"
> + " --version Show version and exit\n");
> + exit(status);
> +}
> +
> /**
> * main() - Entry point and whole program with loop
> * @argc: Argument count
> @@ -56,13 +83,20 @@
> */
> int main(int argc, char **argv)
> {
> + const struct option options[] = {
> + {"quiet", no_argument, NULL, 'q' },
> + {"verbose", no_argument, NULL, 'v' },
> + {"help", no_argument, NULL, 'h' },
> + {"version", no_argument, NULL, 1 },
> + { 0 },
> + };
> struct sockaddr_un a = { AF_UNIX, "" };
> + const char *optstring = "vh";
> struct pesto_hello hello;
> struct sock_fprog prog;
> + int optname, ret, s;
> uint32_t s_version;
> - int ret, s;
> -
> - prctl(PR_SET_DUMPABLE, 0);
I would, at least by default, keep this exactly in line with the
paranoid stuff I added to passt, for consistency and ease of auditing:
what will happen if we run *this* tool as root? If we choose to drop to
nobody in that case, removing this will be a problem. And we'll
probably not remember to add it back.
> + int verbosity = 1;
If we skip --quiet, this can be simplified.
>
> prog.len = (unsigned short)sizeof(filter_pesto) /
> sizeof(filter_pesto[0]);
> @@ -71,15 +105,40 @@ int main(int argc, char **argv)
> prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog))
> die("Failed to apply seccomp filter");
>
> - if (argc < 2)
> - die("Usage: %s CONTROLPATH", argv[0]);
I was suggesting to use PATH instead of CONTROLPATH in the earlier
patch, but this goes away here and we'll probably want to squash this
anyway so it shouldn't matter.
> + do {
> + optname = getopt_long(argc, argv, optstring, options, NULL);
> +
> + switch (optname) {
> + case -1:
> + case 0:
> + break;
> + case 'h':
> + usage(argv[0], stdout, EXIT_SUCCESS);
> + break;
> + case 'q':
> + verbosity--;
> + break;
> + case 'v':
> + verbosity++;
> + break;
> + case 1:
> + FPRINTF(stdout, "pesto ");
> + FPRINTF(stdout, VERSION_BLOB);
> + exit(EXIT_SUCCESS);
> + default:
> + usage(argv[0], stderr, EXIT_FAILURE);
> + }
> + } while (optname != -1);
> +
> + if (argc - optind != 1)
> + usage(argv[0], stderr, EXIT_FAILURE);
>
> if ((s = socket(AF_UNIX, SOCK_STREAM, 0)) < 0)
> die("Failed to create AF_UNIX socket: %s", strerror(errno));
>
> - ret = snprintf(a.sun_path, sizeof(a.sun_path), "%s", argv[1]);
> + ret = snprintf(a.sun_path, sizeof(a.sun_path), "%s", argv[optind]);
> if (ret <= 0 || ret >= (int)sizeof(a.sun_path))
> - die("Invalid socket path \"%s\"", argv[1]);
> + die("Invalid socket path \"%s\"", argv[optind]);
>
> ret = connect(s, (struct sockaddr *)&a, sizeof(a));
> if (ret < 0) {
> @@ -87,6 +146,8 @@ int main(int argc, char **argv)
> a.sun_path, strerror(errno));
> }
>
> + debug("Connected to passt/pasta control socket");
> +
> ret = read_all_buf(s, &hello, sizeof(hello));
> if (ret < 0)
> die("Couldn't read server greeting: %s", strerror(errno));
> @@ -96,6 +157,8 @@ int main(int argc, char **argv)
>
> s_version = ntohl(hello.version);
>
> + debug("Server protocol version: %"PRIu32, s_version);
> +
> if (s_version > PESTO_PROTOCOL_VERSION) {
> die("Unknown server protocol version %"PRIu32" > %"PRIu32"\n",
> s_version, PESTO_PROTOCOL_VERSION);
> diff --git a/util.h b/util.h
> index e7993f4d..d7c397f6 100644
> --- a/util.h
> +++ b/util.h
> @@ -21,14 +21,6 @@
>
> #include "log.h"
>
> -#define VERSION_BLOB \
> - VERSION "\n" \
> - "Copyright Red Hat\n" \
> - "GNU General Public License, version 2 or later\n" \
> - " <https://www.gnu.org/licenses/old-licenses/gpl-2.0.html>\n" \
> - "This is free software: you are free to change and redistribute it.\n" \
> - "There is NO WARRANTY, to the extent permitted by law.\n\n"
> -
> #ifndef SECCOMP_RET_KILL_PROCESS
> #define SECCOMP_RET_KILL_PROCESS SECCOMP_RET_KILL
> #endif
--
Stefano
next prev parent reply other threads:[~2026-03-25 0:55 UTC|newest]
Thread overview: 49+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-03-23 7:37 [PATCH v3 00/25] RFC: Read-only dynamic update implementation David Gibson
2026-03-23 7:37 ` [PATCH v3 01/25] conf: runas can be const David Gibson
2026-03-23 7:37 ` [PATCH v3 02/25] vhost_user: Fix assorted minor cppcheck warnings David Gibson
2026-03-23 7:37 ` [PATCH v3 03/25] serialise: Split functions user for serialisation from util.c David Gibson
2026-03-25 0:54 ` Stefano Brivio
2026-03-25 1:50 ` David Gibson
2026-03-23 7:37 ` [PATCH v3 04/25] serialise: Add helpers for serialising unsigned integers David Gibson
2026-03-23 7:37 ` [PATCH v3 05/25] fwd: Move selecting correct scan bitmap into fwd_sync_one() David Gibson
2026-03-23 7:37 ` [PATCH v3 06/25] fwd: Look up rule index in fwd_sync_one() David Gibson
2026-03-23 7:37 ` [PATCH v3 07/25] fwd: Store forwarding tables indexed by (origin) pif David Gibson
2026-03-25 0:54 ` Stefano Brivio
2026-03-25 4:04 ` David Gibson
2026-03-23 7:37 ` [PATCH v3 08/25] fwd: Allow FWD_DUAL_STACK_ANY flag to be passed directly to fwd_rule_add() David Gibson
2026-03-25 0:54 ` Stefano Brivio
2026-03-25 4:07 ` David Gibson
2026-03-23 7:37 ` [PATCH v3 09/25] fwd, conf: Expose ephemeral ports as bitmap rather than function David Gibson
2026-03-23 7:37 ` [PATCH v3 10/25] conf: Don't bother complaining about overlapping excluded ranges David Gibson
2026-03-23 7:37 ` [PATCH v3 11/25] conf: Move check for mapping port 0 to caller David Gibson
2026-03-23 7:37 ` [PATCH v3 12/25] conf: Move check for disabled interfaces earlier David Gibson
2026-03-23 7:37 ` [PATCH v3 13/25] pesto: Introduce stub configuration interface and tool David Gibson
2026-03-25 0:54 ` Stefano Brivio
2026-03-23 7:37 ` [PATCH v3 14/25] pesto: Add command line option parsing and debug messages David Gibson
2026-03-25 0:55 ` Stefano Brivio [this message]
2026-03-25 4:27 ` David Gibson
2026-03-23 7:37 ` [PATCH v3 15/25] pesto: Expose list of pifs to pesto David Gibson
2026-03-25 0:56 ` Stefano Brivio
2026-03-25 4:34 ` David Gibson
2026-03-25 8:18 ` Stefano Brivio
2026-03-25 8:31 ` David Gibson
2026-03-23 7:37 ` [PATCH v3 16/25] ip: Prepare ip.[ch] for sharing with pesto tool David Gibson
2026-03-23 7:37 ` [PATCH v3 17/25] inany: Prepare inany.[ch] " David Gibson
2026-03-23 7:37 ` [PATCH v3 18/25] fwd: Split forwading rule specification from its implementation state David Gibson
2026-03-23 7:37 ` [PATCH v3 19/25] ip: Define a bound for the string returned by ipproto_name() David Gibson
2026-03-23 7:37 ` [PATCH v3 20/25] fwd_rule: Move forwarding rule text formatting to common code David Gibson
2026-03-25 0:56 ` Stefano Brivio
2026-03-25 4:42 ` David Gibson
2026-03-25 8:18 ` Stefano Brivio
2026-03-25 23:54 ` David Gibson
2026-03-23 7:37 ` [PATCH v3 21/25] pesto: Read current ruleset from passt/pasta and display it David Gibson
2026-03-25 0:56 ` Stefano Brivio
2026-03-25 4:43 ` David Gibson
2026-03-23 7:37 ` [PATCH v3 22/25] conf: Move port parsing functions to own file, ports.c David Gibson
2026-03-23 7:37 ` [PATCH v3 23/25] conf, fwd, ports, util: Move things around for pesto David Gibson
2026-03-23 7:37 ` [PATCH v3 24/25] pesto, conf: Parse, send and receive new rules David Gibson
2026-03-23 7:37 ` [PATCH v3 25/25] conf, fwd: Allow switching to new rules received from pesto David Gibson
2026-03-23 8:38 ` [PATCH v3 00/25] RFC: Read-only dynamic update implementation David Gibson
2026-03-25 0:56 ` Stefano Brivio
2026-03-25 1:00 ` Stefano Brivio
2026-03-25 4:44 ` David Gibson
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260325015506.201d9ca0@elisabeth \
--to=sbrivio@redhat.com \
--cc=david@gibson.dropbear.id.au \
--cc=passt-dev@passt.top \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
Code repositories for project(s) associated with this public inbox
https://passt.top/passt
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for IMAP folder(s).