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 == NULL || 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 == NULL || 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 (con == NULL) return POPT_ERROR_NOCONTEXT;
402 
403  if ((rc = poptReadFile(fn, &b, &nb, POPT_READFILE_TRIMNEWLINES)) != 0)
404  return (errno == ENOENT ? 0 : rc);
405  if (b == NULL || nb == 0)
406  return POPT_ERROR_BADCONFIG;
407 
408  if ((t = malloc(nb + 1)) == NULL)
409  goto exit;
410  te = t;
411 
412  be = (b + nb);
413  for (se = b; se < be; se++) {
414  switch (*se) {
415  case '\n':
416  *te = '\0';
417  te = t;
418  while (*te && _isspaceptr(te)) te++;
419  if (*te && *te != '#')
420  xx = poptConfigLine(con, te);
421  /*@switchbreak@*/ break;
422 /*@-usedef@*/ /* XXX *se may be uninitialized */
423  case '\\':
424  *te = *se++;
425  /* \ at the end of a line does not insert a \n */
426  if (se < be && *se != '\n') {
427  te++;
428  *te++ = *se;
429  }
430  /*@switchbreak@*/ break;
431  default:
432  *te++ = *se;
433  /*@switchbreak@*/ break;
434 /*@=usedef@*/
435  }
436  }
437 
438  free(t);
439  rc = 0;
440 
441 exit:
442  if (b)
443  free(b);
444  return rc;
445 }
446 
447 int poptReadConfigFiles(poptContext con, const char * paths)
448 {
449  char * buf = (paths ? xstrdup(paths) : NULL);
450  const char * p;
451  char * pe;
452  int rc = 0; /* assume success */
453 
454  for (p = buf; p != NULL && *p != '\0'; p = pe) {
455  const char ** av = NULL;
456  int ac = 0;
457  int i;
458  int xx;
459 
460  /* locate start of next path element */
461  pe = strchr(p, ':');
462  if (pe != NULL && *pe == ':')
463  *pe++ = '\0';
464  else
465  pe = (char *) (p + strlen(p));
466 
467  xx = poptGlob(con, p, &ac, &av);
468 
469  /* work-off each resulting file from the path element */
470  for (i = 0; i < ac; i++) {
471  const char * fn = av[i];
472  if (av[i] == NULL) /* XXX can't happen */
473  /*@innercontinue@*/ continue;
474  /* XXX should '@' attention be pushed into poptReadConfigFile? */
475  if (p[0] == '@' && p[1] != '(') {
476  if (fn[0] == '@' && fn[1] != '(')
477  fn++;
478  xx = poptSaneFile(fn);
479  if (!xx && rc == 0)
481  /*@innercontinue@*/ continue;
482  }
483  xx = poptReadConfigFile(con, fn);
484  if (xx && rc == 0)
485  rc = xx;
486  free((void *)av[i]);
487  av[i] = NULL;
488  }
489  free(av);
490  av = NULL;
491  }
492 
493 /*@-usedef@*/
494  if (buf)
495  free(buf);
496 /*@=usedef@*/
497 
498  return rc;
499 }
500 
501 int poptReadDefaultConfig(poptContext con, /*@unused@*/ UNUSED(int useEnv))
502 {
503  static const char _popt_sysconfdir[] = POPT_SYSCONFDIR "/popt";
504  static const char _popt_etc[] = "/etc/popt";
505  char * home;
506  struct stat sb;
507  int rc = 0; /* assume success */
508 
509  if (con == NULL || con->appName == NULL) goto exit;
510 
511  if (strcmp(_popt_sysconfdir, _popt_etc)) {
512  rc = poptReadConfigFile(con, _popt_sysconfdir);
513  if (rc) goto exit;
514  }
515 
516  rc = poptReadConfigFile(con, _popt_etc);
517  if (rc) goto exit;
518 
519 #if defined(HAVE_GLOB_H)
520  if (!stat("/etc/popt.d", &sb) && S_ISDIR(sb.st_mode)) {
521  const char ** av = NULL;
522  int ac = 0;
523  int i;
524 
525  if ((rc = poptGlob(con, "/etc/popt.d/*", &ac, &av)) == 0) {
526  for (i = 0; rc == 0 && i < ac; i++) {
527  const char * fn = av[i];
528  if (fn == NULL || strstr(fn, ".rpmnew") || strstr(fn, ".rpmsave"))
529  continue;
530  if (!stat(fn, &sb)) {
531  if (!S_ISREG(sb.st_mode) && !S_ISLNK(sb.st_mode))
532  continue;
533  }
534  rc = poptReadConfigFile(con, fn);
535  free((void *)av[i]);
536  av[i] = NULL;
537  }
538  free(av);
539  av = NULL;
540  }
541  }
542  if (rc) goto exit;
543 #endif
544 
545  if ((home = getenv("HOME"))) {
546  char * fn = malloc(strlen(home) + 20);
547  if (fn != NULL) {
548  (void) stpcpy(stpcpy(fn, home), "/.popt");
549  rc = poptReadConfigFile(con, fn);
550  free(fn);
551  } else
552  rc = POPT_ERROR_ERRNO;
553  if (rc) goto exit;
554  }
555 
556 exit:
557  return rc;
558 }
559 
562 {
563  return poptFreeContext(con);
564 }
565 
567 poptInit(int argc, const char ** argv,
568  const struct poptOption * options, const char * configPaths)
569 {
570  poptContext con = NULL;
571  const char * argv0;
572 
573  if (argv == NULL || argv[0] == NULL || options == NULL)
574  return con;
575 
576  if ((argv0 = strrchr(argv[0], '/')) != NULL) argv0++;
577  else argv0 = argv[0];
578 
579  con = poptGetContext(argv0, argc, (const char **)argv, options, 0);
580  if (con != NULL&& poptReadConfigFiles(con, configPaths))
581  con = poptFini(con);
582 
583  return con;
584 }
poptSaneFile
int poptSaneFile(const char *fn)
Definition: poptconfig.c:141
poptFini
poptContext poptFini(poptContext con)
Definition: poptconfig.c:561
stpcpy
static char * stpcpy(char *dest, const char *src)
Definition: system.h:69
poptFreeContext
poptContext poptFreeContext(poptContext con)
Definition: popt.c:1624
poptReadDefaultConfig
int poptReadDefaultConfig(poptContext con, int useEnv)
Definition: poptconfig.c:501
poptContext_s
Definition: poptint.h:115
POPT_READFILE_TRIMNEWLINES
#define POPT_READFILE_TRIMNEWLINES
Definition: popt.h:413
POPT_ERROR_ERRNO
#define POPT_ERROR_ERRNO
Definition: popt.h:97
poptInit
poptContext poptInit(int argc, const char **argv, const struct poptOption *options, const char *configPaths)
Definition: poptconfig.c:567
POPT_ARGFLAG_DOC_HIDDEN
#define POPT_ARGFLAG_DOC_HIDDEN
Definition: popt.h:53
poptint.h
poptReadConfigFiles
int poptReadConfigFiles(poptContext con, const char *paths)
Definition: poptconfig.c:447
poptContext_s::appName
const char * appName
Definition: poptint.h:127
POPT_ERROR_NOCONTEXT
#define POPT_ERROR_NOCONTEXT
Definition: popt.h:103
UNUSED
#define UNUSED(x)
Definition: system.h:105
configAppMatch
static int configAppMatch(poptContext con, const char *s)
Check for application match.
Definition: poptconfig.c:239
poptGlob
static int poptGlob(poptContext con, const char *pattern, int *acp, const char ***avp)
Return path(s) from a glob pattern.
Definition: poptconfig.c:96
POPT_ARG_STRING
#define POPT_ARG_STRING
Definition: popt.h:21
POPT_ERROR_BADCONFIG
#define POPT_ERROR_BADCONFIG
Definition: popt.h:104
system.h
poptAddItem
int poptAddItem(poptContext con, poptItem newItem, int flags)
Definition: popt.c:1668
poptParseArgvString
int poptParseArgvString(const char *s, int *argcPtr, const char ***argvPtr)
Definition: poptparse.c:54
POPT_ERROR_MALLOC
#define POPT_ERROR_MALLOC
Definition: popt.h:102
poptReadFile
int poptReadFile(const char *fn, char **bp, size_t *nbp, int flags)
Read a file into a buffer.
Definition: poptconfig.c:159
poptItem_s
Definition: popt.h:157
poptReadConfigFile
int poptReadConfigFile(poptContext con, const char *fn)
Definition: poptconfig.c:392
poptGetContext
poptContext poptGetContext(const char *name, int argc, const char **argv, const struct poptOption *options, unsigned int flags)
Definition: popt.c:169
_isspaceptr
#define _isspaceptr(_chp)
Definition: system.h:21
poptConfigLine
static int poptConfigLine(poptContext con, char *line)
Definition: poptconfig.c:263
xstrdup
char * xstrdup(const char *str)
poptOption
Definition: popt.h:127

Generated for popt by  doxygen 1.8.17