rpm  5.2.1
files.c
Go to the documentation of this file.
1 
7 #include "system.h"
8 
9 #define MYALLPERMS 07777
10 
11 #if defined(WITH_PCRE) && defined(WITH_PCRE_POSIX)
12 #include <pcreposix.h>
13 #else
14 #include <regex.h>
15 #endif
16 
17 #define _RPMIOB_INTERNAL
18 #include <rpmiotypes.h>
19 #include <rpmio_internal.h> /* XXX fdGetFp */
20 #include <rpmcb.h>
21 #include <fts.h>
22 #include <argv.h>
23 
24 #include "iosm.h"
25 #define _RPMTAG_INTERNAL /* XXX rpmTags->aTags */
26 #define _RPMFI_INTERNAL
27 #include <rpmbuild.h>
28 
29 #define _RPMTE_INTERNAL
30 #include <rpmte.h>
31 
32 #include "rpmfc.h"
33 
34 #include "buildio.h"
35 
36 #include "legacy.h" /* XXX dodigest */
37 #include "debug.h"
38 
39 /*@access Header @*/
40 /*@access rpmfi @*/
41 /*@access rpmte @*/
42 /*@access FD_t @*/
43 
44 #define SKIPWHITE(_x) {while(*(_x) && (xisspace(*_x) || *(_x) == ',')) (_x)++;}
45 #define SKIPNONWHITE(_x){while(*(_x) &&!(xisspace(*_x) || *(_x) == ',')) (_x)++;}
46 
47 #define MAXDOCDIR 1024
48 
51 typedef enum specdFlags_e {
52  SPECD_DEFFILEMODE = (1 << 0),
53  SPECD_DEFDIRMODE = (1 << 1),
54  SPECD_DEFUID = (1 << 2),
55  SPECD_DEFGID = (1 << 3),
56  SPECD_DEFVERIFY = (1 << 4),
57 
58  SPECD_FILEMODE = (1 << 8),
59  SPECD_DIRMODE = (1 << 9),
60  SPECD_UID = (1 << 10),
61  SPECD_GID = (1 << 11),
62  SPECD_VERIFY = (1 << 12)
63 } specdFlags;
64 
67 typedef struct FileListRec_s {
68  struct stat fl_st;
69 #define fl_dev fl_st.st_dev
70 #define fl_ino fl_st.st_ino
71 #define fl_mode fl_st.st_mode
72 #define fl_nlink fl_st.st_nlink
73 #define fl_uid fl_st.st_uid
74 #define fl_gid fl_st.st_gid
75 #define fl_rdev fl_st.st_rdev
76 #define fl_size fl_st.st_size
77 #define fl_mtime fl_st.st_mtime
78 
79 /*@only@*/
80  const char *diskURL; /* get file from here */
81 /*@only@*/
82  const char *fileURL; /* filename in cpio archive */
83 /*@observer@*/
84  const char *uname;
85 /*@observer@*/
86  const char *gname;
87  unsigned flags;
88  specdFlags specdFlags; /* which attributes have been explicitly specified. */
89  unsigned verifyFlags;
90 /*@only@*/
91  const char *langs; /* XXX locales separated with | */
92 } * FileListRec;
93 
96 typedef struct AttrRec_s {
97 /*@null@*/
98  const char *ar_fmodestr;
99 /*@null@*/
100  const char *ar_dmodestr;
101 /*@null@*/
102  const char *ar_user;
103 /*@null@*/
104  const char *ar_group;
105  mode_t ar_fmode;
106  mode_t ar_dmode;
107 } * AttrRec;
108 
109 /*@-readonlytrans@*/
110 /*@unchecked@*/ /*@observer@*/
111 static struct AttrRec_s root_ar = { NULL, NULL, "root", "root", 0, 0 };
112 /*@=readonlytrans@*/
113 
117 typedef struct FileList_s {
118 /*@only@*/
119  const char * buildRootURL;
120 /*@only@*/
121  const char * prefix;
122 
126 
129 
130  int noGlob;
131  unsigned devtype;
132  unsigned devmajor;
133  int devminor;
134 
135  int isDir;
136  int inFtw;
144  int nLangs;
145 /*@only@*/ /*@null@*/
146  const char ** currentLangs;
147 
148  /* Hard coded limit of MAXDOCDIR docdirs. */
149  /* If you break it you are doing something wrong. */
150  const char * docDirs[MAXDOCDIR];
152 
153 /*@only@*/
157 } * FileList;
158 
161 static void nullAttrRec(/*@out@*/ AttrRec ar) /*@modifies ar @*/
162 {
163  ar->ar_fmodestr = NULL;
164  ar->ar_dmodestr = NULL;
165  ar->ar_user = NULL;
166  ar->ar_group = NULL;
167  ar->ar_fmode = 0;
168  ar->ar_dmode = 0;
169 }
170 
173 static void freeAttrRec(AttrRec ar) /*@modifies ar @*/
174 {
175  ar->ar_fmodestr = _free(ar->ar_fmodestr);
176  ar->ar_dmodestr = _free(ar->ar_dmodestr);
177  ar->ar_user = _free(ar->ar_user);
178  ar->ar_group = _free(ar->ar_group);
179  /* XXX doesn't free ar (yet) */
180  /*@-nullstate@*/
181  return;
182  /*@=nullstate@*/
183 }
184 
187 static void dupAttrRec(const AttrRec oar, /*@in@*/ /*@out@*/ AttrRec nar)
188  /*@modifies nar @*/
189 {
190  if (oar == nar)
191  return;
192  freeAttrRec(nar);
193  nar->ar_fmodestr = (oar->ar_fmodestr ? xstrdup(oar->ar_fmodestr) : NULL);
194  nar->ar_dmodestr = (oar->ar_dmodestr ? xstrdup(oar->ar_dmodestr) : NULL);
195  nar->ar_user = (oar->ar_user ? xstrdup(oar->ar_user) : NULL);
196  nar->ar_group = (oar->ar_group ? xstrdup(oar->ar_group) : NULL);
197  nar->ar_fmode = oar->ar_fmode;
198  nar->ar_dmode = oar->ar_dmode;
199 }
200 
201 #if 0
202 
204 static void dumpAttrRec(const char * msg, AttrRec ar)
205  /*@globals fileSystem@*/
206  /*@modifies fileSystem @*/
207 {
208  if (msg)
209  fprintf(stderr, "%s:\t", msg);
210  fprintf(stderr, "(%s, %s, %s, %s)\n",
211  ar->ar_fmodestr,
212  ar->ar_user,
213  ar->ar_group,
214  ar->ar_dmodestr);
215 }
216 #endif
217 
223 /*@null@*/
224 static char *strtokWithQuotes(/*@null@*/ char *s, const char *delim)
225  /*@modifies *s @*/
226 {
227  static char *olds = NULL;
228  char *token;
229 
230  if (s == NULL)
231  s = olds;
232  if (s == NULL)
233  return NULL;
234 
235  /* Skip leading delimiters */
236  s += strspn(s, delim);
237  if (*s == '\0')
238  return NULL;
239 
240  /* Find the end of the token. */
241  token = s;
242  if (*token == '"') {
243  token++;
244  /* Find next " char */
245  s = strchr(token, '"');
246  } else {
247  s = strpbrk(token, delim);
248  }
249 
250  /* Terminate it */
251  if (s == NULL) {
252  /* This token finishes the string */
253  olds = strchr(token, '\0');
254  } else {
255  /* Terminate the token and make olds point past it */
256  *s = '\0';
257  olds = s+1;
258  }
259 
260  /*@-retalias -temptrans @*/
261  return token;
262  /*@=retalias =temptrans @*/
263 }
264 
267 static void timeCheck(int tc, Header h)
268  /*@globals internalState @*/
269  /*@modifies internalState @*/
270 {
271  HE_t he = memset(alloca(sizeof(*he)), 0, sizeof(*he));
272  rpmuint32_t currentTime = (rpmuint32_t) time(NULL);
273  rpmuint32_t * mtime;
274  int xx;
275  size_t i;
276 
277  he->tag = RPMTAG_FILEMTIMES;
278  xx = headerGet(h, he, 0);
279  mtime = he->p.ui32p;
280  he->tag = RPMTAG_OLDFILENAMES;
281  xx = headerGet(h, he, 0);
282 
283  for (i = 0; i < he->c; i++) {
284  xx = currentTime - mtime[i];
285  if (xx < 0) xx = -xx;
286  if (xx > tc)
287  rpmlog(RPMLOG_WARNING, _("TIMECHECK failure: %s\n"), he->p.argv[i]);
288  }
289  he->p.ptr = _free(he->p.ptr);
290  mtime = _free(mtime);
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@*/
305 static VFA_t verifyAttrs[] = {
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 static rpmRC parseForVerify(char * buf, FileList fl)
325  /*@modifies buf, fl->processingFailed,
326  fl->currentVerifyFlags, fl->defVerifyFlags,
327  fl->currentSpecdFlags, fl->defSpecdFlags @*/
328 {
329  char *p, *pe, *q;
330  const char *name;
331  int *resultVerify;
332  int negated;
333  int verifyFlags;
335 
336  if ((p = strstr(buf, (name = "%verify"))) != NULL) {
337  resultVerify = &(fl->currentVerifyFlags);
338  specdFlags = &fl->currentSpecdFlags;
339  } else if ((p = strstr(buf, (name = "%defverify"))) != NULL) {
340  resultVerify = &(fl->defVerifyFlags);
341  specdFlags = &fl->defSpecdFlags;
342  } else
343  return RPMRC_OK;
344 
345  for (pe = p; (size_t)(pe-p) < strlen(name); pe++)
346  *pe = ' ';
347 
348  SKIPSPACE(pe);
349 
350  if (*pe != '(') {
351  rpmlog(RPMLOG_ERR, _("Missing '(' in %s %s\n"), name, pe);
352  fl->processingFailed = 1;
353  return RPMRC_FAIL;
354  }
355 
356  /* Bracket %*verify args */
357  *pe++ = ' ';
358  for (p = pe; *pe && *pe != ')'; pe++)
359  {};
360 
361  if (*pe == '\0') {
362  rpmlog(RPMLOG_ERR, _("Missing ')' in %s(%s\n"), name, p);
363  fl->processingFailed = 1;
364  return RPMRC_FAIL;
365  }
366 
367  /* Localize. Erase parsed string */
368  q = alloca((pe-p) + 1);
369  strncpy(q, p, pe-p);
370  q[pe-p] = '\0';
371  while (p <= pe)
372  *p++ = ' ';
373 
374  negated = 0;
375  verifyFlags = RPMVERIFY_NONE;
376 
377  for (p = q; *p != '\0'; p = pe) {
378  SKIPWHITE(p);
379  if (*p == '\0')
380  break;
381  pe = p;
382  SKIPNONWHITE(pe);
383  if (*pe != '\0')
384  *pe++ = '\0';
385 
386  { VFA_t *vfa;
387  for (vfa = verifyAttrs; vfa->attribute != NULL; vfa++) {
388  if (strcmp(p, vfa->attribute))
389  /*@innercontinue@*/ continue;
390  verifyFlags |= vfa->flag;
391  /*@innerbreak@*/ break;
392  }
393  if (vfa->attribute)
394  continue;
395  }
396 
397  if (!strcmp(p, "not")) {
398  negated ^= 1;
399  } else {
400  rpmlog(RPMLOG_ERR, _("Invalid %s token: %s\n"), name, p);
401  fl->processingFailed = 1;
402  return RPMRC_FAIL;
403  }
404  }
405 
406  *resultVerify = negated ? ~(verifyFlags) : verifyFlags;
407  *specdFlags |= SPECD_VERIFY;
408 
409  return RPMRC_OK;
410 }
411 
412 #define isAttrDefault(_ars) ((_ars)[0] == '-' && (_ars)[1] == '\0')
413 
420 static rpmRC parseForDev(char * buf, FileList fl)
421  /*@modifies buf, fl->processingFailed,
422  fl->noGlob, fl->devtype, fl->devmajor, fl->devminor @*/
423 {
424  const char * name;
425  const char * errstr = NULL;
426  char *p, *pe, *q;
427  rpmRC rc = RPMRC_FAIL; /* assume error */
428 
429  if ((p = strstr(buf, (name = "%dev"))) == NULL)
430  return RPMRC_OK;
431 
432  for (pe = p; (size_t)(pe-p) < strlen(name); pe++)
433  *pe = ' ';
434  SKIPSPACE(pe);
435 
436  if (*pe != '(') {
437  errstr = "'('";
438  goto exit;
439  }
440 
441  /* Bracket %dev args */
442  *pe++ = ' ';
443  for (p = pe; *pe && *pe != ')'; pe++)
444  {};
445  if (*pe != ')') {
446  errstr = "')'";
447  goto exit;
448  }
449 
450  /* Localize. Erase parsed string */
451  q = alloca((pe-p) + 1);
452  strncpy(q, p, pe-p);
453  q[pe-p] = '\0';
454  while (p <= pe)
455  *p++ = ' ';
456 
457  p = q; SKIPWHITE(p);
458  pe = p; SKIPNONWHITE(pe); if (*pe != '\0') *pe++ = '\0';
459  if (*p == 'b')
460  fl->devtype = 'b';
461  else if (*p == 'c')
462  fl->devtype = 'c';
463  else {
464  errstr = "devtype";
465  goto exit;
466  }
467 
468  p = pe; SKIPWHITE(p);
469  pe = p; SKIPNONWHITE(pe); if (*pe != '\0') *pe++ = '\0';
470  for (pe = p; *pe && xisdigit(*pe); pe++)
471  {} ;
472  if (*pe == '\0') {
473  fl->devmajor = atoi(p);
474  /*@-unsignedcompare @*/ /* LCL: ge is ok */
475  if (!((int)fl->devmajor >= 0 && (int)fl->devmajor < 256)) {
476  errstr = "devmajor";
477  goto exit;
478  }
479  /*@=unsignedcompare @*/
480  pe++;
481  } else {
482  errstr = "devmajor";
483  goto exit;
484  }
485 
486  p = pe; SKIPWHITE(p);
487  pe = p; SKIPNONWHITE(pe); if (*pe != '\0') *pe++ = '\0';
488  for (pe = p; *pe && xisdigit(*pe); pe++)
489  {} ;
490  if (*pe == '\0') {
491  fl->devminor = atoi(p);
492  if (!(fl->devminor >= 0 && fl->devminor < 256)) {
493  errstr = "devminor";
494  goto exit;
495  }
496  pe++;
497  } else {
498  errstr = "devminor";
499  goto exit;
500  }
501 
502  fl->noGlob = 1;
503 
504  rc = 0;
505 
506 exit:
507  if (rc) {
508  rpmlog(RPMLOG_ERR, _("Missing %s in %s %s\n"), errstr, name, p);
509  fl->processingFailed = 1;
510  }
511  return rc;
512 }
513 
520 static rpmRC parseForAttr(char * buf, FileList fl)
521  /*@modifies buf, fl->processingFailed,
522  fl->cur_ar, fl->def_ar,
523  fl->currentSpecdFlags, fl->defSpecdFlags @*/
524 {
525  const char *name;
526  char *p, *pe, *q;
527  int x;
528  struct AttrRec_s arbuf;
529  AttrRec ar = &arbuf, ret_ar;
531 
532  if ((p = strstr(buf, (name = "%attr"))) != NULL) {
533  ret_ar = &(fl->cur_ar);
534  specdFlags = &fl->currentSpecdFlags;
535  } else if ((p = strstr(buf, (name = "%defattr"))) != NULL) {
536  ret_ar = &(fl->def_ar);
537  specdFlags = &fl->defSpecdFlags;
538  } else
539  return RPMRC_OK;
540 
541  for (pe = p; (size_t)(pe-p) < strlen(name); pe++)
542  *pe = ' ';
543 
544  SKIPSPACE(pe);
545 
546  if (*pe != '(') {
547  rpmlog(RPMLOG_ERR, _("Missing '(' in %s %s\n"), name, pe);
548  fl->processingFailed = 1;
549  return RPMRC_FAIL;
550  }
551 
552  /* Bracket %*attr args */
553  *pe++ = ' ';
554  for (p = pe; *pe && *pe != ')'; pe++)
555  {};
556 
557  if (ret_ar == &(fl->def_ar)) { /* %defattr */
558  q = pe;
559  q++;
560  SKIPSPACE(q);
561  if (*q != '\0') {
563  _("Non-white space follows %s(): %s\n"), name, q);
564  fl->processingFailed = 1;
565  return RPMRC_FAIL;
566  }
567  }
568 
569  /* Localize. Erase parsed string */
570  q = alloca((pe-p) + 1);
571  strncpy(q, p, pe-p);
572  q[pe-p] = '\0';
573  while (p <= pe)
574  *p++ = ' ';
575 
576  nullAttrRec(ar);
577 
578  p = q; SKIPWHITE(p);
579  if (*p != '\0') {
580  pe = p; SKIPNONWHITE(pe); if (*pe != '\0') *pe++ = '\0';
581  ar->ar_fmodestr = p;
582  p = pe; SKIPWHITE(p);
583  }
584  if (*p != '\0') {
585  pe = p; SKIPNONWHITE(pe); if (*pe != '\0') *pe++ = '\0';
586  ar->ar_user = p;
587  p = pe; SKIPWHITE(p);
588  }
589  if (*p != '\0') {
590  pe = p; SKIPNONWHITE(pe); if (*pe != '\0') *pe++ = '\0';
591  ar->ar_group = p;
592  p = pe; SKIPWHITE(p);
593  }
594  if (*p != '\0' && ret_ar == &(fl->def_ar)) { /* %defattr */
595  pe = p; SKIPNONWHITE(pe); if (*pe != '\0') *pe++ = '\0';
596  ar->ar_dmodestr = p;
597  p = pe; SKIPWHITE(p);
598  }
599 
600  if (!(ar->ar_fmodestr && ar->ar_user && ar->ar_group) || *p != '\0') {
601  rpmlog(RPMLOG_ERR, _("Bad syntax: %s(%s)\n"), name, q);
602  fl->processingFailed = 1;
603  return RPMRC_FAIL;
604  }
605 
606  /* Do a quick test on the mode argument and adjust for "-" */
607  if (ar->ar_fmodestr && !isAttrDefault(ar->ar_fmodestr)) {
608  unsigned int ui;
609  x = sscanf(ar->ar_fmodestr, "%o", &ui);
610  if ((x == 0) || (ar->ar_fmode & ~MYALLPERMS)) {
611  rpmlog(RPMLOG_ERR, _("Bad mode spec: %s(%s)\n"), name, q);
612  fl->processingFailed = 1;
613  return RPMRC_FAIL;
614  }
615  ar->ar_fmode = ui;
616  } else
617  ar->ar_fmodestr = NULL;
618 
619  if (ar->ar_dmodestr && !isAttrDefault(ar->ar_dmodestr)) {
620  unsigned int ui;
621  x = sscanf(ar->ar_dmodestr, "%o", &ui);
622  if ((x == 0) || (ar->ar_dmode & ~MYALLPERMS)) {
623  rpmlog(RPMLOG_ERR, _("Bad dirmode spec: %s(%s)\n"), name, q);
624  fl->processingFailed = 1;
625  return RPMRC_FAIL;
626  }
627  ar->ar_dmode = ui;
628  } else
629  ar->ar_dmodestr = NULL;
630 
631  if (!(ar->ar_user && !isAttrDefault(ar->ar_user)))
632  ar->ar_user = NULL;
633 
634  if (!(ar->ar_group && !isAttrDefault(ar->ar_group)))
635  ar->ar_group = NULL;
636 
637  dupAttrRec(ar, ret_ar);
638 
639  /* XXX fix all this */
640  *specdFlags |= SPECD_UID | SPECD_GID | SPECD_FILEMODE | SPECD_DIRMODE;
641 
642  return RPMRC_OK;
643 }
644 
651 static rpmRC parseForConfig(char * buf, FileList fl)
652  /*@modifies buf, fl->processingFailed, fl->currentFlags @*/
653 {
654  char *p, *pe, *q;
655  const char *name;
656 
657  if ((p = strstr(buf, (name = "%config"))) == NULL)
658  return RPMRC_OK;
659 
661 
662  /* Erase "%config" token. */
663  for (pe = p; (size_t)(pe-p) < strlen(name); pe++)
664  *pe = ' ';
665  SKIPSPACE(pe);
666  if (*pe != '(')
667  return RPMRC_OK;
668 
669  /* Bracket %config args */
670  *pe++ = ' ';
671  for (p = pe; *pe && *pe != ')'; pe++)
672  {};
673 
674  if (*pe == '\0') {
675  rpmlog(RPMLOG_ERR, _("Missing ')' in %s(%s\n"), name, p);
676  fl->processingFailed = 1;
677  return RPMRC_FAIL;
678  }
679 
680  /* Localize. Erase parsed string. */
681  q = alloca((pe-p) + 1);
682  strncpy(q, p, pe-p);
683  q[pe-p] = '\0';
684  while (p <= pe)
685  *p++ = ' ';
686 
687  for (p = q; *p != '\0'; p = pe) {
688  SKIPWHITE(p);
689  if (*p == '\0')
690  break;
691  pe = p;
692  SKIPNONWHITE(pe);
693  if (*pe != '\0')
694  *pe++ = '\0';
695  if (!strcmp(p, "missingok")) {
697  } else if (!strcmp(p, "noreplace")) {
699  } else {
700  rpmlog(RPMLOG_ERR, _("Invalid %s token: %s\n"), name, p);
701  fl->processingFailed = 1;
702  return RPMRC_FAIL;
703  }
704  }
705 
706  return RPMRC_OK;
707 }
708 
711 static int langCmp(const void * ap, const void * bp)
712  /*@*/
713 {
714  return strcmp(*(const char **)ap, *(const char **)bp);
715 }
716 
723 static rpmRC parseForLang(char * buf, FileList fl)
724  /*@modifies buf, fl->processingFailed,
725  fl->currentLangs, fl->nLangs @*/
726 {
727  char *p, *pe, *q;
728  const char *name;
729 
730  while ((p = strstr(buf, (name = "%lang"))) != NULL) {
731 
732  for (pe = p; (size_t)(pe-p) < strlen(name); pe++)
733  *pe = ' ';
734  SKIPSPACE(pe);
735 
736  if (*pe != '(') {
737  rpmlog(RPMLOG_ERR, _("Missing '(' in %s %s\n"), name, pe);
738  fl->processingFailed = 1;
739  return RPMRC_FAIL;
740  }
741 
742  /* Bracket %lang args */
743  *pe++ = ' ';
744  for (pe = p; *pe && *pe != ')'; pe++)
745  {};
746 
747  if (*pe == '\0') {
748  rpmlog(RPMLOG_ERR, _("Missing ')' in %s(%s\n"), name, p);
749  fl->processingFailed = 1;
750  return RPMRC_FAIL;
751  }
752 
753  /* Localize. Erase parsed string. */
754  q = alloca((pe-p) + 1);
755  strncpy(q, p, pe-p);
756  q[pe-p] = '\0';
757  while (p <= pe)
758  *p++ = ' ';
759 
760  /* Parse multiple arguments from %lang */
761  for (p = q; *p != '\0'; p = pe) {
762  char *newp;
763  size_t np;
764  int i;
765 
766  SKIPWHITE(p);
767  pe = p;
768  SKIPNONWHITE(pe);
769 
770  np = pe - p;
771 
772  /* Sanity check on locale lengths */
773  if (np < 1 || (np == 1 && *p != 'C') || np >= 32) {
775  _("Unusual locale length: \"%.*s\" in %%lang(%s)\n"),
776  (int)np, p, q);
777  fl->processingFailed = 1;
778  return RPMRC_FAIL;
779  }
780 
781  /* Check for duplicate locales */
782  if (fl->currentLangs != NULL)
783  for (i = 0; i < fl->nLangs; i++) {
784  if (strncmp(fl->currentLangs[i], p, np))
785  /*@innercontinue@*/ continue;
786  rpmlog(RPMLOG_ERR, _("Duplicate locale %.*s in %%lang(%s)\n"),
787  (int)np, p, q);
788  fl->processingFailed = 1;
789  return RPMRC_FAIL;
790  }
791 
792  /* Add new locale */
794  (fl->nLangs + 1) * sizeof(*fl->currentLangs));
795  newp = xmalloc( np+1 );
796  strncpy(newp, p, np);
797  newp[np] = '\0';
798  fl->currentLangs[fl->nLangs++] = newp;
799  if (*pe == ',') pe++; /* skip , if present */
800  }
801  }
802 
803  /* Insure that locales are sorted. */
804  if (fl->currentLangs)
805  qsort(fl->currentLangs, fl->nLangs, sizeof(*fl->currentLangs), langCmp);
806 
807  return RPMRC_OK;
808 }
809 
812 static int parseForRegexLang(const char * fileName, /*@out@*/ char ** lang)
813  /*@globals rpmGlobalMacroContext, h_errno, internalState @*/
814  /*@modifies *lang, rpmGlobalMacroContext, internalState @*/
815 {
816  static int initialized = 0;
817  static int hasRegex = 0;
818  static regex_t compiledPatt;
819  static char buf[BUFSIZ];
820  int x;
821  regmatch_t matches[2];
822  const char *s;
823 
824  if (! initialized) {
825  const char *patt = rpmExpand("%{?_langpatt}", NULL);
826  int rc = 0;
827  if (!(patt && *patt != '\0'))
828  rc = 1;
829  else if (regcomp(&compiledPatt, patt, REG_EXTENDED))
830  rc = -1;
831  patt = _free(patt);
832  if (rc)
833  return rc;
834  hasRegex = 1;
835  initialized = 1;
836  }
837 
838  memset(matches, 0, sizeof(matches));
839  if (! hasRegex || regexec(&compiledPatt, fileName, 2, matches, REG_NOTEOL))
840  return 1;
841 
842  /* Got match */
843  s = fileName + matches[1].rm_eo - 1;
844  x = (int)matches[1].rm_eo - (int)matches[1].rm_so;
845  buf[x] = '\0';
846  while (x) {
847  buf[--x] = *s--;
848  }
849  if (lang)
850  *lang = buf;
851  return 0;
852 }
853 
856 /*@-exportlocal -exportheadervar@*/
857 /*@unchecked@*/
859  { "%dir", 0, 0 }, /* XXX why not RPMFILE_DIR? */
860  { "%doc", 0, RPMFILE_DOC },
861  { "%ghost", 0, RPMFILE_GHOST },
862  { "%exclude", 0, RPMFILE_EXCLUDE },
863  { "%readme", 0, RPMFILE_README },
864  { "%license", 0, RPMFILE_LICENSE },
865  { "%pubkey", 0, RPMFILE_PUBKEY },
866  { "%policy", 0, RPMFILE_POLICY },
867  { "%optional", 0, RPMFILE_OPTIONAL },
868  { "%remove", 0, RPMFILE_REMOVE },
869 
870 #if WHY_NOT
871  { "%icon", 0, RPMFILE_ICON },
872  { "%spec", 0, RPMFILE_SPEC },
873  { "%config", 0, RPMFILE_CONFIG },
874  { "%missingok", 0, RPMFILE_CONFIG|RPMFILE_MISSINGOK },
875  { "%noreplace", 0, RPMFILE_CONFIG|RPMFILE_NOREPLACE },
876 #endif
877 
878  { NULL, 0, 0 }
879 };
880 /*@=exportlocal =exportheadervar@*/
881 
891 static rpmRC parseForSimple(/*@unused@*/ Spec spec, Package pkg,
892  char * buf, FileList fl, /*@out@*/ const char ** fileName)
893  /*@globals rpmGlobalMacroContext, h_errno, internalState @*/
894  /*@modifies buf, fl->processingFailed, *fileName,
895  fl->currentFlags,
896  fl->docDirs, fl->docDirCount, fl->isDir,
897  fl->passedSpecialDoc, fl->isSpecialDoc,
898  pkg->header, pkg->specialDoc,
899  rpmGlobalMacroContext, internalState @*/
900 {
901  char *s, *t;
902  int specialDoc = 0;
903  char specialDocBuf[BUFSIZ];
904  rpmRC res = RPMRC_OK; /* assume success */
905 
906  specialDocBuf[0] = '\0';
907  *fileName = NULL;
908 
909  t = buf;
910  while ((s = strtokWithQuotes(t, " \t\n")) != NULL) {
911  t = NULL;
912  if (!strcmp(s, "%docdir")) {
913  s = strtokWithQuotes(NULL, " \t\n");
914  if (fl->docDirCount == MAXDOCDIR) {
915  rpmlog(RPMLOG_CRIT, _("Hit limit for %%docdir\n"));
916  fl->processingFailed = 1;
917  res = RPMRC_FAIL;
918  }
919 
920  if (s != NULL)
921  fl->docDirs[fl->docDirCount++] = xstrdup(s);
922  if (s == NULL || strtokWithQuotes(NULL, " \t\n")) {
923  rpmlog(RPMLOG_CRIT, _("Only one arg for %%docdir\n"));
924  fl->processingFailed = 1;
925  res = RPMRC_FAIL;
926  }
927  break;
928  }
929 #if defined(__LCLINT__)
930  assert(s != NULL);
931 #endif
932 
933  /* Set flags for virtual file attributes */
934  { VFA_t *vfa;
935  for (vfa = virtualFileAttributes; vfa->attribute != NULL; vfa++) {
936  if (strcmp(s, vfa->attribute))
937  /*@innercontinue@*/ continue;
938  if (!vfa->flag) {
939  if (!strcmp(s, "%dir"))
940  fl->isDir = 1; /* XXX why not RPMFILE_DIR? */
941  } else {
942  if (vfa->not)
943  fl->currentFlags &= ~vfa->flag;
944  else
945  fl->currentFlags |= vfa->flag;
946  }
947 
948  /*@innerbreak@*/ break;
949  }
950  /* if we got an attribute, continue with next token */
951  if (vfa->attribute != NULL)
952  continue;
953  }
954 
955  if (*fileName) {
956  /* We already got a file -- error */
957  rpmlog(RPMLOG_ERR, _("Two files on one line: %s\n"),
958  *fileName);
959  fl->processingFailed = 1;
960  res = RPMRC_FAIL;
961  }
962 
963  if (*s != '/') {
964  if (fl->currentFlags & RPMFILE_DOC) {
965  specialDoc = 1;
966  strcat(specialDocBuf, " ");
967  strcat(specialDocBuf, s);
968  } else
970  {
971  *fileName = s;
972  } else {
973  const char * sfn = NULL;
974  int urltype = urlPath(s, &sfn);
975  switch (urltype) {
976  default: /* relative path, not in %doc and not a URL */
978  _("File must begin with \"/\": %s\n"), s);
979  fl->processingFailed = 1;
980  res = RPMRC_FAIL;
981  /*@switchbreak@*/ break;
982  case URL_IS_PATH:
983  *fileName = s;
984  /*@switchbreak@*/ break;
985  }
986  }
987  } else {
988  *fileName = s;
989  }
990  }
991 
992  if (specialDoc) {
993  if (*fileName || (fl->currentFlags & ~(RPMFILE_DOC))) {
995  _("Can't mix special %%doc with other forms: %s\n"),
996  (*fileName ? *fileName : ""));
997  fl->processingFailed = 1;
998  res = RPMRC_FAIL;
999  } else {
1000  /* XXX WATCHOUT: buf is an arg */
1001  {
1002  /*@only@*/
1003  static char *_docdir_fmt = NULL;
1004  static int oneshot = 0;
1005  const char *ddir, *fmt, *errstr;
1006  if (!oneshot) {
1007  _docdir_fmt = rpmExpand("%{?_docdir_fmt}", NULL);
1008  if (!(_docdir_fmt && *_docdir_fmt))
1009  _docdir_fmt = _free(_docdir_fmt);
1010  oneshot = 1;
1011  }
1012  if (_docdir_fmt == NULL)
1013  _docdir_fmt = xstrdup("%{NAME}-%{VERSION}");
1014  fmt = headerSprintf(pkg->header, _docdir_fmt, NULL, rpmHeaderFormats, &errstr);
1015  if (fmt == NULL) {
1016  rpmlog(RPMLOG_ERR, _("illegal _docdir_fmt: %s\n"), errstr);
1017  fl->processingFailed = 1;
1018  res = RPMRC_FAIL;
1019  } else {
1020  ddir = rpmGetPath("%{_docdir}/", fmt, NULL);
1021  strcpy(buf, ddir);
1022  ddir = _free(ddir);
1023  fmt = _free(fmt);
1024  }
1025  }
1026 
1027  /* XXX FIXME: this is easy to do as macro expansion */
1028 
1029  if (! fl->passedSpecialDoc) {
1030  char *compress_doc;
1031  char *mkdir_p;
1032 
1033  pkg->specialDoc = rpmiobNew(0);
1034  pkg->specialDoc = rpmiobAppend(pkg->specialDoc, "DOCDIR=\"$RPM_BUILD_ROOT\"", 0);
1035  pkg->specialDoc = rpmiobAppend(pkg->specialDoc, buf, 1);
1036  pkg->specialDoc = rpmiobAppend(pkg->specialDoc, "export DOCDIR", 1);
1037  mkdir_p = rpmExpand("%{?__mkdir_p}%{!?__mkdir_p:mkdir -p}", NULL);
1038  if (!mkdir_p)
1039  mkdir_p = xstrdup("mkdir -p");
1040  pkg->specialDoc = rpmiobAppend(pkg->specialDoc, mkdir_p, 0);
1041  mkdir_p = _free(mkdir_p);
1042  pkg->specialDoc = rpmiobAppend(pkg->specialDoc, " \"$DOCDIR\"", 1);
1043 
1044  compress_doc = rpmExpand("%{__compress_doc}", NULL);
1045  if (compress_doc && *compress_doc != '%')
1046  pkg->specialDoc = rpmiobAppend(pkg->specialDoc, compress_doc, 1);
1047  compress_doc = _free(compress_doc);
1048 
1049  /*@-temptrans@*/
1050  *fileName = buf;
1051  /*@=temptrans@*/
1052  fl->passedSpecialDoc = 1;
1053  fl->isSpecialDoc = 1;
1054  }
1055 
1056  pkg->specialDoc = rpmiobAppend(pkg->specialDoc, "cp -pr ", 0);
1057  pkg->specialDoc = rpmiobAppend(pkg->specialDoc, specialDocBuf, 0);
1058  pkg->specialDoc = rpmiobAppend(pkg->specialDoc, " \"$DOCDIR\"", 1);
1059  }
1060  }
1061 
1062  return res;
1063 }
1064 
1067 static int compareFileListRecs(const void * ap, const void * bp) /*@*/
1068 {
1069  const char *aurl = ((FileListRec)ap)->fileURL;
1070  const char *a = NULL;
1071  const char *burl = ((FileListRec)bp)->fileURL;
1072  const char *b = NULL;
1073  (void) urlPath(aurl, &a);
1074  (void) urlPath(burl, &b);
1075  return strcmp(a, b);
1076 }
1077 
1084 static int isDoc(FileList fl, const char * fileName) /*@*/
1085 {
1086  int x = fl->docDirCount;
1087  size_t k, l;
1088 
1089  k = strlen(fileName);
1090  while (x--) {
1091  l = strlen(fl->docDirs[x]);
1092  if (l < k && strncmp(fileName, fl->docDirs[x], l) == 0 && fileName[l] == '/')
1093  return 1;
1094  }
1095  return 0;
1096 }
1097 
1104 static int checkHardLinks(FileList fl)
1105  /*@*/
1106 {
1107  FileListRec ilp, jlp;
1108  int i, j;
1109 
1110  for (i = 0; i < fl->fileListRecsUsed; i++) {
1111  ilp = fl->fileList + i;
1112  if (!(S_ISREG(ilp->fl_mode) && ilp->fl_nlink > 1))
1113  continue;
1114  if (ilp->flags & (RPMFILE_EXCLUDE | RPMFILE_GHOST))
1115  continue;
1116 
1117  for (j = i + 1; j < fl->fileListRecsUsed; j++) {
1118  jlp = fl->fileList + j;
1119  if (!S_ISREG(jlp->fl_mode))
1120  /*@innercontinue@*/ continue;
1121  if (ilp->fl_nlink != jlp->fl_nlink)
1122  /*@innercontinue@*/ continue;
1123  if (ilp->fl_ino != jlp->fl_ino)
1124  /*@innercontinue@*/ continue;
1125  if (ilp->fl_dev != jlp->fl_dev)
1126  /*@innercontinue@*/ continue;
1127  if (jlp->flags & (RPMFILE_EXCLUDE | RPMFILE_GHOST))
1128  /*@innercontinue@*/ continue;
1129  return 1;
1130  }
1131  }
1132  return 0;
1133 }
1134 
1135 static int dncmp(const void * a, const void * b)
1136  /*@*/
1137 {
1138  const char ** aurlp = (const char **)a;
1139  const char ** burlp = (const char **)b;
1140  const char * adn;
1141  const char * bdn;
1142  (void) urlPath(*aurlp, &adn);
1143  (void) urlPath(*burlp, &bdn);
1144  return strcmp(adn, bdn);
1145 }
1146 
1151 static void compressFilelist(Header h)
1152  /*@globals internalState @*/
1153  /*@modifies h, internalState @*/
1154 {
1155  HE_t he = memset(alloca(sizeof(*he)), 0, sizeof(*he));
1156  const char ** fileNames;
1157  const char * fn;
1158  const char ** dirNames;
1159  const char ** baseNames;
1160  rpmuint32_t * dirIndexes;
1161  int count;
1162  int dirIndex = -1;
1163  int xx;
1164  int i;
1165 
1166  /*
1167  * This assumes the file list is already sorted, and begins with a
1168  * single '/'. That assumption isn't critical, but it makes things go
1169  * a bit faster.
1170  */
1171 
1172  if (headerIsEntry(h, RPMTAG_DIRNAMES)) {
1173  he->tag = RPMTAG_OLDFILENAMES;
1174  xx = headerDel(h, he, 0);
1175  return; /* Already converted. */
1176  }
1177 
1178  he->tag = RPMTAG_OLDFILENAMES;
1179  xx = headerGet(h, he, 0);
1180  fileNames = he->p.argv;
1181  count = he->c;
1182  if (!xx || fileNames == NULL || count <= 0)
1183  return; /* no file list */
1184 
1185  dirNames = alloca(sizeof(*dirNames) * count); /* worst case */
1186  baseNames = alloca(sizeof(*dirNames) * count);
1187  dirIndexes = alloca(sizeof(*dirIndexes) * count);
1188 
1189  (void) urlPath(fileNames[0], &fn);
1190  if (fn[0] != '/') {
1191  /* HACK. Source RPM, so just do things differently */
1192  dirIndex = 0;
1193  dirNames[dirIndex] = "";
1194  for (i = 0; i < count; i++) {
1195  dirIndexes[i] = dirIndex;
1196  baseNames[i] = fileNames[i];
1197  }
1198  goto exit;
1199  }
1200 
1201  for (i = 0; i < count; i++) {
1202  const char ** needle;
1203  char savechar;
1204  char * baseName;
1205  size_t len;
1206 
1207  if (fileNames[i] == NULL) /* XXX can't happen */
1208  continue;
1209  baseName = strrchr(fileNames[i], '/') + 1;
1210  len = baseName - fileNames[i];
1211  needle = dirNames;
1212  savechar = *baseName;
1213  *baseName = '\0';
1214 /*@-compdef@*/
1215  if (dirIndex < 0 ||
1216  (needle = bsearch(&fileNames[i], dirNames, dirIndex + 1, sizeof(dirNames[0]), dncmp)) == NULL) {
1217  char *s = alloca(len + 1);
1218  memcpy(s, fileNames[i], len + 1);
1219  s[len] = '\0';
1220  dirIndexes[i] = ++dirIndex;
1221  dirNames[dirIndex] = s;
1222  } else
1223  dirIndexes[i] = needle - dirNames;
1224 /*@=compdef@*/
1225 
1226  *baseName = savechar;
1227  baseNames[i] = baseName;
1228  }
1229 
1230 exit:
1231  if (count > 0) {
1232  he->tag = RPMTAG_DIRINDEXES;
1233  he->t = RPM_UINT32_TYPE;
1234  he->p.ui32p = dirIndexes;
1235  he->c = count;
1236  xx = headerPut(h, he, 0);
1237 
1238  he->tag = RPMTAG_BASENAMES;
1239  he->t = RPM_STRING_ARRAY_TYPE;
1240  he->p.argv = baseNames;
1241  he->c = count;
1242  xx = headerPut(h, he, 0);
1243 
1244  he->tag = RPMTAG_DIRNAMES;
1245  he->t = RPM_STRING_ARRAY_TYPE;
1246  he->p.argv = dirNames;
1247  he->c = dirIndex + 1;
1248  xx = headerPut(h, he, 0);
1249  }
1250 
1251  fileNames = _free(fileNames);
1252 
1253  he->tag = RPMTAG_OLDFILENAMES;
1254  xx = headerDel(h, he, 0);
1255 }
1256 
1257 static rpmuint32_t getDigestAlgo(Header h, int isSrc)
1258  /*@modifies h @*/
1259 {
1260  HE_t he = memset(alloca(sizeof(*he)), 0, sizeof(*he));
1261  static rpmuint32_t source_file_dalgo = 0;
1262  static rpmuint32_t binary_file_dalgo = 0;
1263  static int oneshot = 0;
1264  rpmuint32_t dalgo = 0;
1265  int xx;
1266 
1267  if (!oneshot) {
1268  source_file_dalgo =
1269  rpmExpandNumeric("%{?_build_source_file_digest_algo}");
1270  binary_file_dalgo =
1271  rpmExpandNumeric("%{?_build_binary_file_digest_algo}");
1272  oneshot++;
1273  }
1274 
1275  dalgo = (isSrc ? source_file_dalgo : binary_file_dalgo);
1276  switch (dalgo) {
1277  case PGPHASHALGO_SHA1:
1278  case PGPHASHALGO_MD2:
1279  case PGPHASHALGO_SHA256:
1280  case PGPHASHALGO_SHA384:
1281  case PGPHASHALGO_SHA512:
1282  (void) rpmlibNeedsFeature(h, "FileDigests", "4.6.0-1");
1283  he->tag = RPMTAG_FILEDIGESTALGO;
1284  he->t = RPM_UINT32_TYPE;
1285  he->p.ui32p = &dalgo;
1286  he->c = 1;
1287  xx = headerPut(h, he, 0);
1288  /*@fallthgrough@*/
1289  case PGPHASHALGO_RIPEMD160:
1290  case PGPHASHALGO_TIGER192:
1291  case PGPHASHALGO_MD4:
1292  case PGPHASHALGO_RIPEMD128:
1293  case PGPHASHALGO_CRC32:
1294  case PGPHASHALGO_ADLER32:
1295  case PGPHASHALGO_CRC64:
1296  (void) rpmlibNeedsFeature(h, "FileDigestParameterized", "4.4.6-1");
1297  /*@switchbreak@*/ break;
1298  case PGPHASHALGO_MD5:
1299  case PGPHASHALGO_HAVAL_5_160: /* XXX unimplemented */
1300  default:
1301  dalgo = PGPHASHALGO_MD5;
1302  /*@switchbreak@*/ break;
1303  }
1304 
1305  return dalgo;
1306 }
1307 
1317 static void genCpioListAndHeader(/*@partial@*/ FileList fl,
1318  rpmfi * fip, Header h, int isSrc)
1319  /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/
1320  /*@modifies h, *fip, fl->processingFailed, fl->fileList,
1321  fl->totalFileSize,
1322  rpmGlobalMacroContext, fileSystem, internalState @*/
1323 {
1324  HE_t he = memset(alloca(sizeof(*he)), 0, sizeof(*he));
1325  const char * apath;
1326  rpmuint16_t ui16;
1327  rpmuint32_t ui32;
1328  int _addDotSlash = !isSrc;
1329  int apathlen = 0;
1330  int dpathlen = 0;
1331  int skipLen = 0;
1332  security_context_t scon = NULL;
1333  const char * sxfn;
1334  FileListRec flp;
1335  rpmuint32_t dalgo = getDigestAlgo(h, isSrc);
1336  char buf[BUFSIZ];
1337  int i, xx;
1338 
1339  /* Sort the big list */
1340  qsort(fl->fileList, fl->fileListRecsUsed,
1341  sizeof(*(fl->fileList)), compareFileListRecs);
1342 
1343  /* Generate the header. */
1344  if (! isSrc) {
1345  skipLen = 1;
1346  if (fl->prefix)
1347  skipLen += strlen(fl->prefix);
1348  }
1349 
1350  sxfn = rpmGetPath("%{?_build_file_context_path}", NULL);
1351 /*@-moduncon@*/
1352  if (sxfn != NULL && *sxfn != '\0')
1353  xx = matchpathcon_init(sxfn);
1354 /*@=moduncon@*/
1355 
1356  for (i = 0, flp = fl->fileList; i < fl->fileListRecsUsed; i++, flp++) {
1357  const char *s;
1358 
1359  /* Merge duplicate entries. */
1360  while (i < (fl->fileListRecsUsed - 1) &&
1361  !strcmp(flp->fileURL, flp[1].fileURL)) {
1362 
1363  /* Two entries for the same file found, merge the entries. */
1364  /* Note that an %exclude is a duplication of a file reference */
1365 
1366  /* file flags */
1367  flp[1].flags |= flp->flags;
1368 
1369  if (!(flp[1].flags & RPMFILE_EXCLUDE))
1370  rpmlog(RPMLOG_WARNING, _("File listed twice: %s\n"),
1371  flp->fileURL);
1372 
1373  /* file mode */
1374  if (S_ISDIR(flp->fl_mode)) {
1375  if ((flp[1].specdFlags & (SPECD_DIRMODE | SPECD_DEFDIRMODE)) <
1377  flp[1].fl_mode = flp->fl_mode;
1378  } else {
1379  if ((flp[1].specdFlags & (SPECD_FILEMODE | SPECD_DEFFILEMODE)) <
1381  flp[1].fl_mode = flp->fl_mode;
1382  }
1383 
1384  /* uid */
1385  if ((flp[1].specdFlags & (SPECD_UID | SPECD_DEFUID)) <
1386  (flp->specdFlags & (SPECD_UID | SPECD_DEFUID)))
1387  {
1388  flp[1].fl_uid = flp->fl_uid;
1389  flp[1].uname = flp->uname;
1390  }
1391 
1392  /* gid */
1393  if ((flp[1].specdFlags & (SPECD_GID | SPECD_DEFGID)) <
1394  (flp->specdFlags & (SPECD_GID | SPECD_DEFGID)))
1395  {
1396  flp[1].fl_gid = flp->fl_gid;
1397  flp[1].gname = flp->gname;
1398  }
1399 
1400  /* verify flags */
1401  if ((flp[1].specdFlags & (SPECD_VERIFY | SPECD_DEFVERIFY)) <
1403  flp[1].verifyFlags = flp->verifyFlags;
1404 
1405  /* XXX to-do: language */
1406 
1407  flp++; i++;
1408  }
1409 
1410  /* Skip files that were marked with %exclude. */
1411  if (flp->flags & RPMFILE_EXCLUDE) continue;
1412 
1413  /* Omit '/' and/or URL prefix, leave room for "./" prefix */
1414  (void) urlPath(flp->fileURL, &apath);
1415  apathlen += (strlen(apath) - skipLen + (_addDotSlash ? 3 : 1));
1416 
1417  /* Leave room for both dirname and basename NUL's */
1418  dpathlen += (strlen(flp->diskURL) + 2);
1419 
1420  /*
1421  * Make the header, the OLDFILENAMES will get converted to a
1422  * compressed file list write before we write the actual package to
1423  * disk.
1424  */
1425  he->tag = RPMTAG_OLDFILENAMES;
1426  he->t = RPM_STRING_ARRAY_TYPE;
1427  he->p.argv = &flp->fileURL;
1428  he->c = 1;
1429  he->append = 1;
1430  xx = headerPut(h, he, 0);
1431  he->append = 0;
1432 
1433 /*@-sizeoftype@*/
1434  ui32 = (rpmuint32_t) flp->fl_size;
1435  he->tag = RPMTAG_FILESIZES;
1436  he->t = RPM_UINT32_TYPE;
1437  he->p.ui32p = &ui32;
1438  he->c = 1;
1439  he->append = 1;
1440  xx = headerPut(h, he, 0);
1441  he->append = 0;
1442 
1443  he->tag = RPMTAG_FILEUSERNAME;
1444  he->t = RPM_STRING_ARRAY_TYPE;
1445  he->p.argv = &flp->uname;
1446  he->c = 1;
1447  he->append = 1;
1448  xx = headerPut(h, he, 0);
1449  he->append = 0;
1450 
1451  he->tag = RPMTAG_FILEGROUPNAME;
1452  he->t = RPM_STRING_ARRAY_TYPE;
1453  he->p.argv = &flp->gname;
1454  he->c = 1;
1455  he->append = 1;
1456  xx = headerPut(h, he, 0);
1457  he->append = 0;
1458 
1459  ui32 = (rpmuint32_t) flp->fl_mtime;
1460  he->tag = RPMTAG_FILEMTIMES;
1461  he->t = RPM_UINT32_TYPE;
1462  he->p.ui32p = &ui32;
1463  he->c = 1;
1464  he->append = 1;
1465  xx = headerPut(h, he, 0);
1466  he->append = 0;
1467 
1468  ui16 = (rpmuint16_t)flp->fl_mode;
1469  he->tag = RPMTAG_FILEMODES;
1470  he->t = RPM_UINT16_TYPE;
1471  he->p.ui16p = &ui16;
1472  he->c = 1;
1473  he->append = 1;
1474  xx = headerPut(h, he, 0);
1475  he->append = 0;
1476 
1477  ui16 = (rpmuint16_t) flp->fl_rdev;
1478  he->tag = RPMTAG_FILERDEVS;
1479  he->t = RPM_UINT16_TYPE;
1480  he->p.ui16p = &ui16;
1481  he->c = 1;
1482  he->append = 1;
1483  xx = headerPut(h, he, 0);
1484  he->append = 0;
1485 
1486  ui32 = (rpmuint32_t) flp->fl_dev;
1487  he->tag = RPMTAG_FILEDEVICES;
1488  he->t = RPM_UINT32_TYPE;
1489  he->p.ui32p = &ui32;
1490  he->c = 1;
1491  he->append = 1;
1492  xx = headerPut(h, he, 0);
1493  he->append = 0;
1494 
1495  ui32 = (rpmuint32_t) flp->fl_ino;
1496  he->tag = RPMTAG_FILEINODES;
1497  he->t = RPM_UINT32_TYPE;
1498  he->p.ui32p = &ui32;
1499  he->c = 1;
1500  he->append = 1;
1501  xx = headerPut(h, he, 0);
1502  he->append = 0;
1503 
1504 /*@=sizeoftype@*/
1505 
1506  he->tag = RPMTAG_FILELANGS;
1507  he->t = RPM_STRING_ARRAY_TYPE;
1508  he->p.argv = &flp->langs;
1509  he->c = 1;
1510  he->append = 1;
1511  xx = headerPut(h, he, 0);
1512  he->append = 0;
1513 
1514  buf[0] = '\0';
1515  if (S_ISREG(flp->fl_mode))
1516  (void) dodigest(dalgo, flp->diskURL, (unsigned char *)buf, 1, NULL);
1517  s = buf;
1518 
1519  he->tag = RPMTAG_FILEDIGESTS;
1520  he->t = RPM_STRING_ARRAY_TYPE;
1521  he->p.argv = &s;
1522  he->c = 1;
1523  he->append = 1;
1524  xx = headerPut(h, he, 0);
1525  he->append = 0;
1526 
1527 if (!(_rpmbuildFlags & 4)) {
1528  ui32 = dalgo;
1530  he->t = RPM_UINT32_TYPE;
1531  he->p.ui32p = &ui32;
1532  he->c = 1;
1533  he->append = 1;
1534  xx = headerPut(h, he, 0);
1535  he->append = 0;
1536 }
1537 
1538  buf[0] = '\0';
1539  if (S_ISLNK(flp->fl_mode)) {
1540  xx = Readlink(flp->diskURL, buf, BUFSIZ);
1541  if (xx >= 0)
1542  buf[xx] = '\0';
1543  if (fl->buildRootURL) {
1544  const char * buildRoot;
1545  (void) urlPath(fl->buildRootURL, &buildRoot);
1546 
1547  if (buf[0] == '/' && strcmp(buildRoot, "/") &&
1548  !strncmp(buf, buildRoot, strlen(buildRoot))) {
1550  _("Symlink points to BuildRoot: %s -> %s\n"),
1551  flp->fileURL, buf);
1552  fl->processingFailed = 1;
1553  }
1554  }
1555  }
1556  s = buf;
1557  he->tag = RPMTAG_FILELINKTOS;
1558  he->t = RPM_STRING_ARRAY_TYPE;
1559  he->p.argv = &s;
1560  he->c = 1;
1561  he->append = 1;
1562  xx = headerPut(h, he, 0);
1563  he->append = 0;
1564 
1565  if (flp->flags & RPMFILE_GHOST) {
1568  }
1569  ui32 = flp->verifyFlags;
1571  he->t = RPM_UINT32_TYPE;
1572  he->p.ui32p = &ui32;
1573  he->c = 1;
1574  he->append = 1;
1575  xx = headerPut(h, he, 0);
1576  he->append = 0;
1577 
1578  if (!isSrc && isDoc(fl, flp->fileURL))
1579  flp->flags |= RPMFILE_DOC;
1580  /* XXX Should directories have %doc/%config attributes? (#14531) */
1581  if (S_ISDIR(flp->fl_mode))
1582  flp->flags &= ~(RPMFILE_CONFIG|RPMFILE_DOC);
1583 
1584  ui32 = flp->flags;
1585  he->tag = RPMTAG_FILEFLAGS;
1586  he->t = RPM_UINT32_TYPE;
1587  he->p.ui32p = &ui32;
1588  he->c = 1;
1589  he->append = 1;
1590  xx = headerPut(h, he, 0);
1591  he->append = 0;
1592 
1593  /* Add file security context to package. */
1594 if (!(_rpmbuildFlags & 4) && sxfn != NULL && *sxfn != '\0')
1595  {
1596  static char *nocon = "";
1597 /*@-moduncon@*/
1598  if (matchpathcon(flp->fileURL, flp->fl_mode, &scon) || scon == NULL)
1599  scon = nocon;
1600 /*@=moduncon@*/
1601 
1602  he->tag = RPMTAG_FILECONTEXTS;
1603  he->t = RPM_STRING_ARRAY_TYPE;
1604  he->p.argv = (const char **)&scon; /* XXX NOCAST */
1605  he->c = 1;
1606  he->append = 1;
1607  xx = headerPut(h, he, 0);
1608  he->append = 0;
1609 
1610 /*@-modobserver@*/ /* observer nocon not modified. */
1611  if (scon != nocon) {
1612  freecon(scon);
1613  }
1614 /*@=modobserver@*/
1615  }
1616  }
1617 /*@-moduncon -noeffectuncon @*/
1618  if (sxfn != NULL && *sxfn != '\0') {
1620  }
1621 /*@=moduncon =noeffectuncon @*/
1622  sxfn = _free(sxfn);
1623 
1624 if (_rpmbuildFlags & 4) {
1625 (void) rpmlibNeedsFeature(h, "PayloadFilesHavePrefix", "4.0-1");
1626 (void) rpmlibNeedsFeature(h, "CompressedFileNames", "3.0.4-1");
1627 }
1628 
1629  compressFilelist(h);
1630 
1631  { int scareMem = 0;
1632  void * ts = NULL; /* XXX FIXME drill rpmts ts all the way down here */
1633  rpmfi fi = rpmfiNew(ts, h, RPMTAG_BASENAMES, scareMem);
1634  char * a, * d;
1635 
1636  if (fi == NULL) return; /* XXX can't happen */
1637 
1638 /*@-onlytrans@*/
1639  fi->te = xcalloc(1, sizeof(*((rpmte)fi->te)));
1640 /*@=onlytrans@*/
1641  ((rpmte)fi->te)->type = TR_ADDED;
1642 
1643  fi->dnl = _free(fi->dnl);
1644  fi->bnl = _free(fi->bnl);
1645  if (!scareMem) fi->dil = _free(fi->dil);
1646 
1647  /* XXX Insure at least 1 byte is always allocated. */
1648  fi->dnl = xmalloc(fi->fc * sizeof(*fi->dnl) + dpathlen + 1);
1649  d = (char *)(fi->dnl + fi->fc);
1650  *d = '\0';
1651 
1652  fi->bnl = xmalloc(fi->fc * (sizeof(*fi->bnl) + sizeof(*fi->dil)));
1653 /*@-dependenttrans@*/ /* FIX: artifact of spoofing header tag store */
1654  fi->dil = (!scareMem)
1655  ? xcalloc(sizeof(*fi->dil), fi->fc)
1656  : (rpmuint32_t *)(fi->bnl + fi->fc);
1657 /*@=dependenttrans@*/
1658 
1659  /* XXX Insure at least 1 byte is always allocated. */
1660  fi->apath = xmalloc(fi->fc * sizeof(*fi->apath) + apathlen + 1);
1661  a = (char *)(fi->apath + fi->fc);
1662  *a = '\0';
1663 
1664  fi->actions = _free(fi->actions); /* XXX memory leak */
1665  fi->actions = xcalloc(sizeof(*fi->actions), fi->fc);
1666  fi->fmapflags = xcalloc(sizeof(*fi->fmapflags), fi->fc);
1667  fi->astriplen = 0;
1668  if (fl->buildRootURL)
1669  fi->astriplen = strlen(fl->buildRootURL);
1670  fi->striplen = 0;
1671  fi->fuser = _free(fi->fuser);
1672  fi->fgroup = _free(fi->fgroup);
1673 
1674  /* Make the cpio list */
1675  if (fi->dil != NULL) /* XXX can't happen */
1676  for (i = 0, flp = fl->fileList; (unsigned)i < fi->fc; i++, flp++) {
1677  char * b;
1678 
1679  /* Skip (possible) duplicate file entries, use last entry info. */
1680  while (((flp - fl->fileList) < (fl->fileListRecsUsed - 1)) &&
1681  !strcmp(flp->fileURL, flp[1].fileURL))
1682  flp++;
1683 
1684  if (flp->flags & RPMFILE_EXCLUDE) {
1685  i--;
1686  continue;
1687  }
1688 
1689  {
1690  /* this fi uses diskURL (with buildroot), not fileURL */
1691  size_t fnlen = strlen(flp->diskURL);
1692  if (fnlen > fi->fnlen) {
1693  /* fnlen-sized buffer must not be allocated yet */
1694  assert(fi->fn == NULL);
1695  fi->fnlen = fnlen;
1696  }
1697  }
1698 
1699 
1700  /* Create disk directory and base name. */
1701  fi->dil[i] = i;
1702 /*@-dependenttrans@*/ /* FIX: artifact of spoofing header tag store */
1703  fi->dnl[fi->dil[i]] = d;
1704 /*@=dependenttrans@*/
1705  d = stpcpy(d, flp->diskURL);
1706 
1707  /* Make room for the dirName NUL, find start of baseName. */
1708  for (b = d; b > fi->dnl[fi->dil[i]] && *b != '/'; b--)
1709  b[1] = b[0];
1710  b++; /* dirname's end in '/' */
1711  *b++ = '\0'; /* terminate dirname, b points to basename */
1712  fi->bnl[i] = b;
1713  d += 2; /* skip both dirname and basename NUL's */
1714 
1715  /* Create archive path, normally adding "./" */
1716  /*@-dependenttrans@*/ /* FIX: xstrdup? nah ... */
1717  fi->apath[i] = a;
1718  /*@=dependenttrans@*/
1719  if (_addDotSlash)
1720  a = stpcpy(a, "./");
1721  (void) urlPath(flp->fileURL, &apath);
1722  a = stpcpy(a, (apath + skipLen));
1723  a++; /* skip apath NUL */
1724 
1725  if (flp->flags & RPMFILE_GHOST) {
1726  fi->actions[i] = FA_SKIP;
1727  continue;
1728  }
1729  fi->actions[i] = FA_COPYOUT;
1730  fi->fmapflags[i] = IOSM_MAP_PATH |
1732  if (isSrc)
1733  fi->fmapflags[i] |= IOSM_FOLLOW_SYMLINKS;
1734 
1735  if (S_ISREG(flp->fl_mode)) {
1736  int bingo = 1;
1737  /* Hard links need be tallied only once. */
1738  if (flp->fl_nlink > 1) {
1739  FileListRec jlp = flp + 1;
1740  int j = i + 1;
1741  for (; (unsigned)j < fi->fc; j++, jlp++) {
1742  /* follow outer loop logic */
1743  while (((jlp - fl->fileList) < (fl->fileListRecsUsed - 1)) &&
1744  !strcmp(jlp->fileURL, jlp[1].fileURL))
1745  jlp++;
1746  if (jlp->flags & RPMFILE_EXCLUDE) {
1747  j--;
1748  /*@innercontinue@*/ continue;
1749  }
1750  if (jlp->flags & RPMFILE_GHOST)
1751  /*@innercontinue@*/ continue;
1752  if (!S_ISREG(jlp->fl_mode))
1753  /*@innercontinue@*/ continue;
1754  if (flp->fl_nlink != jlp->fl_nlink)
1755  /*@innercontinue@*/ continue;
1756  if (flp->fl_ino != jlp->fl_ino)
1757  /*@innercontinue@*/ continue;
1758  if (flp->fl_dev != jlp->fl_dev)
1759  /*@innercontinue@*/ continue;
1760  bingo = 0; /* don't tally hardlink yet. */
1761  /*@innerbreak@*/ break;
1762  }
1763  }
1764  if (bingo)
1765  fl->totalFileSize += flp->fl_size;
1766  }
1767  }
1768 
1769  ui32 = fl->totalFileSize;
1770  he->tag = RPMTAG_SIZE;
1771  he->t = RPM_UINT32_TYPE;
1772  he->p.ui32p = &ui32;
1773  he->c = 1;
1774  xx = headerPut(h, he, 0);
1775 
1776  /*@-compdef@*/
1777  if (fip)
1778  *fip = fi;
1779  else
1780  fi = rpmfiFree(fi);
1781  /*@=compdef@*/
1782  }
1783 }
1784 
1787 static /*@null@*/ FileListRec freeFileList(/*@only@*/ FileListRec fileList,
1788  int count)
1789  /*@*/
1790 {
1791  while (count--) {
1792  fileList[count].diskURL = _free(fileList[count].diskURL);
1793  fileList[count].fileURL = _free(fileList[count].fileURL);
1794  fileList[count].langs = _free(fileList[count].langs);
1795  }
1796  fileList = _free(fileList);
1797  return NULL;
1798 }
1799 
1800 /* forward ref */
1801 static rpmRC recurseDir(FileList fl, const char * diskURL)
1802  /*@globals rpmGlobalMacroContext, h_errno,
1803  fileSystem, internalState @*/
1804  /*@modifies *fl, fl->processingFailed,
1805  fl->fileList, fl->fileListRecsAlloced, fl->fileListRecsUsed,
1806  fl->totalFileSize, fl->fileCount, fl->inFtw, fl->isDir,
1807  rpmGlobalMacroContext,
1808  fileSystem, internalState @*/;
1809 
1817 static int addFile(FileList fl, const char * diskURL,
1818  /*@null@*/ struct stat * statp)
1819  /*@globals rpmGlobalMacroContext, h_errno,
1820  fileSystem, internalState @*/
1821  /*@modifies *statp, *fl, fl->processingFailed,
1822  fl->fileList, fl->fileListRecsAlloced, fl->fileListRecsUsed,
1823  fl->totalFileSize, fl->fileCount,
1824  rpmGlobalMacroContext,
1825  fileSystem, internalState @*/
1826 {
1827  const char *fn = xstrdup(diskURL);
1828  const char *fileURL = fn;
1829  struct stat statbuf;
1830  mode_t fileMode;
1831  uid_t fileUid;
1832  gid_t fileGid;
1833  const char *fileUname;
1834  const char *fileGname;
1835  char *lang;
1836  rpmRC rc = RPMRC_OK;
1837 
1838  /* Path may have prepended buildRootURL, so locate the original filename. */
1839  /*
1840  * XXX There are 3 types of entry into addFile:
1841  *
1842  * From diskUrl statp
1843  * =====================================================
1844  * processBinaryFile path NULL
1845  * processBinaryFile glob result path NULL
1846  * recurseDir path stat
1847  *
1848  */
1849  { const char *fileName;
1850  int urltype = urlPath(fileURL, &fileName);
1851  switch (urltype) {
1852  case URL_IS_PATH:
1853  fileURL += (fileName - fileURL);
1854  if (fl->buildRootURL && strcmp(fl->buildRootURL, "/")) {
1855  size_t nb = strlen(fl->buildRootURL);
1856  const char * s = fileURL + nb;
1857  char * t = (char *) fileURL;
1858  (void) memmove(t, s, nb);
1859  }
1860  fileURL = fn;
1861  break;
1862  default:
1863  if (fl->buildRootURL && strcmp(fl->buildRootURL, "/"))
1864  fileURL += strlen(fl->buildRootURL);
1865  break;
1866  }
1867  }
1868 
1869  /* XXX make sure '/' can be packaged also */
1870  if (*fileURL == '\0')
1871  fileURL = "/";
1872 
1873  /* If we are using a prefix, validate the file */
1874  if (!fl->inFtw && fl->prefix) {
1875  const char *prefixTest;
1876  const char *prefixPtr = fl->prefix;
1877 
1878  (void) urlPath(fileURL, &prefixTest);
1879  while (*prefixPtr && *prefixTest && (*prefixTest == *prefixPtr)) {
1880  prefixPtr++;
1881  prefixTest++;
1882  }
1883  if (*prefixPtr || (*prefixTest && *prefixTest != '/')) {
1884  rpmlog(RPMLOG_ERR, _("File doesn't match prefix (%s): %s\n"),
1885  fl->prefix, fileURL);
1886  fl->processingFailed = 1;
1887  rc = RPMRC_FAIL;
1888  goto exit;
1889  }
1890  }
1891 
1892  if (statp == NULL) {
1893  statp = &statbuf;
1894  memset(statp, 0, sizeof(*statp));
1895  if (fl->devtype) {
1896  time_t now = time(NULL);
1897 
1898  /* XXX hack up a stat structure for a %dev(...) directive. */
1899  statp->st_nlink = 1;
1900  statp->st_rdev =
1901  ((fl->devmajor & 0xff) << 8) | (fl->devminor & 0xff);
1902  statp->st_dev = statp->st_rdev;
1903  statp->st_mode = (fl->devtype == 'b' ? S_IFBLK : S_IFCHR);
1904  statp->st_mode |= (fl->cur_ar.ar_fmode & 0777);
1905  statp->st_atime = now;
1906  statp->st_mtime = now;
1907  statp->st_ctime = now;
1908  } else if (Lstat(diskURL, statp)) {
1909  if (fl->currentFlags & RPMFILE_OPTIONAL) {
1910  rpmlog(RPMLOG_WARNING, _("Optional file not found: %s\n"), diskURL);
1911  rc = RPMRC_OK;
1912  } else {
1913  rpmlog(RPMLOG_ERR, _("File not found: %s\n"), diskURL);
1914  fl->processingFailed = 1;
1915  rc = RPMRC_FAIL;
1916  }
1917  goto exit;
1918  }
1919  }
1920 
1921  if ((! fl->isDir) && S_ISDIR(statp->st_mode)) {
1922 /*@-nullstate@*/ /* FIX: fl->buildRootURL may be NULL */
1923  rc = recurseDir(fl, diskURL);
1924  goto exit;
1925 /*@=nullstate@*/
1926  }
1927 
1928  fileMode = statp->st_mode;
1929  fileUid = statp->st_uid;
1930  fileGid = statp->st_gid;
1931 
1932  if (S_ISDIR(fileMode) && fl->cur_ar.ar_dmodestr) {
1933  fileMode &= S_IFMT;
1934  fileMode |= fl->cur_ar.ar_dmode;
1935  } else if (fl->cur_ar.ar_fmodestr != NULL) {
1936  fileMode &= S_IFMT;
1937  fileMode |= fl->cur_ar.ar_fmode;
1938  }
1939  if (fl->cur_ar.ar_user) {
1940  fileUname = getUnameS(fl->cur_ar.ar_user);
1941  } else {
1942  fileUname = getUname(fileUid);
1943  }
1944  if (fl->cur_ar.ar_group) {
1945  fileGname = getGnameS(fl->cur_ar.ar_group);
1946  } else {
1947  fileGname = getGname(fileGid);
1948  }
1949 
1950  /* Default user/group to builder's user/group */
1951  if (fileUname == NULL)
1952  fileUname = getUname(getuid());
1953  if (fileGname == NULL)
1954  fileGname = getGname(getgid());
1955 
1956  /* Add to the file list */
1957  if (fl->fileListRecsUsed == fl->fileListRecsAlloced) {
1958  fl->fileListRecsAlloced += 128;
1959  fl->fileList = xrealloc(fl->fileList,
1960  fl->fileListRecsAlloced * sizeof(*(fl->fileList)));
1961  }
1962 
1963  { FileListRec flp = &fl->fileList[fl->fileListRecsUsed];
1964  int i;
1965 
1966  flp->fl_st = *statp; /* structure assignment */
1967  flp->fl_mode = fileMode;
1968  flp->fl_uid = fileUid;
1969  flp->fl_gid = fileGid;
1970 
1971  flp->fileURL = xstrdup(fileURL);
1972  flp->diskURL = xstrdup(diskURL);
1973  flp->uname = fileUname;
1974  flp->gname = fileGname;
1975 
1976  if (fl->currentLangs && fl->nLangs > 0) {
1977  char * ncl;
1978  size_t nl = 0;
1979 
1980  for (i = 0; i < fl->nLangs; i++)
1981  nl += strlen(fl->currentLangs[i]) + 1;
1982 
1983  flp->langs = ncl = xmalloc(nl);
1984  for (i = 0; i < fl->nLangs; i++) {
1985  const char *ocl;
1986  if (i) *ncl++ = '|';
1987  for (ocl = fl->currentLangs[i]; *ocl != '\0'; ocl++)
1988  *ncl++ = *ocl;
1989  *ncl = '\0';
1990  }
1991  } else if (! parseForRegexLang(fileURL, &lang)) {
1992  flp->langs = xstrdup(lang);
1993  } else {
1994  flp->langs = xstrdup("");
1995  }
1996 
1997  flp->flags = fl->currentFlags;
1998  flp->specdFlags = fl->currentSpecdFlags;
1999  flp->verifyFlags = fl->currentVerifyFlags;
2000  }
2001 
2002  fl->fileListRecsUsed++;
2003  fl->fileCount++;
2004 
2005 exit:
2006 /*@i@*/ fn = _free(fn);
2007  return rc;
2008 }
2009 
2016 static rpmRC recurseDir(FileList fl, const char * diskURL)
2017 {
2018  char * ftsSet[2];
2019  FTS * ftsp;
2020  FTSENT * fts;
2021  int myFtsOpts = (FTS_COMFOLLOW | FTS_NOCHDIR | FTS_PHYSICAL);
2022  rpmRC rc = RPMRC_FAIL;
2023 
2024  fl->inFtw = 1; /* Flag to indicate file has buildRootURL prefixed */
2025  fl->isDir = 1; /* Keep it from following myftw() again */
2026 
2027  ftsSet[0] = (char *) diskURL;
2028  ftsSet[1] = NULL;
2029  ftsp = Fts_open(ftsSet, myFtsOpts, NULL);
2030  while ((fts = Fts_read(ftsp)) != NULL) {
2031  switch (fts->fts_info) {
2032  case FTS_D: /* preorder directory */
2033  case FTS_F: /* regular file */
2034  case FTS_SL: /* symbolic link */
2035  case FTS_SLNONE: /* symbolic link without target */
2036  case FTS_DEFAULT: /* none of the above */
2037  rc = addFile(fl, fts->fts_accpath, fts->fts_statp);
2038  /*@switchbreak@*/ break;
2039  case FTS_DOT: /* dot or dot-dot */
2040  case FTS_DP: /* postorder directory */
2041  rc = 0;
2042  /*@switchbreak@*/ break;
2043  case FTS_NS: /* stat(2) failed */
2044  case FTS_DNR: /* unreadable directory */
2045  case FTS_ERR: /* error; errno is set */
2046  case FTS_DC: /* directory that causes cycles */
2047  case FTS_NSOK: /* no stat(2) requested */
2048  case FTS_INIT: /* initialized only */
2049  case FTS_W: /* whiteout object */
2050  default:
2051  rc = RPMRC_FAIL;
2052  /*@switchbreak@*/ break;
2053  }
2054  if (rc != RPMRC_OK)
2055  break;
2056  }
2057  (void) Fts_close(ftsp);
2058 
2059  fl->isDir = 0;
2060  fl->inFtw = 0;
2061 
2062  return rc;
2063 }
2064 
2073 static rpmRC processMetadataFile(Package pkg, FileList fl, const char * fileURL,
2074  rpmTag tag)
2075  /*@globals rpmGlobalMacroContext, h_errno,
2076  fileSystem, internalState @*/
2077  /*@modifies pkg->header, *fl, fl->processingFailed,
2078  fl->fileList, fl->fileListRecsAlloced, fl->fileListRecsUsed,
2079  fl->totalFileSize, fl->fileCount,
2080  rpmGlobalMacroContext,
2081  fileSystem, internalState @*/
2082 {
2083  HE_t he = memset(alloca(sizeof(*he)), 0, sizeof(*he));
2084  const char * buildURL = "%{_builddir}/%{?buildsubdir}/";
2085  const char * fn = NULL;
2086  const char * apkt = NULL;
2087  rpmiob iob = NULL;
2088  rpmuint8_t * pkt = NULL;
2089  ssize_t pktlen = 0;
2090  int absolute = 0;
2091  rpmRC rc = RPMRC_FAIL;
2092  int xx;
2093 
2094  (void) urlPath(fileURL, &fn);
2095  if (*fn == '/') {
2096  fn = rpmGenPath(fl->buildRootURL, NULL, fn);
2097  absolute = 1;
2098  } else
2099  fn = rpmGenPath(buildURL, NULL, fn);
2100 
2101  switch (tag) {
2102  default:
2103  rpmlog(RPMLOG_ERR, _("%s: can't load unknown tag (%d).\n"),
2104  fn, tag);
2105  goto exit;
2106  /*@notreached@*/ break;
2107  case RPMTAG_PUBKEYS:
2108  if ((xx = pgpReadPkts(fn, &pkt, (size_t *)&pktlen)) <= 0) {
2109  rpmlog(RPMLOG_ERR, _("%s: public key read failed.\n"), fn);
2110  goto exit;
2111  }
2112  if (xx != PGPARMOR_PUBKEY) {
2113  rpmlog(RPMLOG_ERR, _("%s: not an armored public key.\n"), fn);
2114  goto exit;
2115  }
2116  apkt = pgpArmorWrap(PGPARMOR_PUBKEY, pkt, pktlen);
2117  break;
2118  case RPMTAG_POLICIES:
2119  xx = rpmiobSlurp(fn, &iob);
2120  if (!(xx == 0 && iob != NULL)) {
2121  rpmlog(RPMLOG_ERR, _("%s: *.te policy read failed.\n"), fn);
2122  goto exit;
2123  }
2124  apkt = (const char *) iob->b; /* XXX unsigned char */
2125  /* XXX steal the I/O buffer */
2126  iob->b = (rpmuint8_t *)xcalloc(1, sizeof(*iob->b));
2127  iob->blen = 0;
2128  break;
2129  }
2130 
2131  he->tag = tag;
2132  he->t = RPM_STRING_ARRAY_TYPE;
2133  he->p.argv = &apkt;
2134  he->c = 1;
2135  he->append = 1;
2136  xx = headerPut(pkg->header, he, 0);
2137  he->append = 0;
2138 
2139  rc = RPMRC_OK;
2140  if (absolute)
2141  rc = addFile(fl, fn, NULL);
2142 
2143 exit:
2144  apkt = _free(apkt);
2145  pkt = _free(pkt);
2146  iob = rpmiobFree(iob);
2147  fn = _free(fn);
2148  if (rc != RPMRC_OK)
2149  fl->processingFailed = 1;
2150  return rc;
2151 }
2152 
2160 static rpmRC processBinaryFile(/*@unused@*/ Package pkg, FileList fl,
2161  const char * fileURL)
2162  /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/
2163  /*@modifies *fl, fl->processingFailed,
2164  fl->fileList, fl->fileListRecsAlloced, fl->fileListRecsUsed,
2165  fl->totalFileSize, fl->fileCount,
2166  rpmGlobalMacroContext, fileSystem, internalState @*/
2167 {
2168  int quote = 1; /* XXX permit quoted glob characters. */
2169  int doGlob;
2170  const char *diskURL = NULL;
2171  rpmRC rc = RPMRC_OK;
2172  int xx;
2173 
2174  doGlob = Glob_pattern_p(fileURL, quote);
2175 
2176  /* Check that file starts with leading "/" */
2177  { const char * fileName;
2178  (void) urlPath(fileURL, &fileName);
2179  if (*fileName != '/') {
2180  rpmlog(RPMLOG_ERR, _("File needs leading \"/\": %s\n"),
2181  fileName);
2182  rc = RPMRC_FAIL;
2183  goto exit;
2184  }
2185  }
2186 
2187  /* Copy file name or glob pattern removing multiple "/" chars. */
2188  /*
2189  * Note: rpmGetPath should guarantee a "canonical" path. That means
2190  * that the following pathologies should be weeded out:
2191  * //bin//sh
2192  * //usr//bin/
2193  * /.././../usr/../bin//./sh
2194  */
2195  diskURL = rpmGenPath(fl->buildRootURL, NULL, fileURL);
2196 
2197  if (doGlob) {
2198  const char ** argv = NULL;
2199  int argc = 0;
2200  int i;
2201 
2202  /* XXX for %dev marker in file manifest only */
2203  if (fl->noGlob) {
2204  rpmlog(RPMLOG_ERR, _("Glob not permitted: %s\n"),
2205  diskURL);
2206  rc = RPMRC_FAIL;
2207  goto exit;
2208  }
2209 
2210  xx = rpmGlob(diskURL, &argc, &argv);
2211  if (xx == 0 && argc >= 1) {
2212  for (i = 0; i < argc; i++) {
2213  rc = addFile(fl, argv[i], NULL);
2214  argv[i] = _free(argv[i]);
2215  }
2216  argv = _free(argv);
2217  } else {
2218  if (fl->currentFlags & RPMFILE_OPTIONAL) {
2219  rpmlog(RPMLOG_WARNING, _("Optional file not found by glob: %s\n"),
2220  diskURL);
2221  rc = RPMRC_OK;
2222  } else {
2223  rpmlog(RPMLOG_ERR, _("File not found by glob: %s\n"),
2224  diskURL);
2225  rc = RPMRC_FAIL;
2226  }
2227  goto exit;
2228  }
2229  } else
2230  rc = addFile(fl, diskURL, NULL);
2231 
2232 exit:
2233  diskURL = _free(diskURL);
2234  if (rc != RPMRC_OK)
2235  fl->processingFailed = 1;
2236  return rc;
2237 }
2238 
2242  int installSpecialDoc, int test)
2243  /*@globals rpmGlobalMacroContext, h_errno,
2244  fileSystem, internalState@*/
2245  /*@modifies spec->macros,
2246  pkg->cpioList, pkg->fileList, pkg->specialDoc, pkg->header,
2247  rpmGlobalMacroContext, fileSystem, internalState @*/
2248 {
2249  HE_t he = memset(alloca(sizeof(*he)), 0, sizeof(*he));
2250  struct FileList_s fl;
2251  ARGV_t files = NULL;
2252  ARGV_t fp;
2253  const char *fileName;
2254  char buf[BUFSIZ];
2255  struct AttrRec_s arbuf;
2256  AttrRec specialDocAttrRec = &arbuf;
2257  char *specialDoc = NULL;
2258  int xx;
2259 
2260  nullAttrRec(specialDocAttrRec);
2261  pkg->cpioList = NULL;
2262 
2263  if (pkg->fileFile) {
2264  char *saveptr = NULL;
2265  char *filesFiles = xstrdup(pkg->fileFile);
2266 /*@-unrecog@*/
2267  char *token = strtok_r(filesFiles, ",", &saveptr);
2268 /*@=unrecog@*/
2269  do {
2270  const char *ffn;
2271  FILE * f;
2272  FD_t fd;
2273 
2274  /* XXX W2DO? urlPath might be useful here. */
2275  if (*token == '/') {
2276  ffn = rpmGetPath(token, NULL);
2277  } else {
2278  /* XXX FIXME: add %{buildsubdir} */
2279  ffn = rpmGetPath("%{_builddir}/",
2280  (spec->buildSubdir ? spec->buildSubdir : "") ,
2281  "/", token, NULL);
2282  }
2283 
2284  fd = Fopen(ffn, "r.fpio");
2285 
2286  if (fd == NULL || Ferror(fd)) {
2288  _("Could not open %%files file %s: %s\n"),
2289  ffn, Fstrerror(fd));
2290  return RPMRC_FAIL;
2291  }
2292  ffn = _free(ffn);
2293 
2294  /*@+voidabstract@*/ f = fdGetFp(fd); /*@=voidabstract@*/
2295  if (f != NULL) {
2296  while (fgets(buf, (int)sizeof(buf), f)) {
2297  handleComments(buf);
2298  if (expandMacros(spec, spec->macros, buf, sizeof(buf))) {
2299  rpmlog(RPMLOG_ERR, _("line: %s\n"), buf);
2300  return RPMRC_FAIL;
2301  }
2302  pkg->fileList = rpmiobAppend(pkg->fileList, buf, 0);
2303  }
2304  }
2305  (void) Fclose(fd);
2306  } while((token = strtok_r(NULL, ",", &saveptr)) != NULL);
2307  filesFiles = _free(filesFiles);
2308  }
2309 
2310  /* Init the file list structure */
2311  memset(&fl, 0, sizeof(fl));
2312 
2313  fl.buildRootURL = rpmGenPath(spec->rootURL, "%{?buildroot}", NULL);
2314 
2315  he->tag = RPMTAG_DEFAULTPREFIX;
2316  xx = headerGet(pkg->header, he, 0);
2317  fl.prefix = he->p.str;
2318 
2319  fl.fileCount = 0;
2320  fl.totalFileSize = 0;
2321  fl.processingFailed = 0;
2322 
2323  fl.passedSpecialDoc = 0;
2324  fl.isSpecialDoc = 0;
2325 
2326  fl.isDir = 0;
2327  fl.inFtw = 0;
2328  fl.currentFlags = 0;
2329  fl.currentVerifyFlags = 0;
2330 
2331  fl.noGlob = 0;
2332  fl.devtype = 0;
2333  fl.devmajor = 0;
2334  fl.devminor = 0;
2335 
2336  nullAttrRec(&fl.cur_ar);
2337  nullAttrRec(&fl.def_ar);
2338  dupAttrRec(&root_ar, &fl.def_ar); /* XXX assume %defattr(-,root,root) */
2339 
2341  fl.nLangs = 0;
2342  fl.currentLangs = NULL;
2343 
2344  fl.currentSpecdFlags = 0;
2345  fl.defSpecdFlags = 0;
2346 
2347  fl.docDirCount = 0;
2348 #if defined(RPM_VENDOR_OPENPKG) /* no-default-doc-files */
2349  /* do not declare any files as %doc files by default. */
2350 #else
2351  fl.docDirs[fl.docDirCount++] = xstrdup("/usr/doc");
2352  fl.docDirs[fl.docDirCount++] = xstrdup("/usr/man");
2353  fl.docDirs[fl.docDirCount++] = xstrdup("/usr/info");
2354  fl.docDirs[fl.docDirCount++] = xstrdup("/usr/X11R6/man");
2355  fl.docDirs[fl.docDirCount++] = xstrdup("/usr/share/doc");
2356  fl.docDirs[fl.docDirCount++] = xstrdup("/usr/share/man");
2357  fl.docDirs[fl.docDirCount++] = xstrdup("/usr/share/info");
2358  fl.docDirs[fl.docDirCount++] = xstrdup("/usr/src/examples");
2359  fl.docDirs[fl.docDirCount++] = rpmGetPath("%{_docdir}", NULL);
2360  fl.docDirs[fl.docDirCount++] = rpmGetPath("%{_mandir}", NULL);
2361  fl.docDirs[fl.docDirCount++] = rpmGetPath("%{_infodir}", NULL);
2362  fl.docDirs[fl.docDirCount++] = rpmGetPath("%{_javadocdir}", NULL);
2363  fl.docDirs[fl.docDirCount++] = rpmGetPath("%{_examplesdir}", NULL);
2364 #endif
2365 
2366  fl.fileList = NULL;
2367  fl.fileListRecsAlloced = 0;
2368  fl.fileListRecsUsed = 0;
2369 
2370  xx = argvSplit(&files, rpmiobStr(pkg->fileList), "\n");
2371 
2372  for (fp = files; *fp != NULL; fp++) {
2373  const char * s;
2374  s = *fp;
2375  SKIPSPACE(s);
2376  if (*s == '\0')
2377  continue;
2378  fileName = NULL;
2379  /*@-nullpass@*/ /* LCL: buf is NULL ?!? */
2380  strncpy(buf, s, sizeof(buf)-1);
2381  buf[sizeof(buf)-1] = '\0';
2382  /*@=nullpass@*/
2383 
2384  /* Reset for a new line in %files */
2385  fl.isDir = 0;
2386  fl.inFtw = 0;
2387  fl.currentFlags = 0;
2388  /* turn explicit flags into %def'd ones (gosh this is hacky...) */
2389  fl.currentSpecdFlags = ((unsigned)fl.defSpecdFlags) >> 8;
2391  fl.isSpecialDoc = 0;
2392 
2393  fl.noGlob = 0;
2394  fl.devtype = 0;
2395  fl.devmajor = 0;
2396  fl.devminor = 0;
2397 
2398  /* XXX should reset to %deflang value */
2399  if (fl.currentLangs) {
2400  int i;
2401  for (i = 0; i < fl.nLangs; i++)
2402  /*@-unqualifiedtrans@*/
2403  fl.currentLangs[i] = _free(fl.currentLangs[i]);
2404  /*@=unqualifiedtrans@*/
2405  fl.currentLangs = _free(fl.currentLangs);
2406  }
2407  fl.nLangs = 0;
2408 
2409  dupAttrRec(&fl.def_ar, &fl.cur_ar);
2410 
2411  /*@-nullpass@*/ /* LCL: buf is NULL ?!? */
2412  if (parseForVerify(buf, &fl) != RPMRC_OK)
2413  continue;
2414  if (parseForAttr(buf, &fl) != RPMRC_OK)
2415  continue;
2416  if (parseForDev(buf, &fl) != RPMRC_OK)
2417  continue;
2418  if (parseForConfig(buf, &fl) != RPMRC_OK)
2419  continue;
2420  if (parseForLang(buf, &fl) != RPMRC_OK)
2421  continue;
2422  /*@-nullstate@*/ /* FIX: pkg->fileFile might be NULL */
2423  if (parseForSimple(spec, pkg, buf, &fl, &fileName) != RPMRC_OK)
2424  /*@=nullstate@*/
2425  continue;
2426  /*@=nullpass@*/
2427  if (fileName == NULL)
2428  continue;
2429 
2430  if (fl.isSpecialDoc) {
2431  /* Save this stuff for last */
2432  specialDoc = _free(specialDoc);
2433  specialDoc = xstrdup(fileName);
2434  dupAttrRec(&fl.cur_ar, specialDocAttrRec);
2435  } else if (fl.currentFlags & RPMFILE_PUBKEY) {
2436 /*@-nullstate@*/ /* FIX: pkg->fileFile might be NULL */
2437  (void) processMetadataFile(pkg, &fl, fileName, RPMTAG_PUBKEYS);
2438 /*@=nullstate@*/
2439  } else if (fl.currentFlags & RPMFILE_POLICY) {
2440 /*@-nullstate@*/ /* FIX: pkg->fileFile might be NULL */
2441  (void) processMetadataFile(pkg, &fl, fileName, RPMTAG_POLICIES);
2442 /*@=nullstate@*/
2443  } else {
2444 /*@-nullstate@*/ /* FIX: pkg->fileFile might be NULL */
2445  (void) processBinaryFile(pkg, &fl, fileName);
2446 /*@=nullstate@*/
2447  }
2448  }
2449 
2450  /* Now process special doc, if there is one */
2451  if (specialDoc) {
2452  if (installSpecialDoc) {
2453  int _missing_doc_files_terminate_build =
2454  rpmExpandNumeric("%{?_missing_doc_files_terminate_build}");
2455  rpmRC rc;
2456 
2457  rc = doScript(spec, RPMBUILD_STRINGBUF, "%doc", pkg->specialDoc, test);
2458  if (rc != RPMRC_OK && _missing_doc_files_terminate_build)
2459  fl.processingFailed = 1;
2460  }
2461 
2462  /* Reset for %doc */
2463  fl.isDir = 0;
2464  fl.inFtw = 0;
2465  fl.currentFlags = 0;
2467 
2468  fl.noGlob = 0;
2469  fl.devtype = 0;
2470  fl.devmajor = 0;
2471  fl.devminor = 0;
2472 
2473  /* XXX should reset to %deflang value */
2474  if (fl.currentLangs) {
2475  int i;
2476  for (i = 0; i < fl.nLangs; i++)
2477  /*@-unqualifiedtrans@*/
2478  fl.currentLangs[i] = _free(fl.currentLangs[i]);
2479  /*@=unqualifiedtrans@*/
2480  fl.currentLangs = _free(fl.currentLangs);
2481  }
2482  fl.nLangs = 0;
2483 
2484  dupAttrRec(specialDocAttrRec, &fl.cur_ar);
2485  freeAttrRec(specialDocAttrRec);
2486 
2487  /*@-nullstate@*/ /* FIX: pkg->fileFile might be NULL */
2488  (void) processBinaryFile(pkg, &fl, specialDoc);
2489  /*@=nullstate@*/
2490 
2491  specialDoc = _free(specialDoc);
2492  }
2493 
2494  files = argvFree(files);
2495 
2496  if (fl.processingFailed)
2497  goto exit;
2498 
2499  /* Verify that file attributes scope over hardlinks correctly. */
2500  if (checkHardLinks(&fl))
2501  (void) rpmlibNeedsFeature(pkg->header,
2502  "PartialHardlinkSets", "4.0.4-1");
2503 
2504  genCpioListAndHeader(&fl, &pkg->cpioList, pkg->header, 0);
2505 
2506  if (spec->timeCheck)
2507  timeCheck(spec->timeCheck, pkg->header);
2508 
2509 exit:
2510  fl.buildRootURL = _free(fl.buildRootURL);
2511  fl.prefix = _free(fl.prefix);
2512 
2513  freeAttrRec(&fl.cur_ar);
2514  freeAttrRec(&fl.def_ar);
2515 
2516  if (fl.currentLangs) {
2517  int i;
2518  for (i = 0; i < fl.nLangs; i++)
2519  /*@-unqualifiedtrans@*/
2520  fl.currentLangs[i] = _free(fl.currentLangs[i]);
2521  /*@=unqualifiedtrans@*/
2522  fl.currentLangs = _free(fl.currentLangs);
2523  }
2524 
2526  while (fl.docDirCount--)
2527  fl.docDirs[fl.docDirCount] = _free(fl.docDirs[fl.docDirCount]);
2528  return (fl.processingFailed ? RPMRC_FAIL : RPMRC_OK);
2529 }
2530 
2532 {
2533  HE_t he = memset(alloca(sizeof(*he)), 0, sizeof(*he));
2534  HeaderIterator hi;
2535  rpmiob sourceFiles;
2536  struct Source *srcPtr;
2537  static rpmTag classTag = 0xffffffff;
2538  int xx;
2539  size_t i;
2540 
2541  if (classTag == 0xffffffff)
2542  classTag = tagValue("Class");
2543 
2544  /* Only specific tags are added to the source package header */
2545  if (!spec->sourceHdrInit) {
2546  for (hi = headerInit(spec->packages->header);
2547  headerNext(hi, he, 0);
2548  he->p.ptr = _free(he->p.ptr))
2549  {
2550  switch (he->tag) {
2551  case RPMTAG_NAME:
2552  case RPMTAG_VERSION:
2553  case RPMTAG_RELEASE:
2554  case RPMTAG_DISTEPOCH:
2555  case RPMTAG_EPOCH:
2556  case RPMTAG_SUMMARY:
2557  case RPMTAG_DESCRIPTION:
2558  case RPMTAG_PACKAGER:
2559  case RPMTAG_DISTRIBUTION:
2560  case RPMTAG_DISTURL:
2561  case RPMTAG_VENDOR:
2562  case RPMTAG_LICENSE:
2563  case RPMTAG_GROUP:
2564  case RPMTAG_OS:
2565  case RPMTAG_ARCH:
2566  case RPMTAG_CHANGELOGTIME:
2567  case RPMTAG_CHANGELOGNAME:
2568  case RPMTAG_CHANGELOGTEXT:
2569  case RPMTAG_URL:
2570  case RPMTAG_ICON:
2571  case RPMTAG_GIF:
2572  case RPMTAG_XPM:
2573  case HEADER_I18NTABLE:
2574 #if defined(RPM_VENDOR_OPENPKG) /* propagate-provides-to-srpms */
2575  /* make sure the "Provides" headers are available for querying from the .src.rpm files. */
2576  case RPMTAG_PROVIDENAME:
2577  case RPMTAG_PROVIDEVERSION:
2578  case RPMTAG_PROVIDEFLAGS:
2579 #endif
2580  if (he->p.ptr)
2581  xx = headerPut(spec->sourceHeader, he, 0);
2582  /*@switchbreak@*/ break;
2583  default:
2584  if (classTag == he->tag && he->p.ptr != NULL)
2585  xx = headerPut(spec->sourceHeader, he, 0);
2586  /*@switchbreak@*/ break;
2587  }
2588  }
2589  hi = headerFini(hi);
2590 
2591  if (spec->BANames && spec->BACount > 0) {
2592  he->tag = RPMTAG_BUILDARCHS;
2593  he->t = RPM_STRING_ARRAY_TYPE;
2594  he->p.argv = spec->BANames;
2595  he->c = spec->BACount;
2596  xx = headerPut(spec->sourceHeader, he, 0);
2597  }
2598 
2599  /* Load arbitrary tags into srpm header. */
2600  if (spec->foo)
2601  for (i = 0; i < spec->nfoo; i++) {
2602  const char * str = spec->foo[i].str;
2603  rpmTag tag = spec->foo[i].tag;
2604  rpmiob iob = spec->foo[i].iob;
2605  char * s;
2606 
2607  if (str == NULL || iob == NULL)
2608  continue;
2609 
2610  /* XXX Special case %track interpreter for now. */
2611  if (!xstrcasecmp(str, "track")) {
2612  he->p.str = rpmExpand("%{?__vcheck}", NULL);
2613  if (!(he->p.str != NULL && he->p.str[0] != '\0')) {
2614  he->p.str = _free(he->p.str);
2615  continue;
2616  }
2617  he->tag = tagValue("Trackprog");
2618  he->t = RPM_STRING_TYPE;
2619  he->c = 1;
2620  xx = headerPut(spec->sourceHeader, he, 0);
2621  he->p.str = _free(he->p.str);
2622  }
2623 
2624  s = rpmiobStr(iob);
2625  he->tag = tag;
2626  he->append = headerIsEntry(spec->sourceHeader, tag);
2627  if (he->append) {
2628  he->t = RPM_STRING_ARRAY_TYPE;
2629  he->p.argv = (const char **) &s;
2630  he->c = 1;
2631  } else {
2632  he->t = RPM_STRING_TYPE;
2633  he->p.str = s;
2634  he->c = 1;
2635  }
2636  xx = headerPut(spec->sourceHeader, he, 0);
2637  he->append = 0;
2638  }
2639  }
2640 
2641  if (sfp != NULL && *sfp != NULL)
2642  sourceFiles = *sfp;
2643  else
2644  sourceFiles = rpmiobNew(0);
2645 
2646  /* Construct the source/patch tag entries */
2647  sourceFiles = rpmiobAppend(sourceFiles, spec->specFile, 1);
2648  if (spec->sourceHeader != NULL)
2649  for (srcPtr = spec->sources; srcPtr != NULL; srcPtr = srcPtr->next) {
2650  { const char * sfn;
2651 /*@-nullpass@*/ /* XXX getSourceDir returns NULL with bad flags. */
2652  sfn = rpmGetPath( ((srcPtr->flags & RPMFILE_GHOST) ? "!" : ""),
2653 #if defined(RPM_VENDOR_OPENPKG) /* splitted-source-directory */
2654  getSourceDir(srcPtr->flags, srcPtr->source), srcPtr->source, NULL);
2655 #else
2656  getSourceDir(srcPtr->flags), srcPtr->source, NULL);
2657 #endif
2658 /*@=nullpass@*/
2659  sourceFiles = rpmiobAppend(sourceFiles, sfn, 1);
2660  sfn = _free(sfn);
2661  }
2662 
2663  if (spec->sourceHdrInit)
2664  continue;
2665 
2666  if (srcPtr->flags & RPMFILE_SOURCE) {
2667  he->tag = RPMTAG_SOURCE;
2668  he->t = RPM_STRING_ARRAY_TYPE;
2669  he->p.argv = &srcPtr->source;
2670  he->c = 1;
2671  he->append = 1;
2672  xx = headerPut(spec->sourceHeader, he, 0);
2673  he->append = 0;
2674  if (srcPtr->flags & RPMFILE_GHOST) {
2675  he->tag = RPMTAG_NOSOURCE;
2676  he->t = RPM_UINT32_TYPE;
2677  he->p.ui32p = &srcPtr->num;
2678  he->c = 1;
2679  he->append = 1;
2680  xx = headerPut(spec->sourceHeader, he, 0);
2681  he->append = 0;
2682  }
2683  }
2684  if (srcPtr->flags & RPMFILE_PATCH) {
2685  he->tag = RPMTAG_PATCH;
2686  he->t = RPM_STRING_ARRAY_TYPE;
2687  he->p.argv = &srcPtr->source;
2688  he->c = 1;
2689  he->append = 1;
2690  xx = headerPut(spec->sourceHeader, he, 0);
2691  he->append = 0;
2692  if (srcPtr->flags & RPMFILE_GHOST) {
2693  he->tag = RPMTAG_NOPATCH;
2694  he->t = RPM_UINT32_TYPE;
2695  he->p.ui32p = &srcPtr->num;
2696  he->c = 1;
2697  he->append = 1;
2698  xx = headerPut(spec->sourceHeader, he, 0);
2699  he->append = 0;
2700  }
2701  }
2702  }
2703 
2704  if (sfp == NULL)
2705  sourceFiles = rpmiobFree(sourceFiles);
2706 
2707  spec->sourceHdrInit = 1;
2708 
2709 /*@-usereleased@*/
2710  return 0;
2711 /*@=usereleased@*/
2712 }
2713 
2715 {
2716  rpmiob sourceFiles, *sfp = &sourceFiles;
2717  int x, isSpec = 1;
2718  struct FileList_s fl;
2719  ARGV_t files = NULL;
2720  ARGV_t fp;
2721  int rc;
2722  /* srcdefattr: needed variables */
2723  char _srcdefattr_buf[BUFSIZ];
2724  char *_srcdefattr;
2725  int xx;
2726 
2727  _srcdefattr = rpmExpand("%{?_srcdefattr}", NULL);
2728 
2729  *sfp = rpmiobNew(0);
2730  x = initSourceHeader(spec, sfp);
2731 
2732  /* srcdefattr: initialize file list structure */
2733  memset(&fl, 0, sizeof(fl));
2734  if (_srcdefattr && *_srcdefattr) {
2735  xx = snprintf(_srcdefattr_buf, sizeof(_srcdefattr_buf), "%%defattr %s", _srcdefattr);
2736  _srcdefattr_buf[sizeof(_srcdefattr_buf)-1] = '\0';
2737  xx = parseForAttr(_srcdefattr_buf, &fl);
2738  }
2739 
2740  /* Construct the SRPM file list. */
2741  fl.fileList = xcalloc((spec->numSources + 1), sizeof(*fl.fileList));
2742  rc = fl.processingFailed = 0;
2743  fl.fileListRecsUsed = 0;
2744  fl.totalFileSize = 0;
2745  fl.prefix = NULL;
2746  fl.buildRootURL = NULL;
2747 
2748  xx = argvSplit(&files, rpmiobStr(*sfp), "\n");
2749 
2750  /* The first source file is the spec file */
2751  x = 0;
2752  for (fp = files; *fp != NULL; fp++) {
2753  const char * diskURL, *diskPath;
2754  FileListRec flp;
2755 
2756  diskURL = *fp;
2757  SKIPSPACE(diskURL);
2758  if (! *diskURL)
2759  continue;
2760 
2761  flp = &fl.fileList[x];
2762 
2763  flp->flags = isSpec ? RPMFILE_SPECFILE : 0;
2764  /* files with leading ! are no source files */
2765  if (*diskURL == '!') {
2766  flp->flags |= RPMFILE_GHOST;
2767  diskURL++;
2768  }
2769 
2770  (void) urlPath(diskURL, &diskPath);
2771 
2772  flp->diskURL = xstrdup(diskURL);
2773  diskPath = strrchr(diskPath, '/');
2774  if (diskPath)
2775  diskPath++;
2776  else
2777  diskPath = diskURL;
2778 
2779  flp->fileURL = xstrdup(diskPath);
2780  flp->verifyFlags = RPMVERIFY_ALL;
2781 
2782  if (Stat(diskURL, &flp->fl_st)) {
2783  rpmlog(RPMLOG_ERR, _("Bad file: %s: %s\n"),
2784  diskURL, strerror(errno));
2785  rc = fl.processingFailed = 1;
2786  }
2787 
2788 #if defined(RPM_VENDOR_OPENPKG) /* support-srcdefattr */
2789  /* srcdefattr: allow to set SRPM file attributes via %{_srcdefattr} macro */
2790  if (fl.def_ar.ar_fmodestr) {
2791  flp->fl_mode &= S_IFMT;
2792  flp->fl_mode |= fl.def_ar.ar_fmode;
2793  }
2794  flp->uname = fl.def_ar.ar_user ? getUnameS(fl.def_ar.ar_user) : getUname(flp->fl_uid);
2795  flp->gname = fl.def_ar.ar_group ? getGnameS(fl.def_ar.ar_group) : getGname(flp->fl_gid);
2796 #else
2797  flp->uname = getUname(flp->fl_uid);
2798  flp->gname = getGname(flp->fl_gid);
2799 #endif
2800  flp->langs = xstrdup("");
2801 
2802  if (! (flp->uname && flp->gname)) {
2803  rpmlog(RPMLOG_ERR, _("Bad owner/group: %s\n"), diskURL);
2804  rc = fl.processingFailed = 1;
2805  }
2806 
2807  isSpec = 0;
2808  x++;
2809  }
2810  fl.fileListRecsUsed = x;
2811  files = argvFree(files);
2812 
2813  if (rc)
2814  goto exit;
2815 
2816  spec->sourceCpioList = NULL;
2817  genCpioListAndHeader(&fl, &spec->sourceCpioList, spec->sourceHeader, 1);
2818 
2819 exit:
2820  *sfp = rpmiobFree(*sfp);
2822  return rc;
2823 }
2824 
2830 static int checkUnpackagedFiles(Spec spec)
2831  /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/
2832  /*@modifies *spec->packages,
2833  rpmGlobalMacroContext, fileSystem, internalState @*/
2834 {
2835 /*@-readonlytrans@*/
2836  static const char * av_ckfile[] = { "%{?__check_files}", NULL };
2837 /*@=readonlytrans@*/
2838  rpmiob iob_stdout = NULL;
2839  const char * s;
2840  int rc;
2841  rpmiob fileList = NULL;
2842  Package pkg;
2843  int n = 0;
2844 
2845  s = rpmExpand(av_ckfile[0], NULL);
2846  if (!(s && *s)) {
2847  rc = -1;
2848  goto exit;
2849  }
2850  rc = 0;
2851 
2852  /* initialize fileList */
2853  fileList = rpmiobNew(0);
2854  for (pkg = spec->packages; pkg != NULL; pkg = pkg->next) {
2855  int i;
2856  rpmfi fi = rpmfiNew(NULL, pkg->header, RPMTAG_BASENAMES, 0);
2857  fi = rpmfiInit(fi, 0);
2858  while ((i = rpmfiNext(fi)) >= 0) {
2859  const char *fn = rpmfiFN(fi);
2860  fileList = rpmiobAppend(fileList, fn, 1);
2861  n++;
2862  }
2863  fi = rpmfiFree(fi);
2864  }
2865  if (n == 0) {
2866  /* no packaged files, and buildroot may not exist -
2867  * no need to run check */
2868  rc = -1;
2869  goto exit;
2870  }
2871 
2872  rpmlog(RPMLOG_NOTICE, _("Checking for unpackaged file(s): %s\n"), s);
2873 
2874  rc = rpmfcExec(av_ckfile, fileList, &iob_stdout, 0);
2875  if (rc < 0)
2876  goto exit;
2877 
2878  if (iob_stdout) {
2879  int _unpackaged_files_terminate_build =
2880  rpmExpandNumeric("%{?_unpackaged_files_terminate_build}");
2881  const char * t;
2882 
2883  t = rpmiobStr(iob_stdout);
2884  if ((*t != '\0') && (*t != '\n')) {
2885  rc = (_unpackaged_files_terminate_build) ? 1 : 0;
2886  rpmlog((rc ? RPMLOG_ERR : RPMLOG_WARNING),
2887  _("Installed (but unpackaged) file(s) found:\n%s"), t);
2888  }
2889  }
2890 
2891 exit:
2892  fileList = rpmiobFree(fileList);
2893  iob_stdout = rpmiobFree(iob_stdout);
2894  s = _free(s);
2895  return rc;
2896 }
2897 
2898 /* auxiliary function for checkDuplicateFiles() */
2899 /* XXX need to pass Header because fi->h is NULL */
2900 static int fiIntersect(/*@null@*/ rpmfi fi1, /*@null@*/ rpmfi fi2, Header h1, Header h2)
2901  /*@globals internalState @*/
2902  /*@modifies fi1, fi2, internalState @*/
2903 {
2904  int n = 0;
2905  int i1, i2;
2906  const char *fn1, *fn2;
2907  rpmiob dups = NULL;
2908 
2909  if ((fi1 = rpmfiInit(fi1, 0)) != NULL)
2910  while ((i1 = rpmfiNext(fi1)) >= 0) {
2911  if (S_ISDIR(rpmfiFMode(fi1)))
2912  continue;
2913  fn1 = rpmfiFN(fi1);
2914  if ((fi2 = rpmfiInit(fi2, 0)) != NULL)
2915  while ((i2 = rpmfiNext(fi2)) >= 0) {
2916  if (S_ISDIR(rpmfiFMode(fi2)))
2917  /*@innercontinue@*/ continue;
2918  fn2 = rpmfiFN(fi2);
2919  if (strcmp(fn1, fn2))
2920  /*@innercontinue@*/ continue;
2921  if (!dups)
2922  dups = rpmiobNew(0);
2923  dups = rpmiobAppend(dups, "\t", 0);
2924  dups = rpmiobAppend(dups, fn1, 1);
2925  n++;
2926  }
2927  }
2928 
2929  if (n > 0) {
2930  const char *N1, *N2;
2931  HE_t he = memset(alloca(sizeof(*he)), 0, sizeof(*he));
2932 
2933  he->tag = RPMTAG_NVRA;
2934  N1 = (headerGet(h1, he, 0) ? he->p.str : NULL);
2935  he->tag = RPMTAG_NVRA;
2936  N2 = (headerGet(h2, he, 0) ? he->p.str : NULL);
2937 
2939  _("File(s) packaged into both %s and %s:\n%s"),
2940  N1, N2, rpmiobStr(dups));
2941 
2942  N1 = _free(N1);
2943  N2 = _free(N2);
2944  dups = rpmiobFree(dups);
2945  }
2946 
2947  return n;
2948 }
2949 
2955 static int checkDuplicateFiles(Spec spec)
2956  /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/
2957  /*@modifies *spec->packages,
2958  rpmGlobalMacroContext, fileSystem, internalState @*/
2959 {
2960  int n = 0;
2961  Package pkg1, pkg2;
2962 
2963  for (pkg1 = spec->packages; pkg1->next; pkg1 = pkg1->next) {
2964  rpmfi fi1 = rpmfiNew(NULL, pkg1->header, RPMTAG_BASENAMES, 0);
2965  for (pkg2 = pkg1->next; pkg2; pkg2 = pkg2->next) {
2966  rpmfi fi2 = rpmfiNew(NULL, pkg2->header, RPMTAG_BASENAMES, 0);
2967  n += fiIntersect(fi1, fi2, pkg1->header, pkg2->header);
2968  fi2 = rpmfiFree(fi2);
2969  }
2970  fi1 = rpmfiFree(fi1);
2971  }
2972  return n;
2973 }
2974 
2975 /* auxiliary function: check if directory d is packaged */
2976 static int packagedDir(Package pkg, const char *d)
2977  /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/
2978  /*@modifies pkg->header,
2979  rpmGlobalMacroContext, fileSystem, internalState @*/
2980 {
2981  int i;
2982  int found = 0;
2983  const char *fn;
2984  rpmfi fi = rpmfiNew(NULL, pkg->header, RPMTAG_BASENAMES, 0);
2985 
2986  fi = rpmfiInit(fi, 0);
2987  while ((i = rpmfiNext(fi)) >= 0) {
2988  if (!S_ISDIR(rpmfiFMode(fi)))
2989  continue;
2990  fn = rpmfiFN(fi);
2991  if (strcmp(fn, d) == 0) {
2992  found = 1;
2993  break;
2994  }
2995  }
2996  fi = rpmfiFree(fi);
2997  return found;
2998 }
2999 
3000 /* auxiliary function: find unpackaged subdirectories
3001  *
3002  * E.g. consider this %files section:
3003  * %dir /A
3004  * /A/B/C/D
3005  * Now directories "/A/B" and "/A/B/C" should also be packaged.
3006  */
3008  /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/
3009  /*@modifies pkg->header,
3010  rpmGlobalMacroContext, fileSystem, internalState @*/
3011 {
3012  int n = 0;
3013  int i, j;
3014  char **unpackaged = NULL;
3015  char *fn;
3016  rpmfi fi = rpmfiNew(NULL, pkg->header, RPMTAG_BASENAMES, 0);
3017 
3018  if (rpmfiFC(fi) <= 1) {
3019  fi = rpmfiFree(fi);
3020  return 0;
3021  }
3022  fn = alloca(rpmfiFNMaxLen(fi) + 1);
3023 
3024  fi = rpmfiInit(fi, 0);
3025  while ((i = rpmfiNext(fi)) >= 0) {
3026  int found = 0;
3027  /* make local copy of file name */
3028  char *p = fn;
3029  strcpy(fn, rpmfiFN(fi));
3030  /* find the first path component that is packaged */
3031  while ((p = strchr(p + 1, '/'))) {
3032  *p = '\0';
3033  found = packagedDir(pkg, fn);
3034  *p = '/';
3035  if (found)
3036  /*@innerbreak@*/ break;
3037  }
3038  if (!found)
3039  continue;
3040  /* other path components should be packaged, too */
3041  if (p != NULL)
3042  while ((p = strchr(p + 1, '/'))) {
3043  *p = '\0';
3044  if (packagedDir(pkg, fn)) {
3045  *p = '/';
3046  /*@innercontinue@*/ continue;
3047  }
3048  /* might be already added */
3049  found = 0;
3050  for (j = 0; j < n; j++)
3051  if (strcmp(fn, unpackaged[j]) == 0) {
3052  found = 1;
3053  /*@innerbreak@*/ break;
3054  }
3055  if (found) {
3056  *p = '/';
3057  /*@innercontinue@*/ continue;
3058  }
3059  unpackaged = xrealloc(unpackaged, sizeof(*unpackaged) * (n + 1));
3060  unpackaged[n++] = xstrdup(fn);
3061  *p = '/';
3062  }
3063  }
3064  fi = rpmfiFree(fi);
3065 
3066  if (n > 0) {
3067  const char *N;
3068  HE_t he = memset(alloca(sizeof(*he)), 0, sizeof(*he));
3069  rpmiob list = rpmiobNew(0);
3070 
3071  he->tag = RPMTAG_NVRA;
3072  N = (headerGet(pkg->header, he, 0) ? he->p.str : NULL);
3073 
3074  for (i = 0; i < n; i++) {
3075  list = rpmiobAppend(list, "\t", 0);
3076  list = rpmiobAppend(list, unpackaged[i], 1);
3077  unpackaged[i] = _free(unpackaged[i]);
3078  }
3079  unpackaged = _free(unpackaged);
3080 
3082  _("Unpackaged subdir(s) in %s:\n%s"),
3083  N, rpmiobStr(list));
3084 
3085  N = _free(N);
3086  list = rpmiobFree(list);
3087  }
3088 
3089  return n;
3090 }
3091 
3098  /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/
3099  /*@modifies *spec->packages,
3100  rpmGlobalMacroContext, fileSystem, internalState @*/
3101 {
3102  int n = 0;
3103  Package pkg;
3104 
3105  for (pkg = spec->packages; pkg; pkg = pkg->next)
3106  n += pkgUnpackagedSubdirs(pkg);
3107  return n;
3108 }
3109 
3110 /*@-incondefs@*/
3111 rpmRC processBinaryFiles(Spec spec, int installSpecialDoc, int test)
3112 {
3113  HE_t he = memset(alloca(sizeof(*he)), 0, sizeof(*he));
3114  Package pkg;
3115  rpmRC res = RPMRC_OK;
3116 
3117  for (pkg = spec->packages; pkg != NULL; pkg = pkg->next) {
3118  int rc;
3119 
3120  if (pkg->fileList == NULL)
3121  continue;
3122 
3123  (void) headerMacrosLoad(pkg->header);
3124 
3125  he->tag = RPMTAG_NVRA;
3126  rc = headerGet(pkg->header, he, 0);
3127  rpmlog(RPMLOG_NOTICE, _("Processing files: %s\n"), he->p.str);
3128  he->p.ptr = _free(he->p.ptr);
3129 
3130  if ((rc = processPackageFiles(spec, pkg, installSpecialDoc, test))) {
3131  res = RPMRC_FAIL;
3132  (void) headerMacrosUnload(pkg->header);
3133  break;
3134  }
3135 
3136  /* Finalize package scriptlets before extracting dependencies. */
3137  if ((rc = processScriptFiles(spec, pkg))) {
3138  res = rc;
3139  (void) headerMacrosUnload(pkg->header);
3140  break;
3141  }
3142 
3143  if ((rc = rpmfcGenerateDepends(spec, pkg))) {
3144  res = RPMRC_FAIL;
3145  (void) headerMacrosUnload(pkg->header);
3146  break;
3147  }
3148 
3149  /* XXX this should be earlier for deps to be entirely sorted. */
3150  providePackageNVR(pkg->header);
3151 
3152  (void) headerMacrosUnload(pkg->header);
3153  }
3154 
3155  if (res == RPMRC_OK) {
3156  if (checkUnpackagedFiles(spec) > 0)
3157  res = RPMRC_FAIL;
3158  (void) checkDuplicateFiles(spec);
3159  (void) checkUnpackagedSubdirs(spec);
3160  }
3161 
3162  return res;
3163 }
3164 /*@=incondefs@*/