00001
00005
00006
00007
00008
00009 #include "system.h"
00010 #include "poptint.h"
00011 #include <sys/stat.h>
00012
00013 #if defined(HAVE_FNMATCH_H)
00014 #include <fnmatch.h>
00015
00016 #if defined(__LCLINT__)
00017
00018 extern int fnmatch (const char *__pattern, const char *__name, int __flags)
00019 ;
00020
00021 #endif
00022 #endif
00023
00024 #if defined(HAVE_GLOB_H)
00025 #include <glob.h>
00026
00027 #if defined(__LCLINT__)
00028
00029 extern int glob (const char *__pattern, int __flags,
00030 int (*__errfunc) (const char *, int),
00031 glob_t *__pglob)
00032
00033 ;
00034
00035
00036 extern void globfree ( glob_t *__pglob)
00037 ;
00038
00039
00040 extern int glob_pattern_p (const char *__pattern, int __quote)
00041 ;
00042
00043 #endif
00044
00045 #if !defined(__GLIBC__)
00046
00047
00048 static int
00049 glob_pattern_p (const char * pattern, int quote)
00050
00051 {
00052 const char * p;
00053 int open = 0;
00054
00055 for (p = pattern; *p != '\0'; ++p)
00056 switch (*p) {
00057 case '?':
00058 case '*':
00059 return 1;
00060 break;
00061 case '\\':
00062 if (quote && p[1] != '\0')
00063 ++p;
00064 break;
00065 case '[':
00066 open = 1;
00067 break;
00068 case ']':
00069 if (open)
00070 return 1;
00071 break;
00072 }
00073 return 0;
00074 }
00075 #endif
00076
00077
00078 static int poptGlobFlags = 0;
00079
00080 static int poptGlob_error( UNUSED(const char * epath),
00081 UNUSED(int eerrno))
00082
00083 {
00084 return 1;
00085 }
00086 #endif
00087
00096 static int poptGlob( UNUSED(poptContext con), const char * pattern,
00097 int * acp, const char *** avp)
00098
00099 {
00100 const char * pat = pattern;
00101 int rc = 0;
00102
00103
00104 if (pat[0] == '@' && pat[1] != '(')
00105 pat++;
00106
00107 #if defined(HAVE_GLOB_H)
00108 if (glob_pattern_p(pat, 0)) {
00109 glob_t _g, *pglob = &_g;
00110
00111 if (!glob(pat, poptGlobFlags, poptGlob_error, pglob)) {
00112 if (acp) {
00113 *acp = (int) pglob->gl_pathc;
00114 pglob->gl_pathc = 0;
00115 }
00116 if (avp) {
00117
00118 *avp = (const char **) pglob->gl_pathv;
00119
00120 pglob->gl_pathv = NULL;
00121 }
00122
00123 globfree(pglob);
00124
00125 } else
00126 rc = POPT_ERROR_ERRNO;
00127 } else
00128 #endif
00129 {
00130 if (acp)
00131 *acp = 1;
00132 if (avp && (*avp = calloc((size_t)(1 + 1), sizeof (**avp))) != NULL)
00133 (*avp)[0] = xstrdup(pat);
00134 }
00135
00136 return rc;
00137 }
00138
00139
00140
00141 int poptSaneFile(const char * fn)
00142 {
00143 struct stat sb;
00144 uid_t uid = getuid();
00145
00146 if (stat(fn, &sb) == -1)
00147 return 1;
00148 if ((uid_t)sb.st_uid != uid)
00149 return 0;
00150 if (!S_ISREG(sb.st_mode))
00151 return 0;
00152
00153 if (sb.st_mode & (S_IWGRP|S_IWOTH))
00154 return 0;
00155
00156 return 1;
00157 }
00158
00159 int poptReadFile(const char * fn, char ** bp, size_t * nbp, int flags)
00160 {
00161 int fdno;
00162 char * b = NULL;
00163 off_t nb = 0;
00164 char * s, * t, * se;
00165 int rc = POPT_ERROR_ERRNO;
00166
00167 fdno = open(fn, O_RDONLY);
00168 if (fdno < 0)
00169 goto exit;
00170
00171 if ((nb = lseek(fdno, 0, SEEK_END)) == (off_t)-1
00172 || lseek(fdno, 0, SEEK_SET) == (off_t)-1
00173 || (b = calloc(sizeof(*b), (size_t)nb + 1)) == NULL
00174 || read(fdno, (char *)b, (size_t)nb) != (ssize_t)nb)
00175 {
00176 int oerrno = errno;
00177 (void) close(fdno);
00178 errno = oerrno;
00179 goto exit;
00180 }
00181 if (close(fdno) == -1)
00182 goto exit;
00183 if (b == NULL) {
00184 rc = POPT_ERROR_MALLOC;
00185 goto exit;
00186 }
00187 rc = 0;
00188
00189
00190
00191 if (flags & POPT_READFILE_TRIMNEWLINES)
00192
00193 {
00194 for (t = b, s = b, se = b + nb; *s && s < se; s++) {
00195 switch (*s) {
00196 case '\\':
00197 if (s[1] == '\n') {
00198 s++;
00199 continue;
00200 }
00201
00202 default:
00203 *t++ = *s;
00204 break;
00205 }
00206 }
00207 *t++ = '\0';
00208 nb = (off_t)(t - b);
00209 }
00210
00211 exit:
00212 if (rc != 0) {
00213
00214 if (b)
00215 free(b);
00216
00217 b = NULL;
00218 nb = 0;
00219 }
00220 if (bp)
00221 *bp = b;
00222
00223 else if (b)
00224 free(b);
00225
00226 if (nbp)
00227 *nbp = (size_t)nb;
00228
00229 return rc;
00230
00231 }
00232
00239 static int configAppMatch(poptContext con, const char * s)
00240
00241 {
00242 int rc = 1;
00243
00244 if (con->appName == NULL)
00245 return rc;
00246
00247 #if defined(HAVE_GLOB_H) && defined(HAVE_FNMATCH_H)
00248 if (glob_pattern_p(s, 1)) {
00249
00250 static int flags = FNM_PATHNAME | FNM_PERIOD;
00251 #ifdef FNM_EXTMATCH
00252 flags |= FNM_EXTMATCH;
00253 #endif
00254
00255 rc = fnmatch(s, con->appName, flags);
00256 } else
00257 #endif
00258 rc = strcmp(s, con->appName);
00259 return rc;
00260 }
00261
00262
00263 static int poptConfigLine(poptContext con, char * line)
00264
00265
00266 {
00267 char *b = NULL;
00268 size_t nb = 0;
00269 char * se = line;
00270 const char * appName;
00271 const char * entryType;
00272 const char * opt;
00273 struct poptItem_s item_buf;
00274 poptItem item = &item_buf;
00275 int i, j;
00276 int rc = POPT_ERROR_BADCONFIG;
00277
00278 if (con->appName == NULL)
00279 goto exit;
00280
00281 memset(item, 0, sizeof(*item));
00282
00283 appName = se;
00284 while (*se != '\0' && !_isspaceptr(se)) se++;
00285 if (*se == '\0')
00286 goto exit;
00287 else
00288 *se++ = '\0';
00289
00290 if (configAppMatch(con, appName)) goto exit;
00291
00292 while (*se != '\0' && _isspaceptr(se)) se++;
00293 entryType = se;
00294 while (*se != '\0' && !_isspaceptr(se)) se++;
00295 if (*se != '\0') *se++ = '\0';
00296
00297 while (*se != '\0' && _isspaceptr(se)) se++;
00298 if (*se == '\0') goto exit;
00299 opt = se;
00300 while (*se != '\0' && !_isspaceptr(se)) se++;
00301 if (opt[0] == '-' && *se == '\0') goto exit;
00302 if (*se != '\0') *se++ = '\0';
00303
00304 while (*se != '\0' && _isspaceptr(se)) se++;
00305 if (opt[0] == '-' && *se == '\0') goto exit;
00306
00307
00308 if (opt[0] == '-' && opt[1] == '-')
00309 item->option.longName = opt + 2;
00310 else if (opt[0] == '-' && opt[2] == '\0')
00311 item->option.shortName = opt[1];
00312 else {
00313 const char * fn = opt;
00314
00315
00316 if ((rc = poptReadFile(fn, &b, &nb, POPT_READFILE_TRIMNEWLINES)) != 0)
00317 goto exit;
00318 if (b == NULL || nb == 0)
00319 goto exit;
00320
00321
00322 if (*se != '\0') {
00323 size_t nse = strlen(se) + 1;
00324 b = realloc(b, (nb + nse));
00325 (void) stpcpy( stpcpy(&b[nb-1], " "), se);
00326 nb += nse;
00327 }
00328 se = b;
00329
00330
00331 { const char * longName = strrchr(fn, '/');
00332 if (longName != NULL)
00333 longName++;
00334 else
00335 longName = fn;
00336 if (longName == NULL)
00337 goto exit;
00338
00339 if (longName[1] != '\0')
00340 item->option.longName = longName;
00341 else
00342 item->option.shortName = longName[0];
00343 }
00344 }
00345
00346
00347 if (poptParseArgvString(se, &item->argc, &item->argv)) goto exit;
00348
00349
00350 item->option.argInfo = POPT_ARGFLAG_DOC_HIDDEN;
00351 for (i = 0, j = 0; i < item->argc; i++, j++) {
00352 const char * f;
00353 if (!strncmp(item->argv[i], "--POPTdesc=", sizeof("--POPTdesc=")-1)) {
00354 f = item->argv[i] + sizeof("--POPTdesc=");
00355 if (f[0] == '$' && f[1] == '"') f++;
00356 item->option.descrip = f;
00357 item->option.argInfo &= ~POPT_ARGFLAG_DOC_HIDDEN;
00358 j--;
00359 } else
00360 if (!strncmp(item->argv[i], "--POPTargs=", sizeof("--POPTargs=")-1)) {
00361 f = item->argv[i] + sizeof("--POPTargs=");
00362 if (f[0] == '$' && f[1] == '"') f++;
00363 item->option.argDescrip = f;
00364 item->option.argInfo &= ~POPT_ARGFLAG_DOC_HIDDEN;
00365 item->option.argInfo |= POPT_ARG_STRING;
00366 j--;
00367 } else
00368 if (j != i)
00369 item->argv[j] = item->argv[i];
00370 }
00371 if (j != i) {
00372 item->argv[j] = NULL;
00373 item->argc = j;
00374 }
00375
00376
00377
00378 if (!strcmp(entryType, "alias"))
00379 rc = poptAddItem(con, item, 0);
00380 else if (!strcmp(entryType, "exec"))
00381 rc = poptAddItem(con, item, 1);
00382
00383 exit:
00384 rc = 0;
00385 if (b)
00386 free(b);
00387 return rc;
00388 }
00389
00390
00391 int poptReadConfigFile(poptContext con, const char * fn)
00392 {
00393 char * b = NULL, *be;
00394 size_t nb = 0;
00395 const char *se;
00396 char *t, *te;
00397 int rc;
00398 int xx;
00399
00400 if ((rc = poptReadFile(fn, &b, &nb, POPT_READFILE_TRIMNEWLINES)) != 0)
00401 return (errno == ENOENT ? 0 : rc);
00402 if (b == NULL || nb == 0)
00403 return POPT_ERROR_BADCONFIG;
00404
00405 if ((t = malloc(nb + 1)) == NULL)
00406 goto exit;
00407 te = t;
00408
00409 be = (b + nb);
00410 for (se = b; se < be; se++) {
00411 switch (*se) {
00412 case '\n':
00413 *te = '\0';
00414 te = t;
00415 while (*te && _isspaceptr(te)) te++;
00416 if (*te && *te != '#')
00417 xx = poptConfigLine(con, te);
00418 break;
00419
00420 case '\\':
00421 *te = *se++;
00422
00423 if (se < be && *se != '\n') {
00424 te++;
00425 *te++ = *se;
00426 }
00427 break;
00428 default:
00429 *te++ = *se;
00430 break;
00431
00432 }
00433 }
00434
00435 free(t);
00436 rc = 0;
00437
00438 exit:
00439 if (b)
00440 free(b);
00441 return rc;
00442 }
00443
00444 int poptReadConfigFiles(poptContext con, const char * paths)
00445 {
00446 char * buf = (paths ? xstrdup(paths) : NULL);
00447 const char * p;
00448 char * pe;
00449 int rc = 0;
00450
00451 for (p = buf; p != NULL && *p != '\0'; p = pe) {
00452 const char ** av = NULL;
00453 int ac = 0;
00454 int i;
00455 int xx;
00456
00457
00458 pe = strchr(p, ':');
00459 if (pe != NULL && *pe == ':')
00460 *pe++ = '\0';
00461 else
00462 pe = (char *) (p + strlen(p));
00463
00464 xx = poptGlob(con, p, &ac, &av);
00465
00466
00467 for (i = 0; i < ac; i++) {
00468 const char * fn = av[i];
00469 if (av[i] == NULL)
00470 continue;
00471
00472 if (p[0] == '@' && p[1] != '(') {
00473 if (fn[0] == '@' && fn[1] != '(')
00474 fn++;
00475 xx = poptSaneFile(fn);
00476 if (!xx && rc == 0)
00477 rc = POPT_ERROR_BADCONFIG;
00478 continue;
00479 }
00480 xx = poptReadConfigFile(con, fn);
00481 if (xx && rc == 0)
00482 rc = xx;
00483 free((void *)av[i]);
00484 av[i] = NULL;
00485 }
00486 free(av);
00487 av = NULL;
00488 }
00489
00490
00491 if (buf)
00492 free(buf);
00493
00494
00495 return rc;
00496 }
00497
00498 int poptReadDefaultConfig(poptContext con, UNUSED(int useEnv))
00499 {
00500 static const char _popt_sysconfdir[] = POPT_SYSCONFDIR "/popt";
00501 static const char _popt_etc[] = "/etc/popt";
00502 char * home;
00503 struct stat sb;
00504 int rc = 0;
00505
00506 if (con->appName == NULL) goto exit;
00507
00508 if (strcmp(_popt_sysconfdir, _popt_etc)) {
00509 rc = poptReadConfigFile(con, _popt_sysconfdir);
00510 if (rc) goto exit;
00511 }
00512
00513 rc = poptReadConfigFile(con, _popt_etc);
00514 if (rc) goto exit;
00515
00516 #if defined(HAVE_GLOB_H)
00517 if (!stat("/etc/popt.d", &sb) && S_ISDIR(sb.st_mode)) {
00518 const char ** av = NULL;
00519 int ac = 0;
00520 int i;
00521
00522 if ((rc = poptGlob(con, "/etc/popt.d/*", &ac, &av)) == 0) {
00523 for (i = 0; rc == 0 && i < ac; i++) {
00524 const char * fn = av[i];
00525 if (fn == NULL || strstr(fn, ".rpmnew") || strstr(fn, ".rpmsave"))
00526 continue;
00527 if (!stat(fn, &sb)) {
00528 if (!S_ISREG(sb.st_mode) && !S_ISLNK(sb.st_mode))
00529 continue;
00530 }
00531 rc = poptReadConfigFile(con, fn);
00532 free((void *)av[i]);
00533 av[i] = NULL;
00534 }
00535 free(av);
00536 av = NULL;
00537 }
00538 }
00539 if (rc) goto exit;
00540 #endif
00541
00542 if ((home = getenv("HOME"))) {
00543 char * fn = malloc(strlen(home) + 20);
00544 if (fn != NULL) {
00545 (void) stpcpy(stpcpy(fn, home), "/.popt");
00546 rc = poptReadConfigFile(con, fn);
00547 free(fn);
00548 } else
00549 rc = POPT_ERROR_ERRNO;
00550 if (rc) goto exit;
00551 }
00552
00553 exit:
00554 return rc;
00555 }
00556
00557 poptContext
00558 poptFini(poptContext con)
00559 {
00560 return poptFreeContext(con);
00561 }
00562
00563 poptContext
00564 poptInit(int argc, const char ** argv,
00565 const struct poptOption * options, const char * configPaths)
00566 {
00567 poptContext con = NULL;
00568 const char * argv0;
00569
00570 if (argv == NULL || argv[0] == NULL || options == NULL)
00571 return con;
00572
00573 if ((argv0 = strrchr(argv[0], '/')) != NULL) argv0++;
00574 else argv0 = argv[0];
00575
00576 con = poptGetContext(argv0, argc, (const char **)argv, options, 0);
00577 if (con != NULL&& poptReadConfigFiles(con, configPaths))
00578 con = poptFini(con);
00579
00580 return con;
00581 }