rpm  4.5
files.c
Go to the documentation of this file.
1 
7 #include "system.h"
8 
9 #define MYALLPERMS 07777
10 
11 #include <regex.h>
12 
13 #include <rpmio_internal.h>
14 #include <fts.h>
15 
16 #include <rpmbuild.h>
17 
18 #include "cpio.h"
19 
20 #include "argv.h"
21 #include "rpmfc.h"
22 
23 #define _RPMFI_INTERNAL
24 #include "rpmfi.h"
25 
26 #define _RPMTE_INTERNAL
27 #include "rpmte.h"
28 
29 #include "buildio.h"
30 
31 #include "legacy.h" /* XXX dodigest */
32 #include "misc.h"
33 #include "debug.h"
34 
35 /*@access Header @*/
36 /*@access rpmfi @*/
37 /*@access rpmte @*/
38 /*@access FD_t @*/
39 /*@access StringBuf @*/ /* compared with NULL */
40 
41 #define SKIPWHITE(_x) {while(*(_x) && (xisspace(*_x) || *(_x) == ',')) (_x)++;}
42 #define SKIPNONWHITE(_x){while(*(_x) &&!(xisspace(*_x) || *(_x) == ',')) (_x)++;}
43 
44 #define MAXDOCDIR 1024
45 
48 typedef enum specdFlags_e {
49  SPECD_DEFFILEMODE = (1 << 0),
50  SPECD_DEFDIRMODE = (1 << 1),
51  SPECD_DEFUID = (1 << 2),
52  SPECD_DEFGID = (1 << 3),
53  SPECD_DEFVERIFY = (1 << 4),
54 
55  SPECD_FILEMODE = (1 << 8),
56  SPECD_DIRMODE = (1 << 9),
57  SPECD_UID = (1 << 10),
58  SPECD_GID = (1 << 11),
59  SPECD_VERIFY = (1 << 12)
60 } specdFlags;
61 
64 typedef struct FileListRec_s {
65  struct stat fl_st;
66 #define fl_dev fl_st.st_dev
67 #define fl_ino fl_st.st_ino
68 #define fl_mode fl_st.st_mode
69 #define fl_nlink fl_st.st_nlink
70 #define fl_uid fl_st.st_uid
71 #define fl_gid fl_st.st_gid
72 #define fl_rdev fl_st.st_rdev
73 #define fl_size fl_st.st_size
74 #define fl_mtime fl_st.st_mtime
75 
76 /*@only@*/
77  const char *diskURL; /* get file from here */
78 /*@only@*/
79  const char *fileURL; /* filename in cpio archive */
80 /*@observer@*/
81  const char *uname;
82 /*@observer@*/
83  const char *gname;
84  unsigned flags;
85  specdFlags specdFlags; /* which attributes have been explicitly specified. */
86  unsigned verifyFlags;
87 /*@only@*/
88  const char *langs; /* XXX locales separated with | */
89 } * FileListRec;
90 
93 typedef struct AttrRec_s {
94 /*@null@*/
95  const char *ar_fmodestr;
96 /*@null@*/
97  const char *ar_dmodestr;
98 /*@null@*/
99  const char *ar_user;
100 /*@null@*/
101  const char *ar_group;
102  mode_t ar_fmode;
103  mode_t ar_dmode;
104 } * AttrRec;
105 
106 /*@-readonlytrans@*/
107 /*@unchecked@*/ /*@observer@*/
108 static struct AttrRec_s root_ar = { NULL, NULL, "root", "root", 0, 0 };
109 /*@=readonlytrans@*/
110 
111 /* list of files */
112 /*@unchecked@*/ /*@only@*/ /*@null@*/
113 static StringBuf check_fileList = NULL;
114 
118 typedef struct FileList_s {
119 /*@only@*/
120  const char * buildRootURL;
121 /*@only@*/
122  const char * prefix;
123 
127 
130 
131  int noGlob;
132  unsigned devtype;
133  unsigned devmajor;
134  int devminor;
135 
136  int isDir;
137  int inFtw;
145  int nLangs;
146 /*@only@*/ /*@null@*/
147  const char ** currentLangs;
148 
149  /* Hard coded limit of MAXDOCDIR docdirs. */
150  /* If you break it you are doing something wrong. */
151  const char * docDirs[MAXDOCDIR];
153 
154 /*@only@*/
158 } * FileList;
159 
162 static void nullAttrRec(/*@out@*/ AttrRec ar) /*@modifies ar @*/
163 {
164  ar->ar_fmodestr = NULL;
165  ar->ar_dmodestr = NULL;
166  ar->ar_user = NULL;
167  ar->ar_group = NULL;
168  ar->ar_fmode = 0;
169  ar->ar_dmode = 0;
170 }
171 
174 static void freeAttrRec(AttrRec ar) /*@modifies ar @*/
175 {
176  ar->ar_fmodestr = _free(ar->ar_fmodestr);
177  ar->ar_dmodestr = _free(ar->ar_dmodestr);
178  ar->ar_user = _free(ar->ar_user);
179  ar->ar_group = _free(ar->ar_group);
180  /* XXX doesn't free ar (yet) */
181  /*@-nullstate@*/
182  return;
183  /*@=nullstate@*/
184 }
185 
188 static void dupAttrRec(const AttrRec oar, /*@in@*/ /*@out@*/ AttrRec nar)
189  /*@modifies nar @*/
190 {
191  if (oar == nar)
192  return;
193  freeAttrRec(nar);
194  nar->ar_fmodestr = (oar->ar_fmodestr ? xstrdup(oar->ar_fmodestr) : NULL);
195  nar->ar_dmodestr = (oar->ar_dmodestr ? xstrdup(oar->ar_dmodestr) : NULL);
196  nar->ar_user = (oar->ar_user ? xstrdup(oar->ar_user) : NULL);
197  nar->ar_group = (oar->ar_group ? xstrdup(oar->ar_group) : NULL);
198  nar->ar_fmode = oar->ar_fmode;
199  nar->ar_dmode = oar->ar_dmode;
200 }
201 
202 #if 0
203 
205 static void dumpAttrRec(const char * msg, AttrRec ar)
206  /*@globals fileSystem@*/
207  /*@modifies fileSystem @*/
208 {
209  if (msg)
210  fprintf(stderr, "%s:\t", msg);
211  fprintf(stderr, "(%s, %s, %s, %s)\n",
212  ar->ar_fmodestr,
213  ar->ar_user,
214  ar->ar_group,
215  ar->ar_dmodestr);
216 }
217 #endif
218 
223 /*@-boundswrite@*/
224 /*@null@*/
225 static char *strtokWithQuotes(/*@null@*/ char *s, char *delim)
226  /*@modifies *s @*/
227 {
228  static char *olds = NULL;
229  char *token;
230 
231  if (s == NULL)
232  s = olds;
233  if (s == NULL)
234  return NULL;
235 
236  /* Skip leading delimiters */
237  s += strspn(s, delim);
238  if (*s == '\0')
239  return NULL;
240 
241  /* Find the end of the token. */
242  token = s;
243  if (*token == '"') {
244  token++;
245  /* Find next " char */
246  s = strchr(token, '"');
247  } else {
248  s = strpbrk(token, delim);
249  }
250 
251  /* Terminate it */
252  if (s == NULL) {
253  /* This token finishes the string */
254  olds = strchr(token, '\0');
255  } else {
256  /* Terminate the token and make olds point past it */
257  *s = '\0';
258  olds = s+1;
259  }
260 
261  /*@-retalias -temptrans @*/
262  return token;
263  /*@=retalias =temptrans @*/
264 }
265 /*@=boundswrite@*/
266 
269 static void timeCheck(int tc, Header h)
270  /*@globals internalState @*/
271  /*@modifies internalState @*/
272 {
274  HFD_t hfd = headerFreeData;
275  int * mtime;
276  const char ** files;
277  rpmTagType fnt;
278  int count, x;
279  time_t currentTime = time(NULL);
280 
281  x = hge(h, RPMTAG_OLDFILENAMES, &fnt, &files, &count);
282  x = hge(h, RPMTAG_FILEMTIMES, NULL, &mtime, NULL);
283 
284 /*@-boundsread@*/
285  for (x = 0; x < count; x++) {
286  if ((currentTime - mtime[x]) > tc)
287  rpmMessage(RPMMESS_WARNING, _("TIMECHECK failure: %s\n"), files[x]);
288  }
289  files = hfd(files, fnt);
290 /*@=boundsread@*/
291 }
292 
295 typedef struct VFA {
296 /*@observer@*/ /*@null@*/ const char * attribute;
297  int not;
298  int flag;
299 } VFA_t;
300 
303 /*@-exportlocal -exportheadervar@*/
304 /*@unchecked@*/
306  { "md5", 0, RPMVERIFY_MD5 },
307  { "size", 0, RPMVERIFY_FILESIZE },
308  { "link", 0, RPMVERIFY_LINKTO },
309  { "user", 0, RPMVERIFY_USER },
310  { "group", 0, RPMVERIFY_GROUP },
311  { "mtime", 0, RPMVERIFY_MTIME },
312  { "mode", 0, RPMVERIFY_MODE },
313  { "rdev", 0, RPMVERIFY_RDEV },
314  { NULL, 0, 0 }
315 };
316 /*@=exportlocal =exportheadervar@*/
317 
324 /*@-boundswrite@*/
325 static int parseForVerify(char * buf, FileList fl)
326  /*@modifies buf, fl->processingFailed,
327  fl->currentVerifyFlags, fl->defVerifyFlags,
328  fl->currentSpecdFlags, fl->defSpecdFlags @*/
329 {
330  char *p, *pe, *q;
331  const char *name;
332  int *resultVerify;
333  int negated;
334  int verifyFlags;
336 
337  if ((p = strstr(buf, (name = "%verify"))) != NULL) {
338  resultVerify = &(fl->currentVerifyFlags);
339  specdFlags = &fl->currentSpecdFlags;
340  } else if ((p = strstr(buf, (name = "%defverify"))) != NULL) {
341  resultVerify = &(fl->defVerifyFlags);
342  specdFlags = &fl->defSpecdFlags;
343  } else
344  return 0;
345 
346  for (pe = p; (pe-p) < strlen(name); pe++)
347  *pe = ' ';
348 
349  SKIPSPACE(pe);
350 
351  if (*pe != '(') {
352  rpmError(RPMERR_BADSPEC, _("Missing '(' in %s %s\n"), name, pe);
353  fl->processingFailed = 1;
354  return RPMERR_BADSPEC;
355  }
356 
357  /* Bracket %*verify args */
358  *pe++ = ' ';
359  for (p = pe; *pe && *pe != ')'; pe++)
360  {};
361 
362  if (*pe == '\0') {
363  rpmError(RPMERR_BADSPEC, _("Missing ')' in %s(%s\n"), name, p);
364  fl->processingFailed = 1;
365  return RPMERR_BADSPEC;
366  }
367 
368  /* Localize. Erase parsed string */
369  q = alloca((pe-p) + 1);
370  strncpy(q, p, pe-p);
371  q[pe-p] = '\0';
372  while (p <= pe)
373  *p++ = ' ';
374 
375  negated = 0;
376  verifyFlags = RPMVERIFY_NONE;
377 
378  for (p = q; *p != '\0'; p = pe) {
379  SKIPWHITE(p);
380  if (*p == '\0')
381  break;
382  pe = p;
383  SKIPNONWHITE(pe);
384  if (*pe != '\0')
385  *pe++ = '\0';
386 
387  { VFA_t *vfa;
388  for (vfa = verifyAttrs; vfa->attribute != NULL; vfa++) {
389  if (strcmp(p, vfa->attribute))
390  /*@innercontinue@*/ continue;
391  verifyFlags |= vfa->flag;
392  /*@innerbreak@*/ break;
393  }
394  if (vfa->attribute)
395  continue;
396  }
397 
398  if (!strcmp(p, "not")) {
399  negated ^= 1;
400  } else {
401  rpmError(RPMERR_BADSPEC, _("Invalid %s token: %s\n"), name, p);
402  fl->processingFailed = 1;
403  return RPMERR_BADSPEC;
404  }
405  }
406 
407  *resultVerify = negated ? ~(verifyFlags) : verifyFlags;
408  *specdFlags |= SPECD_VERIFY;
409 
410  return 0;
411 }
412 /*@=boundswrite@*/
413 
414 #define isAttrDefault(_ars) ((_ars)[0] == '-' && (_ars)[1] == '\0')
415 
422 /*@-boundswrite@*/
423 static int parseForDev(char * buf, FileList fl)
424  /*@modifies buf, fl->processingFailed,
425  fl->noGlob, fl->devtype, fl->devmajor, fl->devminor @*/
426 {
427  const char * name;
428  const char * errstr = NULL;
429  char *p, *pe, *q;
430  int rc = RPMERR_BADSPEC; /* assume error */
431 
432  if ((p = strstr(buf, (name = "%dev"))) == NULL)
433  return 0;
434 
435  for (pe = p; (pe-p) < strlen(name); pe++)
436  *pe = ' ';
437  SKIPSPACE(pe);
438 
439  if (*pe != '(') {
440  errstr = "'('";
441  goto exit;
442  }
443 
444  /* Bracket %dev args */
445  *pe++ = ' ';
446  for (p = pe; *pe && *pe != ')'; pe++)
447  {};
448  if (*pe != ')') {
449  errstr = "')'";
450  goto exit;
451  }
452 
453  /* Localize. Erase parsed string */
454  q = alloca((pe-p) + 1);
455  strncpy(q, p, pe-p);
456  q[pe-p] = '\0';
457  while (p <= pe)
458  *p++ = ' ';
459 
460  p = q; SKIPWHITE(p);
461  pe = p; SKIPNONWHITE(pe); if (*pe != '\0') *pe++ = '\0';
462  if (*p == 'b')
463  fl->devtype = 'b';
464  else if (*p == 'c')
465  fl->devtype = 'c';
466  else {
467  errstr = "devtype";
468  goto exit;
469  }
470 
471  p = pe; SKIPWHITE(p);
472  pe = p; SKIPNONWHITE(pe); if (*pe != '\0') *pe++ = '\0';
473  for (pe = p; *pe && xisdigit(*pe); pe++)
474  {} ;
475  if (*pe == '\0') {
476  fl->devmajor = atoi(p);
477  /*@-unsignedcompare @*/ /* LCL: ge is ok */
478  if (!(fl->devmajor >= 0 && fl->devmajor < 256)) {
479  errstr = "devmajor";
480  goto exit;
481  }
482  /*@=unsignedcompare @*/
483  pe++;
484  } else {
485  errstr = "devmajor";
486  goto exit;
487  }
488 
489  p = pe; SKIPWHITE(p);
490  pe = p; SKIPNONWHITE(pe); if (*pe != '\0') *pe++ = '\0';
491  for (pe = p; *pe && xisdigit(*pe); pe++)
492  {} ;
493  if (*pe == '\0') {
494  fl->devminor = atoi(p);
495  if (!(fl->devminor >= 0 && fl->devminor < 256)) {
496  errstr = "devminor";
497  goto exit;
498  }
499  pe++;
500  } else {
501  errstr = "devminor";
502  goto exit;
503  }
504 
505  fl->noGlob = 1;
506 
507  rc = 0;
508 
509 exit:
510  if (rc) {
511  rpmError(RPMERR_BADSPEC, _("Missing %s in %s %s\n"), errstr, name, p);
512  fl->processingFailed = 1;
513  }
514  return rc;
515 }
516 /*@=boundswrite@*/
517 
524 /*@-boundswrite@*/
525 static int parseForAttr(char * buf, FileList fl)
526  /*@modifies buf, fl->processingFailed,
527  fl->cur_ar, fl->def_ar,
528  fl->currentSpecdFlags, fl->defSpecdFlags @*/
529 {
530  const char *name;
531  char *p, *pe, *q;
532  int x;
533  struct AttrRec_s arbuf;
534  AttrRec ar = &arbuf, ret_ar;
536 
537  if ((p = strstr(buf, (name = "%attr"))) != NULL) {
538  ret_ar = &(fl->cur_ar);
539  specdFlags = &fl->currentSpecdFlags;
540  } else if ((p = strstr(buf, (name = "%defattr"))) != NULL) {
541  ret_ar = &(fl->def_ar);
542  specdFlags = &fl->defSpecdFlags;
543  } else
544  return 0;
545 
546  for (pe = p; (pe-p) < strlen(name); pe++)
547  *pe = ' ';
548 
549  SKIPSPACE(pe);
550 
551  if (*pe != '(') {
552  rpmError(RPMERR_BADSPEC, _("Missing '(' in %s %s\n"), name, pe);
553  fl->processingFailed = 1;
554  return RPMERR_BADSPEC;
555  }
556 
557  /* Bracket %*attr args */
558  *pe++ = ' ';
559  for (p = pe; *pe && *pe != ')'; pe++)
560  {};
561 
562  if (ret_ar == &(fl->def_ar)) { /* %defattr */
563  q = pe;
564  q++;
565  SKIPSPACE(q);
566  if (*q != '\0') {
568  _("Non-white space follows %s(): %s\n"), name, q);
569  fl->processingFailed = 1;
570  return RPMERR_BADSPEC;
571  }
572  }
573 
574  /* Localize. Erase parsed string */
575  q = alloca((pe-p) + 1);
576  strncpy(q, p, pe-p);
577  q[pe-p] = '\0';
578  while (p <= pe)
579  *p++ = ' ';
580 
581  nullAttrRec(ar);
582 
583  p = q; SKIPWHITE(p);
584  if (*p != '\0') {
585  pe = p; SKIPNONWHITE(pe); if (*pe != '\0') *pe++ = '\0';
586  ar->ar_fmodestr = p;
587  p = pe; SKIPWHITE(p);
588  }
589  if (*p != '\0') {
590  pe = p; SKIPNONWHITE(pe); if (*pe != '\0') *pe++ = '\0';
591  ar->ar_user = p;
592  p = pe; SKIPWHITE(p);
593  }
594  if (*p != '\0') {
595  pe = p; SKIPNONWHITE(pe); if (*pe != '\0') *pe++ = '\0';
596  ar->ar_group = p;
597  p = pe; SKIPWHITE(p);
598  }
599  if (*p != '\0' && ret_ar == &(fl->def_ar)) { /* %defattr */
600  pe = p; SKIPNONWHITE(pe); if (*pe != '\0') *pe++ = '\0';
601  ar->ar_dmodestr = p;
602  p = pe; SKIPWHITE(p);
603  }
604 
605  if (!(ar->ar_fmodestr && ar->ar_user && ar->ar_group) || *p != '\0') {
606  rpmError(RPMERR_BADSPEC, _("Bad syntax: %s(%s)\n"), name, q);
607  fl->processingFailed = 1;
608  return RPMERR_BADSPEC;
609  }
610 
611  /* Do a quick test on the mode argument and adjust for "-" */
612  if (ar->ar_fmodestr && !isAttrDefault(ar->ar_fmodestr)) {
613  unsigned int ui;
614  x = sscanf(ar->ar_fmodestr, "%o", &ui);
615  if ((x == 0) || (ar->ar_fmode & ~MYALLPERMS)) {
616  rpmError(RPMERR_BADSPEC, _("Bad mode spec: %s(%s)\n"), name, q);
617  fl->processingFailed = 1;
618  return RPMERR_BADSPEC;
619  }
620  ar->ar_fmode = ui;
621  } else
622  ar->ar_fmodestr = NULL;
623 
624  if (ar->ar_dmodestr && !isAttrDefault(ar->ar_dmodestr)) {
625  unsigned int ui;
626  x = sscanf(ar->ar_dmodestr, "%o", &ui);
627  if ((x == 0) || (ar->ar_dmode & ~MYALLPERMS)) {
628  rpmError(RPMERR_BADSPEC, _("Bad dirmode spec: %s(%s)\n"), name, q);
629  fl->processingFailed = 1;
630  return RPMERR_BADSPEC;
631  }
632  ar->ar_dmode = ui;
633  } else
634  ar->ar_dmodestr = NULL;
635 
636  if (!(ar->ar_user && !isAttrDefault(ar->ar_user)))
637  ar->ar_user = NULL;
638 
639  if (!(ar->ar_group && !isAttrDefault(ar->ar_group)))
640  ar->ar_group = NULL;
641 
642  dupAttrRec(ar, ret_ar);
643 
644  /* XXX fix all this */
645  *specdFlags |= SPECD_UID | SPECD_GID | SPECD_FILEMODE | SPECD_DIRMODE;
646 
647  return 0;
648 }
649 /*@=boundswrite@*/
650 
657 /*@-boundswrite@*/
658 static int parseForConfig(char * buf, FileList fl)
659  /*@modifies buf, fl->processingFailed, fl->currentFlags @*/
660 {
661  char *p, *pe, *q;
662  const char *name;
663 
664  if ((p = strstr(buf, (name = "%config"))) == NULL)
665  return 0;
666 
668 
669  /* Erase "%config" token. */
670  for (pe = p; (pe-p) < strlen(name); pe++)
671  *pe = ' ';
672  SKIPSPACE(pe);
673  if (*pe != '(')
674  return 0;
675 
676  /* Bracket %config args */
677  *pe++ = ' ';
678  for (p = pe; *pe && *pe != ')'; pe++)
679  {};
680 
681  if (*pe == '\0') {
682  rpmError(RPMERR_BADSPEC, _("Missing ')' in %s(%s\n"), name, p);
683  fl->processingFailed = 1;
684  return RPMERR_BADSPEC;
685  }
686 
687  /* Localize. Erase parsed string. */
688  q = alloca((pe-p) + 1);
689  strncpy(q, p, pe-p);
690  q[pe-p] = '\0';
691  while (p <= pe)
692  *p++ = ' ';
693 
694  for (p = q; *p != '\0'; p = pe) {
695  SKIPWHITE(p);
696  if (*p == '\0')
697  break;
698  pe = p;
699  SKIPNONWHITE(pe);
700  if (*pe != '\0')
701  *pe++ = '\0';
702  if (!strcmp(p, "missingok")) {
704  } else if (!strcmp(p, "noreplace")) {
706  } else {
707  rpmError(RPMERR_BADSPEC, _("Invalid %s token: %s\n"), name, p);
708  fl->processingFailed = 1;
709  return RPMERR_BADSPEC;
710  }
711  }
712 
713  return 0;
714 }
715 /*@=boundswrite@*/
716 
719 static int langCmp(const void * ap, const void * bp)
720  /*@*/
721 {
722 /*@-boundsread@*/
723  return strcmp(*(const char **)ap, *(const char **)bp);
724 /*@=boundsread@*/
725 }
726 
733 /*@-bounds@*/
734 static int parseForLang(char * buf, FileList fl)
735  /*@modifies buf, fl->processingFailed,
736  fl->currentLangs, fl->nLangs @*/
737 {
738  char *p, *pe, *q;
739  const char *name;
740 
741  while ((p = strstr(buf, (name = "%lang"))) != NULL) {
742 
743  for (pe = p; (pe-p) < strlen(name); pe++)
744  *pe = ' ';
745  SKIPSPACE(pe);
746 
747  if (*pe != '(') {
748  rpmError(RPMERR_BADSPEC, _("Missing '(' in %s %s\n"), name, pe);
749  fl->processingFailed = 1;
750  return RPMERR_BADSPEC;
751  }
752 
753  /* Bracket %lang args */
754  *pe++ = ' ';
755  for (pe = p; *pe && *pe != ')'; pe++)
756  {};
757 
758  if (*pe == '\0') {
759  rpmError(RPMERR_BADSPEC, _("Missing ')' in %s(%s\n"), name, p);
760  fl->processingFailed = 1;
761  return RPMERR_BADSPEC;
762  }
763 
764  /* Localize. Erase parsed string. */
765  q = alloca((pe-p) + 1);
766  strncpy(q, p, pe-p);
767  q[pe-p] = '\0';
768  while (p <= pe)
769  *p++ = ' ';
770 
771  /* Parse multiple arguments from %lang */
772  for (p = q; *p != '\0'; p = pe) {
773  char *newp;
774  size_t np;
775  int i;
776 
777  SKIPWHITE(p);
778  pe = p;
779  SKIPNONWHITE(pe);
780 
781  np = pe - p;
782 
783  /* Sanity check on locale lengths */
784  if (np < 1 || (np == 1 && *p != 'C') || np >= 32) {
786  _("Unusual locale length: \"%.*s\" in %%lang(%s)\n"),
787  (int)np, p, q);
788  fl->processingFailed = 1;
789  return RPMERR_BADSPEC;
790  }
791 
792  /* Check for duplicate locales */
793  if (fl->currentLangs != NULL)
794  for (i = 0; i < fl->nLangs; i++) {
795  if (strncmp(fl->currentLangs[i], p, np))
796  /*@innercontinue@*/ continue;
797  rpmError(RPMERR_BADSPEC, _("Duplicate locale %.*s in %%lang(%s)\n"),
798  (int)np, p, q);
799  fl->processingFailed = 1;
800  return RPMERR_BADSPEC;
801  }
802 
803  /* Add new locale */
805  (fl->nLangs + 1) * sizeof(*fl->currentLangs));
806  newp = xmalloc( np+1 );
807  strncpy(newp, p, np);
808  newp[np] = '\0';
809  fl->currentLangs[fl->nLangs++] = newp;
810  if (*pe == ',') pe++; /* skip , if present */
811  }
812  }
813 
814  /* Insure that locales are sorted. */
815  if (fl->currentLangs)
816  qsort(fl->currentLangs, fl->nLangs, sizeof(*fl->currentLangs), langCmp);
817 
818  return 0;
819 }
820 /*@=bounds@*/
821 
824 /*@-boundswrite@*/
825 static int parseForRegexLang(const char * fileName, /*@out@*/ char ** lang)
826  /*@globals rpmGlobalMacroContext, h_errno @*/
827  /*@modifies *lang, rpmGlobalMacroContext @*/
828 {
829  static int initialized = 0;
830  static int hasRegex = 0;
831  static regex_t compiledPatt;
832  static char buf[BUFSIZ];
833  int x;
834  regmatch_t matches[2];
835  const char *s;
836 
837  if (! initialized) {
838  const char *patt = rpmExpand("%{?_langpatt}", NULL);
839  int rc = 0;
840  if (!(patt && *patt != '\0'))
841  rc = 1;
842  else if (regcomp(&compiledPatt, patt, REG_EXTENDED))
843  rc = -1;
844  patt = _free(patt);
845  if (rc)
846  return rc;
847  hasRegex = 1;
848  initialized = 1;
849  }
850 
851  memset(matches, 0, sizeof(matches));
852  if (! hasRegex || regexec(&compiledPatt, fileName, 2, matches, REG_NOTEOL))
853  return 1;
854 
855  /* Got match */
856  s = fileName + matches[1].rm_eo - 1;
857  x = matches[1].rm_eo - matches[1].rm_so;
858  buf[x] = '\0';
859  while (x) {
860  buf[--x] = *s--;
861  }
862  if (lang)
863  *lang = buf;
864  return 0;
865 }
866 /*@=boundswrite@*/
867 
870 /*@-exportlocal -exportheadervar@*/
871 /*@unchecked@*/
873  { "%dir", 0, 0 }, /* XXX why not RPMFILE_DIR? */
874  { "%doc", 0, RPMFILE_DOC },
875  { "%ghost", 0, RPMFILE_GHOST },
876  { "%exclude", 0, RPMFILE_EXCLUDE },
877  { "%readme", 0, RPMFILE_README },
878  { "%license", 0, RPMFILE_LICENSE },
879  { "%pubkey", 0, RPMFILE_PUBKEY },
880  { "%policy", 0, RPMFILE_POLICY },
881 
882 #if WHY_NOT
883  { "%icon", 0, RPMFILE_ICON },
884  { "%spec", 0, RPMFILE_SPEC },
885  { "%config", 0, RPMFILE_CONFIG },
886  { "%missingok", 0, RPMFILE_CONFIG|RPMFILE_MISSINGOK },
887  { "%noreplace", 0, RPMFILE_CONFIG|RPMFILE_NOREPLACE },
888 #endif
889 
890  { NULL, 0, 0 }
891 };
892 /*@=exportlocal =exportheadervar@*/
893 
903 /*@-boundswrite@*/
904 static int parseForSimple(/*@unused@*/Spec spec, Package pkg, char * buf,
905  FileList fl, /*@out@*/ const char ** fileName)
906  /*@globals rpmGlobalMacroContext, h_errno @*/
907  /*@modifies buf, fl->processingFailed, *fileName,
908  fl->currentFlags,
909  fl->docDirs, fl->docDirCount, fl->isDir,
910  fl->passedSpecialDoc, fl->isSpecialDoc,
911  pkg->specialDoc, rpmGlobalMacroContext @*/
912 {
913  char *s, *t;
914  int res, specialDoc = 0;
915  char specialDocBuf[BUFSIZ];
916 
917  specialDocBuf[0] = '\0';
918  *fileName = NULL;
919  res = 0;
920 
921  t = buf;
922  while ((s = strtokWithQuotes(t, " \t\n")) != NULL) {
923  t = NULL;
924  if (!strcmp(s, "%docdir")) {
925  s = strtokWithQuotes(NULL, " \t\n");
926  if (fl->docDirCount == MAXDOCDIR) {
927  rpmError(RPMERR_INTERNAL, _("Hit limit for %%docdir\n"));
928  fl->processingFailed = 1;
929  res = 1;
930  }
931 
932  if (s != NULL)
933  fl->docDirs[fl->docDirCount++] = xstrdup(s);
934  if (s == NULL || strtokWithQuotes(NULL, " \t\n")) {
935  rpmError(RPMERR_INTERNAL, _("Only one arg for %%docdir\n"));
936  fl->processingFailed = 1;
937  res = 1;
938  }
939  break;
940  }
941 #if defined(__LCLINT__)
942  assert(s != NULL);
943 #endif
944 
945  /* Set flags for virtual file attributes */
946  { VFA_t *vfa;
947  for (vfa = virtualFileAttributes; vfa->attribute != NULL; vfa++) {
948  if (strcmp(s, vfa->attribute))
949  /*@innercontinue@*/ continue;
950  if (!vfa->flag) {
951  if (!strcmp(s, "%dir"))
952  fl->isDir = 1; /* XXX why not RPMFILE_DIR? */
953  } else {
954  if (vfa->not)
955  fl->currentFlags &= ~vfa->flag;
956  else
957  fl->currentFlags |= vfa->flag;
958  }
959 
960  /*@innerbreak@*/ break;
961  }
962  /* if we got an attribute, continue with next token */
963  if (vfa->attribute != NULL)
964  continue;
965  }
966 
967  if (*fileName) {
968  /* We already got a file -- error */
969  rpmError(RPMERR_BADSPEC, _("Two files on one line: %s\n"),
970  *fileName);
971  fl->processingFailed = 1;
972  res = 1;
973  }
974 
975  /*@-branchstate@*/
976  if (*s != '/') {
977  if (fl->currentFlags & RPMFILE_DOC) {
978  specialDoc = 1;
979  strcat(specialDocBuf, " ");
980  strcat(specialDocBuf, s);
981  } else
983  {
984  *fileName = s;
985  } else {
986  const char * sfn = NULL;
987  int urltype = urlPath(s, &sfn);
988  switch (urltype) {
989  default: /* relative path, not in %doc and not a URL */
991  _("File must begin with \"/\": %s\n"), s);
992  fl->processingFailed = 1;
993  res = 1;
994  /*@switchbreak@*/ break;
995  case URL_IS_PATH:
996  *fileName = s;
997  /*@switchbreak@*/ break;
998  }
999  }
1000  } else {
1001  *fileName = s;
1002  }
1003  /*@=branchstate@*/
1004  }
1005 
1006  if (specialDoc) {
1007  if (*fileName || (fl->currentFlags & ~(RPMFILE_DOC))) {
1009  _("Can't mix special %%doc with other forms: %s\n"),
1010  (*fileName ? *fileName : ""));
1011  fl->processingFailed = 1;
1012  res = 1;
1013  } else {
1014  /* XXX WATCHOUT: buf is an arg */
1015  { static char *_docdir_fmt= 0;
1016  static int oneshot = 0;
1017  const char *ddir, *fmt, *errstr;
1018  if (!oneshot) {
1019  _docdir_fmt = rpmExpand("%{?_docdir_fmt}", NULL);
1020  if (!_docdir_fmt || !*_docdir_fmt)
1021  _docdir_fmt = "%{NAME}-%{VERSION}";
1022  oneshot = 1;
1023  }
1024  fmt = headerSprintf(pkg->header, _docdir_fmt, rpmTagTable, rpmHeaderFormats, &errstr);
1025  if (!fmt) {
1026  rpmError(RPMERR_BADSPEC, _("illegal _docdir_fmt: %s\n"), errstr);
1027  fl->processingFailed = 1;
1028  res = 1;
1029  }
1030  ddir = rpmGetPath("%{_docdir}/", fmt, NULL);
1031  strcpy(buf, ddir);
1032  ddir = _free(ddir);
1033  }
1034 
1035  /* XXX FIXME: this is easy to do as macro expansion */
1036 
1037  if (! fl->passedSpecialDoc) {
1038  char *compress_doc;
1039 
1040  pkg->specialDoc = newStringBuf();
1041  appendStringBuf(pkg->specialDoc, "DOCDIR=\"$RPM_BUILD_ROOT\"");
1042  appendLineStringBuf(pkg->specialDoc, buf);
1043  appendLineStringBuf(pkg->specialDoc, "export DOCDIR");
1044  appendLineStringBuf(pkg->specialDoc, "rm -rf \"$DOCDIR\"");
1045  appendLineStringBuf(pkg->specialDoc, MKDIR_P " \"$DOCDIR\"");
1046 
1047  compress_doc = rpmExpand("%{__compress_doc}", NULL);
1048  if (compress_doc && *compress_doc != '%')
1049  appendLineStringBuf(pkg->specialDoc, compress_doc);
1050  compress_doc = _free(compress_doc);
1051 
1052  /*@-temptrans@*/
1053  *fileName = buf;
1054  /*@=temptrans@*/
1055  fl->passedSpecialDoc = 1;
1056  fl->isSpecialDoc = 1;
1057  }
1058 
1059  appendStringBuf(pkg->specialDoc, "cp -pr ");
1060  appendStringBuf(pkg->specialDoc, specialDocBuf);
1061  appendLineStringBuf(pkg->specialDoc, " \"$DOCDIR\"");
1062 
1063  {
1064  char *compress_doc;
1065 
1066  compress_doc = rpmExpand("%{__compress_doc}", NULL);
1067  if (compress_doc && *compress_doc != '%')
1068  appendLineStringBuf(pkg->specialDoc, compress_doc);
1069  if (compress_doc)
1070  free(compress_doc);
1071  }
1072  }
1073  }
1074 
1075  return res;
1076 }
1077 /*@=boundswrite@*/
1078 
1081 static int compareFileListRecs(const void * ap, const void * bp) /*@*/
1082 {
1083  const char *aurl = ((FileListRec)ap)->fileURL;
1084  const char *a = NULL;
1085  const char *burl = ((FileListRec)bp)->fileURL;
1086  const char *b = NULL;
1087  (void) urlPath(aurl, &a);
1088  (void) urlPath(burl, &b);
1089  return strcmp(a, b);
1090 }
1091 
1099 static int isDoc(FileList fl, const char * fileName) /*@*/
1100 {
1101  int x = fl->docDirCount;
1102 
1103  while (x--) {
1104  if (strstr(fileName, fl->docDirs[x]) == fileName)
1105  return 1;
1106  }
1107  return 0;
1108 }
1109 
1116 static int checkHardLinks(FileList fl)
1117  /*@*/
1118 {
1119  FileListRec ilp, jlp;
1120  int i, j;
1121 
1122  for (i = 0; i < fl->fileListRecsUsed; i++) {
1123  ilp = fl->fileList + i;
1124  if (!(S_ISREG(ilp->fl_mode) && ilp->fl_nlink > 1))
1125  continue;
1126  if (ilp->flags & (RPMFILE_EXCLUDE | RPMFILE_GHOST))
1127  continue;
1128 
1129  for (j = i + 1; j < fl->fileListRecsUsed; j++) {
1130  jlp = fl->fileList + j;
1131  if (!S_ISREG(jlp->fl_mode))
1132  /*@innercontinue@*/ continue;
1133  if (ilp->fl_nlink != jlp->fl_nlink)
1134  /*@innercontinue@*/ continue;
1135  if (ilp->fl_ino != jlp->fl_ino)
1136  /*@innercontinue@*/ continue;
1137  if (ilp->fl_dev != jlp->fl_dev)
1138  /*@innercontinue@*/ continue;
1139  if (jlp->flags & (RPMFILE_EXCLUDE | RPMFILE_GHOST))
1140  continue;
1141  return 1;
1142  }
1143  }
1144  return 0;
1145 }
1146 
1147 /*@-boundsread@*/
1148 static int dncmp(const void * a, const void * b)
1149  /*@*/
1150 {
1151  const char ** aurlp = a;
1152  const char ** burlp = b;
1153  const char * adn;
1154  const char * bdn;
1155  (void) urlPath(*aurlp, &adn);
1156  (void) urlPath(*burlp, &bdn);
1157  return strcmp(adn, bdn);
1158 }
1159 /*@=boundsread@*/
1160 
1161 /*@-bounds@*/
1166 static void compressFilelist(Header h)
1167  /*@modifies h @*/
1168 {
1170  HAE_t hae = (HAE_t)headerAddEntry;
1171  HRE_t hre = (HRE_t)headerRemoveEntry;
1172  HFD_t hfd = headerFreeData;
1173  char ** fileNames;
1174  const char * fn;
1175  const char ** dirNames;
1176  const char ** baseNames;
1177  int_32 * dirIndexes;
1178  rpmTagType fnt;
1179  int count;
1180  int i, xx;
1181  int dirIndex = -1;
1182 
1183  /*
1184  * This assumes the file list is already sorted, and begins with a
1185  * single '/'. That assumption isn't critical, but it makes things go
1186  * a bit faster.
1187  */
1188 
1189  if (headerIsEntry(h, RPMTAG_DIRNAMES)) {
1190  xx = hre(h, RPMTAG_OLDFILENAMES);
1191  return; /* Already converted. */
1192  }
1193 
1194  if (!hge(h, RPMTAG_OLDFILENAMES, &fnt, &fileNames, &count))
1195  return; /* no file list */
1196  if (fileNames == NULL || count <= 0)
1197  return;
1198 
1199  dirNames = alloca(sizeof(*dirNames) * count); /* worst case */
1200  baseNames = alloca(sizeof(*dirNames) * count);
1201  dirIndexes = alloca(sizeof(*dirIndexes) * count);
1202 
1203  (void) urlPath(fileNames[0], &fn);
1204  if (fn[0] != '/') {
1205  /* HACK. Source RPM, so just do things differently */
1206  dirIndex = 0;
1207  dirNames[dirIndex] = "";
1208  for (i = 0; i < count; i++) {
1209  dirIndexes[i] = dirIndex;
1210  baseNames[i] = fileNames[i];
1211  }
1212  goto exit;
1213  }
1214 
1215  /*@-branchstate@*/
1216  for (i = 0; i < count; i++) {
1217  const char ** needle;
1218  char savechar;
1219  char * baseName;
1220  int len;
1221 
1222  if (fileNames[i] == NULL) /* XXX can't happen */
1223  continue;
1224  baseName = strrchr(fileNames[i], '/') + 1;
1225  len = baseName - fileNames[i];
1226  needle = dirNames;
1227  savechar = *baseName;
1228  *baseName = '\0';
1229 /*@-compdef@*/
1230  if (dirIndex < 0 ||
1231  (needle = bsearch(&fileNames[i], dirNames, dirIndex + 1, sizeof(dirNames[0]), dncmp)) == NULL) {
1232  char *s = alloca(len + 1);
1233  memcpy(s, fileNames[i], len + 1);
1234  s[len] = '\0';
1235  dirIndexes[i] = ++dirIndex;
1236  dirNames[dirIndex] = s;
1237  } else
1238  dirIndexes[i] = needle - dirNames;
1239 /*@=compdef@*/
1240 
1241  *baseName = savechar;
1242  baseNames[i] = baseName;
1243  }
1244  /*@=branchstate@*/
1245 
1246 exit:
1247  if (count > 0) {
1248  xx = hae(h, RPMTAG_DIRINDEXES, RPM_INT32_TYPE, dirIndexes, count);
1250  baseNames, count);
1252  dirNames, dirIndex + 1);
1253  }
1254 
1255  fileNames = hfd(fileNames, fnt);
1256 
1257  xx = hre(h, RPMTAG_OLDFILENAMES);
1258 }
1259 /*@=bounds@*/
1260 
1270 /*@-bounds@*/
1271 static void genCpioListAndHeader(/*@partial@*/ FileList fl,
1272  rpmfi * fip, Header h, int isSrc)
1273  /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/
1274  /*@modifies h, *fip, fl->processingFailed, fl->fileList,
1275  rpmGlobalMacroContext, fileSystem, internalState @*/
1276 {
1277  const char * apath;
1278  int _addDotSlash = !isSrc;
1279  int apathlen = 0;
1280  int dpathlen = 0;
1281  int skipLen = 0;
1282  security_context_t scon = NULL;
1283  const char * sxfn;
1284  size_t fnlen;
1285  FileListRec flp;
1286  char buf[BUFSIZ];
1287  int i, xx;
1288 
1289  /* Sort the big list */
1290  qsort(fl->fileList, fl->fileListRecsUsed,
1291  sizeof(*(fl->fileList)), compareFileListRecs);
1292 
1293  /* Generate the header. */
1294  if (! isSrc) {
1295  skipLen = 1;
1296  if (fl->prefix)
1297  skipLen += strlen(fl->prefix);
1298  }
1299 
1300  sxfn = rpmGetPath("%{?_build_file_context_path}", NULL);
1301  if (sxfn != NULL && *sxfn != '\0')
1302  xx = matchpathcon_init(sxfn);
1303 
1304  for (i = 0, flp = fl->fileList; i < fl->fileListRecsUsed; i++, flp++) {
1305  const char *s;
1306 
1307  /* Merge duplicate entries. */
1308  while (i < (fl->fileListRecsUsed - 1) &&
1309  !strcmp(flp->fileURL, flp[1].fileURL)) {
1310 
1311  /* Two entries for the same file found, merge the entries. */
1312  /* Note that an %exclude is a duplication of a file reference */
1313 
1314  /* file flags */
1315  flp[1].flags |= flp->flags;
1316 
1317  if (!(flp[1].flags & RPMFILE_EXCLUDE))
1318  rpmMessage(RPMMESS_WARNING, _("File listed twice: %s\n"),
1319  flp->fileURL);
1320 
1321  /* file mode */
1322  if (S_ISDIR(flp->fl_mode)) {
1323  if ((flp[1].specdFlags & (SPECD_DIRMODE | SPECD_DEFDIRMODE)) <
1325  flp[1].fl_mode = flp->fl_mode;
1326  } else {
1327  if ((flp[1].specdFlags & (SPECD_FILEMODE | SPECD_DEFFILEMODE)) <
1329  flp[1].fl_mode = flp->fl_mode;
1330  }
1331 
1332  /* uid */
1333  if ((flp[1].specdFlags & (SPECD_UID | SPECD_DEFUID)) <
1334  (flp->specdFlags & (SPECD_UID | SPECD_DEFUID)))
1335  {
1336  flp[1].fl_uid = flp->fl_uid;
1337  flp[1].uname = flp->uname;
1338  }
1339 
1340  /* gid */
1341  if ((flp[1].specdFlags & (SPECD_GID | SPECD_DEFGID)) <
1342  (flp->specdFlags & (SPECD_GID | SPECD_DEFGID)))
1343  {
1344  flp[1].fl_gid = flp->fl_gid;
1345  flp[1].gname = flp->gname;
1346  }
1347 
1348  /* verify flags */
1349  if ((flp[1].specdFlags & (SPECD_VERIFY | SPECD_DEFVERIFY)) <
1351  flp[1].verifyFlags = flp->verifyFlags;
1352 
1353  /* XXX to-do: language */
1354 
1355  flp++; i++;
1356  }
1357 
1358  /* Skip files that were marked with %exclude. */
1359  if (flp->flags & RPMFILE_EXCLUDE) continue;
1360 
1361  /* Omit '/' and/or URL prefix, leave room for "./" prefix */
1362  (void) urlPath(flp->fileURL, &apath);
1363  apathlen += (strlen(apath) - skipLen + (_addDotSlash ? 3 : 1));
1364 
1365  /* Leave room for both dirname and basename NUL's */
1366  dpathlen += (strlen(flp->diskURL) + 2);
1367 
1368  /*
1369  * Make the header, the OLDFILENAMES will get converted to a
1370  * compressed file list write before we write the actual package to
1371  * disk.
1372  */
1374  &(flp->fileURL), 1);
1375 
1376 /*@-sizeoftype@*/
1377  if (sizeof(flp->fl_size) != sizeof(uint_32)) {
1378  uint_32 psize = (uint_32)flp->fl_size;
1380  &(psize), 1);
1381  } else {
1383  &(flp->fl_size), 1);
1384  }
1386  &(flp->uname), 1);
1388  &(flp->gname), 1);
1389  if (sizeof(flp->fl_mtime) != sizeof(uint_32)) {
1390  uint_32 mtime = (uint_32)flp->fl_mtime;
1392  &(mtime), 1);
1393  } else {
1395  &(flp->fl_mtime), 1);
1396  }
1397  if (sizeof(flp->fl_mode) != sizeof(uint_16)) {
1398  uint_16 pmode = (uint_16)flp->fl_mode;
1400  &(pmode), 1);
1401  } else {
1403  &(flp->fl_mode), 1);
1404  }
1405  if (sizeof(flp->fl_rdev) != sizeof(uint_16)) {
1406  uint_16 prdev = (uint_16)flp->fl_rdev;
1408  &(prdev), 1);
1409  } else {
1411  &(flp->fl_rdev), 1);
1412  }
1413  if (sizeof(flp->fl_dev) != sizeof(uint_32)) {
1414  uint_32 pdevice = (uint_32)flp->fl_dev;
1416  &(pdevice), 1);
1417  } else {
1419  &(flp->fl_dev), 1);
1420  }
1421  if (sizeof(flp->fl_ino) != sizeof(uint_32)) {
1422  uint_32 ino = (uint_32)flp->fl_ino;
1424  &(ino), 1);
1425  } else {
1427  &(flp->fl_ino), 1);
1428  }
1429 /*@=sizeoftype@*/
1430 
1432  &(flp->langs), 1);
1433 
1434  { static uint_32 source_file_dalgo = 0;
1435  static uint_32 binary_file_dalgo = 0;
1436  static int oneshot = 0;
1437  uint_32 dalgo = 0;
1438 
1439  if (!oneshot) {
1440  source_file_dalgo =
1441  rpmExpandNumeric("%{?_build_source_file_digest_algo}");
1442  binary_file_dalgo =
1443  rpmExpandNumeric("%{?_build_binary_file_digest_algo}");
1444  oneshot++;
1445  }
1446 
1447  dalgo = (isSrc ? source_file_dalgo : binary_file_dalgo);
1448  switch (dalgo) {
1449  case PGPHASHALGO_SHA1:
1450  case PGPHASHALGO_RIPEMD160:
1451  case PGPHASHALGO_MD2:
1452  case PGPHASHALGO_TIGER192:
1453  case PGPHASHALGO_SHA256:
1454  case PGPHASHALGO_SHA384:
1455  case PGPHASHALGO_SHA512:
1456  case PGPHASHALGO_MD4:
1457  case PGPHASHALGO_RIPEMD128:
1458  case PGPHASHALGO_CRC32:
1459  case PGPHASHALGO_ADLER32:
1460  case PGPHASHALGO_CRC64:
1461  (void) rpmlibNeedsFeature(h, "FileDigestParameterized", "4.4.6-1");
1462  /*@switchbreak@*/ break;
1463  case PGPHASHALGO_MD5:
1464  case PGPHASHALGO_HAVAL_5_160: /* XXX unimplemented */
1465  default:
1466  dalgo = PGPHASHALGO_MD5;
1467  /*@switchbreak@*/ break;
1468  }
1469 
1470  buf[0] = '\0';
1471  if (S_ISREG(flp->fl_mode))
1472  (void) dodigest(dalgo, flp->diskURL, (unsigned char *)buf, 1, NULL);
1473  s = buf;
1475  &s, 1);
1477  &dalgo, 1);
1478  }
1479 
1480  buf[0] = '\0';
1481  if (S_ISLNK(flp->fl_mode)) {
1482  int xx = Readlink(flp->diskURL, buf, BUFSIZ);
1483  if (xx >= 0)
1484  buf[xx] = '\0';
1485  if (fl->buildRootURL) {
1486  const char * buildRoot;
1487  (void) urlPath(fl->buildRootURL, &buildRoot);
1488 
1489  if (buf[0] == '/' && strcmp(buildRoot, "/") &&
1490  !strncmp(buf, buildRoot, strlen(buildRoot))) {
1492  _("Symlink points to BuildRoot: %s -> %s\n"),
1493  flp->fileURL, buf);
1494  fl->processingFailed = 1;
1495  }
1496  }
1497  }
1498  s = buf;
1500  &s, 1);
1501 
1502  if (flp->flags & RPMFILE_GHOST) {
1505  }
1507  &(flp->verifyFlags), 1);
1508 
1509  if (!isSrc && isDoc(fl, flp->fileURL))
1510  flp->flags |= RPMFILE_DOC;
1511  /* XXX Should directories have %doc/%config attributes? (#14531) */
1512  if (S_ISDIR(flp->fl_mode))
1513  flp->flags &= ~(RPMFILE_CONFIG|RPMFILE_DOC);
1514 
1516  &(flp->flags), 1);
1517 
1518  /* Add file security context to package. */
1519  {
1520  mode_t fmode = (uint_16)flp->fl_mode;
1521  static const char *nocon = "";
1522  if (matchpathcon(flp->fileURL, fmode, &scon) || scon == NULL)
1523  scon = nocon;
1525  &scon, 1);
1526  if (scon != nocon)
1527  freecon(scon);
1528  }
1529  }
1530  sxfn = _free(sxfn);
1531 
1532  compressFilelist(h);
1533 
1534  { int scareMem = 0;
1535  rpmts ts = NULL; /* XXX FIXME drill rpmts ts all the way down here */
1536  rpmfi fi = rpmfiNew(ts, h, RPMTAG_BASENAMES, scareMem);
1537  char * a, * d;
1538 
1539  if (fi == NULL) return; /* XXX can't happen */
1540 
1541 /*@-onlytrans@*/
1542  fi->te = xcalloc(1, sizeof(*fi->te));
1543 /*@=onlytrans@*/
1544  fi->te->type = TR_ADDED;
1545 
1546  fi->dnl = _free(fi->dnl);
1547  fi->bnl = _free(fi->bnl);
1548  if (!scareMem) fi->dil = _free(fi->dil);
1549 
1550  /* XXX Insure at least 1 byte is always allocated. */
1551  fi->dnl = xmalloc(fi->fc * sizeof(*fi->dnl) + dpathlen + 1);
1552  d = (char *)(fi->dnl + fi->fc);
1553  *d = '\0';
1554 
1555  fi->bnl = xmalloc(fi->fc * (sizeof(*fi->bnl) + sizeof(*fi->dil)));
1556 /*@-dependenttrans@*/ /* FIX: artifact of spoofing headerGetEntry */
1557  fi->dil = (!scareMem)
1558  ? xcalloc(sizeof(*fi->dil), fi->fc)
1559  : (int *)(fi->bnl + fi->fc);
1560 /*@=dependenttrans@*/
1561 
1562  /* XXX Insure at least 1 byte is always allocated. */
1563  fi->apath = xmalloc(fi->fc * sizeof(*fi->apath) + apathlen + 1);
1564  a = (char *)(fi->apath + fi->fc);
1565  *a = '\0';
1566 
1567  fi->actions = xcalloc(sizeof(*fi->actions), fi->fc);
1568  fi->fmapflags = xcalloc(sizeof(*fi->fmapflags), fi->fc);
1569  fi->astriplen = 0;
1570  if (fl->buildRootURL)
1571  fi->astriplen = strlen(fl->buildRootURL);
1572  fi->striplen = 0;
1573  fi->fuser = NULL;
1574  fi->fgroup = NULL;
1575 
1576  /* Make the cpio list */
1577  if (fi->dil != NULL) /* XXX can't happen */
1578  for (i = 0, flp = fl->fileList; i < fi->fc; i++, flp++) {
1579  char * b;
1580 
1581  /* Skip (possible) duplicate file entries, use last entry info. */
1582  while (((flp - fl->fileList) < (fl->fileListRecsUsed - 1)) &&
1583  !strcmp(flp->fileURL, flp[1].fileURL))
1584  flp++;
1585 
1586  if (flp->flags & RPMFILE_EXCLUDE) {
1587  i--;
1588  continue;
1589  }
1590 
1591  if ((fnlen = strlen(flp->diskURL) + 1) > fi->fnlen)
1592  fi->fnlen = fnlen;
1593 
1594  /* Create disk directory and base name. */
1595  fi->dil[i] = i;
1596 /*@-dependenttrans@*/ /* FIX: artifact of spoofing headerGetEntry */
1597  fi->dnl[fi->dil[i]] = d;
1598 /*@=dependenttrans@*/
1599  d = stpcpy(d, flp->diskURL);
1600 
1601  /* Make room for the dirName NUL, find start of baseName. */
1602  for (b = d; b > fi->dnl[fi->dil[i]] && *b != '/'; b--)
1603  b[1] = b[0];
1604  b++; /* dirname's end in '/' */
1605  *b++ = '\0'; /* terminate dirname, b points to basename */
1606  fi->bnl[i] = b;
1607  d += 2; /* skip both dirname and basename NUL's */
1608 
1609  /* Create archive path, normally adding "./" */
1610  /*@-dependenttrans@*/ /* FIX: xstrdup? nah ... */
1611  fi->apath[i] = a;
1612  /*@=dependenttrans@*/
1613  if (_addDotSlash)
1614  a = stpcpy(a, "./");
1615  (void) urlPath(flp->fileURL, &apath);
1616  a = stpcpy(a, (apath + skipLen));
1617  a++; /* skip apath NUL */
1618 
1619  if (flp->flags & RPMFILE_GHOST) {
1620  fi->actions[i] = FA_SKIP;
1621  continue;
1622  }
1623  fi->actions[i] = FA_COPYOUT;
1624  fi->fmapflags[i] = CPIO_MAP_PATH |
1626  if (isSrc)
1627  fi->fmapflags[i] |= CPIO_FOLLOW_SYMLINKS;
1628 
1629  if (S_ISREG(flp->fl_mode)) {
1630  int bingo = 1;
1631  /* Hard links need be tallied only once. */
1632  if (flp->fl_nlink > 1) {
1633  FileListRec jlp = flp + 1;
1634  int j = i + 1;
1635  for (; (unsigned)j < fi->fc; j++, jlp++) {
1636  if (!S_ISREG(jlp->fl_mode))
1637  continue;
1638  if (flp->fl_nlink != jlp->fl_nlink)
1639  continue;
1640  if (flp->fl_ino != jlp->fl_ino)
1641  continue;
1642  if (flp->fl_dev != jlp->fl_dev)
1643  continue;
1644  if (jlp->flags & (RPMFILE_EXCLUDE | RPMFILE_GHOST))
1645  continue;
1646  bingo = 0; /* don't tally hardlink yet. */
1647  break;
1648  }
1649  }
1650  if (bingo)
1651  fl->totalFileSize += flp->fl_size;
1652  }
1653  }
1654 
1656  &(fl->totalFileSize), 1);
1657 
1658  /*@-branchstate -compdef@*/
1659  if (fip)
1660  *fip = fi;
1661  else
1662  fi = rpmfiFree(fi);
1663  /*@=branchstate =compdef@*/
1664  }
1665 }
1666 /*@=bounds@*/
1667 
1670 /*@-boundswrite@*/
1671 static /*@null@*/ FileListRec freeFileList(/*@only@*/ FileListRec fileList,
1672  int count)
1673  /*@*/
1674 {
1675  while (count--) {
1676  fileList[count].diskURL = _free(fileList[count].diskURL);
1677  fileList[count].fileURL = _free(fileList[count].fileURL);
1678  fileList[count].langs = _free(fileList[count].langs);
1679  }
1680  fileList = _free(fileList);
1681  return NULL;
1682 }
1683 /*@=boundswrite@*/
1684 
1685 /* forward ref */
1686 static int recurseDir(FileList fl, const char * diskURL)
1687  /*@globals check_fileList, rpmGlobalMacroContext, h_errno,
1688  fileSystem, internalState @*/
1689  /*@modifies *fl, fl->processingFailed,
1690  fl->fileList, fl->fileListRecsAlloced, fl->fileListRecsUsed,
1691  fl->totalFileSize, fl->fileCount, fl->inFtw, fl->isDir,
1692  check_fileList, rpmGlobalMacroContext,
1693  fileSystem, internalState @*/;
1694 
1702 /*@-boundswrite@*/
1703 static int addFile(FileList fl, const char * diskURL,
1704  /*@null@*/ struct stat * statp)
1705  /*@globals check_fileList, rpmGlobalMacroContext, h_errno,
1706  fileSystem, internalState @*/
1707  /*@modifies *statp, *fl, fl->processingFailed,
1708  fl->fileList, fl->fileListRecsAlloced, fl->fileListRecsUsed,
1709  fl->totalFileSize, fl->fileCount,
1710  check_fileList, rpmGlobalMacroContext,
1711  fileSystem, internalState @*/
1712 {
1713  const char *fn = xstrdup(diskURL);
1714  const char *fileURL = fn;
1715  struct stat statbuf;
1716  mode_t fileMode;
1717  uid_t fileUid;
1718  gid_t fileGid;
1719  const char *fileUname;
1720  const char *fileGname;
1721  char *lang;
1722 
1723  /* Path may have prepended buildRootURL, so locate the original filename. */
1724  /*
1725  * XXX There are 3 types of entry into addFile:
1726  *
1727  * From diskUrl statp
1728  * =====================================================
1729  * processBinaryFile path NULL
1730  * processBinaryFile glob result path NULL
1731  * recurseDir path stat
1732  *
1733  */
1734 /*@-branchstate@*/
1735  { const char *fileName;
1736  int urltype = urlPath(fileURL, &fileName);
1737  switch (urltype) {
1738  case URL_IS_PATH:
1739  fileURL += (fileName - fileURL);
1740  if (fl->buildRootURL && strcmp(fl->buildRootURL, "/")) {
1741  size_t nb = strlen(fl->buildRootURL);
1742  const char * s = fileURL + nb;
1743  char * t = (char *) fileURL;
1744  (void) memmove(t, s, nb);
1745  }
1746  fileURL = fn;
1747  break;
1748  default:
1749  if (fl->buildRootURL && strcmp(fl->buildRootURL, "/"))
1750  fileURL += strlen(fl->buildRootURL);
1751  break;
1752  }
1753  }
1754 /*@=branchstate@*/
1755 
1756  /* XXX make sure '/' can be packaged also */
1757  /*@-branchstate@*/
1758  if (*fileURL == '\0')
1759  fileURL = "/";
1760  /*@=branchstate@*/
1761 
1762  /* If we are using a prefix, validate the file */
1763  if (!fl->inFtw && fl->prefix) {
1764  const char *prefixTest;
1765  const char *prefixPtr = fl->prefix;
1766 
1767  (void) urlPath(fileURL, &prefixTest);
1768  while (*prefixPtr && *prefixTest && (*prefixTest == *prefixPtr)) {
1769  prefixPtr++;
1770  prefixTest++;
1771  }
1772  if (*prefixPtr || (*prefixTest && *prefixTest != '/')) {
1773  rpmError(RPMERR_BADSPEC, _("File doesn't match prefix (%s): %s\n"),
1774  fl->prefix, fileURL);
1775  fl->processingFailed = 1;
1776  return RPMERR_BADSPEC;
1777  }
1778  }
1779 
1780  if (statp == NULL) {
1781  statp = &statbuf;
1782  memset(statp, 0, sizeof(*statp));
1783  if (fl->devtype) {
1784  time_t now = time(NULL);
1785 
1786  /* XXX hack up a stat structure for a %dev(...) directive. */
1787  statp->st_nlink = 1;
1788  statp->st_rdev =
1789  ((fl->devmajor & 0xff) << 8) | (fl->devminor & 0xff);
1790  statp->st_dev = statp->st_rdev;
1791  statp->st_mode = (fl->devtype == 'b' ? S_IFBLK : S_IFCHR);
1792  statp->st_mode |= (fl->cur_ar.ar_fmode & 0777);
1793  statp->st_atime = now;
1794  statp->st_mtime = now;
1795  statp->st_ctime = now;
1796  } else if (Lstat(diskURL, statp)) {
1797  rpmError(RPMERR_BADSPEC, _("File not found: %s\n"), diskURL);
1798  fl->processingFailed = 1;
1799  return RPMERR_BADSPEC;
1800  }
1801  }
1802 
1803  if ((! fl->isDir) && S_ISDIR(statp->st_mode)) {
1804 /*@-nullstate@*/ /* FIX: fl->buildRootURL may be NULL */
1805  return recurseDir(fl, diskURL);
1806 /*@=nullstate@*/
1807  }
1808 
1809  fileMode = statp->st_mode;
1810  fileUid = statp->st_uid;
1811  fileGid = statp->st_gid;
1812 
1813  if (S_ISDIR(fileMode) && fl->cur_ar.ar_dmodestr) {
1814  fileMode &= S_IFMT;
1815  fileMode |= fl->cur_ar.ar_dmode;
1816  } else if (fl->cur_ar.ar_fmodestr != NULL) {
1817  fileMode &= S_IFMT;
1818  fileMode |= fl->cur_ar.ar_fmode;
1819  }
1820  if (fl->cur_ar.ar_user) {
1821  fileUname = getUnameS(fl->cur_ar.ar_user);
1822  } else {
1823  fileUname = getUname(fileUid);
1824  }
1825  if (fl->cur_ar.ar_group) {
1826  fileGname = getGnameS(fl->cur_ar.ar_group);
1827  } else {
1828  fileGname = getGname(fileGid);
1829  }
1830 
1831  /* Default user/group to builder's user/group */
1832  if (fileUname == NULL)
1833  fileUname = getUname(getuid());
1834  if (fileGname == NULL)
1835  fileGname = getGname(getgid());
1836 
1837  /* S_XXX macro must be consistent with type in find call at check-files script */
1838  if (check_fileList && (S_ISREG(fileMode) || S_ISLNK(fileMode))) {
1839  const char * diskfn = NULL;
1840  (void) urlPath(diskURL, &diskfn);
1841  appendStringBuf(check_fileList, diskfn);
1842  appendStringBuf(check_fileList, "\n");
1843  }
1844 
1845  /* Add to the file list */
1846  if (fl->fileListRecsUsed == fl->fileListRecsAlloced) {
1847  fl->fileListRecsAlloced += 128;
1848  fl->fileList = xrealloc(fl->fileList,
1849  fl->fileListRecsAlloced * sizeof(*(fl->fileList)));
1850  }
1851 
1852  { FileListRec flp = &fl->fileList[fl->fileListRecsUsed];
1853  int i;
1854 
1855  flp->fl_st = *statp; /* structure assignment */
1856  flp->fl_mode = fileMode;
1857  flp->fl_uid = fileUid;
1858  flp->fl_gid = fileGid;
1859 
1860  flp->fileURL = xstrdup(fileURL);
1861  flp->diskURL = xstrdup(diskURL);
1862  flp->uname = fileUname;
1863  flp->gname = fileGname;
1864 
1865  if (fl->currentLangs && fl->nLangs > 0) {
1866  char * ncl;
1867  size_t nl = 0;
1868 
1869  for (i = 0; i < fl->nLangs; i++)
1870  nl += strlen(fl->currentLangs[i]) + 1;
1871 
1872  flp->langs = ncl = xmalloc(nl);
1873  for (i = 0; i < fl->nLangs; i++) {
1874  const char *ocl;
1875  if (i) *ncl++ = '|';
1876  for (ocl = fl->currentLangs[i]; *ocl != '\0'; ocl++)
1877  *ncl++ = *ocl;
1878  *ncl = '\0';
1879  }
1880  } else if (! parseForRegexLang(fileURL, &lang)) {
1881  flp->langs = xstrdup(lang);
1882  } else {
1883  flp->langs = xstrdup("");
1884  }
1885 
1886  flp->flags = fl->currentFlags;
1887  flp->specdFlags = fl->currentSpecdFlags;
1888  flp->verifyFlags = fl->currentVerifyFlags;
1889  }
1890 
1891  fl->fileListRecsUsed++;
1892  fl->fileCount++;
1893 /*@i@*/ fn = _free(fn);
1894 
1895  return 0;
1896 }
1897 /*@=boundswrite@*/
1898 
1905 static int recurseDir(FileList fl, const char * diskURL)
1906 {
1907  char * ftsSet[2];
1908  FTS * ftsp;
1909  FTSENT * fts;
1910  int myFtsOpts = (FTS_COMFOLLOW | FTS_NOCHDIR | FTS_PHYSICAL);
1911  int rc = RPMERR_BADSPEC;
1912 
1913  fl->inFtw = 1; /* Flag to indicate file has buildRootURL prefixed */
1914  fl->isDir = 1; /* Keep it from following myftw() again */
1915 
1916  ftsSet[0] = (char *) diskURL;
1917  ftsSet[1] = NULL;
1918  ftsp = Fts_open(ftsSet, myFtsOpts, NULL);
1919  while ((fts = Fts_read(ftsp)) != NULL) {
1920  switch (fts->fts_info) {
1921  case FTS_D: /* preorder directory */
1922  case FTS_F: /* regular file */
1923  case FTS_SL: /* symbolic link */
1924  case FTS_SLNONE: /* symbolic link without target */
1925  case FTS_DEFAULT: /* none of the above */
1926  rc = addFile(fl, fts->fts_accpath, fts->fts_statp);
1927  /*@switchbreak@*/ break;
1928  case FTS_DOT: /* dot or dot-dot */
1929  case FTS_DP: /* postorder directory */
1930  rc = 0;
1931  /*@switchbreak@*/ break;
1932  case FTS_NS: /* stat(2) failed */
1933  case FTS_DNR: /* unreadable directory */
1934  case FTS_ERR: /* error; errno is set */
1935  case FTS_DC: /* directory that causes cycles */
1936  case FTS_NSOK: /* no stat(2) requested */
1937  case FTS_INIT: /* initialized only */
1938  case FTS_W: /* whiteout object */
1939  default:
1940  rc = RPMERR_BADSPEC;
1941  /*@switchbreak@*/ break;
1942  }
1943  if (rc)
1944  break;
1945  }
1946  (void) Fts_close(ftsp);
1947 
1948  fl->isDir = 0;
1949  fl->inFtw = 0;
1950 
1951  return rc;
1952 }
1953 
1962 static int processMetadataFile(Package pkg, FileList fl, const char * fileURL,
1963  rpmTag tag)
1964  /*@globals check_fileList, rpmGlobalMacroContext, h_errno,
1965  fileSystem, internalState @*/
1966  /*@modifies pkg->header, *fl, fl->processingFailed,
1967  fl->fileList, fl->fileListRecsAlloced, fl->fileListRecsUsed,
1968  fl->totalFileSize, fl->fileCount,
1969  check_fileList, rpmGlobalMacroContext,
1970  fileSystem, internalState @*/
1971 {
1972  const char * buildURL = "%{_builddir}/%{?buildsubdir}/";
1973  const char * fn = NULL;
1974  const char * apkt = NULL;
1975  const unsigned char * pkt = NULL;
1976  ssize_t pktlen = 0;
1977  int absolute = 0;
1978  int rc = 1;
1979  int xx;
1980 
1981  (void) urlPath(fileURL, &fn);
1982  if (*fn == '/') {
1983  fn = rpmGenPath(fl->buildRootURL, NULL, fn);
1984  absolute = 1;
1985  } else
1986  fn = rpmGenPath(buildURL, NULL, fn);
1987 
1988 /*@-branchstate@*/
1989  switch (tag) {
1990  default:
1991  rpmError(RPMERR_BADSPEC, _("%s: can't load unknown tag (%d).\n"),
1992  fn, tag);
1993  goto exit;
1994  /*@notreached@*/ break;
1995  case RPMTAG_PUBKEYS:
1996  if ((rc = pgpReadPkts(fn, &pkt, &pktlen)) <= 0) {
1997  rpmError(RPMERR_BADSPEC, _("%s: public key read failed.\n"), fn);
1998  goto exit;
1999  }
2000  if (rc != PGPARMOR_PUBKEY) {
2001  rpmError(RPMERR_BADSPEC, _("%s: not an armored public key.\n"), fn);
2002  goto exit;
2003  }
2004  apkt = pgpArmorWrap(PGPARMOR_PUBKEY, pkt, pktlen);
2005  break;
2006  case RPMTAG_POLICIES:
2007  if ((rc = rpmioSlurp(fn, &pkt, &pktlen)) != 0) {
2008  rpmError(RPMERR_BADSPEC, _("%s: *.te policy read failed.\n"), fn);
2009  goto exit;
2010  }
2011  apkt = (const char *) pkt; /* XXX unsigned char */
2012  pkt = NULL;
2013  break;
2014  }
2015 /*@=branchstate@*/
2016 
2017  xx = headerAddOrAppendEntry(pkg->header, tag,
2018  RPM_STRING_ARRAY_TYPE, &apkt, 1);
2019 
2020  rc = 0;
2021  if (absolute)
2022  rc = addFile(fl, fn, NULL);
2023 
2024 exit:
2025  apkt = _free(apkt);
2026  pkt = _free(pkt);
2027  fn = _free(fn);
2028  if (rc) {
2029  fl->processingFailed = 1;
2030  rc = RPMERR_BADSPEC;
2031  }
2032  return rc;
2033 }
2034 
2042 static int processBinaryFile(/*@unused@*/ Package pkg, FileList fl,
2043  const char * fileURL)
2044  /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/
2045  /*@modifies *fl, fl->processingFailed,
2046  fl->fileList, fl->fileListRecsAlloced, fl->fileListRecsUsed,
2047  fl->totalFileSize, fl->fileCount,
2048  rpmGlobalMacroContext, fileSystem, internalState @*/
2049 {
2050  int quote = 1; /* XXX permit quoted glob characters. */
2051  int doGlob;
2052  const char *diskURL = NULL;
2053  int rc = 0;
2054 
2055  doGlob = Glob_pattern_p(fileURL, quote);
2056 
2057  /* Check that file starts with leading "/" */
2058  { const char * fileName;
2059  (void) urlPath(fileURL, &fileName);
2060  if (*fileName != '/') {
2061  rpmError(RPMERR_BADSPEC, _("File needs leading \"/\": %s\n"),
2062  fileName);
2063  rc = 1;
2064  goto exit;
2065  }
2066  }
2067 
2068  /* Copy file name or glob pattern removing multiple "/" chars. */
2069  /*
2070  * Note: rpmGetPath should guarantee a "canonical" path. That means
2071  * that the following pathologies should be weeded out:
2072  * //bin//sh
2073  * //usr//bin/
2074  * /.././../usr/../bin//./sh
2075  */
2076  diskURL = rpmGenPath(fl->buildRootURL, NULL, fileURL);
2077 
2078  if (doGlob) {
2079  const char ** argv = NULL;
2080  int argc = 0;
2081  int i;
2082 
2083  /* XXX for %dev marker in file manifest only */
2084  if (fl->noGlob) {
2085  rpmError(RPMERR_BADSPEC, _("Glob not permitted: %s\n"),
2086  diskURL);
2087  rc = 1;
2088  goto exit;
2089  }
2090 
2091  /*@-branchstate@*/
2092  rc = rpmGlob(diskURL, &argc, &argv);
2093  if (rc == 0 && argc >= 1) {
2094  for (i = 0; i < argc; i++) {
2095  rc = addFile(fl, argv[i], NULL);
2096 /*@-boundswrite@*/
2097  argv[i] = _free(argv[i]);
2098 /*@=boundswrite@*/
2099  }
2100  argv = _free(argv);
2101  } else {
2102  rpmError(RPMERR_BADSPEC, _("File not found by glob: %s\n"),
2103  diskURL);
2104  rc = 1;
2105  goto exit;
2106  }
2107  /*@=branchstate@*/
2108  } else {
2109  rc = addFile(fl, diskURL, NULL);
2110  }
2111 
2112 exit:
2113  diskURL = _free(diskURL);
2114  if (rc) {
2115  fl->processingFailed = 1;
2116  rc = RPMERR_BADSPEC;
2117  }
2118  return rc;
2119 }
2120 
2123 /*@-boundswrite@*/
2124 static int processPackageFiles(Spec spec, Package pkg,
2125  int installSpecialDoc, int test)
2126  /*@globals rpmGlobalMacroContext, h_errno,
2127  fileSystem, internalState@*/
2128  /*@modifies spec->macros,
2129  pkg->cpioList, pkg->fileList, pkg->specialDoc, pkg->header,
2130  rpmGlobalMacroContext, fileSystem, internalState @*/
2131 {
2133  struct FileList_s fl;
2134  char *s, **files, **fp;
2135  const char *fileName;
2136  char buf[BUFSIZ];
2137  struct AttrRec_s arbuf;
2138  AttrRec specialDocAttrRec = &arbuf;
2139  char *specialDoc = NULL;
2140 
2141  nullAttrRec(specialDocAttrRec);
2142  pkg->cpioList = NULL;
2143 
2144  if (pkg->fileFile) {
2145  const char *ffn;
2146  FILE * f;
2147  FD_t fd;
2148 
2149  /* XXX W2DO? urlPath might be useful here. */
2150  if (*pkg->fileFile == '/') {
2151  ffn = rpmGetPath(pkg->fileFile, NULL);
2152  } else {
2153  /* XXX FIXME: add %{buildsubdir} */
2154  ffn = rpmGetPath("%{_builddir}/",
2155  (spec->buildSubdir ? spec->buildSubdir : "") ,
2156  "/", pkg->fileFile, NULL);
2157  }
2158  fd = Fopen(ffn, "r.fpio");
2159 
2160  if (fd == NULL || Ferror(fd)) {
2162  _("Could not open %%files file %s: %s\n"),
2163  ffn, Fstrerror(fd));
2164  return RPMERR_BADFILENAME;
2165  }
2166  ffn = _free(ffn);
2167 
2168  /*@+voidabstract@*/ f = fdGetFp(fd); /*@=voidabstract@*/
2169  if (f != NULL)
2170  while (fgets(buf, sizeof(buf), f)) {
2171  handleComments(buf);
2172  if (expandMacros(spec, spec->macros, buf, sizeof(buf))) {
2173  rpmError(RPMERR_BADSPEC, _("line: %s\n"), buf);
2174  return RPMERR_BADSPEC;
2175  }
2176  appendStringBuf(pkg->fileList, buf);
2177  }
2178  (void) Fclose(fd);
2179  }
2180 
2181  /* Init the file list structure */
2182  memset(&fl, 0, sizeof(fl));
2183 
2184  fl.buildRootURL = rpmGenPath(spec->rootURL, "%{?buildroot}", NULL);
2185 
2186  if (hge(pkg->header, RPMTAG_DEFAULTPREFIX, NULL, &fl.prefix, NULL))
2187  fl.prefix = xstrdup(fl.prefix);
2188  else
2189  fl.prefix = NULL;
2190 
2191  fl.fileCount = 0;
2192  fl.totalFileSize = 0;
2193  fl.processingFailed = 0;
2194 
2195  fl.passedSpecialDoc = 0;
2196  fl.isSpecialDoc = 0;
2197 
2198  fl.isDir = 0;
2199  fl.inFtw = 0;
2200  fl.currentFlags = 0;
2201  fl.currentVerifyFlags = 0;
2202 
2203  fl.noGlob = 0;
2204  fl.devtype = 0;
2205  fl.devmajor = 0;
2206  fl.devminor = 0;
2207 
2208  nullAttrRec(&fl.cur_ar);
2209  nullAttrRec(&fl.def_ar);
2210  dupAttrRec(&root_ar, &fl.def_ar); /* XXX assume %defattr(-,root,root) */
2211 
2213  fl.nLangs = 0;
2214  fl.currentLangs = NULL;
2215 
2216  fl.currentSpecdFlags = 0;
2217  fl.defSpecdFlags = 0;
2218 
2219  fl.docDirCount = 0;
2220  fl.docDirs[fl.docDirCount++] = xstrdup("/usr/doc");
2221  fl.docDirs[fl.docDirCount++] = xstrdup("/usr/man");
2222  fl.docDirs[fl.docDirCount++] = xstrdup("/usr/info");
2223  fl.docDirs[fl.docDirCount++] = xstrdup("/usr/X11R6/man");
2224  fl.docDirs[fl.docDirCount++] = xstrdup("/usr/share/doc");
2225  fl.docDirs[fl.docDirCount++] = xstrdup("/usr/share/man");
2226  fl.docDirs[fl.docDirCount++] = xstrdup("/usr/share/info");
2227  fl.docDirs[fl.docDirCount++] = xstrdup("/usr/src/examples");
2228  fl.docDirs[fl.docDirCount++] = rpmGetPath("%{_docdir}", NULL);
2229  fl.docDirs[fl.docDirCount++] = rpmGetPath("%{_mandir}", NULL);
2230  fl.docDirs[fl.docDirCount++] = rpmGetPath("%{_infodir}", NULL);
2231  fl.docDirs[fl.docDirCount++] = rpmGetPath("%{_javadocdir}", NULL);
2232  fl.docDirs[fl.docDirCount++] = rpmGetPath("%{_examplesdir}", NULL);
2233 
2234  fl.fileList = NULL;
2235  fl.fileListRecsAlloced = 0;
2236  fl.fileListRecsUsed = 0;
2237 
2238  s = getStringBuf(pkg->fileList);
2239  files = splitString(s, strlen(s), '\n');
2240 
2241  for (fp = files; *fp != NULL; fp++) {
2242  s = *fp;
2243  SKIPSPACE(s);
2244  if (*s == '\0')
2245  continue;
2246  fileName = NULL;
2247  /*@-nullpass@*/ /* LCL: buf is NULL ?!? */
2248  strcpy(buf, s);
2249  /*@=nullpass@*/
2250 
2251  /* Reset for a new line in %files */
2252  fl.isDir = 0;
2253  fl.inFtw = 0;
2254  fl.currentFlags = 0;
2255  /* turn explicit flags into %def'd ones (gosh this is hacky...) */
2256  fl.currentSpecdFlags = ((unsigned)fl.defSpecdFlags) >> 8;
2258  fl.isSpecialDoc = 0;
2259 
2260  fl.noGlob = 0;
2261  fl.devtype = 0;
2262  fl.devmajor = 0;
2263  fl.devminor = 0;
2264 
2265  /* XXX should reset to %deflang value */
2266  if (fl.currentLangs) {
2267  int i;
2268  for (i = 0; i < fl.nLangs; i++)
2269  /*@-unqualifiedtrans@*/
2270  fl.currentLangs[i] = _free(fl.currentLangs[i]);
2271  /*@=unqualifiedtrans@*/
2272  fl.currentLangs = _free(fl.currentLangs);
2273  }
2274  fl.nLangs = 0;
2275 
2276  dupAttrRec(&fl.def_ar, &fl.cur_ar);
2277 
2278  /*@-nullpass@*/ /* LCL: buf is NULL ?!? */
2279  if (parseForVerify(buf, &fl))
2280  continue;
2281  if (parseForAttr(buf, &fl))
2282  continue;
2283  if (parseForDev(buf, &fl))
2284  continue;
2285  if (parseForConfig(buf, &fl))
2286  continue;
2287  if (parseForLang(buf, &fl))
2288  continue;
2289  /*@-nullstate@*/ /* FIX: pkg->fileFile might be NULL */
2290  if (parseForSimple(spec, pkg, buf, &fl, &fileName))
2291  /*@=nullstate@*/
2292  continue;
2293  /*@=nullpass@*/
2294  if (fileName == NULL)
2295  continue;
2296 
2297  /*@-branchstate@*/
2298  if (fl.isSpecialDoc) {
2299  /* Save this stuff for last */
2300  specialDoc = _free(specialDoc);
2301  specialDoc = xstrdup(fileName);
2302  dupAttrRec(&fl.cur_ar, specialDocAttrRec);
2303  } else if (fl.currentFlags & RPMFILE_PUBKEY) {
2304 /*@-nullstate@*/ /* FIX: pkg->fileFile might be NULL */
2305  (void) processMetadataFile(pkg, &fl, fileName, RPMTAG_PUBKEYS);
2306 /*@=nullstate@*/
2307  } else if (fl.currentFlags & RPMFILE_POLICY) {
2308 /*@-nullstate@*/ /* FIX: pkg->fileFile might be NULL */
2309  (void) processMetadataFile(pkg, &fl, fileName, RPMTAG_POLICIES);
2310 /*@=nullstate@*/
2311  } else {
2312 /*@-nullstate@*/ /* FIX: pkg->fileFile might be NULL */
2313  (void) processBinaryFile(pkg, &fl, fileName);
2314 /*@=nullstate@*/
2315  }
2316  /*@=branchstate@*/
2317  }
2318 
2319  /* Now process special doc, if there is one */
2320  if (specialDoc) {
2321  if (installSpecialDoc) {
2322  int _missing_doc_files_terminate_build =
2323  rpmExpandNumeric("%{?_missing_doc_files_terminate_build}");
2324  int rc;
2325 
2326  rc = doScript(spec, RPMBUILD_STRINGBUF, "%doc", pkg->specialDoc, test);
2327  if (rc && _missing_doc_files_terminate_build)
2328  fl.processingFailed = rc;
2329  }
2330 
2331  /* Reset for %doc */
2332  fl.isDir = 0;
2333  fl.inFtw = 0;
2334  fl.currentFlags = 0;
2336 
2337  fl.noGlob = 0;
2338  fl.devtype = 0;
2339  fl.devmajor = 0;
2340  fl.devminor = 0;
2341 
2342  /* XXX should reset to %deflang value */
2343  if (fl.currentLangs) {
2344  int i;
2345  for (i = 0; i < fl.nLangs; i++)
2346  /*@-unqualifiedtrans@*/
2347  fl.currentLangs[i] = _free(fl.currentLangs[i]);
2348  /*@=unqualifiedtrans@*/
2349  fl.currentLangs = _free(fl.currentLangs);
2350  }
2351  fl.nLangs = 0;
2352 
2353  dupAttrRec(specialDocAttrRec, &fl.cur_ar);
2354  freeAttrRec(specialDocAttrRec);
2355 
2356  /*@-nullstate@*/ /* FIX: pkg->fileFile might be NULL */
2357  (void) processBinaryFile(pkg, &fl, specialDoc);
2358  /*@=nullstate@*/
2359 
2360  specialDoc = _free(specialDoc);
2361  }
2362 
2363  freeSplitString(files);
2364 
2365  if (fl.processingFailed)
2366  goto exit;
2367 
2368  /* Verify that file attributes scope over hardlinks correctly. */
2369  if (checkHardLinks(&fl) && !rpmExpandNumeric("%{_hack_dontneed_PartialHardlinkSets}"))
2370  (void) rpmlibNeedsFeature(pkg->header,
2371  "PartialHardlinkSets", "4.0.4-1");
2372 
2373  genCpioListAndHeader(&fl, &pkg->cpioList, pkg->header, 0);
2374 
2375  if (spec->timeCheck)
2376  timeCheck(spec->timeCheck, pkg->header);
2377 
2378 exit:
2379  fl.buildRootURL = _free(fl.buildRootURL);
2380  fl.prefix = _free(fl.prefix);
2381 
2382  freeAttrRec(&fl.cur_ar);
2383  freeAttrRec(&fl.def_ar);
2384 
2385  if (fl.currentLangs) {
2386  int i;
2387  for (i = 0; i < fl.nLangs; i++)
2388  /*@-unqualifiedtrans@*/
2389  fl.currentLangs[i] = _free(fl.currentLangs[i]);
2390  /*@=unqualifiedtrans@*/
2391  fl.currentLangs = _free(fl.currentLangs);
2392  }
2393 
2395 
2396  while (fl.docDirCount--)
2397  fl.docDirs[fl.docDirCount] = _free(fl.docDirs[fl.docDirCount]);
2398  return fl.processingFailed;
2399 }
2400 /*@=boundswrite@*/
2401 
2403 {
2404  HeaderIterator hi;
2405  int_32 tag, type, count;
2406  const void * ptr;
2407  StringBuf sourceFiles;
2408  struct Source *srcPtr;
2409 
2410  /* Only specific tags are added to the source package header */
2411  /*@-branchstate@*/
2412  if (!spec->sourceHdrInit) {
2413  for (hi = headerInitIterator(spec->packages->header);
2414  headerNextIterator(hi, &tag, &type, &ptr, &count);
2415  ptr = headerFreeData(ptr, type))
2416  {
2417  switch (tag) {
2418  case RPMTAG_NAME:
2419  case RPMTAG_VERSION:
2420  case RPMTAG_RELEASE:
2421  case RPMTAG_EPOCH:
2422  case RPMTAG_SUMMARY:
2423  case RPMTAG_DESCRIPTION:
2424  case RPMTAG_PACKAGER:
2425  case RPMTAG_DISTRIBUTION:
2426  case RPMTAG_DISTURL:
2427  case RPMTAG_VENDOR:
2428  case RPMTAG_LICENSE:
2429  case RPMTAG_GROUP:
2430  case RPMTAG_OS:
2431  case RPMTAG_ARCH:
2432  case RPMTAG_CHANGELOGTIME:
2433  case RPMTAG_CHANGELOGNAME:
2434  case RPMTAG_CHANGELOGTEXT:
2435  case RPMTAG_URL:
2436  case RPMTAG_ICON:
2437  case RPMTAG_GIF:
2438  case RPMTAG_XPM:
2439  case HEADER_I18NTABLE:
2440  if (ptr)
2441  (void)headerAddEntry(spec->sourceHeader, tag, type, ptr, count);
2442  /*@switchbreak@*/ break;
2443  default:
2444  /* do not copy */
2445  /*@switchbreak@*/ break;
2446  }
2447  }
2448  hi = headerFreeIterator(hi);
2449  /*@=branchstate@*/
2450 
2451  if (spec->BANames && spec->BACount > 0) {
2454  spec->BANames, spec->BACount);
2455  }
2456  }
2457 
2458  if (sfp != NULL && *sfp != NULL)
2459  sourceFiles = *sfp;
2460  else
2461  sourceFiles = newStringBuf();
2462 
2463  /* Construct the source/patch tag entries */
2464  appendLineStringBuf(sourceFiles, spec->specFile);
2465  if (spec->sourceHeader != NULL)
2466  for (srcPtr = spec->sources; srcPtr != NULL; srcPtr = srcPtr->next) {
2467  { const char * sfn;
2468  sfn = rpmGetPath( ((srcPtr->flags & RPMFILE_GHOST) ? "!" : ""),
2469  "%{_sourcedir}/", srcPtr->source, NULL);
2470  appendLineStringBuf(sourceFiles, sfn);
2471  sfn = _free(sfn);
2472  }
2473 
2474  if (spec->sourceHdrInit)
2475  continue;
2476 
2477  if (srcPtr->flags & RPMFILE_SOURCE) {
2479  RPM_STRING_ARRAY_TYPE, &srcPtr->source, 1);
2480  if (srcPtr->flags & RPMFILE_GHOST) {
2482  RPM_INT32_TYPE, &srcPtr->num, 1);
2483  }
2484  }
2485  if (srcPtr->flags & RPMFILE_PATCH) {
2487  RPM_STRING_ARRAY_TYPE, &srcPtr->source, 1);
2488  if (srcPtr->flags & RPMFILE_GHOST) {
2490  RPM_INT32_TYPE, &srcPtr->num, 1);
2491  }
2492  }
2493  }
2494 
2495  if (sfp == NULL)
2496  sourceFiles = freeStringBuf(sourceFiles);
2497 
2498  spec->sourceHdrInit = 1;
2499 
2500  return 0;
2501 }
2502 
2504 {
2505  StringBuf sourceFiles, *sfp = &sourceFiles;
2506  int x, isSpec = 1;
2507  struct FileList_s fl;
2508  char **files, **fp;
2509  int rc;
2510  char *_srcdefattr;
2511  char buf[BUFSIZ];
2512 
2513  _srcdefattr = rpmExpand("%{?_srcdefattr}", NULL);
2514 
2515 
2516  *sfp = newStringBuf();
2517  x = initSourceHeader(spec, sfp);
2518 
2519  /* Init the file list structure */
2520  memset(&fl, 0, sizeof(fl));
2521  if (_srcdefattr && *_srcdefattr) {
2522  sprintf(buf, "%%defattr %s", _srcdefattr);
2523  parseForAttr(buf, &fl);
2524  }
2525 
2526  /* Construct the SRPM file list. */
2527  fl.fileList = xcalloc((spec->numSources + 1), sizeof(*fl.fileList));
2528  rc = fl.processingFailed = 0;
2529  fl.fileListRecsUsed = 0;
2530  fl.totalFileSize = 0;
2531  fl.prefix = NULL;
2532  fl.buildRootURL = NULL;
2533 
2534  { const char *s = getStringBuf(*sfp);
2535  files = splitString(s, strlen(s), '\n');
2536  }
2537 
2538  /* The first source file is the spec file */
2539  x = 0;
2540  for (fp = files; *fp != NULL; fp++) {
2541  const char * diskURL, *diskPath;
2542  FileListRec flp;
2543 
2544  diskURL = *fp;
2545  SKIPSPACE(diskURL);
2546  if (! *diskURL)
2547  continue;
2548 
2549  flp = &fl.fileList[x];
2550 
2551  flp->flags = isSpec ? RPMFILE_SPECFILE : 0;
2552  /* files with leading ! are no source files */
2553  if (*diskURL == '!') {
2554  flp->flags |= RPMFILE_GHOST;
2555  diskURL++;
2556  }
2557 
2558  (void) urlPath(diskURL, &diskPath);
2559 
2560  flp->diskURL = xstrdup(diskURL);
2561  diskPath = strrchr(diskPath, '/');
2562  if (diskPath)
2563  diskPath++;
2564  else
2565  diskPath = diskURL;
2566 
2567  flp->fileURL = xstrdup(diskPath);
2568  flp->verifyFlags = RPMVERIFY_ALL;
2569 
2570  if (Stat(diskURL, &flp->fl_st)) {
2571  rpmError(RPMERR_BADSPEC, _("Bad file: %s: %s\n"),
2572  diskURL, strerror(errno));
2573  rc = fl.processingFailed = 1;
2574  }
2575 
2576  if (fl.def_ar.ar_fmodestr) {
2577  flp->fl_mode &= S_IFMT;
2578  flp->fl_mode |= fl.def_ar.ar_fmode;
2579  }
2580 
2581  flp->uname = fl.def_ar.ar_user ?
2582  getUnameS(fl.def_ar.ar_user):
2583  getUname(flp->fl_uid);
2584 
2585  flp->gname = fl.def_ar.ar_group ?
2586  getGnameS(fl.def_ar.ar_group) :
2587  getGname(flp->fl_gid);
2588 
2589  flp->langs = xstrdup("");
2590 
2591  if (! (flp->uname && flp->gname)) {
2592  rpmError(RPMERR_BADSPEC, _("Bad owner/group: %s\n"), diskURL);
2593  rc = fl.processingFailed = 1;
2594  }
2595 
2596  isSpec = 0;
2597  x++;
2598  }
2599  fl.fileListRecsUsed = x;
2600  freeSplitString(files);
2601 
2602  if (rc)
2603  goto exit;
2604 
2605  spec->sourceCpioList = NULL;
2606  genCpioListAndHeader(&fl, &spec->sourceCpioList, spec->sourceHeader, 1);
2607 
2608 exit:
2609  *sfp = freeStringBuf(*sfp);
2611  _free(_srcdefattr);
2612  freeAttrRec(&fl.def_ar);
2613  return rc;
2614 }
2615 
2622  /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/
2623  /*@modifies rpmGlobalMacroContext, fileSystem, internalState @*/
2624 {
2625 /*@-readonlytrans@*/
2626  static const char * av_ckfile[] = { "%{?__check_files}", NULL };
2627 /*@=readonlytrans@*/
2628  StringBuf sb_stdout = NULL;
2629  const char * s;
2630  int rc;
2631 
2632  s = rpmExpand(av_ckfile[0], NULL);
2633  if (!(s && *s)) {
2634  rc = -1;
2635  goto exit;
2636  }
2637  rc = 0;
2638 
2639  rpmMessage(RPMMESS_NORMAL, _("Checking for unpackaged file(s): %s\n"), s);
2640 
2641 /*@-boundswrite@*/
2642  rc = rpmfcExec(av_ckfile, fileList, &sb_stdout, 0);
2643 /*@=boundswrite@*/
2644  if (rc < 0)
2645  goto exit;
2646 
2647  if (sb_stdout) {
2648  int _unpackaged_files_terminate_build =
2649  rpmExpandNumeric("%{?_unpackaged_files_terminate_build}");
2650  const char * t;
2651 
2652  t = getStringBuf(sb_stdout);
2653  if ((*t != '\0') && (*t != '\n')) {
2654  rc = (_unpackaged_files_terminate_build) ? 1 : 0;
2656  _("Installed (but unpackaged) file(s) found:\n%s"), t);
2657  }
2658  }
2659 
2660 exit:
2661  sb_stdout = freeStringBuf(sb_stdout);
2662  s = _free(s);
2663  return rc;
2664 }
2665 
2666 /*@-incondefs@*/
2667 int processBinaryFiles(Spec spec, int installSpecialDoc, int test)
2668  /*@globals check_fileList @*/
2669  /*@modifies check_fileList @*/
2670 {
2671  Package pkg;
2672  int res = 0;
2673 
2674  check_fileList = newStringBuf();
2675 
2676  for (pkg = spec->packages; pkg != NULL; pkg = pkg->next) {
2677  const char *n, *v, *r;
2678  int rc;
2679 
2680  if (pkg->fileList == NULL)
2681  continue;
2682 
2683  (void) headerMacrosLoad(pkg->header);
2684 
2685  (void) headerNVR(pkg->header, &n, &v, &r);
2686  rpmMessage(RPMMESS_NORMAL, _("Processing files: %s-%s-%s\n"), n, v, r);
2687 
2688  if ((rc = processPackageFiles(spec, pkg, installSpecialDoc, test)))
2689  res = rc;
2690 
2691  /* Finalize package scriptlets before extracting dependencies. */
2692  if ((rc = processScriptFiles(spec, pkg)))
2693  res = rc;
2694 
2695  if ((rc = rpmfcGenerateDepends(spec, pkg)))
2696  res = rc;
2697 
2698  /* XXX this should be earlier for deps to be entirely sorted. */
2699  providePackageNVR(pkg->header);
2700 
2701  (void) headerMacrosUnload(pkg->header);
2702  }
2703 
2704  /* Now we have in fileList list of files from all packages.
2705  * We pass it to a script which does the work of finding missing
2706  * and duplicated files.
2707  */
2708 
2709  if (res == 0) {
2710  if (checkFiles(check_fileList) > 0)
2711  res = 1;
2712  }
2713 
2714  check_fileList = freeStringBuf(check_fileList);
2715 
2716  return res;
2717 }
2718 /*@=incondefs@*/