"Fossies" - the Fresh Open Source Software Archive

Member "userinfo-2.5/src/ui.c" (15 Jan 2015, 17610 Bytes) of package /linux/privat/userinfo-2.5.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "ui.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 2.4_vs_2.5.

    1 /*
    2     Copyright (C) 2001-2015 Ben Kibbey <bjk@luxsci.net>
    3 
    4     This program is free software; you can redistribute it and/or modify
    5     it under the terms of the GNU General Public License as published by
    6     the Free Software Foundation; either version 2 of the License, or
    7     (at your option) any later version.
    8 
    9     This program is distributed in the hope that it will be useful,
   10     but WITHOUT ANY WARRANTY; without even the implied warranty of
   11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   12     GNU General Public License for more details.
   13 
   14     You should have received a copy of the GNU General Public License
   15     along with this program; if not, write to the Free Software
   16     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02110-1301  USA
   17 */
   18 #ifdef HAVE_CONFIG_H
   19 #include <config.h>
   20 #endif
   21 
   22 #include <stdio.h>
   23 #include <unistd.h>
   24 #include <stdlib.h>
   25 #include <sys/types.h>
   26 #include <sys/stat.h>
   27 #include <errno.h>
   28 #include <ctype.h>
   29 #include <pwd.h>
   30 #include <time.h>
   31 
   32 #ifdef HAVE_LIMITS_H
   33 #include <limits.h>
   34 #ifndef LINE_MAX
   35 #ifdef _POSIX2_LINE_MAX
   36 #define LINE_MAX _POSIX2_LINE_MAX
   37 #else
   38 #define LINE_MAX 2048
   39 #endif
   40 #endif
   41 #endif
   42 
   43 #ifdef HAVE_GETOPT_H
   44 #include <getopt.h>
   45 #endif
   46 
   47 #ifndef HAVE_ERR_H
   48 #include "err.c"
   49 #endif
   50 
   51 #include "safe_strncat.c"
   52 #include "ui.h"
   53 
   54 static void *Realloc(void *p, size_t size)
   55 {
   56     void *p2;
   57 
   58     if ((p2 = realloc(p, size)) == NULL)
   59     err(EXIT_FAILURE, "%s", "realloc()");
   60 
   61     return p2;
   62 }
   63 
   64 /* This may be used in modules to keep a consistant time format with other
   65  * modules. */
   66 char *stamp(time_t epoch, const char *format)
   67 {
   68     static char buf[TIMEBUFSIZE];
   69     struct tm *t;
   70 
   71     t = localtime(&epoch);
   72     strftime(buf, sizeof(buf), format, t);
   73     return buf;
   74 }
   75 
   76 /*
   77  * This may be used in modules to add a string to the buffer (ui_module_exec()).
   78  */
   79 void add_string(char ***buf, const char *str)
   80 {
   81     char **s;
   82     int i = 0;
   83 
   84     if (*buf) {
   85     for (s = *buf; *s; s++)
   86         i++;
   87     }
   88 
   89     s = *buf;
   90     s = Realloc(s, (i + 2) * sizeof(char *));
   91     s[i++] = strdup(str);
   92     s[i] = NULL;
   93     *buf = s;
   94 }
   95 
   96 /* This is for the field separators (-F and -m). */
   97 static int escapes(const char *str)
   98 {
   99     int c = 0;
  100 
  101     if (str[0] != '\\')
  102     return str[0];
  103 
  104     switch (*++str) {
  105     case 't':
  106         c = '\t';
  107         break;
  108     case 'n':
  109         c = '\n';
  110         break;
  111     case '\\':
  112         c = '\\';
  113         break;
  114     case 'v':
  115         c = '\v';
  116         break;
  117     case 'b':
  118         c = '\b';
  119         break;
  120     case 'f':
  121         c = '\f';
  122         break;
  123     case 'r':
  124         c = '\r';
  125         break;
  126     case '\'':
  127         c = '\'';
  128         break;
  129     default:
  130         c = 0;
  131         break;
  132     }
  133 
  134     return c;
  135 }
  136 
  137 /* Help text. Module help text is displayed after this. */
  138 static void usage_header()
  139 {
  140     printf("Usage: %s [-vhVL] [-c <filename>] [-t fmt] [-m c] [-F c] [-d]\n"
  141        "\t[[-xX] -O <module1> [options] [-- [-xX] -O <module2> [...]]]\n"
  142        "\t[- | username | -f filename] [...]\n\n", __progname);
  143 }
  144 
  145 /* Help text. Module help text is displayed before this. */
  146 static void usage()
  147 {
  148     printf("  -d\tLoad the default modules (passwd.so, mail.so, and login.so).\n");
  149     printf("  -c\tRead a configuration file. Can be used more than once.\n");
  150     printf("  -O\tLoad a module. Can be used more than once.\n");
  151     printf("  -x\tChain module1's output to module2's input.\n");
  152     printf("  -X\tDon't output module1's info, only chain it.\n");
  153     printf("  -F c\tSeparate output with the specified character "
  154        "('%c').\n", delimchar);
  155     printf("  -m c\tSeparate multi-string values with the specified "
  156        "character ('%c').\n", multichar);
  157     printf("  -t tf\tstrftime(3) time format ('%s').\n", DEFAULT_TIMEFORMAT);
  158     printf("  -f\tUsers are the owners of the specified files.\n");
  159     printf("  -L\tFollow symbolic links.\n");
  160     printf("  -v\tVerbose output when possible (twice for all modules).\n");
  161     printf("  -h\tThis help text.\n");
  162     printf("  -V\tVersion information.\n\n");
  163     printf("Output key: %s=unknown/error, %s=none, %s=yes/on, "
  164        "%s=no/off\n", UNKNOWN, NONE, ON, OFF);
  165 }
  166 
  167 /*
  168  * Add a module to the array of loaded modules. The index argument is the
  169  * current item number being added stored in an integer. The module is also
  170  * initialized here with ui_module_init().
  171  */
  172 static int open_module(char *filename, struct module_s **ptr)
  173 {
  174     void *m;
  175     module_init *init;
  176     char *p, s[PATH_MAX];
  177     int chainable = 0;
  178     struct module_s *mod, **mods, *last;
  179     int dup = 0;
  180 
  181     strncpy(s, filename, sizeof(s));
  182     s[sizeof(s)-1] = 0;
  183 
  184     if ((p = strrchr(s, '/')) != NULL)
  185     p++;
  186     else {
  187     strncpy(s, filename, sizeof(s));
  188         s[sizeof(s)-1] = 0;
  189     p = s;
  190     }
  191 
  192     for (mods = modules; mods && *mods; mods++) {
  193     if (strcmp(p, (*mods)->name) == 0) {
  194         dup = 1;
  195         break;
  196     }
  197     }
  198 
  199     if ((m = dlopen(filename, RTLD_NOW)) == NULL) {
  200     warnx("%s", dlerror());
  201     chaining = 0;
  202     chain_output = 1;
  203     return 1;
  204     }
  205 
  206     last = modules ? modules[module_total-1] : NULL;
  207     modules = Realloc(modules, (module_total+2) * sizeof(struct module_s *));
  208     mod = calloc(1, sizeof(struct module_s));
  209     modules[module_total++] = mod;
  210     modules[module_total] = NULL;
  211     mod->m = m;
  212     strncpy(mod->name, p, sizeof(mod->name));
  213     mod->name[sizeof(mod->name)-1] = 0;
  214 
  215     if ((init = dlsym(mod->m, "ui_module_init")) == NULL)
  216     warnx("%s", dlerror());
  217     else
  218     (*init) (&chainable);
  219 
  220     if (chainable)
  221     SET_FLAG(mod->flags, MODULE_CHAINABLE);
  222 
  223     if (last && TEST_FLAG(last->flags, MODULE_CHAINED) &&
  224         !TEST_FLAG(mod->flags, MODULE_CHAINABLE)) {
  225     warnx("%s: this module is not chainable", mod->name);
  226     module_total--;
  227     modules[module_total] = NULL;
  228     free(mod);
  229     return 1;
  230     }
  231 
  232     /* Module chaining. See junction() for more info. */
  233     if (chaining)
  234     SET_FLAG(mod->flags, MODULE_CHAINED);
  235 
  236     if (chain_output)
  237     SET_FLAG(mod->flags, MODULE_OUTPUT);
  238 
  239     if (verbose)
  240     SET_FLAG(mod->flags, MODULE_VERBOSE);
  241 
  242     if (dup) {
  243     SET_FLAG(mod->flags, MODULE_DUP);
  244     warnx("%s: a module by this name is already loaded", p);
  245     }
  246 
  247     chaining = 0;
  248     chain_output = 1;
  249     verbose = (verbose < 2) ? 0 : 2;
  250     *ptr = mod;
  251     return 0;
  252 }
  253 
  254 /* This just free's up the array of modules. The modules should clean up after
  255  * themselves via the ui_module_exit() function. */
  256 static void cleanup_modules()
  257 {
  258     struct module_s **mod;
  259 
  260     if (!modules)
  261     return;
  262 
  263     for (mod = modules; *mod; mod++) {
  264     module_exit *e;
  265     char **p;
  266 
  267     if ((e = dlsym((*mod)->m, "ui_module_exit")) == NULL)
  268         warnx("%s", dlerror());
  269     else
  270         (*e)();
  271 
  272     dlclose((*mod)->m);
  273 
  274     if ((*mod)->argv) {
  275         for (p = (*mod)->argv; *p; p++)
  276         free(*p);
  277 
  278         free((*mod)->argv);
  279     }
  280 
  281     free(*mod);
  282     }
  283 
  284     free(modules);
  285 }
  286 
  287 static void output(char **s, const int sep, int which)
  288 {
  289     char **p = s;
  290 
  291     if (p) {
  292     for (; *p; p++) {
  293         printf("%s", *p);
  294 
  295         if (*(p+1))
  296         printf("%c", sep);
  297     }
  298     }
  299 
  300     printf("%c", which == OUTPUT_DONE ? '\n' : sep);
  301 }
  302 
  303 /* Pass the argument to each loaded module. */
  304 static int junction(const char *arg)
  305 {
  306     struct passwd *pw;
  307     struct stat st;
  308     int ret = EXIT_SUCCESS;
  309     char **s = NULL;
  310     struct module_s **mod;
  311 
  312     if (usefile) {
  313     if ((STAT(arg, &st)) == -1) {
  314         warn("%s", arg);
  315         return EXIT_FAILURE;
  316     }
  317 
  318     errno = 0;
  319 
  320     if ((pw = getpwuid(st.st_uid)) == NULL) {
  321 #ifdef __NetBSD__
  322         warnx("%s: no such user", arg);
  323 #else
  324         if (errno == 0 || errno == ENOENT || errno == EPERM
  325         || errno == EBADF || errno == ESRCH)
  326         warnx("%s: no such uid %u", arg, st.st_uid);
  327         else
  328         warn("%s", "getpwuid()");
  329 #endif
  330 
  331         return EXIT_FAILURE;
  332     }
  333     }
  334     else {
  335     errno = 0;
  336 
  337     if ((pw = getpwnam(arg)) == NULL) {
  338 #ifdef __NetBSD__
  339         warnx("%s: no such user", arg);
  340 #else
  341         if (errno == 0 || errno == ENOENT || errno == EPERM
  342         || errno == EBADF || errno == ESRCH)
  343         warnx("%s: no such user", arg);
  344         else
  345         warn("%s", "getpwnam()");
  346 #endif
  347 
  348         return EXIT_FAILURE;
  349     }
  350     }
  351 
  352     for (mod = modules; *mod; mod++) {
  353     module_exec *m_exec;
  354 
  355     if ((m_exec = dlsym((*mod)->m, "ui_module_exec")) == NULL) {
  356         warnx("%s", dlerror());
  357         continue;
  358     }
  359 
  360     ret |= (*m_exec) (&s, pw, multichar,
  361         TEST_FLAG((*mod)->flags, MODULE_VERBOSE), tf);
  362 
  363     if (!TEST_FLAG((*mod)->flags, MODULE_CHAINED) ||
  364         (TEST_FLAG((*mod)->flags, MODULE_CHAINED) &&
  365          TEST_FLAG((*mod)->flags, MODULE_OUTPUT))) {
  366         output(s, delimchar,
  367             (*(mod+1)) ? OUTPUT_APPEND : OUTPUT_DONE);
  368 
  369         if (!TEST_FLAG((*mod)->flags, MODULE_CHAINED)) {
  370         char **p;
  371 
  372         for (p = s; *p; p++) {
  373             free(*p);
  374         }
  375 
  376         free(s);
  377         s = NULL;
  378         }
  379     }
  380     }
  381 
  382     return ret;
  383 }
  384 
  385 /* Copy options for each module into it's own argc and argv variables stopping
  386  * at -- (getopt(3)). */
  387 static int init_module_options(int the_argc, char **the_argv,
  388     struct module_s *mod)
  389 {
  390     char tmp[255];
  391     module_options *m;
  392     module_options_init *o;
  393     int old_optind = optind;
  394     int opt;
  395     int ret = EXIT_SUCCESS;
  396     char *optstring = NULL;
  397     char *defaults = NULL;
  398     int have_an_argument = 0;
  399 
  400     if ((o = dlsym(mod->m, "ui_module_options_init")) == NULL) {
  401     warnx("%s", dlerror());
  402     return EXIT_FAILURE;
  403     }
  404 
  405     if ((optstring = (*o) (&defaults))) {
  406     mod->argv = Realloc(mod->argv, (mod->argc + 2) * sizeof(char *));
  407     mod->argv[mod->argc++] = strdup(__progname);
  408     mod->argv[mod->argc] = NULL;
  409 
  410     /* Probably a default module. */
  411     if (the_argv == NULL)
  412         goto blah;
  413 
  414     while ((opt = getopt(the_argc, the_argv, optstring)) != -1) {
  415         switch (opt) {
  416         case '?':
  417             warnx("%s: invalid option -- %c\n", mod->name,
  418               optopt);
  419             return EXIT_FAILURE;
  420         default:
  421             break;
  422         }
  423 
  424         mod->argv = Realloc(mod->argv, (mod->argc + 2) * sizeof(char *));
  425         snprintf(tmp, sizeof(tmp), "-%c%s", opt, (optarg) ? optarg : "");
  426         mod->argv[mod->argc++] = strdup(tmp);
  427         mod->argv[mod->argc] = NULL;
  428         have_an_argument = 1;
  429     }
  430     }
  431     else
  432     goto skip_option_stuff;
  433 
  434 blah:
  435     /*
  436      * No options were specified for this module. Set the modules default
  437      * options (ui_module_options_init()) if any. 
  438      */
  439     if (!have_an_argument && defaults) {
  440     mod->argv = Realloc(mod->argv, (mod->argc + 2) * sizeof(char *));
  441     snprintf(tmp, sizeof(tmp), "-%s", defaults);
  442     mod->argv[mod->argc++] = strdup(tmp);
  443     mod->argv[mod->argc] = NULL;
  444     }
  445 
  446     old_optind = optind;
  447     opterr = optind = optopt = 1;
  448 
  449     if ((m = dlsym(mod->m, "ui_module_options")) == NULL) {
  450     warnx("%s", dlerror());
  451     return EXIT_FAILURE;
  452     }
  453 
  454     ret |= (*m) (mod->argc, mod->argv);
  455     optind = old_optind;
  456 
  457 skip_option_stuff:
  458     return ret;
  459 }
  460 
  461 /* 
  462  * parseargs.c
  463  *
  464  * This will parse a line used as an argument list for the exec() line of
  465  * functions returning a dynamically allocated array of character pointers so
  466  * you should free() it afterwards. Both ' and " quoting is supported (with
  467  * escapes) for multi-word arguments.
  468  *
  469  * This is my second attempt at it. Works alot better than the first. :)
  470  *
  471  * 2002/10/05
  472  * Ben Kibbey <bjk@luxsci.net>
  473  *
  474  * 2004/11/07
  475  *     Modified to handle argv[0] and argc. (Ben Kibbey <bjk@luxsci.net>)
  476  */
  477 static char **parseargv(char *str, const char *progname, int *me_argc)
  478 {
  479     char **pptr, *s;
  480     char arg[LINE_MAX];
  481     int idx = 0;
  482     int quote = 0;
  483     int lastchar = 0;
  484     int i;
  485     int my_argc = 0;
  486 
  487     if (!str)
  488     return NULL;
  489 
  490     if (!(pptr = malloc(sizeof(char *))))
  491     return NULL;
  492 
  493     pptr = Realloc(pptr, (idx + 2) * sizeof(char *));
  494     pptr[idx++] = strdup(progname);
  495     my_argc++;
  496 
  497     for (i = 0, s = str; *s; lastchar = *s++) {
  498     if ((*s == '\"' || *s == '\'') && lastchar != '\\') {
  499         quote = (quote) ? 0 : 1;
  500         continue;
  501     }
  502 
  503     if (*s == ' ' && !quote) {
  504         arg[i] = 0;
  505         pptr = Realloc(pptr, (idx + 2) * sizeof(char *));
  506         pptr[idx++] = strdup(arg);
  507         my_argc++;
  508         arg[0] = i = 0;
  509         continue;
  510     }
  511 
  512     if ((i + 1) == sizeof(arg))
  513         continue;
  514 
  515     arg[i++] = *s;
  516     }
  517 
  518     arg[i] = 0;
  519 
  520     if (arg[0]) {
  521     pptr = Realloc(pptr, (idx + 2) * sizeof(char *));
  522     pptr[idx++] = strdup(arg);
  523     my_argc++;
  524     }
  525 
  526     pptr[idx] = NULL;
  527     *me_argc = my_argc;
  528     return pptr;
  529 }
  530 
  531 static char *get_home_directory()
  532 {
  533     struct passwd *pw;
  534     static char dir[PATH_MAX];
  535 
  536     errno = 0;
  537 
  538     if ((pw = getpwuid(getuid())) == NULL) {
  539     if (errno)
  540         warn("getpwuid()");
  541     else
  542         warnx("getpwuid(): no such uid");
  543 
  544     return NULL;
  545     }
  546 
  547     strncpy(dir, pw->pw_dir, sizeof(dir));
  548     dir[sizeof(dir)-1] = 0;
  549     return dir;
  550 }
  551 
  552 /* Read in a configuration file adding modules to the module array and
  553  * checking any module options. */
  554 static int parse_rc_file(const char *filename)
  555 {
  556     char line[LINE_MAX], *p;
  557     FILE *fp;
  558     int old_optind = optind;
  559     struct module_s *mod;
  560     
  561     if ((fp = fopen(filename, "r")) == NULL) {
  562     warn("%s", filename);
  563     return 1;
  564     }
  565 
  566     while ((p = fgets(line, sizeof(line), fp)) != NULL) {
  567     char name[PATH_MAX], options[LINE_MAX], tmp[PATH_MAX], *s;
  568     int my_argc;
  569     char **my_argv, **ap;
  570     int lastchar = '\0';
  571     int n;
  572 
  573     while (*p && isspace((unsigned char) *p))
  574         p++;
  575 
  576     if (*p == '#')
  577         continue;
  578 
  579     s = name;
  580 
  581     if (*p == '>' || *p == '-') {
  582         chaining = 1;
  583 
  584         if (*p == '-')
  585         chain_output = 0;
  586 
  587         p++;
  588     }
  589 
  590     while (*p && *p != ' ' && *p != '\t') {
  591         if (*p == '\n') {
  592         p++;
  593         break;
  594         }
  595 
  596         *s++ = *p++;
  597     }
  598 
  599     *s = '\0';
  600 
  601     if (!name[0])
  602         continue;
  603 
  604     s = options;
  605 
  606     while (*p && isspace((unsigned char) *p))
  607         p++;
  608 
  609     lastchar = *p;
  610 
  611     while (*p) {
  612         if (*p == '\n' || (*p == '#' && lastchar != '\\'))
  613         break;
  614 
  615         if (*p == '#' && lastchar == '\\') {
  616         lastchar = *--s = *p++;
  617         s++;
  618         continue;
  619         }
  620 
  621         lastchar = *s++ = *p++;
  622     }
  623 
  624     *s = '\0';
  625     p = name;
  626 
  627     if (*p == '~') {
  628         s = get_home_directory();
  629         strncpy(tmp, s, sizeof(tmp));
  630             tmp[sizeof(tmp)-1] = 0;
  631         p++;
  632         safe_strncat(tmp, p, sizeof(tmp));
  633         strncpy(name, tmp, sizeof(name));
  634             name[sizeof(name)-1] = 0;
  635     }
  636 
  637     if (open_module(name, &mod))
  638         continue;
  639 
  640     if ((my_argv = parseargv(options, __progname, &my_argc)) == NULL)
  641         continue;
  642 
  643     optind = 0;
  644     n = init_module_options(my_argc, my_argv, mod);
  645 
  646     for (ap = my_argv; *ap; ap++)
  647         free(*ap);
  648 
  649     free(my_argv);
  650 
  651     if (n) {
  652         fclose(fp);
  653         return 2;
  654     }
  655 
  656     optind = old_optind;
  657     }
  658 
  659     fclose(fp);
  660     return 0;
  661 }
  662 
  663 int main(int argc, char *argv[])
  664 {
  665     int ret = EXIT_SUCCESS;
  666     int opt;
  667     char line[LINE_MAX], *s = NULL;
  668     int want_help = 0;
  669 
  670 #ifndef HAVE___PROGNAME
  671     __progname = argv[0];
  672 #endif
  673     delimchar = DEFAULT_DELIMINATING_CHAR;
  674     multichar = DEFAULT_MULTI_CHAR;
  675     strncpy(tf, DEFAULT_TIMEFORMAT, sizeof(tf));
  676     chain_output = 1;
  677 
  678     while ((opt = getopt(argc, argv, "+x:X:dm:c:hO:F:t:vVLf")) != -1) {
  679     struct module_s *mod;
  680 
  681     /*
  682      * See getopt(3). 
  683      */
  684     opterr = 0;
  685 
  686     switch (opt) {
  687         case 'd':
  688         if (open_module("passwd.so", &mod) == 0) {
  689             if (init_module_options(1, NULL, mod))
  690             want_help = 1;
  691         }
  692         else {
  693             ret = EXIT_FAILURE;
  694             goto cleanup;
  695         }
  696 
  697         if (open_module("mail.so", &mod) == 0) {
  698             if (init_module_options(1, NULL, mod))
  699             want_help = 1;
  700         }
  701         else {
  702             ret = EXIT_FAILURE;
  703             goto cleanup;
  704         }
  705 
  706         if (open_module("login.so", &mod) == 0) {
  707             if (init_module_options(1, NULL, mod))
  708             want_help = 1;
  709         }
  710         else {
  711             ret = EXIT_FAILURE;
  712             goto cleanup;
  713         }
  714 
  715         break;
  716         case 'm':
  717         if ((optarg[0] != '\\' && strlen(optarg) > 1) ||
  718             (optarg[0] == '\\' && strlen(optarg) != 2)) {
  719             want_help = 1;
  720             break;
  721         }
  722 
  723         if ((multichar = escapes(optarg)) == 0)
  724             want_help = 1;
  725 
  726         break;
  727         case 'c':
  728         if ((ret = parse_rc_file(optarg)) != 0) {
  729             if (ret == 2)
  730             want_help = 1;
  731             else
  732             exit(EXIT_FAILURE);
  733         }
  734         break;
  735         case 'F':
  736         if ((optarg[0] != '\\' && strlen(optarg) > 1) ||
  737             (optarg[0] == '\\' && strlen(optarg) != 2)) {
  738             want_help = 1;
  739             break;
  740         }
  741 
  742         if ((delimchar = escapes(optarg)) == 0)
  743             want_help = 1;
  744 
  745         break;
  746         case 't':
  747         strncpy(tf, optarg, sizeof(tf));
  748         break;
  749         case 'V':
  750         printf("%s\n%s\n", PACKAGE_STRING, COPYRIGHT);
  751         exit(EXIT_SUCCESS);
  752         break;
  753         case 'L':
  754         followsymlinks = 1;
  755         break;
  756         case 'f':
  757         usefile = 1;
  758         break;
  759         case 'v':
  760         verbose++;
  761         break;
  762         case 'X':
  763         chain_output = 0;
  764         case 'x':
  765         chaining = 1;
  766         case 'O':
  767         if (open_module(optarg, &mod)) {
  768             ret = EXIT_FAILURE;
  769             goto cleanup;
  770         }
  771 
  772         if (init_module_options(argc, argv, mod))
  773             want_help = 1;
  774 
  775         /*
  776          * For modules which have no options at all (to keep getopt
  777          * from interpreting the rest as arguments.
  778          */
  779         if (optind < argc) {
  780             if (strcmp(argv[optind], "--") == 0)
  781             optind++;
  782         }
  783 
  784         break;
  785         case 'h':
  786         default:
  787         want_help = 1;
  788         break;
  789     }
  790     }
  791 
  792     /* The last module cannot be chained (syntax). */
  793     if (!module_total || TEST_FLAG(modules[module_total-1]->flags, MODULE_CHAINED))
  794     want_help = 1;
  795 
  796     /* Cycle through the modules and output their help text. */
  797     if (want_help) {
  798     usage_header();
  799     struct module_s **mod;
  800 
  801     for (mod = modules; mod && *mod; mod++) {
  802         module_help *m_help;
  803 
  804         if (TEST_FLAG((*mod)->flags, MODULE_DUP))
  805         continue;
  806 
  807         if ((m_help = dlsym((*mod)->m, "ui_module_help")) == NULL) {
  808         warnx("%s", dlerror());
  809         continue;
  810         }
  811 
  812         printf("%s\n", (*mod)->name);
  813         (*m_help) ();
  814     }
  815 
  816     usage();
  817     cleanup_modules();
  818     exit(EXIT_FAILURE);
  819     }
  820 
  821     if (argc == optind || strcmp(argv[optind], "-") == 0) {
  822     while ((s = fgets(line, sizeof(line), stdin)) != NULL) {
  823         if (s[strlen(s) - 1] == '\n')
  824         s[strlen(s) - 1] = '\0';
  825 
  826         ret |= junction(s);
  827     }
  828     }
  829     else {
  830     for (; optind < argc; optind++)
  831         ret |= junction(argv[optind]);
  832     }
  833 
  834 cleanup:
  835     cleanup_modules();
  836     exit(ret);
  837 }