"Fossies" - the Fresh Open Source Software Archive

Member "popt-1.18/src/poptconfig.c" (16 Apr 2020, 10880 Bytes) of package /linux/misc/popt-1.18.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 "poptconfig.c" see the Fossies "Dox" file reference documentation.

    1 /** \ingroup popt
    2  * \file popt/poptconfig.c
    3  */
    4 
    5 /* (C) 1998-2002 Red Hat, Inc. -- Licensing details are in the COPYING
    6    file accompanying popt source distributions, available from 
    7    ftp://ftp.rpm.org/pub/rpm/dist. */
    8 
    9 #include "system.h"
   10 #include "poptint.h"
   11 #include <sys/stat.h>
   12 #include <unistd.h>
   13 #include <fcntl.h>
   14 #include <errno.h>
   15 
   16 #if defined(HAVE_FNMATCH_H)
   17 #include <fnmatch.h>
   18 
   19 #endif
   20 
   21 #if defined(HAVE_GLOB_H)
   22 #include <glob.h>
   23 
   24 #if !defined(__GLIBC__)
   25 /* Return nonzero if PATTERN contains any metacharacters.
   26    Metacharacters can be quoted with backslashes if QUOTE is nonzero.  */
   27 static int
   28 glob_pattern_p (const char * pattern, int quote)
   29 {
   30     const char * p;
   31     int open = 0;
   32 
   33     for (p = pattern; *p != '\0'; ++p)
   34     switch (*p) {
   35     case '?':
   36     case '*':
   37     return 1;
   38     break;
   39     case '\\':
   40     if (quote && p[1] != '\0')
   41       ++p;
   42     break;
   43     case '[':
   44     open = 1;
   45     break;
   46     case ']':
   47     if (open)
   48       return 1;
   49     break;
   50     }
   51     return 0;
   52 }
   53 #endif  /* !defined(__GLIBC__) */
   54 
   55 static int poptGlobFlags = 0;
   56 
   57 static int poptGlob_error(UNUSED(const char * epath),
   58         UNUSED(int eerrno))
   59 {
   60     return 1;
   61 }
   62 #endif  /* HAVE_GLOB_H */
   63 
   64 /**
   65  * Return path(s) from a glob pattern.
   66  * @param con       context
   67  * @param pattern   glob pattern
   68  * @retval *acp     no. of paths
   69  * @retval *avp     array of paths
   70  * @return      0 on success
   71  */
   72 static int poptGlob(UNUSED(poptContext con), const char * pattern,
   73         int * acp, const char *** avp)
   74 {
   75     const char * pat = pattern;
   76     int rc = 0;     /* assume success */
   77 
   78 #if defined(HAVE_GLOB_H)
   79     if (glob_pattern_p(pat, 0)) {
   80     glob_t _g, *pglob = &_g;
   81 
   82     if (!(rc = glob(pat, poptGlobFlags, poptGlob_error, pglob))) {
   83         if (acp) {
   84         *acp = (int) pglob->gl_pathc;
   85         pglob->gl_pathc = 0;
   86         }
   87         if (avp) {
   88         *avp = (const char **) pglob->gl_pathv;
   89         pglob->gl_pathv = NULL;
   90         }
   91         globfree(pglob);
   92     } else if (rc == GLOB_NOMATCH) {
   93         *avp = NULL;
   94         *acp = 0;
   95         rc = 0;
   96     } else
   97         rc = POPT_ERROR_ERRNO;
   98     } else
   99 #endif  /* HAVE_GLOB_H */
  100     {
  101     if (acp)
  102         *acp = 1;
  103     if (avp && (*avp = calloc((size_t)(1 + 1), sizeof (**avp))) != NULL)
  104         (*avp)[0] = xstrdup(pat);
  105     }
  106 
  107     return rc;
  108 }
  109 
  110 
  111 int poptSaneFile(const char * fn)
  112 {
  113     struct stat sb;
  114 
  115     if (fn == NULL || strstr(fn, ".rpmnew") || strstr(fn, ".rpmsave"))
  116     return 0;
  117     if (stat(fn, &sb) == -1)
  118     return 0;
  119     if (!S_ISREG(sb.st_mode))
  120     return 0;
  121     if (sb.st_mode & (S_IXUSR|S_IXGRP|S_IXOTH))
  122     return 0;
  123     return 1;
  124 }
  125 
  126 int poptReadFile(const char * fn, char ** bp, size_t * nbp, int flags)
  127 {
  128     int fdno;
  129     char * b = NULL;
  130     off_t nb = 0;
  131     char * s, * t, * se;
  132     int rc = POPT_ERROR_ERRNO;  /* assume failure */
  133 
  134     fdno = open(fn, O_RDONLY);
  135     if (fdno < 0)
  136     goto exit;
  137 
  138     if ((nb = lseek(fdno, 0, SEEK_END)) == (off_t)-1
  139      || lseek(fdno, 0, SEEK_SET) == (off_t)-1
  140      || (b = calloc(sizeof(*b), (size_t)nb + 1)) == NULL
  141      || read(fdno, (char *)b, (size_t)nb) != (ssize_t)nb)
  142     {
  143     int oerrno = errno;
  144     (void) close(fdno);
  145     errno = oerrno;
  146     goto exit;
  147     }
  148     if (close(fdno) == -1)
  149     goto exit;
  150     if (b == NULL) {
  151     rc = POPT_ERROR_MALLOC;
  152     goto exit;
  153     }
  154     rc = 0;
  155 
  156    /* Trim out escaped newlines. */
  157     if (flags & POPT_READFILE_TRIMNEWLINES)
  158     {
  159     for (t = b, s = b, se = b + nb; *s && s < se; s++) {
  160         switch (*s) {
  161         case '\\':
  162         if (s[1] == '\n') {
  163             s++;
  164             continue;
  165         }
  166         /* fallthrough */
  167         default:
  168         *t++ = *s;
  169         break;
  170         }
  171     }
  172     *t++ = '\0';
  173     nb = (off_t)(t - b);
  174     }
  175 
  176 exit:
  177     if (rc != 0) {
  178     if (b)
  179         free(b);
  180     b = NULL;
  181     nb = 0;
  182     }
  183     if (bp)
  184     *bp = b;
  185     else if (b)
  186     free(b);
  187     if (nbp)
  188     *nbp = (size_t)nb;
  189     return rc;
  190 }
  191 
  192 /**
  193  * Check for application match.
  194  * @param con       context
  195  * @param s     config application name
  196  * return       0 if config application matches
  197  */
  198 static int configAppMatch(poptContext con, const char * s)
  199 {
  200     int rc = 1;
  201 
  202     if (con->appName == NULL)   /* XXX can't happen. */
  203     return rc;
  204 
  205 #if defined(HAVE_GLOB_H) && defined(HAVE_FNMATCH_H)
  206     if (glob_pattern_p(s, 1)) {
  207     static int flags = FNM_PATHNAME | FNM_PERIOD;
  208 #ifdef FNM_EXTMATCH
  209     flags |= FNM_EXTMATCH;
  210 #endif
  211     rc = fnmatch(s, con->appName, flags);
  212     } else
  213 #endif
  214     rc = strcmp(s, con->appName);
  215     return rc;
  216 }
  217 
  218 static int poptConfigLine(poptContext con, char * line)
  219 {
  220     char *b = NULL;
  221     size_t nb = 0;
  222     char * se = line;
  223     const char * appName;
  224     const char * entryType;
  225     const char * opt;
  226     struct poptItem_s item_buf;
  227     poptItem item = &item_buf;
  228     int i, j;
  229     int rc = POPT_ERROR_BADCONFIG;
  230 
  231     if (con->appName == NULL)
  232     goto exit;
  233     
  234     memset(item, 0, sizeof(*item));
  235 
  236     appName = se;
  237     while (*se != '\0' && !_isspaceptr(se)) se++;
  238     if (*se == '\0')
  239     goto exit;
  240     else
  241     *se++ = '\0';
  242 
  243     if (configAppMatch(con, appName)) goto exit;
  244 
  245     while (*se != '\0' && _isspaceptr(se)) se++;
  246     entryType = se;
  247     while (*se != '\0' && !_isspaceptr(se)) se++;
  248     if (*se != '\0') *se++ = '\0';
  249 
  250     while (*se != '\0' && _isspaceptr(se)) se++;
  251     if (*se == '\0') goto exit;
  252     opt = se;
  253     while (*se != '\0' && !_isspaceptr(se)) se++;
  254     if (opt[0] == '-' && *se == '\0') goto exit;
  255     if (*se != '\0') *se++ = '\0';
  256 
  257     while (*se != '\0' && _isspaceptr(se)) se++;
  258     if (opt[0] == '-' && *se == '\0') goto exit;
  259 
  260     if (opt[0] == '-' && opt[1] == '-')
  261     item->option.longName = opt + 2;
  262     else if (opt[0] == '-' && opt[2] == '\0')
  263     item->option.shortName = opt[1];
  264     else {
  265     const char * fn = opt;
  266 
  267     /* XXX handle globs and directories in fn? */
  268     if ((rc = poptReadFile(fn, &b, &nb, POPT_READFILE_TRIMNEWLINES)) != 0)
  269         goto exit;
  270     if (b == NULL || nb == 0)
  271         goto exit;
  272 
  273     /* Append remaining text to the interpolated file option text. */
  274     if (*se != '\0') {
  275         size_t nse = strlen(se) + 1;
  276         if ((b = realloc(b, (nb + nse))) == NULL)   /* XXX can't happen */
  277         goto exit;
  278         (void) stpcpy( stpcpy(&b[nb-1], " "), se);
  279         nb += nse;
  280     }
  281     se = b;
  282 
  283     /* Use the basename of the path as the long option name. */
  284     {   const char * longName = strrchr(fn, '/');
  285         if (longName != NULL)
  286         longName++;
  287         else
  288         longName = fn;
  289         if (longName == NULL)   /* XXX can't happen. */
  290         goto exit;
  291         /* Single character basenames are treated as short options. */
  292         if (longName[1] != '\0')
  293         item->option.longName = longName;
  294         else
  295         item->option.shortName = longName[0];
  296     }
  297     }
  298 
  299     if (poptParseArgvString(se, &item->argc, &item->argv)) goto exit;
  300 
  301     item->option.argInfo = POPT_ARGFLAG_DOC_HIDDEN;
  302     for (i = 0, j = 0; i < item->argc; i++, j++) {
  303     const char * f;
  304     if (!strncmp(item->argv[i], "--POPTdesc=", sizeof("--POPTdesc=")-1)) {
  305         f = item->argv[i] + sizeof("--POPTdesc=");
  306         if (f[0] == '$' && f[1] == '"') f++;
  307         item->option.descrip = f;
  308         item->option.argInfo &= ~POPT_ARGFLAG_DOC_HIDDEN;
  309         j--;
  310     } else
  311     if (!strncmp(item->argv[i], "--POPTargs=", sizeof("--POPTargs=")-1)) {
  312         f = item->argv[i] + sizeof("--POPTargs=");
  313         if (f[0] == '$' && f[1] == '"') f++;
  314         item->option.argDescrip = f;
  315         item->option.argInfo &= ~POPT_ARGFLAG_DOC_HIDDEN;
  316         item->option.argInfo |= POPT_ARG_STRING;
  317         j--;
  318     } else
  319     if (j != i)
  320         item->argv[j] = item->argv[i];
  321     }
  322     if (j != i) {
  323     item->argv[j] = NULL;
  324     item->argc = j;
  325     }
  326     
  327     if (!strcmp(entryType, "alias"))
  328     rc = poptAddItem(con, item, 0);
  329     else if (!strcmp(entryType, "exec"))
  330     rc = poptAddItem(con, item, 1);
  331 exit:
  332     rc = 0; /* XXX for now, always return success */
  333     if (b)
  334     free(b);
  335     return rc;
  336 }
  337 
  338 int poptReadConfigFile(poptContext con, const char * fn)
  339 {
  340     char * b = NULL, *be;
  341     size_t nb = 0;
  342     const char *se;
  343     char *t, *te;
  344     int rc;
  345 
  346     if ((rc = poptReadFile(fn, &b, &nb, POPT_READFILE_TRIMNEWLINES)) != 0)
  347     return (errno == ENOENT ? 0 : rc);
  348     if (b == NULL || nb == 0)
  349     return POPT_ERROR_BADCONFIG;
  350 
  351     if ((t = malloc(nb + 1)) == NULL)
  352     goto exit;
  353     te = t;
  354 
  355     be = (b + nb);
  356     for (se = b; se < be; se++) {
  357     switch (*se) {
  358       case '\n':
  359         *te = '\0';
  360         te = t;
  361         while (*te && _isspaceptr(te)) te++;
  362         if (*te && *te != '#')
  363         if ((rc = poptConfigLine(con, te)) != 0)
  364             goto exit;
  365         break;
  366       case '\\':
  367         *te = *se++;
  368         /* \ at the end of a line does not insert a \n */
  369         if (se < be && *se != '\n') {
  370         te++;
  371         *te++ = *se;
  372         }
  373         break;
  374       default:
  375         *te++ = *se;
  376         break;
  377     }
  378     }
  379     rc = 0;
  380 
  381 exit:
  382     free(t);
  383     if (b)
  384     free(b);
  385     return rc;
  386 }
  387 
  388 int poptReadConfigFiles(poptContext con, const char * paths)
  389 {
  390     char * buf = (paths ? xstrdup(paths) : NULL);
  391     const char * p;
  392     char * pe;
  393     int rc = 0;     /* assume success */
  394 
  395     for (p = buf; p != NULL && *p != '\0'; p = pe) {
  396     const char ** av = NULL;
  397     int ac = 0;
  398     int i;
  399     int xx;
  400 
  401     /* locate start of next path element */
  402     pe = strchr(p, ':');
  403     if (pe != NULL && *pe == ':')
  404         *pe++ = '\0';
  405     else
  406         pe = (char *) (p + strlen(p));
  407 
  408     xx = poptGlob(con, p, &ac, &av);
  409 
  410     /* work-off each resulting file from the path element */
  411     for (i = 0; i < ac; i++) {
  412         const char * fn = av[i];
  413         if (!poptSaneFile(fn))
  414         continue;
  415         xx = poptReadConfigFile(con, fn);
  416         if (xx && rc == 0)
  417         rc = xx;
  418         free((void *)av[i]);
  419         av[i] = NULL;
  420     }
  421     free(av);
  422     av = NULL;
  423     }
  424 
  425     if (buf)
  426     free(buf);
  427 
  428     return rc;
  429 }
  430 
  431 int poptReadDefaultConfig(poptContext con, UNUSED(int useEnv))
  432 {
  433     char * home;
  434     struct stat sb;
  435     int rc = 0;     /* assume success */
  436 
  437     if (con->appName == NULL) goto exit;
  438 
  439     rc = poptReadConfigFile(con, POPT_SYSCONFDIR "/popt");
  440     if (rc) goto exit;
  441 
  442 #if defined(HAVE_GLOB_H)
  443     if (!stat(POPT_SYSCONFDIR "/popt.d", &sb) && S_ISDIR(sb.st_mode)) {
  444     const char ** av = NULL;
  445     int ac = 0;
  446     int i;
  447 
  448     if ((rc = poptGlob(con, POPT_SYSCONFDIR "/popt.d/*", &ac, &av)) == 0) {
  449         for (i = 0; rc == 0 && i < ac; i++) {
  450         const char * fn = av[i];
  451         if (!poptSaneFile(fn))
  452             continue;
  453         rc = poptReadConfigFile(con, fn);
  454         free((void *)av[i]);
  455         av[i] = NULL;
  456         }
  457         free(av);
  458         av = NULL;
  459     }
  460     }
  461     if (rc) goto exit;
  462 #endif
  463 
  464     if ((home = getenv("HOME"))) {
  465     char * fn = malloc(strlen(home) + 20);
  466     if (fn != NULL) {
  467         (void) stpcpy(stpcpy(fn, home), "/.popt");
  468         rc = poptReadConfigFile(con, fn);
  469         free(fn);
  470     } else
  471         rc = POPT_ERROR_ERRNO;
  472     if (rc) goto exit;
  473     }
  474 
  475 exit:
  476     return rc;
  477 }
  478 
  479 poptContext
  480 poptFini(poptContext con)
  481 {
  482     return poptFreeContext(con);
  483 }
  484 
  485 poptContext
  486 poptInit(int argc, const char ** argv,
  487         const struct poptOption * options, const char * configPaths)
  488 {
  489     poptContext con = NULL;
  490     const char * argv0;
  491 
  492     if (argv == NULL || argv[0] == NULL || options == NULL)
  493     return con;
  494 
  495     if ((argv0 = strrchr(argv[0], '/')) != NULL) argv0++;
  496     else argv0 = argv[0];
  497    
  498     con = poptGetContext(argv0, argc, (const char **)argv, options, 0);
  499     if (con != NULL&& poptReadConfigFiles(con, configPaths))
  500     con = poptFini(con);
  501 
  502     return con;
  503 }