Bug Summary

File:build/files.c
Warning:line 2318, column 12
Dereference of null pointer (loaded from variable 'files')

Annotated Source Code

1/** \ingroup rpmbuild
2 * \file build/files.c
3 * The post-build, pre-packaging file tree walk to assemble the package
4 * manifest.
5 */
6
7#include "system.h"
8
9#define MYALLPERMS07777 07777
10
11#include <errno(*__errno_location ()).h>
12#include <stdlib.h>
13#include <regex.h>
14#if WITH_CAP
15#include <sys/capability.h>
16#endif
17
18#if HAVE_LIBDW1
19#include <libelf.h>
20#include <elfutils/libdwelf.h>
21#endif
22
23#include <rpm/rpmpgp.h>
24#include <rpm/argv.h>
25#include <rpm/rpmfc.h>
26#include <rpm/rpmfileutil.h> /* rpmDoDigest() */
27#include <rpm/rpmlog.h>
28#include <rpm/rpmbase64.h>
29
30#include "rpmio/rpmio_internal.h" /* XXX rpmioSlurp */
31#include "misc/rpmfts.h"
32#include "lib/rpmfi_internal.h" /* XXX fi->apath */
33#include "lib/rpmug.h"
34#include "build/rpmbuild_internal.h"
35#include "build/rpmbuild_misc.h"
36
37#include "debug.h"
38#include <libgen.h>
39
40#define SKIPSPACE(s){ while (*(s) && risspace(*(s))) (s)++; } { while (*(s) && risspace(*(s))) (s)++; }
41#define SKIPWHITE(_x){while (*(_x) && (risspace(*_x) || *(_x) == ',')) (_x
)++;}
{while (*(_x) && (risspace(*_x) || *(_x) == ',')) (_x)++;}
42#define SKIPNONWHITE(_x){while (*(_x) &&!(risspace(*_x) || *(_x) == ',')) (_x
)++;}
{while (*(_x) &&!(risspace(*_x) || *(_x) == ',')) (_x)++;}
43
44/* the following defines must be in sync with the equally hardcoded paths from
45 * scripts/find-debuginfo.sh
46 */
47#define BUILD_ID_DIR"/usr/lib/.build-id" "/usr/lib/.build-id"
48#define DEBUG_SRC_DIR"/usr/src/debug" "/usr/src/debug"
49#define DEBUG_LIB_DIR"/usr/lib/debug" "/usr/lib/debug"
50#define DEBUG_LIB_PREFIX"/usr/lib/debug/" "/usr/lib/debug/"
51#define DEBUG_ID_DIR"/usr/lib/debug/.build-id" "/usr/lib/debug/.build-id"
52#define DEBUG_DWZ_DIR"/usr/lib/debug/.dwz" "/usr/lib/debug/.dwz"
53
54#undef HASHTYPE
55#undef HTKEYTYPE
56#undef HTDATATYPE
57#define HASHTYPE fileRenameHash
58#define HTKEYTYPE const char *
59#define HTDATATYPE const char *
60#include "lib/rpmhash.C"
61#undef HASHTYPE
62#undef HTKEYTYPE
63#undef HTDATATYPE
64
65/**
66 */
67enum specfFlags_e {
68 SPECD_DEFFILEMODE = (1 << 0),
69 SPECD_DEFDIRMODE = (1 << 1),
70 SPECD_DEFUID = (1 << 2),
71 SPECD_DEFGID = (1 << 3),
72 SPECD_DEFVERIFY = (1 << 4),
73
74 SPECD_FILEMODE = (1 << 8),
75 SPECD_DIRMODE = (1 << 9),
76 SPECD_UID = (1 << 10),
77 SPECD_GID = (1 << 11),
78 SPECD_VERIFY = (1 << 12)
79};
80
81typedef rpmFlags specfFlags;
82
83/* internal %files parsing state attributes */
84enum parseAttrs_e {
85 RPMFILE_EXCLUDE = (1 << 16), /*!< from %%exclude */
86 RPMFILE_DOCDIR = (1 << 17), /*!< from %%docdir */
87 RPMFILE_DIR = (1 << 18), /*!< from %%dir */
88 RPMFILE_SPECIALDIR = (1 << 19), /*!< from special %%doc */
89};
90
91/* bits up to 15 (for now) reserved for exported rpmfileAttrs */
92#define PARSEATTR_MASK0x0000ffff 0x0000ffff
93
94/**
95 */
96typedef struct FileListRec_s {
97 struct stat fl_st;
98#define fl_devfl_st.st_dev fl_st.st_dev
99#define fl_inofl_st.st_ino fl_st.st_ino
100#define fl_modefl_st.st_mode fl_st.st_mode
101#define fl_nlinkfl_st.st_nlink fl_st.st_nlink
102#define fl_uidfl_st.st_uid fl_st.st_uid
103#define fl_gidfl_st.st_gid fl_st.st_gid
104#define fl_rdevfl_st.st_rdev fl_st.st_rdev
105#define fl_sizefl_st.st_size fl_st.st_size
106#define fl_mtimefl_st.st_mtim.tv_sec fl_st.st_mtimest_mtim.tv_sec
107
108 char *diskPath; /* get file from here */
109 char *cpioPath; /* filename in cpio archive */
110 rpmsid uname;
111 rpmsid gname;
112 unsigned flags;
113 specfFlags specdFlags; /* which attributes have been explicitly specified. */
114 rpmVerifyFlags verifyFlags;
115 char *langs; /* XXX locales separated with | */
116 char *caps;
117} * FileListRec;
118
119/**
120 */
121typedef struct AttrRec_s {
122 rpmsid ar_fmodestr;
123 rpmsid ar_dmodestr;
124 rpmsid ar_user;
125 rpmsid ar_group;
126 mode_t ar_fmode;
127 mode_t ar_dmode;
128} * AttrRec;
129
130/* list of files */
131static StringBuf check_fileList = NULL((void*)0);
132
133typedef struct FileEntry_s {
134 rpmfileAttrs attrFlags;
135 specfFlags specdFlags;
136 rpmVerifyFlags verifyFlags;
137 struct AttrRec_s ar;
138
139 ARGV_t langs;
140 char *caps;
141
142 /* these are only ever relevant for current entry */
143 unsigned devtype;
144 unsigned devmajor;
145 int devminor;
146 int isDir;
147} * FileEntry;
148
149typedef struct specialDir_s {
150 char * dirname;
151 ARGV_t files;
152 struct AttrRec_s ar;
153 struct AttrRec_s def_ar;
154 rpmFlags sdtype;
155
156 int entriesCount;
157 int entriesAlloced;
158
159 struct {
160 struct FileEntry_s defEntry;
161 struct FileEntry_s curEntry;
162 } *entries;
163
164} * specialDir;
165
166typedef struct FileRecords_s {
167 FileListRec recs;
168 int alloced;
169 int used;
170} * FileRecords;
171
172/**
173 * Package file tree walk data.
174 */
175typedef struct FileList_s {
176 /* global filelist state */
177 char * buildRoot;
178 size_t buildRootLen;
179 int processingFailed;
180 int haveCaps;
181 int largeFiles;
182 ARGV_t docDirs;
183 rpmBuildPkgFlags pkgFlags;
184 rpmstrPool pool;
185
186 /* actual file records */
187 struct FileRecords_s files;
188
189 /* active defaults */
190 struct FileEntry_s def;
191
192 /* current file-entry state */
193 struct FileEntry_s cur;
194} * FileList;
195
196static void nullAttrRec(AttrRec ar)
197{
198 memset(ar, 0, sizeof(*ar));
199}
200
201static void dupAttrRec(const AttrRec oar, AttrRec nar)
202{
203 if (oar == nar)
204 return;
205 *nar = *oar; /* struct assignment */
206}
207
208/* Creates a default $defattr string. Can be used with argvAdd().
209 Caller owns the new string which needs to be freed when done. */
210static char *mkattr(void)
211{
212 char *s = NULL((void*)0);
213 rasprintf(&s, "%s(644,%s,%s,755)", "%defattr", UID_0_USER"root", GID_0_GROUP"root");
214 return s;
215}
216
217static void copyFileEntry(FileEntry src, FileEntry dest)
218{
219 /* Copying struct makes just shallow copy */
220 *dest = *src;
221
222 /* Do also deep copying */
223 if (src->langs != NULL((void*)0)) {
224 dest->langs = argvNew();
225 argvAppend(&dest->langs, src->langs);
226 }
227
228 if (src->caps != NULL((void*)0)) {
229 dest->caps = xstrdup(src->caps)rstrdup((src->caps));
230 }
231}
232
233static void FileEntryFree(FileEntry entry)
234{
235 argvFree(entry->langs);
236 memset(entry, 0, sizeof(*entry));
237}
238
239/**
240 * strtokWithQuotes.
241 * @param s
242 * @param delim
243 */
244static char *strtokWithQuotes(char *s, const char *delim)
245{
246 static char *olds = NULL((void*)0);
247 char *token;
248
249 if (s == NULL((void*)0))
250 s = olds;
251 if (s == NULL((void*)0))
252 return NULL((void*)0);
253
254 /* Skip leading delimiters */
255 s += strspn(s, delim);
256 if (*s == '\0')
257 return NULL((void*)0);
258
259 /* Find the end of the token. */
260 token = s;
261 if (*token == '"') {
262 token++;
263 /* Find next " char */
264 s = strchr(token, '"');
265 } else {
266 s = strpbrk(token, delim);
267 }
268
269 /* Terminate it */
270 if (s == NULL((void*)0)) {
271 /* This token finishes the string */
272 olds = strchr(token, '\0');
273 } else {
274 /* Terminate the token and make olds point past it */
275 *s = '\0';
276 olds = s+1;
277 }
278
279 return token;
280}
281
282/**
283 */
284typedef const struct VFA {
285 const char * attribute;
286 int flag;
287} VFA_t;
288
289/**
290 */
291static VFA_t const verifyAttrs[] = {
292 { "md5", RPMVERIFY_FILEDIGEST },
293 { "filedigest", RPMVERIFY_FILEDIGEST },
294 { "size", RPMVERIFY_FILESIZE },
295 { "link", RPMVERIFY_LINKTO },
296 { "user", RPMVERIFY_USER },
297 { "owner", RPMVERIFY_USER },
298 { "group", RPMVERIFY_GROUP },
299 { "mtime", RPMVERIFY_MTIME },
300 { "mode", RPMVERIFY_MODE },
301 { "rdev", RPMVERIFY_RDEV },
302 { "caps", RPMVERIFY_CAPS },
303 { NULL((void*)0), 0 }
304};
305
306static rpmFlags vfaMatch(VFA_t *attrs, const char *token, rpmFlags *flags)
307{
308 VFA_t *vfa;
309
310 for (vfa = attrs; vfa->attribute != NULL((void*)0); vfa++) {
311 if (rstreq(token, vfa->attribute)) {
312 *flags |= vfa->flag;
313 break;
314 }
315 }
316 return vfa->flag;
317}
318
319/**
320 * Parse %verify and %defverify from file manifest.
321 * @param buf current spec file line
322 * @param def parse for %defverify or %verify?
323 * @param entry file entry data (current or default)
324 * @return RPMRC_OK on success
325 */
326static rpmRC parseForVerify(char * buf, int def, FileEntry entry)
327{
328 char *p, *pe, *q = NULL((void*)0);
329 const char *name = def ? "%defverify" : "%verify";
330 int negated = 0;
331 rpmVerifyFlags verifyFlags = RPMVERIFY_NONE;
332 rpmRC rc = RPMRC_FAIL;
333
334 if ((p = strstr(buf, name)) == NULL((void*)0))
335 return RPMRC_OK;
336
337 for (pe = p; (pe-p) < strlen(name); pe++)
338 *pe = ' ';
339
340 SKIPSPACE(pe){ while (*(pe) && risspace(*(pe))) (pe)++; };
341
342 if (*pe != '(') {
343 rpmlog(RPMLOG_ERR, _("Missing '(' in %s %s\n")dcgettext ("rpm", "Missing '(' in %s %s\n", 5), name, pe);
344 goto exit;
345 }
346
347 /* Bracket %*verify args */
348 *pe++ = ' ';
349 for (p = pe; *pe && *pe != ')'; pe++)
350 {};
351
352 if (*pe == '\0') {
353 rpmlog(RPMLOG_ERR, _("Missing ')' in %s(%s\n")dcgettext ("rpm", "Missing ')' in %s(%s\n", 5), name, p);
354 goto exit;
355 }
356
357 /* Localize. Erase parsed string */
358 q = xmalloc((pe-p) + 1)rmalloc(((pe-p) + 1));
359 rstrlcpy(q, p, (pe-p) + 1);
360 while (p <= pe)
361 *p++ = ' ';
362
363 for (p = q; *p != '\0'; p = pe) {
364 SKIPWHITE(p){while (*(p) && (risspace(*p) || *(p) == ',')) (p)++;
}
;
365 if (*p == '\0')
366 break;
367 pe = p;
368 SKIPNONWHITE(pe){while (*(pe) &&!(risspace(*pe) || *(pe) == ',')) (pe
)++;}
;
369 if (*pe != '\0')
370 *pe++ = '\0';
371
372 if (vfaMatch(verifyAttrs, p, &verifyFlags))
373 continue;
374
375 if (rstreq(p, "not")) {
376 negated ^= 1;
377 } else {
378 rpmlog(RPMLOG_ERR, _("Invalid %s token: %s\n")dcgettext ("rpm", "Invalid %s token: %s\n", 5), name, p);
379 goto exit;
380 }
381 }
382
383 entry->verifyFlags = negated ? ~(verifyFlags) : verifyFlags;
384 entry->specdFlags |= SPECD_VERIFY;
385 rc = RPMRC_OK;
386
387exit:
388 free(q);
389
390 return rc;
391}
392
393static int isAttrDefault(rpmstrPool pool, rpmsid arsid)
394{
395 const char *ars = rpmstrPoolStr(pool, arsid);
396 return (ars && ars[0] == '-' && ars[1] == '\0');
397}
398
399/**
400 * Parse %dev from file manifest.
401 * @param buf current spec file line
402 * @param cur current file entry data
403 * @return RPMRC_OK on success
404 */
405static rpmRC parseForDev(char * buf, FileEntry cur)
406{
407 const char * name;
408 const char * errstr = NULL((void*)0);
409 char *p, *pe, *q = NULL((void*)0);
410 rpmRC rc = RPMRC_FAIL; /* assume error */
411 char *attr_parameters = NULL((void*)0);
412
413 if ((p = strstr(buf, (name = "%dev"))) == NULL((void*)0))
414 return RPMRC_OK;
415
416 for (pe = p; (pe-p) < strlen(name); pe++)
417 *pe = ' ';
418 SKIPSPACE(pe){ while (*(pe) && risspace(*(pe))) (pe)++; };
419
420 if (*pe != '(') {
421 errstr = "'('";
422 goto exit;
423 }
424
425 /* Bracket %dev args */
426 *pe++ = ' ';
427 for (p = pe; *pe && *pe != ')'; pe++)
428 {};
429 if (*pe != ')') {
430 errstr = "')'";
431 goto exit;
432 }
433
434 /* Localize. Erase parsed string */
435 q = xmalloc((pe-p) + 1)rmalloc(((pe-p) + 1));
436 rstrlcpy(q, p, (pe-p) + 1);
437
438 attr_parameters = xmalloc((pe-p) + 1)rmalloc(((pe-p) + 1));
439 rstrlcpy(attr_parameters, p, (pe-p) + 1);
440
441 while (p <= pe)
442 *p++ = ' ';
443
444 p = q; SKIPWHITE(p){while (*(p) && (risspace(*p) || *(p) == ',')) (p)++;
}
;
445 pe = p; SKIPNONWHITE(pe){while (*(pe) &&!(risspace(*pe) || *(pe) == ',')) (pe
)++;}
; if (*pe != '\0') *pe++ = '\0';
446 if (*p == 'b')
447 cur->devtype = 'b';
448 else if (*p == 'c')
449 cur->devtype = 'c';
450 else {
451 errstr = "devtype";
452 goto exit;
453 }
454
455 p = pe; SKIPWHITE(p){while (*(p) && (risspace(*p) || *(p) == ',')) (p)++;
}
;
456 pe = p; SKIPNONWHITE(pe){while (*(pe) &&!(risspace(*pe) || *(pe) == ',')) (pe
)++;}
; if (*pe != '\0') *pe = '\0';
457 for (pe = p; *pe && risdigit(*pe); pe++)
458 {} ;
459 if (*pe == '\0') {
460 cur->devmajor = atoi(p);
461 if (!(cur->devmajor >= 0 && cur->devmajor < 256)) {
462 errstr = "devmajor";
463 goto exit;
464 }
465 pe++;
466 } else {
467 errstr = "devmajor";
468 goto exit;
469 }
470
471 p = pe; SKIPWHITE(p){while (*(p) && (risspace(*p) || *(p) == ',')) (p)++;
}
;
472 pe = p; SKIPNONWHITE(pe){while (*(pe) &&!(risspace(*pe) || *(pe) == ',')) (pe
)++;}
; if (*pe != '\0') *pe = '\0';
473 for (pe = p; *pe && risdigit(*pe); pe++)
474 {} ;
475 if (*pe == '\0') {
476 cur->devminor = atoi(p);
477 if (!(cur->devminor >= 0 && cur->devminor < 256)) {
478 errstr = "devminor";
479 goto exit;
480 }
481 } else {
482 errstr = "devminor";
483 goto exit;
484 }
485
486 rc = RPMRC_OK;
487
488exit:
489 if (rc) {
490 rpmlog(RPMLOG_ERR, _("Missing %s in %s(%s)\n")dcgettext ("rpm", "Missing %s in %s(%s)\n", 5), errstr, name, attr_parameters);
491 }
492 free(attr_parameters);
493 free(q);
494 return rc;
495}
496
497/**
498 * Parse %attr and %defattr from file manifest.
499 * @param pool string pool
500 * @param buf current spec file line
501 * @param def parse for %defattr or %attr?
502 * @param entry file entry data (current / default)
503 * @return 0 on success
504 */
505static rpmRC parseForAttr(rpmstrPool pool, char * buf, int def, FileEntry entry)
506{
507 const char *name = def ? "%defattr" : "%attr";
508 char *p, *pe, *q = NULL((void*)0);
509 char *attr_parameters = NULL((void*)0);
510 int x;
511 struct AttrRec_s arbuf;
512 AttrRec ar = &arbuf;
513 rpmRC rc = RPMRC_FAIL;
514
515 if ((p = strstr(buf, name)) == NULL((void*)0))
516 return RPMRC_OK;
517
518 for (pe = p; (pe-p) < strlen(name); pe++)
519 *pe = ' ';
520
521 SKIPSPACE(pe){ while (*(pe) && risspace(*(pe))) (pe)++; };
522
523 if (*pe != '(') {
524 rpmlog(RPMLOG_ERR, _("Missing '(' in %s %s\n")dcgettext ("rpm", "Missing '(' in %s %s\n", 5), name, pe);
525 goto exit;
526 }
527
528 /* Bracket %*attr args */
529 *pe++ = ' ';
530 for (p = pe; *pe && *pe != ')'; pe++)
531 {};
532
533 if (def) { /* %defattr */
534 char *r = pe;
535 r++;
536 SKIPSPACE(r){ while (*(r) && risspace(*(r))) (r)++; };
537 if (*r != '\0') {
538 rpmlog(RPMLOG_ERR,
539 _("Non-white space follows %s(): %s\n")dcgettext ("rpm", "Non-white space follows %s(): %s\n", 5), name, r);
540 goto exit;
541 }
542 }
543
544 /* Localize. Erase parsed string */
545 q = xmalloc((pe-p) + 1)rmalloc(((pe-p) + 1));
546 rstrlcpy(q, p, (pe-p) + 1);
547
548 attr_parameters = xmalloc((pe-p) + 1)rmalloc(((pe-p) + 1));
549 rstrlcpy(attr_parameters, p, (pe-p) + 1);
550
551 while (p <= pe)
552 *p++ = ' ';
553
554 nullAttrRec(ar);
555
556 p = q; SKIPWHITE(p){while (*(p) && (risspace(*p) || *(p) == ',')) (p)++;
}
;
557 if (*p != '\0') {
558 pe = p; SKIPNONWHITE(pe){while (*(pe) &&!(risspace(*pe) || *(pe) == ',')) (pe
)++;}
; if (*pe != '\0') *pe++ = '\0';
559 ar->ar_fmodestr = rpmstrPoolId(pool, p, 1);
560 p = pe; SKIPWHITE(p){while (*(p) && (risspace(*p) || *(p) == ',')) (p)++;
}
;
561 }
562 if (*p != '\0') {
563 pe = p; SKIPNONWHITE(pe){while (*(pe) &&!(risspace(*pe) || *(pe) == ',')) (pe
)++;}
; if (*pe != '\0') *pe++ = '\0';
564 ar->ar_user = rpmstrPoolId(pool, p, 1);
565 p = pe; SKIPWHITE(p){while (*(p) && (risspace(*p) || *(p) == ',')) (p)++;
}
;
566 }
567 if (*p != '\0') {
568 pe = p; SKIPNONWHITE(pe){while (*(pe) &&!(risspace(*pe) || *(pe) == ',')) (pe
)++;}
; if (*pe != '\0') *pe++ = '\0';
569 ar->ar_group = rpmstrPoolId(pool, p, 1);
570 p = pe; SKIPWHITE(p){while (*(p) && (risspace(*p) || *(p) == ',')) (p)++;
}
;
571 }
572 if (*p != '\0' && def) { /* %defattr */
573 pe = p; SKIPNONWHITE(pe){while (*(pe) &&!(risspace(*pe) || *(pe) == ',')) (pe
)++;}
; if (*pe != '\0') *pe++ = '\0';
574 ar->ar_dmodestr = rpmstrPoolId(pool, p, 1);
575 p = pe; SKIPWHITE(p){while (*(p) && (risspace(*p) || *(p) == ',')) (p)++;
}
;
576 }
577
578 if (!(ar->ar_fmodestr && ar->ar_user && ar->ar_group) || *p != '\0') {
579 rpmlog(RPMLOG_ERR, _("Bad syntax: %s(%s)\n")dcgettext ("rpm", "Bad syntax: %s(%s)\n", 5), name, attr_parameters);
580 goto exit;
581 }
582
583 /* Do a quick test on the mode argument and adjust for "-" */
584 if (ar->ar_fmodestr && !isAttrDefault(pool, ar->ar_fmodestr)) {
585 unsigned int ui;
586 x = sscanf(rpmstrPoolStr(pool, ar->ar_fmodestr), "%o", &ui);
587 if ((x == 0) || (ar->ar_fmode & ~MYALLPERMS07777)) {
588 rpmlog(RPMLOG_ERR, _("Bad mode spec: %s(%s)\n")dcgettext ("rpm", "Bad mode spec: %s(%s)\n", 5), name, attr_parameters);
589 goto exit;
590 }
591 ar->ar_fmode = ui;
592 } else {
593 ar->ar_fmodestr = 0;
594 }
595
596 if (ar->ar_dmodestr && !isAttrDefault(pool, ar->ar_dmodestr)) {
597 unsigned int ui;
598 x = sscanf(rpmstrPoolStr(pool, ar->ar_dmodestr), "%o", &ui);
599 if ((x == 0) || (ar->ar_dmode & ~MYALLPERMS07777)) {
600 rpmlog(RPMLOG_ERR, _("Bad dirmode spec: %s(%s)\n")dcgettext ("rpm", "Bad dirmode spec: %s(%s)\n", 5), name, attr_parameters);
601 goto exit;
602 }
603 ar->ar_dmode = ui;
604 } else {
605 ar->ar_dmodestr = 0;
606 }
607
608 if (!(ar->ar_user && !isAttrDefault(pool, ar->ar_user))) {
609 ar->ar_user = 0;
610 }
611
612 if (!(ar->ar_group && !isAttrDefault(pool, ar->ar_group))) {
613 ar->ar_group = 0;
614 }
615
616 dupAttrRec(ar, &(entry->ar));
617
618 /* XXX fix all this */
619 entry->specdFlags |= SPECD_UID | SPECD_GID | SPECD_FILEMODE | SPECD_DIRMODE;
620 rc = RPMRC_OK;
621
622exit:
623 free(q);
624 free(attr_parameters);
625
626 return rc;
627}
628
629static VFA_t const configAttrs[] = {
630 { "missingok", RPMFILE_MISSINGOK },
631 { "noreplace", RPMFILE_NOREPLACE },
632 { NULL((void*)0), 0 }
633};
634
635/**
636 * Parse %config from file manifest.
637 * @param buf current spec file line
638 * @param cur current file entry data
639 * @return RPMRC_OK on success
640 */
641static rpmRC parseForConfig(char * buf, FileEntry cur)
642{
643 char *p, *pe, *q = NULL((void*)0);
644 const char *name;
645 rpmRC rc = RPMRC_FAIL;
646
647 if ((p = strstr(buf, (name = "%config"))) == NULL((void*)0))
648 return RPMRC_OK;
649
650 cur->attrFlags |= RPMFILE_CONFIG;
651
652 /* Erase "%config" token. */
653 for (pe = p; (pe-p) < strlen(name); pe++)
654 *pe = ' ';
655 SKIPSPACE(pe){ while (*(pe) && risspace(*(pe))) (pe)++; };
656 if (*pe != '(')
657 return RPMRC_OK;
658
659 /* Bracket %config args */
660 *pe++ = ' ';
661 for (p = pe; *pe && *pe != ')'; pe++)
662 {};
663
664 if (*pe == '\0') {
665 rpmlog(RPMLOG_ERR, _("Missing ')' in %s(%s\n")dcgettext ("rpm", "Missing ')' in %s(%s\n", 5), name, p);
666 goto exit;
667 }
668
669 /* Localize. Erase parsed string. */
670 q = xmalloc((pe-p) + 1)rmalloc(((pe-p) + 1));
671 rstrlcpy(q, p, (pe-p) + 1);
672 while (p <= pe)
673 *p++ = ' ';
674
675 for (p = q; *p != '\0'; p = pe) {
676 SKIPWHITE(p){while (*(p) && (risspace(*p) || *(p) == ',')) (p)++;
}
;
677 if (*p == '\0')
678 break;
679 pe = p;
680 SKIPNONWHITE(pe){while (*(pe) &&!(risspace(*pe) || *(pe) == ',')) (pe
)++;}
;
681 if (*pe != '\0')
682 *pe++ = '\0';
683 if (!vfaMatch(configAttrs, p, &(cur->attrFlags))) {
684 rpmlog(RPMLOG_ERR, _("Invalid %s token: %s\n")dcgettext ("rpm", "Invalid %s token: %s\n", 5), name, p);
685 goto exit;
686 }
687 }
688 rc = RPMRC_OK;
689
690exit:
691 free(q);
692
693 return rc;
694}
695
696static rpmRC addLang(ARGV_t *av, const char *lang, size_t n, const char *ent)
697{
698 rpmRC rc = RPMRC_FAIL;
699 char lbuf[n + 1];
700 rstrlcpy(lbuf, lang, sizeof(lbuf));
701 SKIPWHITE(ent){while (*(ent) && (risspace(*ent) || *(ent) == ',')) (
ent)++;}
;
702
703 /* Sanity check locale length */
704 if (n < 1 || (n == 1 && *lang != 'C') || n >= 32) {
705 rpmlog(RPMLOG_ERR, _("Unusual locale length: \"%s\" in %%lang(%s)\n")dcgettext ("rpm", "Unusual locale length: \"%s\" in %%lang(%s)\n"
, 5)
,
706 lbuf, ent);
707 goto exit;
708 }
709
710 /* Check for duplicate locales */
711 if (argvSearch(*av, lbuf, NULL((void*)0))) {
712 rpmlog(RPMLOG_WARNING, _("Duplicate locale %s in %%lang(%s)\n")dcgettext ("rpm", "Duplicate locale %s in %%lang(%s)\n", 5),
713 lbuf, ent);
714 } else {
715 argvAdd(av, lbuf);
716 argvSort(*av, NULL((void*)0));
717 }
718 rc = RPMRC_OK;
719
720exit:
721 return rc;
722}
723
724/**
725 * Parse %lang from file manifest.
726 * @param buf current spec file line
727 * @param cur current file entry data
728 * @return RPMRC_OK on success
729 */
730static rpmRC parseForLang(char * buf, FileEntry cur)
731{
732 char *p, *pe, *q = NULL((void*)0);
733 const char *name;
734 rpmRC rc = RPMRC_FAIL;
735
736 while ((p = strstr(buf, (name = "%lang"))) != NULL((void*)0)) {
737
738 for (pe = p; (pe-p) < strlen(name); pe++)
739 *pe = ' ';
740 SKIPSPACE(pe){ while (*(pe) && risspace(*(pe))) (pe)++; };
741
742 if (*pe != '(') {
743 rpmlog(RPMLOG_ERR, _("Missing '(' in %s %s\n")dcgettext ("rpm", "Missing '(' in %s %s\n", 5), name, pe);
744 goto exit;
745 }
746
747 /* Bracket %lang args */
748 *pe = ' ';
749 for (pe = p; *pe && *pe != ')'; pe++)
750 {};
751
752 if (*pe == '\0') {
753 rpmlog(RPMLOG_ERR, _("Missing ')' in %s(%s\n")dcgettext ("rpm", "Missing ')' in %s(%s\n", 5), name, p);
754 goto exit;
755 }
756
757 /* Localize. Erase parsed string. */
758 q = xmalloc((pe-p) + 1)rmalloc(((pe-p) + 1));
759 rstrlcpy(q, p, (pe-p) + 1);
760 while (p <= pe)
761 *p++ = ' ';
762
763 /* Parse multiple arguments from %lang */
764 for (p = q; *p != '\0'; p = pe) {
765 SKIPWHITE(p){while (*(p) && (risspace(*p) || *(p) == ',')) (p)++;
}
;
766 pe = p;
767 SKIPNONWHITE(pe){while (*(pe) &&!(risspace(*pe) || *(pe) == ',')) (pe
)++;}
;
768
769 if (addLang(&(cur->langs), p, (pe-p), q))
770 goto exit;
771
772 if (*pe == ',') pe++; /* skip , if present */
773 }
774 }
775
776 rc = RPMRC_OK;
777
778exit:
779 free(q);
780
781 return rc;
782}
783
784/**
785 * Parse %caps from file manifest.
786 * @param buf current spec file line
787 * @param cur current file entry data
788 * @return RPMRC_OK on success
789 */
790static rpmRC parseForCaps(char * buf, FileEntry cur)
791{
792 char *p, *pe, *q = NULL((void*)0);
793 const char *name;
794 rpmRC rc = RPMRC_FAIL;
795
796 if ((p = strstr(buf, (name = "%caps"))) == NULL((void*)0))
797 return RPMRC_OK;
798
799 /* Erase "%caps" token. */
800 for (pe = p; (pe-p) < strlen(name); pe++)
801 *pe = ' ';
802 SKIPSPACE(pe){ while (*(pe) && risspace(*(pe))) (pe)++; };
803 if (*pe != '(')
804 return RPMRC_OK;
805
806 /* Bracket %caps args */
807 *pe++ = ' ';
808 for (p = pe; *pe && *pe != ')'; pe++)
809 {};
810
811 if (*pe == '\0') {
812 rpmlog(RPMLOG_ERR, _("Missing ')' in %s(%s\n")dcgettext ("rpm", "Missing ')' in %s(%s\n", 5), name, p);
813 goto exit;
814 }
815
816 /* Localize. Erase parsed string. */
817 q = xmalloc((pe-p) + 1)rmalloc(((pe-p) + 1));
818 rstrlcpy(q, p, (pe-p) + 1);
819 while (p <= pe)
820 *p++ = ' ';
821
822#if WITH_CAP
823 {
824 char *captxt = NULL((void*)0);
825 cap_t fcaps = cap_from_text(q);
826 if (fcaps == NULL((void*)0)) {
827 rpmlog(RPMLOG_ERR, _("Invalid capability: %s\n")dcgettext ("rpm", "Invalid capability: %s\n", 5), q);
828 goto exit;
829 }
830 /* run our string through cap_to_text() to get libcap presentation */
831 captxt = cap_to_text(fcaps, NULL((void*)0));
832 cur->caps = xstrdup(captxt)rstrdup((captxt));
833 cap_free(captxt);
834 cap_free(fcaps);
835 }
836#else
837 rpmlog(RPMLOG_ERR, _("File capability support not built in\n")dcgettext ("rpm", "File capability support not built in\n", 5
)
);
838 goto exit;
839#endif
840
841 rc = RPMRC_OK;
842
843exit:
844 free(q);
845
846 return rc;
847}
848/**
849 */
850static VFA_t const virtualAttrs[] = {
851 { "%dir", RPMFILE_DIR },
852 { "%docdir", RPMFILE_DOCDIR },
853 { "%doc", RPMFILE_DOC },
854 { "%ghost", RPMFILE_GHOST },
855 { "%exclude", RPMFILE_EXCLUDE },
856 { "%readme", RPMFILE_README },
857 { "%license", RPMFILE_LICENSE },
858 { "%pubkey", RPMFILE_PUBKEY },
859 { "%missingok", RPMFILE_MISSINGOK },
860 { NULL((void*)0), 0 }
861};
862
863/**
864 * Parse simple attributes (e.g. %dir) from file manifest.
865 * @param buf current spec file line
866 * @param cur current file entry data
867 * @retval *fileNames file names
868 * @return RPMRC_OK on success
869 */
870static rpmRC parseForSimple(char * buf, FileEntry cur, ARGV_t * fileNames)
871{
872 char *s, *t;
873 rpmRC res = RPMRC_OK;
874 int allow_relative = (RPMFILE_PUBKEY|RPMFILE_DOC|RPMFILE_LICENSE);
875
876 t = buf;
877 while ((s = strtokWithQuotes(t, " \t\n")) != NULL((void*)0)) {
878 t = NULL((void*)0);
879
880 /* Set flags for virtual file attributes */
881 if (vfaMatch(virtualAttrs, s, &(cur->attrFlags)))
882 continue;
883
884 /* normally paths need to be absolute */
885 if (*s != '/') {
886 if (!(cur->attrFlags & allow_relative)) {
887 rpmlog(RPMLOG_ERR, _("File must begin with \"/\": %s\n")dcgettext ("rpm", "File must begin with \"/\": %s\n", 5), s);
888 res = RPMRC_FAIL;
889 continue;
890 }
891 /* non-absolute %doc and %license paths are special */
892 if (cur->attrFlags & (RPMFILE_DOC | RPMFILE_LICENSE))
893 cur->attrFlags |= RPMFILE_SPECIALDIR;
894 }
895 argvAdd(fileNames, s);
896 }
897
898 return res;
899}
900
901/**
902 */
903static int compareFileListRecs(const void * ap, const void * bp)
904{
905 const char *a = ((FileListRec)ap)->cpioPath;
906 const char *b = ((FileListRec)bp)->cpioPath;
907 return strcmp(a, b);
908}
909
910/**
911 * Test if file is located in a %docdir.
912 * @param docDirs doc dirs
913 * @param fileName file path
914 * @return 1 if doc file, 0 if not
915 */
916static int isDoc(ARGV_const_t docDirs, const char * fileName)
917{
918 size_t k, l;
919
920 k = strlen(fileName);
921 for (ARGV_const_t dd = docDirs; *dd; dd++) {
922 l = strlen(*dd);
923 if (l < k && rstreqn(fileName, *dd, l) && fileName[l] == '/')
924 return 1;
925 }
926 return 0;
927}
928
929static int isHardLink(FileListRec flp, FileListRec tlp)
930{
931 return ((S_ISREG(flp->fl_mode)((((flp->fl_st.st_mode)) & 0170000) == (0100000)) && S_ISREG(tlp->fl_mode)((((tlp->fl_st.st_mode)) & 0170000) == (0100000))) &&
932 ((flp->fl_nlinkfl_st.st_nlink > 1) && (flp->fl_nlinkfl_st.st_nlink == tlp->fl_nlinkfl_st.st_nlink)) &&
933 (flp->fl_inofl_st.st_ino == tlp->fl_inofl_st.st_ino) &&
934 (flp->fl_devfl_st.st_dev == tlp->fl_devfl_st.st_dev));
935}
936
937/**
938 * Verify that file attributes scope over hardlinks correctly.
939 * If partial hardlink sets are possible, then add tracking dependency.
940 * @param files package file records
941 * @return 1 if partial hardlink sets can exist, 0 otherwise.
942 */
943static int checkHardLinks(FileRecords files)
944{
945 FileListRec ilp, jlp;
946 int i, j;
947
948 for (i = 0; i < files->used; i++) {
949 ilp = files->recs + i;
950 if (!(S_ISREG(ilp->fl_mode)((((ilp->fl_st.st_mode)) & 0170000) == (0100000)) && ilp->fl_nlinkfl_st.st_nlink > 1))
951 continue;
952
953 for (j = i + 1; j < files->used; j++) {
954 jlp = files->recs + j;
955 if (isHardLink(ilp, jlp)) {
956 return 1;
957 }
958 }
959 }
960 return 0;
961}
962
963static int seenHardLink(FileRecords files, FileListRec flp, rpm_ino_t *fileid)
964{
965 for (FileListRec ilp = files->recs; ilp < flp; ilp++) {
966 if (isHardLink(flp, ilp)) {
967 *fileid = ilp - files->recs;
968 return 1;
969 }
970 }
971 return 0;
972}
973
974/**
975 * Add file entries to header.
976 * @todo Should directories have %doc/%config attributes? (#14531)
977 * @todo Remove RPMTAG_OLDFILENAMES, add dirname/basename instead.
978 * @param fl package file tree walk data
979 * @param pkg (sub) package
980 * @param isSrc pass 1 for source packages 0 otherwise
981 */
982static void genCpioListAndHeader(FileList fl, Package pkg, int isSrc)
983{
984 FileListRec flp;
985 char buf[BUFSIZ8192];
986 int i, npaths = 0;
987 uint32_t defaultalgo = PGPHASHALGO_MD5, digestalgo;
988 rpm_loff_t totalFileSize = 0;
989 Header h = pkg->header; /* just a shortcut */
990 int override_date = 0;
991 time_t source_date_epoch;
992 char *srcdate = getenv("SOURCE_DATE_EPOCH")secure_getenv("SOURCE_DATE_EPOCH");
993
994 /* Limit the maximum date to SOURCE_DATE_EPOCH if defined
995 * similar to the tar --clamp-mtime option
996 * https://reproducible-builds.org/specs/source-date-epoch/
997 */
998 if (srcdate && rpmExpandNumeric("%{?clamp_mtime_to_source_date_epoch}")) {
999 char *endptr;
1000 errno(*__errno_location ()) = 0;
1001 source_date_epoch = strtol(srcdate, &endptr, 10);
1002 if (srcdate == endptr || *endptr || errno(*__errno_location ()) != 0) {
1003 rpmlog(RPMLOG_ERR, _("unable to parse %s=%s\n")dcgettext ("rpm", "unable to parse %s=%s\n", 5), "SOURCE_DATE_EPOCH", srcdate);
1004 exit(28);
1005 }
1006 override_date = 1;
1007 }
1008
1009 /*
1010 * See if non-md5 file digest algorithm is requested. If not
1011 * specified, quietly assume md5. Otherwise check if supported type.
1012 */
1013 digestalgo = rpmExpandNumeric(isSrc ? "%{_source_filedigest_algorithm}" :
1014 "%{_binary_filedigest_algorithm}");
1015 if (digestalgo == 0) {
1016 digestalgo = defaultalgo;
1017 }
1018
1019 if (rpmDigestLength(digestalgo) == 0) {
1020 rpmlog(RPMLOG_WARNING,
1021 _("Unknown file digest algorithm %u, falling back to MD5\n")dcgettext ("rpm", "Unknown file digest algorithm %u, falling back to MD5\n"
, 5)
,
1022 digestalgo);
1023 digestalgo = defaultalgo;
1024 }
1025
1026 /* Adjust paths if needed */
1027 if (!isSrc && pkg->removePostfixes) {
1028 pkg->fileRenameMap = fileRenameHashCreate(fl->files.used,
1029 rstrhash, strcmp,
1030 (fileRenameHashFreeKey)rfree, (fileRenameHashFreeData)rfree);
1031 for (i = 0, flp = fl->files.recs; i < fl->files.used; i++, flp++) {
1032 char * cpiopath = flp->cpioPath;
1033 char * cpiopath_orig = xstrdup(cpiopath)rstrdup((cpiopath));
1034
1035 for (ARGV_const_t postfix_p = pkg->removePostfixes; *postfix_p; postfix_p++) {
1036 int len = strlen(*postfix_p);
1037 int plen = strlen(cpiopath);
1038 if (len <= plen && !strncmp(cpiopath+plen-len, *postfix_p, len)) {
1039 cpiopath[plen-len] = '\0';
1040 if (plen-len > 0 && cpiopath[plen-len-1] == '/') {
1041 cpiopath[plen-len-1] = '\0';
1042 }
1043 }
1044 }
1045 if (strcmp(cpiopath_orig, cpiopath))
1046 fileRenameHashAddEntry(pkg->fileRenameMap, xstrdup(cpiopath)rstrdup((cpiopath)), cpiopath_orig);
1047 else
1048 _free(cpiopath_orig)rfree((cpiopath_orig));
1049 }
1050 }
1051
1052 /* Sort the big list */
1053 qsort(fl->files.recs, fl->files.used,
1054 sizeof(*(fl->files.recs)), compareFileListRecs);
1055
1056 pkg->dpaths = xmalloc((fl->files.used + 1) * sizeof(*pkg->dpaths))rmalloc(((fl->files.used + 1) * sizeof(*pkg->dpaths)));
1057
1058 /* Generate the header. */
1059 for (i = 0, flp = fl->files.recs; i < fl->files.used; i++, flp++) {
1060 rpm_ino_t fileid = flp - fl->files.recs;
1061
1062 /* Merge duplicate entries. */
1063 while (i < (fl->files.used - 1) &&
1064 rstreq(flp->cpioPath, flp[1].cpioPath)) {
1065
1066 /* Two entries for the same file found, merge the entries. */
1067 /* Note that an %exclude is a duplication of a file reference */
1068
1069 /* file flags */
1070 flp[1].flags |= flp->flags;
1071
1072 if (!(flp[1].flags & RPMFILE_EXCLUDE))
1073 rpmlog(RPMLOG_WARNING, _("File listed twice: %s\n")dcgettext ("rpm", "File listed twice: %s\n", 5),
1074 flp->cpioPath);
1075
1076 /* file mode */
1077 if (S_ISDIR(flp->fl_mode)((((flp->fl_st.st_mode)) & 0170000) == (0040000))) {
1078 if ((flp[1].specdFlags & (SPECD_DIRMODE | SPECD_DEFDIRMODE)) <
1079 (flp->specdFlags & (SPECD_DIRMODE | SPECD_DEFDIRMODE)))
1080 flp[1].fl_modefl_st.st_mode = flp->fl_modefl_st.st_mode;
1081 } else {
1082 if ((flp[1].specdFlags & (SPECD_FILEMODE | SPECD_DEFFILEMODE)) <
1083 (flp->specdFlags & (SPECD_FILEMODE | SPECD_DEFFILEMODE)))
1084 flp[1].fl_modefl_st.st_mode = flp->fl_modefl_st.st_mode;
1085 }
1086
1087 /* uid */
1088 if ((flp[1].specdFlags & (SPECD_UID | SPECD_DEFUID)) <
1089 (flp->specdFlags & (SPECD_UID | SPECD_DEFUID)))
1090 {
1091 flp[1].fl_uidfl_st.st_uid = flp->fl_uidfl_st.st_uid;
1092 flp[1].uname = flp->uname;
1093 }
1094
1095 /* gid */
1096 if ((flp[1].specdFlags & (SPECD_GID | SPECD_DEFGID)) <
1097 (flp->specdFlags & (SPECD_GID | SPECD_DEFGID)))
1098 {
1099 flp[1].fl_gidfl_st.st_gid = flp->fl_gidfl_st.st_gid;
1100 flp[1].gname = flp->gname;
1101 }
1102
1103 /* verify flags */
1104 if ((flp[1].specdFlags & (SPECD_VERIFY | SPECD_DEFVERIFY)) <
1105 (flp->specdFlags & (SPECD_VERIFY | SPECD_DEFVERIFY)))
1106 flp[1].verifyFlags = flp->verifyFlags;
1107
1108 /* XXX to-do: language */
1109
1110 flp++; i++;
1111 }
1112
1113 /* Skip files that were marked with %exclude. */
1114 if (flp->flags & RPMFILE_EXCLUDE)
1115 {
1116 argvAdd(&pkg->fileExcludeList, flp->cpioPath);
1117 continue;
1118 }
1119
1120 /* Collect on-disk paths for archive creation */
1121 pkg->dpaths[npaths++] = xstrdup(flp->diskPath)rstrdup((flp->diskPath));
1122
1123 headerPutString(h, RPMTAG_OLDFILENAMES, flp->cpioPath);
1124 headerPutString(h, RPMTAG_FILEUSERNAME,
1125 rpmstrPoolStr(fl->pool, flp->uname));
1126 headerPutString(h, RPMTAG_FILEGROUPNAME,
1127 rpmstrPoolStr(fl->pool, flp->gname));
1128
1129 /* Only use 64bit filesizes tag if required. */
1130 if (fl->largeFiles) {
1131 rpm_loff_t rsize64 = (rpm_loff_t)flp->fl_sizefl_st.st_size;
1132 headerPutUint64(h, RPMTAG_LONGFILESIZES, &rsize64, 1);
1133 (void) rpmlibNeedsFeature(pkg, "LargeFiles", "4.12.0-1");
1134 } else {
1135 rpm_off_t rsize32 = (rpm_off_t)flp->fl_sizefl_st.st_size;
1136 headerPutUint32(h, RPMTAG_FILESIZES, &rsize32, 1);
1137 }
1138 /* Excludes and dupes have been filtered out by now. */
1139 if (S_ISREG(flp->fl_mode)((((flp->fl_st.st_mode)) & 0170000) == (0100000))) {
1140 if (flp->fl_nlinkfl_st.st_nlink == 1 || !seenHardLink(&fl->files, flp, &fileid)) {
1141 totalFileSize += flp->fl_sizefl_st.st_size;
1142 }
1143 }
1144
1145 if (override_date && flp->fl_mtimefl_st.st_mtim.tv_sec > source_date_epoch) {
1146 flp->fl_mtimefl_st.st_mtim.tv_sec = source_date_epoch;
1147 }
1148 /*
1149 * For items whose size varies between systems, always explicitly
1150 * cast to the header type before inserting.
1151 * TODO: check and warn if header type overflows for each case.
1152 */
1153 { rpm_time_t rtime = (rpm_time_t) flp->fl_mtimefl_st.st_mtim.tv_sec;
1154 headerPutUint32(h, RPMTAG_FILEMTIMES, &rtime, 1);
1155 }
1156
1157 { rpm_mode_t rmode = (rpm_mode_t) flp->fl_modefl_st.st_mode;
1158 headerPutUint16(h, RPMTAG_FILEMODES, &rmode, 1);
1159 }
1160
1161 { rpm_rdev_t rrdev = (rpm_rdev_t) flp->fl_rdevfl_st.st_rdev;
1162 headerPutUint16(h, RPMTAG_FILERDEVS, &rrdev, 1);
1163 }
1164
1165 /*
1166 * To allow rpmbuild to work on filesystems with 64bit inodes numbers,
1167 * remap them into 32bit integers based on filelist index, just
1168 * preserving semantics for determining hardlinks.
1169 * Start at 1 as inode zero as that could be considered as an error.
1170 * Since we flatten all the inodes to appear within a single fs,
1171 * we also need to flatten the devices.
1172 */
1173 { rpm_ino_t rino = fileid + 1;
1174 rpm_dev_t rdev = flp->fl_devfl_st.st_dev ? 1 : 0;
1175 headerPutUint32(h, RPMTAG_FILEINODES, &rino, 1);
1176 headerPutUint32(h, RPMTAG_FILEDEVICES, &rdev, 1);
1177 }
1178
1179 headerPutString(h, RPMTAG_FILELANGS, flp->langs);
1180
1181 if (fl->haveCaps) {
1182 headerPutString(h, RPMTAG_FILECAPS, flp->caps);
1183 }
1184
1185 buf[0] = '\0';
1186 if (S_ISREG(flp->fl_mode)((((flp->fl_st.st_mode)) & 0170000) == (0100000)) && !(flp->flags & RPMFILE_GHOST))
1187 (void) rpmDoDigest(digestalgo, flp->diskPath, 1,
1188 (unsigned char *)buf, NULL((void*)0));
1189 headerPutString(h, RPMTAG_FILEDIGESTS, buf);
1190
1191 buf[0] = '\0';
1192 if (S_ISLNK(flp->fl_mode)((((flp->fl_st.st_mode)) & 0170000) == (0120000))) {
1193 ssize_t llen = readlink(flp->diskPath, buf, BUFSIZ8192-1);
1194 if (llen == -1) {
1195 rpmlog(RPMLOG_ERR, _("reading symlink %s failed: %s\n")dcgettext ("rpm", "reading symlink %s failed: %s\n", 5),
1196 flp->diskPath, strerror(errno(*__errno_location ())));
1197 fl->processingFailed = 1;
1198 } else {
1199 buf[llen] = '\0';
1200 if (buf[0] == '/' && !rstreq(fl->buildRoot, "/") &&
1201 rstreqn(buf, fl->buildRoot, fl->buildRootLen)) {
1202 rpmlog(RPMLOG_ERR,
1203 _("Symlink points to BuildRoot: %s -> %s\n")dcgettext ("rpm", "Symlink points to BuildRoot: %s -> %s\n"
, 5)
,
1204 flp->cpioPath, buf);
1205 fl->processingFailed = 1;
1206 }
1207 }
1208 }
1209 headerPutString(h, RPMTAG_FILELINKTOS, buf);
1210
1211 if (flp->flags & RPMFILE_GHOST) {
1212 flp->verifyFlags &= ~(RPMVERIFY_FILEDIGEST | RPMVERIFY_FILESIZE |
1213 RPMVERIFY_LINKTO | RPMVERIFY_MTIME);
1214 }
1215 headerPutUint32(h, RPMTAG_FILEVERIFYFLAGS, &(flp->verifyFlags),1);
1216
1217 if (!isSrc && isDoc(fl->docDirs, flp->cpioPath))
1218 flp->flags |= RPMFILE_DOC;
1219 /* XXX Should directories have %doc/%config attributes? (#14531) */
1220 if (S_ISDIR(flp->fl_mode)((((flp->fl_st.st_mode)) & 0170000) == (0040000)))
1221 flp->flags &= ~(RPMFILE_CONFIG|RPMFILE_DOC|RPMFILE_LICENSE);
1222 /* Strip internal parse data */
1223 flp->flags &= PARSEATTR_MASK0x0000ffff;
1224
1225 headerPutUint32(h, RPMTAG_FILEFLAGS, &(flp->flags) ,1);
1226 }
1227 pkg->dpaths[npaths] = NULL((void*)0);
1228
1229 if (totalFileSize < UINT32_MAX(4294967295U)) {
1230 rpm_off_t totalsize = totalFileSize;
1231 headerPutUint32(h, RPMTAG_SIZE, &totalsize, 1);
1232 } else {
1233 rpm_loff_t totalsize = totalFileSize;
1234 headerPutUint64(h, RPMTAG_LONGSIZE, &totalsize, 1);
1235 }
1236
1237 if (digestalgo != defaultalgo) {
1238 headerPutUint32(h, RPMTAG_FILEDIGESTALGO, &digestalgo, 1);
1239 rpmlibNeedsFeature(pkg, "FileDigests", "4.6.0-1");
1240 }
1241
1242 if (fl->haveCaps) {
1243 rpmlibNeedsFeature(pkg, "FileCaps", "4.6.1-1");
1244 }
1245
1246 if (!isSrc && !rpmExpandNumeric("%{_noPayloadPrefix}"))
1247 (void) rpmlibNeedsFeature(pkg, "PayloadFilesHavePrefix", "4.0-1");
1248
1249 /* rpmfiNew() only groks compressed filelists */
1250 headerConvert(h, HEADERCONV_COMPRESSFILELIST);
1251 pkg->cpioList = rpmfilesNew(NULL((void*)0), h, RPMTAG_BASENAMES,
1252 (RPMFI_NOFILEUSER|RPMFI_NOFILEGROUP));
1253
1254 if (pkg->cpioList == NULL((void*)0) || rpmfilesFC(pkg->cpioList) != npaths) {
1255 fl->processingFailed = 1;
1256 }
1257
1258 if (fl->pkgFlags & RPMBUILD_PKG_NODIRTOKENS) {
1259 /* Uncompress filelist if legacy format requested */
1260 headerConvert(h, HEADERCONV_EXPANDFILELIST);
1261 } else {
1262 /* Binary packages with dirNames cannot be installed by legacy rpm. */
1263 (void) rpmlibNeedsFeature(pkg, "CompressedFileNames", "3.0.4-1");
1264 }
1265}
1266
1267static FileRecords FileRecordsFree(FileRecords files)
1268{
1269 for (int i = 0; i < files->used; i++) {
1270 free(files->recs[i].diskPath);
1271 free(files->recs[i].cpioPath);
1272 free(files->recs[i].langs);
1273 free(files->recs[i].caps);
1274 }
1275 free(files->recs);
1276 return NULL((void*)0);
1277}
1278
1279static void FileListFree(FileList fl)
1280{
1281 FileEntryFree(&(fl->cur));
1282 FileEntryFree(&(fl->def));
1283 FileRecordsFree(&(fl->files));
1284 free(fl->buildRoot);
1285 argvFree(fl->docDirs);
1286 rpmstrPoolFree(fl->pool);
1287}
1288
1289/* forward ref */
1290static rpmRC recurseDir(FileList fl, const char * diskPath);
1291
1292/* Hack up a stat structure for a %dev or non-existing %ghost */
1293static struct stat * fakeStat(FileEntry cur, struct stat * statp)
1294{
1295 time_t now = time(NULL((void*)0));
1296
1297 if (cur->devtype) {
1298 statp->st_rdev = ((cur->devmajor & 0xff) << 8) | (cur->devminor & 0xff);
1299 statp->st_dev = statp->st_rdev;
1300 statp->st_mode = (cur->devtype == 'b' ? S_IFBLK0060000 : S_IFCHR0020000);
1301 } else {
1302 /* non-existing %ghost file or directory */
1303 statp->st_mode = cur->isDir ? S_IFDIR0040000 : S_IFREG0100000;
1304 /* can't recurse into non-existing directory */
1305 if (cur->isDir)
1306 cur->isDir = 1;
1307 }
1308 statp->st_mode |= (cur->ar.ar_fmode & 0777);
1309 statp->st_atimest_atim.tv_sec = now;
1310 statp->st_mtimest_mtim.tv_sec = now;
1311 statp->st_ctimest_ctim.tv_sec = now;
1312 statp->st_nlink = 1;
1313 return statp;
1314}
1315
1316/**
1317 * Add a file to the package manifest.
1318 * @param fl package file tree walk data
1319 * @param diskPath path to file
1320 * @param statp file stat (possibly NULL)
1321 * @return RPMRC_OK on success
1322 */
1323static rpmRC addFile(FileList fl, const char * diskPath,
1324 struct stat * statp)
1325{
1326 size_t plen = strlen(diskPath);
1327 char buf[plen + 1];
1328 const char *cpioPath;
1329 struct stat statbuf;
1330 mode_t fileMode;
1331 uid_t fileUid;
1332 gid_t fileGid;
1333 const char *fileUname;
1334 const char *fileGname;
1335 rpmRC rc = RPMRC_FAIL; /* assume failure */
1336
1337 /* Strip trailing slash. The special case of '/' path is handled below. */
1338 if (plen > 0 && diskPath[plen - 1] == '/') {
1339 diskPath = strcpy(buf, diskPath);
1340 buf[plen - 1] = '\0';
1341 }
1342 cpioPath = diskPath;
1343
1344 if (strncmp(diskPath, fl->buildRoot, fl->buildRootLen)) {
1345 rpmlog(RPMLOG_ERR, _("Path is outside buildroot: %s\n")dcgettext ("rpm", "Path is outside buildroot: %s\n", 5), diskPath);
1346 goto exit;
1347 }
1348
1349 /* Path may have prepended buildRoot, so locate the original filename. */
1350 /*
1351 * XXX There are 3 types of entry into addFile:
1352 *
1353 * From diskUrl statp
1354 * =====================================================
1355 * processBinaryFile path NULL
1356 * processBinaryFile glob result path NULL
1357 * myftw path stat
1358 *
1359 */
1360 if (fl->buildRoot && !rstreq(fl->buildRoot, "/"))
1361 cpioPath += fl->buildRootLen;
1362
1363 /* XXX make sure '/' can be packaged also */
1364 if (*cpioPath == '\0')
1365 cpioPath = "/";
1366
1367 /*
1368 * Unless recursing, we dont have stat() info at hand. Handle the
1369 * various cases, preserving historical behavior wrt %dev():
1370 * - for %dev() entries we fake it up whether the file exists or not
1371 * - otherwise try to grab the data by lstat()
1372 * - %ghost entries might not exist, fake it up
1373 */
1374 if (statp == NULL((void*)0)) {
1375 memset(&statbuf, 0, sizeof(statbuf));
1376
1377 if (fl->cur.devtype) {
1378 statp = fakeStat(&(fl->cur), &statbuf);
1379 } else if (lstat(diskPath, &statbuf) == 0) {
1380 statp = &statbuf;
1381 } else if (fl->cur.attrFlags & RPMFILE_GHOST) {
1382 statp = fakeStat(&(fl->cur), &statbuf);
1383 } else {
1384 int lvl = RPMLOG_ERR;
1385 const char *msg = fl->cur.isDir ? _("Directory not found: %s\n")dcgettext ("rpm", "Directory not found: %s\n", 5) :
1386 _("File not found: %s\n")dcgettext ("rpm", "File not found: %s\n", 5);
1387 if (fl->cur.attrFlags & RPMFILE_EXCLUDE) {
1388 lvl = RPMLOG_WARNING;
1389 rc = RPMRC_OK;
1390 }
1391 rpmlog(lvl, msg, diskPath);
1392 goto exit;
1393 }
1394 }
1395
1396 /* Error out when a non-directory is specified as one in spec */
1397 if (fl->cur.isDir && (statp == &statbuf) && !S_ISDIR(statp->st_mode)((((statp->st_mode)) & 0170000) == (0040000))) {
1398 rpmlog(RPMLOG_ERR, _("Not a directory: %s\n")dcgettext ("rpm", "Not a directory: %s\n", 5), diskPath);
1399 goto exit;
1400 }
1401
1402 /* Don't recurse into explicit %dir, don't double-recurse from fts */
1403 if ((fl->cur.isDir != 1) && (statp == &statbuf) && S_ISDIR(statp->st_mode)((((statp->st_mode)) & 0170000) == (0040000))) {
1404 return recurseDir(fl, diskPath);
1405 }
1406
1407 fileMode = statp->st_mode;
1408 fileUid = statp->st_uid;
1409 fileGid = statp->st_gid;
1410
1411 /* Explicit %attr() always wins */
1412 if (fl->cur.ar.ar_fmodestr) {
1413 if (S_ISLNK(fileMode)((((fileMode)) & 0170000) == (0120000))) {
1414 rpmlog(RPMLOG_WARNING,
1415 "Explicit %%attr() mode not applicable to symlink: %s\n",
1416 diskPath);
1417 } else {
1418 fileMode &= S_IFMT0170000;
1419 fileMode |= fl->cur.ar.ar_fmode;
1420 }
1421 } else {
1422 /* ...but %defattr() for directories and files is different */
1423 if (S_ISDIR(fileMode)((((fileMode)) & 0170000) == (0040000))) {
1424 if (fl->def.ar.ar_dmodestr) {
1425 fileMode &= S_IFMT0170000;
1426 fileMode |= fl->def.ar.ar_dmode;
1427 }
1428 } else if (!S_ISLNK(fileMode)((((fileMode)) & 0170000) == (0120000)) && fl->def.ar.ar_fmodestr) {
1429 fileMode &= S_IFMT0170000;
1430 fileMode |= fl->def.ar.ar_fmode;
1431 }
1432 }
1433 if (fl->cur.ar.ar_user) {
1434 fileUname = rpmstrPoolStr(fl->pool, fl->cur.ar.ar_user);
1435 } else if (fl->def.ar.ar_user) {
1436 fileUname = rpmstrPoolStr(fl->pool, fl->def.ar.ar_user);
1437 } else {
1438 fileUname = rpmugUname(fileUid);
1439 }
1440 if (fl->cur.ar.ar_group) {
1441 fileGname = rpmstrPoolStr(fl->pool, fl->cur.ar.ar_group);
1442 } else if (fl->def.ar.ar_group) {
1443 fileGname = rpmstrPoolStr(fl->pool, fl->def.ar.ar_group);
1444 } else {
1445 fileGname = rpmugGname(fileGid);
1446 }
1447
1448 /* Default user/group to builder's user/group */
1449 if (fileUname == NULL((void*)0))
1450 fileUname = rpmugUname(getuid());
1451 if (fileGname == NULL((void*)0))
1452 fileGname = rpmugGname(getgid());
1453
1454 /* S_XXX macro must be consistent with type in find call at check-files script */
1455 if (check_fileList && (S_ISREG(fileMode)((((fileMode)) & 0170000) == (0100000)) || S_ISLNK(fileMode)((((fileMode)) & 0170000) == (0120000)))) {
1456 appendStringBuf(check_fileList, diskPath)appendStringBufAux(check_fileList, diskPath, 0);
1457 appendStringBuf(check_fileList, "\n")appendStringBufAux(check_fileList, "\n", 0);
1458 }
1459
1460 /* Add to the file list */
1461 if (fl->files.used == fl->files.alloced) {
1462 fl->files.alloced += 128;
1463 fl->files.recs = xrealloc(fl->files.recs,rrealloc((fl->files.recs), (fl->files.alloced * sizeof(
*(fl->files.recs))))
1464 fl->files.alloced * sizeof(*(fl->files.recs)))rrealloc((fl->files.recs), (fl->files.alloced * sizeof(
*(fl->files.recs))))
;
1465 }
1466
1467 { FileListRec flp = &fl->files.recs[fl->files.used];
1468
1469 flp->fl_st = *statp; /* structure assignment */
1470 flp->fl_modefl_st.st_mode = fileMode;
1471 flp->fl_uidfl_st.st_uid = fileUid;
1472 flp->fl_gidfl_st.st_gid = fileGid;
1473 if (S_ISDIR(fileMode)((((fileMode)) & 0170000) == (0040000)))
1474 flp->fl_sizefl_st.st_size = 0;
1475
1476 flp->cpioPath = xstrdup(cpioPath)rstrdup((cpioPath));
1477 flp->diskPath = xstrdup(diskPath)rstrdup((diskPath));
1478 flp->uname = rpmstrPoolId(fl->pool, fileUname, 1);
1479 flp->gname = rpmstrPoolId(fl->pool, fileGname, 1);
1480
1481 if (fl->cur.langs) {
1482 flp->langs = argvJoin(fl->cur.langs, "|");
1483 } else {
1484 flp->langs = xstrdup("")rstrdup((""));
1485 }
1486
1487 if (fl->cur.caps) {
1488 flp->caps = xstrdup(fl->cur.caps)rstrdup((fl->cur.caps));
1489 } else {
1490 flp->caps = xstrdup("")rstrdup((""));
1491 }
1492
1493 flp->flags = fl->cur.attrFlags;
1494 flp->specdFlags = fl->cur.specdFlags;
1495 flp->verifyFlags = fl->cur.verifyFlags;
1496
1497 if (!(flp->flags & RPMFILE_EXCLUDE) && S_ISREG(flp->fl_mode)((((flp->fl_st.st_mode)) & 0170000) == (0100000))) {
1498 if (flp->fl_sizefl_st.st_size >= UINT32_MAX(4294967295U)) {
1499 fl->largeFiles = 1;
1500 }
1501 }
1502 }
1503
1504 rc = RPMRC_OK;
1505 fl->files.used++;
1506
1507exit:
1508 if (rc != RPMRC_OK)
1509 fl->processingFailed = 1;
1510
1511 return rc;
1512}
1513
1514/**
1515 * Add directory (and all of its files) to the package manifest.
1516 * @param fl package file tree walk data
1517 * @param diskPath path to file
1518 * @return RPMRC_OK on success
1519 */
1520static rpmRC recurseDir(FileList fl, const char * diskPath)
1521{
1522 char * ftsSet[2];
1523 FTS * ftsp;
1524 FTSENT * fts;
1525 int myFtsOpts = (FTS_COMFOLLOW0x0001 | FTS_NOCHDIR0x0004 | FTS_PHYSICAL0x0010);
1526 rpmRC rc = RPMRC_FAIL;
1527
1528 ftsSet[0] = (char *) diskPath;
1529 ftsSet[1] = NULL((void*)0);
1530 ftsp = Fts_open(ftsSet, myFtsOpts, NULL((void*)0));
1531 while ((fts = Fts_read(ftsp)) != NULL((void*)0)) {
1532 switch (fts->fts_info) {
1533 case FTS_D1: /* preorder directory */
1534 case FTS_F8: /* regular file */
1535 case FTS_SL12: /* symbolic link */
1536 case FTS_SLNONE13: /* symbolic link without target */
1537 case FTS_DEFAULT3: /* none of the above */
1538 rc = addFile(fl, fts->fts_accpath, fts->fts_statp);
1539 break;
1540 case FTS_DOT5: /* dot or dot-dot */
1541 case FTS_DP6: /* postorder directory */
1542 rc = RPMRC_OK;
1543 break;
1544 case FTS_NS10: /* stat(2) failed */
1545 case FTS_DNR4: /* unreadable directory */
1546 case FTS_ERR7: /* error; errno is set */
1547 case FTS_DC2: /* directory that causes cycles */
1548 case FTS_NSOK11: /* no stat(2) requested */
1549 case FTS_INIT9: /* initialized only */
1550 case FTS_W14: /* whiteout object */
1551 default:
1552 rc = RPMRC_FAIL;
1553 break;
1554 }
1555 if (rc)
1556 break;
1557 }
1558 (void) Fts_close(ftsp);
1559
1560 return rc;
1561}
1562
1563/**
1564 * Add a pubkey/icon to a binary package.
1565 * @param pkg
1566 * @param fl package file tree walk data
1567 * @param fileName path to file, relative is builddir, absolute buildroot.
1568 * @param tag tag to add
1569 * @return RPMRC_OK on success
1570 */
1571static rpmRC processMetadataFile(Package pkg, FileList fl,
1572 const char * fileName, rpmTagVal tag)
1573{
1574 const char * buildDir = "%{_builddir}/%{?buildsubdir}/";
1575 char * fn = NULL((void*)0);
1576 char * apkt = NULL((void*)0);
1577 uint8_t * pkt = NULL((void*)0);
1578 ssize_t pktlen = 0;
1579 int absolute = 0;
1580 rpmRC rc = RPMRC_FAIL;
1581 int xx;
1582
1583 if (*fileName == '/') {
1584 fn = rpmGenPath(fl->buildRoot, NULL((void*)0), fileName);
1585 absolute = 1;
1586 } else
1587 fn = rpmGenPath(buildDir, NULL((void*)0), fileName);
1588
1589 switch (tag) {
1590 default:
1591 rpmlog(RPMLOG_ERR, _("%s: can't load unknown tag (%d).\n")dcgettext ("rpm", "%s: can't load unknown tag (%d).\n", 5),
1592 fn, tag);
1593 goto exit;
1594 break;
1595 case RPMTAG_PUBKEYS: {
1596 if ((xx = pgpReadPkts(fn, &pkt, (size_t *)&pktlen)) <= 0) {
1597 rpmlog(RPMLOG_ERR, _("%s: public key read failed.\n")dcgettext ("rpm", "%s: public key read failed.\n", 5), fn);
1598 goto exit;
1599 }
1600 if (xx != PGPARMOR_PUBKEY) {
1601 rpmlog(RPMLOG_ERR, _("%s: not an armored public key.\n")dcgettext ("rpm", "%s: not an armored public key.\n", 5), fn);
1602 goto exit;
1603 }
1604 apkt = pgpArmorWrap(PGPARMOR_PUBKEY, pkt, pktlen);
1605 break;
1606 }
1607 }
1608
1609 if (!apkt) {
1610 rpmlog(RPMLOG_ERR, _("%s: failed to encode\n")dcgettext ("rpm", "%s: failed to encode\n", 5), fn);
1611 goto exit;
1612 }
1613
1614 headerPutString(pkg->header, tag, apkt);
1615 rc = RPMRC_OK;
1616
1617 if (absolute)
1618 rc = addFile(fl, fn, NULL((void*)0));
1619
1620exit:
1621 free(apkt);
1622 free(pkt);
1623 free(fn);
1624 if (rc) {
1625 fl->processingFailed = 1;
1626 rc = RPMRC_FAIL;
1627 }
1628 return rc;
1629}
1630
1631/* add a directory to the file list */
1632static void argvAddDir(ARGV_t *filesp, const char *dir)
1633{
1634 char *line = NULL((void*)0);
1635 rasprintf(&line, "%%dir %s", dir);
1636 argvAdd(filesp, line);
1637 _free(line)rfree((line));
1638}
1639
1640#if HAVE_LIBDW1
1641/* How build id links are generated. See macros.in for description. */
1642#define BUILD_IDS_NONE0 0
1643#define BUILD_IDS_ALLDEBUG1 1
1644#define BUILD_IDS_SEPARATE2 2
1645#define BUILD_IDS_COMPAT3 3
1646
1647static int addNewIDSymlink(ARGV_t *files,
1648 char *targetpath, char *idlinkpath,
1649 int isDbg, int *dups)
1650{
1651 const char *linkerr = _("failed symlink")dcgettext ("rpm", "failed symlink", 5);
1652 int rc = 0;
1653 int nr = 0;
1654 int exists = 0;
1655 char *origpath, *linkpath;
1656
1657 if (isDbg)
1658 rasprintf(&linkpath, "%s.debug", idlinkpath);
1659 else
1660 linkpath = idlinkpath;
1661 origpath = linkpath;
1662
1663 while (faccessat(AT_FDCWD-100, linkpath, F_OK0, AT_SYMLINK_NOFOLLOW0x100) == 0) {
1664 /* We don't care about finding dups for compat links, they are
1665 OK as is. Otherwise we will need to double check if
1666 existing link points to the correct target. */
1667 if (dups == NULL((void*)0))
1668 {
1669 exists = 1;
1670 break;
1671 }
1672
1673 char ltarget[PATH_MAX4096];
1674 ssize_t llen;
1675 /* In short-circuited builds the link might already exist */
1676 if ((llen = readlink(linkpath, ltarget, sizeof(ltarget)-1)) != -1) {
1677 ltarget[llen] = '\0';
1678 if (rstreq(ltarget, targetpath)) {
1679 exists = 1;
1680 break;
1681 }
1682 }
1683
1684 if (nr > 0)
1685 free(linkpath);
1686 nr++;
1687 rasprintf(&linkpath, "%s.%d%s", idlinkpath, nr,
1688 isDbg ? ".debug" : "");
1689 }
1690
1691 if (!exists && symlink(targetpath, linkpath) < 0) {
1692 rc = 1;
1693 rpmlog(RPMLOG_ERR, "%s: %s -> %s: %m\n",
1694 linkerr, linkpath, targetpath);
1695 } else {
1696 rc = argvAdd(files, linkpath);
1697 }
1698
1699 if (nr > 0) {
1700 /* Lets see why there are multiple build-ids. If the original
1701 targets are hard linked, then it is OK, otherwise warn
1702 something fishy is going on. Would be nice to call
1703 something like eu-elfcmp to see if they are really the same
1704 ELF file or not. */
1705 struct stat st1, st2;
1706 if (stat (origpath, &st1) != 0) {
1707 rpmlog(RPMLOG_WARNING, _("Duplicate build-id, stat %s: %m\n")dcgettext ("rpm", "Duplicate build-id, stat %s: %m\n", 5),
1708 origpath);
1709 } else if (stat (linkpath, &st2) != 0) {
1710 rpmlog(RPMLOG_WARNING, _("Duplicate build-id, stat %s: %m\n")dcgettext ("rpm", "Duplicate build-id, stat %s: %m\n", 5),
1711 linkpath);
1712 } else if (!(S_ISREG(st1.st_mode)((((st1.st_mode)) & 0170000) == (0100000)) && S_ISREG(st2.st_mode)((((st2.st_mode)) & 0170000) == (0100000))
1713 && st1.st_nlink > 1 && st2.st_nlink == st1.st_nlink
1714 && st1.st_ino == st2.st_ino && st1.st_dev == st2.st_dev)) {
1715 char *rpath1 = realpath(origpath, NULL((void*)0));
1716 char *rpath2 = realpath(linkpath, NULL((void*)0));
1717 rpmlog(RPMLOG_WARNING, _("Duplicate build-ids %s and %s\n")dcgettext ("rpm", "Duplicate build-ids %s and %s\n", 5),
1718 rpath1, rpath2);
1719 free(rpath1);
1720 free(rpath2);
1721 }
1722 }
1723
1724 if (isDbg)
1725 free(origpath);
1726 if (nr > 0)
1727 free(linkpath);
1728 if (dups != NULL((void*)0))
1729 *dups = nr;
1730
1731 return rc;
1732}
1733
1734static int generateBuildIDs(FileList fl, ARGV_t *files)
1735{
1736 int rc = 0;
1737 int i;
1738 FileListRec flp;
1739 char **ids = NULL((void*)0);
1740 char **paths = NULL((void*)0);
1741 size_t nr_ids, allocated;
1742 nr_ids = allocated = 0;
1743
1744 /* How are we supposed to create the build-id links? */
1745 char *build_id_links_macro = rpmExpand("%{?_build_id_links}", NULL((void*)0));
1746 int build_id_links;
1747 if (*build_id_links_macro == '\0') {
1748 rpmlog(RPMLOG_WARNING,
1749 _("_build_id_links macro not set, assuming 'compat'\n")dcgettext ("rpm", "_build_id_links macro not set, assuming 'compat'\n"
, 5)
);
1750 build_id_links = BUILD_IDS_COMPAT3;
1751 } else if (strcmp(build_id_links_macro, "none") == 0) {
1752 build_id_links = BUILD_IDS_NONE0;
1753 } else if (strcmp(build_id_links_macro, "alldebug") == 0) {
1754 build_id_links = BUILD_IDS_ALLDEBUG1;
1755 } else if (strcmp(build_id_links_macro, "separate") == 0) {
1756 build_id_links = BUILD_IDS_SEPARATE2;
1757 } else if (strcmp(build_id_links_macro, "compat") == 0) {
1758 build_id_links = BUILD_IDS_COMPAT3;
1759 } else {
1760 rc = 1;
1761 rpmlog(RPMLOG_ERR,
1762 _("_build_id_links macro set to unknown value '%s'\n")dcgettext ("rpm", "_build_id_links macro set to unknown value '%s'\n"
, 5)
,
1763 build_id_links_macro);
1764 build_id_links = BUILD_IDS_NONE0;
1765 }
1766 free(build_id_links_macro);
1767
1768 if (build_id_links == BUILD_IDS_NONE0 || rc != 0)
1769 return rc;
1770
1771 /* Historically we have only checked build_ids when __debug_package
1772 was defined. So don't terminate the build if __debug_package is
1773 unset, even when _missing_build_ids_terminate_build is. */
1774 int terminate = (rpmExpandNumeric("%{?_missing_build_ids_terminate_build}")
1775 && rpmExpandNumeric("%{?__debug_package}"));
1776
1777 /* Collect and check all build-ids for ELF files in this package. */
1778 int needMain = 0;
1779 int needDbg = 0;
1780 for (i = 0, flp = fl->files.recs; i < fl->files.used; i++, flp++) {
1781 struct stat sbuf;
1782 if (lstat(flp->diskPath, &sbuf) == 0 && S_ISREG (sbuf.st_mode)((((sbuf.st_mode)) & 0170000) == (0100000))) {
1783 /* We determine whether this is a main or
1784 debug ELF based on path. */
1785 int isDbg = strncmp (flp->cpioPath,
1786 DEBUG_LIB_PREFIX"/usr/lib/debug/", strlen (DEBUG_LIB_PREFIX"/usr/lib/debug/")) == 0;
1787
1788 /* For the main package files mimic what find-debuginfo.sh does.
1789 Only check build-ids for executable files. Debug files are
1790 always non-executable. */
1791 if (!isDbg
1792 && (sbuf.st_mode & (S_IXUSR0100 | S_IXGRP(0100 >> 3) | S_IXOTH((0100 >> 3) >> 3))) == 0)
1793 continue;
1794
1795 int fd = open (flp->diskPath, O_RDONLY00);
1796 if (fd >= 0) {
1797 /* Only real ELF files, that are ET_EXEC, ET_DYN or
1798 kernel modules (ET_REL files with names ending in .ko)
1799 should have build-ids. */
1800 GElf_Ehdr ehdr;
1801 Elf *elf = elf_begin (fd, ELF_C_READ, NULL((void*)0));
1802 if (elf != NULL((void*)0) && elf_kind(elf) == ELF_K_ELF
1803 && gelf_getehdr(elf, &ehdr) != NULL((void*)0)
1804 && (ehdr.e_type == ET_EXEC2 || ehdr.e_type == ET_DYN3
1805 || (ehdr.e_type == ET_REL1
1806 && rpmFileHasSuffix (flp->diskPath, ".ko")))) {
1807 const void *build_id;
1808 ssize_t len = dwelf_elf_gnu_build_id (elf, &build_id);
1809 /* len == -1 means error. Zero means no
1810 build-id. We want at least a length of 2 so we
1811 have at least a xx/yy (hex) dir/file. But
1812 reasonable build-ids are between 16 bytes (md5
1813 is 128 bits) and 64 bytes (largest sha3 is 512
1814 bits), common is 20 bytes (sha1 is 160 bits). */
1815 if (len >= 16 && len <= 64) {
1816 int addid = 0;
1817 if (isDbg) {
1818 needDbg = 1;
1819 addid = 1;
1820 }
1821 else if (build_id_links != BUILD_IDS_ALLDEBUG1) {
1822 needMain = 1;
1823 addid = 1;
1824 }
1825 if (addid) {
1826 const unsigned char *p = build_id;
1827 const unsigned char *end = p + len;
1828 char *id_str;
1829 if (allocated <= nr_ids) {
1830 allocated += 16;
1831 paths = xrealloc (paths,rrealloc((paths), (allocated * sizeof(char *)))
1832 allocated * sizeof(char *))rrealloc((paths), (allocated * sizeof(char *)));
1833 ids = xrealloc (ids,rrealloc((ids), (allocated * sizeof(char *)))
1834 allocated * sizeof(char *))rrealloc((ids), (allocated * sizeof(char *)));
1835 }
1836
1837 paths[nr_ids] = xstrdup(flp->cpioPath)rstrdup((flp->cpioPath));
1838 id_str = ids[nr_ids] = xmalloc(2 * len + 1)rmalloc((2 * len + 1));
1839 while (p < end)
1840 id_str += sprintf(id_str, "%02x",
1841 (unsigned)*p++);
1842 *id_str = '\0';
1843 nr_ids++;
1844 }
1845 } else {
1846 if (len < 0) {
1847 rpmlog(terminate ? RPMLOG_ERR : RPMLOG_WARNING,
1848 _("error reading build-id in %s: %s\n")dcgettext ("rpm", "error reading build-id in %s: %s\n", 5),
1849 flp->diskPath, elf_errmsg (-1));
1850 } else if (len == 0) {
1851 rpmlog(terminate ? RPMLOG_ERR : RPMLOG_WARNING,
1852 _("Missing build-id in %s\n")dcgettext ("rpm", "Missing build-id in %s\n", 5),
1853 flp->diskPath);
1854 } else {
1855 rpmlog(terminate ? RPMLOG_ERR : RPMLOG_WARNING,
1856 (len < 16
1857 ? _("build-id found in %s too small\n")dcgettext ("rpm", "build-id found in %s too small\n", 5)
1858 : _("build-id found in %s too large\n")dcgettext ("rpm", "build-id found in %s too large\n", 5)),
1859 flp->diskPath);
1860 }
1861 if (terminate)
1862 rc = 1;
1863 }
1864 elf_end (elf);
1865 }
1866 close (fd);
1867 }
1868 }
1869 }
1870
1871 /* Process and clean up all build-ids. */
1872 if (nr_ids > 0) {
1873 const char *errdir = _("failed to create directory")dcgettext ("rpm", "failed to create directory", 5);
1874 char *mainiddir = NULL((void*)0);
1875 char *debugiddir = NULL((void*)0);
1876 if (rc == 0) {
1877 char *attrstr;
1878 /* Add .build-id directories to hold the subdirs/symlinks. */
1879
1880 mainiddir = rpmGetPath(fl->buildRoot, BUILD_ID_DIR"/usr/lib/.build-id", NULL((void*)0));
1881 debugiddir = rpmGetPath(fl->buildRoot, DEBUG_ID_DIR"/usr/lib/debug/.build-id", NULL((void*)0));
1882
1883 /* Make sure to reset all file flags to defaults. */
1884 attrstr = mkattr();
1885 argvAdd(files, attrstr);
1886 free (attrstr);
1887
1888 /* Supported, but questionable. */
1889 if (needMain && needDbg)
1890 rpmlog(RPMLOG_WARNING,
1891 _("Mixing main ELF and debug files in package")dcgettext ("rpm", "Mixing main ELF and debug files in package"
, 5)
);
1892
1893 if (needMain) {
1894 if ((rc = rpmioMkpath(mainiddir, 0755, -1, -1)) != 0) {
1895 rpmlog(RPMLOG_ERR, "%s %s: %m\n", errdir, mainiddir);
1896 } else {
1897 argvAddDir(files, mainiddir);
1898 }
1899 }
1900
1901 if (rc == 0 && needDbg) {
1902 if ((rc = rpmioMkpath(debugiddir, 0755, -1, -1)) != 0) {
1903 rpmlog(RPMLOG_ERR, "%s %s: %m\n", errdir, debugiddir);
1904 } else {
1905 argvAddDir(files, debugiddir);
1906 }
1907 }
1908 }
1909
1910 /* In case we need ALLDEBUG links we might need the vra as
1911 tagged onto the .debug file name. */
1912 char *vra = NULL((void*)0);
1913 if (rc == 0 && needDbg && build_id_links == BUILD_IDS_ALLDEBUG1) {
1914 int unique_debug_names =
1915 rpmExpandNumeric("%{?_unique_debug_names}");
1916 if (unique_debug_names == 1)
1917 vra = rpmExpand("-%{VERSION}-%{RELEASE}.%{_arch}", NULL((void*)0));
1918 }
1919
1920 /* Now add a subdir and symlink for each buildid found. */
1921 for (i = 0; i < nr_ids; i++) {
1922 /* Don't add anything more when an error occurred. But do
1923 cleanup. */
1924 if (rc == 0) {
1925 int isDbg = strncmp (paths[i], DEBUG_LIB_PREFIX"/usr/lib/debug/",
1926 strlen (DEBUG_LIB_PREFIX"/usr/lib/debug/")) == 0;
1927
1928 char *buildidsubdir;
1929 char subdir[4];
1930 subdir[0] = '/';
1931 subdir[1] = ids[i][0];
1932 subdir[2] = ids[i][1];
1933 subdir[3] = '\0';
1934 if (isDbg)
1935 buildidsubdir = rpmGetPath(debugiddir, subdir, NULL((void*)0));
1936 else
1937 buildidsubdir = rpmGetPath(mainiddir, subdir, NULL((void*)0));
1938 /* We only need to create and add the subdir once. */
1939 int addsubdir = access (buildidsubdir, F_OK0) == -1;
1940 if (addsubdir
1941 && (rc = rpmioMkpath(buildidsubdir, 0755, -1, -1)) != 0) {
1942 rpmlog(RPMLOG_ERR, "%s %s: %m\n", errdir, buildidsubdir);
1943 } else {
1944 if (addsubdir)
1945 argvAddDir (files, buildidsubdir);
1946 if (rc == 0) {
1947 char *linkpattern, *targetpattern;
1948 char *linkpath, *targetpath;
1949 int dups = 0;
1950 if (isDbg) {
1951 linkpattern = "%s/%s";
1952 targetpattern = "../../../../..%s";
1953 } else {
1954 linkpattern = "%s/%s";
1955 targetpattern = "../../../..%s";
1956 }
1957 rasprintf(&linkpath, linkpattern,
1958 buildidsubdir, &ids[i][2]);
1959 rasprintf(&targetpath, targetpattern, paths[i]);
1960 rc = addNewIDSymlink(files, targetpath, linkpath,
1961 isDbg, &dups);
1962
1963 /* We might want to have a link from the debug
1964 build_ids dir to the main one. We create it
1965 when we are creating compat links or doing
1966 an old style alldebug build-ids package. In
1967 the first case things are simple since we
1968 just link to the main build-id symlink. The
1969 second case is a bit tricky, since we
1970 cannot be 100% sure the file names in the
1971 main and debug package match. Currently
1972 they do, but when creating parallel
1973 installable debuginfo packages they might
1974 not (in that case we might have to also
1975 strip the nvr from the debug name).
1976
1977 In general either method is discouraged
1978 since it might create dangling symlinks if
1979 the package versions get out of sync. */
1980 if (rc == 0 && isDbg
1981 && build_id_links == BUILD_IDS_COMPAT3) {
1982 /* buildidsubdir already points to the
1983 debug buildid. We just need to setup
1984 the symlink to the main one. There
1985 might be duplicate IDs, those are found
1986 by the addNewIDSymlink above. Target
1987 the last found duplicate, if any. */
1988 free(linkpath);
1989 free(targetpath);
1990 if (dups == 0)
1991 {
1992 rasprintf(&linkpath, "%s/%s",
1993 buildidsubdir, &ids[i][2]);
1994 rasprintf(&targetpath,
1995 "../../../.build-id%s/%s",
1996 subdir, &ids[i][2]);
1997 }
1998 else
1999 {
2000 rasprintf(&linkpath, "%s/%s.%d",
2001 buildidsubdir, &ids[i][2], dups);
2002 rasprintf(&targetpath,
2003 "../../../.build-id%s/%s.%d",
2004 subdir, &ids[i][2], dups);
2005 }
2006 rc = addNewIDSymlink(files, targetpath, linkpath,
2007 0, NULL((void*)0));
2008 }
2009
2010 if (rc == 0 && isDbg
2011 && build_id_links == BUILD_IDS_ALLDEBUG1) {
2012 /* buildidsubdir already points to the
2013 debug buildid. We do have to figure out
2014 the main ELF file though (which is most
2015 likely not in this package). Guess we
2016 can find it by stripping the
2017 /usr/lib/debug path and .debug
2018 prefix. Which might not really be
2019 correct if there was a more involved
2020 transformation (for example for
2021 parallel installable debuginfo
2022 packages), but then we shouldn't be
2023 using ALLDEBUG in the first place.
2024 Also ignore things like .dwz multifiles
2025 which don't end in ".debug". */
2026 int pathlen = strlen(paths[i]);
2027 int debuglen = strlen(".debug");
2028 int prefixlen = strlen(DEBUG_LIB_DIR"/usr/lib/debug");
2029 int vralen = vra == NULL((void*)0) ? 0 : strlen(vra);
2030 if (pathlen > prefixlen + debuglen + vralen
2031 && strcmp ((paths[i] + pathlen - debuglen),
2032 ".debug") == 0) {
2033 free(linkpath);
2034 free(targetpath);
2035 char *targetstr = xstrdup (paths[i]rstrdup((paths[i] + prefixlen))
2036 + prefixlen)rstrdup((paths[i] + prefixlen));
2037 int targetlen = pathlen - prefixlen;
2038 int targetend = targetlen - debuglen - vralen;
2039 targetstr[targetend] = '\0';
2040 rasprintf(&linkpath, "%s/%s",
2041 buildidsubdir, &ids[i][2]);
2042 rasprintf(&targetpath, "../../../../..%s",
2043 targetstr);
2044 rc = addNewIDSymlink(files, targetpath,
2045 linkpath, 0, &dups);
2046 free(targetstr);
2047 }
2048 }
2049 free(linkpath);
2050 free(targetpath);
2051 }
2052 }
2053 free(buildidsubdir);
2054 }
2055 free(paths[i]);
2056 free(ids[i]);
2057 }
2058 free(mainiddir);
2059 free(debugiddir);
2060 free(vra);
2061 free(paths);
2062 free(ids);
2063 }
2064 return rc;
2065}
2066#endif
2067
2068/**
2069 * Add a file to a binary package.
2070 * @param pkg
2071 * @param fl package file tree walk data
2072 * @param fileName file to add
2073 * @return RPMRC_OK on success
2074 */
2075static rpmRC processBinaryFile(Package pkg, FileList fl, const char * fileName)
2076{
2077 int quote = 1; /* XXX permit quoted glob characters. */
2078 int doGlob;
2079 char *diskPath = NULL((void*)0);
2080 rpmRC rc = RPMRC_OK;
2081 size_t fnlen = strlen(fileName);
2082 int trailing_slash = (fnlen > 0 && fileName[fnlen-1] == '/');
2083
2084 /* XXX differentiate other directories from explicit %dir */
2085 if (trailing_slash && !fl->cur.isDir)
2086 fl->cur.isDir = -1;
2087
2088 doGlob = rpmIsGlob(fileName, quote);
2089
2090 /* Check that file starts with leading "/" */
2091 if (*fileName != '/') {
2092 rpmlog(RPMLOG_ERR, _("File needs leading \"/\": %s\n")dcgettext ("rpm", "File needs leading \"/\": %s\n", 5), fileName);
2093 rc = RPMRC_FAIL;
2094 goto exit;
2095 }
2096
2097 /* Copy file name or glob pattern removing multiple "/" chars. */
2098 /*
2099 * Note: rpmGetPath should guarantee a "canonical" path. That means
2100 * that the following pathologies should be weeded out:
2101 * //bin//sh
2102 * //usr//bin/
2103 * /.././../usr/../bin//./sh
2104 */
2105 diskPath = rpmGenPath(fl->buildRoot, NULL((void*)0), fileName);
2106 /* Arrange trailing slash on directories */
2107 if (fl->cur.isDir)
2108 diskPath = rstrcat(&diskPath, "/");
2109
2110 if (doGlob) {
2111 ARGV_t argv = NULL((void*)0);
2112 int argc = 0;
2113 int i;
2114
2115 if (fl->cur.devtype) {
2116 rpmlog(RPMLOG_ERR, _("%%dev glob not permitted: %s\n")dcgettext ("rpm", "%%dev glob not permitted: %s\n", 5), diskPath);
2117 rc = RPMRC_FAIL;
2118 goto exit;
2119 }
2120
2121 if (rpmGlob(diskPath, &argc, &argv) == 0 && argc >= 1) {
2122 for (i = 0; i < argc; i++) {
2123 rc = addFile(fl, argv[i], NULL((void*)0));
2124 }
2125 argvFree(argv);
2126 } else {
2127 const char *msg = (fl->cur.isDir) ?
2128 _("Directory not found by glob: %s. "dcgettext ("rpm", "Directory not found by glob: %s. " "Trying without globbing.\n"
, 5)
2129 "Trying without globbing.\n")dcgettext ("rpm", "Directory not found by glob: %s. " "Trying without globbing.\n"
, 5)
:
2130 _("File not found by glob: %s. "dcgettext ("rpm", "File not found by glob: %s. " "Trying without globbing.\n"
, 5)
2131 "Trying without globbing.\n")dcgettext ("rpm", "File not found by glob: %s. " "Trying without globbing.\n"
, 5)
;
2132 rpmlog(RPMLOG_DEBUG, msg, diskPath);
2133 rc = addFile(fl, diskPath, NULL((void*)0));
2134 }
2135 } else {
2136 rc = addFile(fl, diskPath, NULL((void*)0));
2137 }
2138
2139exit:
2140 free(diskPath);
2141 if (rc) {
2142 fl->processingFailed = 1;
2143 rc = RPMRC_FAIL;
2144 }
2145 return rc;
2146}
2147
2148static rpmRC readFilesManifest(rpmSpec spec, Package pkg, const char *path)
2149{
2150 char *fn, buf[BUFSIZ8192];
2151 FILE *fd = NULL((void*)0);
2152 rpmRC rc = RPMRC_FAIL;
2153 unsigned int nlines = 0;
2154 char *expanded;
2155
2156 if (*path == '/') {
2157 fn = rpmGetPath(path, NULL((void*)0));
2158 } else {
2159 fn = rpmGetPath("%{_builddir}/",
2160 (spec->buildSubdir ? spec->buildSubdir : "") , "/", path, NULL((void*)0));
2161 }
2162 fd = fopen(fn, "r");
2163
2164 if (fd == NULL((void*)0)) {
2165 rpmlog(RPMLOG_ERR, _("Could not open %%files file %s: %m\n")dcgettext ("rpm", "Could not open %%files file %s: %m\n", 5), fn);
2166 goto exit;
2167 }
2168
2169 /* XXX unmask %license while parsing files manifest*/
2170 rpmPushMacro(spec->macros, "license", NULL((void*)0), "%%license", RMIL_SPEC-3);
2171
2172 while (fgets(buf, sizeof(buf), fd)) {
2173 if (handleComments(buf))
2174 continue;
2175 if (rpmExpandMacros(spec->macros, buf, &expanded, 0) < 0) {
2176 rpmlog(RPMLOG_ERR, _("line: %s\n")dcgettext ("rpm", "line: %s\n", 5), buf);
2177 goto exit;
2178 }
2179 argvAdd(&(pkg->fileList), expanded);
2180 free(expanded);
2181 nlines++;
2182 }
2183
2184 if (nlines == 0) {
2185 int terminate =
2186 rpmExpandNumeric("%{?_empty_manifest_terminate_build}");
2187 rpmlog(terminate ? RPMLOG_ERR : RPMLOG_WARNING,
2188 _("Empty %%files file %s\n")dcgettext ("rpm", "Empty %%files file %s\n", 5), fn);
2189 if (terminate)
2190 goto exit;
2191 }
2192
2193 if (ferror(fd))
2194 rpmlog(RPMLOG_ERR, _("Error reading %%files file %s: %m\n")dcgettext ("rpm", "Error reading %%files file %s: %m\n", 5), fn);
2195 else
2196 rc = RPMRC_OK;
2197
2198exit:
2199 rpmPopMacro(NULL((void*)0), "license");
2200 if (fd) fclose(fd);
2201 free(fn);
2202 return rc;
2203}
2204
2205static char * getSpecialDocDir(Header h, rpmFlags sdtype)
2206{
2207 const char *errstr = NULL((void*)0);
2208 const char *dirtype = (sdtype == RPMFILE_DOC) ? "docdir" : "licensedir";
2209 const char *fmt_default = "%{NAME}-%{VERSION}";
2210 char *fmt_macro = rpmExpand("%{?_docdir_fmt}", NULL((void*)0));
2211 char *fmt = NULL((void*)0);
2212 char *res = NULL((void*)0);
2213
2214 if (fmt_macro && strlen(fmt_macro) > 0) {
2215 fmt = headerFormat(h, fmt_macro, &errstr);
2216 if (errstr) {
2217 rpmlog(RPMLOG_WARNING, _("illegal _docdir_fmt %s: %s\n")dcgettext ("rpm", "illegal _docdir_fmt %s: %s\n", 5),
2218 fmt_macro, errstr);
2219 }
2220 }
2221
2222 if (fmt == NULL((void*)0))
2223 fmt = headerFormat(h, fmt_default, &errstr);
2224
2225 res = rpmGetPath("%{_", dirtype, "}/", fmt, NULL((void*)0));
2226
2227 free(fmt);
2228 free(fmt_macro);
2229 return res;
2230}
2231
2232static specialDir specialDirNew(Header h, rpmFlags sdtype)
2233{
2234 specialDir sd = xcalloc(1, sizeof(*sd))rcalloc((1), (sizeof(*sd)));
2235
2236 sd->entriesCount = 0;
2237 sd->entriesAlloced = 10;
2238 sd->entries = xcalloc(sd->entriesAlloced, sizeof(sd->entries[0]))rcalloc((sd->entriesAlloced), (sizeof(sd->entries[0])));
2239
2240 sd->dirname = getSpecialDocDir(h, sdtype);
2241 sd->sdtype = sdtype;
2242 return sd;
2243}
2244
2245static void addSpecialFile(specialDir sd, const char *path, FileEntry cur,
2246 FileEntry def)
2247{
2248 argvAdd(&sd->files, path);
2249
2250 if (sd->entriesCount >= sd->entriesAlloced) {
2251 sd->entriesAlloced <<= 1;
2252 sd->entries = xrealloc(sd->entries, sd->entriesAlloced *rrealloc((sd->entries), (sd->entriesAlloced * sizeof(sd
->entries[0])))
2253 sizeof(sd->entries[0]))rrealloc((sd->entries), (sd->entriesAlloced * sizeof(sd
->entries[0])))
;
2254 }
2255
2256 copyFileEntry(cur, &sd->entries[sd->entriesCount].curEntry);
2257 copyFileEntry(def, &sd->entries[sd->entriesCount].defEntry);
2258 sd->entriesCount++;
2259}
2260
2261static specialDir specialDirFree(specialDir sd)
2262{
2263 int i = 0;
2264
2265 if (sd) {
2266 argvFree(sd->files);
2267 free(sd->dirname);
2268 for (i = 0; i < sd->entriesCount; i++) {
2269 FileEntryFree(&sd->entries[i].curEntry);
2270 FileEntryFree(&sd->entries[i].defEntry);
2271 }
2272 free(sd->entries);
2273 free(sd);
2274 }
2275 return NULL((void*)0);
2276}
2277
2278static void processSpecialDir(rpmSpec spec, Package pkg, FileList fl,
2279 specialDir sd, int install, int test)
2280{
2281 const char *sdenv = (sd->sdtype == RPMFILE_DOC) ? "DOCDIR" : "LICENSEDIR";
48
Assuming the condition is false
49
'?' condition is false
2282 const char *sdname = (sd->sdtype == RPMFILE_DOC) ? "%doc" : "%license";
50
'?' condition is false
2283 char *mkdocdir = rpmExpand("%{__mkdir_p} $", sdenv, NULL((void*)0));
2284 StringBuf docScript = newStringBuf();
2285 char *basepath, **files;
2286 int fi;
2287
2288 appendStringBuf(docScript, sdenv)appendStringBufAux(docScript, sdenv, 0);
2289 appendStringBuf(docScript, "=$RPM_BUILD_ROOT")appendStringBufAux(docScript, "=$RPM_BUILD_ROOT", 0);
2290 appendLineStringBuf(docScript, sd->dirname)appendStringBufAux(docScript, sd->dirname, 1);
2291 appendLineStringBuf(docScript, "export LC_ALL=C")appendStringBufAux(docScript, "export LC_ALL=C", 1);
2292 appendStringBuf(docScript, "export ")appendStringBufAux(docScript, "export ", 0);
2293 appendLineStringBuf(docScript, sdenv)appendStringBufAux(docScript, sdenv, 1);
2294 appendLineStringBuf(docScript, mkdocdir)appendStringBufAux(docScript, mkdocdir, 1);
2295
2296 for (ARGV_const_t fn = sd->files; fn && *fn; fn++) {
51
Assuming 'fn' is null
2297 /* Quotes would break globs, escape spaces instead */
2298 char *efn = rpmEscapeSpaces(*fn);
2299 appendStringBuf(docScript, "cp -pr ")appendStringBufAux(docScript, "cp -pr ", 0);
2300 appendStringBuf(docScript, efn)appendStringBufAux(docScript, efn, 0);
2301 appendStringBuf(docScript, " $")appendStringBufAux(docScript, " $", 0);
2302 appendStringBuf(docScript, sdenv)appendStringBufAux(docScript, sdenv, 0);
2303 appendLineStringBuf(docScript, " ||:")appendStringBufAux(docScript, " ||:", 1);
2304 free(efn);
2305 }
2306
2307 if (install) {
52
Assuming 'install' is 0
53
Taking false branch
2308 rpmRC rc = doScript(spec, RPMBUILD_STRINGBUF, sdname,
2309 getStringBuf(docScript), test);
2310
2311 if (rc && rpmExpandNumeric("%{?_missing_doc_files_terminate_build}"))
2312 fl->processingFailed = 1;
2313 }
2314
2315 basepath = rpmGenPath(spec->rootDir, "%{_builddir}", spec->buildSubdir);
2316 files = sd->files;
54
Null pointer value stored to 'files'
2317 fi = 0;
2318 while (*files != NULL((void*)0)) {
55
Dereference of null pointer (loaded from variable 'files')
2319 char *origfile = rpmGenPath(basepath, *files, NULL((void*)0));
2320 char *eorigfile = rpmEscapeSpaces(origfile);
2321 ARGV_t globFiles;
2322 int globFilesCount, i;
2323 char *newfile;
2324
2325 FileEntryFree(&fl->cur);
2326 FileEntryFree(&fl->def);
2327 copyFileEntry(&sd->entries[fi].curEntry, &fl->cur);
2328 copyFileEntry(&sd->entries[fi].defEntry, &fl->def);
2329 fi++;
2330
2331 if (rpmGlob(eorigfile, &globFilesCount, &globFiles) == 0) {
2332 for (i = 0; i < globFilesCount; i++) {
2333 rasprintf(&newfile, "%s/%s", sd->dirname, basename__xpg_basename(globFiles[i]));
2334 processBinaryFile(pkg, fl, newfile);
2335 free(newfile);
2336 }
2337 argvFree(globFiles);
2338 } else {
2339 rpmlog(RPMLOG_ERR, _("File not found by glob: %s\n")dcgettext ("rpm", "File not found by glob: %s\n", 5), eorigfile);
2340 fl->processingFailed = 1;
2341 }
2342 free(eorigfile);
2343 free(origfile);
2344 files++;
2345 }
2346 free(basepath);
2347
2348 FileEntryFree(&fl->cur);
2349 FileEntryFree(&fl->def);
2350 copyFileEntry(&sd->entries[0].defEntry, &fl->def);
2351 fl->cur.isDir = 1;
2352 (void) processBinaryFile(pkg, fl, sd->dirname);
2353
2354 freeStringBuf(docScript);
2355 free(mkdocdir);
2356}
2357
2358
2359/* Resets the default settings for files in the package list.
2360 Used in processPackageFiles whenever a new set of files is added. */
2361static void resetPackageFilesDefaults (struct FileList_s *fl,
2362 rpmBuildPkgFlags pkgFlags)
2363{
2364 struct AttrRec_s root_ar = { 0, 0, 0, 0, 0, 0 };
2365
2366 root_ar.ar_user = rpmstrPoolId(fl->pool, UID_0_USER"root", 1);
2367 root_ar.ar_group = rpmstrPoolId(fl->pool, GID_0_GROUP"root", 1);
2368 dupAttrRec(&root_ar, &fl->def.ar); /* XXX assume %defattr(-,root,root) */
2369
2370 fl->def.verifyFlags = RPMVERIFY_ALL~(RPMVERIFY_NONE);
2371
2372 fl->pkgFlags = pkgFlags;
2373}
2374
2375/* Adds the given fileList to the package. If fromSpecFileList is not zero
2376 then the specialDirs are also filled in and the files are sanitized
2377 through processBinaryFile(). Otherwise no special files are processed
2378 and the files are added directly through addFile(). */
2379static void addPackageFileList (struct FileList_s *fl, Package pkg,
2380 ARGV_t *fileList,
2381 specialDir *specialDoc, specialDir *specialLic,
2382 int fromSpecFileList)
2383{
2384 ARGV_t fileNames = NULL((void*)0);
2385 for (ARGV_const_t fp = *fileList; *fp != NULL((void*)0); fp++) {
2386 char buf[strlen(*fp) + 1];
2387 const char *s = *fp;
2388 SKIPSPACE(s){ while (*(s) && risspace(*(s))) (s)++; };
2389 if (*s == '\0')
2390 continue;
2391 fileNames = argvFree(fileNames);
2392 rstrlcpy(buf, s, sizeof(buf));
2393
2394 /* Reset for a new line in %files */
2395 FileEntryFree(&fl->cur);
2396
2397 /* turn explicit flags into %def'd ones (gosh this is hacky...) */
2398 fl->cur.specdFlags = ((unsigned)fl->def.specdFlags) >> 8;
2399 fl->cur.verifyFlags = fl->def.verifyFlags;
2400
2401 if (parseForVerify(buf, 0, &fl->cur) ||
2402 parseForVerify(buf, 1, &fl->def) ||
2403 parseForAttr(fl->pool, buf, 0, &fl->cur) ||
2404 parseForAttr(fl->pool, buf, 1, &fl->def) ||
2405 parseForDev(buf, &fl->cur) ||
2406 parseForConfig(buf, &fl->cur) ||
2407 parseForLang(buf, &fl->cur) ||
2408 parseForCaps(buf, &fl->cur) ||
2409 parseForSimple(buf, &fl->cur, &fileNames))
2410 {
2411 fl->processingFailed = 1;
2412 continue;
2413 }
2414
2415 for (ARGV_const_t fn = fileNames; fn && *fn; fn++) {
2416
2417 /* For file lists that don't come from a spec file list
2418 processing is easy. There are no special files and the
2419 file names don't need to be adjusted. */
2420 if (!fromSpecFileList) {
2421 if (fl->cur.attrFlags & RPMFILE_SPECIALDIR
2422 || fl->cur.attrFlags & RPMFILE_DOCDIR
2423 || fl->cur.attrFlags & RPMFILE_PUBKEY) {
2424 rpmlog(RPMLOG_ERR,
2425 _("Special file in generated file list: %s\n")dcgettext ("rpm", "Special file in generated file list: %s\n"
, 5)
,
2426 *fn);
2427 fl->processingFailed = 1;
2428 continue;
2429 }
2430 if (fl->cur.attrFlags & RPMFILE_DIR)
2431 fl->cur.isDir = 1;
2432 addFile(fl, *fn, NULL((void*)0));
2433 continue;
2434 }
2435
2436 /* File list does come from the spec, try to detect special
2437 files and adjust the actual file names. */
2438 if (fl->cur.attrFlags & RPMFILE_SPECIALDIR) {
2439 rpmFlags oattrs = (fl->cur.attrFlags & ~RPMFILE_SPECIALDIR);
2440 specialDir *sdp = NULL((void*)0);
2441 if (oattrs == RPMFILE_DOC) {
2442 sdp = specialDoc;
2443 } else if (oattrs == RPMFILE_LICENSE) {
2444 sdp = specialLic;
2445 }
2446
2447 if (sdp == NULL((void*)0) || **fn == '/') {
2448 rpmlog(RPMLOG_ERR,
2449 _("Can't mix special %s with other forms: %s\n")dcgettext ("rpm", "Can't mix special %s with other forms: %s\n"
, 5)
,
2450 (oattrs & RPMFILE_DOC) ? "%doc" : "%license", *fn);
2451 fl->processingFailed = 1;
2452 continue;
2453 }
2454
2455 /* save attributes on first special doc/license for later use */
2456 if (*sdp == NULL((void*)0)) {
2457 *sdp = specialDirNew(pkg->header, oattrs);
2458 }
2459 addSpecialFile(*sdp, *fn, &fl->cur, &fl->def);
2460 continue;
2461 }
2462
2463 /* this is now an artificial limitation */
2464 if (fn != fileNames) {
2465 rpmlog(RPMLOG_ERR, _("More than one file on a line: %s\n")dcgettext ("rpm", "More than one file on a line: %s\n", 5),*fn);
2466 fl->processingFailed = 1;
2467 continue;
2468 }
2469
2470 if (fl->cur.attrFlags & RPMFILE_DOCDIR) {
2471 argvAdd(&(fl->docDirs), *fn);
2472 } else if (fl->cur.attrFlags & RPMFILE_PUBKEY) {
2473 (void) processMetadataFile(pkg, fl, *fn, RPMTAG_PUBKEYS);
2474 } else {
2475 if (fl->cur.attrFlags & RPMFILE_DIR)
2476 fl->cur.isDir = 1;
2477 (void) processBinaryFile(pkg, fl, *fn);
2478 }
2479 }
2480
2481 if (fl->cur.caps)
2482 fl->haveCaps = 1;
2483 }
2484 argvFree(fileNames);
2485}
2486
2487static rpmRC processPackageFiles(rpmSpec spec, rpmBuildPkgFlags pkgFlags,
2488 Package pkg, int didInstall, int test)
2489{
2490 struct FileList_s fl;
2491 specialDir specialDoc = NULL((void*)0);
2492 specialDir specialLic = NULL((void*)0);
2493
2494 pkg->cpioList = NULL((void*)0);
2495
2496 for (ARGV_const_t fp = pkg->fileFile; fp && *fp != NULL((void*)0); fp++) {
42
Assuming 'fp' is null
2497 if (readFilesManifest(spec, pkg, *fp))
2498 return RPMRC_FAIL;
2499 }
2500 /* Init the file list structure */
2501 memset(&fl, 0, sizeof(fl));
2502
2503 fl.pool = rpmstrPoolLink(spec->pool);
2504 /* XXX spec->buildRoot == NULL, then xstrdup("") is returned */
2505 fl.buildRoot = rpmGenPath(spec->rootDir, spec->buildRoot, NULL((void*)0));
2506 fl.buildRootLen = strlen(fl.buildRoot);
2507
2508 resetPackageFilesDefaults (&fl, pkgFlags);
2509
2510 { char *docs = rpmGetPath("%{?__docdir_path}", NULL((void*)0));
2511 argvSplit(&fl.docDirs, docs, ":");
2512 free(docs);
2513 }
2514
2515 addPackageFileList (&fl, pkg, &pkg->fileList,
2516 &specialDoc, &specialLic, 1);
2517
2518 /* Now process special docs and licenses if present */
2519 if (specialDoc)
43
Assuming 'specialDoc' is null
44
Taking false branch
2520 processSpecialDir(spec, pkg, &fl, specialDoc, didInstall, test);
2521 if (specialLic)
45
Assuming 'specialLic' is non-null
46
Taking true branch
2522 processSpecialDir(spec, pkg, &fl, specialLic, didInstall, test);
47
Calling 'processSpecialDir'
2523
2524 if (fl.processingFailed)
2525 goto exit;
2526
2527#if HAVE_LIBDW1
2528 /* Check build-ids and add build-ids links for files to package list. */
2529 const char *arch = headerGetString(pkg->header, RPMTAG_ARCH);
2530 if (!rstreq(arch, "noarch")) {
2531 /* Go through the current package list and generate a files list. */
2532 ARGV_t idFiles = NULL((void*)0);
2533 if (generateBuildIDs (&fl, &idFiles) != 0) {
2534 rpmlog(RPMLOG_ERR, _("Generating build-id links failed\n")dcgettext ("rpm", "Generating build-id links failed\n", 5));
2535 fl.processingFailed = 1;
2536 argvFree(idFiles);
2537 goto exit;
2538 }
2539
2540 if (idFiles != NULL((void*)0)) {
2541 resetPackageFilesDefaults (&fl, pkgFlags);
2542 addPackageFileList (&fl, pkg, &idFiles, NULL((void*)0), NULL((void*)0), 0);
2543 }
2544 argvFree(idFiles);
2545
2546 if (fl.processingFailed)
2547 goto exit;
2548 }
2549#endif
2550
2551 /* Verify that file attributes scope over hardlinks correctly. */
2552 if (checkHardLinks(&fl.files))
2553 (void) rpmlibNeedsFeature(pkg, "PartialHardlinkSets", "4.0.4-1");
2554
2555 genCpioListAndHeader(&fl, pkg, 0);
2556
2557exit:
2558 FileListFree(&fl);
2559 specialDirFree(specialDoc);
2560 specialDirFree(specialLic);
2561 return fl.processingFailed ? RPMRC_FAIL : RPMRC_OK;
2562}
2563
2564static void genSourceRpmName(rpmSpec spec)
2565{
2566 if (spec->sourceRpmName == NULL((void*)0)) {
2567 char *nvr = headerGetAsString(spec->packages->header, RPMTAG_NVR);
2568 rasprintf(&spec->sourceRpmName, "%s.%ssrc.rpm", nvr,
2569 spec->noSource ? "no" : "");
2570 free(nvr);
2571 }
2572}
2573
2574rpmRC processSourceFiles(rpmSpec spec, rpmBuildPkgFlags pkgFlags)
2575{
2576 struct Source *srcPtr;
2577 struct FileList_s fl;
2578 ARGV_t files = NULL((void*)0);
2579 Package pkg;
2580 Package sourcePkg = spec->sourcePackage;
2581 static char *_srcdefattr;
2582 static int oneshot;
2583
2584 if (!oneshot) {
2585 _srcdefattr = rpmExpand("%{?_srcdefattr}", NULL((void*)0));
2586 if (_srcdefattr && !*_srcdefattr)
2587 _srcdefattr = _free(_srcdefattr)rfree((_srcdefattr));
2588 oneshot = 1;
2589 }
2590
2591 genSourceRpmName(spec);
2592 /* Construct the file list and source entries */
2593 argvAdd(&files, spec->specFile);
2594 for (srcPtr = spec->sources; srcPtr != NULL((void*)0); srcPtr = srcPtr->next) {
2595 char * sfn = rpmGetPath( ((srcPtr->flags & RPMBUILD_ISNO) ? "!" : ""),
2596 "%{_sourcedir}/", srcPtr->source, NULL((void*)0));
2597 argvAdd(&files, sfn);
2598 free(sfn);
2599 }
2600
2601 for (pkg = spec->packages; pkg != NULL((void*)0); pkg = pkg->next) {
2602 for (srcPtr = pkg->icon; srcPtr != NULL((void*)0); srcPtr = srcPtr->next) {
2603 char * sfn;
2604 sfn = rpmGetPath( ((srcPtr->flags & RPMBUILD_ISNO) ? "!" : ""),
2605 "%{_sourcedir}/", srcPtr->source, NULL((void*)0));
2606 argvAdd(&files, sfn);
2607 free(sfn);
2608 }
2609 }
2610
2611 sourcePkg->cpioList = NULL((void*)0);
2612
2613 /* Init the file list structure */
2614 memset(&fl, 0, sizeof(fl));
2615 fl.pool = rpmstrPoolLink(spec->pool);
2616 if (_srcdefattr) {
2617 char *a = rstrscat(NULL((void*)0), "%defattr ", _srcdefattr, NULL((void*)0));
2618 parseForAttr(fl.pool, a, 1, &fl.def);
2619 free(a);
2620 }
2621 fl.files.alloced = spec->numSources + 1;
2622 fl.files.recs = xcalloc(fl.files.alloced, sizeof(*fl.files.recs))rcalloc((fl.files.alloced), (sizeof(*fl.files.recs)));
2623 fl.pkgFlags = pkgFlags;
2624
2625 for (ARGV_const_t fp = files; *fp != NULL((void*)0); fp++) {
2626 const char *diskPath = *fp;
2627 char *tmp;
2628 FileListRec flp;
2629
2630 SKIPSPACE(diskPath){ while (*(diskPath) && risspace(*(diskPath))) (diskPath
)++; }
;
2631 if (! *diskPath)
2632 continue;
2633
2634 flp = &fl.files.recs[fl.files.used];
2635
2636 /* The first source file is the spec file */
2637 flp->flags = (fl.files.used == 0) ? RPMFILE_SPECFILE : 0;
2638 /* files with leading ! are no source files */
2639 if (*diskPath == '!') {
2640 flp->flags |= RPMFILE_GHOST;
2641 diskPath++;
2642 }
2643
2644 tmp = xstrdup(diskPath)rstrdup((diskPath)); /* basename() might modify */
2645 flp->diskPath = xstrdup(diskPath)rstrdup((diskPath));
2646 flp->cpioPath = xstrdup(basename(tmp))rstrdup((__xpg_basename(tmp)));
2647 flp->verifyFlags = RPMVERIFY_ALL~(RPMVERIFY_NONE);
2648 free(tmp);
2649
2650 if (stat(diskPath, &flp->fl_st)) {
2651 rpmlog(RPMLOG_ERR, _("Bad file: %s: %s\n")dcgettext ("rpm", "Bad file: %s: %s\n", 5),
2652 diskPath, strerror(errno(*__errno_location ())));
2653 fl.processingFailed = 1;
2654 } else {
2655 if (S_ISREG(flp->fl_mode)((((flp->fl_st.st_mode)) & 0170000) == (0100000)) && flp->fl_sizefl_st.st_size >= UINT32_MAX(4294967295U))
2656 fl.largeFiles = 1;
2657 }
2658
2659 if (fl.def.ar.ar_fmodestr) {
2660 flp->fl_modefl_st.st_mode &= S_IFMT0170000;
2661 flp->fl_modefl_st.st_mode |= fl.def.ar.ar_fmode;
2662 }
2663
2664 if (fl.def.ar.ar_user) {
2665 flp->uname = fl.def.ar.ar_user;
2666 } else {
2667 flp->uname = rpmstrPoolId(fl.pool, rpmugUname(flp->fl_uidfl_st.st_uid), 1);
2668 }
2669 if (! flp->uname) {
2670 flp->uname = rpmstrPoolId(fl.pool, rpmugUname(getuid()), 1);
2671 }
2672 if (! flp->uname) {
2673 flp->uname = rpmstrPoolId(fl.pool, UID_0_USER"root", 1);
2674 }
2675
2676 if (fl.def.ar.ar_group) {
2677 flp->gname = fl.def.ar.ar_group;
2678 } else {
2679 flp->gname = rpmstrPoolId(fl.pool, rpmugGname(flp->fl_gidfl_st.st_gid), 1);
2680 }
2681 if (! flp->gname) {
2682 flp->gname = rpmstrPoolId(fl.pool, rpmugGname(getgid()), 1);
2683 }
2684 if (! flp->gname) {
2685 flp->gname = rpmstrPoolId(fl.pool, GID_0_GROUP"root", 1);
2686 }
2687
2688 flp->langs = xstrdup("")rstrdup((""));
2689 fl.files.used++;
2690 }
2691 argvFree(files);
2692
2693 if (! fl.processingFailed) {
2694 if (sourcePkg->header != NULL((void*)0)) {
2695 genCpioListAndHeader(&fl, sourcePkg, 1);
2696 }
2697 }
2698
2699 FileListFree(&fl);
2700 return fl.processingFailed ? RPMRC_FAIL : RPMRC_OK;
2701}
2702
2703/**
2704 * Check packaged file list against what's in the build root.
2705 * @param buildRoot path of build root
2706 * @param fileList packaged file list
2707 * @return -1 if skipped, 0 on OK, 1 on error
2708 */
2709static int checkFiles(const char *buildRoot, StringBuf fileList)
2710{
2711 static char * const av_ckfile[] = { "%{?__check_files}", NULL((void*)0) };
2712 StringBuf sb_stdout = NULL((void*)0);
2713 int rc = -1;
2714 char * s = rpmExpand(av_ckfile[0], NULL((void*)0));
2715
2716 if (!(s && *s))
2717 goto exit;
2718
2719 rpmlog(RPMLOG_NOTICE, _("Checking for unpackaged file(s): %s\n")dcgettext ("rpm", "Checking for unpackaged file(s): %s\n", 5), s);
2720
2721 rc = rpmfcExec(av_ckfile, fileList, &sb_stdout, 0, buildRoot);
2722 if (rc < 0)
2723 goto exit;
2724
2725 if (sb_stdout) {
2726 int _unpackaged_files_terminate_build =
2727 rpmExpandNumeric("%{?_unpackaged_files_terminate_build}");
2728 const char * t = getStringBuf(sb_stdout);
2729 if ((*t != '\0') && (*t != '\n')) {
2730 rc = (_unpackaged_files_terminate_build) ? 1 : 0;
2731 rpmlog((rc ? RPMLOG_ERR : RPMLOG_WARNING),
2732 _("Installed (but unpackaged) file(s) found:\n%s")dcgettext ("rpm", "Installed (but unpackaged) file(s) found:\n%s"
, 5)
, t);
2733 }
2734 }
2735
2736exit:
2737 freeStringBuf(sb_stdout);
2738 free(s);
2739 return rc;
2740}
2741
2742static rpmTag copyTagsFromMainDebug[] = {
2743 RPMTAG_ARCH,
2744 RPMTAG_SUMMARY,
2745 RPMTAG_DESCRIPTION,
2746 RPMTAG_GROUP,
2747 /* see addTargets */
2748 RPMTAG_OS,
2749 RPMTAG_PLATFORM,
2750 RPMTAG_OPTFLAGS,
2751};
2752
2753/* this is a hack: patch the summary and the description to include
2754 * the correct package name */
2755static void patchDebugPackageString(Package dbg, rpmTag tag, Package pkg, Package mainpkg)
2756{
2757 const char *oldname, *newname, *old;
2758 char *oldsubst = NULL((void*)0), *newsubst = NULL((void*)0), *p;
2759 oldname = headerGetString(mainpkg->header, RPMTAG_NAME);
2760 newname = headerGetString(pkg->header, RPMTAG_NAME);
2761 rasprintf(&oldsubst, "package %s", oldname);
2762 rasprintf(&newsubst, "package %s", newname);
2763 old = headerGetString(dbg->header, tag);
2764 p = old ? strstr(old, oldsubst) : NULL((void*)0);
2765 if (p) {
2766 char *new = NULL((void*)0);
2767 rasprintf(&new, "%.*s%s%s", (int)(p - old), old, newsubst, p + strlen(oldsubst));
2768 headerDel(dbg->header, tag);
2769 headerPutString(dbg->header, tag, new);
2770 _free(new)rfree((new));
2771 }
2772 _free(oldsubst)rfree((oldsubst));
2773 _free(newsubst)rfree((newsubst));
2774}
2775
2776/* create a new debuginfo subpackage for package pkg from the
2777 * main debuginfo package */
2778static Package cloneDebuginfoPackage(rpmSpec spec, Package pkg, Package maindbg)
2779{
2780 const char *name = headerGetString(pkg->header, RPMTAG_NAME);
2781 char *dbgname = NULL((void*)0);
2782 Package dbg;
2783
2784 rasprintf(&dbgname, "%s-%s", name, "debuginfo");
2785 dbg = newPackage(dbgname, spec->pool, &spec->packages);
2786 headerPutString(dbg->header, RPMTAG_NAME, dbgname);
2787 copyInheritedTags(dbg->header, pkg->header);
2788 headerDel(dbg->header, RPMTAG_GROUP);
2789 headerCopyTags(maindbg->header, dbg->header, copyTagsFromMainDebug);
2790 dbg->autoReq = maindbg->autoReq;
2791 dbg->autoProv = maindbg->autoProv;
2792
2793 /* patch summary and description strings */
2794 patchDebugPackageString(dbg, RPMTAG_SUMMARY, pkg, spec->packages);
2795 patchDebugPackageString(dbg, RPMTAG_DESCRIPTION, pkg, spec->packages);
2796
2797 /* Add self-provides (normally done by addTargets) */
2798 addPackageProvides(dbg);
2799 dbg->ds = rpmdsThis(dbg->header, RPMTAG_REQUIRENAME, RPMSENSE_EQUAL);
2800
2801 _free(dbgname)rfree((dbgname));
2802 return dbg;
2803}
2804
2805/* collect the debug files for package pkg and put them into
2806 * a (possibly new) debuginfo subpackage */
2807static void filterDebuginfoPackage(rpmSpec spec, Package pkg,
2808 Package maindbg, char *buildroot, char *uniquearch)
2809{
2810 rpmfi fi;
2811 ARGV_t files = NULL((void*)0);
2812 ARGV_t dirs = NULL((void*)0);
2813 int lastdiridx = -1, dirsadded;
2814 char *path = NULL((void*)0), *p, *pmin;
2815 size_t buildrootlen = strlen(buildroot);
2816
2817 /* ignore noarch subpackages */
2818 if (rstreq(headerGetString(pkg->header, RPMTAG_ARCH), "noarch"))
2819 return;
2820
2821 if (!uniquearch)
2822 uniquearch = "";
2823
2824 fi = rpmfilesIter(pkg->cpioList, RPMFI_ITER_FWD);
2825 /* Check if the current package has files with debug info
2826 and add them to the file list */
2827 fi = rpmfiInit(fi, 0);
2828 while (rpmfiNext(fi) >= 0) {
2829 const char *name = rpmfiFN(fi);
2830 int namel = strlen(name);
2831
2832 /* strip trailing .debug like in find-debuginfo.sh */
2833 if (namel > 6 && !strcmp(name + namel - 6, ".debug"))
2834 namel -= 6;
2835
2836 /* fileRenameMap doesn't necessarily have to be initialized */
2837 if (pkg->fileRenameMap) {
2838 const char **names = NULL((void*)0);
2839 int namec = 0;
2840 fileRenameHashGetEntry(pkg->fileRenameMap, name, &names, &namec, NULL((void*)0));
2841 if (namec) {
2842 if (namec > 1)
2843 rpmlog(RPMLOG_WARNING, _("%s was mapped to multiple filenames")dcgettext ("rpm", "%s was mapped to multiple filenames", 5), name);
2844 name = *names;
2845 namel = strlen(name);
2846 }
2847 }
2848
2849 /* generate path */
2850 rasprintf(&path, "%s%s%.*s%s.debug", buildroot, DEBUG_LIB_DIR"/usr/lib/debug", namel, name, uniquearch);
2851
2852 /* If that file exists we have debug information for it */
2853 if (access(path, F_OK0) == 0) {
2854 /* Append the file list preamble */
2855 if (!files) {
2856 char *attr = mkattr();
2857 argvAdd(&files, attr);
2858 argvAddDir(&files, DEBUG_LIB_DIR"/usr/lib/debug");
2859 free(attr);
2860 }
2861
2862 /* Add the files main debug-info file */
2863 argvAdd(&files, path + buildrootlen);
2864
2865 /* Add the dir(s) */
2866 dirsadded = 0;
2867 pmin = path + buildrootlen + strlen(DEBUG_LIB_DIR"/usr/lib/debug");
2868 while ((p = strrchr(path + buildrootlen, '/')) != NULL((void*)0) && p > pmin) {
2869 *p = 0;
2870 if (lastdiridx >= 0 && !strcmp(dirs[lastdiridx], path + buildrootlen))
2871 break; /* already added this one */
2872 argvAdd(&dirs, path + buildrootlen);
2873 dirsadded++;
2874 }
2875 if (dirsadded)
2876 lastdiridx = argvCount(dirs) - dirsadded; /* remember longest dir */
2877 }
2878 path = _free(path)rfree((path));
2879 }
2880 rpmfiFree(fi);
2881 /* Exclude debug files for files which were excluded in respective non-debug package */
2882 for (ARGV_const_t excl = pkg->fileExcludeList; excl && *excl; excl++) {
2883 const char *name = *excl;
2884
2885 /* generate path */
2886 rasprintf(&path, "%s%s%s%s.debug", buildroot, DEBUG_LIB_DIR"/usr/lib/debug", name, uniquearch);
2887 /* Exclude only debuginfo files which actually exist */
2888 if (access(path, F_OK0) == 0) {
2889 char *line = NULL((void*)0);
2890 rasprintf(&line, "%%exclude %s", path + buildrootlen);
2891 argvAdd(&files, line);
2892 _free(line)rfree((line));
2893 }
2894 path = _free(path)rfree((path));
2895 }
2896
2897 /* add collected directories to file list */
2898 if (dirs) {
2899 int i;
2900 argvSort(dirs, NULL((void*)0));
2901 for (i = 0; dirs[i]; i++) {
2902 if (!i || strcmp(dirs[i], dirs[i - 1]) != 0)
2903 argvAddDir(&files, dirs[i]);
2904 }
2905 dirs = argvFree(dirs);
2906 }
2907
2908 if (files) {
2909 /* we have collected some files. Now put them in a debuginfo
2910 * package. If this is not the main package, clone the main
2911 * debuginfo package */
2912 if (pkg == spec->packages)
2913 maindbg->fileList = files;
2914 else {
2915 Package dbg = cloneDebuginfoPackage(spec, pkg, maindbg);
2916 dbg->fileList = files;
2917 }
2918 }
2919}
2920
2921/* add the debug dwz files to package pkg.
2922 * return 1 if something was added, 0 otherwise. */
2923static int addDebugDwz(Package pkg, char *buildroot)
2924{
2925 int ret = 0;
2926 char *path = NULL((void*)0);
2927 struct stat sbuf;
2928
2929 rasprintf(&path, "%s%s", buildroot, DEBUG_DWZ_DIR"/usr/lib/debug/.dwz");
2930 if (lstat(path, &sbuf) == 0 && S_ISDIR(sbuf.st_mode)((((sbuf.st_mode)) & 0170000) == (0040000))) {
2931 if (!pkg->fileList) {
2932 char *attr = mkattr();
2933 argvAdd(&pkg->fileList, attr);
2934 argvAddDir(&pkg->fileList, DEBUG_LIB_DIR"/usr/lib/debug");
2935 free(attr);
2936 }
2937 argvAdd(&pkg->fileList, DEBUG_DWZ_DIR"/usr/lib/debug/.dwz");
2938 ret = 1;
2939 }
2940 path = _free(path)rfree((path));
2941 return ret;
2942}
2943
2944/* add the debug source files to package pkg.
2945 * return 1 if something was added, 0 otherwise. */
2946static int addDebugSrc(Package pkg, char *buildroot)
2947{
2948 int ret = 0;
2949 char *path = NULL((void*)0);
2950 DIR *d;
2951 struct dirent *de;
2952
2953 /* not needed if we have an extra debugsource subpackage */
2954 if (rpmExpandNumeric("%{?_debugsource_packages}"))
2955 return 0;
2956
2957 rasprintf(&path, "%s%s", buildroot, DEBUG_SRC_DIR"/usr/src/debug");
2958 d = opendir(path);
2959 path = _free(path)rfree((path));
2960 if (d) {
2961 while ((de = readdir(d)) != NULL((void*)0)) {
2962 if (!strcmp(de->d_name, ".") || !strcmp(de->d_name, ".."))
2963 continue;
2964 rasprintf(&path, "%s/%s", DEBUG_SRC_DIR"/usr/src/debug", de->d_name);
2965 if (!pkg->fileList) {
2966 char *attr = mkattr();
2967 argvAdd(&pkg->fileList, attr);
2968 free(attr);
2969 }
2970 argvAdd(&pkg->fileList, path);
2971 path = _free(path)rfree((path));
2972 ret = 1;
2973 }
2974 closedir(d);
2975 }
2976 return ret;
2977}
2978
2979/* find the main debuginfo package. We do this simply by
2980 * searching for a package with the right name. */
2981static Package findDebuginfoPackage(rpmSpec spec)
2982{
2983 Package pkg = NULL((void*)0);
2984 if (lookupPackage(spec, "debuginfo", PART_SUBNAME0|PART_QUIET2, &pkg))
2985 return NULL((void*)0);
2986 return pkg && pkg->fileList ? pkg : NULL((void*)0);
2987}
2988
2989/* add a requires for package "to" into package "from". */
2990static void addPackageRequires(Package from, Package to)
2991{
2992 const char *name;
2993 char *evr, *isaprov;
2994 name = headerGetString(to->header, RPMTAG_NAME);
2995 evr = headerGetAsString(to->header, RPMTAG_EVR);
2996 isaprov = rpmExpand(name, "%{?_isa}", NULL((void*)0));
2997 addReqProv(from, RPMTAG_REQUIRENAME, isaprov, evr, RPMSENSE_EQUAL, 0);
2998 free(isaprov);
2999 free(evr);
3000}
3001
3002rpmRC processBinaryFiles(rpmSpec spec, rpmBuildPkgFlags pkgFlags,
3003 int didInstall, int test)
3004{
3005 Package pkg;
3006 rpmRC rc = RPMRC_OK;
3007 char *buildroot;
3008 char *uniquearch = NULL((void*)0);
3009 Package maindbg = NULL((void*)0); /* the (existing) main debuginfo package */
3010 Package deplink = NULL((void*)0); /* create requires to this package */
3011
3012#if HAVE_LIBDW1
3013 elf_version (EV_CURRENT1);
3014#endif
3015 check_fileList = newStringBuf();
3016 genSourceRpmName(spec);
3017 buildroot = rpmGenPath(spec->rootDir, spec->buildRoot, NULL((void*)0));
3018
3019 if (rpmExpandNumeric("%{?_debuginfo_subpackages}")) {
1
Assuming the condition is false
2
Taking false branch
3020 maindbg = findDebuginfoPackage(spec);
3021 if (maindbg) {
3022 /* move debuginfo package to back */
3023 if (maindbg->next) {
3024 Package *pp;
3025 /* dequeue */
3026 for (pp = &spec->packages; *pp != maindbg; pp = &(*pp)->next)
3027 ;
3028 *pp = maindbg->next;
3029 maindbg->next = 0;
3030 /* enqueue at tail */
3031 for (; *pp; pp = &(*pp)->next)
3032 ;
3033 *pp = maindbg;
3034 }
3035 /* delete unsplit file list, we will re-add files back later */
3036 maindbg->fileFile = argvFree(maindbg->fileFile);
3037 maindbg->fileList = argvFree(maindbg->fileList);
3038 if (rpmExpandNumeric("%{?_unique_debug_names}"))
3039 uniquearch = rpmExpand("-%{VERSION}-%{RELEASE}.%{_arch}", NULL((void*)0));
3040 }
3041 }
3042
3043 for (pkg = spec->packages; pkg != NULL((void*)0); pkg = pkg->next) {
3
Assuming 'pkg' is not equal to NULL
4
Loop condition is true. Entering loop body
14
Assuming 'pkg' is not equal to NULL
15
Loop condition is true. Entering loop body
25
Assuming 'pkg' is not equal to NULL
26
Loop condition is true. Entering loop body
36
Assuming 'pkg' is not equal to NULL
37
Loop condition is true. Entering loop body
3044 char *nvr;
3045 const char *a;
3046 int header_color;
3047 int arch_color;
3048
3049 if (pkg == maindbg) {
5
Taking false branch
16
Taking false branch
27
Taking false branch
38
Taking false branch
3050 /* if there is just one debuginfo package, we put our extra stuff
3051 * in it. Otherwise we put it in the main debug package */
3052 Package extradbg = !maindbg->fileList && maindbg->next && !maindbg->next->next ?
3053 maindbg->next : maindbg;
3054 if (addDebugDwz(extradbg, buildroot))
3055 deplink = extradbg;
3056 if (addDebugSrc(extradbg, buildroot))
3057 deplink = extradbg;
3058 maindbg = NULL((void*)0); /* all normal packages processed */
3059 }
3060
3061 if (pkg->fileList == NULL((void*)0))
6
Assuming the condition is false
7
Taking false branch
17
Assuming the condition is false
18
Taking false branch
28
Assuming the condition is false
29
Taking false branch
39
Assuming the condition is false
40
Taking false branch
3062 continue;
3063
3064 headerPutString(pkg->header, RPMTAG_SOURCERPM, spec->sourceRpmName);
3065
3066 nvr = headerGetAsString(pkg->header, RPMTAG_NVRA);
3067 rpmlog(RPMLOG_NOTICE, _("Processing files: %s\n")dcgettext ("rpm", "Processing files: %s\n", 5), nvr);
3068 free(nvr);
3069
3070 if ((rc = processPackageFiles(spec, pkgFlags, pkg, didInstall, test)) != RPMRC_OK)
8
Taking false branch
19
Taking false branch
30
Taking false branch
41
Calling 'processPackageFiles'
3071 goto exit;
3072
3073 if (maindbg)
9
Taking false branch
20
Taking false branch
31
Taking false branch
3074 filterDebuginfoPackage(spec, pkg, maindbg, buildroot, uniquearch);
3075 else if (deplink && pkg != deplink)
3076 addPackageRequires(pkg, deplink);
3077
3078 if ((rc = rpmfcGenerateDepends(spec, pkg)) != RPMRC_OK)
10
Assuming the condition is false
11
Taking false branch
21
Assuming the condition is false
22
Taking false branch
32
Assuming the condition is false
33
Taking false branch
3079 goto exit;
3080
3081 a = headerGetString(pkg->header, RPMTAG_ARCH);
3082 header_color = headerGetNumber(pkg->header, RPMTAG_HEADERCOLOR);
3083 if (!rstreq(a, "noarch")) {
12
Taking true branch
23
Taking true branch
34
Taking true branch
3084 arch_color = rpmGetArchColor(a);
3085 if (arch_color > 0 && header_color > 0 &&
13
Assuming 'arch_color' is <= 0
24
Assuming 'arch_color' is <= 0
35
Assuming 'arch_color' is <= 0
3086 !(arch_color & header_color)) {
3087 rpmlog(RPMLOG_WARNING,
3088 _("Binaries arch (%d) not matching the package arch (%d).\n")dcgettext ("rpm", "Binaries arch (%d) not matching the package arch (%d).\n"
, 5)
,
3089 header_color, arch_color);
3090 }
3091 } else if (header_color != 0) {
3092 int terminate = rpmExpandNumeric("%{?_binaries_in_noarch_packages_terminate_build}");
3093 rpmlog(terminate ? RPMLOG_ERR : RPMLOG_WARNING,
3094 _("Arch dependent binaries in noarch package\n")dcgettext ("rpm", "Arch dependent binaries in noarch package\n"
, 5)
);
3095 if (terminate) {
3096 rc = RPMRC_FAIL;
3097 goto exit;
3098 }
3099 }
3100 }
3101
3102 /* Now we have in fileList list of files from all packages.
3103 * We pass it to a script which does the work of finding missing
3104 * and duplicated files.
3105 */
3106
3107
3108 if (checkFiles(spec->buildRoot, check_fileList) > 0) {
3109 rc = RPMRC_FAIL;
3110 }
3111exit:
3112 check_fileList = freeStringBuf(check_fileList);
3113 _free(buildroot)rfree((buildroot));
3114 _free(uniquearch)rfree((uniquearch));
3115
3116 return rc;
3117}