rpm 5.3.12
|
00001 #include "system.h" 00002 /*@unchecked@*/ 00003 extern const char * __progname; 00004 00005 #define _RPMIOB_INTERNAL 00006 #include <rpmiotypes.h> 00007 #include <rpmio_internal.h> /* XXX fdGetFILE */ 00008 #include <poptIO.h> 00009 #include "debug.h" 00010 00011 static int _rpmdc_debug = 0; 00012 00013 /* XXX older 0install manifest format. */ 00014 static int _old_0install = 0; 00015 00016 #define _KFB(n) (1U << (n)) 00017 #define _DFB(n) (_KFB(n) | 0x40000000) 00018 00019 #define F_ISSET(_dc, _FLAG) ((_dc)->flags & ((RPMDC_FLAGS_##_FLAG) & ~0x40000000)) 00020 00024 enum dcFlags_e { 00025 RPMDC_FLAGS_NONE = 0, 00026 /* 0 reserved */ 00027 RPMDC_FLAGS_WARN = _DFB( 1), 00028 RPMDC_FLAGS_CREATE = _DFB( 2), 00029 RPMDC_FLAGS_DIRSONLY = _DFB( 3), 00030 /* 4-13 reserved */ 00031 RPMDC_FLAGS_BINARY = _DFB(14), 00032 RPMDC_FLAGS_STATUS = _DFB(15), 00033 RPMDC_FLAGS_0INSTALL = _DFB(16), 00034 RPMDC_FLAGS_HMAC = _DFB(17), 00035 /* 18-31 unused */ 00036 }; 00037 00040 typedef struct rpmdc_s * rpmdc; 00041 00044 struct rpmdc_s { 00045 int ftsoptions; 00046 FTS * t; 00047 FTSENT * p; 00048 struct stat sb; 00050 enum dcFlags_e flags; 00051 uint32_t algo; 00052 uint32_t dalgo; 00053 /*@observer@*/ /*@null@*/ 00054 const char * dalgoName; 00055 const char * digest; 00056 size_t digestlen; 00057 const char * fn; 00058 FD_t fd; 00059 int (*parse) (rpmdc dc); 00060 const char * (*print) (rpmdc dc, int rc); 00061 const char * ofn; 00062 FD_t ofd; 00063 uint32_t oalgo; 00064 const char * oalgoName; 00065 ARGV_t manifests; 00066 ARGI_t algos; 00067 ARGV_t digests; 00068 ARGV_t paths; 00069 unsigned char buf[BUFSIZ]; 00070 ssize_t nb; 00071 int ix; 00072 00073 size_t ncomputed; 00074 size_t nchecked; 00075 size_t nmatched; 00076 size_t nfailed; 00077 struct rpmop_s totalops; 00078 struct rpmop_s readops; 00079 struct rpmop_s digestops; 00080 }; 00081 00084 static struct rpmdc_s _dc = { 00085 .ftsoptions = FTS_PHYSICAL, 00086 .flags = RPMDC_FLAGS_CREATE 00087 }; 00088 00091 static rpmdc dc = &_dc; 00092 00093 static const char hmackey[] = "orboDeJITITejsirpADONivirpUkvarP"; 00094 00095 /*==============================================================*/ 00096 static uint32_t rpmdcName2Algo(const char * dname) 00097 /*@*/ 00098 { 00099 struct poptOption * opt = rpmioDigestPoptTable; 00100 uint32_t dalgo = 0xffffffff; 00101 00102 /* XXX compatible with 0install legacy derangement. bug imho. */ 00103 if (!strcmp(dname, "sha1new")) 00104 dname = "sha1"; 00105 00106 for (; (opt->longName || opt->shortName || opt->arg) ; opt++) { 00107 if ((opt->argInfo & POPT_ARG_MASK) != POPT_ARG_VAL) 00108 continue; 00109 if (opt->longName == NULL) 00110 continue; 00111 if (!(opt->val > 0 && opt->val < 256)) 00112 continue; 00113 if (strcmp(opt->longName, dname)) 00114 continue; 00115 dalgo = (uint32_t) opt->val; 00116 break; 00117 } 00118 return dalgo; 00119 } 00120 00121 /*@null@*/ 00122 static const char * rpmdcAlgo2Name(uint32_t dalgo) 00123 /*@*/ 00124 { 00125 struct poptOption * opt = rpmioDigestPoptTable; 00126 const char * dalgoName = NULL; 00127 00128 for (; (opt->longName || opt->shortName || opt->arg) ; opt++) { 00129 if ((opt->argInfo & POPT_ARG_MASK) != POPT_ARG_VAL) 00130 continue; 00131 if (opt->longName == NULL) 00132 continue; 00133 if (!(opt->val > 0 && opt->val < 256)) 00134 continue; 00135 if ((uint32_t)opt->val != dalgo) 00136 continue; 00137 dalgoName = opt->longName; 00138 break; 00139 } 00140 return dalgoName; 00141 } 00142 00143 /*==============================================================*/ 00144 00145 static int rpmdcParseCoreutils(rpmdc dc) 00146 /*@globals h_errno, fileSystem, internalState @*/ 00147 /*@modifies h_errno, fileSystem, internalState @*/ 00148 { 00149 int rc = -1; /* assume failure */ 00150 00151 if (dc->manifests != NULL) /* note rc=0 return with no files to load. */ 00152 while ((dc->fn = *dc->manifests++) != NULL) { 00153 char buf[BUFSIZ]; 00154 unsigned lineno; 00155 FILE *fp; 00156 00157 if (strcmp(dc->fn, "-") == 0) { 00158 dc->fd = NULL; 00159 fp = stdin; 00160 } else { 00161 /* XXX .fpio is needed because of fgets(3) usage. */ 00162 dc->fd = Fopen(dc->fn, "r.fpio"); 00163 if (dc->fd == NULL || Ferror(dc->fd) || (fp = fdGetFILE(dc->fd)) == NULL) { 00164 fprintf(stderr, _("%s: Failed to open %s: %s\n"), 00165 __progname, dc->fn, Fstrerror(dc->fd)); 00166 if (dc->fd != NULL) (void) Fclose(dc->fd); 00167 dc->fd = NULL; 00168 fp = NULL; 00169 goto exit; 00170 } 00171 } 00172 00173 lineno = 0; 00174 while (fgets(buf, sizeof(buf), fp) != NULL) { 00175 const char * dname, * digest, * path; 00176 char *se = buf + (int)strlen(buf); 00177 int c, xx; 00178 00179 lineno++; 00180 while (se > buf && xisspace((int)se[-1])) 00181 se--; 00182 *se = '\0'; 00183 00184 /* Skip blank lines */ 00185 if (buf[0] == '\0') /*@innercontinue@*/ continue; 00186 /* Skip comment lines */ 00187 if (buf[0] == '#') /*@innercontinue@*/ continue; 00188 00189 /* Parse "[algo:]digest [* ]path" line. */ 00190 dname = NULL; path = NULL; 00191 for (digest = se = buf; (c = (int)*se) != 0; se++) 00192 switch (c) { 00193 default: 00194 /*@switchbreak@*/ break; 00195 case ':': 00196 *se++ = '\0'; 00197 dname = digest; 00198 digest = se; 00199 /*@switchbreak@*/ break; 00200 case ' ': 00201 se[0] = '\0'; /* loop will terminate */ 00202 if (se[1] == ' ' || se[1] == '*') 00203 se[1] = '\0'; 00204 path = se + 2; 00205 /*@switchbreak@*/ break; 00206 } 00207 if (path == NULL) { 00208 fprintf(stderr, _("%s: %s line %u: No file path found.\n"), 00209 __progname, dc->fn, lineno); 00210 rc = 2; 00211 goto exit; 00212 } 00213 00214 /* Map name to algorithm number. */ 00215 if (dname) { 00216 if ((dc->dalgo = rpmdcName2Algo(dname)) != 0xffffffff) 00217 dc->dalgoName = xstrdup(dname); 00218 if (dc->dalgo == 0xffffffff) { 00219 fprintf(stderr, _("%s: %s line %u: Unknown digest name \"%s\"\n"), 00220 __progname, dc->fn, lineno, dname); 00221 rc = 2; 00222 goto exit; 00223 } 00224 } else 00225 dc->dalgo = dc->algo; 00226 00227 /* Save {algo, digest, path} for processing. */ 00228 xx = argiAdd(&dc->algos, -1, dc->dalgo); 00229 xx = argvAdd(&dc->digests, digest); 00230 xx = argvAdd(&dc->paths, path); 00231 } 00232 00233 if (dc->fd != NULL) { 00234 (void) Fclose(dc->fd); 00235 dc->fd = NULL; 00236 } 00237 } 00238 rc = 0; 00239 00240 exit: 00241 return rc; 00242 } 00243 00244 /*@null@*/ 00245 static const char * rpmdcPrintCoreutils(rpmdc dc, int rc) 00246 { 00247 const char *msg = (rc ? "FAILED" : "OK"); 00248 char * t, * te; 00249 size_t nb = 0; 00250 00251 /* Don't bother formatting if noone cares. */ 00252 if (rc == 0 && F_ISSET(dc, STATUS)) 00253 return NULL; 00254 00255 /* Calculate size of message. */ 00256 if (dc->dalgoName != NULL) 00257 nb += strlen(dc->dalgoName) + sizeof(":") - 1; 00258 assert(dc->digest != NULL); 00259 if (dc->digest != NULL && dc->digestlen > 0) 00260 nb += dc->digestlen; 00261 nb += sizeof(" *") - 1; 00262 if (dc->fn != NULL) 00263 nb += strlen(dc->fn); 00264 nb += strlen(msg); 00265 nb += sizeof("\n"); /* XXX trailing NUL */ 00266 00267 /* Compose the message. */ 00268 te = t = xmalloc(nb); 00269 *te = '\0'; 00270 00271 if (dc->manifests) { 00272 if (rc || !F_ISSET(dc, STATUS)) { 00273 if (dc->fn) 00274 te = stpcpy( stpcpy(te, dc->fn), ": "); 00275 te = stpcpy(te, msg); 00276 *te++ = '\n'; 00277 } 00278 } else { 00279 if (dc->dalgoName) 00280 te = stpcpy( stpcpy(te, dc->dalgoName), ":"); 00281 te = stpcpy(te, dc->digest); 00282 *te++ = ' '; 00283 *te++ = (F_ISSET(dc, BINARY) ? '*' : ' '); 00284 te = stpcpy(te, dc->fn); 00285 *te++ = '\n'; 00286 } 00287 *te = '\0'; 00288 00289 return t; 00290 } 00291 00292 /*==============================================================*/ 00293 00294 static int rpmdcParseZeroInstall(rpmdc dc) 00295 /*@globals h_errno, fileSystem, internalState @*/ 00296 /*@modifies h_errno, fileSystem, internalState @*/ 00297 { 00298 int rc = 0; /* assume success */ 00299 00300 if (dc->manifests != NULL) /* note rc=0 return with no files to load. */ 00301 while ((dc->fn = *dc->manifests++) != NULL) { 00302 unsigned lineno; 00303 char * be; 00304 rpmiob iob = NULL; 00305 int xx = rpmiobSlurp(dc->fn, &iob); 00306 const char * digest; 00307 char * f; 00308 char * fe; 00309 00310 if (!(xx == 0 && iob != NULL)) { 00311 fprintf(stderr, _("%s: Failed to open %s\n"), __progname, dc->fn); 00312 rc = -1; 00313 goto bottom; 00314 } 00315 00316 be = (char *)(iob->b + iob->blen); 00317 while (be > (char *)iob->b && (be[-1] == '\n' || be[-1] == '\r')) { 00318 be--; 00319 *be = '\0'; 00320 } 00321 00322 /* Parse "algo=digest" from last line. */ 00323 be = strrchr((char *)iob->b, '='); 00324 if (be == NULL) { 00325 fprintf(stderr, 00326 _("%s: %s: Manifest needs \"algo=digest\" as last line\n"), 00327 __progname, dc->fn); 00328 rc = 2; 00329 goto bottom; 00330 } 00331 *be = '\0'; 00332 dc->digest = be + 1; 00333 while (be > (char *)iob->b && !(be[-1] == '\n' || be[-1] == '\r')) 00334 be--; 00335 if (be <= (char *)iob->b) { 00336 fprintf(stderr, _("%s: %s: Manifest is empty\n"), 00337 __progname, dc->fn); 00338 rc = 2; 00339 goto bottom; 00340 } 00341 00342 /* Map name to algorithm number. */ 00343 if ((dc->dalgo = rpmdcName2Algo(be)) == 0xffffffff) { 00344 fprintf(stderr, _("%s: %s: Unknown digest algo name \"%s\"\n"), 00345 __progname, dc->fn, be); 00346 rc = 2; 00347 goto bottom; 00348 } 00349 *be = '\0'; 00350 00351 /* Verify the manifest digest. */ 00352 { DIGEST_CTX ctx = rpmDigestInit(dc->dalgo, 0); 00353 00354 if (F_ISSET(dc, HMAC)) 00355 (void) rpmHmacInit(ctx, hmackey, 0); 00356 00357 (void) rpmDigestUpdate(ctx, (char *)iob->b, (be - (char *)iob->b)); 00358 digest = NULL; 00359 (void) rpmDigestFinal(ctx, &digest, NULL, 1); 00360 if (strcmp(dc->digest, digest)) { 00361 fprintf(stderr, 00362 _("%s: %s: Manifest digest check: Expected(%s) != (%s)\n"), 00363 __progname, dc->fn, dc->digest, digest); 00364 rc = 2; 00365 goto bottom; 00366 } 00367 digest = _free(digest); 00368 } 00369 00370 /* Parse and save manifest items. */ 00371 lineno = 0; 00372 for (f = (char *)iob->b; *f; f = fe) { 00373 static const char hexdigits[] = "0123456789ABCDEFabcdef"; 00374 const char * _dn = NULL; 00375 const char * path; 00376 00377 lineno++; 00378 fe = f; 00379 while (*fe && !(*fe == '\n' || *fe == '\r')) 00380 fe++; 00381 while (*fe && (*fe == '\n' || *fe == '\r')) 00382 *fe++ = '\0'; 00383 switch ((int)*f) { 00384 case 'D': 00385 _dn = f + 2; 00386 continue; 00387 /*@notreached@*/ break; 00388 case 'F': 00389 case 'S': 00390 case 'X': 00391 digest = f + 2; 00392 f += 2; 00393 while (*f && strchr(hexdigits, *f) != NULL) 00394 f++; 00395 if (*f != ' ') { 00396 fprintf(stderr, _("%s: %s line %u: Malformed digest field.\n"), 00397 __progname, dc->fn, lineno); 00398 rc = 2; 00399 goto bottom; 00400 } 00401 *f++ = '\0'; 00402 while (*f && xisdigit(*f)) 00403 f++; 00404 if (*f != ' ') { 00405 fprintf(stderr, _("%s: %s line %u: Malformed mtime field.\n"), 00406 __progname, dc->fn, lineno); 00407 rc = 2; 00408 goto bottom; 00409 } 00410 *f++ = '\0'; 00411 while (*f && xisdigit(*f)) 00412 f++; 00413 if (*f != ' ') { 00414 fprintf(stderr, _("%s: %s line %u: Malformed size field.\n"), 00415 __progname, dc->fn, lineno); 00416 rc = 2; 00417 goto bottom; 00418 } 00419 *f++ = '\0'; 00420 if (*f == '\0') { 00421 fprintf(stderr, _("%s: %s line %u: No file path.\n"), 00422 __progname, dc->fn, lineno); 00423 rc = 2; 00424 goto bottom; 00425 } 00426 00427 if (_dn && *_dn == '/') 00428 path = rpmExpand(_dn+1, "/", f, NULL); 00429 else 00430 path = xstrdup(f); 00431 00432 /* Save {algo, digest, path} for processing. */ 00433 xx = argiAdd(&dc->algos, -1, dc->dalgo); 00434 xx = argvAdd(&dc->digests, digest); 00435 xx = argvAdd(&dc->paths, path); 00436 path = _free(path); 00437 break; 00438 } 00439 } 00440 00441 bottom: 00442 iob = rpmiobFree(iob); 00443 if (rc != 0) 00444 goto exit; 00445 } 00446 00447 exit: 00448 return rc; 00449 } 00450 00451 /*@null@*/ 00452 static const char * rpmdcPrintZeroInstall(rpmdc dc, int rc) 00453 { 00454 char * t, * te; 00455 size_t nb = 0; 00456 char _mtime[32]; 00457 char _size[32]; 00458 const struct stat * st = &dc->sb; 00459 const char * _bn; 00460 00461 /* Don't bother formatting if noone cares. */ 00462 if (rc == 0 && F_ISSET(dc, STATUS)) 00463 return NULL; 00464 00465 snprintf(_mtime, sizeof(_mtime), "%llu", 00466 (unsigned long long) st->st_mtime); 00467 _mtime[sizeof(_mtime)-1] = '\0'; 00468 snprintf(_size, sizeof(_size), "%llu", 00469 (unsigned long long) st->st_size); 00470 _size[sizeof(_size)-1] = '\0'; 00471 if ((_bn = strrchr(dc->fn, '/')) != NULL) 00472 _bn++; 00473 else 00474 _bn = dc->fn; 00475 00476 /* Calculate size of message. */ 00477 nb += sizeof("F"); 00478 if (dc->digest != NULL && dc->digestlen > 0) 00479 nb += 1 + dc->digestlen; 00480 nb += 1 + strlen(_mtime); 00481 nb += 1 + strlen(_size); 00482 nb += 1 + strlen(_bn); 00483 nb += sizeof("\n"); /* XXX trailing NUL */ 00484 00485 /* Compose the message. */ 00486 te = t = xmalloc(nb); 00487 *te = '\0'; 00488 00489 if (dc->manifests) { 00490 const char *msg = (rc ? "FAILED" : "OK"); 00491 if (rc || !F_ISSET(dc, STATUS)) { 00492 if (dc->fn) 00493 te = stpcpy( stpcpy(te, dc->fn), ": "); 00494 te = stpcpy(te, msg); 00495 *te++ = '\n'; 00496 } 00497 } else { 00498 if (S_ISDIR(st->st_mode)) { 00499 *te++ = 'D'; 00500 if (_old_0install) { 00501 *te++ = ' '; 00502 te = stpcpy(te, _mtime); 00503 } 00504 *te++ = ' '; 00505 *te++ = '/'; 00506 te = stpcpy(te, _bn); 00507 *te++ = '\n'; 00508 } else if (S_ISREG(st->st_mode) || S_ISLNK(st->st_mode)) { 00509 if (S_ISLNK(st->st_mode)) 00510 *te++ = 'S'; 00511 else 00512 *te++ = (st->st_mode & (S_IXUSR|S_IXGRP|S_IXOTH)) ? 'X' : 'F'; 00513 *te++ = ' '; 00514 te = stpcpy(te, dc->digest); 00515 *te++ = ' '; 00516 te = stpcpy(te, _mtime); 00517 *te++ = ' '; 00518 te = stpcpy(te, _size); 00519 *te++ = ' '; 00520 te = stpcpy(te, _bn); 00521 *te++ = '\n'; 00522 } 00523 } 00524 *te = '\0'; 00525 00526 return t; 00527 } 00528 00529 /*==============================================================*/ 00530 00531 static int rpmdcPrintFile(rpmdc dc) 00532 { 00533 static int asAscii = 1; 00534 int rc = 0; 00535 00536 if (_rpmdc_debug) 00537 fprintf(stderr, "\t%s(%p) fd %p fn %s\n", __FUNCTION__, dc, dc->fd, dc->fn); 00538 00539 assert(dc->fd != NULL); 00540 fdFiniDigest(dc->fd, dc->dalgo, &dc->digest, &dc->digestlen, asAscii); 00541 assert(dc->digest != NULL); 00542 dc->ncomputed++; 00543 00544 if (dc->manifests) { 00545 dc->nchecked++; 00546 if ((rc = strcmp(dc->digest, dc->digests[dc->ix])) != 0) 00547 dc->nfailed++; 00548 else 00549 dc->nmatched++; 00550 } 00551 00552 { const char * t = (*dc->print) (dc, rc); 00553 if (dc->ofd && t && *t) { 00554 size_t nb = strlen(t); 00555 nb = Fwrite(t, nb, sizeof(*t), dc->ofd); 00556 (void) Fflush(dc->ofd); 00557 } 00558 t = _free(t); 00559 } 00560 00561 dc->digest = _free(dc->digest); 00562 dc->digestlen = 0; 00563 return rc; 00564 } 00565 00566 static int rpmdcFiniFile(rpmdc dc) 00567 { 00568 uint32_t dalgo = (dc->manifests ? dc->algos->vals[dc->ix] : dc->algo); 00569 int rc = 0; 00570 int xx; 00571 00572 /* Only regular files have dc->fd != NULL here. Skip all other paths. */ 00573 if (dc->fd == NULL) 00574 return rc; 00575 00576 if (_rpmdc_debug) 00577 fprintf(stderr, "\t%s(%p) fn %s\n", __FUNCTION__, dc, dc->fn); 00578 switch (dalgo) { 00579 default: 00580 dc->dalgo = dalgo; 00581 dc->dalgoName = NULL; 00582 xx = rpmdcPrintFile(dc); 00583 if (xx) rc = xx; 00584 break; 00585 case 256: /* --all digests requested. */ 00586 { struct poptOption * opt = rpmioDigestPoptTable; 00587 for (; (opt->longName || opt->shortName || opt->arg) ; opt++) { 00588 if ((opt->argInfo & POPT_ARG_MASK) != POPT_ARG_VAL) 00589 continue; 00590 if (opt->arg != (void *)&rpmioDigestHashAlgo) 00591 continue; 00592 dc->dalgo = opt->val; 00593 if (!(dc->dalgo > 0 && dc->dalgo < 256)) 00594 continue; 00595 dc->dalgoName = opt->longName; 00596 xx = rpmdcPrintFile(dc); 00597 if (xx) rc = xx; 00598 } 00599 } break; 00600 } 00601 00602 (void) rpmswAdd(&dc->readops, fdstat_op(dc->fd, FDSTAT_READ)); 00603 (void) rpmswAdd(&dc->digestops, fdstat_op(dc->fd, FDSTAT_DIGEST)); 00604 Fclose(dc->fd); 00605 dc->fd = NULL; 00606 00607 return rc; 00608 } 00609 00610 static int rpmdcCalcFile(rpmdc dc) 00611 { 00612 int rc = 0; 00613 00614 if (_rpmdc_debug) 00615 fprintf(stderr, "\t%s(%p) fn %s\n", __FUNCTION__, dc, dc->fn); 00616 /* Skip (unopened) non-files. */ 00617 if (dc->fd != NULL) 00618 do { 00619 dc->nb = Fread(dc->buf, sizeof(dc->buf[0]), sizeof(dc->buf), dc->fd); 00620 if (Ferror(dc->fd)) { 00621 rc = 2; 00622 break; 00623 } 00624 } while (dc->nb > 0); 00625 00626 return rc; 00627 } 00628 00629 static int rpmdcInitFile(rpmdc dc) 00630 { 00631 int rc = 0; 00632 00633 if (_rpmdc_debug) 00634 fprintf(stderr, "\t%s(%p) fn %s\n", __FUNCTION__, dc, dc->fn); 00635 /* Skip non-files. */ 00636 if (!S_ISREG(dc->sb.st_mode)) { 00637 /* XXX not found return code? */ 00638 goto exit; 00639 } 00640 00641 dc->fd = Fopen(dc->fn, "r.ufdio"); 00642 if (dc->fd == NULL || Ferror(dc->fd)) { 00643 fprintf(stderr, _("open of %s failed: %s\n"), dc->fn, Fstrerror(dc->fd)); 00644 if (dc->fd != NULL) Fclose(dc->fd); 00645 dc->fd = NULL; 00646 rc = 2; 00647 goto exit; 00648 } 00649 00650 switch (dc->algo) { 00651 default: 00652 /* XXX TODO: instantiate verify digests for all identical paths. */ 00653 dc->dalgo = dc->algo; 00654 fdInitDigest(dc->fd, dc->dalgo, 0); 00655 if (F_ISSET(dc, HMAC)) 00656 fdInitHmac(dc->fd, hmackey, 0); 00657 break; 00658 case 256: /* --all digests requested. */ 00659 { struct poptOption * opt = rpmioDigestPoptTable; 00660 for (; (opt->longName || opt->shortName || opt->arg) ; opt++) { 00661 if ((opt->argInfo & POPT_ARG_MASK) != POPT_ARG_VAL) 00662 continue; 00663 if (opt->longName == NULL) 00664 continue; 00665 if (!(opt->val > 0 && opt->val < 256)) 00666 continue; 00667 dc->dalgo = opt->val; 00668 dc->dalgoName = opt->longName; 00669 fdInitDigest(dc->fd, dc->dalgo, 0); 00670 if (F_ISSET(dc, HMAC)) 00671 fdInitHmac(dc->fd, hmackey, 0); 00672 } 00673 } break; 00674 } 00675 00676 exit: 00677 return rc; 00678 } 00679 00680 static int 00681 rpmdcVisitF(rpmdc dc) 00682 /*@modifies dc @*/ 00683 { 00684 int rc = 0; 00685 int xx; 00686 00687 if (_rpmdc_debug) 00688 fprintf(stderr, "*** %s(%p) fn %s\n", __FUNCTION__, dc, dc->fn); 00689 if ((xx = rpmdcInitFile(dc)) != 0) 00690 rc = xx; 00691 else { 00692 if ((xx = rpmdcCalcFile(dc)) != 0) 00693 rc = xx; 00694 if ((xx = rpmdcFiniFile(dc)) != 0) 00695 rc = xx; 00696 } 00697 return rc; 00698 } 00699 00700 static int 00701 rpmdcSortLexical(const FTSENT ** a, const FTSENT ** b) 00702 /*@*/ 00703 { 00704 return strcmp((*a)->fts_name, (*b)->fts_name); 00705 } 00706 00707 static int 00708 rpmdcSortDirsLast(const FTSENT ** a, const FTSENT ** b) 00709 /*@*/ 00710 { 00711 if (S_ISDIR((*a)->fts_statp->st_mode)) { 00712 if (!S_ISDIR((*b)->fts_statp->st_mode)) 00713 return 1; 00714 } else if (S_ISDIR((*b)->fts_statp->st_mode)) 00715 return -1; 00716 return strcmp((*a)->fts_name, (*b)->fts_name); 00717 } 00718 00719 static int 00720 rpmdcCWalk(rpmdc dc) 00721 { 00722 char *const * paths = (char * const *) dc->paths; 00723 int ftsoptions = dc->ftsoptions; 00724 int rval = 0; 00725 00726 dc->t = Fts_open(paths, ftsoptions, 00727 (F_ISSET(dc, 0INSTALL) && _old_0install ? rpmdcSortLexical : rpmdcSortDirsLast)); 00728 if (dc->t == NULL) { 00729 fprintf(stderr, "Fts_open: %s", strerror(errno)); 00730 return -1; 00731 } 00732 00733 while ((dc->p = Fts_read(dc->t)) != NULL) { 00734 #ifdef NOTYET 00735 int indent = 0; 00736 if (F_ISSET(dc, INDENT)) 00737 indent = dc->p->fts_level * 4; 00738 if (rpmdcCheckExcludes(dc->p->fts_name, dc->p->fts_path)) { 00739 (void) Fts_set(dc->t, dc->p, FTS_SKIP); 00740 continue; 00741 } 00742 #endif 00743 00744 dc->fn = dc->p->fts_path; /* XXX eliminate dc->fn */ 00745 memcpy(&dc->sb, dc->p->fts_statp, sizeof(dc->sb)); 00746 00747 switch(dc->p->fts_info) { 00748 case FTS_D: 00749 #ifdef NOTYET 00750 if (!F_ISSET(dc, DIRSONLY)) 00751 (void) printf("\n"); 00752 if (!F_ISSET(dc, NOCOMMENT)) 00753 (void) printf("# %s\n", dc->p->fts_path); 00754 (void) rpmdcVisitD(dc); 00755 #endif 00756 /* XXX don't visit topdirs for 0install. */ 00757 if (F_ISSET(dc, 0INSTALL) && dc->p->fts_level > 0) 00758 rpmdcVisitF(dc); 00759 /*@switchbreak@*/ break; 00760 case FTS_DP: 00761 #ifdef NOTYET 00762 if (!F_ISSET(dc, NOCOMMENT) && (dc->p->fts_level > 0)) 00763 (void) printf("%*s# %s\n", indent, "", dc->p->fts_path); 00764 (void) printf("%*s..\n", indent, ""); 00765 if (!F_ISSET(dc, DIRSONLY)) 00766 (void) printf("\n"); 00767 #endif 00768 /*@switchbreak@*/ break; 00769 case FTS_DNR: 00770 case FTS_ERR: 00771 case FTS_NS: 00772 (void) fprintf(stderr, "%s: %s: %s\n", __progname, 00773 dc->p->fts_path, strerror(dc->p->fts_errno)); 00774 /*@switchbreak@*/ break; 00775 default: 00776 if (!F_ISSET(dc, DIRSONLY)) 00777 rpmdcVisitF(dc); 00778 /*@switchbreak@*/ break; 00779 } 00780 } 00781 (void) Fts_close(dc->t); 00782 dc->p = NULL; 00783 dc->t = NULL; 00784 return rval; 00785 } 00786 00787 static int rpmdcLoadManifests(rpmdc dc) 00788 /*@globals h_errno, fileSystem, internalState @*/ 00789 /*@modifies dc, h_errno, fileSystem, internalState @*/ 00790 { 00791 return (dc->manifests != NULL ? (*dc->parse) (dc) : 0); 00792 } 00793 00794 #if !defined(POPT_ARG_ARGV) 00795 static int _poptSaveString(const char ***argvp, unsigned int argInfo, const char * val) 00796 /*@*/ 00797 { 00798 ARGV_t argv; 00799 int argc = 0; 00800 if (argvp == NULL) 00801 return -1; 00802 if (*argvp) 00803 while ((*argvp)[argc] != NULL) 00804 argc++; 00805 *argvp = xrealloc(*argvp, (argc + 1 + 1) * sizeof(**argvp)); 00806 if ((argv = *argvp) != NULL) { 00807 argv[argc++] = xstrdup(val); 00808 argv[argc ] = NULL; 00809 } 00810 return 0; 00811 } 00812 00815 static void rpmdcArgCallback(poptContext con, 00816 /*@unused@*/ enum poptCallbackReason reason, 00817 const struct poptOption * opt, /*@unused@*/ const char * arg, 00818 /*@unused@*/ void * data) 00819 /*@globals fileSystem @*/ 00820 /*@modifies fileSystem @*/ 00821 { 00822 /* XXX avoid accidental collisions with POPT_BIT_SET for flags */ 00823 if (opt->arg == NULL) 00824 switch (opt->val) { 00825 int xx; 00826 case 'c': 00827 assert(arg != NULL); 00828 xx = _poptSaveString(&_dc.manifests, opt->argInfo, arg); 00829 break; 00830 00831 default: 00832 fprintf(stderr, _("%s: Unknown option -%c\n"), __progname, opt->val); 00833 poptPrintUsage(con, stderr, 0); 00834 /*@-exitarg@*/ 00835 exit(2); 00836 /*@=exitarg@*/ 00837 /*@notreached@*/ break; 00838 } 00839 } 00840 #endif /* POPT_ARG_ARGV */ 00841 00842 static struct poptOption _optionsTable[] = { 00843 #if !defined(POPT_ARG_ARGV) 00844 /*@-type@*/ /* FIX: cast? */ 00845 { NULL, '\0', POPT_ARG_CALLBACK | POPT_CBFLAG_INC_DATA | POPT_CBFLAG_CONTINUE, 00846 rpmdcArgCallback, 0, NULL, NULL }, 00847 /*@=type@*/ 00848 #endif /* POPT_ARG_ARGV */ 00849 00850 { "0install", '0', POPT_BIT_SET, &_dc.flags, RPMDC_FLAGS_0INSTALL, 00851 N_("Print 0install manifest"), NULL }, 00852 00853 { "binary", 'b', POPT_BIT_SET, &_dc.flags, RPMDC_FLAGS_BINARY, 00854 N_("Read in binary mode"), NULL }, 00855 00856 #if !defined(POPT_ARG_ARGV) 00857 { "check", 'c', POPT_ARG_STRING, NULL, 'c', 00858 N_("Read digests from MANIFEST file and verify (may be used more than once)"), 00859 N_("MANIFEST") }, 00860 #else 00861 { "check", 'c', POPT_ARG_ARGV, &_dc.manifests, 0, 00862 N_("Read digests from MANIFEST file and verify (may be used more than once)"), 00863 N_("MANIFEST") }, 00864 #endif 00865 { "create",'c', POPT_BIT_SET, &_dc.flags, RPMDC_FLAGS_CREATE, 00866 N_("Print file tree specification to stdout"), NULL }, 00867 { "dirs",'d', POPT_BIT_SET, &_dc.flags, RPMDC_FLAGS_DIRSONLY, 00868 N_("Directories only"), NULL }, 00869 00870 { "text", 't', POPT_BIT_CLR, &_dc.flags, RPMDC_FLAGS_BINARY, 00871 N_("read in text mode (default)"), NULL }, 00872 00873 { "hmac", '\0', POPT_BIT_SET, &_dc.flags, RPMDC_FLAGS_HMAC, 00874 N_("generate HMAC's instead"), NULL }, 00875 00876 #ifdef NOTYET /* XXX todo for popt-1.15 */ 00877 { NULL, -1, POPT_ARG_INCLUDE_TABLE, NULL, 0, 00878 N_("\ 00879 The following two options are useful only when verifying digests:\ 00880 "), NULL }, 00881 #endif 00882 00883 { "status", '\0', POPT_BIT_SET, &_dc.flags, RPMDC_FLAGS_STATUS, 00884 N_("no output when verifying"), NULL }, 00885 { "warn", 'w', POPT_BIT_SET, &_dc.flags, RPMDC_FLAGS_WARN, 00886 N_("warn about improperly formatted checksum lines"), NULL }, 00887 00888 { NULL, '\0', POPT_ARG_INCLUDE_TABLE, rpmioDigestPoptTable, 0, 00889 N_("Available digests:"), NULL }, 00890 00891 { NULL, '\0', POPT_ARG_INCLUDE_TABLE, rpmioAllPoptTable, 0, 00892 N_("Common options for all rpmio executables:"), NULL }, 00893 00894 POPT_AUTOALIAS 00895 POPT_AUTOHELP 00896 00897 { NULL, -1, POPT_ARG_INCLUDE_TABLE, NULL, 0, 00898 N_("\ 00899 When checking, the input should be a former output of this program. The\n\ 00900 default mode is to print a line with digest, a character indicating type\n\ 00901 (`*' for binary, ` ' for text), and name for each FILE.\n"), NULL }, 00902 00903 POPT_TABLEEND 00904 }; 00905 00906 static struct poptOption *optionsTable = &_optionsTable[0]; 00907 00908 int 00909 main(int argc, char *argv[]) 00910 { 00911 poptContext optCon = rpmioInit(argc, argv, optionsTable); 00912 ARGV_t av; 00913 int ac; 00914 int rc = 0; 00915 int xx; 00916 00917 rpmswEnter(&dc->totalops, -1); 00918 00919 if (F_ISSET(dc, 0INSTALL)) { 00920 dc->parse = rpmdcParseZeroInstall; 00921 dc->print = rpmdcPrintZeroInstall; 00922 if ((int)rpmioDigestHashAlgo < 0) 00923 rpmioDigestHashAlgo = PGPHASHALGO_SHA1; 00924 dc->algo = rpmioDigestHashAlgo; 00925 dc->oalgo = dc->algo; 00926 dc->oalgoName = rpmdcAlgo2Name(dc->oalgo); 00927 if (!strcmp(dc->oalgoName, "sha1")) 00928 dc->oalgoName = "sha1new"; 00929 } else { 00930 dc->parse = rpmdcParseCoreutils; 00931 dc->print = rpmdcPrintCoreutils; 00932 if ((int)rpmioDigestHashAlgo < 0) 00933 rpmioDigestHashAlgo = PGPHASHALGO_MD5; 00934 dc->algo = rpmioDigestHashAlgo; 00935 } 00936 00937 if (dc->ofn == NULL) 00938 dc->ofn = "-"; 00939 dc->ftsoptions = rpmioFtsOpts; 00940 if (!(dc->ftsoptions & (FTS_LOGICAL|FTS_PHYSICAL))) 00941 dc->ftsoptions |= FTS_PHYSICAL; 00942 dc->ftsoptions |= FTS_NOCHDIR; 00943 00944 dc->ofd = Fopen(dc->ofn, "w.ufdio"); 00945 if (F_ISSET(dc, 0INSTALL)) { 00946 fdInitDigest(dc->ofd, dc->oalgo, 0); 00947 if (F_ISSET(dc, HMAC)) 00948 fdInitHmac(dc->ofd, hmackey, 0); 00949 } 00950 00951 av = poptGetArgs(optCon); 00952 ac = argvCount(av); 00953 if ((ac == 0 && dc->manifests == NULL) 00954 || (ac > 0 && dc->manifests != NULL)) 00955 { 00956 poptPrintUsage(optCon, stderr, 0); 00957 rc = 2; 00958 goto exit; 00959 } 00960 00961 if (dc->manifests != NULL) { 00962 if ((xx = rpmdcLoadManifests(dc)) != 0) 00963 rc = xx; 00964 } else { 00965 int i; 00966 for (i = 0; i < ac; i++) 00967 xx = argvAdd(&dc->paths, av[i]); 00968 } 00969 if (rc) 00970 goto exit; 00971 00972 if (dc->manifests != NULL) { 00973 dc->ix = 0; 00974 av = dc->paths; 00975 if (av != NULL) 00976 while ((dc->fn = *av++) != NULL) { 00977 if ((xx = Lstat(dc->fn, &dc->sb)) != 0 00978 || (xx = rpmdcVisitF(dc)) != 0) 00979 rc = xx; 00980 dc->ix++; 00981 } 00982 } else { 00983 if ((xx = rpmdcCWalk(dc)) != 0) 00984 rc = xx; 00985 } 00986 00987 exit: 00988 if (dc->nfailed) 00989 fprintf(stderr, "%s: WARNING: %u of %u computed checksums did NOT match\n", 00990 __progname, (unsigned) dc->nfailed, (unsigned) dc->ncomputed); 00991 00992 if (dc->ofd) { 00993 /* Print the output spewage digest for 0install format manifests. */ 00994 if (rc == 0 && F_ISSET(dc, 0INSTALL) && dc->manifests == NULL) { 00995 static int asAscii = 1; 00996 char *t; 00997 fdFiniDigest(dc->ofd, dc->oalgo, &dc->digest, &dc->digestlen, asAscii); 00998 assert(dc->digest != NULL); 00999 t = rpmExpand(dc->oalgoName, "=", dc->digest, "\n", NULL); 01000 (void) Fwrite(t, strlen(t), sizeof(*t), dc->ofd); 01001 t = _free(t); 01002 dc->digest = _free(dc->digest); 01003 } 01004 (void) Fclose(dc->ofd); 01005 dc->ofd = NULL; 01006 } 01007 01008 #ifdef NOTYET 01009 dc->manifests = argvFree(dc->manifests); 01010 #endif 01011 dc->algos = argiFree(dc->algos); 01012 dc->digests = argvFree(dc->digests); 01013 dc->paths = argvFree(dc->paths); 01014 01015 rpmswExit(&dc->totalops, 0); 01016 if (_rpmsw_stats) { 01017 rpmswPrint(" total:", &dc->totalops, NULL); 01018 rpmswPrint(" read:", &dc->readops, NULL); 01019 rpmswPrint("digest:", &dc->digestops, NULL); 01020 } 01021 01022 optCon = rpmioFini(optCon); 01023 01024 return rc; 01025 }