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