3
* The post-build, pre-packaging file tree walk to assemble the package
9
#define MYALLPERMS 07777
12
#include <signal.h> /* getOutputFrom() */
14
#include <rpmio_internal.h>
27
/*@access StringBuf @*/ /* compared with NULL */
29
#define SKIPWHITE(_x) {while(*(_x) && (xisspace(*_x) || *(_x) == ',')) (_x)++;}
30
#define SKIPNONWHITE(_x){while(*(_x) &&!(xisspace(*_x) || *(_x) == ',')) (_x)++;}
32
#define MAXDOCDIR 1024
35
extern int _noDirTokens;
40
typedef enum specdFlags_e {
41
SPECD_DEFFILEMODE = (1 << 0),
42
SPECD_DEFDIRMODE = (1 << 1),
43
SPECD_DEFUID = (1 << 2),
44
SPECD_DEFGID = (1 << 3),
45
SPECD_DEFVERIFY = (1 << 4),
47
SPECD_FILEMODE = (1 << 8),
48
SPECD_DIRMODE = (1 << 9),
49
SPECD_UID = (1 << 10),
50
SPECD_GID = (1 << 11),
51
SPECD_VERIFY = (1 << 12)
56
typedef struct FileListRec_s {
58
#define fl_dev fl_st.st_dev
59
#define fl_ino fl_st.st_ino
60
#define fl_mode fl_st.st_mode
61
#define fl_nlink fl_st.st_nlink
62
#define fl_uid fl_st.st_uid
63
#define fl_gid fl_st.st_gid
64
#define fl_rdev fl_st.st_rdev
65
#define fl_size fl_st.st_size
66
#define fl_mtime fl_st.st_mtime
68
/*@only@*/ const char * diskURL; /* get file from here */
69
/*@only@*/ const char * fileURL; /* filename in cpio archive */
70
/*@observer@*/ const char * uname;
71
/*@observer@*/ const char * gname;
73
specdFlags specdFlags; /* which attributes have been explicitly specified. */
75
/*@only@*/ const char *langs; /* XXX locales separated with | */
80
typedef struct AttrRec_s {
81
const char * ar_fmodestr;
82
const char * ar_dmodestr;
84
const char * ar_group;
91
static int multiLib = 0; /* MULTILIB */
94
* Package file tree walk data.
96
typedef struct FileList_s {
97
/*@only@*/ const char * buildRootURL;
98
/*@only@*/ const char * prefix;
102
int processingFailed;
104
int passedSpecialDoc;
115
specdFlags currentSpecdFlags;
116
int currentVerifyFlags;
117
struct AttrRec_s cur_ar;
118
struct AttrRec_s def_ar;
119
specdFlags defSpecdFlags;
122
/*@only@*/ /*@null@*/ const char ** currentLangs;
124
/* Hard coded limit of MAXDOCDIR docdirs. */
125
/* If you break it you are doing something wrong. */
126
const char * docDirs[MAXDOCDIR];
129
/*@only@*/ FileListRec fileList;
130
int fileListRecsAlloced;
131
int fileListRecsUsed;
136
static void nullAttrRec(/*@out@*/ AttrRec ar) /*@modifies ar @*/
138
ar->ar_fmodestr = NULL;
139
ar->ar_dmodestr = NULL;
148
static void freeAttrRec(AttrRec ar) /*@modifies ar @*/
150
ar->ar_fmodestr = _free(ar->ar_fmodestr);
151
ar->ar_dmodestr = _free(ar->ar_dmodestr);
152
ar->ar_user = _free(ar->ar_user);
153
ar->ar_group = _free(ar->ar_group);
154
/* XXX doesn't free ar (yet) */
162
static void dupAttrRec(const AttrRec oar, /*@in@*/ /*@out@*/ AttrRec nar)
168
nar->ar_fmodestr = (oar->ar_fmodestr ? xstrdup(oar->ar_fmodestr) : NULL);
169
nar->ar_dmodestr = (oar->ar_dmodestr ? xstrdup(oar->ar_dmodestr) : NULL);
170
nar->ar_user = (oar->ar_user ? xstrdup(oar->ar_user) : NULL);
171
nar->ar_group = (oar->ar_group ? xstrdup(oar->ar_group) : NULL);
172
nar->ar_fmode = oar->ar_fmode;
173
nar->ar_dmode = oar->ar_dmode;
179
static void dumpAttrRec(const char * msg, AttrRec ar)
180
/*@modifies fileSystem @*/
183
fprintf(stderr, "%s:\t", msg);
184
fprintf(stderr, "(%s, %s, %s, %s)\n",
192
/* strtokWithQuotes() modified from glibc strtok() */
193
/* Copyright (C) 1991, 1996 Free Software Foundation, Inc.
194
This file is part of the GNU C Library.
196
The GNU C Library is free software; you can redistribute it and/or
197
modify it under the terms of the GNU Library General Public License as
198
published by the Free Software Foundation; either version 2 of the
199
License, or (at your option) any later version.
201
The GNU C Library is distributed in the hope that it will be useful,
202
but WITHOUT ANY WARRANTY; without even the implied warranty of
203
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
204
Library General Public License for more details.
206
You should have received a copy of the GNU Library General Public
207
License along with the GNU C Library; see the file COPYING.LIB. If
208
not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
209
Boston, MA 02111-1307, USA. */
213
static char *strtokWithQuotes(char *s, char *delim)
215
static char *olds = NULL;
222
/* Skip leading delimiters */
223
s += strspn(s, delim);
228
/* Find the end of the token. */
232
/* Find next " char */
233
s = strchr(token, '"');
235
s = strpbrk(token, delim);
240
/* This token finishes the string */
241
olds = strchr(token, '\0');
243
/* Terminate the token and make olds point past it */
253
static void timeCheck(int tc, Header h) /*@modifies internalState @*/
255
HGE_t hge = (HGE_t)headerGetEntryMinMemory;
256
HFD_t hfd = headerFreeData;
261
time_t currentTime = time(NULL);
263
(void) hge(h, RPMTAG_OLDFILENAMES, &fnt, (void **) &files, &count);
264
(void) hge(h, RPMTAG_FILEMTIMES, NULL, (void **) &mtime, NULL);
266
for (x = 0; x < count; x++) {
267
if ((currentTime - mtime[x]) > tc)
268
rpmMessage(RPMMESS_WARNING, _("TIMECHECK failure: %s\n"), files[x]);
270
files = hfd(files, fnt);
276
/*@observer@*/ /*@null@*/ const char * attribute;
282
/*@-exportlocal -exportheadervar@*/
283
VFA_t verifyAttrs[] = {
284
{ "md5", RPMVERIFY_MD5 },
285
{ "size", RPMVERIFY_FILESIZE },
286
{ "link", RPMVERIFY_LINKTO },
287
{ "user", RPMVERIFY_USER },
288
{ "group", RPMVERIFY_GROUP },
289
{ "mtime", RPMVERIFY_MTIME },
290
{ "mode", RPMVERIFY_MODE },
291
{ "rdev", RPMVERIFY_RDEV },
294
/*@=exportlocal =exportheadervar@*/
297
* @param fl package file tree walk data
299
static int parseForVerify(char * buf, FileList fl)
300
/*@modifies buf, fl->processingFailed,
301
fl->currentVerifyFlags, fl->defVerifyFlags,
302
fl->currentSpecdFlags, fl->defSpecdFlags @*/
309
specdFlags * specdFlags;
311
if ((p = strstr(buf, (name = "%verify"))) != NULL) {
312
resultVerify = &(fl->currentVerifyFlags);
313
specdFlags = &fl->currentSpecdFlags;
314
} else if ((p = strstr(buf, (name = "%defverify"))) != NULL) {
315
resultVerify = &(fl->defVerifyFlags);
316
specdFlags = &fl->defSpecdFlags;
320
for (pe = p; (pe-p) < strlen(name); pe++)
326
rpmError(RPMERR_BADSPEC, _("Missing '(' in %s %s\n"), name, pe);
327
fl->processingFailed = 1;
328
return RPMERR_BADSPEC;
331
/* Bracket %*verify args */
333
for (p = pe; *pe && *pe != ')'; pe++)
337
rpmError(RPMERR_BADSPEC, _("Missing ')' in %s(%s\n"), name, p);
338
fl->processingFailed = 1;
339
return RPMERR_BADSPEC;
342
/* Localize. Erase parsed string */
343
q = alloca((pe-p) + 1);
350
verifyFlags = RPMVERIFY_NONE;
352
for (p = q; *p != '\0'; p = pe) {
362
for (vfa = verifyAttrs; vfa->attribute != NULL; vfa++) {
363
if (strcmp(p, vfa->attribute))
365
verifyFlags |= vfa->flag;
366
/*@innerbreak@*/ break;
372
if (!strcmp(p, "not")) {
375
rpmError(RPMERR_BADSPEC, _("Invalid %s token: %s\n"), name, p);
376
fl->processingFailed = 1;
377
return RPMERR_BADSPEC;
381
*resultVerify = negated ? ~(verifyFlags) : verifyFlags;
382
*specdFlags |= SPECD_VERIFY;
387
#define isAttrDefault(_ars) ((_ars)[0] == '-' && (_ars)[1] == '\0')
390
* Parse %dev from file manifest.
391
* @param fl package file tree walk data
393
static int parseForDev(char * buf, FileList fl)
394
/*@modifies buf, fl->processingFailed,
395
fl->noGlob, fl->devtype, fl->devmajor, fl->devminor @*/
398
const char * errstr = NULL;
400
int rc = RPMERR_BADSPEC; /* assume error */
402
if ((p = strstr(buf, (name = "%dev"))) == NULL)
405
for (pe = p; (pe-p) < strlen(name); pe++)
414
/* Bracket %dev args */
416
for (p = pe; *pe && *pe != ')'; pe++)
423
/* Localize. Erase parsed string */
424
q = alloca((pe-p) + 1);
431
pe = p; SKIPNONWHITE(pe); if (*pe != '\0') *pe++ = '\0';
441
p = pe; SKIPWHITE(p);
442
pe = p; SKIPNONWHITE(pe); if (*pe != '\0') *pe++ = '\0';
443
for (pe = p; *pe && xisdigit(*pe); pe++)
446
fl->devmajor = atoi(p);
447
/*@-unsignedcompare @*/ /* LCL: ge is ok */
448
if (!(fl->devmajor >= 0 && fl->devmajor < 256)) {
452
/*@=unsignedcompare @*/
459
p = pe; SKIPWHITE(p);
460
pe = p; SKIPNONWHITE(pe); if (*pe != '\0') *pe++ = '\0';
461
for (pe = p; *pe && xisdigit(*pe); pe++)
464
fl->devminor = atoi(p);
465
if (!(fl->devminor >= 0 && fl->devminor < 256)) {
481
rpmError(RPMERR_BADSPEC, _("Missing %s in %s %s\n"), errstr, name, p);
482
fl->processingFailed = 1;
488
* Parse %attr and %defattr from file manifest.
489
* @param fl package file tree walk data
491
static int parseForAttr(char * buf, FileList fl)
492
/*@modifies buf, fl->processingFailed,
493
fl->cur_ar, fl->def_ar,
494
fl->currentSpecdFlags, fl->defSpecdFlags @*/
499
struct AttrRec_s arbuf;
500
AttrRec ar = &arbuf, ret_ar;
501
specdFlags * specdFlags;
503
if ((p = strstr(buf, (name = "%attr"))) != NULL) {
504
ret_ar = &(fl->cur_ar);
505
specdFlags = &fl->currentSpecdFlags;
506
} else if ((p = strstr(buf, (name = "%defattr"))) != NULL) {
507
ret_ar = &(fl->def_ar);
508
specdFlags = &fl->defSpecdFlags;
512
for (pe = p; (pe-p) < strlen(name); pe++)
518
rpmError(RPMERR_BADSPEC, _("Missing '(' in %s %s\n"), name, pe);
519
fl->processingFailed = 1;
520
return RPMERR_BADSPEC;
523
/* Bracket %*attr args */
525
for (p = pe; *pe && *pe != ')'; pe++)
528
if (ret_ar == &(fl->def_ar)) { /* %defattr */
533
rpmError(RPMERR_BADSPEC,
534
_("Non-white space follows %s(): %s\n"), name, q);
535
fl->processingFailed = 1;
536
return RPMERR_BADSPEC;
540
/* Localize. Erase parsed string */
541
q = alloca((pe-p) + 1);
551
pe = p; SKIPNONWHITE(pe); if (*pe != '\0') *pe++ = '\0';
553
p = pe; SKIPWHITE(p);
556
pe = p; SKIPNONWHITE(pe); if (*pe != '\0') *pe++ = '\0';
558
p = pe; SKIPWHITE(p);
561
pe = p; SKIPNONWHITE(pe); if (*pe != '\0') *pe++ = '\0';
563
p = pe; SKIPWHITE(p);
565
if (*p != '\0' && ret_ar == &(fl->def_ar)) { /* %defattr */
566
pe = p; SKIPNONWHITE(pe); if (*pe != '\0') *pe++ = '\0';
568
p = pe; SKIPWHITE(p);
571
if (!(ar->ar_fmodestr && ar->ar_user && ar->ar_group) || *p != '\0') {
572
rpmError(RPMERR_BADSPEC, _("Bad syntax: %s(%s)\n"), name, q);
573
fl->processingFailed = 1;
574
return RPMERR_BADSPEC;
577
/* Do a quick test on the mode argument and adjust for "-" */
578
if (ar->ar_fmodestr && !isAttrDefault(ar->ar_fmodestr)) {
580
x = sscanf(ar->ar_fmodestr, "%o", &ui);
581
if ((x == 0) || (ar->ar_fmode & ~MYALLPERMS)) {
582
rpmError(RPMERR_BADSPEC, _("Bad mode spec: %s(%s)\n"), name, q);
583
fl->processingFailed = 1;
584
return RPMERR_BADSPEC;
588
ar->ar_fmodestr = NULL;
590
if (ar->ar_dmodestr && !isAttrDefault(ar->ar_dmodestr)) {
592
x = sscanf(ar->ar_dmodestr, "%o", &ui);
593
if ((x == 0) || (ar->ar_dmode & ~MYALLPERMS)) {
594
rpmError(RPMERR_BADSPEC, _("Bad dirmode spec: %s(%s)\n"), name, q);
595
fl->processingFailed = 1;
596
return RPMERR_BADSPEC;
600
ar->ar_dmodestr = NULL;
602
if (!(ar->ar_user && !isAttrDefault(ar->ar_user)))
605
if (!(ar->ar_group && !isAttrDefault(ar->ar_group)))
608
dupAttrRec(ar, ret_ar);
610
/* XXX fix all this */
611
*specdFlags |= SPECD_UID | SPECD_GID | SPECD_FILEMODE | SPECD_DIRMODE;
617
* @param fl package file tree walk data
619
static int parseForConfig(char * buf, FileList fl)
620
/*@modifies buf, fl->processingFailed,
626
if ((p = strstr(buf, (name = "%config"))) == NULL)
629
fl->currentFlags = RPMFILE_CONFIG;
631
for (pe = p; (pe-p) < strlen(name); pe++)
637
/* Bracket %config args */
639
for (p = pe; *pe && *pe != ')'; pe++)
643
rpmError(RPMERR_BADSPEC, _("Missing ')' in %s(%s\n"), name, p);
644
fl->processingFailed = 1;
645
return RPMERR_BADSPEC;
648
/* Localize. Erase parsed string */
649
q = alloca((pe-p) + 1);
655
for (p = q; *p != '\0'; p = pe) {
663
if (!strcmp(p, "missingok")) {
664
fl->currentFlags |= RPMFILE_MISSINGOK;
665
} else if (!strcmp(p, "noreplace")) {
666
fl->currentFlags |= RPMFILE_NOREPLACE;
668
rpmError(RPMERR_BADSPEC, _("Invalid %s token: %s\n"), name, p);
669
fl->processingFailed = 1;
670
return RPMERR_BADSPEC;
679
static int langCmp(const void * ap, const void * bp) /*@*/
681
return strcmp(*(const char **)ap, *(const char **)bp);
685
* @param fl package file tree walk data
687
static int parseForLang(char * buf, FileList fl)
688
/*@modifies buf, fl->processingFailed,
689
fl->currentLangs, fl->nLangs @*/
694
while ((p = strstr(buf, (name = "%lang"))) != NULL) {
696
for (pe = p; (pe-p) < strlen(name); pe++)
701
rpmError(RPMERR_BADSPEC, _("Missing '(' in %s %s\n"), name, pe);
702
fl->processingFailed = 1;
703
return RPMERR_BADSPEC;
706
/* Bracket %lang args */
708
for (pe = p; *pe && *pe != ')'; pe++)
712
rpmError(RPMERR_BADSPEC, _("Missing ')' in %s(%s\n"), name, p);
713
fl->processingFailed = 1;
714
return RPMERR_BADSPEC;
717
/* Localize. Erase parsed string */
718
q = alloca((pe-p) + 1);
724
/* Parse multiple arguments from %lang */
725
for (p = q; *p != '\0'; p = pe) {
736
/* Sanity check on locale lengths */
737
if (np < 1 || (np == 1 && *p != 'C') || np >= 32) {
738
rpmError(RPMERR_BADSPEC,
739
_("Unusual locale length: \"%.*s\" in %%lang(%s)\n"),
741
fl->processingFailed = 1;
742
return RPMERR_BADSPEC;
745
/* Check for duplicate locales */
746
if (fl->currentLangs != NULL)
747
for (i = 0; i < fl->nLangs; i++) {
748
if (strncmp(fl->currentLangs[i], p, np))
750
rpmError(RPMERR_BADSPEC, _("Duplicate locale %.*s in %%lang(%s)\n"),
752
fl->processingFailed = 1;
753
return RPMERR_BADSPEC;
757
fl->currentLangs = xrealloc(fl->currentLangs,
758
(fl->nLangs + 1) * sizeof(*fl->currentLangs));
759
newp = xmalloc( np+1 );
760
strncpy(newp, p, np);
762
fl->currentLangs[fl->nLangs++] = newp;
763
if (*pe == ',') pe++; /* skip , if present */
767
/* Insure that locales are sorted. */
768
if (fl->currentLangs)
769
qsort(fl->currentLangs, fl->nLangs, sizeof(*fl->currentLangs), langCmp);
776
static int parseForRegexLang(const char * fileName, /*@out@*/ char ** lang)
777
/*@modifies *lang @*/
779
static int initialized = 0;
780
static int hasRegex = 0;
781
static regex_t compiledPatt;
782
static char buf[BUFSIZ];
784
regmatch_t matches[2];
788
const char *patt = rpmExpand("%{_langpatt}", NULL);
790
if (!(patt && *patt != '%'))
792
else if (regcomp(&compiledPatt, patt, REG_EXTENDED))
801
memset(matches, 0, sizeof(matches));
802
if (! hasRegex || regexec(&compiledPatt, fileName, 2, matches, REG_NOTEOL))
806
s = fileName + matches[1].rm_eo - 1;
807
x = matches[1].rm_eo - matches[1].rm_so;
819
static int parseForRegexMultiLib(const char *fileName) /*@*/
821
static int initialized = 0;
822
static int hasRegex = 0;
823
static regex_t compiledPatt;
830
patt = rpmExpand("%{_multilibpatt}", NULL);
831
if (!(patt && *patt != '%'))
833
else if (regcomp(&compiledPatt, patt, REG_EXTENDED | REG_NOSUB))
841
if (! hasRegex || regexec(&compiledPatt, fileName, 0, NULL, 0))
849
/*@-exportlocal -exportheadervar@*/
850
VFA_t virtualFileAttributes[] = {
851
{ "%dir", 0 }, /* XXX why not RPMFILE_DIR? */
852
{ "%doc", RPMFILE_DOC },
853
{ "%ghost", RPMFILE_GHOST },
854
{ "%exclude", RPMFILE_EXCLUDE },
855
{ "%readme", RPMFILE_README },
856
{ "%license", RPMFILE_LICENSE },
860
{ "%spec", RPMFILE_SPEC },
861
{ "%config", RPMFILE_CONFIG },
862
{ "%donotuse", RPMFILE_DONOTUSE }, /* XXX WTFO? */
863
{ "%missingok", RPMFILE_CONFIG|RPMFILE_MISSINGOK },
864
{ "%noreplace", RPMFILE_CONFIG|RPMFILE_NOREPLACE },
869
/*@=exportlocal =exportheadervar@*/
872
* @param fl package file tree walk data
874
static int parseForSimple(/*@unused@*/Spec spec, Package pkg, char * buf,
875
FileList fl, /*@out@*/ const char ** fileName)
876
/*@modifies buf, fl->processingFailed, *fileName,
878
fl->docDirs, fl->docDirCount, fl->isDir,
879
fl->passedSpecialDoc, fl->isSpecialDoc,
883
int res, specialDoc = 0;
884
char specialDocBuf[BUFSIZ];
886
specialDocBuf[0] = '\0';
891
while ((s = strtokWithQuotes(t, " \t\n")) != NULL) {
893
if (!strcmp(s, "%docdir")) {
894
s = strtokWithQuotes(NULL, " \t\n");
895
if (fl->docDirCount == MAXDOCDIR) {
896
rpmError(RPMERR_INTERNAL, _("Hit limit for %%docdir\n"));
897
fl->processingFailed = 1;
900
fl->docDirs[fl->docDirCount++] = xstrdup(s);
901
if (strtokWithQuotes(NULL, " \t\n")) {
902
rpmError(RPMERR_INTERNAL, _("Only one arg for %%docdir\n"));
903
fl->processingFailed = 1;
909
/* Set flags for virtual file attributes */
911
for (vfa = virtualFileAttributes; vfa->attribute != NULL; vfa++) {
912
if (strcmp(s, vfa->attribute))
915
if (!strcmp(s, "%dir"))
916
fl->isDir = 1; /* XXX why not RPMFILE_DIR? */
917
else if (!strcmp(s, "%multilib"))
918
fl->currentFlags |= multiLib;
920
fl->currentFlags |= vfa->flag;
921
/*@innerbreak@*/ break;
923
/* if we got an attribute, continue with next token */
924
if (vfa->attribute != NULL)
929
/* We already got a file -- error */
930
rpmError(RPMERR_BADSPEC, _("Two files on one line: %s\n"),
932
fl->processingFailed = 1;
937
if (fl->currentFlags & RPMFILE_DOC) {
939
strcat(specialDocBuf, " ");
940
strcat(specialDocBuf, s);
942
/* not in %doc, does not begin with / -- error */
943
rpmError(RPMERR_BADSPEC,
944
_("File must begin with \"/\": %s\n"), s);
945
fl->processingFailed = 1;
954
if (*fileName || (fl->currentFlags & ~(RPMFILE_DOC))) {
955
rpmError(RPMERR_BADSPEC,
956
_("Can't mix special %%doc with other forms: %s\n"),
957
(*fileName ? *fileName : ""));
958
fl->processingFailed = 1;
961
/* XXX WATCHOUT: buf is an arg */
962
{ const char *ddir, *n, *v;
964
(void) headerNVR(pkg->header, &n, &v, NULL);
966
ddir = rpmGetPath("%{_docdir}/", n, "-", v, NULL);
971
/* XXX FIXME: this is easy to do as macro expansion */
973
if (! fl->passedSpecialDoc) {
974
pkg->specialDoc = newStringBuf();
975
appendStringBuf(pkg->specialDoc, "DOCDIR=$RPM_BUILD_ROOT");
976
appendLineStringBuf(pkg->specialDoc, buf);
977
appendLineStringBuf(pkg->specialDoc, "export DOCDIR");
978
appendLineStringBuf(pkg->specialDoc, "rm -rf $DOCDIR");
979
appendLineStringBuf(pkg->specialDoc, MKDIR_P " $DOCDIR");
984
fl->passedSpecialDoc = 1;
985
fl->isSpecialDoc = 1;
988
appendStringBuf(pkg->specialDoc, "cp -pr ");
989
appendStringBuf(pkg->specialDoc, specialDocBuf);
990
appendLineStringBuf(pkg->specialDoc, " $DOCDIR");
999
static int compareFileListRecs(const void * ap, const void * bp) /*@*/
1001
const char *a = ((FileListRec)ap)->fileURL;
1002
const char *b = ((FileListRec)bp)->fileURL;
1003
return strcmp(a, b);
1007
* @param fl package file tree walk data
1009
static int isDoc(FileList fl, const char * fileName) /*@*/
1011
int x = fl->docDirCount;
1014
if (strstr(fileName, fl->docDirs[x]) == fileName)
1021
* Verify that file attributes scope over hardlinks correctly.
1022
* @todo only %lang for now, finish other attributes later.
1023
* @param fl package file tree walk data
1025
static void checkHardLinks(FileList fl)
1026
/*@modifies fl->fileList->flags, fl->fileList->langs @*/
1028
char nlangs[BUFSIZ];
1029
FileListRec ilp, jlp;
1033
for (i = 0; i < fl->fileListRecsUsed; i++) {
1036
ilp = fl->fileList + i;
1037
if (!(S_ISREG(ilp->fl_mode) && ilp->fl_nlink > 1))
1039
if (ilp->flags & RPMFILE_SPECFILE)
1044
for (j = i + 1; j < fl->fileListRecsUsed; j++) {
1045
jlp = fl->fileList + j;
1046
if (!S_ISREG(jlp->fl_mode))
1048
if (ilp->fl_nlink != jlp->fl_nlink)
1050
if (ilp->fl_ino != jlp->fl_ino)
1052
if (ilp->fl_dev != jlp->fl_dev)
1054
if (!strcmp(ilp->langs, jlp->langs)) {
1055
jlp->flags |= RPMFILE_SPECFILE;
1059
te = stpcpy(te, ilp->langs);
1061
te = stpcpy(te, jlp->langs);
1064
/* Are locales distributed over hard links correctly? */
1068
ilp->langs = _free(ilp->langs);
1069
ilp->langs = xstrdup(nlangs);
1070
for (j = i + 1; j < fl->fileListRecsUsed; j++) {
1071
jlp = fl->fileList + j;
1072
if (!S_ISREG(jlp->fl_mode))
1074
if (ilp->fl_nlink != jlp->fl_nlink)
1076
if (ilp->fl_ino != jlp->fl_ino)
1078
if (ilp->fl_dev != jlp->fl_dev)
1080
jlp->flags |= RPMFILE_SPECFILE;
1081
jlp->langs = _free(jlp->langs);
1082
jlp->langs = xstrdup(nlangs);
1086
for (i = 0; i < fl->fileListRecsUsed; i++) {
1087
ilp = fl->fileList + i;
1088
ilp->flags &= ~RPMFILE_SPECFILE;
1093
* @todo Should directories have %doc/%config attributes? (#14531)
1094
* @todo Remove RPMTAG_OLDFILENAMES, add dirname/basename instead.
1095
* @param fl package file tree walk data
1097
static void genCpioListAndHeader(/*@partial@*/ FileList fl,
1098
TFI_t * cpioList, Header h, int isSrc)
1099
/*@modifies h, *cpioList, fl->processingFailed, fl->fileList @*/
1101
int _addDotSlash = !(isSrc || rpmExpandNumeric("%{_noPayloadPrefix}"));
1102
uint_32 multiLibMask = 0;
1110
/* Sort the big list */
1111
qsort(fl->fileList, fl->fileListRecsUsed,
1112
sizeof(*(fl->fileList)), compareFileListRecs);
1114
/* Generate the header. */
1118
skipLen += strlen(fl->prefix);
1121
for (i = 0, flp = fl->fileList; i < fl->fileListRecsUsed; i++, flp++) {
1124
/* Merge duplicate entries. */
1125
while (i < (fl->fileListRecsUsed - 1) &&
1126
!strcmp(flp->fileURL, flp[1].fileURL)) {
1128
/* Two entries for the same file found, merge the entries. */
1130
rpmMessage(RPMMESS_WARNING, _("File listed twice: %s\n"),
1134
flp[1].flags |= flp->flags;
1137
if (S_ISDIR(flp->fl_mode)) {
1138
if ((flp[1].specdFlags & (SPECD_DIRMODE | SPECD_DEFDIRMODE)) <
1139
(flp->specdFlags & (SPECD_DIRMODE | SPECD_DEFDIRMODE)))
1140
flp[1].fl_mode = flp->fl_mode;
1142
if ((flp[1].specdFlags & (SPECD_FILEMODE | SPECD_DEFFILEMODE)) <
1143
(flp->specdFlags & (SPECD_FILEMODE | SPECD_DEFFILEMODE)))
1144
flp[1].fl_mode = flp->fl_mode;
1148
if ((flp[1].specdFlags & (SPECD_UID | SPECD_DEFUID)) <
1149
(flp->specdFlags & (SPECD_UID | SPECD_DEFUID)))
1151
flp[1].fl_uid = flp->fl_uid;
1152
flp[1].uname = flp->uname;
1156
if ((flp[1].specdFlags & (SPECD_GID | SPECD_DEFGID)) <
1157
(flp->specdFlags & (SPECD_GID | SPECD_DEFGID)))
1159
flp[1].fl_gid = flp->fl_gid;
1160
flp[1].gname = flp->gname;
1164
if ((flp[1].specdFlags & (SPECD_VERIFY | SPECD_DEFVERIFY)) <
1165
(flp->specdFlags & (SPECD_VERIFY | SPECD_DEFVERIFY)))
1166
flp[1].verifyFlags = flp->verifyFlags;
1168
/* XXX to-do: language */
1173
/* Skip files that were marked with %exclude. */
1174
if (flp->flags & RPMFILE_EXCLUDE) continue;
1176
/* Omit '/' and/or URL prefix, leave room for "./" prefix */
1177
apathlen += (strlen(flp->fileURL) - skipLen + (_addDotSlash ? 3 : 1));
1179
/* Leave room for both dirname and basename NUL's */
1180
dpathlen += (strlen(flp->diskURL) + 2);
1182
if (flp->flags & RPMFILE_MULTILIB_MASK)
1184
(1u << ((flp->flags & RPMFILE_MULTILIB_MASK))
1185
>> RPMFILE_MULTILIB_SHIFT);
1188
* Make the header, the OLDFILENAMES will get converted to a
1189
* compressed file list write before we write the actual package to
1192
(void) headerAddOrAppendEntry(h, RPMTAG_OLDFILENAMES, RPM_STRING_ARRAY_TYPE,
1193
&(flp->fileURL), 1);
1195
if (sizeof(flp->fl_size) != sizeof(uint_32)) {
1196
uint_32 psize = (uint_32)flp->fl_size;
1197
(void) headerAddOrAppendEntry(h, RPMTAG_FILESIZES, RPM_INT32_TYPE,
1200
(void) headerAddOrAppendEntry(h, RPMTAG_FILESIZES, RPM_INT32_TYPE,
1201
&(flp->fl_size), 1);
1203
(void) headerAddOrAppendEntry(h, RPMTAG_FILEUSERNAME, RPM_STRING_ARRAY_TYPE,
1205
(void) headerAddOrAppendEntry(h, RPMTAG_FILEGROUPNAME, RPM_STRING_ARRAY_TYPE,
1207
if (sizeof(flp->fl_mtime) != sizeof(uint_32)) {
1208
uint_32 mtime = (uint_32)flp->fl_mtime;
1209
(void) headerAddOrAppendEntry(h, RPMTAG_FILEMTIMES, RPM_INT32_TYPE,
1212
(void) headerAddOrAppendEntry(h, RPMTAG_FILEMTIMES, RPM_INT32_TYPE,
1213
&(flp->fl_mtime), 1);
1215
if (sizeof(flp->fl_mode) != sizeof(uint_16)) {
1216
uint_16 pmode = (uint_16)flp->fl_mode;
1217
(void) headerAddOrAppendEntry(h, RPMTAG_FILEMODES, RPM_INT16_TYPE,
1220
(void) headerAddOrAppendEntry(h, RPMTAG_FILEMODES, RPM_INT16_TYPE,
1221
&(flp->fl_mode), 1);
1223
if (sizeof(flp->fl_rdev) != sizeof(uint_16)) {
1224
uint_16 prdev = (uint_16)flp->fl_rdev;
1225
(void) headerAddOrAppendEntry(h, RPMTAG_FILERDEVS, RPM_INT16_TYPE,
1228
(void) headerAddOrAppendEntry(h, RPMTAG_FILERDEVS, RPM_INT16_TYPE,
1229
&(flp->fl_rdev), 1);
1231
if (sizeof(flp->fl_dev) != sizeof(uint_32)) {
1232
uint_32 pdevice = (uint_32)flp->fl_dev;
1233
(void) headerAddOrAppendEntry(h, RPMTAG_FILEDEVICES, RPM_INT32_TYPE,
1236
(void) headerAddOrAppendEntry(h, RPMTAG_FILEDEVICES, RPM_INT32_TYPE,
1240
if (sizeof(flp->fl_ino) != sizeof(uint_32)) {
1241
uint_32 ino = (uint_32)flp->fl_ino;
1242
(void) headerAddOrAppendEntry(h, RPMTAG_FILEINODES, RPM_INT32_TYPE,
1245
(void) headerAddOrAppendEntry(h, RPMTAG_FILEINODES, RPM_INT32_TYPE,
1249
(void) headerAddOrAppendEntry(h, RPMTAG_FILELANGS, RPM_STRING_ARRAY_TYPE,
1252
/* We used to add these, but they should not be needed */
1253
/* (void) headerAddOrAppendEntry(h, RPMTAG_FILEUIDS,
1254
* RPM_INT32_TYPE, &(flp->fl_uid), 1);
1255
* (void) headerAddOrAppendEntry(h, RPMTAG_FILEGIDS,
1256
* RPM_INT32_TYPE, &(flp->fl_gid), 1);
1260
if (S_ISREG(flp->fl_mode))
1261
(void) mdfile(flp->diskURL, buf);
1263
(void) headerAddOrAppendEntry(h, RPMTAG_FILEMD5S, RPM_STRING_ARRAY_TYPE,
1267
if (S_ISLNK(flp->fl_mode)) {
1268
buf[Readlink(flp->diskURL, buf, BUFSIZ)] = '\0';
1269
if (fl->buildRootURL) {
1270
const char * buildRoot;
1271
(void) urlPath(fl->buildRootURL, &buildRoot);
1273
if (buf[0] == '/' && strcmp(buildRoot, "/") &&
1274
!strncmp(buf, buildRoot, strlen(buildRoot))) {
1275
rpmError(RPMERR_BADSPEC,
1276
_("Symlink points to BuildRoot: %s -> %s\n"),
1278
fl->processingFailed = 1;
1283
(void) headerAddOrAppendEntry(h, RPMTAG_FILELINKTOS, RPM_STRING_ARRAY_TYPE,
1286
if (flp->flags & RPMFILE_GHOST) {
1287
flp->verifyFlags &= ~(RPMVERIFY_MD5 | RPMVERIFY_FILESIZE |
1288
RPMVERIFY_LINKTO | RPMVERIFY_MTIME);
1290
(void) headerAddOrAppendEntry(h, RPMTAG_FILEVERIFYFLAGS, RPM_INT32_TYPE,
1291
&(flp->verifyFlags), 1);
1293
if (!isSrc && isDoc(fl, flp->fileURL))
1294
flp->flags |= RPMFILE_DOC;
1295
/* XXX Should directories have %doc/%config attributes? (#14531) */
1296
if (S_ISDIR(flp->fl_mode))
1297
flp->flags &= ~(RPMFILE_CONFIG|RPMFILE_DOC);
1299
(void) headerAddOrAppendEntry(h, RPMTAG_FILEFLAGS, RPM_INT32_TYPE,
1303
(void) headerAddEntry(h, RPMTAG_SIZE, RPM_INT32_TYPE,
1304
&(fl->totalFileSize), 1);
1306
/* XXX This should be added always so that packages look alike.
1307
* XXX However, there is logic in files.c/depends.c that checks for
1308
* XXX existence (rather than value) that will need to change as well.
1311
(void) headerAddEntry(h, RPMTAG_MULTILIBS, RPM_INT32_TYPE,
1315
(void) rpmlibNeedsFeature(h, "PayloadFilesHavePrefix", "4.0-1");
1317
/* Choose how filenames are represented. */
1321
compressFilelist(h);
1322
/* Binary packages with dirNames cannot be installed by legacy rpm. */
1323
(void) rpmlibNeedsFeature(h, "CompressedFileNames", "3.0.4-1");
1326
{ TFI_t fi = xcalloc(sizeof(*fi), 1);
1329
fi->type = TR_ADDED;
1331
fi->dnl = _free(fi->dnl);
1332
fi->bnl = _free(fi->bnl);
1334
fi->dnl = xmalloc(fi->fc * sizeof(*fi->dnl) + dpathlen);
1335
d = (char *)(fi->dnl + fi->fc);
1338
fi->bnl = xmalloc(fi->fc * (sizeof(*fi->bnl) + sizeof(*fi->dil)));
1339
fi->dil = (int *)(fi->bnl + fi->fc);
1341
fi->apath = xmalloc(fi->fc * sizeof(*fi->apath) + apathlen);
1342
a = (char *)(fi->apath + fi->fc);
1345
fi->actions = xcalloc(sizeof(*fi->actions), fi->fc);
1346
fi->fmapflags = xcalloc(sizeof(*fi->fmapflags), fi->fc);
1348
if (fl->buildRootURL)
1349
fi->astriplen = strlen(fl->buildRootURL);
1352
fi->fuids = xcalloc(sizeof(*fi->fuids), fi->fc);
1354
fi->fgids = xcalloc(sizeof(*fi->fgids), fi->fc);
1356
/* Make the cpio list */
1357
for (i = 0, flp = fl->fileList; i < fi->fc; i++, flp++) {
1360
/* Skip (possible) duplicate file entries, use last entry info. */
1361
while (((flp - fl->fileList) < (fl->fileListRecsUsed - 1)) &&
1362
!strcmp(flp->fileURL, flp[1].fileURL))
1365
/* Create disk directory and base name. */
1367
fi->dnl[fi->dil[i]] = d;
1368
d = stpcpy(d, flp->diskURL);
1370
/* Make room for the dirName NUL, find start of baseName. */
1371
for (b = d; b > fi->dnl[fi->dil[i]] && *b != '/'; b--)
1373
b++; /* dirname's end in '/' */
1374
*b++ = '\0'; /* terminate dirname, b points to basename */
1376
d += 2; /* skip both dirname and basename NUL's */
1378
/* Create archive path, normally adding "./" */
1379
/*@-dependenttrans@*/ /* FIX: xstrdup? nah ... */
1381
/*@=dependenttrans@*/
1382
if (_addDotSlash) a = stpcpy(a, "./");
1383
a = stpcpy(a, (flp->fileURL + skipLen));
1384
a++; /* skip apath NUL */
1386
if (flp->flags & RPMFILE_GHOST) {
1387
fi->actions[i] = FA_SKIP;
1390
fi->actions[i] = FA_COPYOUT;
1391
fi->fuids[i] = getUidS(flp->uname);
1392
fi->fgids[i] = getGidS(flp->gname);
1393
if (fi->fuids[i] == (uid_t)-1) fi->fuids[i] = 0;
1394
if (fi->fgids[i] == (gid_t)-1) fi->fgids[i] = 0;
1395
fi->fmapflags[i] = CPIO_MAP_PATH |
1396
CPIO_MAP_TYPE | CPIO_MAP_MODE | CPIO_MAP_UID | CPIO_MAP_GID;
1398
fi->fmapflags[i] |= CPIO_FOLLOW_SYMLINKS;
1399
if (flp->flags & RPMFILE_MULTILIB_MASK)
1400
fi->fmapflags[i] |= CPIO_MULTILIB;
1412
static /*@null@*/ FileListRec freeFileList(/*@only@*/ FileListRec fileList,
1417
fileList[count].diskURL = _free(fileList[count].diskURL);
1418
fileList[count].fileURL = _free(fileList[count].fileURL);
1419
fileList[count].langs = _free(fileList[count].langs);
1421
fileList = _free(fileList);
1426
* @param fl package file tree walk data
1428
static int addFile(FileList fl, const char * diskURL, struct stat * statp)
1429
/*@modifies *statp, fl->processingFailed,
1430
fl->fileList, fl->fileListRecsAlloced, fl->fileListRecsUsed,
1431
fl->totalFileSize, fl->fileCount, fl->inFtw, fl->isDir @*/
1433
const char *fileURL = diskURL;
1434
struct stat statbuf;
1438
const char *fileUname;
1439
const char *fileGname;
1442
/* Path may have prepended buildRootURL, so locate the original filename. */
1444
* XXX There are 3 types of entry into addFile:
1446
* From diskUrl statp
1447
* =====================================================
1448
* processBinaryFile path NULL
1449
* processBinaryFile glob result path NULL
1453
{ const char *fileName;
1454
(void) urlPath(fileURL, &fileName);
1455
if (fl->buildRootURL && strcmp(fl->buildRootURL, "/"))
1456
fileURL += strlen(fl->buildRootURL);
1459
/* XXX make sure '/' can be packaged also */
1460
if (*fileURL == '\0')
1463
/* If we are using a prefix, validate the file */
1464
if (!fl->inFtw && fl->prefix) {
1465
const char *prefixTest;
1466
const char *prefixPtr = fl->prefix;
1468
(void) urlPath(fileURL, &prefixTest);
1469
while (*prefixPtr && *prefixTest && (*prefixTest == *prefixPtr)) {
1473
if (*prefixPtr || (*prefixTest && *prefixTest != '/')) {
1474
rpmError(RPMERR_BADSPEC, _("File doesn't match prefix (%s): %s\n"),
1475
fl->prefix, fileURL);
1476
fl->processingFailed = 1;
1477
return RPMERR_BADSPEC;
1481
if (statp == NULL) {
1483
memset(statp, 0, sizeof(*statp));
1485
time_t now = time(NULL);
1487
/* XXX hack up a stat structure for a %dev(...) directive. */
1488
statp->st_nlink = 1;
1490
((fl->devmajor & 0xff) << 8) | (fl->devminor & 0xff);
1491
statp->st_dev = statp->st_rdev;
1492
statp->st_mode = (fl->devtype == 'b' ? S_IFBLK : S_IFCHR);
1493
statp->st_mode |= (fl->cur_ar.ar_fmode & 0777);
1494
statp->st_atime = now;
1495
statp->st_mtime = now;
1496
statp->st_ctime = now;
1497
} else if (Lstat(diskURL, statp)) {
1498
rpmError(RPMERR_BADSPEC, _("File not found: %s\n"), diskURL);
1499
fl->processingFailed = 1;
1500
return RPMERR_BADSPEC;
1504
if ((! fl->isDir) && S_ISDIR(statp->st_mode)) {
1505
/* We use our own ftw() call, because ftw() uses stat() */
1506
/* instead of lstat(), which causes it to follow symlinks! */
1507
/* It also has better callback support. */
1509
fl->inFtw = 1; /* Flag to indicate file has buildRootURL prefixed */
1510
fl->isDir = 1; /* Keep it from following myftw() again */
1511
(void) myftw(diskURL, 16, (myftwFunc) addFile, fl);
1517
fileMode = statp->st_mode;
1518
fileUid = statp->st_uid;
1519
fileGid = statp->st_gid;
1521
if (S_ISDIR(fileMode) && fl->cur_ar.ar_dmodestr) {
1523
fileMode |= fl->cur_ar.ar_dmode;
1524
} else if (fl->cur_ar.ar_fmodestr != NULL) {
1526
fileMode |= fl->cur_ar.ar_fmode;
1528
if (fl->cur_ar.ar_user) {
1529
fileUname = getUnameS(fl->cur_ar.ar_user);
1531
fileUname = getUname(fileUid);
1533
if (fl->cur_ar.ar_group) {
1534
fileGname = getGnameS(fl->cur_ar.ar_group);
1536
fileGname = getGname(fileGid);
1539
#if 0 /* XXX this looks dumb to me */
1540
if (! (fileUname && fileGname)) {
1541
rpmError(RPMERR_BADSPEC, _("Bad owner/group: %s\n"), diskName);
1542
fl->processingFailed = 1;
1543
return RPMERR_BADSPEC;
1546
/* Default user/group to builder's user/group */
1547
if (fileUname == NULL)
1548
fileUname = getUname(getuid());
1549
if (fileGname == NULL)
1550
fileGname = getGname(getgid());
1553
rpmMessage(RPMMESS_DEBUG, _("File %4d: %07o %s.%s\t %s\n"), fl->fileCount,
1554
(unsigned)fileMode, fileUname, fileGname, fileURL);
1556
/* Add to the file list */
1557
if (fl->fileListRecsUsed == fl->fileListRecsAlloced) {
1558
fl->fileListRecsAlloced += 128;
1559
fl->fileList = xrealloc(fl->fileList,
1560
fl->fileListRecsAlloced * sizeof(*(fl->fileList)));
1563
{ FileListRec flp = &fl->fileList[fl->fileListRecsUsed];
1566
flp->fl_st = *statp; /* structure assignment */
1567
flp->fl_mode = fileMode;
1568
flp->fl_uid = fileUid;
1569
flp->fl_gid = fileGid;
1571
flp->fileURL = xstrdup(fileURL);
1572
flp->diskURL = xstrdup(diskURL);
1573
flp->uname = fileUname;
1574
flp->gname = fileGname;
1576
if (fl->currentLangs && fl->nLangs > 0) {
1580
for (i = 0; i < fl->nLangs; i++)
1581
nl += strlen(fl->currentLangs[i]) + 1;
1583
flp->langs = ncl = xmalloc(nl);
1584
for (i = 0; i < fl->nLangs; i++) {
1586
if (i) *ncl++ = '|';
1587
for (ocl = fl->currentLangs[i]; *ocl != '\0'; ocl++)
1591
} else if (! parseForRegexLang(fileURL, &lang)) {
1592
flp->langs = xstrdup(lang);
1594
flp->langs = xstrdup("");
1597
flp->flags = fl->currentFlags;
1598
flp->specdFlags = fl->currentSpecdFlags;
1599
flp->verifyFlags = fl->currentVerifyFlags;
1602
&& !(flp->flags & RPMFILE_MULTILIB_MASK)
1603
&& !parseForRegexMultiLib(fileURL))
1604
flp->flags |= multiLib;
1607
/* Hard links need be counted only once. */
1608
if (S_ISREG(flp->fl_mode) && flp->fl_nlink > 1) {
1610
for (i = 0; i < fl->fileListRecsUsed; i++) {
1611
ilp = fl->fileList + i;
1612
if (!S_ISREG(ilp->fl_mode))
1614
if (flp->fl_nlink != ilp->fl_nlink)
1616
if (flp->fl_ino != ilp->fl_ino)
1618
if (flp->fl_dev != ilp->fl_dev)
1623
i = fl->fileListRecsUsed;
1625
if (S_ISREG(flp->fl_mode) && i >= fl->fileListRecsUsed)
1626
fl->totalFileSize += flp->fl_size;
1629
fl->fileListRecsUsed++;
1636
* @param fl package file tree walk data
1638
static int processBinaryFile(/*@unused@*/ Package pkg, FileList fl,
1639
const char * fileURL)
1640
/*@modifies fl->processingFailed,
1641
fl->fileList, fl->fileListRecsAlloced, fl->fileListRecsUsed,
1642
fl->totalFileSize, fl->fileCount, fl->inFtw, fl->isDir @*/
1645
const char *diskURL = NULL;
1648
doGlob = myGlobPatternP(fileURL);
1650
/* Check that file starts with leading "/" */
1651
{ const char * fileName;
1652
(void) urlPath(fileURL, &fileName);
1653
if (*fileName != '/') {
1654
rpmError(RPMERR_BADSPEC, _("File needs leading \"/\": %s\n"),
1661
/* Copy file name or glob pattern removing multiple "/" chars. */
1663
* Note: rpmGetPath should guarantee a "canonical" path. That means
1664
* that the following pathologies should be weeded out:
1667
* /.././../usr/../bin//./sh
1669
diskURL = rpmGenPath(fl->buildRootURL, NULL, fileURL);
1672
const char ** argv = NULL;
1677
rpmError(RPMERR_BADSPEC, _("Glob not permitted: %s\n"),
1683
rc = rpmGlob(diskURL, &argc, &argv);
1684
if (rc == 0 && argc >= 1 && !myGlobPatternP(argv[0])) {
1685
for (i = 0; i < argc; i++) {
1686
rc = addFile(fl, argv[i], NULL);
1687
argv[i] = _free(argv[i]);
1691
rpmError(RPMERR_BADSPEC, _("File not found by glob: %s\n"),
1696
rc = addFile(fl, diskURL, NULL);
1700
diskURL = _free(diskURL);
1702
fl->processingFailed = 1;
1708
static int processPackageFiles(Spec spec, Package pkg,
1709
int installSpecialDoc, int test)
1710
/*@modifies spec->macros,
1711
pkg->cpioList, pkg->fileList, pkg->specialDoc, pkg->header */
1713
HGE_t hge = (HGE_t)headerGetEntryMinMemory;
1714
struct FileList_s fl;
1715
char *s, **files, **fp;
1716
const char *fileName;
1718
struct AttrRec_s arbuf;
1719
AttrRec specialDocAttrRec = &arbuf;
1720
char *specialDoc = NULL;
1723
multiLib = rpmExpandNumeric("%{_multilibno}");
1725
multiLib = RPMFILE_MULTILIB(multiLib);
1726
#endif /* MULTILIB */
1728
nullAttrRec(specialDocAttrRec);
1729
pkg->cpioList = NULL;
1731
if (pkg->fileFile) {
1736
/* XXX W2DO? urlPath might be useful here. */
1737
if (*pkg->fileFile == '/') {
1738
ffn = rpmGetPath(pkg->fileFile, NULL);
1740
/* XXX FIXME: add %{_buildsubdir} */
1741
ffn = rpmGetPath("%{_builddir}/",
1742
(spec->buildSubdir ? spec->buildSubdir : "") ,
1743
"/", pkg->fileFile, NULL);
1745
fd = Fopen(ffn, "r.fpio");
1747
if (fd == NULL || Ferror(fd)) {
1748
rpmError(RPMERR_BADFILENAME,
1749
_("Could not open %%files file %s: %s\n"),
1750
ffn, Fstrerror(fd));
1751
return RPMERR_BADFILENAME;
1755
/*@+voidabstract@*/ f = fdGetFp(fd); /*@=voidabstract@*/
1757
while (fgets(buf, sizeof(buf), f)) {
1758
handleComments(buf);
1759
if (expandMacros(spec, spec->macros, buf, sizeof(buf))) {
1760
rpmError(RPMERR_BADSPEC, _("line: %s\n"), buf);
1761
return RPMERR_BADSPEC;
1763
appendStringBuf(pkg->fileList, buf);
1768
/* Init the file list structure */
1769
memset(&fl, 0, sizeof(fl));
1771
/* XXX spec->buildRootURL == NULL, then xstrdup("") is returned */
1772
fl.buildRootURL = rpmGenPath(spec->rootURL, spec->buildRootURL, NULL);
1774
if (hge(pkg->header, RPMTAG_DEFAULTPREFIX, NULL, (void **)&fl.prefix, NULL))
1775
fl.prefix = xstrdup(fl.prefix);
1780
fl.totalFileSize = 0;
1781
fl.processingFailed = 0;
1783
fl.passedSpecialDoc = 0;
1784
fl.isSpecialDoc = 0;
1788
fl.currentFlags = 0;
1789
fl.currentVerifyFlags = 0;
1796
nullAttrRec(&fl.cur_ar);
1797
nullAttrRec(&fl.def_ar);
1799
fl.defVerifyFlags = RPMVERIFY_ALL;
1801
fl.currentLangs = NULL;
1803
fl.currentSpecdFlags = 0;
1804
fl.defSpecdFlags = 0;
1807
fl.docDirs[fl.docDirCount++] = xstrdup("/usr/doc");
1808
fl.docDirs[fl.docDirCount++] = xstrdup("/usr/man");
1809
fl.docDirs[fl.docDirCount++] = xstrdup("/usr/info");
1810
fl.docDirs[fl.docDirCount++] = xstrdup("/usr/X11R6/man");
1811
fl.docDirs[fl.docDirCount++] = xstrdup("/usr/share/doc");
1812
fl.docDirs[fl.docDirCount++] = xstrdup("/usr/share/man");
1813
fl.docDirs[fl.docDirCount++] = xstrdup("/usr/share/info");
1814
fl.docDirs[fl.docDirCount++] = rpmGetPath("%{_docdir}", NULL);
1815
fl.docDirs[fl.docDirCount++] = rpmGetPath("%{_mandir}", NULL);
1816
fl.docDirs[fl.docDirCount++] = rpmGetPath("%{_infodir}", NULL);
1819
fl.fileListRecsAlloced = 0;
1820
fl.fileListRecsUsed = 0;
1822
s = getStringBuf(pkg->fileList);
1823
files = splitString(s, strlen(s), '\n');
1825
for (fp = files; *fp != NULL; fp++) {
1831
/*@-nullpass@*/ /* LCL: buf is NULL ?!? */
1835
/* Reset for a new line in %files */
1838
fl.currentFlags = 0;
1839
/* turn explicit flags into %def'd ones (gosh this is hacky...) */
1840
fl.currentSpecdFlags = ((unsigned)fl.defSpecdFlags) >> 8;
1841
fl.currentVerifyFlags = fl.defVerifyFlags;
1842
fl.isSpecialDoc = 0;
1849
/* XXX should reset to %deflang value */
1850
if (fl.currentLangs) {
1852
for (i = 0; i < fl.nLangs; i++)
1853
/*@-unqualifiedtrans@*/
1854
fl.currentLangs[i] = _free(fl.currentLangs[i]);
1855
/*@=unqualifiedtrans@*/
1856
fl.currentLangs = _free(fl.currentLangs);
1860
dupAttrRec(&fl.def_ar, &fl.cur_ar);
1862
/*@-nullpass@*/ /* LCL: buf is NULL ?!? */
1863
if (parseForVerify(buf, &fl))
1865
if (parseForAttr(buf, &fl))
1867
if (parseForDev(buf, &fl))
1869
if (parseForConfig(buf, &fl))
1871
if (parseForLang(buf, &fl))
1873
/*@-nullstate@*/ /* FIX: pkg->fileFile might be NULL */
1874
if (parseForSimple(spec, pkg, buf, &fl, &fileName))
1878
if (fileName == NULL)
1881
if (fl.isSpecialDoc) {
1882
/* Save this stuff for last */
1883
specialDoc = _free(specialDoc);
1884
specialDoc = xstrdup(fileName);
1885
dupAttrRec(&fl.cur_ar, specialDocAttrRec);
1887
/*@-nullstate@*/ /* FIX: pkg->fileFile might be NULL */
1888
(void) processBinaryFile(pkg, &fl, fileName);
1893
/* Now process special doc, if there is one */
1895
if (installSpecialDoc) {
1896
(void) doScript(spec, RPMBUILD_STRINGBUF, "%doc", pkg->specialDoc, test);
1899
/* Reset for %doc */
1902
fl.currentFlags = 0;
1903
fl.currentVerifyFlags = 0;
1910
/* XXX should reset to %deflang value */
1911
if (fl.currentLangs) {
1913
for (i = 0; i < fl.nLangs; i++)
1914
/*@-unqualifiedtrans@*/
1915
fl.currentLangs[i] = _free(fl.currentLangs[i]);
1916
/*@=unqualifiedtrans@*/
1917
fl.currentLangs = _free(fl.currentLangs);
1921
dupAttrRec(specialDocAttrRec, &fl.cur_ar);
1922
freeAttrRec(specialDocAttrRec);
1924
/*@-nullstate@*/ /* FIX: pkg->fileFile might be NULL */
1925
(void) processBinaryFile(pkg, &fl, specialDoc);
1928
specialDoc = _free(specialDoc);
1931
freeSplitString(files);
1933
if (fl.processingFailed)
1936
/* Verify that file attributes scope over hardlinks correctly. */
1937
checkHardLinks(&fl);
1939
genCpioListAndHeader(&fl, (TFI_t *)&pkg->cpioList, pkg->header, 0);
1941
if (spec->timeCheck)
1942
timeCheck(spec->timeCheck, pkg->header);
1945
fl.buildRootURL = _free(fl.buildRootURL);
1946
fl.prefix = _free(fl.prefix);
1948
freeAttrRec(&fl.cur_ar);
1949
freeAttrRec(&fl.def_ar);
1951
if (fl.currentLangs) {
1953
for (i = 0; i < fl.nLangs; i++)
1954
/*@-unqualifiedtrans@*/
1955
fl.currentLangs[i] = _free(fl.currentLangs[i]);
1956
/*@=unqualifiedtrans@*/
1957
fl.currentLangs = _free(fl.currentLangs);
1960
fl.fileList = freeFileList(fl.fileList, fl.fileListRecsUsed);
1961
while (fl.docDirCount--)
1962
fl.docDirs[fl.docDirCount] = _free(fl.docDirs[fl.docDirCount]);
1963
return fl.processingFailed;
1966
void initSourceHeader(Spec spec)
1969
int_32 tag, type, count;
1972
spec->sourceHeader = headerNew();
1973
/* Only specific tags are added to the source package header */
1974
for (hi = headerInitIterator(spec->packages->header);
1975
headerNextIterator(hi, &tag, &type, &ptr, &count);
1976
ptr = headerFreeData(ptr, type))
1980
case RPMTAG_VERSION:
1981
case RPMTAG_RELEASE:
1983
case RPMTAG_SUMMARY:
1984
case RPMTAG_DESCRIPTION:
1985
case RPMTAG_PACKAGER:
1986
case RPMTAG_DISTRIBUTION:
1987
case RPMTAG_DISTURL:
1989
case RPMTAG_LICENSE:
1993
case RPMTAG_CHANGELOGTIME:
1994
case RPMTAG_CHANGELOGNAME:
1995
case RPMTAG_CHANGELOGTEXT:
1997
case HEADER_I18NTABLE:
1999
(void)headerAddEntry(spec->sourceHeader, tag, type, ptr, count);
2006
hi = headerFreeIterator(hi);
2008
/* Add the build restrictions */
2009
for (hi = headerInitIterator(spec->buildRestrictions);
2010
headerNextIterator(hi, &tag, &type, &ptr, &count);
2011
ptr = headerFreeData(ptr, type))
2014
(void) headerAddEntry(spec->sourceHeader, tag, type, ptr, count);
2016
hi = headerFreeIterator(hi);
2018
if (spec->BANames && spec->BACount > 0) {
2019
(void) headerAddEntry(spec->sourceHeader, RPMTAG_BUILDARCHS,
2020
RPM_STRING_ARRAY_TYPE,
2021
spec->BANames, spec->BACount);
2025
int processSourceFiles(Spec spec)
2027
struct Source *srcPtr;
2028
StringBuf sourceFiles;
2030
struct FileList_s fl;
2031
char *s, **files, **fp;
2034
sourceFiles = newStringBuf();
2037
* XXX This is where the source header for noarch packages needs
2038
* XXX to be initialized.
2040
if (spec->sourceHeader == NULL)
2041
initSourceHeader(spec);
2043
/* Construct the file list and source entries */
2044
appendLineStringBuf(sourceFiles, spec->specFile);
2045
if (spec->sourceHeader != NULL)
2046
for (srcPtr = spec->sources; srcPtr != NULL; srcPtr = srcPtr->next) {
2047
if (srcPtr->flags & RPMBUILD_ISSOURCE) {
2048
(void) headerAddOrAppendEntry(spec->sourceHeader, RPMTAG_SOURCE,
2049
RPM_STRING_ARRAY_TYPE, &srcPtr->source, 1);
2050
if (srcPtr->flags & RPMBUILD_ISNO) {
2051
(void) headerAddOrAppendEntry(spec->sourceHeader, RPMTAG_NOSOURCE,
2052
RPM_INT32_TYPE, &srcPtr->num, 1);
2055
if (srcPtr->flags & RPMBUILD_ISPATCH) {
2056
(void) headerAddOrAppendEntry(spec->sourceHeader, RPMTAG_PATCH,
2057
RPM_STRING_ARRAY_TYPE, &srcPtr->source, 1);
2058
if (srcPtr->flags & RPMBUILD_ISNO) {
2059
(void) headerAddOrAppendEntry(spec->sourceHeader, RPMTAG_NOPATCH,
2060
RPM_INT32_TYPE, &srcPtr->num, 1);
2065
sfn = rpmGetPath( ((srcPtr->flags & RPMBUILD_ISNO) ? "!" : ""),
2066
"%{_sourcedir}/", srcPtr->source, NULL);
2067
appendLineStringBuf(sourceFiles, sfn);
2072
for (pkg = spec->packages; pkg != NULL; pkg = pkg->next) {
2073
for (srcPtr = pkg->icon; srcPtr != NULL; srcPtr = srcPtr->next) {
2075
sfn = rpmGetPath( ((srcPtr->flags & RPMBUILD_ISNO) ? "!" : ""),
2076
"%{_sourcedir}/", srcPtr->source, NULL);
2077
appendLineStringBuf(sourceFiles, sfn);
2082
spec->sourceCpioList = NULL;
2084
fl.fileList = xcalloc((spec->numSources + 1), sizeof(*fl.fileList));
2085
fl.processingFailed = 0;
2086
fl.fileListRecsUsed = 0;
2087
fl.totalFileSize = 0;
2089
fl.buildRootURL = NULL;
2091
s = getStringBuf(sourceFiles);
2092
files = splitString(s, strlen(s), '\n');
2094
/* The first source file is the spec file */
2096
for (fp = files; *fp != NULL; fp++) {
2097
const char * diskURL, *diskPath;
2105
flp = &fl.fileList[x];
2107
flp->flags = isSpec ? RPMFILE_SPECFILE : 0;
2108
/* files with leading ! are no source files */
2109
if (*diskURL == '!') {
2110
flp->flags |= RPMFILE_GHOST;
2114
(void) urlPath(diskURL, &diskPath);
2116
flp->diskURL = xstrdup(diskURL);
2117
diskPath = strrchr(diskPath, '/');
2123
flp->fileURL = xstrdup(diskPath);
2124
flp->verifyFlags = RPMVERIFY_ALL;
2126
if (Stat(diskURL, &flp->fl_st)) {
2127
rpmError(RPMERR_BADSPEC, _("Bad file: %s: %s\n"),
2128
diskURL, strerror(errno));
2129
fl.processingFailed = 1;
2132
flp->uname = getUname(flp->fl_uid);
2133
flp->gname = getGname(flp->fl_gid);
2134
flp->langs = xstrdup("");
2136
fl.totalFileSize += flp->fl_size;
2138
if (! (flp->uname && flp->gname)) {
2139
rpmError(RPMERR_BADSPEC, _("Bad owner/group: %s\n"), diskURL);
2140
fl.processingFailed = 1;
2146
fl.fileListRecsUsed = x;
2147
freeSplitString(files);
2149
if (! fl.processingFailed) {
2150
if (spec->sourceHeader != NULL)
2151
genCpioListAndHeader(&fl, (TFI_t *)&spec->sourceCpioList,
2152
spec->sourceHeader, 1);
2155
sourceFiles = freeStringBuf(sourceFiles);
2156
fl.fileList = freeFileList(fl.fileList, fl.fileListRecsUsed);
2157
return fl.processingFailed;
2162
static StringBuf getOutputFrom(char * dir, char * argv[],
2163
const char * writePtr, int writeBytesLeft,
2175
oldhandler = signal(SIGPIPE, SIG_IGN);
2177
toProg[0] = toProg[1] = 0;
2178
(void) pipe(toProg);
2179
fromProg[0] = fromProg[1] = 0;
2180
(void) pipe(fromProg);
2182
if (!(progPID = fork())) {
2183
(void) close(toProg[1]);
2184
(void) close(fromProg[0]);
2186
(void) dup2(toProg[0], STDIN_FILENO); /* Make stdin the in pipe */
2187
(void) dup2(fromProg[1], STDOUT_FILENO); /* Make stdout the out pipe */
2189
(void) close(toProg[0]);
2190
(void) close(fromProg[1]);
2196
(void) execvp(argv[0], argv);
2197
/* XXX this error message is probably not seen. */
2198
rpmError(RPMERR_EXEC, _("Couldn't exec %s: %s\n"),
2199
argv[0], strerror(errno));
2203
rpmError(RPMERR_FORK, _("Couldn't fork %s: %s\n"),
2204
argv[0], strerror(errno));
2208
(void) close(toProg[0]);
2209
(void) close(fromProg[1]);
2211
/* Do not block reading or writing from/to prog. */
2212
(void) fcntl(fromProg[0], F_SETFL, O_NONBLOCK);
2213
(void) fcntl(toProg[1], F_SETFL, O_NONBLOCK);
2215
readBuff = newStringBuf();
2218
fd_set ibits, obits;
2225
/* XXX the select is mainly a timer since all I/O is non-blocking */
2228
if (fromProg[0] >= 0) {
2229
FD_SET(fromProg[0], &ibits);
2231
if (toProg[1] >= 0) {
2232
FD_SET(toProg[1], &obits);
2236
nfd = ((fromProg[0] > toProg[1]) ? fromProg[0] : toProg[1]);
2237
if ((rc = select(nfd, &ibits, &obits, NULL, &tv)) < 0) {
2243
/* Write any data to program */
2244
if (toProg[1] >= 0 && FD_ISSET(toProg[1], &obits)) {
2245
if (writeBytesLeft) {
2246
if ((nbw = write(toProg[1], writePtr,
2247
(1024<writeBytesLeft) ? 1024 : writeBytesLeft)) < 0) {
2248
if (errno != EAGAIN) {
2249
perror("getOutputFrom()");
2254
writeBytesLeft -= nbw;
2256
} else if (toProg[1] >= 0) { /* close write fd */
2257
(void) close(toProg[1]);
2262
/* Read any data from prog */
2263
{ char buf[BUFSIZ+1];
2264
while ((nbr = read(fromProg[0], buf, sizeof(buf)-1)) > 0) {
2266
appendStringBuf(readBuff, buf);
2270
/* terminate on (non-blocking) EOF or error */
2271
done = (nbr == 0 || (nbr < 0 && errno != EAGAIN));
2277
(void) close(toProg[1]);
2278
if (fromProg[0] >= 0)
2279
(void) close(fromProg[0]);
2280
(void) signal(SIGPIPE, oldhandler);
2282
/* Collect status from prog */
2283
(void)waitpid(progPID, &status, 0);
2284
if (failNonZero && (!WIFEXITED(status) || WEXITSTATUS(status))) {
2285
rpmError(RPMERR_EXEC, _("%s failed\n"), argv[0]);
2288
if (writeBytesLeft) {
2289
rpmError(RPMERR_EXEC, _("failed to write all data to %s\n"), argv[0]);
2298
/*@observer@*/ /*@null@*/ const char * msg;
2299
/*@observer@*/ const char * argv[4];
2309
/*@-exportlocal -exportheadervar@*/
2310
DepMsg_t depMsgs[] = {
2311
{ "Provides", { "%{__find_provides}", NULL, NULL, NULL },
2312
RPMTAG_PROVIDENAME, RPMTAG_PROVIDEVERSION, RPMTAG_PROVIDEFLAGS,
2314
{ "PreReq", { NULL, NULL, NULL, NULL },
2315
RPMTAG_REQUIRENAME, RPMTAG_REQUIREVERSION, RPMTAG_REQUIREFLAGS,
2316
RPMSENSE_PREREQ, 0 },
2317
{ "Requires(interp)", { NULL, "interp", NULL, NULL },
2318
-1, -1, RPMTAG_REQUIREFLAGS,
2319
_notpre(RPMSENSE_INTERP), 0 },
2320
{ "Requires(rpmlib)", { NULL, "rpmlib", NULL, NULL },
2321
-1, -1, RPMTAG_REQUIREFLAGS,
2322
_notpre(RPMSENSE_RPMLIB), 0 },
2323
{ "Requires(verify)", { NULL, "verify", NULL, NULL },
2324
-1, -1, RPMTAG_REQUIREFLAGS,
2325
RPMSENSE_SCRIPT_VERIFY, 0 },
2326
{ "Requires(pre)", { NULL, "pre", NULL, NULL },
2327
-1, -1, RPMTAG_REQUIREFLAGS,
2328
_notpre(RPMSENSE_SCRIPT_PRE), 0 },
2329
{ "Requires(post)", { NULL, "post", NULL, NULL },
2330
-1, -1, RPMTAG_REQUIREFLAGS,
2331
_notpre(RPMSENSE_SCRIPT_POST), 0 },
2332
{ "Requires(preun)", { NULL, "preun", NULL, NULL },
2333
-1, -1, RPMTAG_REQUIREFLAGS,
2334
_notpre(RPMSENSE_SCRIPT_PREUN), 0 },
2335
{ "Requires(postun)", { NULL, "postun", NULL, NULL },
2336
-1, -1, RPMTAG_REQUIREFLAGS,
2337
_notpre(RPMSENSE_SCRIPT_POSTUN), 0 },
2338
{ "Requires", { "%{__find_requires}", NULL, NULL, NULL },
2339
-1, -1, RPMTAG_REQUIREFLAGS, /* XXX inherit name/version arrays */
2340
RPMSENSE_PREREQ, RPMSENSE_PREREQ },
2341
{ "Conflicts", { "%{__find_conflicts}", NULL, NULL, NULL },
2342
RPMTAG_CONFLICTNAME, RPMTAG_CONFLICTVERSION, RPMTAG_CONFLICTFLAGS,
2344
{ "Obsoletes", { "%{__find_obsoletes}", NULL, NULL, NULL },
2345
RPMTAG_OBSOLETENAME, RPMTAG_OBSOLETEVERSION, RPMTAG_OBSOLETEFLAGS,
2347
{ NULL, { NULL, NULL, NULL, NULL }, 0, 0, 0, 0, 0 }
2349
/*@=exportlocal =exportheadervar@*/
2353
static int generateDepends(Spec spec, Package pkg, TFI_t cpioList, int multiLib)
2354
/*@modifies cpioList @*/
2356
TFI_t fi = cpioList;
2362
int failnonzero = 0;
2366
if (!(fi && fi->fc > 0))
2369
if (! (pkg->autoReq || pkg->autoProv))
2372
writeBuf = newStringBuf();
2373
for (i = 0, writeBytes = 0; i < fi->fc; i++) {
2375
if (fi->fmapflags && multiLib == 2) {
2376
if (!(fi->fmapflags[i] & CPIO_MULTILIB))
2378
fi->fmapflags[i] &= ~CPIO_MULTILIB;
2381
appendStringBuf(writeBuf, fi->dnl[fi->dil[i]]);
2382
writeBytes += strlen(fi->dnl[fi->dil[i]]);
2383
appendLineStringBuf(writeBuf, fi->bnl[i]);
2384
writeBytes += strlen(fi->bnl[i]) + 1;
2387
for (dm = depMsgs; dm->msg != NULL; dm++) {
2390
tag = (dm->ftag > 0) ? dm->ftag : dm->ntag;
2394
case RPMTAG_PROVIDEFLAGS:
2398
tagflags = RPMSENSE_FIND_PROVIDES;
2400
case RPMTAG_REQUIREFLAGS:
2404
tagflags = RPMSENSE_FIND_REQUIRES;
2408
/*@notreached@*/ break;
2411
/* Get the script name to run */
2412
/*@-nullderef@*/ /* FIX: double indirection. @*/
2413
myargv[0] = (dm->argv[0] ? rpmExpand(dm->argv[0], NULL) : NULL);
2416
if (!(myargv[0] && *myargv[0] != '%')) {
2417
myargv[0] = _free(myargv[0]);
2421
rpmMessage(RPMMESS_NORMAL, _("Finding %s: (using %s)...\n"),
2422
dm->msg, myargv[0]);
2425
if (*myargv[0] != '/') { /* XXX FIXME: stat script here */
2426
myargv[0] = _free(myargv[0]);
2431
/* Expand rest of script arguments (if any) */
2432
for (i = 1; i < 4; i++) {
2433
/*@-nullderef@*/ /* FIX: double indirection. @*/
2434
myargv[i] = dm->argv[i] ? rpmExpand(dm->argv[i], NULL) : NULL;
2438
readBuf = getOutputFrom(NULL, myargv,
2439
getStringBuf(writeBuf), writeBytes, failnonzero);
2441
/* Free expanded args */
2442
for (i = 0; i < 4; i++)
2443
myargv[i] = _free(myargv[i]);
2445
if (readBuf == NULL) {
2447
rpmError(rc, _("Failed to find %s:\n"), dm->msg);
2451
/* Parse dependencies into header */
2452
tagflags &= ~RPMSENSE_MULTILIB;
2454
tagflags |= RPMSENSE_MULTILIB;
2456
tagflags &= ~RPMSENSE_MULTILIB;
2457
rc = parseRCPOT(spec, pkg, getStringBuf(readBuf), tag, 0, tagflags);
2458
readBuf = freeStringBuf(readBuf);
2461
rpmError(rc, _("Failed to find %s:\n"), dm->msg);
2466
writeBuf = freeStringBuf(writeBuf);
2472
static void printDepMsg(DepMsg_t * dm, int count, const char ** names,
2473
const char ** versions, int *flags)
2474
/*@modifies fileSystem @*/
2476
int hasVersions = (versions != NULL);
2477
int hasFlags = (flags != NULL);
2481
for (i = 0; i < count; i++, names++, versions++, flags++) {
2482
if (hasFlags && !((*flags & dm->mask) ^ dm->xor))
2485
rpmMessage(RPMMESS_NORMAL, "%s:", (dm->msg ? dm->msg : ""));
2488
rpmMessage(RPMMESS_NORMAL, " %s", *names);
2490
if (hasFlags && isDependsMULTILIB(*flags))
2491
rpmMessage(RPMMESS_NORMAL, " (multilib)");
2493
if (hasVersions && !(*versions != NULL && **versions != '\0'))
2495
if (!(hasFlags && (*flags && RPMSENSE_SENSEMASK)))
2498
rpmMessage(RPMMESS_NORMAL, " ");
2499
if (*flags & RPMSENSE_LESS)
2500
rpmMessage(RPMMESS_NORMAL, "<");
2501
if (*flags & RPMSENSE_GREATER)
2502
rpmMessage(RPMMESS_NORMAL, ">");
2503
if (*flags & RPMSENSE_EQUAL)
2504
rpmMessage(RPMMESS_NORMAL, "=");
2506
rpmMessage(RPMMESS_NORMAL, " %s", *versions);
2509
rpmMessage(RPMMESS_NORMAL, "\n");
2514
static void printDeps(Header h)
2515
/*@modifies fileSystem @*/
2517
HGE_t hge = (HGE_t)headerGetEntryMinMemory;
2518
HFD_t hfd = headerFreeData;
2519
const char ** names = NULL;
2520
rpmTagType dnt = -1;
2521
const char ** versions = NULL;
2522
rpmTagType dvt = -1;
2527
for (dm = depMsgs; dm->msg != NULL; dm++) {
2530
names = hfd(names, dnt);
2535
names = hfd(names, dnt);
2536
if (!hge(h, dm->ntag, &dnt, (void **) &names, &count))
2542
versions = hfd(versions, dvt);
2547
versions = hfd(versions, dvt);
2548
(void) hge(h, dm->vtag, &dvt, (void **) &versions, NULL);
2558
(void) hge(h, dm->ftag, NULL, (void **) &flags, NULL);
2561
printDepMsg(dm, count, names, versions, flags);
2563
names = hfd(names, dnt);
2564
versions = hfd(versions, dvt);
2567
int processBinaryFiles(Spec spec, int installSpecialDoc, int test)
2572
for (pkg = spec->packages; pkg != NULL; pkg = pkg->next) {
2573
const char *n, *v, *r;
2576
if (pkg->fileList == NULL)
2579
(void) headerNVR(pkg->header, &n, &v, &r);
2580
rpmMessage(RPMMESS_NORMAL, _("Processing files: %s-%s-%s\n"), n, v, r);
2582
if ((rc = processPackageFiles(spec, pkg, installSpecialDoc, test)))
2585
/* XXX This should be added always so that packages look alike.
2586
* XXX However, there is logic in files.c/depends.c that checks for
2587
* XXX existence (rather than value) that will need to change as well.
2589
if (headerIsEntry(pkg->header, RPMTAG_MULTILIBS)) {
2590
(void) generateDepends(spec, pkg, pkg->cpioList, 1);
2591
(void) generateDepends(spec, pkg, pkg->cpioList, 2);
2593
(void) generateDepends(spec, pkg, pkg->cpioList, 0);
2594
printDeps(pkg->header);