popt  1.16
poptconfig.c
Go to the documentation of this file.
1 
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 
13 #if defined(HAVE_FNMATCH_H)
14 #include <fnmatch.h>
15 
16 #if defined(__LCLINT__)
17 /*@-declundef -exportheader -incondefs -protoparammatch -redecl -type @*/
18 extern int fnmatch (const char *__pattern, const char *__name, int __flags)
19  /*@*/;
20 /*@=declundef =exportheader =incondefs =protoparammatch =redecl =type @*/
21 #endif /* __LCLINT__ */
22 #endif
23 
24 #if defined(HAVE_GLOB_H)
25 #include <glob.h>
26 
27 #if defined(__LCLINT__)
28 /*@-declundef -exportheader -incondefs -protoparammatch -redecl -type @*/
29 extern int glob (const char *__pattern, int __flags,
30  /*@null@*/ int (*__errfunc) (const char *, int),
31  /*@out@*/ glob_t *__pglob)
32  /*@globals errno, fileSystem @*/
33  /*@modifies *__pglob, errno, fileSystem @*/;
34 
35 /* XXX only annotation is a white lie */
36 extern void globfree (/*@only@*/ glob_t *__pglob)
37  /*@modifies *__pglob @*/;
38 
39 /* XXX _GNU_SOURCE ifdef and/or retrofit is needed for portability. */
40 extern int glob_pattern_p (const char *__pattern, int __quote)
41  /*@*/;
42 /*@=declundef =exportheader =incondefs =protoparammatch =redecl =type @*/
43 #endif /* __LCLINT__ */
44 
45 #if !defined(__GLIBC__)
46 /* Return nonzero if PATTERN contains any metacharacters.
47  Metacharacters can be quoted with backslashes if QUOTE is nonzero. */
48 static int
49 glob_pattern_p (const char * pattern, int quote)
50  /*@*/
51 {
52  const char * p;
53  int open = 0;
54 
55  for (p = pattern; *p != '\0'; ++p)
56  switch (*p) {
57  case '?':
58  case '*':
59  return 1;
60  /*@notreached@*/ /*@switchbreak@*/ break;
61  case '\\':
62  if (quote && p[1] != '\0')
63  ++p;
64  /*@switchbreak@*/ break;
65  case '[':
66  open = 1;
67  /*@switchbreak@*/ break;
68  case ']':
69  if (open)
70  return 1;
71  /*@switchbreak@*/ break;
72  }
73  return 0;
74 }
75 #endif /* !defined(__GLIBC__) */
76 
77 /*@unchecked@*/
78 static int poptGlobFlags = 0;
79 
80 static int poptGlob_error(/*@unused@*/ UNUSED(const char * epath),
81  /*@unused@*/ UNUSED(int eerrno))
82  /*@*/
83 {
84  return 1;
85 }
86 #endif /* HAVE_GLOB_H */
87 
96 static int poptGlob(/*@unused@*/ UNUSED(poptContext con), const char * pattern,
97  /*@out@*/ int * acp, /*@out@*/ const char *** avp)
98  /*@modifies *acp, *avp @*/
99 {
100  const char * pat = pattern;
101  int rc = 0; /* assume success */
102 
103  /* XXX skip the attention marker. */
104  if (pat[0] == '@' && pat[1] != '(')
105  pat++;
106 
107 #if defined(HAVE_GLOB_H)
108  if (glob_pattern_p(pat, 0)) {
109  glob_t _g, *pglob = &_g;
110 
111  if (!glob(pat, poptGlobFlags, poptGlob_error, pglob)) {
112  if (acp) {
113  *acp = (int) pglob->gl_pathc;
114  pglob->gl_pathc = 0;
115  }
116  if (avp) {
117 /*@-onlytrans@*/
118  *avp = (const char **) pglob->gl_pathv;
119 /*@=onlytrans@*/
120  pglob->gl_pathv = NULL;
121  }
122 /*@-nullstate@*/
123  globfree(pglob);
124 /*@=nullstate@*/
125  } else
126  rc = POPT_ERROR_ERRNO;
127  } else
128 #endif /* HAVE_GLOB_H */
129  {
130  if (acp)
131  *acp = 1;
132  if (avp && (*avp = calloc((size_t)(1 + 1), sizeof (**avp))) != NULL)
133  (*avp)[0] = xstrdup(pat);
134  }
135 
136  return rc;
137 }
138 
139 /*@access poptContext @*/
140 
141 int poptSaneFile(const char * fn)
142 {
143  struct stat sb;
144  uid_t uid = getuid();
145 
146  if (stat(fn, &sb) == -1)
147  return 1;
148  if ((uid_t)sb.st_uid != uid)
149  return 0;
150  if (!S_ISREG(sb.st_mode))
151  return 0;
152 /*@-bitwisesigned@*/
153  if (sb.st_mode & (S_IWGRP|S_IWOTH))
154  return 0;
155 /*@=bitwisesigned@*/
156  return 1;
157 }
158 
159 int poptReadFile(const char * fn, char ** bp, size_t * nbp, int flags)
160 {
161  int fdno;
162  char * b = NULL;
163  off_t nb = 0;
164  char * s, * t, * se;
165  int rc = POPT_ERROR_ERRNO; /* assume failure */
166 
167  fdno = open(fn, O_RDONLY);
168  if (fdno < 0)
169  goto exit;
170 
171  if ((nb = lseek(fdno, 0, SEEK_END)) == (off_t)-1
172  || lseek(fdno, 0, SEEK_SET) == (off_t)-1
173  || (b = calloc(sizeof(*b), (size_t)nb + 1)) == NULL
174  || read(fdno, (char *)b, (size_t)nb) != (ssize_t)nb)
175  {
176  int oerrno = errno;
177  (void) close(fdno);
178  errno = oerrno;
179  goto exit;
180  }
181  if (close(fdno) == -1)
182  goto exit;
183  if (b == NULL) {
184  rc = POPT_ERROR_MALLOC;
185  goto exit;
186  }
187  rc = 0;
188 
189  /* Trim out escaped newlines. */
190 /*@-bitwisesigned@*/
191  if (flags & POPT_READFILE_TRIMNEWLINES)
192 /*@=bitwisesigned@*/
193  {
194  for (t = b, s = b, se = b + nb; *s && s < se; s++) {
195  switch (*s) {
196  case '\\':
197  if (s[1] == '\n') {
198  s++;
199  continue;
200  }
201  /*@fallthrough@*/
202  default:
203  *t++ = *s;
204  /*@switchbreak@*/ break;
205  }
206  }
207  *t++ = '\0';
208  nb = (off_t)(t - b);
209  }
210 
211 exit:
212  if (rc != 0) {
213 /*@-usedef@*/
214  if (b)
215  free(b);
216 /*@=usedef@*/
217  b = NULL;
218  nb = 0;
219  }
220  if (bp)
221  *bp = b;
222 /*@-usereleased@*/
223  else if (b)
224  free(b);
225 /*@=usereleased@*/
226  if (nbp)
227  *nbp = (size_t)nb;
228 /*@-compdef -nullstate @*/ /* XXX cannot annotate char ** correctly */
229  return rc;
230 /*@=compdef =nullstate @*/
231 }
232 
239 static int configAppMatch(poptContext con, const char * s)
240  /*@*/
241 {
242  int rc = 1;
243 
244  if (con->appName == NULL) /* XXX can't happen. */
245  return rc;
246 
247 #if defined(HAVE_GLOB_H) && defined(HAVE_FNMATCH_H)
248  if (glob_pattern_p(s, 1)) {
249 /*@-bitwisesigned@*/
250  static int flags = FNM_PATHNAME | FNM_PERIOD;
251 #ifdef FNM_EXTMATCH
252  flags |= FNM_EXTMATCH;
253 #endif
254 /*@=bitwisesigned@*/
255  rc = fnmatch(s, con->appName, flags);
256  } else
257 #endif
258  rc = strcmp(s, con->appName);
259  return rc;
260 }
261 
262 /*@-compmempass@*/ /* FIX: item->option.longName kept, not dependent. */
263 static int poptConfigLine(poptContext con, char * line)
264  /*@globals fileSystem, internalState @*/
265  /*@modifies con, fileSystem, internalState @*/
266 {
267  char *b = NULL;
268  size_t nb = 0;
269  char * se = line;
270  const char * appName;
271  const char * entryType;
272  const char * opt;
273  struct poptItem_s item_buf;
274  poptItem item = &item_buf;
275  int i, j;
276  int rc = POPT_ERROR_BADCONFIG;
277 
278  if (con->appName == NULL)
279  goto exit;
280 
281  memset(item, 0, sizeof(*item));
282 
283  appName = se;
284  while (*se != '\0' && !_isspaceptr(se)) se++;
285  if (*se == '\0')
286  goto exit;
287  else
288  *se++ = '\0';
289 
290  if (configAppMatch(con, appName)) goto exit;
291 
292  while (*se != '\0' && _isspaceptr(se)) se++;
293  entryType = se;
294  while (*se != '\0' && !_isspaceptr(se)) se++;
295  if (*se != '\0') *se++ = '\0';
296 
297  while (*se != '\0' && _isspaceptr(se)) se++;
298  if (*se == '\0') goto exit;
299  opt = se;
300  while (*se != '\0' && !_isspaceptr(se)) se++;
301  if (opt[0] == '-' && *se == '\0') goto exit;
302  if (*se != '\0') *se++ = '\0';
303 
304  while (*se != '\0' && _isspaceptr(se)) se++;
305  if (opt[0] == '-' && *se == '\0') goto exit;
306 
307 /*@-temptrans@*/ /* FIX: line alias is saved */
308  if (opt[0] == '-' && opt[1] == '-')
309  item->option.longName = opt + 2;
310  else if (opt[0] == '-' && opt[2] == '\0')
311  item->option.shortName = opt[1];
312  else {
313  const char * fn = opt;
314 
315  /* XXX handle globs and directories in fn? */
316  if ((rc = poptReadFile(fn, &b, &nb, POPT_READFILE_TRIMNEWLINES)) != 0)
317  goto exit;
318  if (b == NULL || nb == 0)
319  goto exit;
320 
321  /* Append remaining text to the interpolated file option text. */
322  if (*se != '\0') {
323  size_t nse = strlen(se) + 1;
324  if ((b = realloc(b, (nb + nse))) == NULL) /* XXX can't happen */
325  goto exit;
326  (void) stpcpy( stpcpy(&b[nb-1], " "), se);
327  nb += nse;
328  }
329  se = b;
330 
331  /* Use the basename of the path as the long option name. */
332  { const char * longName = strrchr(fn, '/');
333  if (longName != NULL)
334  longName++;
335  else
336  longName = fn;
337  if (longName == NULL) /* XXX can't happen. */
338  goto exit;
339  /* Single character basenames are treated as short options. */
340  if (longName[1] != '\0')
341  item->option.longName = longName;
342  else
343  item->option.shortName = longName[0];
344  }
345  }
346 /*@=temptrans@*/
347 
348  if (poptParseArgvString(se, &item->argc, &item->argv)) goto exit;
349 
350 /*@-modobserver@*/
351  item->option.argInfo = POPT_ARGFLAG_DOC_HIDDEN;
352  for (i = 0, j = 0; i < item->argc; i++, j++) {
353  const char * f;
354  if (!strncmp(item->argv[i], "--POPTdesc=", sizeof("--POPTdesc=")-1)) {
355  f = item->argv[i] + sizeof("--POPTdesc=");
356  if (f[0] == '$' && f[1] == '"') f++;
357  item->option.descrip = f;
358  item->option.argInfo &= ~POPT_ARGFLAG_DOC_HIDDEN;
359  j--;
360  } else
361  if (!strncmp(item->argv[i], "--POPTargs=", sizeof("--POPTargs=")-1)) {
362  f = item->argv[i] + sizeof("--POPTargs=");
363  if (f[0] == '$' && f[1] == '"') f++;
364  item->option.argDescrip = f;
365  item->option.argInfo &= ~POPT_ARGFLAG_DOC_HIDDEN;
366  item->option.argInfo |= POPT_ARG_STRING;
367  j--;
368  } else
369  if (j != i)
370  item->argv[j] = item->argv[i];
371  }
372  if (j != i) {
373  item->argv[j] = NULL;
374  item->argc = j;
375  }
376 /*@=modobserver@*/
377 
378 /*@-nullstate@*/ /* FIX: item->argv[] may be NULL */
379  if (!strcmp(entryType, "alias"))
380  rc = poptAddItem(con, item, 0);
381  else if (!strcmp(entryType, "exec"))
382  rc = poptAddItem(con, item, 1);
383 /*@=nullstate@*/
384 exit:
385  rc = 0; /* XXX for now, always return success */
386  if (b)
387  free(b);
388  return rc;
389 }
390 /*@=compmempass@*/
391 
392 int poptReadConfigFile(poptContext con, const char * fn)
393 {
394  char * b = NULL, *be;
395  size_t nb = 0;
396  const char *se;
397  char *t, *te;
398  int rc;
399  int xx;
400 
401  if ((rc = poptReadFile(fn, &b, &nb, POPT_READFILE_TRIMNEWLINES)) != 0)
402  return (errno == ENOENT ? 0 : rc);
403  if (b == NULL || nb == 0)
404  return POPT_ERROR_BADCONFIG;
405 
406  if ((t = malloc(nb + 1)) == NULL)
407  goto exit;
408  te = t;
409 
410  be = (b + nb);
411  for (se = b; se < be; se++) {
412  switch (*se) {
413  case '\n':
414  *te = '\0';
415  te = t;
416  while (*te && _isspaceptr(te)) te++;
417  if (*te && *te != '#')
418  xx = poptConfigLine(con, te);
419  /*@switchbreak@*/ break;
420 /*@-usedef@*/ /* XXX *se may be uninitialized */
421  case '\\':
422  *te = *se++;
423  /* \ at the end of a line does not insert a \n */
424  if (se < be && *se != '\n') {
425  te++;
426  *te++ = *se;
427  }
428  /*@switchbreak@*/ break;
429  default:
430  *te++ = *se;
431  /*@switchbreak@*/ break;
432 /*@=usedef@*/
433  }
434  }
435 
436  free(t);
437  rc = 0;
438 
439 exit:
440  if (b)
441  free(b);
442  return rc;
443 }
444 
445 int poptReadConfigFiles(poptContext con, const char * paths)
446 {
447  char * buf = (paths ? xstrdup(paths) : NULL);
448  const char * p;
449  char * pe;
450  int rc = 0; /* assume success */
451 
452  for (p = buf; p != NULL && *p != '\0'; p = pe) {
453  const char ** av = NULL;
454  int ac = 0;
455  int i;
456  int xx;
457 
458  /* locate start of next path element */
459  pe = strchr(p, ':');
460  if (pe != NULL && *pe == ':')
461  *pe++ = '\0';
462  else
463  pe = (char *) (p + strlen(p));
464 
465  xx = poptGlob(con, p, &ac, &av);
466 
467  /* work-off each resulting file from the path element */
468  for (i = 0; i < ac; i++) {
469  const char * fn = av[i];
470  if (av[i] == NULL) /* XXX can't happen */
471  /*@innercontinue@*/ continue;
472  /* XXX should '@' attention be pushed into poptReadConfigFile? */
473  if (p[0] == '@' && p[1] != '(') {
474  if (fn[0] == '@' && fn[1] != '(')
475  fn++;
476  xx = poptSaneFile(fn);
477  if (!xx && rc == 0)
479  /*@innercontinue@*/ continue;
480  }
481  xx = poptReadConfigFile(con, fn);
482  if (xx && rc == 0)
483  rc = xx;
484  free((void *)av[i]);
485  av[i] = NULL;
486  }
487  free(av);
488  av = NULL;
489  }
490 
491 /*@-usedef@*/
492  if (buf)
493  free(buf);
494 /*@=usedef@*/
495 
496  return rc;
497 }
498 
499 int poptReadDefaultConfig(poptContext con, /*@unused@*/ UNUSED(int useEnv))
500 {
501  static const char _popt_sysconfdir[] = POPT_SYSCONFDIR "/popt";
502  static const char _popt_etc[] = "/etc/popt";
503  char * home;
504  struct stat sb;
505  int rc = 0; /* assume success */
506 
507  if (con->appName == NULL) goto exit;
508 
509  if (strcmp(_popt_sysconfdir, _popt_etc)) {
510  rc = poptReadConfigFile(con, _popt_sysconfdir);
511  if (rc) goto exit;
512  }
513 
514  rc = poptReadConfigFile(con, _popt_etc);
515  if (rc) goto exit;
516 
517 #if defined(HAVE_GLOB_H)
518  if (!stat("/etc/popt.d", &sb) && S_ISDIR(sb.st_mode)) {
519  const char ** av = NULL;
520  int ac = 0;
521  int i;
522 
523  if ((rc = poptGlob(con, "/etc/popt.d/*", &ac, &av)) == 0) {
524  for (i = 0; rc == 0 && i < ac; i++) {
525  const char * fn = av[i];
526  if (fn == NULL || strstr(fn, ".rpmnew") || strstr(fn, ".rpmsave"))
527  continue;
528  if (!stat(fn, &sb)) {
529  if (!S_ISREG(sb.st_mode) && !S_ISLNK(sb.st_mode))
530  continue;
531  }
532  rc = poptReadConfigFile(con, fn);
533  free((void *)av[i]);
534  av[i] = NULL;
535  }
536  free(av);
537  av = NULL;
538  }
539  }
540  if (rc) goto exit;
541 #endif
542 
543  if ((home = getenv("HOME"))) {
544  char * fn = malloc(strlen(home) + 20);
545  if (fn != NULL) {
546  (void) stpcpy(stpcpy(fn, home), "/.popt");
547  rc = poptReadConfigFile(con, fn);
548  free(fn);
549  } else
550  rc = POPT_ERROR_ERRNO;
551  if (rc) goto exit;
552  }
553 
554 exit:
555  return rc;
556 }
557 
560 {
561  return poptFreeContext(con);
562 }
563 
565 poptInit(int argc, const char ** argv,
566  const struct poptOption * options, const char * configPaths)
567 {
568  poptContext con = NULL;
569  const char * argv0;
570 
571  if (argv == NULL || argv[0] == NULL || options == NULL)
572  return con;
573 
574  if ((argv0 = strrchr(argv[0], '/')) != NULL) argv0++;
575  else argv0 = argv[0];
576 
577  con = poptGetContext(argv0, argc, (const char **)argv, options, 0);
578  if (con != NULL&& poptReadConfigFiles(con, configPaths))
579  con = poptFini(con);
580 
581  return con;
582 }
poptContext poptInit(int argc, const char **argv, const struct poptOption *options, const char *configPaths)
Initialize popt context (alternative implementation).
Definition: poptconfig.c:565
int poptParseArgvString(const char *s, int *argcPtr, const char ***argvPtr)
Parse a string into an argument array.
Definition: poptparse.c:54
#define POPT_ERROR_ERRNO
Definition: popt.h:104
static char * stpcpy(char *dest, const char *src)
Definition: system.h:69
A popt alias or exec argument for poptAddItem().
Definition: popt.h:162
static int configAppMatch(poptContext con, const char *s)
Check for application match.
Definition: poptconfig.c:239
int poptSaneFile(const char *fn)
Perform sanity checks on a file path.
Definition: poptconfig.c:141
#define POPT_ERROR_BADCONFIG
Definition: popt.h:110
poptContext poptGetContext(const char *name, int argc, const char **argv, const struct poptOption *options, unsigned int flags)
Initialize popt context.
Definition: popt.c:168
#define UNUSED(x)
Definition: system.h:101
poptContext poptFini(poptContext con)
Destroy context (alternative implementation).
Definition: poptconfig.c:559
int poptReadFile(const char *fn, char **bp, size_t *nbp, int flags)
Read a file into a buffer.
Definition: poptconfig.c:159
const char * appName
Definition: poptint.h:127
#define POPT_ARGFLAG_DOC_HIDDEN
Definition: popt.h:59
int poptReadConfigFiles(poptContext con, const char *paths)
Read configuration file(s).
Definition: poptconfig.c:445
poptContext poptFreeContext(poptContext con)
Destroy context.
Definition: popt.c:1613
char * xstrdup(const char *str)
int poptReadConfigFile(poptContext con, const char *fn)
Read configuration file.
Definition: poptconfig.c:392
#define POPT_READFILE_TRIMNEWLINES
Definition: popt.h:418
static int poptConfigLine(poptContext con, char *line)
Definition: poptconfig.c:263
int poptAddItem(poptContext con, poptItem newItem, int flags)
Add alias/exec item to context.
Definition: popt.c:1654
#define _isspaceptr(_chp)
Definition: system.h:21
static int poptGlob(poptContext con, const char *pattern, int *acp, const char ***avp)
Return path(s) from a glob pattern.
Definition: poptconfig.c:96
#define POPT_ARG_STRING
Definition: popt.h:21
#define POPT_ERROR_MALLOC
Definition: popt.h:109
int poptReadDefaultConfig(poptContext con, int useEnv)
Read default configuration from /etc/popt and $HOME/.popt.
Definition: poptconfig.c:499

Generated for popt by  doxygen 1.8.13