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