=== modified file 'plugin-runner.c' --- plugin-runner.c 2009-09-23 08:52:09 +0000 +++ plugin-runner.c 2009-10-24 19:17:52 +0000 @@ -68,6 +68,7 @@ */ #include /* errno, EBADF */ #include /* intmax_t, PRIdMAX, strtoimax() */ +#include /* EX_OSERR, EX_USAGE */ #define BUFFER_SIZE 256 @@ -102,7 +103,7 @@ /* Gets an existing plugin based on name, or if none is found, creates a new one */ static plugin *getplugin(char *name){ - /* Check for exiting plugin with that name */ + /* Check for existing plugin with that name */ for(plugin *p = plugin_list; p != NULL; p = p->next){ if((p->name == name) or (p->name and name and (strcmp(p->name, name) == 0))){ @@ -123,7 +124,9 @@ copy_name = strdup(name); } while(copy_name == NULL and errno == EINTR); if(copy_name == NULL){ + int e = errno; free(new_plugin); + errno = e; return NULL; } } @@ -137,8 +140,10 @@ new_plugin->argv = malloc(sizeof(char *) * 2); } while(new_plugin->argv == NULL and errno == EINTR); if(new_plugin->argv == NULL){ + int e = errno; free(copy_name); free(new_plugin); + errno = e; return NULL; } new_plugin->argv[0] = copy_name; @@ -148,9 +153,11 @@ new_plugin->environ = malloc(sizeof(char *)); } while(new_plugin->environ == NULL and errno == EINTR); if(new_plugin->environ == NULL){ + int e = errno; free(copy_name); free(new_plugin->argv); free(new_plugin); + errno = e; return NULL; } new_plugin->environ[0] = NULL; @@ -394,119 +401,137 @@ .doc = "Group ID the plugins will run as", .group = 3 }, { .name = "debug", .key = 132, .doc = "Debug mode", .group = 4 }, + /* + * These reproduce what we would get without ARGP_NO_HELP + */ + { .name = "help", .key = '?', + .doc = "Give this help list", .group = -1 }, + { .name = "usage", .key = -3, + .doc = "Give a short usage message", .group = -1 }, + { .name = "version", .key = 'V', + .doc = "Print program version", .group = -1 }, { .name = NULL } }; - error_t parse_opt(int key, char *arg, __attribute__((unused)) - struct argp_state *state){ + error_t parse_opt(int key, char *arg, struct argp_state *state){ + errno = 0; switch(key){ char *tmp; intmax_t tmpmax; case 'g': /* --global-options */ - if(arg != NULL){ + { char *plugin_option; while((plugin_option = strsep(&arg, ",")) != NULL){ - if(plugin_option[0] == '\0'){ - continue; - } if(not add_argument(getplugin(NULL), plugin_option)){ - perror("add_argument"); - return ARGP_ERR_UNKNOWN; + break; } } } break; case 'G': /* --global-env */ - if(arg == NULL){ - break; - } - if(not add_environment(getplugin(NULL), arg, true)){ - perror("add_environment"); - } + add_environment(getplugin(NULL), arg, true); break; case 'o': /* --options-for */ - if(arg != NULL){ - char *plugin_name = strsep(&arg, ":"); - if(plugin_name[0] == '\0'){ - break; - } - char *plugin_option; - while((plugin_option = strsep(&arg, ",")) != NULL){ - if(not add_argument(getplugin(plugin_name), plugin_option)){ - perror("add_argument"); - return ARGP_ERR_UNKNOWN; + { + char *option_list = strchr(arg, ':'); + if(option_list == NULL){ + argp_error(state, "No colon in \"%s\"", arg); + errno = EINVAL; + break; + } + *option_list = '\0'; + option_list++; + if(arg[0] == '\0'){ + argp_error(state, "Empty plugin name"); + errno = EINVAL; + break; + } + char *option; + while((option = strsep(&option_list, ",")) != NULL){ + if(not add_argument(getplugin(arg), option)){ + break; } } } break; case 'E': /* --env-for */ - if(arg == NULL){ - break; - } { char *envdef = strchr(arg, ':'); if(envdef == NULL){ + argp_error(state, "No colon in \"%s\"", arg); + errno = EINVAL; break; } *envdef = '\0'; - if(not add_environment(getplugin(arg), envdef+1, true)){ - perror("add_environment"); + envdef++; + if(arg[0] == '\0'){ + argp_error(state, "Empty plugin name"); + errno = EINVAL; + break; } + add_environment(getplugin(arg), envdef, true); } break; case 'd': /* --disable */ - if(arg != NULL){ + { plugin *p = getplugin(arg); - if(p == NULL){ - return ARGP_ERR_UNKNOWN; + if(p != NULL){ + p->disabled = true; } - p->disabled = true; } break; case 'e': /* --enable */ - if(arg != NULL){ + { plugin *p = getplugin(arg); - if(p == NULL){ - return ARGP_ERR_UNKNOWN; + if(p != NULL){ + p->disabled = false; } - p->disabled = false; } break; case 128: /* --plugin-dir */ free(plugindir); plugindir = strdup(arg); - if(plugindir == NULL){ - perror("strdup"); - } break; case 129: /* --config-file */ /* This is already done by parse_opt_config_file() */ break; case 130: /* --userid */ - errno = 0; tmpmax = strtoimax(arg, &tmp, 10); if(errno != 0 or tmp == arg or *tmp != '\0' or tmpmax != (uid_t)tmpmax){ - fprintf(stderr, "Bad user ID number: \"%s\", using %" - PRIdMAX "\n", arg, (intmax_t)uid); - } else { - uid = (uid_t)tmpmax; + argp_error(state, "Bad user ID number: \"%s\", using %" + PRIdMAX, arg, (intmax_t)uid); + break; } + uid = (uid_t)tmpmax; break; case 131: /* --groupid */ - errno = 0; tmpmax = strtoimax(arg, &tmp, 10); if(errno != 0 or tmp == arg or *tmp != '\0' or tmpmax != (gid_t)tmpmax){ - fprintf(stderr, "Bad group ID number: \"%s\", using %" - PRIdMAX "\n", arg, (intmax_t)gid); - } else { - gid = (gid_t)tmpmax; + argp_error(state, "Bad group ID number: \"%s\", using %" + PRIdMAX, arg, (intmax_t)gid); + break; } + gid = (gid_t)tmpmax; break; case 132: /* --debug */ debug = true; break; + /* + * These reproduce what we would get without ARGP_NO_HELP + */ + case '?': /* --help */ + state->flags &= ~(unsigned int)ARGP_NO_EXIT; /* force exit */ + argp_state_help(state, state->out_stream, ARGP_HELP_STD_HELP); + case -3: /* --usage */ + state->flags &= ~(unsigned int)ARGP_NO_EXIT; /* force exit */ + argp_state_help(state, state->out_stream, + ARGP_HELP_USAGE | ARGP_HELP_EXIT_OK); + case 'V': /* --version */ + fprintf(state->out_stream, "%s\n", argp_program_version); + exit(EXIT_SUCCESS); + break; /* * When adding more options before this line, remember to also add a * "case" to the "parse_opt_config_file" function below. @@ -515,16 +540,13 @@ /* Cryptsetup always passes an argument, which is an empty string if "none" was specified in /etc/crypttab. So if argument was empty, we ignore it silently. */ - if(arg[0] != '\0'){ - fprintf(stderr, "Ignoring unknown argument \"%s\"\n", arg); + if(arg[0] == '\0'){ + break; } - break; - case ARGP_KEY_END: - break; default: return ARGP_ERR_UNKNOWN; } - return 0; + return errno; /* Set to 0 at start */ } /* This option parser is the same as parse_opt() above, except it @@ -532,6 +554,7 @@ error_t parse_opt_config_file(int key, char *arg, __attribute__((unused)) struct argp_state *state){ + errno = 0; switch(key){ case 'g': /* --global-options */ case 'G': /* --global-env */ @@ -544,20 +567,19 @@ case 129: /* --config-file */ free(argfile); argfile = strdup(arg); - if(argfile == NULL){ - perror("strdup"); - } break; case 130: /* --userid */ case 131: /* --groupid */ case 132: /* --debug */ + case '?': /* --help */ + case -3: /* --usage */ + case 'V': /* --version */ case ARGP_KEY_ARG: - case ARGP_KEY_END: break; default: return ARGP_ERR_UNKNOWN; } - return 0; + return errno; } struct argp argp = { .options = options, @@ -567,10 +589,20 @@ /* Parse using parse_opt_config_file() in order to get the custom config file location, if any. */ - ret = argp_parse(&argp, argc, argv, ARGP_IN_ORDER, 0, NULL); - if(ret == ARGP_ERR_UNKNOWN){ - fprintf(stderr, "Unknown error while parsing arguments\n"); - exitstatus = EXIT_FAILURE; + ret = argp_parse(&argp, argc, argv, + ARGP_IN_ORDER | ARGP_NO_EXIT | ARGP_NO_HELP, + NULL, NULL); + switch(ret){ + case 0: + break; + case ENOMEM: + default: + errno = ret; + perror("argp_parse"); + exitstatus = EX_OSERR; + goto fallback; + case EINVAL: + exitstatus = EX_USAGE; goto fallback; } @@ -653,24 +685,43 @@ goto fallback; } } - /* If there was any arguments from configuration file, - pass them to parser as command arguments */ + /* If there were any arguments from the configuration file, pass + them to parser as command line arguments */ if(custom_argv != NULL){ - ret = argp_parse(&argp, custom_argc, custom_argv, ARGP_IN_ORDER, - 0, NULL); - if(ret == ARGP_ERR_UNKNOWN){ - fprintf(stderr, "Unknown error while parsing arguments\n"); - exitstatus = EXIT_FAILURE; + ret = argp_parse(&argp, custom_argc, custom_argv, + ARGP_IN_ORDER | ARGP_NO_EXIT | ARGP_NO_HELP, + NULL, NULL); + switch(ret){ + case 0: + break; + case ENOMEM: + default: + errno = ret; + perror("argp_parse"); + exitstatus = EX_OSERR; + goto fallback; + case EINVAL: + exitstatus = EX_CONFIG; goto fallback; } } /* Parse actual command line arguments, to let them override the config file */ - ret = argp_parse(&argp, argc, argv, ARGP_IN_ORDER, 0, NULL); - if(ret == ARGP_ERR_UNKNOWN){ - fprintf(stderr, "Unknown error while parsing arguments\n"); - exitstatus = EXIT_FAILURE; + ret = argp_parse(&argp, argc, argv, + ARGP_IN_ORDER | ARGP_NO_EXIT | ARGP_NO_HELP, + NULL, NULL); + switch(ret){ + case 0: + break; + case ENOMEM: + default: + errno = ret; + perror("argp_parse"); + exitstatus = EX_OSERR; + goto fallback; + case EINVAL: + exitstatus = EX_USAGE; goto fallback; } === modified file 'plugins.d/mandos-client.c' --- plugins.d/mandos-client.c 2009-09-17 11:22:28 +0000 +++ plugins.d/mandos-client.c 2009-10-24 19:17:52 +0000 @@ -82,6 +82,7 @@ #include /* sigemptyset(), sigaddset(), sigaction(), SIGTERM, sig_atomic_t, raise() */ +#include /* EX_OSERR, EX_USAGE */ #ifdef __linux__ #include /* klogctl() */ @@ -1056,11 +1057,21 @@ .arg = "SECONDS", .doc = "Maximum delay to wait for interface startup", .group = 2 }, + /* + * These reproduce what we would get without ARGP_NO_HELP + */ + { .name = "help", .key = '?', + .doc = "Give this help list", .group = -1 }, + { .name = "usage", .key = -3, + .doc = "Give a short usage message", .group = -1 }, + { .name = "version", .key = 'V', + .doc = "Print program version", .group = -1 }, { .name = NULL } }; error_t parse_opt(int key, char *arg, struct argp_state *state){ + errno = 0; switch(key){ case 128: /* --debug */ debug = true; @@ -1082,8 +1093,7 @@ tmpmax = strtoimax(arg, &tmp, 10); if(errno != 0 or tmp == arg or *tmp != '\0' or tmpmax != (typeof(mc.dh_bits))tmpmax){ - fprintf(stderr, "Bad number of DH bits\n"); - exit(EXIT_FAILURE); + argp_error(state, "Bad number of DH bits"); } mc.dh_bits = (typeof(mc.dh_bits))tmpmax; break; @@ -1094,28 +1104,46 @@ errno = 0; delay = strtof(arg, &tmp); if(errno != 0 or tmp == arg or *tmp != '\0'){ - fprintf(stderr, "Bad delay\n"); - exit(EXIT_FAILURE); + argp_error(state, "Bad delay"); } break; - case ARGP_KEY_ARG: - argp_usage(state); - case ARGP_KEY_END: + /* + * These reproduce what we would get without ARGP_NO_HELP + */ + case '?': /* --help */ + argp_state_help(state, state->out_stream, + (ARGP_HELP_STD_HELP | ARGP_HELP_EXIT_ERR) + & ~(unsigned int)ARGP_HELP_EXIT_OK); + case -3: /* --usage */ + argp_state_help(state, state->out_stream, + ARGP_HELP_USAGE | ARGP_HELP_EXIT_ERR); + case 'V': /* --version */ + fprintf(state->out_stream, "%s\n", argp_program_version); + exit(argp_err_exit_status); break; default: return ARGP_ERR_UNKNOWN; } - return 0; + return errno; } struct argp argp = { .options = options, .parser = parse_opt, .args_doc = "", .doc = "Mandos client -- Get and decrypt" " passwords from a Mandos server" }; - ret = argp_parse(&argp, argc, argv, 0, 0, NULL); - if(ret == ARGP_ERR_UNKNOWN){ - fprintf(stderr, "Unknown error while parsing arguments\n"); - exitcode = EXIT_FAILURE; + ret = argp_parse(&argp, argc, argv, + ARGP_IN_ORDER | ARGP_NO_HELP, 0, NULL); + switch(ret){ + case 0: + break; + case ENOMEM: + default: + errno = ret; + perror("argp_parse"); + exitcode = EX_OSERR; + goto end; + case EINVAL: + exitcode = EX_USAGE; goto end; } } @@ -1220,7 +1248,7 @@ #ifdef __linux__ /* Lower kernel loglevel to KERN_NOTICE to avoid KERN_INFO - messages to mess up the prompt */ + messages about the network interface to mess up the prompt */ ret = klogctl(8, NULL, 5); bool restore_loglevel = true; if(ret == -1){ @@ -1530,7 +1558,7 @@ if(ret == -1){ perror("ioctl SIOCGIFFLAGS"); } else if(network.ifr_flags & IFF_UP) { - network.ifr_flags &= ~IFF_UP; /* clear flag */ + network.ifr_flags &= ~(short)IFF_UP; /* clear flag */ ret = ioctl(sd, SIOCSIFFLAGS, &network); if(ret == -1){ perror("ioctl SIOCSIFFLAGS"); === modified file 'plugins.d/password-prompt.c' --- plugins.d/password-prompt.c 2009-10-18 17:29:55 +0000 +++ plugins.d/password-prompt.c 2009-10-24 19:17:52 +0000 @@ -37,10 +37,10 @@ #include /* NULL, size_t, ssize_t */ #include /* ssize_t */ #include /* EXIT_SUCCESS, EXIT_FAILURE, - getopt_long, getenv() */ + getenv() */ #include /* fprintf(), stderr, getline(), - stdin, feof(), perror(), fputc(), - getopt_long */ + stdin, feof(), perror(), fputc() + */ #include /* errno, EBADF, ENOTTY, EINVAL, EFAULT, EFBIG, EIO, ENOSPC, EINTR */ @@ -86,10 +86,20 @@ .doc = "Prefix shown before the prompt", .group = 2 }, { .name = "debug", .key = 128, .doc = "Debug mode", .group = 3 }, + /* + * These reproduce what we would get without ARGP_NO_HELP + */ + { .name = "help", .key = '?', + .doc = "Give this help list", .group = -1 }, + { .name = "usage", .key = -3, + .doc = "Give a short usage message", .group = -1 }, + { .name = "version", .key = 'V', + .doc = "Print program version", .group = -1 }, { .name = NULL } }; error_t parse_opt (int key, char *arg, struct argp_state *state){ + errno = 0; switch (key){ case 'p': prefix = arg; @@ -97,25 +107,42 @@ case 128: debug = true; break; - case ARGP_KEY_ARG: - argp_usage(state); - break; - case ARGP_KEY_END: + /* + * These reproduce what we would get without ARGP_NO_HELP + */ + case '?': /* --help */ + argp_state_help(state, state->out_stream, + (ARGP_HELP_STD_HELP | ARGP_HELP_EXIT_ERR) + & ~(unsigned int)ARGP_HELP_EXIT_OK); + case -3: /* --usage */ + argp_state_help(state, state->out_stream, + ARGP_HELP_USAGE | ARGP_HELP_EXIT_ERR); + case 'V': /* --version */ + fprintf(state->out_stream, "%s\n", argp_program_version); + exit(argp_err_exit_status); break; default: return ARGP_ERR_UNKNOWN; } - return 0; + return errno; } struct argp argp = { .options = options, .parser = parse_opt, .args_doc = "", .doc = "Mandos password-prompt -- Read and" " output a password" }; - ret = argp_parse(&argp, argc, argv, 0, 0, NULL); - if(ret == ARGP_ERR_UNKNOWN){ - fprintf(stderr, "Unknown error while parsing arguments\n"); - return EX_SOFTWARE; + ret = argp_parse(&argp, argc, argv, + ARGP_IN_ORDER | ARGP_NO_HELP, NULL, NULL); + switch(ret){ + case 0: + break; + case ENOMEM: + default: + errno = ret; + perror("argp_parse"); + return EX_OSERR; + case EINVAL: + return EX_USAGE; } }