rpm 5.2.1

- Main Page
- Related Pages
- Modules
- Data Structures
- Files

- File List
- Globals

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
123 int fileCount;
124 int totalFileSize;
125 int processingFailed;
126
127 int passedSpecialDoc;
128 int isSpecialDoc;
129
130 int noGlob;
131 unsigned devtype;
132 unsigned devmajor;
133 int devminor;
134
135 int isDir;
136 int inFtw;
137 int currentFlags;
138 specdFlags currentSpecdFlags;
139 int currentVerifyFlags;
140 struct AttrRec_s cur_ar;
141 struct AttrRec_s def_ar;
142 specdFlags defSpecdFlags;
143 int defVerifyFlags;
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];
151 int docDirCount;
152
153 /*@only@*/
154 FileListRec fileList;
155 int fileListRecsAlloced;
156 int fileListRecsUsed;
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;
334 specdFlags * specdFlags;
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;
530 specdFlags * specdFlags;
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') {
562 rpmlog(RPMLOG_ERR,
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
660 fl->currentFlags |= RPMFILE_CONFIG;
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")) {
696 fl->currentFlags |= RPMFILE_MISSINGOK;
697 } else if (!strcmp(p, "noreplace")) {
698 fl->currentFlags |= RPMFILE_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) {
774 rpmlog(RPMLOG_ERR,
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 */
793 fl->currentLangs = xrealloc(fl->currentLangs,
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@*/
858 static VFA_t virtualFileAttributes[] = {
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
969 if (fl->currentFlags & (RPMFILE_POLICY|RPMFILE_PUBKEY|RPMFILE_ICON))
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 */
977 rpmlog(RPMLOG_ERR,
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))) {
994 rpmlog(RPMLOG_ERR,
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)) <
1376 (flp->specdFlags & (SPECD_DIRMODE | SPECD_DEFDIRMODE)))
1377 flp[1].fl_mode = flp->fl_mode;
1378 } else {
1379 if ((flp[1].specdFlags & (SPECD_FILEMODE | SPECD_DEFFILEMODE)) <
1380 (flp->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)) <
1402 (flp->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;
1529 he->tag = RPMTAG_FILEDIGESTALGOS;
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))) {
1549 rpmlog(RPMLOG_ERR,
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) {
1566 flp->verifyFlags &= ~(RPMVERIFY_MD5 | RPMVERIFY_FILESIZE |
1567 RPMVERIFY_LINKTO | RPMVERIFY_MTIME);
1568 }
1569 ui32 = flp->verifyFlags;
1570 he->tag = RPMTAG_FILEVERIFYFLAGS;
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') {
1619 matchpathcon_fini();
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 |
1731 IOSM_MAP_TYPE | IOSM_MAP_MODE | IOSM_MAP_UID | IOSM_MAP_GID;
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
2241 static rpmRC processPackageFiles(Spec spec, Package pkg,
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)) {
2287 rpmlog(RPMLOG_ERR,
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
2340 fl.defVerifyFlags = RPMVERIFY_ALL;
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;
2390 fl.currentVerifyFlags = fl.defVerifyFlags;
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;
2466 fl.currentVerifyFlags = fl.defVerifyFlags;
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
2525 fl.fileList = freeFileList(fl.fileList, fl.fileListRecsUsed);
2526 while (fl.docDirCount--)
2527 fl.docDirs[fl.docDirCount] = _free(fl.docDirs[fl.docDirCount]);
2528 return (fl.processingFailed ? RPMRC_FAIL : RPMRC_OK);
2529 }
2530
2531 int initSourceHeader(Spec spec, rpmiob *sfp)
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
2714 int processSourceFiles(Spec spec)
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);
2821 fl.fileList = freeFileList(fl.fileList, fl.fileListRecsUsed);
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
2938 rpmlog(RPMLOG_WARNING,
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 */
3007 static int pkgUnpackagedSubdirs(Package pkg)
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
3081 rpmlog(RPMLOG_WARNING,
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
3097 static int checkUnpackagedSubdirs(Spec spec)
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@*/