rpm  5.4.10
rpmdigest.c
Go to the documentation of this file.
1 #include "system.h"
2 /*@unchecked@*/
3 extern const char * __progname;
4 
5 #define _RPMIOB_INTERNAL
6 #include <rpmiotypes.h>
7 #include <rpmio_internal.h> /* XXX fdGetFILE */
8 #include <poptIO.h>
9 #include "debug.h"
10 
11 static int _rpmdc_debug = 0;
12 
13 /* XXX older 0install manifest format. */
14 static int _old_0install = 0;
15 
16 #define _KFB(n) (1U << (n))
17 #define _DFB(n) (_KFB(n) | 0x40000000)
18 
19 #define F_ISSET(_dc, _FLAG) ((_dc)->flags & ((RPMDC_FLAGS_##_FLAG) & ~0x40000000))
20 
24 enum dcFlags_e {
26  /* 0 reserved */
30  /* 4-13 reserved */
35  /* 18-31 unused */
36 };
37 
40 typedef struct rpmdc_s * rpmdc;
41 
44 struct rpmdc_s {
45  int ftsoptions;
46  FTS * t;
47  FTSENT * p;
48  struct stat sb;
51  uint32_t algo;
52  uint32_t dalgo;
53 /*@observer@*/ /*@null@*/
54  const char * dalgoName;
55  const char * digest;
56  size_t digestlen;
57  const char * fn;
59  int (*parse) (rpmdc dc);
60  const char * (*print) (rpmdc dc, int rc);
61  const char * ofn;
63  uint32_t oalgo;
64  const char * oalgoName;
69  unsigned char buf[BUFSIZ];
70  ssize_t nb;
71  int ix;
72 
73  size_t ncomputed;
74  size_t nchecked;
75  size_t nmatched;
76  size_t nfailed;
77  struct rpmop_s totalops;
78  struct rpmop_s readops;
80 };
81 
84 static struct rpmdc_s _dc = {
86  .flags = RPMDC_FLAGS_CREATE
87 };
88 
91 static rpmdc dc = &_dc;
92 
93 static const char hmackey[] = "orboDeJITITejsirpADONivirpUkvarP";
94 
95 /*==============================================================*/
96 static uint32_t rpmdcName2Algo(const char * dname)
97  /*@*/
98 {
99  struct poptOption * opt = rpmioDigestPoptTable;
100  uint32_t dalgo = 0xffffffff;
101 
102  /* XXX compatible with 0install legacy derangement. bug imho. */
103  if (!strcmp(dname, "sha1new"))
104  dname = "sha1";
105 
106  for (; (opt->longName || opt->shortName || opt->arg) ; opt++) {
107  if ((opt->argInfo & POPT_ARG_MASK) != POPT_ARG_VAL)
108  continue;
109  if (opt->longName == NULL)
110  continue;
111  if (!(opt->val > 0 && opt->val < 256))
112  continue;
113  if (strcmp(opt->longName, dname))
114  continue;
115  dalgo = (uint32_t) opt->val;
116  break;
117  }
118  return dalgo;
119 }
120 
121 /*@null@*/
122 static const char * rpmdcAlgo2Name(uint32_t dalgo)
123  /*@*/
124 {
125  struct poptOption * opt = rpmioDigestPoptTable;
126  const char * dalgoName = NULL;
127 
128  for (; (opt->longName || opt->shortName || opt->arg) ; opt++) {
129  if ((opt->argInfo & POPT_ARG_MASK) != POPT_ARG_VAL)
130  continue;
131  if (opt->longName == NULL)
132  continue;
133  if (!(opt->val > 0 && opt->val < 256))
134  continue;
135  if ((uint32_t)opt->val != dalgo)
136  continue;
137  dalgoName = opt->longName;
138  break;
139  }
140  return dalgoName;
141 }
142 
143 /*==============================================================*/
144 
145 static int rpmdcParseCoreutils(rpmdc dc)
146  /*@globals h_errno, fileSystem, internalState @*/
147  /*@modifies h_errno, fileSystem, internalState @*/
148 {
149  int rc = -1; /* assume failure */
150 
151  if (dc->manifests != NULL) /* note rc=0 return with no files to load. */
152  while ((dc->fn = *dc->manifests++) != NULL) {
153  char buf[BUFSIZ];
154  unsigned lineno;
155  FILE *fp;
156 
157  if (strcmp(dc->fn, "-") == 0) {
158  dc->fd = NULL;
159  fp = stdin;
160  } else {
161  /* XXX .fpio is needed because of fgets(3) usage. */
162  dc->fd = Fopen(dc->fn, "r.fpio");
163  if (dc->fd == NULL || Ferror(dc->fd) || (fp = fdGetFILE(dc->fd)) == NULL) {
164  fprintf(stderr, _("%s: Failed to open %s: %s\n"),
165  __progname, dc->fn, Fstrerror(dc->fd));
166  if (dc->fd != NULL) (void) Fclose(dc->fd);
167  dc->fd = NULL;
168  fp = NULL;
169  goto exit;
170  }
171  }
172 
173  lineno = 0;
174  while (fgets(buf, sizeof(buf), fp) != NULL) {
175  const char * dname, * digest, * path;
176  char *se = buf + (int)strlen(buf);
177  int c, xx;
178 
179  lineno++;
180  while (se > buf && xisspace((int)se[-1]))
181  se--;
182  *se = '\0';
183 
184  /* Skip blank lines */
185  if (buf[0] == '\0') /*@innercontinue@*/ continue;
186  /* Skip comment lines */
187  if (buf[0] == '#') /*@innercontinue@*/ continue;
188 
189  /* Parse "[algo:]digest [* ]path" line. */
190  dname = NULL; path = NULL;
191  for (digest = se = buf; (c = (int)*se) != 0; se++)
192  switch (c) {
193  default:
194  /*@switchbreak@*/ break;
195  case ':':
196  *se++ = '\0';
197  dname = digest;
198  digest = se;
199  /*@switchbreak@*/ break;
200  case ' ':
201  se[0] = '\0'; /* loop will terminate */
202  if (se[1] == ' ' || se[1] == '*')
203  se[1] = '\0';
204  path = se + 2;
205  /*@switchbreak@*/ break;
206  }
207  if (path == NULL) {
208  fprintf(stderr, _("%s: %s line %u: No file path found.\n"),
209  __progname, dc->fn, lineno);
210  rc = 2;
211  goto exit;
212  }
213 
214  /* Map name to algorithm number. */
215  if (dname) {
216  if ((dc->dalgo = rpmdcName2Algo(dname)) != 0xffffffff)
217  dc->dalgoName = xstrdup(dname);
218  if (dc->dalgo == 0xffffffff) {
219  fprintf(stderr, _("%s: %s line %u: Unknown digest name \"%s\"\n"),
220  __progname, dc->fn, lineno, dname);
221  rc = 2;
222  goto exit;
223  }
224  } else
225  dc->dalgo = dc->algo;
226 
227  /* Save {algo, digest, path} for processing. */
228  xx = argiAdd(&dc->algos, -1, dc->dalgo);
229  xx = argvAdd(&dc->digests, digest);
230  xx = argvAdd(&dc->paths, path);
231  }
232 
233  if (dc->fd != NULL) {
234  (void) Fclose(dc->fd);
235  dc->fd = NULL;
236  }
237  }
238  rc = 0;
239 
240 exit:
241  return rc;
242 }
243 
244 /*@null@*/
245 static const char * rpmdcPrintCoreutils(rpmdc dc, int rc)
246 {
247  const char *msg = (rc ? "FAILED" : "OK");
248  char * t, * te;
249  size_t nb = 0;
250 
251  /* Don't bother formatting if no one cares. */
252  if (rc == 0 && F_ISSET(dc, STATUS))
253  return NULL;
254 
255  /* Calculate size of message. */
256  if (dc->dalgoName != NULL)
257  nb += strlen(dc->dalgoName) + sizeof(":") - 1;
258 assert(dc->digest != NULL);
259  if (dc->digest != NULL && dc->digestlen > 0)
260  nb += dc->digestlen;
261  nb += sizeof(" *") - 1;
262  if (dc->fn != NULL)
263  nb += strlen(dc->fn);
264  nb += strlen(msg);
265  nb += sizeof("\n"); /* XXX trailing NUL */
266 
267  /* Compose the message. */
268  te = t = xmalloc(nb);
269  *te = '\0';
270 
271  if (dc->manifests) {
272  if (rc || !F_ISSET(dc, STATUS)) {
273  if (dc->fn)
274  te = stpcpy( stpcpy(te, dc->fn), ": ");
275  te = stpcpy(te, msg);
276  *te++ = '\n';
277  }
278  } else {
279  if (dc->dalgoName)
280  te = stpcpy( stpcpy(te, dc->dalgoName), ":");
281  te = stpcpy(te, dc->digest);
282  *te++ = ' ';
283  *te++ = (F_ISSET(dc, BINARY) ? '*' : ' ');
284  te = stpcpy(te, dc->fn);
285  *te++ = '\n';
286  }
287  *te = '\0';
288 
289  return t;
290 }
291 
292 /*==============================================================*/
293 
294 static int rpmdcParseZeroInstall(rpmdc dc)
295  /*@globals h_errno, fileSystem, internalState @*/
296  /*@modifies h_errno, fileSystem, internalState @*/
297 {
298  int rc = 0; /* assume success */
299 
300  if (dc->manifests != NULL) /* note rc=0 return with no files to load. */
301  while ((dc->fn = *dc->manifests++) != NULL) {
302  unsigned lineno;
303  char * be;
304  rpmiob iob = NULL;
305  int xx = rpmiobSlurp(dc->fn, &iob);
306  const char * digest;
307  char * f;
308  char * fe;
309 
310  if (!(xx == 0 && iob != NULL)) {
311  fprintf(stderr, _("%s: Failed to open %s\n"), __progname, dc->fn);
312  rc = -1;
313  goto bottom;
314  }
315 
316  be = (char *)(iob->b + iob->blen);
317  while (be > (char *)iob->b && (be[-1] == '\n' || be[-1] == '\r')) {
318  be--;
319  *be = '\0';
320  }
321 
322  /* Parse "algo=digest" from last line. */
323  be = strrchr((char *)iob->b, '=');
324  if (be == NULL) {
325  fprintf(stderr,
326  _("%s: %s: Manifest needs \"algo=digest\" as last line\n"),
327  __progname, dc->fn);
328  rc = 2;
329  goto bottom;
330  }
331  *be = '\0';
332  dc->digest = be + 1;
333  while (be > (char *)iob->b && !(be[-1] == '\n' || be[-1] == '\r'))
334  be--;
335  if (be <= (char *)iob->b) {
336  fprintf(stderr, _("%s: %s: Manifest is empty\n"),
337  __progname, dc->fn);
338  rc = 2;
339  goto bottom;
340  }
341 
342  /* Map name to algorithm number. */
343  if ((dc->dalgo = rpmdcName2Algo(be)) == 0xffffffff) {
344  fprintf(stderr, _("%s: %s: Unknown digest algo name \"%s\"\n"),
345  __progname, dc->fn, be);
346  rc = 2;
347  goto bottom;
348  }
349  *be = '\0';
350 
351  /* Verify the manifest digest. */
352  { DIGEST_CTX ctx = rpmDigestInit(dc->dalgo, 0);
353 
354  if (F_ISSET(dc, HMAC))
355  (void) rpmHmacInit(ctx, hmackey, 0);
356 
357  (void) rpmDigestUpdate(ctx, (char *)iob->b, (be - (char *)iob->b));
358  digest = NULL;
359  (void) rpmDigestFinal(ctx, &digest, NULL, 1);
360  if (strcmp(dc->digest, digest)) {
361  fprintf(stderr,
362  _("%s: %s: Manifest digest check: Expected(%s) != (%s)\n"),
363  __progname, dc->fn, dc->digest, digest);
364  rc = 2;
365  goto bottom;
366  }
367  digest = _free(digest);
368  }
369 
370  /* Parse and save manifest items. */
371  lineno = 0;
372  for (f = (char *)iob->b; *f; f = fe) {
373  static const char hexdigits[] = "0123456789ABCDEFabcdef";
374  const char * _dn = NULL;
375  const char * path;
376 
377  lineno++;
378  fe = f;
379  while (*fe && !(*fe == '\n' || *fe == '\r'))
380  fe++;
381  while (*fe && (*fe == '\n' || *fe == '\r'))
382  *fe++ = '\0';
383  switch ((int)*f) {
384  case 'D':
385  _dn = f + 2;
386  continue;
387  /*@notreached@*/ break;
388  case 'F':
389  case 'S':
390  case 'X':
391  digest = f + 2;
392  f += 2;
393  while (*f && strchr(hexdigits, *f) != NULL)
394  f++;
395  if (*f != ' ') {
396  fprintf(stderr, _("%s: %s line %u: Malformed digest field.\n"),
397  __progname, dc->fn, lineno);
398  rc = 2;
399  goto bottom;
400  }
401  *f++ = '\0';
402  while (*f && xisdigit(*f))
403  f++;
404  if (*f != ' ') {
405  fprintf(stderr, _("%s: %s line %u: Malformed mtime field.\n"),
406  __progname, dc->fn, lineno);
407  rc = 2;
408  goto bottom;
409  }
410  *f++ = '\0';
411  while (*f && xisdigit(*f))
412  f++;
413  if (*f != ' ') {
414  fprintf(stderr, _("%s: %s line %u: Malformed size field.\n"),
415  __progname, dc->fn, lineno);
416  rc = 2;
417  goto bottom;
418  }
419  *f++ = '\0';
420  if (*f == '\0') {
421  fprintf(stderr, _("%s: %s line %u: No file path.\n"),
422  __progname, dc->fn, lineno);
423  rc = 2;
424  goto bottom;
425  }
426 
427  if (_dn && *_dn == '/')
428  path = rpmExpand(_dn+1, "/", f, NULL);
429  else
430  path = xstrdup(f);
431 
432  /* Save {algo, digest, path} for processing. */
433  xx = argiAdd(&dc->algos, -1, dc->dalgo);
434  xx = argvAdd(&dc->digests, digest);
435  xx = argvAdd(&dc->paths, path);
436  path = _free(path);
437  break;
438  }
439  }
440 
441 bottom:
442  iob = rpmiobFree(iob);
443  if (rc != 0)
444  goto exit;
445  }
446 
447 exit:
448  return rc;
449 }
450 
451 /*@null@*/
452 static const char * rpmdcPrintZeroInstall(rpmdc dc, int rc)
453 {
454  char * t, * te;
455  size_t nb = 0;
456  char _mtime[32];
457  char _size[32];
458  const struct stat * st = &dc->sb;
459  const char * _bn;
460 
461  /* Don't bother formatting if no one cares. */
462  if (rc == 0 && F_ISSET(dc, STATUS))
463  return NULL;
464 
465  snprintf(_mtime, sizeof(_mtime), "%llu",
466  (unsigned long long) st->st_mtime);
467  _mtime[sizeof(_mtime)-1] = '\0';
468  snprintf(_size, sizeof(_size), "%llu",
469  (unsigned long long) st->st_size);
470  _size[sizeof(_size)-1] = '\0';
471  if ((_bn = strrchr(dc->fn, '/')) != NULL)
472  _bn++;
473  else
474  _bn = dc->fn;
475 
476  /* Calculate size of message. */
477  nb += sizeof("F");
478  if (dc->digest != NULL && dc->digestlen > 0)
479  nb += 1 + dc->digestlen;
480  nb += 1 + strlen(_mtime);
481  nb += 1 + strlen(_size);
482  nb += 1 + strlen(_bn);
483  nb += sizeof("\n"); /* XXX trailing NUL */
484 
485  /* Compose the message. */
486  te = t = xmalloc(nb);
487  *te = '\0';
488 
489  if (dc->manifests) {
490  const char *msg = (rc ? "FAILED" : "OK");
491  if (rc || !F_ISSET(dc, STATUS)) {
492  if (dc->fn)
493  te = stpcpy( stpcpy(te, dc->fn), ": ");
494  te = stpcpy(te, msg);
495  *te++ = '\n';
496  }
497  } else {
498  if (S_ISDIR(st->st_mode)) {
499  *te++ = 'D';
500  if (_old_0install) {
501  *te++ = ' ';
502  te = stpcpy(te, _mtime);
503  }
504  *te++ = ' ';
505  *te++ = '/';
506  te = stpcpy(te, _bn);
507  *te++ = '\n';
508  } else if (S_ISREG(st->st_mode) || S_ISLNK(st->st_mode)) {
509  if (S_ISLNK(st->st_mode))
510  *te++ = 'S';
511  else
512  *te++ = (st->st_mode & (S_IXUSR|S_IXGRP|S_IXOTH)) ? 'X' : 'F';
513  *te++ = ' ';
514  te = stpcpy(te, dc->digest);
515  *te++ = ' ';
516  te = stpcpy(te, _mtime);
517  *te++ = ' ';
518  te = stpcpy(te, _size);
519  *te++ = ' ';
520  te = stpcpy(te, _bn);
521  *te++ = '\n';
522  }
523  }
524  *te = '\0';
525 
526  return t;
527 }
528 
529 /*==============================================================*/
530 
531 static int rpmdcPrintFile(rpmdc dc)
532 {
533  static int asAscii = 1;
534  int rc = 0;
535 
536 if (_rpmdc_debug)
537 fprintf(stderr, "\t%s(%p) fd %p fn %s\n", __FUNCTION__, dc, dc->fd, dc->fn);
538 
539 assert(dc->fd != NULL);
540  fdFiniDigest(dc->fd, dc->dalgo, &dc->digest, &dc->digestlen, asAscii);
541 assert(dc->digest != NULL);
542  dc->ncomputed++;
543 
544  if (dc->manifests) {
545  dc->nchecked++;
546  if ((rc = strcmp(dc->digest, dc->digests[dc->ix])) != 0)
547  dc->nfailed++;
548  else
549  dc->nmatched++;
550  }
551 
552  { const char * t = (*dc->print) (dc, rc);
553  if (dc->ofd && t && *t) {
554  size_t nb = strlen(t);
555  nb = Fwrite(t, nb, sizeof(*t), dc->ofd);
556  (void) Fflush(dc->ofd);
557  }
558  t = _free(t);
559  }
560 
561  dc->digest = _free(dc->digest);
562  dc->digestlen = 0;
563  return rc;
564 }
565 
566 static int rpmdcFiniFile(rpmdc dc)
567 {
568  uint32_t dalgo = (dc->manifests ? dc->algos->vals[dc->ix] : dc->algo);
569  int rc = 0;
570  int xx;
571 
572  /* Only regular files have dc->fd != NULL here. Skip all other paths. */
573  if (dc->fd == NULL)
574  return rc;
575 
576 if (_rpmdc_debug)
577 fprintf(stderr, "\t%s(%p) fn %s\n", __FUNCTION__, dc, dc->fn);
578  switch (dalgo) {
579  default:
580  dc->dalgo = dalgo;
581  dc->dalgoName = NULL;
582  xx = rpmdcPrintFile(dc);
583  if (xx) rc = xx;
584  break;
585  case 256: /* --all digests requested. */
586  { struct poptOption * opt = rpmioDigestPoptTable;
587  for (; (opt->longName || opt->shortName || opt->arg) ; opt++) {
588  if ((opt->argInfo & POPT_ARG_MASK) != POPT_ARG_VAL)
589  continue;
590  if (opt->arg != (void *)&rpmioDigestHashAlgo)
591  continue;
592  dc->dalgo = opt->val;
593  if (!(dc->dalgo > 0 && dc->dalgo < 256))
594  continue;
595  dc->dalgoName = opt->longName;
596  xx = rpmdcPrintFile(dc);
597  if (xx) rc = xx;
598  }
599  } break;
600  }
601 
602  (void) rpmswAdd(&dc->readops, fdstat_op(dc->fd, FDSTAT_READ));
603  (void) rpmswAdd(&dc->digestops, fdstat_op(dc->fd, FDSTAT_DIGEST));
604  Fclose(dc->fd);
605  dc->fd = NULL;
606 
607  return rc;
608 }
609 
610 static int rpmdcCalcFile(rpmdc dc)
611 {
612  int rc = 0;
613 
614 if (_rpmdc_debug)
615 fprintf(stderr, "\t%s(%p) fn %s\n", __FUNCTION__, dc, dc->fn);
616  /* Skip (unopened) non-files. */
617  if (dc->fd != NULL)
618  do {
619  dc->nb = Fread(dc->buf, sizeof(dc->buf[0]), sizeof(dc->buf), dc->fd);
620  if (Ferror(dc->fd)) {
621  rc = 2;
622  break;
623  }
624  } while (dc->nb > 0);
625 
626  return rc;
627 }
628 
629 static int rpmdcInitFile(rpmdc dc)
630 {
631  int rc = 0;
632 
633 if (_rpmdc_debug)
634 fprintf(stderr, "\t%s(%p) fn %s\n", __FUNCTION__, dc, dc->fn);
635  /* Skip non-files. */
636  if (!S_ISREG(dc->sb.st_mode)) {
637  /* XXX not found return code? */
638  goto exit;
639  }
640 
641  dc->fd = Fopen(dc->fn, "r.ufdio");
642  if (dc->fd == NULL || Ferror(dc->fd)) {
643  fprintf(stderr, _("open of %s failed: %s\n"), dc->fn, Fstrerror(dc->fd));
644  if (dc->fd != NULL) Fclose(dc->fd);
645  dc->fd = NULL;
646  rc = 2;
647  goto exit;
648  }
649 
650  switch (dc->algo) {
651  default:
652  /* XXX TODO: instantiate verify digests for all identical paths. */
653  dc->dalgo = dc->algo;
654  fdInitDigest(dc->fd, dc->dalgo, 0);
655  if (F_ISSET(dc, HMAC))
656  fdInitHmac(dc->fd, hmackey, 0);
657  break;
658  case 256: /* --all digests requested. */
659  { struct poptOption * opt = rpmioDigestPoptTable;
660  for (; (opt->longName || opt->shortName || opt->arg) ; opt++) {
661  if ((opt->argInfo & POPT_ARG_MASK) != POPT_ARG_VAL)
662  continue;
663  if (opt->longName == NULL)
664  continue;
665  if (!(opt->val > 0 && opt->val < 256))
666  continue;
667  dc->dalgo = opt->val;
668  dc->dalgoName = opt->longName;
669  fdInitDigest(dc->fd, dc->dalgo, 0);
670  if (F_ISSET(dc, HMAC))
671  fdInitHmac(dc->fd, hmackey, 0);
672  }
673  } break;
674  }
675 
676 exit:
677  return rc;
678 }
679 
680 static int
681 rpmdcVisitF(rpmdc dc)
682  /*@modifies dc @*/
683 {
684  int rc = 0;
685  int xx;
686 
687 if (_rpmdc_debug)
688 fprintf(stderr, "*** %s(%p) fn %s\n", __FUNCTION__, dc, dc->fn);
689  if ((xx = rpmdcInitFile(dc)) != 0)
690  rc = xx;
691  else {
692  if ((xx = rpmdcCalcFile(dc)) != 0)
693  rc = xx;
694  if ((xx = rpmdcFiniFile(dc)) != 0)
695  rc = xx;
696  }
697  return rc;
698 }
699 
700 static int
701 rpmdcSortLexical(const FTSENT ** a, const FTSENT ** b)
702  /*@*/
703 {
704  return strcmp((*a)->fts_name, (*b)->fts_name);
705 }
706 
707 static int
708 rpmdcSortDirsLast(const FTSENT ** a, const FTSENT ** b)
709  /*@*/
710 {
711  if (S_ISDIR((*a)->fts_statp->st_mode)) {
712  if (!S_ISDIR((*b)->fts_statp->st_mode))
713  return 1;
714  } else if (S_ISDIR((*b)->fts_statp->st_mode))
715  return -1;
716  return strcmp((*a)->fts_name, (*b)->fts_name);
717 }
718 
719 static int
720 rpmdcCWalk(rpmdc dc)
721 {
722  char *const * paths = (char * const *) dc->paths;
723  int ftsoptions = dc->ftsoptions;
724  int rval = 0;
725 
726  dc->t = Fts_open(paths, ftsoptions,
728  if (dc->t == NULL) {
729  fprintf(stderr, "Fts_open: %s", strerror(errno));
730  return -1;
731  }
732 
733  while ((dc->p = Fts_read(dc->t)) != NULL) {
734 #ifdef NOTYET
735  int indent = 0;
736  if (F_ISSET(dc, INDENT))
737  indent = dc->p->fts_level * 4;
738  if (rpmdcCheckExcludes(dc->p->fts_name, dc->p->fts_path)) {
739  (void) Fts_set(dc->t, dc->p, FTS_SKIP);
740  continue;
741  }
742 #endif
743 
744  dc->fn = dc->p->fts_path; /* XXX eliminate dc->fn */
745  memcpy(&dc->sb, dc->p->fts_statp, sizeof(dc->sb));
746 
747  switch(dc->p->fts_info) {
748  case FTS_D:
749 #ifdef NOTYET
750  if (!F_ISSET(dc, DIRSONLY))
751  (void) printf("\n");
752  if (!F_ISSET(dc, NOCOMMENT))
753  (void) printf("# %s\n", dc->p->fts_path);
754  (void) rpmdcVisitD(dc);
755 #endif
756  /* XXX don't visit topdirs for 0install. */
757  if (F_ISSET(dc, 0INSTALL) && dc->p->fts_level > 0)
758  rpmdcVisitF(dc);
759  /*@switchbreak@*/ break;
760  case FTS_DP:
761 #ifdef NOTYET
762  if (!F_ISSET(dc, NOCOMMENT) && (dc->p->fts_level > 0))
763  (void) printf("%*s# %s\n", indent, "", dc->p->fts_path);
764  (void) printf("%*s..\n", indent, "");
765  if (!F_ISSET(dc, DIRSONLY))
766  (void) printf("\n");
767 #endif
768  /*@switchbreak@*/ break;
769  case FTS_DNR:
770  case FTS_ERR:
771  case FTS_NS:
772  (void) fprintf(stderr, "%s: %s: %s\n", __progname,
773  dc->p->fts_path, strerror(dc->p->fts_errno));
774  /*@switchbreak@*/ break;
775  default:
776  if (!F_ISSET(dc, DIRSONLY))
777  rpmdcVisitF(dc);
778  /*@switchbreak@*/ break;
779  }
780  }
781  (void) Fts_close(dc->t);
782  dc->p = NULL;
783  dc->t = NULL;
784  return rval;
785 }
786 
787 static int rpmdcLoadManifests(rpmdc dc)
788  /*@globals h_errno, fileSystem, internalState @*/
789  /*@modifies dc, h_errno, fileSystem, internalState @*/
790 {
791  return (dc->manifests != NULL ? (*dc->parse) (dc) : 0);
792 }
793 
794 #if !defined(POPT_ARG_ARGV)
795 static int _poptSaveString(const char ***argvp, unsigned int argInfo, const char * val)
796  /*@*/
797 {
798  ARGV_t argv;
799  int argc = 0;
800  if (argvp == NULL)
801  return -1;
802  if (*argvp)
803  while ((*argvp)[argc] != NULL)
804  argc++;
805  *argvp = xrealloc(*argvp, (argc + 1 + 1) * sizeof(**argvp));
806  if ((argv = *argvp) != NULL) {
807  argv[argc++] = xstrdup(val);
808  argv[argc ] = NULL;
809  }
810  return 0;
811 }
812 
815 static void rpmdcArgCallback(poptContext con,
816  /*@unused@*/ enum poptCallbackReason reason,
817  const struct poptOption * opt, /*@unused@*/ const char * arg,
818  /*@unused@*/ void * data)
819  /*@globals fileSystem @*/
820  /*@modifies fileSystem @*/
821 {
822  /* XXX avoid accidental collisions with POPT_BIT_SET for flags */
823  if (opt->arg == NULL)
824  switch (opt->val) {
825  int xx;
826  case 'c':
827 assert(arg != NULL);
828  xx = _poptSaveString(&_dc.manifests, opt->argInfo, arg);
829  break;
830 
831  default:
832  fprintf(stderr, _("%s: Unknown option -%c\n"), __progname, opt->val);
833  poptPrintUsage(con, stderr, 0);
834 /*@-exitarg@*/
835  exit(2);
836 /*@=exitarg@*/
837  /*@notreached@*/ break;
838  }
839 }
840 #endif /* POPT_ARG_ARGV */
841 
842 static struct poptOption _optionsTable[] = {
843 #if !defined(POPT_ARG_ARGV)
844 /*@-type@*/ /* FIX: cast? */
845  { NULL, '\0', POPT_ARG_CALLBACK | POPT_CBFLAG_INC_DATA | POPT_CBFLAG_CONTINUE,
846  rpmdcArgCallback, 0, NULL, NULL },
847 /*@=type@*/
848 #endif /* POPT_ARG_ARGV */
849 
850  { "0install", '0', POPT_BIT_SET, &_dc.flags, RPMDC_FLAGS_0INSTALL,
851  N_("Print 0install manifest"), NULL },
852 
853  { "binary", 'b', POPT_BIT_SET, &_dc.flags, RPMDC_FLAGS_BINARY,
854  N_("Read in binary mode"), NULL },
855 
856 #if !defined(POPT_ARG_ARGV)
857  { "check", 'c', POPT_ARG_STRING, NULL, 'c',
858  N_("Read digests from MANIFEST file and verify (may be used more than once)"),
859  N_("MANIFEST") },
860 #else
861  { "check", 'c', POPT_ARG_ARGV, &_dc.manifests, 0,
862  N_("Read digests from MANIFEST file and verify (may be used more than once)"),
863  N_("MANIFEST") },
864 #endif
865  { "create",'c', POPT_BIT_SET, &_dc.flags, RPMDC_FLAGS_CREATE,
866  N_("Print file tree specification to stdout"), NULL },
867  { "dirs",'d', POPT_BIT_SET, &_dc.flags, RPMDC_FLAGS_DIRSONLY,
868  N_("Directories only"), NULL },
869 
870  { "text", 't', POPT_BIT_CLR, &_dc.flags, RPMDC_FLAGS_BINARY,
871  N_("read in text mode (default)"), NULL },
872 
873  { "hmac", '\0', POPT_BIT_SET, &_dc.flags, RPMDC_FLAGS_HMAC,
874  N_("generate HMAC's instead"), NULL },
875 
876 #ifdef NOTYET /* XXX todo for popt-1.15 */
877  { NULL, -1, POPT_ARG_INCLUDE_TABLE, NULL, 0,
878  N_("\
879 The following two options are useful only when verifying digests:\
880 "), NULL },
881 #endif
882 
883  { "status", '\0', POPT_BIT_SET, &_dc.flags, RPMDC_FLAGS_STATUS,
884  N_("no output when verifying"), NULL },
885  { "warn", 'w', POPT_BIT_SET, &_dc.flags, RPMDC_FLAGS_WARN,
886  N_("warn about improperly formatted checksum lines"), NULL },
887 
888  { NULL, '\0', POPT_ARG_INCLUDE_TABLE, rpmioDigestPoptTable, 0,
889  N_("Available digests:"), NULL },
890 
891  { NULL, '\0', POPT_ARG_INCLUDE_TABLE, rpmioAllPoptTable, 0,
892  N_("Common options for all rpmio executables:"), NULL },
893 
894  POPT_AUTOALIAS
895  POPT_AUTOHELP
896 
897  { NULL, -1, POPT_ARG_INCLUDE_TABLE, NULL, 0,
898  N_("\
899 When checking, the input should be a former output of this program. The\n\
900 default mode is to print a line with digest, a character indicating type\n\
901 (`*' for binary, ` ' for text), and name for each FILE.\n"), NULL },
902 
903  POPT_TABLEEND
904 };
905 
906 static struct poptOption *optionsTable = &_optionsTable[0];
907 
908 int
909 main(int argc, char *argv[])
910 {
911  poptContext optCon = rpmioInit(argc, argv, optionsTable);
912  ARGV_t av;
913  int ac;
914  int rc = 0;
915  int xx;
916 
917  rpmswEnter(&dc->totalops, -1);
918 
919  if (F_ISSET(dc, 0INSTALL)) {
922  if ((int)rpmioDigestHashAlgo < 0)
925  dc->oalgo = dc->algo;
926  dc->oalgoName = rpmdcAlgo2Name(dc->oalgo);
927  if (!strcmp(dc->oalgoName, "sha1"))
928  dc->oalgoName = "sha1new";
929  } else {
932  if ((int)rpmioDigestHashAlgo < 0)
935  }
936 
937  if (dc->ofn == NULL)
938  dc->ofn = "-";
939  dc->ftsoptions = rpmioFtsOpts;
940  if (!(dc->ftsoptions & (FTS_LOGICAL|FTS_PHYSICAL)))
941  dc->ftsoptions |= FTS_PHYSICAL;
942  dc->ftsoptions |= FTS_NOCHDIR;
943 
944  dc->ofd = Fopen(dc->ofn, "w.ufdio");
945  if (F_ISSET(dc, 0INSTALL)) {
946  fdInitDigest(dc->ofd, dc->oalgo, 0);
947  if (F_ISSET(dc, HMAC))
948  fdInitHmac(dc->ofd, hmackey, 0);
949  }
950 
951  av = poptGetArgs(optCon);
952  ac = argvCount(av);
953  if ((ac == 0 && dc->manifests == NULL)
954  || (ac > 0 && dc->manifests != NULL))
955  {
956  poptPrintUsage(optCon, stderr, 0);
957  rc = 2;
958  goto exit;
959  }
960 
961  if (dc->manifests != NULL) {
962  if ((xx = rpmdcLoadManifests(dc)) != 0)
963  rc = xx;
964  } else {
965  int i;
966  for (i = 0; i < ac; i++)
967  xx = argvAdd(&dc->paths, av[i]);
968  }
969  if (rc)
970  goto exit;
971 
972  if (dc->manifests != NULL) {
973  dc->ix = 0;
974  av = dc->paths;
975  if (av != NULL)
976  while ((dc->fn = *av++) != NULL) {
977  if ((xx = Lstat(dc->fn, &dc->sb)) != 0
978  || (xx = rpmdcVisitF(dc)) != 0)
979  rc = xx;
980  dc->ix++;
981  }
982  } else {
983  if ((xx = rpmdcCWalk(dc)) != 0)
984  rc = xx;
985  }
986 
987 exit:
988  if (dc->nfailed)
989  fprintf(stderr, "%s: WARNING: %u of %u computed checksums did NOT match\n",
990  __progname, (unsigned) dc->nfailed, (unsigned) dc->ncomputed);
991 
992  if (dc->ofd) {
993  /* Print the output spewage digest for 0install format manifests. */
994  if (rc == 0 && F_ISSET(dc, 0INSTALL) && dc->manifests == NULL) {
995  static int asAscii = 1;
996  char *t;
997  fdFiniDigest(dc->ofd, dc->oalgo, &dc->digest, &dc->digestlen, asAscii);
998 assert(dc->digest != NULL);
999  t = rpmExpand(dc->oalgoName, "=", dc->digest, "\n", NULL);
1000  (void) Fwrite(t, strlen(t), sizeof(*t), dc->ofd);
1001  t = _free(t);
1002  dc->digest = _free(dc->digest);
1003  }
1004  (void) Fclose(dc->ofd);
1005  dc->ofd = NULL;
1006  }
1007 
1008 #ifdef NOTYET
1009  dc->manifests = argvFree(dc->manifests);
1010 #endif
1011  dc->algos = argiFree(dc->algos);
1012  dc->digests = argvFree(dc->digests);
1013  dc->paths = argvFree(dc->paths);
1014 
1015  rpmswExit(&dc->totalops, 0);
1016  if (_rpmsw_stats) {
1017  rpmswPrint(" total:", &dc->totalops, NULL);
1018  rpmswPrint(" read:", &dc->readops, NULL);
1019  rpmswPrint("digest:", &dc->digestops, NULL);
1020  }
1021 
1022  optCon = rpmioFini(optCon);
1023 
1024  return rc;
1025 }
poptContext rpmioInit(int argc, char *const argv[], struct poptOption *optionsTable)
Definition: poptIO.c:752
const char * digest
Definition: rpmdigest.c:55
struct poptOption rpmioDigestPoptTable[]
Digest options using popt.
Definition: poptIO.c:151
rpmtime_t rpmswExit(rpmop op, ssize_t rc)
Exit timed operation.
Definition: rpmsw.c:264
static int rpmdcInitFile(rpmdc dc)
Definition: rpmdigest.c:629
FTS * Fts_open(char *const *argv, int options, int(*compar)(const FTSENT **, const FTSENT **))
Create a handle for file hierarchy traversal.
Definition: fts.c:207
static struct poptOption _optionsTable[]
Definition: rpmdigest.c:842
ARGint_t vals
Definition: argv.h:15
dcFlags_e
Bit field enum for rpmdigest CLI options.
Definition: rpmdigest.c:24
ARGI_t argiFree(ARGI_t argi)
Destroy an argi array.
Definition: argv.c:34
static const char * rpmdcPrintCoreutils(rpmdc dc, int rc)
Definition: rpmdigest.c:245
static int rpmdcSortLexical(const FTSENT **a, const FTSENT **b)
Definition: rpmdigest.c:701
size_t nmatched
Definition: rpmdigest.c:75
int main(int argc, char *argv[])
Definition: rpmdigest.c:909
size_t Fwrite(const void *buf, size_t size, size_t nmemb, FD_t fd)
fwrite(3) clone.
Definition: rpmio.c:2434
char * xstrdup(const char *str)
Definition: rpmmalloc.c:322
FD_t Fopen(const char *path, const char *_fmode)
fopen(3) clone.
Definition: rpmio.c:2833
DIGEST_CTX rpmDigestInit(pgpHashAlgo hashalgo, rpmDigestFlags flags)
Initialize digest.
Definition: digest.c:244
static const char hmackey[]
Definition: rpmdigest.c:93
const char * fn
Definition: rpmdigest.c:57
rpmtime_t rpmswAdd(rpmop to, rpmop from)
Sum statistic counters.
Definition: rpmsw.c:280
ARGV_t paths
Definition: rpmdigest.c:68
#define S_ISLNK(mode)
Definition: system.h:610
int Fflush(FD_t fd)
fflush(3) clone.
Definition: rpmio.c:2916
FTSENT * p
Definition: rpmdigest.c:47
int errno
#define FTS_NS
Definition: fts.h:138
static const char * rpmdcAlgo2Name(uint32_t dalgo)
Definition: rpmdigest.c:122
short fts_level
Definition: fts.h:127
rpmiob rpmiobFree(rpmiob iob)
Destroy a I/O buffer instance.
static void fdInitHmac(FD_t fd, const void *key, size_t keylen)
Attach digest to fd.
pgpHashAlgo rpmioDigestHashAlgo
Definition: poptIO.c:146
ssize_t nb
Definition: rpmdigest.c:70
static void fdInitDigest(FD_t fd, pgpHashAlgo hashalgo, int _flags)
Attach digest to fd.
struct rpmop_s totalops
Definition: rpmdigest.c:77
struct rpmop_s digestops
Definition: rpmdigest.c:79
size_t digestlen
Definition: rpmdigest.c:56
void rpmswPrint(const char *name, rpmop op, FILE *fp)
Print operation statistics.
Definition: rpmsw.c:304
static int _rpmdc_debug
Definition: rpmdigest.c:11
static rpmop fdstat_op(FD_t fd, fdOpX opx)
static int rpmdcSortDirsLast(const FTSENT **a, const FTSENT **b)
Definition: rpmdigest.c:708
int rpmiobSlurp(const char *fn, rpmiob *iobp)
Definition: rpmiob.c:130
int rpmHmacInit(DIGEST_CTX ctx, const void *key, size_t keylen)
Compute key material and add to digest context.
Definition: digest.c:983
const char * oalgoName
Definition: rpmdigest.c:64
u_short fts_info
Definition: fts.h:143
const char * ofn
Definition: rpmdigest.c:61
struct rpmop_s readops
Definition: rpmdigest.c:78
#define FTS_D
Definition: fts.h:129
#define fdGetFILE(_fd)
Definition: rpmio.c:157
const char * Fstrerror(FD_t fd)
strerror(3) clone.
Definition: rpmio.c:2401
static int _old_0install
Definition: rpmdigest.c:14
int rpmDigestUpdate(DIGEST_CTX ctx, const void *data, size_t len)
Update context with next plain text buffer.
Definition: digest.c:907
#define _DFB(n)
Definition: rpmdigest.c:17
static void rpmdcArgCallback(poptContext con, enum poptCallbackReason reason, const struct poptOption *opt, const char *arg, void *data)
Definition: rpmdigest.c:815
#define N_(Text)
Definition: system.h:490
static int rpmdcFiniFile(rpmdc dc)
Definition: rpmdigest.c:566
ARGV_t digests
Definition: rpmdigest.c:67
FD_t ofd
Definition: rpmdigest.c:62
int(* parse)(rpmdc dc)
Definition: rpmdigest.c:59
int argvCount(const ARGV_t argv)
Return no.
Definition: argv.c:71
static int rpmdcParseCoreutils(rpmdc dc)
Definition: rpmdigest.c:145
int Lstat(const char *path, struct stat *st)
lstat(2) clone.
Definition: rpmrpc.c:1401
static int xisspace(int c)
Definition: rpmiotypes.h:446
ARGV_t argvFree(ARGV_t argv)
Destroy an argv array.
Definition: argv.c:44
static int rpmdcVisitF(rpmdc dc)
Definition: rpmdigest.c:681
static struct rpmdc_s _dc
Definition: rpmdigest.c:84
static int rpmdcPrintFile(rpmdc dc)
Definition: rpmdigest.c:531
FTS * t
Definition: rpmdigest.c:46
Digest private data.
Definition: digest.c:127
static int rpmdcCWalk(rpmdc dc)
Definition: rpmdigest.c:720
static int _poptSaveString(const char ***argvp, unsigned int argInfo, const char *val)
Definition: rpmdigest.c:795
char * fts_path
Definition: fts.h:115
The FD_t File Handle data structure.
static void fdFiniDigest(FD_t fd, pgpHashAlgo hashalgo, void *datap, size_t *lenp, int asAscii)
int argvAdd(ARGV_t *argvp, ARGstr_t val)
Add a string to an argv array.
Definition: argv.c:199
Definition: fts.h:54
static int rpmdcCalcFile(rpmdc dc)
Definition: rpmdigest.c:610
int rpmioFtsOpts
Definition: poptIO.c:526
FTSENT * Fts_read(FTS *sp)
Return next node in the file hierarchy traversal.
Definition: fts.c:467
int rpmswEnter(rpmop op, ssize_t rc)
Enter timed operation.
Definition: rpmsw.c:248
char * rpmExpand(const char *arg,...)
Return (malloc&#39;ed) concatenated macro expansion(s).
Definition: macro.c:3117
size_t Fread(void *buf, size_t size, size_t nmemb, FD_t fd)
fread(3) clone.
Definition: rpmio.c:2412
ARGV_t manifests
Definition: rpmdigest.c:65
static const char * rpmdcPrintZeroInstall(rpmdc dc, int rc)
Definition: rpmdigest.c:452
static rpmdc dc
Definition: rpmdigest.c:91
int Fclose(FD_t fd)
fclose(3) clone.
Definition: rpmio.c:2534
size_t nfailed
Definition: rpmdigest.c:76
Cumulative statistics for an operation.
Definition: rpmsw.h:33
const char * dalgoName
Definition: rpmdigest.c:54
#define FTS_DNR
Definition: fts.h:132
size_t nchecked
Definition: rpmdigest.c:74
uint32_t dalgo
Definition: rpmdigest.c:52
int Fts_set(FTS *sp, FTSENT *p, int instr)
Modify the traversal for a file set member.
Definition: fts.c:688
static int rpmdcParseZeroInstall(rpmdc dc)
Definition: rpmdigest.c:294
int ix
Definition: rpmdigest.c:71
size_t ncomputed
Definition: rpmdigest.c:73
char fts_name[1]
Definition: fts.h:157
const char *(* print)(rpmdc dc, int rc)
Definition: rpmdigest.c:60
int Ferror(FD_t fd)
ferror(3) clone.
Definition: rpmio.c:2944
#define F_ISSET(_dc, _FLAG)
Definition: rpmdigest.c:19
static uint32_t rpmdcName2Algo(const char *dname)
Definition: rpmdigest.c:96
static int xisdigit(int c)
Definition: rpmiotypes.h:437
static int snprintf(char *buf, int nb, const char *fmt,...)
Definition: rpmps.c:220
struct rpmdc_s * rpmdc
Definition: rpmdigest.c:40
#define FTS_NOCHDIR
Definition: fts.h:89
Definition: fts.h:102
static int rpmdcLoadManifests(rpmdc dc)
Definition: rpmdigest.c:787
struct stat sb
Definition: rpmdigest.c:48
ARGI_t algos
Definition: rpmdigest.c:66
static struct poptOption * optionsTable
Definition: rpmdigest.c:906
struct stat * fts_statp
Definition: fts.h:156
char * stpcpy(char *dest, const char *src)
int fts_errno
Definition: fts.h:116
static void * _free(const void *p)
Wrapper to free(3), hides const compilation noise, permit NULL, return NULL.
Definition: rpmiotypes.h:647
struct rpmiob_s * rpmiob
Definition: rpmiotypes.h:57
int argiAdd(ARGI_t *argip, int ix, int val)
Add an int to an argi array.
Definition: argv.c:178
enum dcFlags_e flags
Definition: rpmdigest.c:50
#define FTS_PHYSICAL
Definition: fts.h:91
#define FTS_LOGICAL
Definition: fts.h:88
int Fts_close(FTS *sp)
Destroy a file hierarchy traversal handle.
Definition: fts.c:380
int _rpmsw_stats
Definition: rpmsw.c:20
int rpmDigestFinal(DIGEST_CTX ctx, void *datap, size_t *lenp, int asAscii)
Return digest and destroy context.
Definition: digest.c:921
unsigned char buf[BUFSIZ]
Definition: rpmdigest.c:69
static int indent
Definition: rpmgi.c:47
int ftsoptions
Definition: rpmdigest.c:45
#define _(Text)
Definition: system.h:30
#define xmalloc
Definition: system.h:33
#define FTS_DP
Definition: fts.h:134
ARGstr_t * ARGV_t
Definition: argv.h:9
struct poptOption rpmioAllPoptTable[]
Definition: poptIO.c:551
uint32_t oalgo
Definition: rpmdigest.c:63
poptContext rpmioFini(poptContext optCon)
Definition: poptIO.c:719
FD_t fd
Definition: rpmdigest.c:58
uint32_t algo
Definition: rpmdigest.c:51
Definition: argv.h:13
const char * __progname
Definition: poptIO.c:65
#define FTS_ERR
Definition: fts.h:135
#define xrealloc
Definition: system.h:36
#define FTS_SKIP
Definition: fts.h:152