rpm  5.4.15
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 assert(dc->fn); /* XXX coverity #1035807 */
285  te = stpcpy(te, dc->fn);
286  *te++ = '\n';
287  }
288  *te = '\0';
289 
290  return t;
291 }
292 
293 /*==============================================================*/
294 
295 static int rpmdcParseZeroInstall(rpmdc dc)
296  /*@globals h_errno, fileSystem, internalState @*/
297  /*@modifies h_errno, fileSystem, internalState @*/
298 {
299  int rc = 0; /* assume success */
300 
301  if (dc->manifests != NULL) /* note rc=0 return with no files to load. */
302  while ((dc->fn = *dc->manifests++) != NULL) {
303  unsigned lineno;
304  char * be;
305  rpmiob iob = NULL;
306  int xx = rpmiobSlurp(dc->fn, &iob);
307  const char * digest;
308  char * f;
309  char * fe;
310 
311  if (!(xx == 0 && iob != NULL)) {
312  fprintf(stderr, _("%s: Failed to open %s\n"), __progname, dc->fn);
313  rc = -1;
314  goto bottom;
315  }
316 
317  be = (char *)(iob->b + iob->blen);
318  while (be > (char *)iob->b && (be[-1] == '\n' || be[-1] == '\r')) {
319  be--;
320  *be = '\0';
321  }
322 
323  /* Parse "algo=digest" from last line. */
324  be = strrchr((char *)iob->b, '=');
325  if (be == NULL) {
326  fprintf(stderr,
327  _("%s: %s: Manifest needs \"algo=digest\" as last line\n"),
328  __progname, dc->fn);
329  rc = 2;
330  goto bottom;
331  }
332  *be = '\0';
333  dc->digest = be + 1;
334  while (be > (char *)iob->b && !(be[-1] == '\n' || be[-1] == '\r'))
335  be--;
336  if (be <= (char *)iob->b) {
337  fprintf(stderr, _("%s: %s: Manifest is empty\n"),
338  __progname, dc->fn);
339  rc = 2;
340  goto bottom;
341  }
342 
343  /* Map name to algorithm number. */
344  if ((dc->dalgo = rpmdcName2Algo(be)) == 0xffffffff) {
345  fprintf(stderr, _("%s: %s: Unknown digest algo name \"%s\"\n"),
346  __progname, dc->fn, be);
347  rc = 2;
348  goto bottom;
349  }
350  *be = '\0';
351 
352  /* Verify the manifest digest. */
353  { DIGEST_CTX ctx = rpmDigestInit(dc->dalgo, 0);
354 
355  if (F_ISSET(dc, HMAC))
356  (void) rpmHmacInit(ctx, hmackey, 0);
357 
358  (void) rpmDigestUpdate(ctx, (char *)iob->b, (be - (char *)iob->b));
359  digest = NULL;
360  (void) rpmDigestFinal(ctx, &digest, NULL, 1);
361  if (strcmp(dc->digest, digest)) {
362  fprintf(stderr,
363  _("%s: %s: Manifest digest check: Expected(%s) != (%s)\n"),
364  __progname, dc->fn, dc->digest, digest);
365  rc = 2;
366  goto bottom;
367  }
368  digest = _free(digest);
369  }
370 
371  /* Parse and save manifest items. */
372  lineno = 0;
373  for (f = (char *)iob->b; *f; f = fe) {
374  static const char hexdigits[] = "0123456789ABCDEFabcdef";
375  const char * _dn = NULL;
376  const char * path;
377 
378  lineno++;
379  fe = f;
380  while (*fe && !(*fe == '\n' || *fe == '\r'))
381  fe++;
382  while (*fe && (*fe == '\n' || *fe == '\r'))
383  *fe++ = '\0';
384  switch ((int)*f) {
385  case 'D':
386  _dn = f + 2;
387  continue;
388  /*@notreached@*/ break;
389  case 'F':
390  case 'S':
391  case 'X':
392  digest = f + 2;
393  f += 2;
394  while (*f && strchr(hexdigits, *f) != NULL)
395  f++;
396  if (*f != ' ') {
397  fprintf(stderr, _("%s: %s line %u: Malformed digest field.\n"),
398  __progname, dc->fn, lineno);
399  rc = 2;
400  goto bottom;
401  }
402  *f++ = '\0';
403  while (*f && xisdigit(*f))
404  f++;
405  if (*f != ' ') {
406  fprintf(stderr, _("%s: %s line %u: Malformed mtime field.\n"),
407  __progname, dc->fn, lineno);
408  rc = 2;
409  goto bottom;
410  }
411  *f++ = '\0';
412  while (*f && xisdigit(*f))
413  f++;
414  if (*f != ' ') {
415  fprintf(stderr, _("%s: %s line %u: Malformed size field.\n"),
416  __progname, dc->fn, lineno);
417  rc = 2;
418  goto bottom;
419  }
420  *f++ = '\0';
421  if (*f == '\0') {
422  fprintf(stderr, _("%s: %s line %u: No file path.\n"),
423  __progname, dc->fn, lineno);
424  rc = 2;
425  goto bottom;
426  }
427 
428  if (_dn && *_dn == '/')
429  path = rpmExpand(_dn+1, "/", f, NULL);
430  else
431  path = xstrdup(f);
432 
433  /* Save {algo, digest, path} for processing. */
434  xx = argiAdd(&dc->algos, -1, dc->dalgo);
435  xx = argvAdd(&dc->digests, digest);
436  xx = argvAdd(&dc->paths, path);
437  path = _free(path);
438  break;
439  }
440  }
441 
442 bottom:
443  iob = rpmiobFree(iob);
444  if (rc != 0)
445  goto exit;
446  }
447 
448 exit:
449  return rc;
450 }
451 
452 /*@null@*/
453 static const char * rpmdcPrintZeroInstall(rpmdc dc, int rc)
454 {
455  char * t, * te;
456  size_t nb = 0;
457  char _mtime[32];
458  char _size[32];
459  const struct stat * st = &dc->sb;
460  const char * _bn;
461 
462  /* Don't bother formatting if no one cares. */
463  if (rc == 0 && F_ISSET(dc, STATUS))
464  return NULL;
465 
466  snprintf(_mtime, sizeof(_mtime), "%llu",
467  (unsigned long long) st->st_mtime);
468  _mtime[sizeof(_mtime)-1] = '\0';
469  snprintf(_size, sizeof(_size), "%llu",
470  (unsigned long long) st->st_size);
471  _size[sizeof(_size)-1] = '\0';
472 assert(dc->fn); /* XXX coverity #1035950 */
473  if ((_bn = strrchr(dc->fn, '/')) != NULL)
474  _bn++;
475  else
476  _bn = dc->fn;
477 
478  /* Calculate size of message. */
479  nb += sizeof("F");
480  if (dc->digest != NULL && dc->digestlen > 0)
481  nb += 1 + dc->digestlen;
482  nb += 1 + strlen(_mtime);
483  nb += 1 + strlen(_size);
484  nb += 1 + strlen(_bn);
485  nb += sizeof("\n"); /* XXX trailing NUL */
486 
487  /* Compose the message. */
488  te = t = xmalloc(nb);
489  *te = '\0';
490 
491  if (dc->manifests) {
492  const char *msg = (rc ? "FAILED" : "OK");
493  if (rc || !F_ISSET(dc, STATUS)) {
494  te = stpcpy( stpcpy(te, dc->fn), ": ");
495  te = stpcpy(te, msg);
496  *te++ = '\n';
497  }
498  } else {
499  if (S_ISDIR(st->st_mode)) {
500  *te++ = 'D';
501  if (_old_0install) {
502  *te++ = ' ';
503  te = stpcpy(te, _mtime);
504  }
505  *te++ = ' ';
506  *te++ = '/';
507  te = stpcpy(te, _bn);
508  *te++ = '\n';
509  } else if (S_ISREG(st->st_mode) || S_ISLNK(st->st_mode)) {
510  if (S_ISLNK(st->st_mode))
511  *te++ = 'S';
512  else
513  *te++ = (st->st_mode & (S_IXUSR|S_IXGRP|S_IXOTH)) ? 'X' : 'F';
514  *te++ = ' ';
515 assert(dc->digest); /* XXX coverity #1035808 */
516  te = stpcpy(te, dc->digest);
517  *te++ = ' ';
518  te = stpcpy(te, _mtime);
519  *te++ = ' ';
520  te = stpcpy(te, _size);
521  *te++ = ' ';
522  te = stpcpy(te, _bn);
523  *te++ = '\n';
524  }
525  }
526  *te = '\0';
527 
528  return t;
529 }
530 
531 /*==============================================================*/
532 
533 static int rpmdcPrintFile(rpmdc dc)
534 {
535  static int asAscii = 1;
536  int rc = 0;
537 
538 if (_rpmdc_debug)
539 fprintf(stderr, "\t%s(%p) fd %p fn %s\n", __FUNCTION__, dc, dc->fd, dc->fn);
540 
541 assert(dc->fd != NULL);
542  fdFiniDigest(dc->fd, dc->dalgo, &dc->digest, &dc->digestlen, asAscii);
543 assert(dc->digest != NULL);
544  dc->ncomputed++;
545 
546  if (dc->manifests) {
547  dc->nchecked++;
548  if ((rc = strcmp(dc->digest, dc->digests[dc->ix])) != 0)
549  dc->nfailed++;
550  else
551  dc->nmatched++;
552  }
553 
554  { const char * t = (*dc->print) (dc, rc);
555  if (dc->ofd && t && *t) {
556  size_t nb = strlen(t);
557  nb = Fwrite(t, nb, sizeof(*t), dc->ofd);
558  (void) Fflush(dc->ofd);
559  }
560  t = _free(t);
561  }
562 
563  dc->digest = _free(dc->digest);
564  dc->digestlen = 0;
565  return rc;
566 }
567 
568 static int rpmdcFiniFile(rpmdc dc)
569 {
570  uint32_t dalgo = (dc->manifests ? dc->algos->vals[dc->ix] : dc->algo);
571  int rc = 0;
572  int xx;
573 
574  /* Only regular files have dc->fd != NULL here. Skip all other paths. */
575  if (dc->fd == NULL)
576  return rc;
577 
578 if (_rpmdc_debug)
579 fprintf(stderr, "\t%s(%p) fn %s\n", __FUNCTION__, dc, dc->fn);
580  switch (dalgo) {
581  default:
582  dc->dalgo = dalgo;
583  dc->dalgoName = NULL;
584  xx = rpmdcPrintFile(dc);
585  if (xx) rc = xx;
586  break;
587  case 256: /* --all digests requested. */
588  { struct poptOption * opt = rpmioDigestPoptTable;
589  for (; (opt->longName || opt->shortName || opt->arg) ; opt++) {
590  if ((opt->argInfo & POPT_ARG_MASK) != POPT_ARG_VAL)
591  continue;
592  if (opt->arg != (void *)&rpmioDigestHashAlgo)
593  continue;
594  dc->dalgo = opt->val;
595  if (!(dc->dalgo > 0 && dc->dalgo < 256))
596  continue;
597  dc->dalgoName = opt->longName;
598  xx = rpmdcPrintFile(dc);
599  if (xx) rc = xx;
600  }
601  } break;
602  }
603 
604  (void) rpmswAdd(&dc->readops, fdstat_op(dc->fd, FDSTAT_READ));
605  (void) rpmswAdd(&dc->digestops, fdstat_op(dc->fd, FDSTAT_DIGEST));
606  Fclose(dc->fd);
607  dc->fd = NULL;
608 
609  return rc;
610 }
611 
612 static int rpmdcCalcFile(rpmdc dc)
613 {
614  int rc = 0;
615 
616 if (_rpmdc_debug)
617 fprintf(stderr, "\t%s(%p) fn %s\n", __FUNCTION__, dc, dc->fn);
618  /* Skip (unopened) non-files. */
619  if (dc->fd != NULL)
620  do {
621  dc->nb = Fread(dc->buf, sizeof(dc->buf[0]), sizeof(dc->buf), dc->fd);
622  if (Ferror(dc->fd)) {
623  rc = 2;
624  break;
625  }
626  } while (dc->nb > 0);
627 
628  return rc;
629 }
630 
631 static int rpmdcInitFile(rpmdc dc)
632 {
633  int rc = 0;
634 
635 if (_rpmdc_debug)
636 fprintf(stderr, "\t%s(%p) fn %s\n", __FUNCTION__, dc, dc->fn);
637  /* Skip non-files. */
638  if (!S_ISREG(dc->sb.st_mode)) {
639  /* XXX not found return code? */
640  goto exit;
641  }
642 
643  dc->fd = Fopen(dc->fn, "r.ufdio");
644  if (dc->fd == NULL || Ferror(dc->fd)) {
645  fprintf(stderr, _("open of %s failed: %s\n"), dc->fn, Fstrerror(dc->fd));
646  if (dc->fd != NULL) Fclose(dc->fd);
647  dc->fd = NULL;
648  rc = 2;
649  goto exit;
650  }
651 
652  switch (dc->algo) {
653  default:
654  /* XXX TODO: instantiate verify digests for all identical paths. */
655  dc->dalgo = dc->algo;
656  fdInitDigest(dc->fd, dc->dalgo, 0);
657  if (F_ISSET(dc, HMAC))
658  fdInitHmac(dc->fd, hmackey, 0);
659  break;
660  case 256: /* --all digests requested. */
661  { struct poptOption * opt = rpmioDigestPoptTable;
662  for (; (opt->longName || opt->shortName || opt->arg) ; opt++) {
663  if ((opt->argInfo & POPT_ARG_MASK) != POPT_ARG_VAL)
664  continue;
665  if (opt->longName == NULL)
666  continue;
667  if (!(opt->val > 0 && opt->val < 256))
668  continue;
669  dc->dalgo = opt->val;
670  dc->dalgoName = opt->longName;
671  fdInitDigest(dc->fd, dc->dalgo, 0);
672  if (F_ISSET(dc, HMAC))
673  fdInitHmac(dc->fd, hmackey, 0);
674  }
675  } break;
676  }
677 
678 exit:
679  return rc;
680 }
681 
682 static int
683 rpmdcVisitF(rpmdc dc)
684  /*@modifies dc @*/
685 {
686  int rc = 0;
687  int xx;
688 
689 if (_rpmdc_debug)
690 fprintf(stderr, "*** %s(%p) fn %s\n", __FUNCTION__, dc, dc->fn);
691  if ((xx = rpmdcInitFile(dc)) != 0)
692  rc = xx;
693  else {
694  if ((xx = rpmdcCalcFile(dc)) != 0)
695  rc = xx;
696  if ((xx = rpmdcFiniFile(dc)) != 0)
697  rc = xx;
698  }
699  return rc;
700 }
701 
702 static int
703 rpmdcSortLexical(const FTSENT ** a, const FTSENT ** b)
704  /*@*/
705 {
706  return strcmp((*a)->fts_name, (*b)->fts_name);
707 }
708 
709 static int
710 rpmdcSortDirsLast(const FTSENT ** a, const FTSENT ** b)
711  /*@*/
712 {
713  if (S_ISDIR((*a)->fts_statp->st_mode)) {
714  if (!S_ISDIR((*b)->fts_statp->st_mode))
715  return 1;
716  } else if (S_ISDIR((*b)->fts_statp->st_mode))
717  return -1;
718  return strcmp((*a)->fts_name, (*b)->fts_name);
719 }
720 
721 static int
722 rpmdcCWalk(rpmdc dc)
723 {
724  char *const * paths = (char * const *) dc->paths;
725  int ftsoptions = dc->ftsoptions;
726  int rval = 0;
727 
728  dc->t = Fts_open(paths, ftsoptions,
730  if (dc->t == NULL) {
731  fprintf(stderr, "Fts_open: %s", strerror(errno));
732  return -1;
733  }
734 
735  while ((dc->p = Fts_read(dc->t)) != NULL) {
736 #ifdef NOTYET
737  int indent = 0;
738  if (F_ISSET(dc, INDENT))
739  indent = dc->p->fts_level * 4;
740  if (rpmdcCheckExcludes(dc->p->fts_name, dc->p->fts_path)) {
741  (void) Fts_set(dc->t, dc->p, FTS_SKIP);
742  continue;
743  }
744 #endif
745 
746  dc->fn = dc->p->fts_path; /* XXX eliminate dc->fn */
747  memcpy(&dc->sb, dc->p->fts_statp, sizeof(dc->sb));
748 
749  switch(dc->p->fts_info) {
750  case FTS_D:
751 #ifdef NOTYET
752  if (!F_ISSET(dc, DIRSONLY))
753  (void) printf("\n");
754  if (!F_ISSET(dc, NOCOMMENT))
755  (void) printf("# %s\n", dc->p->fts_path);
756  (void) rpmdcVisitD(dc);
757 #endif
758  /* XXX don't visit topdirs for 0install. */
759  if (F_ISSET(dc, 0INSTALL) && dc->p->fts_level > 0)
760  rpmdcVisitF(dc);
761  /*@switchbreak@*/ break;
762  case FTS_DP:
763 #ifdef NOTYET
764  if (!F_ISSET(dc, NOCOMMENT) && (dc->p->fts_level > 0))
765  (void) printf("%*s# %s\n", indent, "", dc->p->fts_path);
766  (void) printf("%*s..\n", indent, "");
767  if (!F_ISSET(dc, DIRSONLY))
768  (void) printf("\n");
769 #endif
770  /*@switchbreak@*/ break;
771  case FTS_DNR:
772  case FTS_ERR:
773  case FTS_NS:
774  (void) fprintf(stderr, "%s: %s: %s\n", __progname,
775  dc->p->fts_path, strerror(dc->p->fts_errno));
776  /*@switchbreak@*/ break;
777  default:
778  if (!F_ISSET(dc, DIRSONLY))
779  rpmdcVisitF(dc);
780  /*@switchbreak@*/ break;
781  }
782  }
783  (void) Fts_close(dc->t);
784  dc->p = NULL;
785  dc->t = NULL;
786  return rval;
787 }
788 
789 static int rpmdcLoadManifests(rpmdc dc)
790  /*@globals h_errno, fileSystem, internalState @*/
791  /*@modifies dc, h_errno, fileSystem, internalState @*/
792 {
793  return (dc->manifests != NULL ? (*dc->parse) (dc) : 0);
794 }
795 
796 #if !defined(POPT_ARG_ARGV)
797 static int _poptSaveString(const char ***argvp, unsigned int argInfo, const char * val)
798  /*@*/
799 {
800  ARGV_t argv;
801  int argc = 0;
802  if (argvp == NULL)
803  return -1;
804  if (*argvp)
805  while ((*argvp)[argc] != NULL)
806  argc++;
807  *argvp = xrealloc(*argvp, (argc + 1 + 1) * sizeof(**argvp));
808  if ((argv = *argvp) != NULL) {
809  argv[argc++] = xstrdup(val);
810  argv[argc ] = NULL;
811  }
812  return 0;
813 }
814 
817 static void rpmdcArgCallback(poptContext con,
818  /*@unused@*/ enum poptCallbackReason reason,
819  const struct poptOption * opt, /*@unused@*/ const char * arg,
820  /*@unused@*/ void * data)
821  /*@globals fileSystem @*/
822  /*@modifies fileSystem @*/
823 {
824  /* XXX avoid accidental collisions with POPT_BIT_SET for flags */
825  if (opt->arg == NULL)
826  switch (opt->val) {
827  int xx;
828  case 'c':
829 assert(arg != NULL);
830  xx = _poptSaveString(&_dc.manifests, opt->argInfo, arg);
831  break;
832 
833  default:
834  fprintf(stderr, _("%s: Unknown option -%c\n"), __progname, opt->val);
835  poptPrintUsage(con, stderr, 0);
836 /*@-exitarg@*/
837  exit(2);
838 /*@=exitarg@*/
839  /*@notreached@*/ break;
840  }
841 }
842 #endif /* POPT_ARG_ARGV */
843 
844 static struct poptOption _optionsTable[] = {
845 #if !defined(POPT_ARG_ARGV)
846 /*@-type@*/ /* FIX: cast? */
847  { NULL, '\0', POPT_ARG_CALLBACK | POPT_CBFLAG_INC_DATA | POPT_CBFLAG_CONTINUE,
848  rpmdcArgCallback, 0, NULL, NULL },
849 /*@=type@*/
850 #endif /* POPT_ARG_ARGV */
851 
852  { "0install", '0', POPT_BIT_SET, &_dc.flags, RPMDC_FLAGS_0INSTALL,
853  N_("Print 0install manifest"), NULL },
854 
855  { "binary", 'b', POPT_BIT_SET, &_dc.flags, RPMDC_FLAGS_BINARY,
856  N_("Read in binary mode"), NULL },
857 
858 #if !defined(POPT_ARG_ARGV)
859  { "check", 'c', POPT_ARG_STRING, NULL, 'c',
860  N_("Read digests from MANIFEST file and verify (may be used more than once)"),
861  N_("MANIFEST") },
862 #else
863  { "check", 'c', POPT_ARG_ARGV, &_dc.manifests, 0,
864  N_("Read digests from MANIFEST file and verify (may be used more than once)"),
865  N_("MANIFEST") },
866 #endif
867  { "create",'c', POPT_BIT_SET, &_dc.flags, RPMDC_FLAGS_CREATE,
868  N_("Print file tree specification to stdout"), NULL },
869  { "dirs",'d', POPT_BIT_SET, &_dc.flags, RPMDC_FLAGS_DIRSONLY,
870  N_("Directories only"), NULL },
871 
872  { "text", 't', POPT_BIT_CLR, &_dc.flags, RPMDC_FLAGS_BINARY,
873  N_("read in text mode (default)"), NULL },
874 
875  { "hmac", '\0', POPT_BIT_SET, &_dc.flags, RPMDC_FLAGS_HMAC,
876  N_("generate HMAC's instead"), NULL },
877 
878 #ifdef NOTYET /* XXX todo for popt-1.15 */
879  { NULL, -1, POPT_ARG_INCLUDE_TABLE, NULL, 0,
880  N_("\
881 The following two options are useful only when verifying digests:\
882 "), NULL },
883 #endif
884 
885  { "status", '\0', POPT_BIT_SET, &_dc.flags, RPMDC_FLAGS_STATUS,
886  N_("no output when verifying"), NULL },
887  { "warn", 'w', POPT_BIT_SET, &_dc.flags, RPMDC_FLAGS_WARN,
888  N_("warn about improperly formatted checksum lines"), NULL },
889 
890  { NULL, '\0', POPT_ARG_INCLUDE_TABLE, rpmioDigestPoptTable, 0,
891  N_("Available digests:"), NULL },
892 
893  { NULL, '\0', POPT_ARG_INCLUDE_TABLE, rpmioAllPoptTable, 0,
894  N_("Common options for all rpmio executables:"), NULL },
895 
896  POPT_AUTOALIAS
897  POPT_AUTOHELP
898 
899  { NULL, -1, POPT_ARG_INCLUDE_TABLE, NULL, 0,
900  N_("\
901 When checking, the input should be a former output of this program. The\n\
902 default mode is to print a line with digest, a character indicating type\n\
903 (`*' for binary, ` ' for text), and name for each FILE.\n"), NULL },
904 
905  POPT_TABLEEND
906 };
907 
908 static struct poptOption *optionsTable = &_optionsTable[0];
909 
910 int
911 main(int argc, char *argv[])
912 {
913  poptContext optCon = rpmioInit(argc, argv, optionsTable);
914  ARGV_t av;
915  int ac;
916  int rc = 0;
917  int xx;
918 
919  rpmswEnter(&dc->totalops, -1);
920 
921  if (F_ISSET(dc, 0INSTALL)) {
924  if ((int)rpmioDigestHashAlgo < 0)
927  dc->oalgo = dc->algo;
928  dc->oalgoName = rpmdcAlgo2Name(dc->oalgo);
929  if (!strcmp(dc->oalgoName, "sha1"))
930  dc->oalgoName = "sha1new";
931  } else {
934  if ((int)rpmioDigestHashAlgo < 0)
937  }
938 
939  if (dc->ofn == NULL)
940  dc->ofn = "-";
941  dc->ftsoptions = rpmioFtsOpts;
942  if (!(dc->ftsoptions & (FTS_LOGICAL|FTS_PHYSICAL)))
943  dc->ftsoptions |= FTS_PHYSICAL;
944  dc->ftsoptions |= FTS_NOCHDIR;
945 
946  dc->ofd = Fopen(dc->ofn, "w.ufdio");
947  if (F_ISSET(dc, 0INSTALL)) {
948  fdInitDigest(dc->ofd, dc->oalgo, 0);
949  if (F_ISSET(dc, HMAC))
950  fdInitHmac(dc->ofd, hmackey, 0);
951  }
952 
953  av = poptGetArgs(optCon);
954  ac = argvCount(av);
955  if ((ac == 0 && dc->manifests == NULL)
956  || (ac > 0 && dc->manifests != NULL))
957  {
958  poptPrintUsage(optCon, stderr, 0);
959  rc = 2;
960  goto exit;
961  }
962 
963  if (dc->manifests != NULL) {
964  if ((xx = rpmdcLoadManifests(dc)) != 0)
965  rc = xx;
966  } else {
967  int i;
968  for (i = 0; i < ac; i++)
969  xx = argvAdd(&dc->paths, av[i]);
970  }
971  if (rc)
972  goto exit;
973 
974  if (dc->manifests != NULL) {
975  dc->ix = 0;
976  av = dc->paths;
977  if (av != NULL)
978  while ((dc->fn = *av++) != NULL) {
979  if ((xx = Lstat(dc->fn, &dc->sb)) != 0
980  || (xx = rpmdcVisitF(dc)) != 0)
981  rc = xx;
982  dc->ix++;
983  }
984  } else {
985  if ((xx = rpmdcCWalk(dc)) != 0)
986  rc = xx;
987  }
988 
989 exit:
990  if (dc->nfailed)
991  fprintf(stderr, "%s: WARNING: %u of %u computed checksums did NOT match\n",
992  __progname, (unsigned) dc->nfailed, (unsigned) dc->ncomputed);
993 
994  if (dc->ofd) {
995  /* Print the output spewage digest for 0install format manifests. */
996  if (rc == 0 && F_ISSET(dc, 0INSTALL) && dc->manifests == NULL) {
997  static int asAscii = 1;
998  char *t;
999  fdFiniDigest(dc->ofd, dc->oalgo, &dc->digest, &dc->digestlen, asAscii);
1000 assert(dc->digest != NULL);
1001  t = rpmExpand(dc->oalgoName, "=", dc->digest, "\n", NULL);
1002  (void) Fwrite(t, strlen(t), sizeof(*t), dc->ofd);
1003  t = _free(t);
1004  dc->digest = _free(dc->digest);
1005  }
1006  (void) Fclose(dc->ofd);
1007  dc->ofd = NULL;
1008  }
1009 
1010 #ifdef NOTYET
1011  dc->manifests = argvFree(dc->manifests);
1012 #endif
1013  dc->algos = argiFree(dc->algos);
1014  dc->digests = argvFree(dc->digests);
1015  dc->paths = argvFree(dc->paths);
1016 
1017  rpmswExit(&dc->totalops, 0);
1018  if (_rpmsw_stats) {
1019  rpmswPrint(" total:", &dc->totalops, NULL);
1020  rpmswPrint(" read:", &dc->readops, NULL);
1021  rpmswPrint("digest:", &dc->digestops, NULL);
1022  }
1023 
1024  optCon = rpmioFini(optCon);
1025 
1026  return rc;
1027 }
const bson * b
Definition: bson.h:280
poptContext rpmioInit(int argc, char *const argv[], struct poptOption *optionsTable)
Initialize most everything needed by an rpmio executable context.
Definition: poptIO.c:767
const char * digest
Definition: rpmdigest.c:55
struct poptOption rpmioDigestPoptTable[]
Digest options using popt.
Definition: poptIO.c:152
rpmtime_t rpmswExit(rpmop op, ssize_t rc)
Exit timed operation.
Definition: rpmsw.c:264
static int rpmdcInitFile(rpmdc dc)
Definition: rpmdigest.c:631
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:844
ARGint_t vals
Definition: argv.h:18
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:703
size_t nmatched
Definition: rpmdigest.c:75
int main(int argc, char *argv[])
Definition: rpmdigest.c:911
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:321
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 context.
Definition: digest.c:247
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:651
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:147
ssize_t nb
Definition: rpmdigest.c:70
const char *(* print)(rpmdc dc, int rc)
Definition: rpmdigest.c:60
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:710
int rpmiobSlurp(const char *fn, rpmiob *iobp)
Definition: rpmiob.c:129
int rpmHmacInit(DIGEST_CTX ctx, const void *key, size_t keylen)
Compute key material and add to digest context.
Definition: digest.c:1062
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:159
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:986
#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:817
#define N_(Text)
Definition: system.h:531
static int rpmdcFiniFile(rpmdc dc)
Definition: rpmdigest.c:568
ARGV_t digests
Definition: rpmdigest.c:67
FD_t ofd
Definition: rpmdigest.c:62
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
const char const bson * data
Definition: mongo.h:463
static int xisspace(int c)
Definition: rpmiotypes.h:555
ARGV_t argvFree(ARGV_t argv)
Destroy an argv array.
Definition: argv.c:44
static int rpmdcVisitF(rpmdc dc)
Definition: rpmdigest.c:683
static struct rpmdc_s _dc
Definition: rpmdigest.c:84
static int rpmdcPrintFile(rpmdc dc)
Definition: rpmdigest.c:533
FTS * t
Definition: rpmdigest.c:46
Digest private data.
Definition: digest.c:130
static int rpmdcCWalk(rpmdc dc)
Definition: rpmdigest.c:722
static int _poptSaveString(const char ***argvp, unsigned int argInfo, const char *val)
Definition: rpmdigest.c:797
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:612
int rpmioFtsOpts
Definition: poptIO.c:539
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'ed) concatenated macro expansion(s).
Definition: macro.c:3238
size_t Fread(void *buf, size_t size, size_t nmemb, FD_t fd)
fread(3) clone.
Definition: rpmio.c:2412
const char const char int arg
Definition: mongo.h:777
ARGV_t manifests
Definition: rpmdigest.c:65
static const char * rpmdcPrintZeroInstall(rpmdc dc, int rc)
Definition: rpmdigest.c:453
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:39
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:295
int ix
Definition: rpmdigest.c:71
size_t ncomputed
Definition: rpmdigest.c:73
char fts_name[1]
Definition: fts.h:157
int Ferror(FD_t fd)
ferror(3) clone.
Definition: rpmio.c:2944
#define F_ISSET(_dc, _FLAG)
Definition: rpmdigest.c:19
const char const int i
Definition: bson.h:778
static uint32_t rpmdcName2Algo(const char *dname)
Definition: rpmdigest.c:96
static int xisdigit(int c)
Definition: rpmiotypes.h:546
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:789
struct stat sb
Definition: rpmdigest.c:48
ARGI_t algos
Definition: rpmdigest.c:66
static struct poptOption * optionsTable
Definition: rpmdigest.c:908
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:756
struct rpmiob_s * rpmiob
Definition: rpmiotypes.h:60
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:1000
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:29
#define xmalloc
Definition: system.h:32
#define FTS_DP
Definition: fts.h:134
ARGstr_t * ARGV_t
Definition: argv.h:12
struct poptOption rpmioAllPoptTable[]
Popt option table for options shared by all modes and executables.
Definition: poptIO.c:564
int(* parse)(rpmdc dc)
Definition: rpmdigest.c:59
uint32_t oalgo
Definition: rpmdigest.c:63
poptContext rpmioFini(poptContext optCon)
Destroy most everything needed by an rpm CLI executable context.
Definition: poptIO.c:734
FD_t fd
Definition: rpmdigest.c:58
uint32_t algo
Definition: rpmdigest.c:51
Definition: argv.h:16
const char * __progname
Definition: poptIO.c:66
#define FTS_ERR
Definition: fts.h:135
#define xrealloc
Definition: system.h:35
#define FTS_SKIP
Definition: fts.h:152