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 if ((b = realloc(b, (nb + nse))) == NULL)
00325 goto exit;
00326 (void) stpcpy( stpcpy(&b[nb-1], " "), se);
00327 nb += nse;
00328 }
00329 se = b;
00330
00331
00332 { const char * longName = strrchr(fn, '/');
00333 if (longName != NULL)
00334 longName++;
00335 else
00336 longName = fn;
00337 if (longName == NULL)
00338 goto exit;
00339
00340 if (longName[1] != '\0')
00341 item->option.longName = longName;
00342 else
00343 item->option.shortName = longName[0];
00344 }
00345 }
00346
00347
00348 if (poptParseArgvString(se, &item->argc, &item->argv)) goto exit;
00349
00350
00351 item->option.argInfo = POPT_ARGFLAG_DOC_HIDDEN;
00352 for (i = 0, j = 0; i < item->argc; i++, j++) {
00353 const char * f;
00354 if (!strncmp(item->argv[i], "--POPTdesc=", sizeof("--POPTdesc=")-1)) {
00355 f = item->argv[i] + sizeof("--POPTdesc=");
00356 if (f[0] == '$' && f[1] == '"') f++;
00357 item->option.descrip = f;
00358 item->option.argInfo &= ~POPT_ARGFLAG_DOC_HIDDEN;
00359 j--;
00360 } else
00361 if (!strncmp(item->argv[i], "--POPTargs=", sizeof("--POPTargs=")-1)) {
00362 f = item->argv[i] + sizeof("--POPTargs=");
00363 if (f[0] == '$' && f[1] == '"') f++;
00364 item->option.argDescrip = f;
00365 item->option.argInfo &= ~POPT_ARGFLAG_DOC_HIDDEN;
00366 item->option.argInfo |= POPT_ARG_STRING;
00367 j--;
00368 } else
00369 if (j != i)
00370 item->argv[j] = item->argv[i];
00371 }
00372 if (j != i) {
00373 item->argv[j] = NULL;
00374 item->argc = j;
00375 }
00376
00377
00378
00379 if (!strcmp(entryType, "alias"))
00380 rc = poptAddItem(con, item, 0);
00381 else if (!strcmp(entryType, "exec"))
00382 rc = poptAddItem(con, item, 1);
00383
00384 exit:
00385 rc = 0;
00386 if (b)
00387 free(b);
00388 return rc;
00389 }
00390
00391
00392 int poptReadConfigFile(poptContext con, const char * fn)
00393 {
00394 char * b = NULL, *be;
00395 size_t nb = 0;
00396 const char *se;
00397 char *t, *te;
00398 int rc;
00399 int xx;
00400
00401 if ((rc = poptReadFile(fn, &b, &nb, POPT_READFILE_TRIMNEWLINES)) != 0)
00402 return (errno == ENOENT ? 0 : rc);
00403 if (b == NULL || nb == 0)
00404 return POPT_ERROR_BADCONFIG;
00405
00406 if ((t = malloc(nb + 1)) == NULL)
00407 goto exit;
00408 te = t;
00409
00410 be = (b + nb);
00411 for (se = b; se < be; se++) {
00412 switch (*se) {
00413 case '\n':
00414 *te = '\0';
00415 te = t;
00416 while (*te && _isspaceptr(te)) te++;
00417 if (*te && *te != '#')
00418 xx = poptConfigLine(con, te);
00419 break;
00420
00421 case '\\':
00422 *te = *se++;
00423
00424 if (se < be && *se != '\n') {
00425 te++;
00426 *te++ = *se;
00427 }
00428 break;
00429 default:
00430 *te++ = *se;
00431 break;
00432
00433 }
00434 }
00435
00436 free(t);
00437 rc = 0;
00438
00439 exit:
00440 if (b)
00441 free(b);
00442 return rc;
00443 }
00444
00445 int poptReadConfigFiles(poptContext con, const char * paths)
00446 {
00447 char * buf = (paths ? xstrdup(paths) : NULL);
00448 const char * p;
00449 char * pe;
00450 int rc = 0;
00451
00452 for (p = buf; p != NULL && *p != '\0'; p = pe) {
00453 const char ** av = NULL;
00454 int ac = 0;
00455 int i;
00456 int xx;
00457
00458
00459 pe = strchr(p, ':');
00460 if (pe != NULL && *pe == ':')
00461 *pe++ = '\0';
00462 else
00463 pe = (char *) (p + strlen(p));
00464
00465 xx = poptGlob(con, p, &ac, &av);
00466
00467
00468 for (i = 0; i < ac; i++) {
00469 const char * fn = av[i];
00470 if (av[i] == NULL)
00471 continue;
00472
00473 if (p[0] == '@' && p[1] != '(') {
00474 if (fn[0] == '@' && fn[1] != '(')
00475 fn++;
00476 xx = poptSaneFile(fn);
00477 if (!xx && rc == 0)
00478 rc = POPT_ERROR_BADCONFIG;
00479 continue;
00480 }
00481 xx = poptReadConfigFile(con, fn);
00482 if (xx && rc == 0)
00483 rc = xx;
00484 free((void *)av[i]);
00485 av[i] = NULL;
00486 }
00487 free(av);
00488 av = NULL;
00489 }
00490
00491
00492 if (buf)
00493 free(buf);
00494
00495
00496 return rc;
00497 }
00498
00499 int poptReadDefaultConfig(poptContext con, UNUSED(int useEnv))
00500 {
00501 static const char _popt_sysconfdir[] = POPT_SYSCONFDIR "/popt";
00502 static const char _popt_etc[] = "/etc/popt";
00503 char * home;
00504 struct stat sb;
00505 int rc = 0;
00506
00507 if (con->appName == NULL) goto exit;
00508
00509 if (strcmp(_popt_sysconfdir, _popt_etc)) {
00510 rc = poptReadConfigFile(con, _popt_sysconfdir);
00511 if (rc) goto exit;
00512 }
00513
00514 rc = poptReadConfigFile(con, _popt_etc);
00515 if (rc) goto exit;
00516
00517 #if defined(HAVE_GLOB_H)
00518 if (!stat("/etc/popt.d", &sb) && S_ISDIR(sb.st_mode)) {
00519 const char ** av = NULL;
00520 int ac = 0;
00521 int i;
00522
00523 if ((rc = poptGlob(con, "/etc/popt.d/*", &ac, &av)) == 0) {
00524 for (i = 0; rc == 0 && i < ac; i++) {
00525 const char * fn = av[i];
00526 if (fn == NULL || strstr(fn, ".rpmnew") || strstr(fn, ".rpmsave"))
00527 continue;
00528 if (!stat(fn, &sb)) {
00529 if (!S_ISREG(sb.st_mode) && !S_ISLNK(sb.st_mode))
00530 continue;
00531 }
00532 rc = poptReadConfigFile(con, fn);
00533 free((void *)av[i]);
00534 av[i] = NULL;
00535 }
00536 free(av);
00537 av = NULL;
00538 }
00539 }
00540 if (rc) goto exit;
00541 #endif
00542
00543 if ((home = getenv("HOME"))) {
00544 char * fn = malloc(strlen(home) + 20);
00545 if (fn != NULL) {
00546 (void) stpcpy(stpcpy(fn, home), "/.popt");
00547 rc = poptReadConfigFile(con, fn);
00548 free(fn);
00549 } else
00550 rc = POPT_ERROR_ERRNO;
00551 if (rc) goto exit;
00552 }
00553
00554 exit:
00555 return rc;
00556 }
00557
00558 poptContext
00559 poptFini(poptContext con)
00560 {
00561 return poptFreeContext(con);
00562 }
00563
00564 poptContext
00565 poptInit(int argc, const char ** argv,
00566 const struct poptOption * options, const char * configPaths)
00567 {
00568 poptContext con = NULL;
00569 const char * argv0;
00570
00571 if (argv == NULL || argv[0] == NULL || options == NULL)
00572 return con;
00573
00574 if ((argv0 = strrchr(argv[0], '/')) != NULL) argv0++;
00575 else argv0 = argv[0];
00576
00577 con = poptGetContext(argv0, argc, (const char **)argv, options, 0);
00578 if (con != NULL&& poptReadConfigFiles(con, configPaths))
00579 con = poptFini(con);
00580
00581 return con;
00582 }