# HG changeset patch # User Timo Sirainen # Date 1449480569 -7200 # Node ID ed41702f14c2a3bea222fc28375cefd36d446eca # Parent 1f1fc5eb4a8e755bdc2cfdf9b48946aa2e3d873b 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. diff -r 1f1fc5eb4a8e -r ed41702f14c2 src/doveadm/client-connection.c --- 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) { diff -r 1f1fc5eb4a8e -r ed41702f14c2 src/doveadm/doveadm-dsync.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(); } diff -r 1f1fc5eb4a8e -r ed41702f14c2 src/doveadm/doveadm-mail-batch.c --- 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 || diff -r 1f1fc5eb4a8e -r ed41702f14c2 src/doveadm/doveadm.c --- 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) { diff -r 1f1fc5eb4a8e -r ed41702f14c2 src/lib/lib.c --- 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); diff -r 1f1fc5eb4a8e -r ed41702f14c2 src/lib/lib.h --- 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