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
36 extern int _noDirTokens;
41 typedef enum specdFlags_e {
42 SPECD_DEFFILEMODE = (1 << 0),
43 SPECD_DEFDIRMODE = (1 << 1),
44 SPECD_DEFUID = (1 << 2),
45 SPECD_DEFGID = (1 << 3),
46 SPECD_DEFVERIFY = (1 << 4),
48 SPECD_FILEMODE = (1 << 8),
49 SPECD_DIRMODE = (1 << 9),
50 SPECD_UID = (1 << 10),
51 SPECD_GID = (1 << 11),
52 SPECD_VERIFY = (1 << 12)
57 typedef struct FileListRec_s {
59 #define fl_dev fl_st.st_dev
60 #define fl_ino fl_st.st_ino
61 #define fl_mode fl_st.st_mode
62 #define fl_nlink fl_st.st_nlink
63 #define fl_uid fl_st.st_uid
64 #define fl_gid fl_st.st_gid
65 #define fl_rdev fl_st.st_rdev
66 #define fl_size fl_st.st_size
67 #define fl_mtime fl_st.st_mtime
69 /*@only@*/ const char * diskURL; /* get file from here */
70 /*@only@*/ const char * fileURL; /* filename in cpio archive */
71 /*@observer@*/ const char * uname;
72 /*@observer@*/ const char * gname;
74 specdFlags specdFlags; /* which attributes have been explicitly specified. */
76 /*@only@*/ const char *langs; /* XXX locales separated with | */
81 typedef struct AttrRec_s {
82 const char * ar_fmodestr;
83 const char * ar_dmodestr;
85 const char * ar_group;
93 static int multiLib = 0; /* MULTILIB */
96 * Package file tree walk data.
98 typedef struct FileList_s {
99 /*@only@*/ const char * buildRootURL;
100 /*@only@*/ const char * prefix;
104 int processingFailed;
106 int passedSpecialDoc;
117 specdFlags currentSpecdFlags;
118 int currentVerifyFlags;
119 struct AttrRec_s cur_ar;
120 struct AttrRec_s def_ar;
121 specdFlags defSpecdFlags;
124 /*@only@*/ /*@null@*/ const char ** currentLangs;
126 /* Hard coded limit of MAXDOCDIR docdirs. */
127 /* If you break it you are doing something wrong. */
128 const char * docDirs[MAXDOCDIR];
131 /*@only@*/ FileListRec fileList;
132 int fileListRecsAlloced;
133 int fileListRecsUsed;
138 static void nullAttrRec(/*@out@*/ AttrRec ar) /*@modifies ar @*/
140 ar->ar_fmodestr = NULL;
141 ar->ar_dmodestr = NULL;
150 static void freeAttrRec(AttrRec ar) /*@modifies ar @*/
152 ar->ar_fmodestr = _free(ar->ar_fmodestr);
153 ar->ar_dmodestr = _free(ar->ar_dmodestr);
154 ar->ar_user = _free(ar->ar_user);
155 ar->ar_group = _free(ar->ar_group);
156 /* XXX doesn't free ar (yet) */
164 static void dupAttrRec(const AttrRec oar, /*@in@*/ /*@out@*/ AttrRec nar)
170 nar->ar_fmodestr = (oar->ar_fmodestr ? xstrdup(oar->ar_fmodestr) : NULL);
171 nar->ar_dmodestr = (oar->ar_dmodestr ? xstrdup(oar->ar_dmodestr) : NULL);
172 nar->ar_user = (oar->ar_user ? xstrdup(oar->ar_user) : NULL);
173 nar->ar_group = (oar->ar_group ? xstrdup(oar->ar_group) : NULL);
174 nar->ar_fmode = oar->ar_fmode;
175 nar->ar_dmode = oar->ar_dmode;
181 static void dumpAttrRec(const char * msg, AttrRec ar)
182 /*@globals fileSystem@*/
183 /*@modifies fileSystem @*/
186 fprintf(stderr, "%s:\t", msg);
187 fprintf(stderr, "(%s, %s, %s, %s)\n",
195 /* strtokWithQuotes() modified from glibc strtok() */
196 /* Copyright (C) 1991, 1996 Free Software Foundation, Inc.
197 This file is part of the GNU C Library.
199 The GNU C Library is free software; you can redistribute it and/or
200 modify it under the terms of the GNU Library General Public License as
201 published by the Free Software Foundation; either version 2 of the
202 License, or (at your option) any later version.
204 The GNU C Library is distributed in the hope that it will be useful,
205 but WITHOUT ANY WARRANTY; without even the implied warranty of
206 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
207 Library General Public License for more details.
209 You should have received a copy of the GNU Library General Public
210 License along with the GNU C Library; see the file COPYING.LIB. If
211 not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
212 Boston, MA 02111-1307, USA. */
216 static char *strtokWithQuotes(char *s, char *delim)
219 static char *olds = NULL;
226 /* Skip leading delimiters */
227 s += strspn(s, delim);
232 /* Find the end of the token. */
236 /* Find next " char */
237 s = strchr(token, '"');
239 s = strpbrk(token, delim);
244 /* This token finishes the string */
245 olds = strchr(token, '\0');
247 /* Terminate the token and make olds point past it */
257 static void timeCheck(int tc, Header h)
258 /*@globals internalState @*/
259 /*@modifies internalState @*/
261 HGE_t hge = (HGE_t)headerGetEntryMinMemory;
262 HFD_t hfd = headerFreeData;
267 time_t currentTime = time(NULL);
269 x = hge(h, RPMTAG_OLDFILENAMES, &fnt, (void **) &files, &count);
270 x = hge(h, RPMTAG_FILEMTIMES, NULL, (void **) &mtime, NULL);
272 for (x = 0; x < count; x++) {
273 if ((currentTime - mtime[x]) > tc)
274 rpmMessage(RPMMESS_WARNING, _("TIMECHECK failure: %s\n"), files[x]);
276 files = hfd(files, fnt);
282 /*@observer@*/ /*@null@*/ const char * attribute;
288 /*@-exportlocal -exportheadervar@*/
290 VFA_t verifyAttrs[] = {
291 { "md5", RPMVERIFY_MD5 },
292 { "size", RPMVERIFY_FILESIZE },
293 { "link", RPMVERIFY_LINKTO },
294 { "user", RPMVERIFY_USER },
295 { "group", RPMVERIFY_GROUP },
296 { "mtime", RPMVERIFY_MTIME },
297 { "mode", RPMVERIFY_MODE },
298 { "rdev", RPMVERIFY_RDEV },
301 /*@=exportlocal =exportheadervar@*/
304 * @param fl package file tree walk data
306 static int parseForVerify(char * buf, FileList fl)
307 /*@modifies buf, fl->processingFailed,
308 fl->currentVerifyFlags, fl->defVerifyFlags,
309 fl->currentSpecdFlags, fl->defSpecdFlags @*/
316 specdFlags * specdFlags;
318 if ((p = strstr(buf, (name = "%verify"))) != NULL) {
319 resultVerify = &(fl->currentVerifyFlags);
320 specdFlags = &fl->currentSpecdFlags;
321 } else if ((p = strstr(buf, (name = "%defverify"))) != NULL) {
322 resultVerify = &(fl->defVerifyFlags);
323 specdFlags = &fl->defSpecdFlags;
327 for (pe = p; (pe-p) < strlen(name); pe++)
333 rpmError(RPMERR_BADSPEC, _("Missing '(' in %s %s\n"), name, pe);
334 fl->processingFailed = 1;
335 return RPMERR_BADSPEC;
338 /* Bracket %*verify args */
340 for (p = pe; *pe && *pe != ')'; pe++)
344 rpmError(RPMERR_BADSPEC, _("Missing ')' in %s(%s\n"), name, p);
345 fl->processingFailed = 1;
346 return RPMERR_BADSPEC;
349 /* Localize. Erase parsed string */
350 q = alloca((pe-p) + 1);
357 verifyFlags = RPMVERIFY_NONE;
359 for (p = q; *p != '\0'; p = pe) {
369 for (vfa = verifyAttrs; vfa->attribute != NULL; vfa++) {
370 if (strcmp(p, vfa->attribute))
371 /*@innercontinue@*/ continue;
372 verifyFlags |= vfa->flag;
373 /*@innerbreak@*/ break;
379 if (!strcmp(p, "not")) {
382 rpmError(RPMERR_BADSPEC, _("Invalid %s token: %s\n"), name, p);
383 fl->processingFailed = 1;
384 return RPMERR_BADSPEC;
388 *resultVerify = negated ? ~(verifyFlags) : verifyFlags;
389 *specdFlags |= SPECD_VERIFY;
394 #define isAttrDefault(_ars) ((_ars)[0] == '-' && (_ars)[1] == '\0')
397 * Parse %dev from file manifest.
398 * @param fl package file tree walk data
400 static int parseForDev(char * buf, FileList fl)
401 /*@modifies buf, fl->processingFailed,
402 fl->noGlob, fl->devtype, fl->devmajor, fl->devminor @*/
405 const char * errstr = NULL;
407 int rc = RPMERR_BADSPEC; /* assume error */
409 if ((p = strstr(buf, (name = "%dev"))) == NULL)
412 for (pe = p; (pe-p) < strlen(name); pe++)
421 /* Bracket %dev args */
423 for (p = pe; *pe && *pe != ')'; pe++)
430 /* Localize. Erase parsed string */
431 q = alloca((pe-p) + 1);
438 pe = p; SKIPNONWHITE(pe); if (*pe != '\0') *pe++ = '\0';
448 p = pe; SKIPWHITE(p);
449 pe = p; SKIPNONWHITE(pe); if (*pe != '\0') *pe++ = '\0';
450 for (pe = p; *pe && xisdigit(*pe); pe++)
453 fl->devmajor = atoi(p);
454 /*@-unsignedcompare @*/ /* LCL: ge is ok */
455 if (!(fl->devmajor >= 0 && fl->devmajor < 256)) {
459 /*@=unsignedcompare @*/
466 p = pe; SKIPWHITE(p);
467 pe = p; SKIPNONWHITE(pe); if (*pe != '\0') *pe++ = '\0';
468 for (pe = p; *pe && xisdigit(*pe); pe++)
471 fl->devminor = atoi(p);
472 if (!(fl->devminor >= 0 && fl->devminor < 256)) {
488 rpmError(RPMERR_BADSPEC, _("Missing %s in %s %s\n"), errstr, name, p);
489 fl->processingFailed = 1;
495 * Parse %attr and %defattr from file manifest.
496 * @param fl package file tree walk data
498 static int parseForAttr(char * buf, FileList fl)
499 /*@modifies buf, fl->processingFailed,
500 fl->cur_ar, fl->def_ar,
501 fl->currentSpecdFlags, fl->defSpecdFlags @*/
506 struct AttrRec_s arbuf;
507 AttrRec ar = &arbuf, ret_ar;
508 specdFlags * specdFlags;
510 if ((p = strstr(buf, (name = "%attr"))) != NULL) {
511 ret_ar = &(fl->cur_ar);
512 specdFlags = &fl->currentSpecdFlags;
513 } else if ((p = strstr(buf, (name = "%defattr"))) != NULL) {
514 ret_ar = &(fl->def_ar);
515 specdFlags = &fl->defSpecdFlags;
519 for (pe = p; (pe-p) < strlen(name); pe++)
525 rpmError(RPMERR_BADSPEC, _("Missing '(' in %s %s\n"), name, pe);
526 fl->processingFailed = 1;
527 return RPMERR_BADSPEC;
530 /* Bracket %*attr args */
532 for (p = pe; *pe && *pe != ')'; pe++)
535 if (ret_ar == &(fl->def_ar)) { /* %defattr */
540 rpmError(RPMERR_BADSPEC,
541 _("Non-white space follows %s(): %s\n"), name, q);
542 fl->processingFailed = 1;
543 return RPMERR_BADSPEC;
547 /* Localize. Erase parsed string */
548 q = alloca((pe-p) + 1);
558 pe = p; SKIPNONWHITE(pe); if (*pe != '\0') *pe++ = '\0';
560 p = pe; SKIPWHITE(p);
563 pe = p; SKIPNONWHITE(pe); if (*pe != '\0') *pe++ = '\0';
565 p = pe; SKIPWHITE(p);
568 pe = p; SKIPNONWHITE(pe); if (*pe != '\0') *pe++ = '\0';
570 p = pe; SKIPWHITE(p);
572 if (*p != '\0' && ret_ar == &(fl->def_ar)) { /* %defattr */
573 pe = p; SKIPNONWHITE(pe); if (*pe != '\0') *pe++ = '\0';
575 p = pe; SKIPWHITE(p);
578 if (!(ar->ar_fmodestr && ar->ar_user && ar->ar_group) || *p != '\0') {
579 rpmError(RPMERR_BADSPEC, _("Bad syntax: %s(%s)\n"), name, q);
580 fl->processingFailed = 1;
581 return RPMERR_BADSPEC;
584 /* Do a quick test on the mode argument and adjust for "-" */
585 if (ar->ar_fmodestr && !isAttrDefault(ar->ar_fmodestr)) {
587 x = sscanf(ar->ar_fmodestr, "%o", &ui);
588 if ((x == 0) || (ar->ar_fmode & ~MYALLPERMS)) {
589 rpmError(RPMERR_BADSPEC, _("Bad mode spec: %s(%s)\n"), name, q);
590 fl->processingFailed = 1;
591 return RPMERR_BADSPEC;
595 ar->ar_fmodestr = NULL;
597 if (ar->ar_dmodestr && !isAttrDefault(ar->ar_dmodestr)) {
599 x = sscanf(ar->ar_dmodestr, "%o", &ui);
600 if ((x == 0) || (ar->ar_dmode & ~MYALLPERMS)) {
601 rpmError(RPMERR_BADSPEC, _("Bad dirmode spec: %s(%s)\n"), name, q);
602 fl->processingFailed = 1;
603 return RPMERR_BADSPEC;
607 ar->ar_dmodestr = NULL;
609 if (!(ar->ar_user && !isAttrDefault(ar->ar_user)))
612 if (!(ar->ar_group && !isAttrDefault(ar->ar_group)))
615 dupAttrRec(ar, ret_ar);
617 /* XXX fix all this */
618 *specdFlags |= SPECD_UID | SPECD_GID | SPECD_FILEMODE | SPECD_DIRMODE;
624 * @param fl package file tree walk data
626 static int parseForConfig(char * buf, FileList fl)
627 /*@modifies buf, fl->processingFailed,
633 if ((p = strstr(buf, (name = "%config"))) == NULL)
636 fl->currentFlags = RPMFILE_CONFIG;
638 for (pe = p; (pe-p) < strlen(name); pe++)
644 /* Bracket %config args */
646 for (p = pe; *pe && *pe != ')'; pe++)
650 rpmError(RPMERR_BADSPEC, _("Missing ')' in %s(%s\n"), name, p);
651 fl->processingFailed = 1;
652 return RPMERR_BADSPEC;
655 /* Localize. Erase parsed string */
656 q = alloca((pe-p) + 1);
662 for (p = q; *p != '\0'; p = pe) {
670 if (!strcmp(p, "missingok")) {
671 fl->currentFlags |= RPMFILE_MISSINGOK;
672 } else if (!strcmp(p, "noreplace")) {
673 fl->currentFlags |= RPMFILE_NOREPLACE;
675 rpmError(RPMERR_BADSPEC, _("Invalid %s token: %s\n"), name, p);
676 fl->processingFailed = 1;
677 return RPMERR_BADSPEC;
686 static int langCmp(const void * ap, const void * bp) /*@*/
688 return strcmp(*(const char **)ap, *(const char **)bp);
692 * @param fl package file tree walk data
694 static int parseForLang(char * buf, FileList fl)
695 /*@modifies buf, fl->processingFailed,
696 fl->currentLangs, fl->nLangs @*/
701 while ((p = strstr(buf, (name = "%lang"))) != NULL) {
703 for (pe = p; (pe-p) < strlen(name); pe++)
708 rpmError(RPMERR_BADSPEC, _("Missing '(' in %s %s\n"), name, pe);
709 fl->processingFailed = 1;
710 return RPMERR_BADSPEC;
713 /* Bracket %lang args */
715 for (pe = p; *pe && *pe != ')'; pe++)
719 rpmError(RPMERR_BADSPEC, _("Missing ')' in %s(%s\n"), name, p);
720 fl->processingFailed = 1;
721 return RPMERR_BADSPEC;
724 /* Localize. Erase parsed string */
725 q = alloca((pe-p) + 1);
731 /* Parse multiple arguments from %lang */
732 for (p = q; *p != '\0'; p = pe) {
743 /* Sanity check on locale lengths */
744 if (np < 1 || (np == 1 && *p != 'C') || np >= 32) {
745 rpmError(RPMERR_BADSPEC,
746 _("Unusual locale length: \"%.*s\" in %%lang(%s)\n"),
748 fl->processingFailed = 1;
749 return RPMERR_BADSPEC;
752 /* Check for duplicate locales */
753 if (fl->currentLangs != NULL)
754 for (i = 0; i < fl->nLangs; i++) {
755 if (strncmp(fl->currentLangs[i], p, np))
756 /*@innercontinue@*/ continue;
757 rpmError(RPMERR_BADSPEC, _("Duplicate locale %.*s in %%lang(%s)\n"),
759 fl->processingFailed = 1;
760 return RPMERR_BADSPEC;
764 fl->currentLangs = xrealloc(fl->currentLangs,
765 (fl->nLangs + 1) * sizeof(*fl->currentLangs));
766 newp = xmalloc( np+1 );
767 strncpy(newp, p, np);
769 fl->currentLangs[fl->nLangs++] = newp;
770 if (*pe == ',') pe++; /* skip , if present */
774 /* Insure that locales are sorted. */
775 if (fl->currentLangs)
776 qsort(fl->currentLangs, fl->nLangs, sizeof(*fl->currentLangs), langCmp);
783 static int parseForRegexLang(const char * fileName, /*@out@*/ char ** lang)
784 /*@globals rpmGlobalMacroContext @*/
785 /*@modifies *lang, rpmGlobalMacroContext @*/
787 static int initialized = 0;
788 static int hasRegex = 0;
789 static regex_t compiledPatt;
790 static char buf[BUFSIZ];
792 regmatch_t matches[2];
796 const char *patt = rpmExpand("%{_langpatt}", NULL);
798 if (!(patt && *patt != '%'))
800 else if (regcomp(&compiledPatt, patt, REG_EXTENDED))
809 memset(matches, 0, sizeof(matches));
810 if (! hasRegex || regexec(&compiledPatt, fileName, 2, matches, REG_NOTEOL))
814 s = fileName + matches[1].rm_eo - 1;
815 x = matches[1].rm_eo - matches[1].rm_so;
827 static int parseForRegexMultiLib(const char *fileName)
828 /*@globals rpmGlobalMacroContext @*/
829 /*@modifies rpmGlobalMacroContext @*/
831 static int initialized = 0;
832 static int hasRegex = 0;
833 static regex_t compiledPatt;
840 patt = rpmExpand("%{_multilibpatt}", NULL);
841 if (!(patt && *patt != '%'))
843 else if (regcomp(&compiledPatt, patt, REG_EXTENDED | REG_NOSUB))
851 if (! hasRegex || regexec(&compiledPatt, fileName, 0, NULL, 0))
859 /*@-exportlocal -exportheadervar@*/
861 VFA_t virtualFileAttributes[] = {
862 { "%dir", 0 }, /* XXX why not RPMFILE_DIR? */
863 { "%doc", RPMFILE_DOC },
864 { "%ghost", RPMFILE_GHOST },
865 { "%exclude", RPMFILE_EXCLUDE },
866 { "%readme", RPMFILE_README },
867 { "%license", RPMFILE_LICENSE },
871 { "%spec", RPMFILE_SPEC },
872 { "%config", RPMFILE_CONFIG },
873 { "%donotuse", RPMFILE_DONOTUSE }, /* XXX WTFO? */
874 { "%missingok", RPMFILE_CONFIG|RPMFILE_MISSINGOK },
875 { "%noreplace", RPMFILE_CONFIG|RPMFILE_NOREPLACE },
880 /*@=exportlocal =exportheadervar@*/
883 * @param fl package file tree walk data
885 static int parseForSimple(/*@unused@*/Spec spec, Package pkg, char * buf,
886 FileList fl, /*@out@*/ const char ** fileName)
887 /*@globals rpmGlobalMacroContext @*/
888 /*@modifies buf, fl->processingFailed, *fileName,
890 fl->docDirs, fl->docDirCount, fl->isDir,
891 fl->passedSpecialDoc, fl->isSpecialDoc,
892 pkg->specialDoc, rpmGlobalMacroContext @*/
895 int res, specialDoc = 0;
896 char specialDocBuf[BUFSIZ];
898 specialDocBuf[0] = '\0';
903 while ((s = strtokWithQuotes(t, " \t\n")) != NULL) {
905 if (!strcmp(s, "%docdir")) {
906 s = strtokWithQuotes(NULL, " \t\n");
907 if (fl->docDirCount == MAXDOCDIR) {
908 rpmError(RPMERR_INTERNAL, _("Hit limit for %%docdir\n"));
909 fl->processingFailed = 1;
912 fl->docDirs[fl->docDirCount++] = xstrdup(s);
913 if (strtokWithQuotes(NULL, " \t\n")) {
914 rpmError(RPMERR_INTERNAL, _("Only one arg for %%docdir\n"));
915 fl->processingFailed = 1;
921 /* Set flags for virtual file attributes */
923 for (vfa = virtualFileAttributes; vfa->attribute != NULL; vfa++) {
924 if (strcmp(s, vfa->attribute))
925 /*@innercontinue@*/ continue;
927 if (!strcmp(s, "%dir"))
928 fl->isDir = 1; /* XXX why not RPMFILE_DIR? */
929 else if (!strcmp(s, "%multilib"))
930 fl->currentFlags |= multiLib;
932 fl->currentFlags |= vfa->flag;
933 /*@innerbreak@*/ break;
935 /* if we got an attribute, continue with next token */
936 if (vfa->attribute != NULL)
941 /* We already got a file -- error */
942 rpmError(RPMERR_BADSPEC, _("Two files on one line: %s\n"),
944 fl->processingFailed = 1;
950 if (fl->currentFlags & RPMFILE_DOC) {
952 strcat(specialDocBuf, " ");
953 strcat(specialDocBuf, s);
955 /* not in %doc, does not begin with / -- error */
956 rpmError(RPMERR_BADSPEC,
957 _("File must begin with \"/\": %s\n"), s);
958 fl->processingFailed = 1;
968 if (*fileName || (fl->currentFlags & ~(RPMFILE_DOC))) {
969 rpmError(RPMERR_BADSPEC,
970 _("Can't mix special %%doc with other forms: %s\n"),
971 (*fileName ? *fileName : ""));
972 fl->processingFailed = 1;
975 /* XXX WATCHOUT: buf is an arg */
976 { const char *ddir, *n, *v;
978 (void) headerNVR(pkg->header, &n, &v, NULL);
980 ddir = rpmGetPath("%{_docdir}/", n, "-", v, NULL);
985 /* XXX FIXME: this is easy to do as macro expansion */
987 if (! fl->passedSpecialDoc) {
988 pkg->specialDoc = newStringBuf();
989 appendStringBuf(pkg->specialDoc, "DOCDIR=$RPM_BUILD_ROOT");
990 appendLineStringBuf(pkg->specialDoc, buf);
991 appendLineStringBuf(pkg->specialDoc, "export DOCDIR");
992 appendLineStringBuf(pkg->specialDoc, "rm -rf $DOCDIR");
993 appendLineStringBuf(pkg->specialDoc, MKDIR_P " $DOCDIR");
998 fl->passedSpecialDoc = 1;
999 fl->isSpecialDoc = 1;
1002 appendStringBuf(pkg->specialDoc, "cp -pr ");
1003 appendStringBuf(pkg->specialDoc, specialDocBuf);
1004 appendLineStringBuf(pkg->specialDoc, " $DOCDIR");
1013 static int compareFileListRecs(const void * ap, const void * bp) /*@*/
1015 const char *a = ((FileListRec)ap)->fileURL;
1016 const char *b = ((FileListRec)bp)->fileURL;
1017 return strcmp(a, b);
1021 * @param fl package file tree walk data
1023 static int isDoc(FileList fl, const char * fileName) /*@*/
1025 int x = fl->docDirCount;
1028 if (strstr(fileName, fl->docDirs[x]) == fileName)
1035 * Verify that file attributes scope over hardlinks correctly.
1036 * @todo only %lang for now, finish other attributes later.
1037 * @param fl package file tree walk data
1039 static void checkHardLinks(FileList fl)
1040 /*@modifies fl->fileList->flags, fl->fileList->langs @*/
1042 char nlangs[BUFSIZ];
1043 FileListRec ilp, jlp;
1047 for (i = 0; i < fl->fileListRecsUsed; i++) {
1050 ilp = fl->fileList + i;
1051 if (!(S_ISREG(ilp->fl_mode) && ilp->fl_nlink > 1))
1053 if (ilp->flags & RPMFILE_SPECFILE)
1058 for (j = i + 1; j < fl->fileListRecsUsed; j++) {
1059 jlp = fl->fileList + j;
1060 if (!S_ISREG(jlp->fl_mode))
1061 /*@innercontinue@*/ continue;
1062 if (ilp->fl_nlink != jlp->fl_nlink)
1063 /*@innercontinue@*/ continue;
1064 if (ilp->fl_ino != jlp->fl_ino)
1065 /*@innercontinue@*/ continue;
1066 if (ilp->fl_dev != jlp->fl_dev)
1067 /*@innercontinue@*/ continue;
1068 if (!strcmp(ilp->langs, jlp->langs)) {
1069 jlp->flags |= RPMFILE_SPECFILE;
1070 /*@innercontinue@*/ continue;
1073 te = stpcpy(te, ilp->langs);
1075 te = stpcpy(te, jlp->langs);
1078 /* Are locales distributed over hard links correctly? */
1082 ilp->langs = _free(ilp->langs);
1083 ilp->langs = xstrdup(nlangs);
1084 for (j = i + 1; j < fl->fileListRecsUsed; j++) {
1085 jlp = fl->fileList + j;
1086 if (!S_ISREG(jlp->fl_mode))
1087 /*@innercontinue@*/ continue;
1088 if (ilp->fl_nlink != jlp->fl_nlink)
1089 /*@innercontinue@*/ continue;
1090 if (ilp->fl_ino != jlp->fl_ino)
1091 /*@innercontinue@*/ continue;
1092 if (ilp->fl_dev != jlp->fl_dev)
1093 /*@innercontinue@*/ continue;
1094 jlp->flags |= RPMFILE_SPECFILE;
1095 jlp->langs = _free(jlp->langs);
1096 jlp->langs = xstrdup(nlangs);
1100 for (i = 0; i < fl->fileListRecsUsed; i++) {
1101 ilp = fl->fileList + i;
1102 ilp->flags &= ~RPMFILE_SPECFILE;
1107 * @todo Should directories have %doc/%config attributes? (#14531)
1108 * @todo Remove RPMTAG_OLDFILENAMES, add dirname/basename instead.
1109 * @param fl package file tree walk data
1111 static void genCpioListAndHeader(/*@partial@*/ FileList fl,
1112 TFI_t * cpioList, Header h, int isSrc)
1113 /*@globals rpmGlobalMacroContext,
1115 /*@modifies h, *cpioList, fl->processingFailed, fl->fileList,
1116 rpmGlobalMacroContext, fileSystem @*/
1118 int _addDotSlash = !(isSrc || rpmExpandNumeric("%{_noPayloadPrefix}"));
1119 uint_32 multiLibMask = 0;
1127 /* Sort the big list */
1128 qsort(fl->fileList, fl->fileListRecsUsed,
1129 sizeof(*(fl->fileList)), compareFileListRecs);
1131 /* Generate the header. */
1135 skipLen += strlen(fl->prefix);
1138 for (i = 0, flp = fl->fileList; i < fl->fileListRecsUsed; i++, flp++) {
1141 /* Merge duplicate entries. */
1142 while (i < (fl->fileListRecsUsed - 1) &&
1143 !strcmp(flp->fileURL, flp[1].fileURL)) {
1145 /* Two entries for the same file found, merge the entries. */
1147 rpmMessage(RPMMESS_WARNING, _("File listed twice: %s\n"),
1151 flp[1].flags |= flp->flags;
1154 if (S_ISDIR(flp->fl_mode)) {
1155 if ((flp[1].specdFlags & (SPECD_DIRMODE | SPECD_DEFDIRMODE)) <
1156 (flp->specdFlags & (SPECD_DIRMODE | SPECD_DEFDIRMODE)))
1157 flp[1].fl_mode = flp->fl_mode;
1159 if ((flp[1].specdFlags & (SPECD_FILEMODE | SPECD_DEFFILEMODE)) <
1160 (flp->specdFlags & (SPECD_FILEMODE | SPECD_DEFFILEMODE)))
1161 flp[1].fl_mode = flp->fl_mode;
1165 if ((flp[1].specdFlags & (SPECD_UID | SPECD_DEFUID)) <
1166 (flp->specdFlags & (SPECD_UID | SPECD_DEFUID)))
1168 flp[1].fl_uid = flp->fl_uid;
1169 flp[1].uname = flp->uname;
1173 if ((flp[1].specdFlags & (SPECD_GID | SPECD_DEFGID)) <
1174 (flp->specdFlags & (SPECD_GID | SPECD_DEFGID)))
1176 flp[1].fl_gid = flp->fl_gid;
1177 flp[1].gname = flp->gname;
1181 if ((flp[1].specdFlags & (SPECD_VERIFY | SPECD_DEFVERIFY)) <
1182 (flp->specdFlags & (SPECD_VERIFY | SPECD_DEFVERIFY)))
1183 flp[1].verifyFlags = flp->verifyFlags;
1185 /* XXX to-do: language */
1190 /* Skip files that were marked with %exclude. */
1191 if (flp->flags & RPMFILE_EXCLUDE) continue;
1193 /* Omit '/' and/or URL prefix, leave room for "./" prefix */
1194 apathlen += (strlen(flp->fileURL) - skipLen + (_addDotSlash ? 3 : 1));
1196 /* Leave room for both dirname and basename NUL's */
1197 dpathlen += (strlen(flp->diskURL) + 2);
1199 if (flp->flags & RPMFILE_MULTILIB_MASK)
1201 (1u << ((flp->flags & RPMFILE_MULTILIB_MASK))
1202 >> RPMFILE_MULTILIB_SHIFT);
1205 * Make the header, the OLDFILENAMES will get converted to a
1206 * compressed file list write before we write the actual package to
1209 (void) headerAddOrAppendEntry(h, RPMTAG_OLDFILENAMES, RPM_STRING_ARRAY_TYPE,
1210 &(flp->fileURL), 1);
1213 if (sizeof(flp->fl_size) != sizeof(uint_32)) {
1214 uint_32 psize = (uint_32)flp->fl_size;
1215 (void) headerAddOrAppendEntry(h, RPMTAG_FILESIZES, RPM_INT32_TYPE,
1218 (void) headerAddOrAppendEntry(h, RPMTAG_FILESIZES, RPM_INT32_TYPE,
1219 &(flp->fl_size), 1);
1221 (void) headerAddOrAppendEntry(h, RPMTAG_FILEUSERNAME, RPM_STRING_ARRAY_TYPE,
1223 (void) headerAddOrAppendEntry(h, RPMTAG_FILEGROUPNAME, RPM_STRING_ARRAY_TYPE,
1225 (void) headerAddOrAppendEntry(h, RPMTAG_FILEMTIMES, RPM_INT32_TYPE,
1226 &(flp->fl_mtime), 1);
1227 if (sizeof(flp->fl_mode) != sizeof(uint_16)) {
1228 uint_16 pmode = (uint_16)flp->fl_mode;
1229 (void) headerAddOrAppendEntry(h, RPMTAG_FILEMODES, RPM_INT16_TYPE,
1232 (void) headerAddOrAppendEntry(h, RPMTAG_FILEMODES, RPM_INT16_TYPE,
1233 &(flp->fl_mode), 1);
1235 if (sizeof(flp->fl_rdev) != sizeof(uint_16)) {
1236 uint_16 prdev = (uint_16)flp->fl_rdev;
1237 (void) headerAddOrAppendEntry(h, RPMTAG_FILERDEVS, RPM_INT16_TYPE,
1240 (void) headerAddOrAppendEntry(h, RPMTAG_FILERDEVS, RPM_INT16_TYPE,
1241 &(flp->fl_rdev), 1);
1243 if (sizeof(flp->fl_dev) != sizeof(uint_32)) {
1244 uint_32 pdevice = (uint_32)flp->fl_dev;
1245 (void) headerAddOrAppendEntry(h, RPMTAG_FILEDEVICES, RPM_INT32_TYPE,
1248 (void) headerAddOrAppendEntry(h, RPMTAG_FILEDEVICES, RPM_INT32_TYPE,
1252 (void) headerAddOrAppendEntry(h, RPMTAG_FILEINODES, RPM_INT32_TYPE,
1255 (void) headerAddOrAppendEntry(h, RPMTAG_FILELANGS, RPM_STRING_ARRAY_TYPE,
1258 /* We used to add these, but they should not be needed */
1259 /* (void) headerAddOrAppendEntry(h, RPMTAG_FILEUIDS,
1260 * RPM_INT32_TYPE, &(flp->fl_uid), 1);
1261 * (void) headerAddOrAppendEntry(h, RPMTAG_FILEGIDS,
1262 * RPM_INT32_TYPE, &(flp->fl_gid), 1);
1266 if (S_ISREG(flp->fl_mode))
1267 (void) mdfile(flp->diskURL, buf);
1269 (void) headerAddOrAppendEntry(h, RPMTAG_FILEMD5S, RPM_STRING_ARRAY_TYPE,
1273 if (S_ISLNK(flp->fl_mode)) {
1274 buf[Readlink(flp->diskURL, buf, BUFSIZ)] = '\0';
1275 if (fl->buildRootURL) {
1276 const char * buildRoot;
1277 (void) urlPath(fl->buildRootURL, &buildRoot);
1279 if (buf[0] == '/' && strcmp(buildRoot, "/") &&
1280 !strncmp(buf, buildRoot, strlen(buildRoot))) {
1281 rpmError(RPMERR_BADSPEC,
1282 _("Symlink points to BuildRoot: %s -> %s\n"),
1284 fl->processingFailed = 1;
1289 (void) headerAddOrAppendEntry(h, RPMTAG_FILELINKTOS, RPM_STRING_ARRAY_TYPE,
1292 if (flp->flags & RPMFILE_GHOST) {
1293 flp->verifyFlags &= ~(RPMVERIFY_MD5 | RPMVERIFY_FILESIZE |
1294 RPMVERIFY_LINKTO | RPMVERIFY_MTIME);
1296 (void) headerAddOrAppendEntry(h, RPMTAG_FILEVERIFYFLAGS, RPM_INT32_TYPE,
1297 &(flp->verifyFlags), 1);
1299 if (!isSrc && isDoc(fl, flp->fileURL))
1300 flp->flags |= RPMFILE_DOC;
1301 /* XXX Should directories have %doc/%config attributes? (#14531) */
1302 if (S_ISDIR(flp->fl_mode))
1303 flp->flags &= ~(RPMFILE_CONFIG|RPMFILE_DOC);
1305 (void) headerAddOrAppendEntry(h, RPMTAG_FILEFLAGS, RPM_INT32_TYPE,
1309 (void) headerAddEntry(h, RPMTAG_SIZE, RPM_INT32_TYPE,
1310 &(fl->totalFileSize), 1);
1312 /* XXX This should be added always so that packages look alike.
1313 * XXX However, there is logic in files.c/depends.c that checks for
1314 * XXX existence (rather than value) that will need to change as well.
1317 (void) headerAddEntry(h, RPMTAG_MULTILIBS, RPM_INT32_TYPE,
1321 (void) rpmlibNeedsFeature(h, "PayloadFilesHavePrefix", "4.0-1");
1323 /* Choose how filenames are represented. */
1327 compressFilelist(h);
1328 /* Binary packages with dirNames cannot be installed by legacy rpm. */
1329 (void) rpmlibNeedsFeature(h, "CompressedFileNames", "3.0.4-1");
1332 { TFI_t fi = xcalloc(sizeof(*fi), 1);
1335 fi->type = TR_ADDED;
1337 fi->dnl = _free(fi->dnl);
1338 fi->bnl = _free(fi->bnl);
1340 fi->dnl = xmalloc(fi->fc * sizeof(*fi->dnl) + dpathlen);
1341 d = (char *)(fi->dnl + fi->fc);
1344 fi->bnl = xmalloc(fi->fc * (sizeof(*fi->bnl) + sizeof(*fi->dil)));
1345 fi->dil = (int *)(fi->bnl + fi->fc);
1347 fi->apath = xmalloc(fi->fc * sizeof(*fi->apath) + apathlen);
1348 a = (char *)(fi->apath + fi->fc);
1351 fi->actions = xcalloc(sizeof(*fi->actions), fi->fc);
1352 fi->fmapflags = xcalloc(sizeof(*fi->fmapflags), fi->fc);
1354 if (fl->buildRootURL)
1355 fi->astriplen = strlen(fl->buildRootURL);
1358 fi->fuids = xcalloc(sizeof(*fi->fuids), fi->fc);
1360 fi->fgids = xcalloc(sizeof(*fi->fgids), fi->fc);
1362 /* Make the cpio list */
1363 for (i = 0, flp = fl->fileList; i < fi->fc; i++, flp++) {
1366 /* Skip (possible) duplicate file entries, use last entry info. */
1367 while (((flp - fl->fileList) < (fl->fileListRecsUsed - 1)) &&
1368 !strcmp(flp->fileURL, flp[1].fileURL))
1371 /* Create disk directory and base name. */
1373 fi->dnl[fi->dil[i]] = d;
1374 d = stpcpy(d, flp->diskURL);
1376 /* Make room for the dirName NUL, find start of baseName. */
1377 for (b = d; b > fi->dnl[fi->dil[i]] && *b != '/'; b--)
1379 b++; /* dirname's end in '/' */
1380 *b++ = '\0'; /* terminate dirname, b points to basename */
1382 d += 2; /* skip both dirname and basename NUL's */
1384 /* Create archive path, normally adding "./" */
1385 /*@-dependenttrans@*/ /* FIX: xstrdup? nah ... */
1387 /*@=dependenttrans@*/
1388 if (_addDotSlash) a = stpcpy(a, "./");
1389 a = stpcpy(a, (flp->fileURL + skipLen));
1390 a++; /* skip apath NUL */
1392 if (flp->flags & RPMFILE_GHOST) {
1393 fi->actions[i] = FA_SKIP;
1396 fi->actions[i] = FA_COPYOUT;
1397 fi->fuids[i] = getUidS(flp->uname);
1398 fi->fgids[i] = getGidS(flp->gname);
1399 if (fi->fuids[i] == (uid_t)-1) fi->fuids[i] = 0;
1400 if (fi->fgids[i] == (gid_t)-1) fi->fgids[i] = 0;
1401 fi->fmapflags[i] = CPIO_MAP_PATH |
1402 CPIO_MAP_TYPE | CPIO_MAP_MODE | CPIO_MAP_UID | CPIO_MAP_GID;
1404 fi->fmapflags[i] |= CPIO_FOLLOW_SYMLINKS;
1405 if (flp->flags & RPMFILE_MULTILIB_MASK)
1406 fi->fmapflags[i] |= CPIO_MULTILIB;
1420 static /*@null@*/ FileListRec freeFileList(/*@only@*/ FileListRec fileList,
1425 fileList[count].diskURL = _free(fileList[count].diskURL);
1426 fileList[count].fileURL = _free(fileList[count].fileURL);
1427 fileList[count].langs = _free(fileList[count].langs);
1429 fileList = _free(fileList);
1434 * @param fl package file tree walk data
1436 static int addFile(FileList fl, const char * diskURL, struct stat * statp)
1437 /*@globals rpmGlobalMacroContext,
1439 /*@modifies *statp, *fl, fl->processingFailed,
1440 fl->fileList, fl->fileListRecsAlloced, fl->fileListRecsUsed,
1441 fl->totalFileSize, fl->fileCount, fl->inFtw, fl->isDir,
1442 rpmGlobalMacroContext, fileSystem @*/
1444 const char *fileURL = diskURL;
1445 struct stat statbuf;
1449 const char *fileUname;
1450 const char *fileGname;
1453 /* Path may have prepended buildRootURL, so locate the original filename. */
1455 * XXX There are 3 types of entry into addFile:
1457 * From diskUrl statp
1458 * =====================================================
1459 * processBinaryFile path NULL
1460 * processBinaryFile glob result path NULL
1464 { const char *fileName;
1465 (void) urlPath(fileURL, &fileName);
1466 if (fl->buildRootURL && strcmp(fl->buildRootURL, "/"))
1467 fileURL += strlen(fl->buildRootURL);
1470 /* XXX make sure '/' can be packaged also */
1472 if (*fileURL == '\0')
1476 /* If we are using a prefix, validate the file */
1477 if (!fl->inFtw && fl->prefix) {
1478 const char *prefixTest;
1479 const char *prefixPtr = fl->prefix;
1481 (void) urlPath(fileURL, &prefixTest);
1482 while (*prefixPtr && *prefixTest && (*prefixTest == *prefixPtr)) {
1486 if (*prefixPtr || (*prefixTest && *prefixTest != '/')) {
1487 rpmError(RPMERR_BADSPEC, _("File doesn't match prefix (%s): %s\n"),
1488 fl->prefix, fileURL);
1489 fl->processingFailed = 1;
1490 return RPMERR_BADSPEC;
1494 if (statp == NULL) {
1496 memset(statp, 0, sizeof(*statp));
1498 time_t now = time(NULL);
1500 /* XXX hack up a stat structure for a %dev(...) directive. */
1501 statp->st_nlink = 1;
1503 ((fl->devmajor & 0xff) << 8) | (fl->devminor & 0xff);
1504 statp->st_dev = statp->st_rdev;
1505 statp->st_mode = (fl->devtype == 'b' ? S_IFBLK : S_IFCHR);
1506 statp->st_mode |= (fl->cur_ar.ar_fmode & 0777);
1507 statp->st_atime = now;
1508 statp->st_mtime = now;
1509 statp->st_ctime = now;
1510 } else if (Lstat(diskURL, statp)) {
1511 rpmError(RPMERR_BADSPEC, _("File not found: %s\n"), diskURL);
1512 fl->processingFailed = 1;
1513 return RPMERR_BADSPEC;
1517 if ((! fl->isDir) && S_ISDIR(statp->st_mode)) {
1518 /* We use our own ftw() call, because ftw() uses stat() */
1519 /* instead of lstat(), which causes it to follow symlinks! */
1520 /* It also has better callback support. */
1522 fl->inFtw = 1; /* Flag to indicate file has buildRootURL prefixed */
1523 fl->isDir = 1; /* Keep it from following myftw() again */
1524 (void) myftw(diskURL, 16, (myftwFunc) addFile, fl);
1530 fileMode = statp->st_mode;
1531 fileUid = statp->st_uid;
1532 fileGid = statp->st_gid;
1534 if (S_ISDIR(fileMode) && fl->cur_ar.ar_dmodestr) {
1536 fileMode |= fl->cur_ar.ar_dmode;
1537 } else if (fl->cur_ar.ar_fmodestr != NULL) {
1539 fileMode |= fl->cur_ar.ar_fmode;
1541 if (fl->cur_ar.ar_user) {
1542 fileUname = getUnameS(fl->cur_ar.ar_user);
1544 fileUname = getUname(fileUid);
1546 if (fl->cur_ar.ar_group) {
1547 fileGname = getGnameS(fl->cur_ar.ar_group);
1549 fileGname = getGname(fileGid);
1552 #if 0 /* XXX this looks dumb to me */
1553 if (! (fileUname && fileGname)) {
1554 rpmError(RPMERR_BADSPEC, _("Bad owner/group: %s\n"), diskName);
1555 fl->processingFailed = 1;
1556 return RPMERR_BADSPEC;
1559 /* Default user/group to builder's user/group */
1560 if (fileUname == NULL)
1561 fileUname = getUname(getuid());
1562 if (fileGname == NULL)
1563 fileGname = getGname(getgid());
1566 rpmMessage(RPMMESS_DEBUG, _("File %4d: %07o %s.%s\t %s\n"), fl->fileCount,
1567 (unsigned)fileMode, fileUname, fileGname, fileURL);
1569 /* Add to the file list */
1570 if (fl->fileListRecsUsed == fl->fileListRecsAlloced) {
1571 fl->fileListRecsAlloced += 128;
1572 fl->fileList = xrealloc(fl->fileList,
1573 fl->fileListRecsAlloced * sizeof(*(fl->fileList)));
1576 { FileListRec flp = &fl->fileList[fl->fileListRecsUsed];
1579 flp->fl_st = *statp; /* structure assignment */
1580 flp->fl_mode = fileMode;
1581 flp->fl_uid = fileUid;
1582 flp->fl_gid = fileGid;
1584 flp->fileURL = xstrdup(fileURL);
1585 flp->diskURL = xstrdup(diskURL);
1586 flp->uname = fileUname;
1587 flp->gname = fileGname;
1589 if (fl->currentLangs && fl->nLangs > 0) {
1593 for (i = 0; i < fl->nLangs; i++)
1594 nl += strlen(fl->currentLangs[i]) + 1;
1596 flp->langs = ncl = xmalloc(nl);
1597 for (i = 0; i < fl->nLangs; i++) {
1599 if (i) *ncl++ = '|';
1600 for (ocl = fl->currentLangs[i]; *ocl != '\0'; ocl++)
1604 } else if (! parseForRegexLang(fileURL, &lang)) {
1605 flp->langs = xstrdup(lang);
1607 flp->langs = xstrdup("");
1610 flp->flags = fl->currentFlags;
1611 flp->specdFlags = fl->currentSpecdFlags;
1612 flp->verifyFlags = fl->currentVerifyFlags;
1615 && !(flp->flags & RPMFILE_MULTILIB_MASK)
1616 && !parseForRegexMultiLib(fileURL))
1617 flp->flags |= multiLib;
1620 /* Hard links need be counted only once. */
1621 if (S_ISREG(flp->fl_mode) && flp->fl_nlink > 1) {
1623 for (i = 0; i < fl->fileListRecsUsed; i++) {
1624 ilp = fl->fileList + i;
1625 if (!S_ISREG(ilp->fl_mode))
1627 if (flp->fl_nlink != ilp->fl_nlink)
1629 if (flp->fl_ino != ilp->fl_ino)
1631 if (flp->fl_dev != ilp->fl_dev)
1636 i = fl->fileListRecsUsed;
1638 if (S_ISREG(flp->fl_mode) && i >= fl->fileListRecsUsed)
1639 fl->totalFileSize += flp->fl_size;
1642 fl->fileListRecsUsed++;
1649 * @param fl package file tree walk data
1651 static int processBinaryFile(/*@unused@*/ Package pkg, FileList fl,
1652 const char * fileURL)
1653 /*@globals rpmGlobalMacroContext,
1655 /*@modifies *fl, fl->processingFailed,
1656 fl->fileList, fl->fileListRecsAlloced, fl->fileListRecsUsed,
1657 fl->totalFileSize, fl->fileCount, fl->inFtw, fl->isDir,
1658 rpmGlobalMacroContext, fileSystem @*/
1661 const char *diskURL = NULL;
1664 doGlob = myGlobPatternP(fileURL);
1666 /* Check that file starts with leading "/" */
1667 { const char * fileName;
1668 (void) urlPath(fileURL, &fileName);
1669 if (*fileName != '/') {
1670 rpmError(RPMERR_BADSPEC, _("File needs leading \"/\": %s\n"),
1677 /* Copy file name or glob pattern removing multiple "/" chars. */
1679 * Note: rpmGetPath should guarantee a "canonical" path. That means
1680 * that the following pathologies should be weeded out:
1683 * /.././../usr/../bin//./sh
1685 diskURL = rpmGenPath(fl->buildRootURL, NULL, fileURL);
1688 const char ** argv = NULL;
1693 rpmError(RPMERR_BADSPEC, _("Glob not permitted: %s\n"),
1700 rc = rpmGlob(diskURL, &argc, &argv);
1701 if (rc == 0 && argc >= 1 && !myGlobPatternP(argv[0])) {
1702 for (i = 0; i < argc; i++) {
1703 rc = addFile(fl, argv[i], NULL);
1704 argv[i] = _free(argv[i]);
1708 rpmError(RPMERR_BADSPEC, _("File not found by glob: %s\n"),
1714 rc = addFile(fl, diskURL, NULL);
1718 diskURL = _free(diskURL);
1720 fl->processingFailed = 1;
1726 static int processPackageFiles(Spec spec, Package pkg,
1727 int installSpecialDoc, int test)
1728 /*@globals rpmGlobalMacroContext,
1729 fileSystem, internalState@*/
1730 /*@modifies spec->macros,
1731 pkg->cpioList, pkg->fileList, pkg->specialDoc, pkg->header,
1732 rpmGlobalMacroContext, fileSystem, internalState @*/
1734 HGE_t hge = (HGE_t)headerGetEntryMinMemory;
1735 struct FileList_s fl;
1736 char *s, **files, **fp;
1737 const char *fileName;
1739 struct AttrRec_s arbuf;
1740 AttrRec specialDocAttrRec = &arbuf;
1741 char *specialDoc = NULL;
1744 multiLib = rpmExpandNumeric("%{_multilibno}");
1746 multiLib = RPMFILE_MULTILIB(multiLib);
1747 #endif /* MULTILIB */
1749 nullAttrRec(specialDocAttrRec);
1750 pkg->cpioList = NULL;
1752 if (pkg->fileFile) {
1757 /* XXX W2DO? urlPath might be useful here. */
1758 if (*pkg->fileFile == '/') {
1759 ffn = rpmGetPath(pkg->fileFile, NULL);
1761 /* XXX FIXME: add %{_buildsubdir} */
1762 ffn = rpmGetPath("%{_builddir}/",
1763 (spec->buildSubdir ? spec->buildSubdir : "") ,
1764 "/", pkg->fileFile, NULL);
1766 fd = Fopen(ffn, "r.fpio");
1768 if (fd == NULL || Ferror(fd)) {
1769 rpmError(RPMERR_BADFILENAME,
1770 _("Could not open %%files file %s: %s\n"),
1771 ffn, Fstrerror(fd));
1772 return RPMERR_BADFILENAME;
1776 /*@+voidabstract@*/ f = fdGetFp(fd); /*@=voidabstract@*/
1778 while (fgets(buf, sizeof(buf), f)) {
1779 handleComments(buf);
1780 if (expandMacros(spec, spec->macros, buf, sizeof(buf))) {
1781 rpmError(RPMERR_BADSPEC, _("line: %s\n"), buf);
1782 return RPMERR_BADSPEC;
1784 appendStringBuf(pkg->fileList, buf);
1789 /* Init the file list structure */
1790 memset(&fl, 0, sizeof(fl));
1792 /* XXX spec->buildRootURL == NULL, then xstrdup("") is returned */
1793 fl.buildRootURL = rpmGenPath(spec->rootURL, spec->buildRootURL, NULL);
1795 if (hge(pkg->header, RPMTAG_DEFAULTPREFIX, NULL, (void **)&fl.prefix, NULL))
1796 fl.prefix = xstrdup(fl.prefix);
1801 fl.totalFileSize = 0;
1802 fl.processingFailed = 0;
1804 fl.passedSpecialDoc = 0;
1805 fl.isSpecialDoc = 0;
1809 fl.currentFlags = 0;
1810 fl.currentVerifyFlags = 0;
1817 nullAttrRec(&fl.cur_ar);
1818 nullAttrRec(&fl.def_ar);
1820 fl.defVerifyFlags = RPMVERIFY_ALL;
1822 fl.currentLangs = NULL;
1824 fl.currentSpecdFlags = 0;
1825 fl.defSpecdFlags = 0;
1828 fl.docDirs[fl.docDirCount++] = xstrdup("/usr/doc");
1829 fl.docDirs[fl.docDirCount++] = xstrdup("/usr/man");
1830 fl.docDirs[fl.docDirCount++] = xstrdup("/usr/info");
1831 fl.docDirs[fl.docDirCount++] = xstrdup("/usr/X11R6/man");
1832 fl.docDirs[fl.docDirCount++] = xstrdup("/usr/share/doc");
1833 fl.docDirs[fl.docDirCount++] = xstrdup("/usr/share/man");
1834 fl.docDirs[fl.docDirCount++] = xstrdup("/usr/share/info");
1835 fl.docDirs[fl.docDirCount++] = rpmGetPath("%{_docdir}", NULL);
1836 fl.docDirs[fl.docDirCount++] = rpmGetPath("%{_mandir}", NULL);
1837 fl.docDirs[fl.docDirCount++] = rpmGetPath("%{_infodir}", NULL);
1840 fl.fileListRecsAlloced = 0;
1841 fl.fileListRecsUsed = 0;
1843 s = getStringBuf(pkg->fileList);
1844 files = splitString(s, strlen(s), '\n');
1846 for (fp = files; *fp != NULL; fp++) {
1852 /*@-nullpass@*/ /* LCL: buf is NULL ?!? */
1856 /* Reset for a new line in %files */
1859 fl.currentFlags = 0;
1860 /* turn explicit flags into %def'd ones (gosh this is hacky...) */
1861 fl.currentSpecdFlags = ((unsigned)fl.defSpecdFlags) >> 8;
1862 fl.currentVerifyFlags = fl.defVerifyFlags;
1863 fl.isSpecialDoc = 0;
1870 /* XXX should reset to %deflang value */
1871 if (fl.currentLangs) {
1873 for (i = 0; i < fl.nLangs; i++)
1874 /*@-unqualifiedtrans@*/
1875 fl.currentLangs[i] = _free(fl.currentLangs[i]);
1876 /*@=unqualifiedtrans@*/
1877 fl.currentLangs = _free(fl.currentLangs);
1881 dupAttrRec(&fl.def_ar, &fl.cur_ar);
1883 /*@-nullpass@*/ /* LCL: buf is NULL ?!? */
1884 if (parseForVerify(buf, &fl))
1886 if (parseForAttr(buf, &fl))
1888 if (parseForDev(buf, &fl))
1890 if (parseForConfig(buf, &fl))
1892 if (parseForLang(buf, &fl))
1894 /*@-nullstate@*/ /* FIX: pkg->fileFile might be NULL */
1895 if (parseForSimple(spec, pkg, buf, &fl, &fileName))
1899 if (fileName == NULL)
1903 if (fl.isSpecialDoc) {
1904 /* Save this stuff for last */
1905 specialDoc = _free(specialDoc);
1906 specialDoc = xstrdup(fileName);
1907 dupAttrRec(&fl.cur_ar, specialDocAttrRec);
1909 /*@-nullstate@*/ /* FIX: pkg->fileFile might be NULL */
1910 (void) processBinaryFile(pkg, &fl, fileName);
1916 /* Now process special doc, if there is one */
1918 if (installSpecialDoc) {
1919 (void) doScript(spec, RPMBUILD_STRINGBUF, "%doc", pkg->specialDoc, test);
1922 /* Reset for %doc */
1925 fl.currentFlags = 0;
1926 fl.currentVerifyFlags = 0;
1933 /* XXX should reset to %deflang value */
1934 if (fl.currentLangs) {
1936 for (i = 0; i < fl.nLangs; i++)
1937 /*@-unqualifiedtrans@*/
1938 fl.currentLangs[i] = _free(fl.currentLangs[i]);
1939 /*@=unqualifiedtrans@*/
1940 fl.currentLangs = _free(fl.currentLangs);
1944 dupAttrRec(specialDocAttrRec, &fl.cur_ar);
1945 freeAttrRec(specialDocAttrRec);
1947 /*@-nullstate@*/ /* FIX: pkg->fileFile might be NULL */
1948 (void) processBinaryFile(pkg, &fl, specialDoc);
1951 specialDoc = _free(specialDoc);
1954 freeSplitString(files);
1956 if (fl.processingFailed)
1959 /* Verify that file attributes scope over hardlinks correctly. */
1960 checkHardLinks(&fl);
1962 genCpioListAndHeader(&fl, (TFI_t *)&pkg->cpioList, pkg->header, 0);
1964 if (spec->timeCheck)
1965 timeCheck(spec->timeCheck, pkg->header);
1968 fl.buildRootURL = _free(fl.buildRootURL);
1969 fl.prefix = _free(fl.prefix);
1971 freeAttrRec(&fl.cur_ar);
1972 freeAttrRec(&fl.def_ar);
1974 if (fl.currentLangs) {
1976 for (i = 0; i < fl.nLangs; i++)
1977 /*@-unqualifiedtrans@*/
1978 fl.currentLangs[i] = _free(fl.currentLangs[i]);
1979 /*@=unqualifiedtrans@*/
1980 fl.currentLangs = _free(fl.currentLangs);
1983 fl.fileList = freeFileList(fl.fileList, fl.fileListRecsUsed);
1984 while (fl.docDirCount--)
1985 fl.docDirs[fl.docDirCount] = _free(fl.docDirs[fl.docDirCount]);
1986 return fl.processingFailed;
1989 void initSourceHeader(Spec spec)
1992 int_32 tag, type, count;
1995 spec->sourceHeader = headerNew();
1996 /* Only specific tags are added to the source package header */
1998 for (hi = headerInitIterator(spec->packages->header);
1999 headerNextIterator(hi, &tag, &type, &ptr, &count);
2000 ptr = headerFreeData(ptr, type))
2004 case RPMTAG_VERSION:
2005 case RPMTAG_RELEASE:
2007 case RPMTAG_SUMMARY:
2008 case RPMTAG_DESCRIPTION:
2009 case RPMTAG_PACKAGER:
2010 case RPMTAG_DISTRIBUTION:
2011 case RPMTAG_DISTURL:
2013 case RPMTAG_LICENSE:
2017 case RPMTAG_CHANGELOGTIME:
2018 case RPMTAG_CHANGELOGNAME:
2019 case RPMTAG_CHANGELOGTEXT:
2021 case HEADER_I18NTABLE:
2023 (void)headerAddEntry(spec->sourceHeader, tag, type, ptr, count);
2024 /*@switchbreak@*/ break;
2027 /*@switchbreak@*/ break;
2030 hi = headerFreeIterator(hi);
2033 /* Add the build restrictions */
2035 for (hi = headerInitIterator(spec->buildRestrictions);
2036 headerNextIterator(hi, &tag, &type, &ptr, &count);
2037 ptr = headerFreeData(ptr, type))
2040 (void) headerAddEntry(spec->sourceHeader, tag, type, ptr, count);
2042 hi = headerFreeIterator(hi);
2045 if (spec->BANames && spec->BACount > 0) {
2046 (void) headerAddEntry(spec->sourceHeader, RPMTAG_BUILDARCHS,
2047 RPM_STRING_ARRAY_TYPE,
2048 spec->BANames, spec->BACount);
2052 int processSourceFiles(Spec spec)
2054 struct Source *srcPtr;
2055 StringBuf sourceFiles;
2057 struct FileList_s fl;
2058 char *s, **files, **fp;
2061 sourceFiles = newStringBuf();
2064 * XXX This is where the source header for noarch packages needs
2065 * XXX to be initialized.
2067 if (spec->sourceHeader == NULL)
2068 initSourceHeader(spec);
2070 /* Construct the file list and source entries */
2071 appendLineStringBuf(sourceFiles, spec->specFile);
2072 if (spec->sourceHeader != NULL)
2073 for (srcPtr = spec->sources; srcPtr != NULL; srcPtr = srcPtr->next) {
2074 if (srcPtr->flags & RPMBUILD_ISSOURCE) {
2075 (void) headerAddOrAppendEntry(spec->sourceHeader, RPMTAG_SOURCE,
2076 RPM_STRING_ARRAY_TYPE, &srcPtr->source, 1);
2077 if (srcPtr->flags & RPMBUILD_ISNO) {
2078 (void) headerAddOrAppendEntry(spec->sourceHeader, RPMTAG_NOSOURCE,
2079 RPM_INT32_TYPE, &srcPtr->num, 1);
2082 if (srcPtr->flags & RPMBUILD_ISPATCH) {
2083 (void) headerAddOrAppendEntry(spec->sourceHeader, RPMTAG_PATCH,
2084 RPM_STRING_ARRAY_TYPE, &srcPtr->source, 1);
2085 if (srcPtr->flags & RPMBUILD_ISNO) {
2086 (void) headerAddOrAppendEntry(spec->sourceHeader, RPMTAG_NOPATCH,
2087 RPM_INT32_TYPE, &srcPtr->num, 1);
2092 sfn = rpmGetPath( ((srcPtr->flags & RPMBUILD_ISNO) ? "!" : ""),
2093 "%{_sourcedir}/", srcPtr->source, NULL);
2094 appendLineStringBuf(sourceFiles, sfn);
2099 for (pkg = spec->packages; pkg != NULL; pkg = pkg->next) {
2100 for (srcPtr = pkg->icon; srcPtr != NULL; srcPtr = srcPtr->next) {
2102 sfn = rpmGetPath( ((srcPtr->flags & RPMBUILD_ISNO) ? "!" : ""),
2103 "%{_sourcedir}/", srcPtr->source, NULL);
2104 appendLineStringBuf(sourceFiles, sfn);
2109 spec->sourceCpioList = NULL;
2111 fl.fileList = xcalloc((spec->numSources + 1), sizeof(*fl.fileList));
2112 fl.processingFailed = 0;
2113 fl.fileListRecsUsed = 0;
2114 fl.totalFileSize = 0;
2116 fl.buildRootURL = NULL;
2118 s = getStringBuf(sourceFiles);
2119 files = splitString(s, strlen(s), '\n');
2121 /* The first source file is the spec file */
2123 for (fp = files; *fp != NULL; fp++) {
2124 const char * diskURL, *diskPath;
2132 flp = &fl.fileList[x];
2134 flp->flags = isSpec ? RPMFILE_SPECFILE : 0;
2135 /* files with leading ! are no source files */
2136 if (*diskURL == '!') {
2137 flp->flags |= RPMFILE_GHOST;
2141 (void) urlPath(diskURL, &diskPath);
2143 flp->diskURL = xstrdup(diskURL);
2144 diskPath = strrchr(diskPath, '/');
2150 flp->fileURL = xstrdup(diskPath);
2151 flp->verifyFlags = RPMVERIFY_ALL;
2153 if (Stat(diskURL, &flp->fl_st)) {
2154 rpmError(RPMERR_BADSPEC, _("Bad file: %s: %s\n"),
2155 diskURL, strerror(errno));
2156 fl.processingFailed = 1;
2159 flp->uname = getUname(flp->fl_uid);
2160 flp->gname = getGname(flp->fl_gid);
2161 flp->langs = xstrdup("");
2163 fl.totalFileSize += flp->fl_size;
2165 if (! (flp->uname && flp->gname)) {
2166 rpmError(RPMERR_BADSPEC, _("Bad owner/group: %s\n"), diskURL);
2167 fl.processingFailed = 1;
2173 fl.fileListRecsUsed = x;
2174 freeSplitString(files);
2176 if (! fl.processingFailed) {
2177 if (spec->sourceHeader != NULL)
2178 genCpioListAndHeader(&fl, (TFI_t *)&spec->sourceCpioList,
2179 spec->sourceHeader, 1);
2182 sourceFiles = freeStringBuf(sourceFiles);
2183 fl.fileList = freeFileList(fl.fileList, fl.fileListRecsUsed);
2184 return fl.processingFailed;
2189 static StringBuf getOutputFrom(char * dir, char * argv[],
2190 const char * writePtr, int writeBytesLeft,
2192 /*@globals fileSystem, internalState@*/
2193 /*@modifies fileSystem, internalState@*/
2203 /*@-type@*/ /* FIX: cast? */
2204 oldhandler = signal(SIGPIPE, SIG_IGN);
2207 toProg[0] = toProg[1] = 0;
2208 (void) pipe(toProg);
2209 fromProg[0] = fromProg[1] = 0;
2210 (void) pipe(fromProg);
2212 if (!(progPID = fork())) {
2213 (void) close(toProg[1]);
2214 (void) close(fromProg[0]);
2216 (void) dup2(toProg[0], STDIN_FILENO); /* Make stdin the in pipe */
2217 (void) dup2(fromProg[1], STDOUT_FILENO); /* Make stdout the out pipe */
2219 (void) close(toProg[0]);
2220 (void) close(fromProg[1]);
2226 (void) execvp(argv[0], argv);
2227 /* XXX this error message is probably not seen. */
2228 rpmError(RPMERR_EXEC, _("Couldn't exec %s: %s\n"),
2229 argv[0], strerror(errno));
2233 rpmError(RPMERR_FORK, _("Couldn't fork %s: %s\n"),
2234 argv[0], strerror(errno));
2238 (void) close(toProg[0]);
2239 (void) close(fromProg[1]);
2241 /* Do not block reading or writing from/to prog. */
2242 (void) fcntl(fromProg[0], F_SETFL, O_NONBLOCK);
2243 (void) fcntl(toProg[1], F_SETFL, O_NONBLOCK);
2245 readBuff = newStringBuf();
2248 fd_set ibits, obits;
2255 /* XXX the select is mainly a timer since all I/O is non-blocking */
2258 if (fromProg[0] >= 0) {
2259 FD_SET(fromProg[0], &ibits);
2261 if (toProg[1] >= 0) {
2262 FD_SET(toProg[1], &obits);
2266 nfd = ((fromProg[0] > toProg[1]) ? fromProg[0] : toProg[1]);
2267 if ((rc = select(nfd, &ibits, &obits, NULL, &tv)) < 0) {
2273 /* Write any data to program */
2274 if (toProg[1] >= 0 && FD_ISSET(toProg[1], &obits)) {
2275 if (writeBytesLeft) {
2276 if ((nbw = write(toProg[1], writePtr,
2277 (1024<writeBytesLeft) ? 1024 : writeBytesLeft)) < 0) {
2278 if (errno != EAGAIN) {
2279 perror("getOutputFrom()");
2284 writeBytesLeft -= nbw;
2286 } else if (toProg[1] >= 0) { /* close write fd */
2287 (void) close(toProg[1]);
2292 /* Read any data from prog */
2293 { char buf[BUFSIZ+1];
2294 while ((nbr = read(fromProg[0], buf, sizeof(buf)-1)) > 0) {
2296 appendStringBuf(readBuff, buf);
2300 /* terminate on (non-blocking) EOF or error */
2301 done = (nbr == 0 || (nbr < 0 && errno != EAGAIN));
2307 (void) close(toProg[1]);
2308 if (fromProg[0] >= 0)
2309 (void) close(fromProg[0]);
2310 /*@-type@*/ /* FIX: cast? */
2311 (void) signal(SIGPIPE, oldhandler);
2314 /* Collect status from prog */
2315 (void)waitpid(progPID, &status, 0);
2316 if (failNonZero && (!WIFEXITED(status) || WEXITSTATUS(status))) {
2317 rpmError(RPMERR_EXEC, _("%s failed\n"), argv[0]);
2320 if (writeBytesLeft) {
2321 rpmError(RPMERR_EXEC, _("failed to write all data to %s\n"), argv[0]);
2330 /*@observer@*/ /*@null@*/ const char * msg;
2331 /*@observer@*/ const char * argv[4];
2341 /*@-exportlocal -exportheadervar@*/
2343 DepMsg_t depMsgs[] = {
2344 { "Provides", { "%{__find_provides}", NULL, NULL, NULL },
2345 RPMTAG_PROVIDENAME, RPMTAG_PROVIDEVERSION, RPMTAG_PROVIDEFLAGS,
2347 { "PreReq", { NULL, NULL, NULL, NULL },
2348 RPMTAG_REQUIRENAME, RPMTAG_REQUIREVERSION, RPMTAG_REQUIREFLAGS,
2349 RPMSENSE_PREREQ, 0 },
2350 { "Requires(interp)", { NULL, "interp", NULL, NULL },
2351 -1, -1, RPMTAG_REQUIREFLAGS,
2352 _notpre(RPMSENSE_INTERP), 0 },
2353 { "Requires(rpmlib)", { NULL, "rpmlib", NULL, NULL },
2354 -1, -1, RPMTAG_REQUIREFLAGS,
2355 _notpre(RPMSENSE_RPMLIB), 0 },
2356 { "Requires(verify)", { NULL, "verify", NULL, NULL },
2357 -1, -1, RPMTAG_REQUIREFLAGS,
2358 RPMSENSE_SCRIPT_VERIFY, 0 },
2359 { "Requires(pre)", { NULL, "pre", NULL, NULL },
2360 -1, -1, RPMTAG_REQUIREFLAGS,
2361 _notpre(RPMSENSE_SCRIPT_PRE), 0 },
2362 { "Requires(post)", { NULL, "post", NULL, NULL },
2363 -1, -1, RPMTAG_REQUIREFLAGS,
2364 _notpre(RPMSENSE_SCRIPT_POST), 0 },
2365 { "Requires(preun)", { NULL, "preun", NULL, NULL },
2366 -1, -1, RPMTAG_REQUIREFLAGS,
2367 _notpre(RPMSENSE_SCRIPT_PREUN), 0 },
2368 { "Requires(postun)", { NULL, "postun", NULL, NULL },
2369 -1, -1, RPMTAG_REQUIREFLAGS,
2370 _notpre(RPMSENSE_SCRIPT_POSTUN), 0 },
2371 { "Requires", { "%{__find_requires}", NULL, NULL, NULL },
2372 -1, -1, RPMTAG_REQUIREFLAGS, /* XXX inherit name/version arrays */
2373 RPMSENSE_PREREQ, RPMSENSE_PREREQ },
2374 { "Conflicts", { "%{__find_conflicts}", NULL, NULL, NULL },
2375 RPMTAG_CONFLICTNAME, RPMTAG_CONFLICTVERSION, RPMTAG_CONFLICTFLAGS,
2377 { "Obsoletes", { "%{__find_obsoletes}", NULL, NULL, NULL },
2378 RPMTAG_OBSOLETENAME, RPMTAG_OBSOLETEVERSION, RPMTAG_OBSOLETEFLAGS,
2380 { NULL, { NULL, NULL, NULL, NULL }, 0, 0, 0, 0, 0 }
2382 /*@=exportlocal =exportheadervar@*/
2386 static int generateDepends(Spec spec, Package pkg, TFI_t cpioList, int multiLib)
2387 /*@globals rpmGlobalMacroContext,
2388 fileSystem, internalState @*/
2389 /*@modifies cpioList, rpmGlobalMacroContext,
2390 fileSystem, internalState @*/
2392 TFI_t fi = cpioList;
2398 int failnonzero = 0;
2402 if (!(fi && fi->fc > 0))
2405 if (! (pkg->autoReq || pkg->autoProv))
2408 writeBuf = newStringBuf();
2409 for (i = 0, writeBytes = 0; i < fi->fc; i++) {
2411 if (fi->fmapflags && multiLib == 2) {
2412 if (!(fi->fmapflags[i] & CPIO_MULTILIB))
2414 fi->fmapflags[i] &= ~CPIO_MULTILIB;
2417 appendStringBuf(writeBuf, fi->dnl[fi->dil[i]]);
2418 writeBytes += strlen(fi->dnl[fi->dil[i]]);
2419 appendLineStringBuf(writeBuf, fi->bnl[i]);
2420 writeBytes += strlen(fi->bnl[i]) + 1;
2423 for (dm = depMsgs; dm->msg != NULL; dm++) {
2426 tag = (dm->ftag > 0) ? dm->ftag : dm->ntag;
2430 case RPMTAG_PROVIDEFLAGS:
2434 tagflags = RPMSENSE_FIND_PROVIDES;
2435 /*@switchbreak@*/ break;
2436 case RPMTAG_REQUIREFLAGS:
2440 tagflags = RPMSENSE_FIND_REQUIRES;
2441 /*@switchbreak@*/ break;
2444 /*@notreached@*/ /*@switchbreak@*/ break;
2447 /* Get the script name to run */
2448 /*@-nullderef@*/ /* FIX: double indirection. @*/
2449 myargv[0] = (dm->argv[0] ? rpmExpand(dm->argv[0], NULL) : NULL);
2452 if (!(myargv[0] && *myargv[0] != '%')) {
2453 myargv[0] = _free(myargv[0]);
2457 rpmMessage(RPMMESS_NORMAL, _("Finding %s: (using %s)...\n"),
2458 dm->msg, myargv[0]);
2461 if (*myargv[0] != '/') { /* XXX FIXME: stat script here */
2462 myargv[0] = _free(myargv[0]);
2467 /* Expand rest of script arguments (if any) */
2468 for (i = 1; i < 4; i++) {
2469 /*@-nullderef@*/ /* FIX: double indirection. @*/
2470 myargv[i] = dm->argv[i] ? rpmExpand(dm->argv[i], NULL) : NULL;
2474 readBuf = getOutputFrom(NULL, myargv,
2475 getStringBuf(writeBuf), writeBytes, failnonzero);
2477 /* Free expanded args */
2478 for (i = 0; i < 4; i++)
2479 myargv[i] = _free(myargv[i]);
2481 if (readBuf == NULL) {
2483 rpmError(rc, _("Failed to find %s:\n"), dm->msg);
2487 /* Parse dependencies into header */
2488 tagflags &= ~RPMSENSE_MULTILIB;
2490 tagflags |= RPMSENSE_MULTILIB;
2492 tagflags &= ~RPMSENSE_MULTILIB;
2493 rc = parseRCPOT(spec, pkg, getStringBuf(readBuf), tag, 0, tagflags);
2494 readBuf = freeStringBuf(readBuf);
2497 rpmError(rc, _("Failed to find %s:\n"), dm->msg);
2502 writeBuf = freeStringBuf(writeBuf);
2508 static void printDepMsg(DepMsg_t * dm, int count, const char ** names,
2509 const char ** versions, int *flags)
2512 int hasVersions = (versions != NULL);
2513 int hasFlags = (flags != NULL);
2517 for (i = 0; i < count; i++, names++, versions++, flags++) {
2518 if (hasFlags && !((*flags & dm->mask) ^ dm->xor))
2521 rpmMessage(RPMMESS_NORMAL, "%s:", (dm->msg ? dm->msg : ""));
2524 rpmMessage(RPMMESS_NORMAL, " %s", *names);
2526 if (hasFlags && isDependsMULTILIB(*flags))
2527 rpmMessage(RPMMESS_NORMAL, " (multilib)");
2529 if (hasVersions && !(*versions != NULL && **versions != '\0'))
2531 if (!(hasFlags && (*flags && RPMSENSE_SENSEMASK)))
2534 rpmMessage(RPMMESS_NORMAL, " ");
2535 if (*flags & RPMSENSE_LESS)
2536 rpmMessage(RPMMESS_NORMAL, "<");
2537 if (*flags & RPMSENSE_GREATER)
2538 rpmMessage(RPMMESS_NORMAL, ">");
2539 if (*flags & RPMSENSE_EQUAL)
2540 rpmMessage(RPMMESS_NORMAL, "=");
2542 rpmMessage(RPMMESS_NORMAL, " %s", *versions);
2545 rpmMessage(RPMMESS_NORMAL, "\n");
2550 static void printDeps(Header h)
2553 HGE_t hge = (HGE_t)headerGetEntryMinMemory;
2554 HFD_t hfd = headerFreeData;
2555 const char ** names = NULL;
2556 rpmTagType dnt = -1;
2557 const char ** versions = NULL;
2558 rpmTagType dvt = -1;
2563 for (dm = depMsgs; dm->msg != NULL; dm++) {
2566 names = hfd(names, dnt);
2567 /*@switchbreak@*/ break;
2569 /*@switchbreak@*/ break;
2571 names = hfd(names, dnt);
2572 if (!hge(h, dm->ntag, &dnt, (void **) &names, &count))
2574 /*@switchbreak@*/ break;
2578 versions = hfd(versions, dvt);
2579 /*@switchbreak@*/ break;
2581 /*@switchbreak@*/ break;
2583 versions = hfd(versions, dvt);
2584 xx = hge(h, dm->vtag, &dvt, (void **) &versions, NULL);
2585 /*@switchbreak@*/ break;
2590 /*@switchbreak@*/ break;
2592 /*@switchbreak@*/ break;
2594 xx = hge(h, dm->ftag, NULL, (void **) &flags, NULL);
2595 /*@switchbreak@*/ break;
2598 printDepMsg(dm, count, names, versions, flags);
2601 names = hfd(names, dnt);
2602 versions = hfd(versions, dvt);
2605 int processBinaryFiles(Spec spec, int installSpecialDoc, int test)
2610 for (pkg = spec->packages; pkg != NULL; pkg = pkg->next) {
2611 const char *n, *v, *r;
2614 if (pkg->fileList == NULL)
2617 (void) headerNVR(pkg->header, &n, &v, &r);
2618 rpmMessage(RPMMESS_NORMAL, _("Processing files: %s-%s-%s\n"), n, v, r);
2620 if ((rc = processPackageFiles(spec, pkg, installSpecialDoc, test)))
2623 /* XXX This should be added always so that packages look alike.
2624 * XXX However, there is logic in files.c/depends.c that checks for
2625 * XXX existence (rather than value) that will need to change as well.
2627 if (headerIsEntry(pkg->header, RPMTAG_MULTILIBS)) {
2628 (void) generateDepends(spec, pkg, pkg->cpioList, 1);
2629 (void) generateDepends(spec, pkg, pkg->cpioList, 2);
2631 (void) generateDepends(spec, pkg, pkg->cpioList, 0);
2633 printDeps(pkg->header);