Bug Summary

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