From: David Gibson <david@gibson.dropbear.id.au>
To: Stefano Brivio <sbrivio@redhat.com>, passt-dev@passt.top
Cc: David Gibson <david@gibson.dropbear.id.au>
Subject: [PATCH v2 08/15] pesto: Add command line option parsing and debug messages
Date: Thu, 19 Mar 2026 17:11:50 +1100 [thread overview]
Message-ID: <20260319061157.1983818-9-david@gibson.dropbear.id.au> (raw)
In-Reply-To: <20260319061157.1983818-1-david@gibson.dropbear.id.au>
Add basic command line option parsing using getopt_long() to pesto.
Implement --help, --version, --quiet and --verbose options, along with a
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 031de352..e862b023 100644
--- a/conf.c
+++ b/conf.c
@@ -1146,6 +1146,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) : "",
@@ -1433,15 +1436,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) {
+ 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;
}
}
@@ -1486,13 +1489,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");
}
@@ -1847,11 +1850,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;
@@ -2295,10 +2298,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);
}
/**
@@ -2322,7 +2325,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;
@@ -2332,7 +2335,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;
}
@@ -2350,7 +2353,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(
@@ -2375,7 +2378,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);
@@ -2398,7 +2401,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 6bb748fb..4245c4c8 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
@@ -227,7 +227,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];
@@ -245,8 +245,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 edc07e77..a8c134f5 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);
+ int verbosity = 1;
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]);
+ 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 = seread_var(s, &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
--
2.53.0
next prev parent reply other threads:[~2026-03-19 6:12 UTC|newest]
Thread overview: 16+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-03-19 6:11 [PATCH v2 00/15] RFC: Read-only dynamic update implementation David Gibson
2026-03-19 6:11 ` [PATCH v2 01/15] treewide: Spell ASSERT() as assert() David Gibson
2026-03-19 6:11 ` [PATCH v2 02/15] serialise: Split functions user for serialisation from util.c David Gibson
2026-03-19 6:11 ` [PATCH v2 03/15] serialise: Add helpers for serialising unsigned integers David Gibson
2026-03-19 6:11 ` [PATCH v2 04/15] fwd: Move selecting correct scan bitmap into fwd_sync_one() David Gibson
2026-03-19 6:11 ` [PATCH v2 05/15] fwd: Look up rule index in fwd_sync_one() David Gibson
2026-03-19 6:11 ` [PATCH v2 06/15] fwd: Store forwarding tables indexed by (origin) pif David Gibson
2026-03-19 6:11 ` [PATCH v2 07/15] pesto: Introduce stub configuration interface and tool David Gibson
2026-03-19 6:11 ` David Gibson [this message]
2026-03-19 6:11 ` [PATCH v2 09/15] pesto: Expose list of pifs to pesto David Gibson
2026-03-19 6:11 ` [PATCH v2 10/15] ip: Prepare ip.[ch] for sharing with pesto tool David Gibson
2026-03-19 6:11 ` [PATCH v2 11/15] inany: Prepare inany.[ch] " David Gibson
2026-03-19 6:11 ` [PATCH v2 12/15] fwd: Split forwading rule specification from its implementation state David Gibson
2026-03-19 6:11 ` [PATCH v2 13/15] ip: Define a bound for the string returned by ipproto_name() David Gibson
2026-03-19 6:11 ` [PATCH v2 14/15] fwd_rule: Move forwarding rule text formatting to common code David Gibson
2026-03-19 6:11 ` [PATCH v2 15/15] pesto: Read current ruleset from passt/pasta and display it 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=20260319061157.1983818-9-david@gibson.dropbear.id.au \
--to=david@gibson.dropbear.id.au \
--cc=passt-dev@passt.top \
--cc=sbrivio@redhat.com \
/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).