changeset 19480:ed41702f14c2

doveadm: Fixed reseting getopt() with glibc when processing multiple commands in a single process. This means commands run with doveadm batch or multiple commands in a single doveadm-server connection. glibc's getopt() man page says that optind=1 should reset it for scanning a new argument vector, but this doesn't actually seem to work. Setting optind=0 does work though, so use it everywhere.
author Timo Sirainen <tss@iki.fi>
date Mon, 07 Dec 2015 11:29:29 +0200
parents 1f1fc5eb4a8e
children 62aa3c6ca7ed
files src/doveadm/client-connection.c src/doveadm/doveadm-dsync.c src/doveadm/doveadm-mail-batch.c src/doveadm/doveadm.c src/lib/lib.c src/lib/lib.h
diffstat 6 files changed, 18 insertions(+), 10 deletions(-) [+]
line wrap: on
line diff
--- a/src/doveadm/client-connection.c	Mon Dec 07 11:21:59 2015 +0200
+++ b/src/doveadm/client-connection.c	Mon Dec 07 11:29:29 2015 +0200
@@ -46,7 +46,7 @@
 	const char *str = NULL;
 	unsigned int i;
 
-	optind = 1;
+	i_getopt_reset();
 	doveadm_exit_code = 0;
 	cmd->cmd(argc, argv);
 
@@ -93,7 +93,7 @@
 	if (doveadm_debug)
 		ctx->service_flags |= MAIL_STORAGE_SERVICE_FLAG_DEBUG;
 
-	optind = 1;
+	i_getopt_reset();
 	getopt_args = t_strconcat("AF:S:u:", ctx->getopt_args, NULL);
 	while ((c = getopt(argc, argv, getopt_args)) > 0) {
 		switch (c) {
--- a/src/doveadm/doveadm-dsync.c	Mon Dec 07 11:21:59 2015 +0200
+++ b/src/doveadm/doveadm-dsync.c	Mon Dec 07 11:29:29 2015 +0200
@@ -1335,5 +1335,5 @@
 	legacy_dsync = TRUE;
 	*_argc = dest;
 	*_argv = new_argv;
-	optind = 1;
+	i_getopt_reset();
 }
--- a/src/doveadm/doveadm-mail-batch.c	Mon Dec 07 11:21:59 2015 +0200
+++ b/src/doveadm/doveadm-mail-batch.c	Mon Dec 07 11:29:29 2015 +0200
@@ -68,7 +68,7 @@
 	subctx->full_args = argv + 1;
 	subctx->service_flags |= batchctx->ctx.service_flags;
 
-	optind = 1;
+	i_getopt_reset();
 	getopt_args = subctx->getopt_args != NULL ? subctx->getopt_args : "";
 	while ((c = getopt(argc, (void *)argv, getopt_args)) > 0) {
 		if (subctx->v.parse_arg == NULL ||
--- a/src/doveadm/doveadm.c	Mon Dec 07 11:21:59 2015 +0200
+++ b/src/doveadm/doveadm.c	Mon Dec 07 11:29:29 2015 +0200
@@ -328,12 +328,7 @@
 
 	argc -= optind;
 	argv += optind;
-#ifdef __GLIBC__
-	/* for subcommands allow -options anywhere in command line */
-	optind = 0;
-#else
-	optind = 1;
-#endif
+	i_getopt_reset();
 
 	master_service_init_finish(master_service);
 	if (!doveadm_debug) {
--- a/src/lib/lib.c	Mon Dec 07 11:21:59 2015 +0200
+++ b/src/lib/lib.c	Mon Dec 07 11:29:29 2015 +0200
@@ -56,6 +56,17 @@
 	}
 }
 
+void i_getopt_reset(void)
+{
+#ifdef __GLIBC__
+	/* a) for subcommands allow -options anywhere in command line
+	   b) this is actually required for the reset to work (glibc bug?) */
+	optind = 0;
+#else
+	optind = 1;
+#endif
+}
+
 void lib_atexit(lib_atexit_callback_t *callback)
 {
 	lib_atexit_priority(callback, 0);
--- a/src/lib/lib.h	Mon Dec 07 11:21:59 2015 +0200
+++ b/src/lib/lib.h	Mon Dec 07 11:29:29 2015 +0200
@@ -60,6 +60,8 @@
 int i_unlink_if_exists(const char *path, const char *source_fname,
 		       unsigned int source_linenum);
 #define i_unlink_if_exists(path) i_unlink_if_exists(path, __FILE__, __LINE__)
+/* Reset getopt() so it can be used for the next args. */
+void i_getopt_reset(void);
 
 /* Call the given callback at the beginning of lib_deinit(). The main
    difference to atexit() is that liblib's memory allocation and logging