Main Page   Modules   Data Structures   File List   Data Fields   Globals   Related Pages  

build/files.c

Go to the documentation of this file.
00001 
00007 #include "system.h"
00008 
00009 #define MYALLPERMS      07777
00010 
00011 #include <regex.h>
00012 #include <signal.h>     /* getOutputFrom() */
00013 
00014 #include <rpmio_internal.h>
00015 #include <rpmbuild.h>
00016 #include <rpmmacro.h>
00017 
00018 #include "buildio.h"
00019 
00020 #include "myftw.h"
00021 #include "md5.h"
00022 #include "debug.h"
00023 
00024 /*@access Header @*/
00025 /*@access TFI_t @*/
00026 /*@access FD_t @*/
00027 /*@access StringBuf @*/         /* compared with NULL */
00028 
00029 #define SKIPWHITE(_x)   {while(*(_x) && (xisspace(*_x) || *(_x) == ',')) (_x)++;}
00030 #define SKIPNONWHITE(_x){while(*(_x) &&!(xisspace(*_x) || *(_x) == ',')) (_x)++;}
00031 
00032 #define MAXDOCDIR 1024
00033 
00034 /*@-redecl@*/
00035 extern int _noDirTokens;
00036 /*@=redecl@*/
00037 
00040 typedef enum specdFlags_e {
00041     SPECD_DEFFILEMODE   = (1 << 0),
00042     SPECD_DEFDIRMODE    = (1 << 1),
00043     SPECD_DEFUID        = (1 << 2),
00044     SPECD_DEFGID        = (1 << 3),
00045     SPECD_DEFVERIFY     = (1 << 4),
00046 
00047     SPECD_FILEMODE      = (1 << 8),
00048     SPECD_DIRMODE       = (1 << 9),
00049     SPECD_UID           = (1 << 10),
00050     SPECD_GID           = (1 << 11),
00051     SPECD_VERIFY        = (1 << 12)
00052 } specdFlags;
00053 
00056 typedef struct FileListRec_s {
00057     struct stat fl_st;
00058 #define fl_dev  fl_st.st_dev
00059 #define fl_ino  fl_st.st_ino
00060 #define fl_mode fl_st.st_mode
00061 #define fl_nlink fl_st.st_nlink
00062 #define fl_uid  fl_st.st_uid
00063 #define fl_gid  fl_st.st_gid
00064 #define fl_rdev fl_st.st_rdev
00065 #define fl_size fl_st.st_size
00066 #define fl_mtime fl_st.st_mtime
00067 
00068 /*@only@*/ const char * diskURL;        /* get file from here       */
00069 /*@only@*/ const char * fileURL;        /* filename in cpio archive */
00070 /*@observer@*/ const char * uname;
00071 /*@observer@*/ const char * gname;
00072     int         flags;
00073     specdFlags  specdFlags;     /* which attributes have been explicitly specified. */
00074     int         verifyFlags;
00075 /*@only@*/ const char *langs;   /* XXX locales separated with | */
00076 } * FileListRec;
00077 
00080 typedef struct AttrRec_s {
00081     const char * ar_fmodestr;
00082     const char * ar_dmodestr;
00083     const char * ar_user;
00084     const char * ar_group;
00085     mode_t      ar_fmode;
00086     mode_t      ar_dmode;
00087 } * AttrRec;
00088 
00091 static int multiLib = 0;        /* MULTILIB */
00092 
00096 typedef struct FileList_s {
00097 /*@only@*/ const char * buildRootURL;
00098 /*@only@*/ const char * prefix;
00099 
00100     int fileCount;
00101     int totalFileSize;
00102     int processingFailed;
00103 
00104     int passedSpecialDoc;
00105     int isSpecialDoc;
00106 
00107     int noGlob;
00108     unsigned devtype;
00109     unsigned devmajor;
00110     int devminor;
00111     
00112     int isDir;
00113     int inFtw;
00114     int currentFlags;
00115     specdFlags currentSpecdFlags;
00116     int currentVerifyFlags;
00117     struct AttrRec_s cur_ar;
00118     struct AttrRec_s def_ar;
00119     specdFlags defSpecdFlags;
00120     int defVerifyFlags;
00121     int nLangs;
00122 /*@only@*/ /*@null@*/ const char ** currentLangs;
00123 
00124     /* Hard coded limit of MAXDOCDIR docdirs.         */
00125     /* If you break it you are doing something wrong. */
00126     const char * docDirs[MAXDOCDIR];
00127     int docDirCount;
00128     
00129 /*@only@*/ FileListRec fileList;
00130     int fileListRecsAlloced;
00131     int fileListRecsUsed;
00132 } * FileList;
00133 
00136 static void nullAttrRec(/*@out@*/ AttrRec ar)   /*@modifies ar @*/
00137 {
00138     ar->ar_fmodestr = NULL;
00139     ar->ar_dmodestr = NULL;
00140     ar->ar_user = NULL;
00141     ar->ar_group = NULL;
00142     ar->ar_fmode = 0;
00143     ar->ar_dmode = 0;
00144 }
00145 
00148 static void freeAttrRec(AttrRec ar)     /*@modifies ar @*/
00149 {
00150     ar->ar_fmodestr = _free(ar->ar_fmodestr);
00151     ar->ar_dmodestr = _free(ar->ar_dmodestr);
00152     ar->ar_user = _free(ar->ar_user);
00153     ar->ar_group = _free(ar->ar_group);
00154     /* XXX doesn't free ar (yet) */
00155     /*@-nullstate@*/
00156     return;
00157     /*@=nullstate@*/
00158 }
00159 
00162 static void dupAttrRec(const AttrRec oar, /*@in@*/ /*@out@*/ AttrRec nar)
00163         /*@modifies nar @*/
00164 {
00165     if (oar == nar)
00166         return;
00167     freeAttrRec(nar);
00168     nar->ar_fmodestr = (oar->ar_fmodestr ? xstrdup(oar->ar_fmodestr) : NULL);
00169     nar->ar_dmodestr = (oar->ar_dmodestr ? xstrdup(oar->ar_dmodestr) : NULL);
00170     nar->ar_user = (oar->ar_user ? xstrdup(oar->ar_user) : NULL);
00171     nar->ar_group = (oar->ar_group ? xstrdup(oar->ar_group) : NULL);
00172     nar->ar_fmode = oar->ar_fmode;
00173     nar->ar_dmode = oar->ar_dmode;
00174 }
00175 
00176 #if 0
00177 
00179 static void dumpAttrRec(const char * msg, AttrRec ar)
00180         /*@modifies fileSystem @*/
00181 {
00182     if (msg)
00183         fprintf(stderr, "%s:\t", msg);
00184     fprintf(stderr, "(%s, %s, %s, %s)\n",
00185         ar->ar_fmodestr,
00186         ar->ar_user,
00187         ar->ar_group,
00188         ar->ar_dmodestr);
00189 }
00190 #endif
00191 
00192 /* strtokWithQuotes() modified from glibc strtok() */
00193 /* Copyright (C) 1991, 1996 Free Software Foundation, Inc.
00194    This file is part of the GNU C Library.
00195 
00196    The GNU C Library is free software; you can redistribute it and/or
00197    modify it under the terms of the GNU Library General Public License as
00198    published by the Free Software Foundation; either version 2 of the
00199    License, or (at your option) any later version.
00200 
00201    The GNU C Library is distributed in the hope that it will be useful,
00202    but WITHOUT ANY WARRANTY; without even the implied warranty of
00203    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00204    Library General Public License for more details.
00205 
00206    You should have received a copy of the GNU Library General Public
00207    License along with the GNU C Library; see the file COPYING.LIB.  If
00208    not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
00209    Boston, MA 02111-1307, USA.  */
00210 
00213 static char *strtokWithQuotes(char *s, char *delim)
00214 {
00215     static char *olds = NULL;
00216     char *token;
00217 
00218     if (s == NULL) {
00219         s = olds;
00220     }
00221 
00222     /* Skip leading delimiters */
00223     s += strspn(s, delim);
00224     if (*s == '\0') {
00225         return NULL;
00226     }
00227 
00228     /* Find the end of the token.  */
00229     token = s;
00230     if (*token == '"') {
00231         token++;
00232         /* Find next " char */
00233         s = strchr(token, '"');
00234     } else {
00235         s = strpbrk(token, delim);
00236     }
00237 
00238     /* Terminate it */
00239     if (s == NULL) {
00240         /* This token finishes the string */
00241         olds = strchr(token, '\0');
00242     } else {
00243         /* Terminate the token and make olds point past it */
00244         *s = '\0';
00245         olds = s+1;
00246     }
00247 
00248     return token;
00249 }
00250 
00253 static void timeCheck(int tc, Header h) /*@modifies internalState @*/
00254 {
00255     HGE_t hge = (HGE_t)headerGetEntryMinMemory;
00256     HFD_t hfd = headerFreeData;
00257     int * mtime;
00258     const char ** files;
00259     rpmTagType fnt;
00260     int count, x;
00261     time_t currentTime = time(NULL);
00262 
00263     (void) hge(h, RPMTAG_OLDFILENAMES, &fnt, (void **) &files, &count);
00264     (void) hge(h, RPMTAG_FILEMTIMES, NULL, (void **) &mtime, NULL);
00265     
00266     for (x = 0; x < count; x++) {
00267         if ((currentTime - mtime[x]) > tc)
00268             rpmMessage(RPMMESS_WARNING, _("TIMECHECK failure: %s\n"), files[x]);
00269     }
00270     files = hfd(files, fnt);
00271 }
00272 
00275 typedef struct VFA {
00276 /*@observer@*/ /*@null@*/ const char * attribute;
00277     int flag;
00278 } VFA_t;
00279 
00282 /*@-exportlocal -exportheadervar@*/
00283 VFA_t verifyAttrs[] = {
00284     { "md5",    RPMVERIFY_MD5 },
00285     { "size",   RPMVERIFY_FILESIZE },
00286     { "link",   RPMVERIFY_LINKTO },
00287     { "user",   RPMVERIFY_USER },
00288     { "group",  RPMVERIFY_GROUP },
00289     { "mtime",  RPMVERIFY_MTIME },
00290     { "mode",   RPMVERIFY_MODE },
00291     { "rdev",   RPMVERIFY_RDEV },
00292     { NULL, 0 }
00293 };
00294 /*@=exportlocal =exportheadervar@*/
00295 
00299 static int parseForVerify(char * buf, FileList fl)
00300         /*@modifies buf, fl->processingFailed,
00301                 fl->currentVerifyFlags, fl->defVerifyFlags,
00302                 fl->currentSpecdFlags, fl->defSpecdFlags @*/
00303 {
00304     char *p, *pe, *q;
00305     const char *name;
00306     int *resultVerify;
00307     int negated;
00308     int verifyFlags;
00309     specdFlags * specdFlags;
00310 
00311     if ((p = strstr(buf, (name = "%verify"))) != NULL) {
00312         resultVerify = &(fl->currentVerifyFlags);
00313         specdFlags = &fl->currentSpecdFlags;
00314     } else if ((p = strstr(buf, (name = "%defverify"))) != NULL) {
00315         resultVerify = &(fl->defVerifyFlags);
00316         specdFlags = &fl->defSpecdFlags;
00317     } else
00318         return 0;
00319 
00320     for (pe = p; (pe-p) < strlen(name); pe++)
00321         *pe = ' ';
00322 
00323     SKIPSPACE(pe);
00324 
00325     if (*pe != '(') {
00326         rpmError(RPMERR_BADSPEC, _("Missing '(' in %s %s\n"), name, pe);
00327         fl->processingFailed = 1;
00328         return RPMERR_BADSPEC;
00329     }
00330 
00331     /* Bracket %*verify args */
00332     *pe++ = ' ';
00333     for (p = pe; *pe && *pe != ')'; pe++)
00334         {};
00335 
00336     if (*pe == '\0') {
00337         rpmError(RPMERR_BADSPEC, _("Missing ')' in %s(%s\n"), name, p);
00338         fl->processingFailed = 1;
00339         return RPMERR_BADSPEC;
00340     }
00341 
00342     /* Localize. Erase parsed string */
00343     q = alloca((pe-p) + 1);
00344     strncpy(q, p, pe-p);
00345     q[pe-p] = '\0';
00346     while (p <= pe)
00347         *p++ = ' ';
00348 
00349     negated = 0;
00350     verifyFlags = RPMVERIFY_NONE;
00351 
00352     for (p = q; *p != '\0'; p = pe) {
00353         SKIPWHITE(p);
00354         if (*p == '\0')
00355             break;
00356         pe = p;
00357         SKIPNONWHITE(pe);
00358         if (*pe != '\0')
00359             *pe++ = '\0';
00360 
00361         {   VFA_t *vfa;
00362             for (vfa = verifyAttrs; vfa->attribute != NULL; vfa++) {
00363                 if (strcmp(p, vfa->attribute))
00364                     continue;
00365                 verifyFlags |= vfa->flag;
00366                 /*@innerbreak@*/ break;
00367             }
00368             if (vfa->attribute)
00369                 continue;
00370         }
00371 
00372         if (!strcmp(p, "not")) {
00373             negated ^= 1;
00374         } else {
00375             rpmError(RPMERR_BADSPEC, _("Invalid %s token: %s\n"), name, p);
00376             fl->processingFailed = 1;
00377             return RPMERR_BADSPEC;
00378         }
00379     }
00380 
00381     *resultVerify = negated ? ~(verifyFlags) : verifyFlags;
00382     *specdFlags |= SPECD_VERIFY;
00383 
00384     return 0;
00385 }
00386 
00387 #define isAttrDefault(_ars)     ((_ars)[0] == '-' && (_ars)[1] == '\0')
00388 
00393 static int parseForDev(char * buf, FileList fl)
00394         /*@modifies buf, fl->processingFailed,
00395                 fl->noGlob, fl->devtype, fl->devmajor, fl->devminor @*/
00396 {
00397     const char * name;
00398     const char * errstr = NULL;
00399     char *p, *pe, *q;
00400     int rc = RPMERR_BADSPEC;    /* assume error */
00401 
00402     if ((p = strstr(buf, (name = "%dev"))) == NULL)
00403         return 0;
00404 
00405     for (pe = p; (pe-p) < strlen(name); pe++)
00406         *pe = ' ';
00407     SKIPSPACE(pe);
00408 
00409     if (*pe != '(') {
00410         errstr = "'('";
00411         goto exit;
00412     }
00413 
00414     /* Bracket %dev args */
00415     *pe++ = ' ';
00416     for (p = pe; *pe && *pe != ')'; pe++)
00417         {};
00418     if (*pe != ')') {
00419         errstr = "')'";
00420         goto exit;
00421     }
00422 
00423     /* Localize. Erase parsed string */
00424     q = alloca((pe-p) + 1);
00425     strncpy(q, p, pe-p);
00426     q[pe-p] = '\0';
00427     while (p <= pe)
00428         *p++ = ' ';
00429 
00430     p = q; SKIPWHITE(p);
00431     pe = p; SKIPNONWHITE(pe); if (*pe != '\0') *pe++ = '\0';
00432     if (*p == 'b')
00433         fl->devtype = 'b';
00434     else if (*p == 'c')
00435         fl->devtype = 'c';
00436     else {
00437         errstr = "devtype";
00438         goto exit;
00439     }
00440 
00441     p = pe; SKIPWHITE(p);
00442     pe = p; SKIPNONWHITE(pe); if (*pe != '\0') *pe++ = '\0';
00443     for (pe = p; *pe && xisdigit(*pe); pe++)
00444         {} ;
00445     if (*pe == '\0') {
00446         fl->devmajor = atoi(p);
00447         if (!(fl->devmajor >= 0 && fl->devmajor < 256)) {
00448             errstr = "devmajor";
00449             goto exit;
00450         }
00451         pe++;
00452     } else {
00453         errstr = "devmajor";
00454         goto exit;
00455     }
00456 
00457     p = pe; SKIPWHITE(p);
00458     pe = p; SKIPNONWHITE(pe); if (*pe != '\0') *pe++ = '\0';
00459     for (pe = p; *pe && xisdigit(*pe); pe++)
00460         {} ;
00461     if (*pe == '\0') {
00462         fl->devminor = atoi(p);
00463         if (!(fl->devminor >= 0 && fl->devminor < 256)) {
00464             errstr = "devminor";
00465             goto exit;
00466         }
00467         pe++;
00468     } else {
00469         errstr = "devminor";
00470         goto exit;
00471     }
00472 
00473     fl->noGlob = 1;
00474 
00475     rc = 0;
00476 
00477 exit:
00478     if (rc) {
00479         rpmError(RPMERR_BADSPEC, _("Missing %s in %s %s\n"), errstr, name, p);
00480         fl->processingFailed = 1;
00481     }
00482     return rc;
00483 }
00484 
00489 static int parseForAttr(char * buf, FileList fl)
00490         /*@modifies buf, fl->processingFailed,
00491                 fl->cur_ar, fl->def_ar,
00492                 fl->currentSpecdFlags, fl->defSpecdFlags @*/
00493 {
00494     const char *name;
00495     char *p, *pe, *q;
00496     int x;
00497     struct AttrRec_s arbuf;
00498     AttrRec ar = &arbuf, ret_ar;
00499     specdFlags * specdFlags;
00500 
00501     if ((p = strstr(buf, (name = "%attr"))) != NULL) {
00502         ret_ar = &(fl->cur_ar);
00503         specdFlags = &fl->currentSpecdFlags;
00504     } else if ((p = strstr(buf, (name = "%defattr"))) != NULL) {
00505         ret_ar = &(fl->def_ar);
00506         specdFlags = &fl->defSpecdFlags;
00507     } else
00508         return 0;
00509 
00510     for (pe = p; (pe-p) < strlen(name); pe++)
00511         *pe = ' ';
00512 
00513     SKIPSPACE(pe);
00514 
00515     if (*pe != '(') {
00516         rpmError(RPMERR_BADSPEC, _("Missing '(' in %s %s\n"), name, pe);
00517         fl->processingFailed = 1;
00518         return RPMERR_BADSPEC;
00519     }
00520 
00521     /* Bracket %*attr args */
00522     *pe++ = ' ';
00523     for (p = pe; *pe && *pe != ')'; pe++)
00524         {};
00525 
00526     if (ret_ar == &(fl->def_ar)) {      /* %defattr */
00527         q = pe;
00528         q++;
00529         SKIPSPACE(q);
00530         if (*q != '\0') {
00531             rpmError(RPMERR_BADSPEC,
00532                      _("Non-white space follows %s(): %s\n"), name, q);
00533             fl->processingFailed = 1;
00534             return RPMERR_BADSPEC;
00535         }
00536     }
00537 
00538     /* Localize. Erase parsed string */
00539     q = alloca((pe-p) + 1);
00540     strncpy(q, p, pe-p);
00541     q[pe-p] = '\0';
00542     while (p <= pe)
00543         *p++ = ' ';
00544 
00545     nullAttrRec(ar);
00546 
00547     p = q; SKIPWHITE(p);
00548     if (*p != '\0') {
00549         pe = p; SKIPNONWHITE(pe); if (*pe != '\0') *pe++ = '\0';
00550         ar->ar_fmodestr = p;
00551         p = pe; SKIPWHITE(p);
00552     }
00553     if (*p != '\0') {
00554         pe = p; SKIPNONWHITE(pe); if (*pe != '\0') *pe++ = '\0';
00555         ar->ar_user = p;
00556         p = pe; SKIPWHITE(p);
00557     }
00558     if (*p != '\0') {
00559         pe = p; SKIPNONWHITE(pe); if (*pe != '\0') *pe++ = '\0';
00560         ar->ar_group = p;
00561         p = pe; SKIPWHITE(p);
00562     }
00563     if (*p != '\0' && ret_ar == &(fl->def_ar)) {        /* %defattr */
00564         pe = p; SKIPNONWHITE(pe); if (*pe != '\0') *pe++ = '\0';
00565         ar->ar_dmodestr = p;
00566         p = pe; SKIPWHITE(p);
00567     }
00568 
00569     if (!(ar->ar_fmodestr && ar->ar_user && ar->ar_group) || *p != '\0') {
00570         rpmError(RPMERR_BADSPEC, _("Bad syntax: %s(%s)\n"), name, q);
00571         fl->processingFailed = 1;
00572         return RPMERR_BADSPEC;
00573     }
00574 
00575     /* Do a quick test on the mode argument and adjust for "-" */
00576     if (ar->ar_fmodestr && !isAttrDefault(ar->ar_fmodestr)) {
00577         unsigned int ui;
00578         x = sscanf(ar->ar_fmodestr, "%o", &ui);
00579         if ((x == 0) || (ar->ar_fmode & ~MYALLPERMS)) {
00580             rpmError(RPMERR_BADSPEC, _("Bad mode spec: %s(%s)\n"), name, q);
00581             fl->processingFailed = 1;
00582             return RPMERR_BADSPEC;
00583         }
00584         ar->ar_fmode = ui;
00585     } else
00586         ar->ar_fmodestr = NULL;
00587 
00588     if (ar->ar_dmodestr && !isAttrDefault(ar->ar_dmodestr)) {
00589         unsigned int ui;
00590         x = sscanf(ar->ar_dmodestr, "%o", &ui);
00591         if ((x == 0) || (ar->ar_dmode & ~MYALLPERMS)) {
00592             rpmError(RPMERR_BADSPEC, _("Bad dirmode spec: %s(%s)\n"), name, q);
00593             fl->processingFailed = 1;
00594             return RPMERR_BADSPEC;
00595         }
00596         ar->ar_dmode = ui;
00597     } else
00598         ar->ar_dmodestr = NULL;
00599 
00600     if (!(ar->ar_user && !isAttrDefault(ar->ar_user)))
00601         ar->ar_user = NULL;
00602 
00603     if (!(ar->ar_group && !isAttrDefault(ar->ar_group)))
00604         ar->ar_group = NULL;
00605 
00606     dupAttrRec(ar, ret_ar);
00607 
00608     /* XXX fix all this */
00609     *specdFlags |= SPECD_UID | SPECD_GID | SPECD_FILEMODE | SPECD_DIRMODE;
00610     
00611     return 0;
00612 }
00613 
00617 static int parseForConfig(char * buf, FileList fl)
00618         /*@modifies buf, fl->processingFailed,
00619                 fl->currentFlags @*/
00620 {
00621     char *p, *pe, *q;
00622     const char *name;
00623 
00624     if ((p = strstr(buf, (name = "%config"))) == NULL)
00625         return 0;
00626 
00627     fl->currentFlags = RPMFILE_CONFIG;
00628 
00629     for (pe = p; (pe-p) < strlen(name); pe++)
00630         *pe = ' ';
00631     SKIPSPACE(pe);
00632     if (*pe != '(')
00633         return 0;
00634 
00635     /* Bracket %config args */
00636     *pe++ = ' ';
00637     for (p = pe; *pe && *pe != ')'; pe++)
00638         {};
00639 
00640     if (*pe == '\0') {
00641         rpmError(RPMERR_BADSPEC, _("Missing ')' in %s(%s\n"), name, p);
00642         fl->processingFailed = 1;
00643         return RPMERR_BADSPEC;
00644     }
00645 
00646     /* Localize. Erase parsed string */
00647     q = alloca((pe-p) + 1);
00648     strncpy(q, p, pe-p);
00649     q[pe-p] = '\0';
00650     while (p <= pe)
00651         *p++ = ' ';
00652 
00653     for (p = q; *p != '\0'; p = pe) {
00654         SKIPWHITE(p);
00655         if (*p == '\0')
00656             break;
00657         pe = p;
00658         SKIPNONWHITE(pe);
00659         if (*pe != '\0')
00660             *pe++ = '\0';
00661         if (!strcmp(p, "missingok")) {
00662             fl->currentFlags |= RPMFILE_MISSINGOK;
00663         } else if (!strcmp(p, "noreplace")) {
00664             fl->currentFlags |= RPMFILE_NOREPLACE;
00665         } else {
00666             rpmError(RPMERR_BADSPEC, _("Invalid %s token: %s\n"), name, p);
00667             fl->processingFailed = 1;
00668             return RPMERR_BADSPEC;
00669         }
00670     }
00671 
00672     return 0;
00673 }
00674 
00677 static int langCmp(const void * ap, const void * bp)    /*@*/
00678 {
00679     return strcmp(*(const char **)ap, *(const char **)bp);
00680 }
00681 
00685 static int parseForLang(char * buf, FileList fl)
00686         /*@modifies buf, fl->processingFailed,
00687                 fl->currentLangs, fl->nLangs @*/
00688 {
00689     char *p, *pe, *q;
00690     const char *name;
00691 
00692   while ((p = strstr(buf, (name = "%lang"))) != NULL) {
00693 
00694     for (pe = p; (pe-p) < strlen(name); pe++)
00695         *pe = ' ';
00696     SKIPSPACE(pe);
00697 
00698     if (*pe != '(') {
00699         rpmError(RPMERR_BADSPEC, _("Missing '(' in %s %s\n"), name, pe);
00700         fl->processingFailed = 1;
00701         return RPMERR_BADSPEC;
00702     }
00703 
00704     /* Bracket %lang args */
00705     *pe++ = ' ';
00706     for (pe = p; *pe && *pe != ')'; pe++)
00707         {};
00708 
00709     if (*pe == '\0') {
00710         rpmError(RPMERR_BADSPEC, _("Missing ')' in %s(%s\n"), name, p);
00711         fl->processingFailed = 1;
00712         return RPMERR_BADSPEC;
00713     }
00714 
00715     /* Localize. Erase parsed string */
00716     q = alloca((pe-p) + 1);
00717     strncpy(q, p, pe-p);
00718     q[pe-p] = '\0';
00719     while (p <= pe)
00720         *p++ = ' ';
00721 
00722     /* Parse multiple arguments from %lang */
00723     for (p = q; *p != '\0'; p = pe) {
00724         char *newp;
00725         size_t np;
00726         int i;
00727 
00728         SKIPWHITE(p);
00729         pe = p;
00730         SKIPNONWHITE(pe);
00731 
00732         np = pe - p;
00733         
00734         /* Sanity check on locale lengths */
00735         if (np < 1 || (np == 1 && *p != 'C') || np >= 32) {
00736             rpmError(RPMERR_BADSPEC,
00737                 _("Unusual locale length: \"%.*s\" in %%lang(%s)\n"),
00738                 (int)np, p, q);
00739             fl->processingFailed = 1;
00740             return RPMERR_BADSPEC;
00741         }
00742 
00743         /* Check for duplicate locales */
00744         if (fl->currentLangs != NULL)
00745         for (i = 0; i < fl->nLangs; i++) {
00746             if (strncmp(fl->currentLangs[i], p, np))
00747                 continue;
00748             rpmError(RPMERR_BADSPEC, _("Duplicate locale %.*s in %%lang(%s)\n"),
00749                 (int)np, p, q);
00750             fl->processingFailed = 1;
00751             return RPMERR_BADSPEC;
00752         }
00753 
00754         /* Add new locale */
00755         fl->currentLangs = xrealloc(fl->currentLangs,
00756                                 (fl->nLangs + 1) * sizeof(*fl->currentLangs));
00757         newp = xmalloc( np+1 );
00758         strncpy(newp, p, np);
00759         newp[np] = '\0';
00760         fl->currentLangs[fl->nLangs++] = newp;
00761         if (*pe == ',') pe++;   /* skip , if present */
00762     }
00763   }
00764 
00765     /* Insure that locales are sorted. */
00766     if (fl->currentLangs)
00767         qsort(fl->currentLangs, fl->nLangs, sizeof(*fl->currentLangs), langCmp);
00768 
00769     return 0;
00770 }
00771 
00774 static int parseForRegexLang(const char * fileName, /*@out@*/ char ** lang)
00775         /*@modifies *lang @*/
00776 {
00777     static int initialized = 0;
00778     static int hasRegex = 0;
00779     static regex_t compiledPatt;
00780     static char buf[BUFSIZ];
00781     int x;
00782     regmatch_t matches[2];
00783     const char *s;
00784 
00785     if (! initialized) {
00786         const char *patt = rpmExpand("%{_langpatt}", NULL);
00787         int rc = 0;
00788         if (!(patt && *patt != '%'))
00789             rc = 1;
00790         else if (regcomp(&compiledPatt, patt, REG_EXTENDED))
00791             rc = -1;
00792         patt = _free(patt);
00793         if (rc)
00794             return rc;
00795         hasRegex = 1;
00796         initialized = 1;
00797     }
00798     
00799     memset(matches, 0, sizeof(matches));
00800     if (! hasRegex || regexec(&compiledPatt, fileName, 2, matches, REG_NOTEOL))
00801         return 1;
00802 
00803     /* Got match */
00804     s = fileName + matches[1].rm_eo - 1;
00805     x = matches[1].rm_eo - matches[1].rm_so;
00806     buf[x] = '\0';
00807     while (x) {
00808         buf[--x] = *s--;
00809     }
00810     if (lang)
00811         *lang = buf;
00812     return 0;
00813 }
00814 
00817 static int parseForRegexMultiLib(const char *fileName)  /*@*/
00818 {
00819     static int initialized = 0;
00820     static int hasRegex = 0;
00821     static regex_t compiledPatt;
00822 
00823     if (! initialized) {
00824         const char *patt;
00825         int rc = 0;
00826 
00827         initialized = 1;
00828         patt = rpmExpand("%{_multilibpatt}", NULL);
00829         if (!(patt && *patt != '%'))
00830             rc = 1;
00831         else if (regcomp(&compiledPatt, patt, REG_EXTENDED | REG_NOSUB))
00832             rc = -1;
00833         patt = _free(patt);
00834         if (rc)
00835             return rc;
00836         hasRegex = 1;
00837     }
00838 
00839     if (! hasRegex || regexec(&compiledPatt, fileName, 0, NULL, 0))
00840         return 1;
00841 
00842     return 0;
00843 }
00844 
00847 /*@-exportlocal -exportheadervar@*/
00848 VFA_t virtualFileAttributes[] = {
00849         { "%dir",       0 },    /* XXX why not RPMFILE_DIR? */
00850         { "%doc",       RPMFILE_DOC },
00851         { "%ghost",     RPMFILE_GHOST },
00852         { "%exclude",   RPMFILE_EXCLUDE },
00853         { "%readme",    RPMFILE_README },
00854         { "%license",   RPMFILE_LICENSE },
00855         { "%multilib",  0 },
00856 
00857 #if WHY_NOT
00858         { "%spec",      RPMFILE_SPEC },
00859         { "%config",    RPMFILE_CONFIG },
00860         { "%donotuse",  RPMFILE_DONOTUSE },     /* XXX WTFO? */
00861         { "%missingok", RPMFILE_CONFIG|RPMFILE_MISSINGOK },
00862         { "%noreplace", RPMFILE_CONFIG|RPMFILE_NOREPLACE },
00863 #endif
00864 
00865         { NULL, 0 }
00866 };
00867 /*@=exportlocal =exportheadervar@*/
00868 
00872 static int parseForSimple(/*@unused@*/Spec spec, Package pkg, char * buf,
00873                           FileList fl, /*@out@*/ const char ** fileName)
00874         /*@modifies buf, fl->processingFailed, *fileName,
00875                 fl->currentFlags,
00876                 fl->docDirs, fl->docDirCount, fl->isDir,
00877                 fl->passedSpecialDoc, fl->isSpecialDoc,
00878                 pkg->specialDoc @*/
00879 {
00880     char *s, *t;
00881     int res, specialDoc = 0;
00882     char specialDocBuf[BUFSIZ];
00883 
00884     specialDocBuf[0] = '\0';
00885     *fileName = NULL;
00886     res = 0;
00887 
00888     t = buf;
00889     while ((s = strtokWithQuotes(t, " \t\n")) != NULL) {
00890         t = NULL;
00891         if (!strcmp(s, "%docdir")) {
00892             s = strtokWithQuotes(NULL, " \t\n");
00893             if (fl->docDirCount == MAXDOCDIR) {
00894                 rpmError(RPMERR_INTERNAL, _("Hit limit for %%docdir\n"));
00895                 fl->processingFailed = 1;
00896                 res = 1;
00897             }
00898             fl->docDirs[fl->docDirCount++] = xstrdup(s);
00899             if (strtokWithQuotes(NULL, " \t\n")) {
00900                 rpmError(RPMERR_INTERNAL, _("Only one arg for %%docdir\n"));
00901                 fl->processingFailed = 1;
00902                 res = 1;
00903             }
00904             break;
00905         }
00906 
00907     /* Set flags for virtual file attributes */
00908     {   VFA_t *vfa;
00909         for (vfa = virtualFileAttributes; vfa->attribute != NULL; vfa++) {
00910             if (strcmp(s, vfa->attribute))
00911                 continue;
00912             if (!vfa->flag) {
00913                 if (!strcmp(s, "%dir"))
00914                     fl->isDir = 1;      /* XXX why not RPMFILE_DIR? */
00915                 else if (!strcmp(s, "%multilib"))
00916                     fl->currentFlags |= multiLib;
00917             } else
00918                 fl->currentFlags |= vfa->flag;
00919             /*@innerbreak@*/ break;
00920         }
00921         /* if we got an attribute, continue with next token */
00922         if (vfa->attribute != NULL)
00923             continue;
00924     }
00925 
00926         if (*fileName) {
00927             /* We already got a file -- error */
00928             rpmError(RPMERR_BADSPEC, _("Two files on one line: %s\n"),
00929                 *fileName);
00930             fl->processingFailed = 1;
00931             res = 1;
00932         }
00933 
00934         if (*s != '/') {
00935             if (fl->currentFlags & RPMFILE_DOC) {
00936                 specialDoc = 1;
00937                 strcat(specialDocBuf, " ");
00938                 strcat(specialDocBuf, s);
00939             } else {
00940                 /* not in %doc, does not begin with / -- error */
00941                 rpmError(RPMERR_BADSPEC,
00942                     _("File must begin with \"/\": %s\n"), s);
00943                 fl->processingFailed = 1;
00944                 res = 1;
00945             }
00946         } else {
00947             *fileName = s;
00948         }
00949     }
00950 
00951     if (specialDoc) {
00952         if (*fileName || (fl->currentFlags & ~(RPMFILE_DOC))) {
00953             rpmError(RPMERR_BADSPEC,
00954                      _("Can't mix special %%doc with other forms: %s\n"),
00955                      (*fileName ? *fileName : ""));
00956             fl->processingFailed = 1;
00957             res = 1;
00958         } else {
00959         /* XXX WATCHOUT: buf is an arg */
00960             {   const char *ddir, *n, *v;
00961 
00962                 (void) headerNVR(pkg->header, &n, &v, NULL);
00963 
00964                 ddir = rpmGetPath("%{_docdir}/", n, "-", v, NULL);
00965                 strcpy(buf, ddir);
00966                 ddir = _free(ddir);
00967             }
00968 
00969         /* XXX FIXME: this is easy to do as macro expansion */
00970 
00971             if (! fl->passedSpecialDoc) {
00972                 pkg->specialDoc = newStringBuf();
00973                 appendStringBuf(pkg->specialDoc, "DOCDIR=$RPM_BUILD_ROOT");
00974                 appendLineStringBuf(pkg->specialDoc, buf);
00975                 appendLineStringBuf(pkg->specialDoc, "export DOCDIR");
00976                 appendLineStringBuf(pkg->specialDoc, "rm -rf $DOCDIR");
00977                 appendLineStringBuf(pkg->specialDoc, MKDIR_P " $DOCDIR");
00978 
00979                 /*@-temptrans@*/
00980                 *fileName = buf;
00981                 /*@=temptrans@*/
00982                 fl->passedSpecialDoc = 1;
00983                 fl->isSpecialDoc = 1;
00984             }
00985 
00986             appendStringBuf(pkg->specialDoc, "cp -pr ");
00987             appendStringBuf(pkg->specialDoc, specialDocBuf);
00988             appendLineStringBuf(pkg->specialDoc, " $DOCDIR");
00989         }
00990     }
00991 
00992     return res;
00993 }
00994 
00997 static int compareFileListRecs(const void * ap, const void * bp)        /*@*/
00998 {
00999     const char *a = ((FileListRec)ap)->fileURL;
01000     const char *b = ((FileListRec)bp)->fileURL;
01001     return strcmp(a, b);
01002 }
01003 
01007 static int isDoc(FileList fl, const char * fileName)    /*@*/
01008 {
01009     int x = fl->docDirCount;
01010 
01011     while (x--) {
01012         if (strstr(fileName, fl->docDirs[x]) == fileName)
01013             return 1;
01014     }
01015     return 0;
01016 }
01017 
01023 static void checkHardLinks(FileList fl)
01024         /*@modifies fl->fileList->flags, fl->fileList->langs @*/
01025 {
01026     char nlangs[BUFSIZ];
01027     FileListRec ilp, jlp;
01028     int i, j;
01029 
01030     for (i = 0;  i < fl->fileListRecsUsed; i++) {
01031         char *te;
01032 
01033         ilp = fl->fileList + i;
01034         if (!(S_ISREG(ilp->fl_mode) && ilp->fl_nlink > 1))
01035             continue;
01036         if (ilp->flags & RPMFILE_SPECFILE)
01037             continue;
01038 
01039         te = nlangs;
01040         *te = '\0';
01041         for (j = i + 1; j < fl->fileListRecsUsed; j++) {
01042             jlp = fl->fileList + j;
01043             if (!S_ISREG(jlp->fl_mode))
01044                 continue;
01045             if (ilp->fl_nlink != jlp->fl_nlink)
01046                 continue;
01047             if (ilp->fl_ino != jlp->fl_ino)
01048                 continue;
01049             if (ilp->fl_dev != jlp->fl_dev)
01050                 continue;
01051             if (!strcmp(ilp->langs, jlp->langs)) {
01052                 jlp->flags |= RPMFILE_SPECFILE;
01053                 continue;
01054             }
01055             if (te == nlangs)
01056                 te = stpcpy(te, ilp->langs);
01057             *te++ = '|';
01058             te = stpcpy(te, jlp->langs);
01059         }
01060 
01061         /* Are locales distributed over hard links correctly? */
01062         if (te == nlangs)
01063             continue;
01064 
01065         ilp->langs = _free(ilp->langs);
01066         ilp->langs = xstrdup(nlangs);
01067         for (j = i + 1; j < fl->fileListRecsUsed; j++) {
01068             jlp = fl->fileList + j;
01069             if (!S_ISREG(jlp->fl_mode))
01070                 continue;
01071             if (ilp->fl_nlink != jlp->fl_nlink)
01072                 continue;
01073             if (ilp->fl_ino != jlp->fl_ino)
01074                 continue;
01075             if (ilp->fl_dev != jlp->fl_dev)
01076                 continue;
01077             jlp->flags |= RPMFILE_SPECFILE;
01078             jlp->langs = _free(jlp->langs);
01079             jlp->langs = xstrdup(nlangs);
01080         }
01081     }
01082 
01083     for (i = 0;  i < fl->fileListRecsUsed; i++) {
01084         ilp = fl->fileList + i;
01085         ilp->flags &= ~RPMFILE_SPECFILE;
01086     }
01087 }
01088 
01094 static void genCpioListAndHeader(/*@partial@*/ FileList fl,
01095                 TFI_t * cpioList, Header h, int isSrc)
01096         /*@modifies h, *cpioList, fl->processingFailed, fl->fileList @*/
01097 {
01098     int _addDotSlash = !(isSrc || rpmExpandNumeric("%{_noPayloadPrefix}"));
01099     uint_32 multiLibMask = 0;
01100     int apathlen = 0;
01101     int dpathlen = 0;
01102     int skipLen = 0;
01103     FileListRec flp;
01104     uint_32 timetislongbutlongisnotint32;
01105     char buf[BUFSIZ];
01106     int i;
01107     
01108     /* Sort the big list */
01109     qsort(fl->fileList, fl->fileListRecsUsed,
01110           sizeof(*(fl->fileList)), compareFileListRecs);
01111     
01112     /* Generate the header. */
01113     if (! isSrc) {
01114         skipLen = 1;
01115         if (fl->prefix)
01116             skipLen += strlen(fl->prefix);
01117     }
01118 
01119     for (i = 0, flp = fl->fileList; i < fl->fileListRecsUsed; i++, flp++) {
01120         char *s;
01121 
01122         /* Merge duplicate entries. */
01123         while (i < (fl->fileListRecsUsed - 1) &&
01124             !strcmp(flp->fileURL, flp[1].fileURL)) {
01125 
01126             /* Two entries for the same file found, merge the entries. */
01127 
01128             rpmMessage(RPMMESS_WARNING, _("File listed twice: %s\n"),
01129                 flp->fileURL);
01130 
01131             /* file flags */
01132             flp[1].flags |= flp->flags; 
01133    
01134             /* file mode */
01135             if (S_ISDIR(flp->fl_mode)) {
01136                 if ((flp[1].specdFlags & (SPECD_DIRMODE | SPECD_DEFDIRMODE)) <
01137                     (flp->specdFlags & (SPECD_DIRMODE | SPECD_DEFDIRMODE)))
01138                         flp[1].fl_mode = flp->fl_mode;
01139             } else {
01140                 if ((flp[1].specdFlags & (SPECD_FILEMODE | SPECD_DEFFILEMODE)) <
01141                     (flp->specdFlags & (SPECD_FILEMODE | SPECD_DEFFILEMODE)))
01142                         flp[1].fl_mode = flp->fl_mode;
01143             }
01144 
01145             /* uid */
01146             if ((flp[1].specdFlags & (SPECD_UID | SPECD_DEFUID)) <
01147                 (flp->specdFlags & (SPECD_UID | SPECD_DEFUID)))
01148             {
01149                 flp[1].fl_uid = flp->fl_uid;
01150                 flp[1].uname = flp->uname;
01151             }
01152 
01153             /* gid */
01154             if ((flp[1].specdFlags & (SPECD_GID | SPECD_DEFGID)) <
01155                 (flp->specdFlags & (SPECD_GID | SPECD_DEFGID)))
01156             {
01157                 flp[1].fl_gid = flp->fl_gid;
01158                 flp[1].gname = flp->gname;
01159             }
01160 
01161             /* verify flags */
01162             if ((flp[1].specdFlags & (SPECD_VERIFY | SPECD_DEFVERIFY)) <
01163                 (flp->specdFlags & (SPECD_VERIFY | SPECD_DEFVERIFY)))
01164                     flp[1].verifyFlags = flp->verifyFlags;
01165 
01166             /* XXX to-do: language */
01167 
01168             flp++; i++;
01169         }
01170 
01171         /* Skip files that were marked with %exclude. */
01172         if (flp->flags & RPMFILE_EXCLUDE) continue;
01173 
01174         /* Omit '/' and/or URL prefix, leave room for "./" prefix */
01175         apathlen += (strlen(flp->fileURL) - skipLen + (_addDotSlash ? 3 : 1));
01176 
01177         /* Leave room for both dirname and basename NUL's */
01178         dpathlen += (strlen(flp->diskURL) + 2);
01179 
01180         if (flp->flags & RPMFILE_MULTILIB_MASK)
01181             multiLibMask |=
01182                 (1u << ((flp->flags & RPMFILE_MULTILIB_MASK))
01183                       >> RPMFILE_MULTILIB_SHIFT);
01184 
01185         /*
01186          * Make the header, the OLDFILENAMES will get converted to a 
01187          * compressed file list write before we write the actual package to
01188          * disk.
01189          */
01190         (void) headerAddOrAppendEntry(h, RPMTAG_OLDFILENAMES, RPM_STRING_ARRAY_TYPE,
01191                                &(flp->fileURL), 1);
01192 
01193       if (sizeof(flp->fl_size) != sizeof(uint_32)) {
01194         uint_32 psize = (uint_32)flp->fl_size;
01195         (void) headerAddOrAppendEntry(h, RPMTAG_FILESIZES, RPM_INT32_TYPE,
01196                                &(psize), 1);
01197       } else {
01198         (void) headerAddOrAppendEntry(h, RPMTAG_FILESIZES, RPM_INT32_TYPE,
01199                                &(flp->fl_size), 1);
01200       }
01201         (void) headerAddOrAppendEntry(h, RPMTAG_FILEUSERNAME, RPM_STRING_ARRAY_TYPE,
01202                                &(flp->uname), 1);
01203         (void) headerAddOrAppendEntry(h, RPMTAG_FILEGROUPNAME, RPM_STRING_ARRAY_TYPE,
01204                                &(flp->gname), 1);
01205         timetislongbutlongisnotint32 = flp->fl_mtime;
01206         (void) headerAddOrAppendEntry(h, RPMTAG_FILEMTIMES, RPM_INT32_TYPE,
01207                                &(timetislongbutlongisnotint32), 1);
01208       if (sizeof(flp->fl_mode) != sizeof(uint_16)) {
01209         uint_16 pmode = (uint_16)flp->fl_mode;
01210         (void) headerAddOrAppendEntry(h, RPMTAG_FILEMODES, RPM_INT16_TYPE,
01211                                &(pmode), 1);
01212       } else {
01213         (void) headerAddOrAppendEntry(h, RPMTAG_FILEMODES, RPM_INT16_TYPE,
01214                                &(flp->fl_mode), 1);
01215       }
01216       if (sizeof(flp->fl_rdev) != sizeof(uint_16)) {
01217         uint_16 prdev = (uint_16)flp->fl_rdev;
01218         (void) headerAddOrAppendEntry(h, RPMTAG_FILERDEVS, RPM_INT16_TYPE,
01219                                &(prdev), 1);
01220       } else {
01221         (void) headerAddOrAppendEntry(h, RPMTAG_FILERDEVS, RPM_INT16_TYPE,
01222                                &(flp->fl_rdev), 1);
01223       }
01224       if (sizeof(flp->fl_dev) != sizeof(uint_32)) {
01225         uint_32 pdevice = (uint_32)flp->fl_dev;
01226         (void) headerAddOrAppendEntry(h, RPMTAG_FILEDEVICES, RPM_INT32_TYPE,
01227                                &(pdevice), 1);
01228       } else {
01229         (void) headerAddOrAppendEntry(h, RPMTAG_FILEDEVICES, RPM_INT32_TYPE,
01230                                &(flp->fl_dev), 1);
01231       }
01232         (void) headerAddOrAppendEntry(h, RPMTAG_FILEINODES, RPM_INT32_TYPE,
01233                                &(flp->fl_ino), 1);
01234 
01235         (void) headerAddOrAppendEntry(h, RPMTAG_FILELANGS, RPM_STRING_ARRAY_TYPE,
01236                                &(flp->langs),  1);
01237         
01238         /* We used to add these, but they should not be needed */
01239         /* (void) headerAddOrAppendEntry(h, RPMTAG_FILEUIDS,
01240          *                 RPM_INT32_TYPE, &(flp->fl_uid), 1);
01241          * (void) headerAddOrAppendEntry(h, RPMTAG_FILEGIDS,
01242          *                 RPM_INT32_TYPE, &(flp->fl_gid), 1);
01243          */
01244         
01245         buf[0] = '\0';
01246         if (S_ISREG(flp->fl_mode))
01247             (void) mdfile(flp->diskURL, buf);
01248         s = buf;
01249         (void) headerAddOrAppendEntry(h, RPMTAG_FILEMD5S, RPM_STRING_ARRAY_TYPE,
01250                                &s, 1);
01251         
01252         buf[0] = '\0';
01253         if (S_ISLNK(flp->fl_mode)) {
01254             buf[Readlink(flp->diskURL, buf, BUFSIZ)] = '\0';
01255             if (fl->buildRootURL) {
01256                 const char * buildRoot;
01257                 (void) urlPath(fl->buildRootURL, &buildRoot);
01258 
01259                 if (buf[0] == '/' && strcmp(buildRoot, "/") &&
01260                     !strncmp(buf, buildRoot, strlen(buildRoot))) {
01261                      rpmError(RPMERR_BADSPEC,
01262                                 _("Symlink points to BuildRoot: %s -> %s\n"),
01263                                 flp->fileURL, buf);
01264                     fl->processingFailed = 1;
01265                 }
01266             }
01267         }
01268         s = buf;
01269         (void) headerAddOrAppendEntry(h, RPMTAG_FILELINKTOS, RPM_STRING_ARRAY_TYPE,
01270                                &s, 1);
01271         
01272         if (flp->flags & RPMFILE_GHOST) {
01273             flp->verifyFlags &= ~(RPMVERIFY_MD5 | RPMVERIFY_FILESIZE |
01274                                 RPMVERIFY_LINKTO | RPMVERIFY_MTIME);
01275         }
01276         (void) headerAddOrAppendEntry(h, RPMTAG_FILEVERIFYFLAGS, RPM_INT32_TYPE,
01277                                &(flp->verifyFlags), 1);
01278         
01279         if (!isSrc && isDoc(fl, flp->fileURL))
01280             flp->flags |= RPMFILE_DOC;
01281         /* XXX Should directories have %doc/%config attributes? (#14531) */
01282         if (S_ISDIR(flp->fl_mode))
01283             flp->flags &= ~(RPMFILE_CONFIG|RPMFILE_DOC);
01284 
01285         (void) headerAddOrAppendEntry(h, RPMTAG_FILEFLAGS, RPM_INT32_TYPE,
01286                                &(flp->flags), 1);
01287 
01288     }
01289     (void) headerAddEntry(h, RPMTAG_SIZE, RPM_INT32_TYPE,
01290                    &(fl->totalFileSize), 1);
01291 
01292     /* XXX This should be added always so that packages look alike.
01293      * XXX However, there is logic in files.c/depends.c that checks for
01294      * XXX existence (rather than value) that will need to change as well.
01295      */
01296     if (multiLibMask)
01297         (void) headerAddEntry(h, RPMTAG_MULTILIBS, RPM_INT32_TYPE,
01298                        &multiLibMask, 1);
01299 
01300     if (_addDotSlash)
01301         (void) rpmlibNeedsFeature(h, "PayloadFilesHavePrefix", "4.0-1");
01302 
01303     /* Choose how filenames are represented. */
01304     if (_noDirTokens)
01305         expandFilelist(h);
01306     else {
01307         compressFilelist(h);
01308         /* Binary packages with dirNames cannot be installed by legacy rpm. */
01309         (void) rpmlibNeedsFeature(h, "CompressedFileNames", "3.0.4-1");
01310     }
01311 
01312   { TFI_t fi = xcalloc(sizeof(*fi), 1);
01313     char * a, * d;
01314 
01315     fi->type = TR_ADDED;
01316     loadFi(h, fi);
01317     fi->dnl = _free(fi->dnl);
01318     fi->bnl = _free(fi->bnl);
01319 
01320     fi->dnl = xmalloc(fi->fc * sizeof(*fi->dnl) + dpathlen);
01321     d = (char *)(fi->dnl + fi->fc);
01322     *d = '\0';
01323 
01324     fi->bnl = xmalloc(fi->fc * (sizeof(*fi->bnl) + sizeof(*fi->dil)));
01325     fi->dil = (int *)(fi->bnl + fi->fc);
01326 
01327     fi->apath = xmalloc(fi->fc * sizeof(*fi->apath) + apathlen);
01328     a = (char *)(fi->apath + fi->fc);
01329     *a = '\0';
01330 
01331     fi->actions = xcalloc(sizeof(*fi->actions), fi->fc);
01332     fi->fmapflags = xcalloc(sizeof(*fi->fmapflags), fi->fc);
01333     fi->astriplen = 0;
01334     if (fl->buildRootURL)
01335         fi->astriplen = strlen(fl->buildRootURL);
01336     fi->striplen = 0;
01337     fi->fuser = NULL;
01338     fi->fuids = xcalloc(sizeof(*fi->fuids), fi->fc);
01339     fi->fgroup = NULL;
01340     fi->fgids = xcalloc(sizeof(*fi->fgids), fi->fc);
01341 
01342     /* Make the cpio list */
01343     for (i = 0, flp = fl->fileList; i < fi->fc; i++, flp++) {
01344         char * b;
01345 
01346         /* Skip (possible) duplicate file entries, use last entry info. */
01347         while (((flp - fl->fileList) < (fl->fileListRecsUsed - 1)) &&
01348                 !strcmp(flp->fileURL, flp[1].fileURL))
01349             flp++;
01350 
01351         /* Create disk directory and base name. */
01352         fi->dil[i] = i;
01353         fi->dnl[fi->dil[i]] = d;
01354         d = stpcpy(d, flp->diskURL);
01355 
01356         /* Make room for the dirName NUL, find start of baseName. */
01357         for (b = d; b > fi->dnl[fi->dil[i]] && *b != '/'; b--)
01358             b[1] = b[0];
01359         b++;            /* dirname's end in '/' */
01360         *b++ = '\0';    /* terminate dirname, b points to basename */
01361         fi->bnl[i] = b;
01362         d += 2;         /* skip both dirname and basename NUL's */
01363 
01364         /* Create archive path, normally adding "./" */
01365         /*@-dependenttrans@*/   /* FIX: xstrdup? nah ... */
01366         fi->apath[i] = a;
01367         /*@=dependenttrans@*/
01368         if (_addDotSlash) a = stpcpy(a, "./");
01369         a = stpcpy(a, (flp->fileURL + skipLen));
01370         a++;            /* skip apath NUL */
01371 
01372         if (flp->flags & RPMFILE_GHOST) {
01373             fi->actions[i] = FA_SKIP;
01374             continue;
01375         }
01376         fi->actions[i] = FA_COPYOUT;
01377         fi->fuids[i] = getUidS(flp->uname);
01378         fi->fgids[i] = getGidS(flp->gname);
01379         if (fi->fuids[i] == (uid_t)-1) fi->fuids[i] = 0;
01380         if (fi->fgids[i] == (gid_t)-1) fi->fgids[i] = 0;
01381         fi->fmapflags[i] = CPIO_MAP_PATH |
01382                 CPIO_MAP_TYPE | CPIO_MAP_MODE | CPIO_MAP_UID | CPIO_MAP_GID;
01383         if (isSrc)
01384             fi->fmapflags[i] |= CPIO_FOLLOW_SYMLINKS;
01385         if (flp->flags & RPMFILE_MULTILIB_MASK)
01386             fi->fmapflags[i] |= CPIO_MULTILIB;
01387 
01388     }
01389     if (cpioList)
01390         *cpioList = fi;
01391     else
01392         fi = _free(fi);
01393   }
01394 }
01395 
01398 static /*@null@*/ FileListRec freeFileList(/*@only@*/ FileListRec fileList,
01399                         int count)
01400         /*@*/
01401 {
01402     while (count--) {
01403         fileList[count].diskURL = _free(fileList[count].diskURL);
01404         fileList[count].fileURL = _free(fileList[count].fileURL);
01405         fileList[count].langs = _free(fileList[count].langs);
01406     }
01407     fileList = _free(fileList);
01408     return NULL;
01409 }
01410 
01414 static int addFile(FileList fl, const char * diskURL, struct stat * statp)
01415         /*@modifies *statp, fl->processingFailed,
01416                 fl->fileList, fl->fileListRecsAlloced, fl->fileListRecsUsed,
01417                 fl->totalFileSize, fl->fileCount, fl->inFtw, fl->isDir @*/
01418 {
01419     const char *fileURL = diskURL;
01420     struct stat statbuf;
01421     mode_t fileMode;
01422     uid_t fileUid;
01423     gid_t fileGid;
01424     const char *fileUname;
01425     const char *fileGname;
01426     char *lang;
01427     
01428     /* Path may have prepended buildRootURL, so locate the original filename. */
01429     /*
01430      * XXX There are 3 types of entry into addFile:
01431      *
01432      *  From                    diskUrl                 statp
01433      *  =====================================================
01434      *  processBinaryFile       path                    NULL
01435      *  processBinaryFile       glob result path        NULL
01436      *  myftw                   path                    stat
01437      *
01438      */
01439     {   const char *fileName;
01440         (void) urlPath(fileURL, &fileName);
01441         if (fl->buildRootURL && strcmp(fl->buildRootURL, "/"))
01442             fileURL += strlen(fl->buildRootURL);
01443     }
01444 
01445     /* XXX make sure '/' can be packaged also */
01446     if (*fileURL == '\0')
01447         fileURL = "/";
01448 
01449     /* If we are using a prefix, validate the file */
01450     if (!fl->inFtw && fl->prefix) {
01451         const char *prefixTest;
01452         const char *prefixPtr = fl->prefix;
01453 
01454         (void) urlPath(fileURL, &prefixTest);
01455         while (*prefixPtr && *prefixTest && (*prefixTest == *prefixPtr)) {
01456             prefixPtr++;
01457             prefixTest++;
01458         }
01459         if (*prefixPtr || (*prefixTest && *prefixTest != '/')) {
01460             rpmError(RPMERR_BADSPEC, _("File doesn't match prefix (%s): %s\n"),
01461                      fl->prefix, fileURL);
01462             fl->processingFailed = 1;
01463             return RPMERR_BADSPEC;
01464         }
01465     }
01466 
01467     if (statp == NULL) {
01468         statp = &statbuf;
01469         memset(statp, 0, sizeof(*statp));
01470         if (fl->devtype) {
01471             time_t now = time(NULL);
01472 
01473             /* XXX hack up a stat structure for a %dev(...) directive. */
01474             statp->st_nlink = 1;
01475             statp->st_rdev =
01476                 ((fl->devmajor & 0xff) << 8) | (fl->devminor & 0xff);
01477             statp->st_dev = statp->st_rdev;
01478             statp->st_mode = (fl->devtype == 'b' ? S_IFBLK : S_IFCHR);
01479             statp->st_mode |= (fl->cur_ar.ar_fmode & 0777);
01480             statp->st_atime = now;
01481             statp->st_mtime = now;
01482             statp->st_ctime = now;
01483         } else if (Lstat(diskURL, statp)) {
01484             rpmError(RPMERR_BADSPEC, _("File not found: %s\n"), diskURL);
01485             fl->processingFailed = 1;
01486             return RPMERR_BADSPEC;
01487         }
01488     }
01489 
01490     if ((! fl->isDir) && S_ISDIR(statp->st_mode)) {
01491         /* We use our own ftw() call, because ftw() uses stat()    */
01492         /* instead of lstat(), which causes it to follow symlinks! */
01493         /* It also has better callback support.                    */
01494         
01495         fl->inFtw = 1;  /* Flag to indicate file has buildRootURL prefixed */
01496         fl->isDir = 1;  /* Keep it from following myftw() again         */
01497         (void) myftw(diskURL, 16, (myftwFunc) addFile, fl);
01498         fl->isDir = 0;
01499         fl->inFtw = 0;
01500         return 0;
01501     }
01502 
01503     fileMode = statp->st_mode;
01504     fileUid = statp->st_uid;
01505     fileGid = statp->st_gid;
01506 
01507     if (S_ISDIR(fileMode) && fl->cur_ar.ar_dmodestr) {
01508         fileMode &= S_IFMT;
01509         fileMode |= fl->cur_ar.ar_dmode;
01510     } else if (fl->cur_ar.ar_fmodestr != NULL) {
01511         fileMode &= S_IFMT;
01512         fileMode |= fl->cur_ar.ar_fmode;
01513     }
01514     if (fl->cur_ar.ar_user) {
01515         fileUname = getUnameS(fl->cur_ar.ar_user);
01516     } else {
01517         fileUname = getUname(fileUid);
01518     }
01519     if (fl->cur_ar.ar_group) {
01520         fileGname = getGnameS(fl->cur_ar.ar_group);
01521     } else {
01522         fileGname = getGname(fileGid);
01523     }
01524         
01525 #if 0   /* XXX this looks dumb to me */
01526     if (! (fileUname && fileGname)) {
01527         rpmError(RPMERR_BADSPEC, _("Bad owner/group: %s\n"), diskName);
01528         fl->processingFailed = 1;
01529         return RPMERR_BADSPEC;
01530     }
01531 #else
01532     /* Default user/group to builder's user/group */
01533     if (fileUname == NULL)
01534         fileUname = getUname(getuid());
01535     if (fileGname == NULL)
01536         fileGname = getGname(getgid());
01537 #endif
01538     
01539     rpmMessage(RPMMESS_DEBUG, _("File %4d: %07o %s.%s\t %s\n"), fl->fileCount,
01540         (unsigned)fileMode, fileUname, fileGname, fileURL);
01541 
01542     /* Add to the file list */
01543     if (fl->fileListRecsUsed == fl->fileListRecsAlloced) {
01544         fl->fileListRecsAlloced += 128;
01545         fl->fileList = xrealloc(fl->fileList,
01546                         fl->fileListRecsAlloced * sizeof(*(fl->fileList)));
01547     }
01548             
01549     {   FileListRec flp = &fl->fileList[fl->fileListRecsUsed];
01550         int i;
01551 
01552         flp->fl_st = *statp;    /* structure assignment */
01553         flp->fl_mode = fileMode;
01554         flp->fl_uid = fileUid;
01555         flp->fl_gid = fileGid;
01556 
01557         flp->fileURL = xstrdup(fileURL);
01558         flp->diskURL = xstrdup(diskURL);
01559         flp->uname = fileUname;
01560         flp->gname = fileGname;
01561 
01562         if (fl->currentLangs && fl->nLangs > 0) {
01563             char * ncl;
01564             size_t nl = 0;
01565             
01566             for (i = 0; i < fl->nLangs; i++)
01567                 nl += strlen(fl->currentLangs[i]) + 1;
01568 
01569             flp->langs = ncl = xmalloc(nl);
01570             for (i = 0; i < fl->nLangs; i++) {
01571                 const char *ocl;
01572                 if (i)  *ncl++ = '|';
01573                 for (ocl = fl->currentLangs[i]; *ocl != '\0'; ocl++)
01574                         *ncl++ = *ocl;
01575                 *ncl = '\0';
01576             }
01577         } else if (! parseForRegexLang(fileURL, &lang)) {
01578             flp->langs = xstrdup(lang);
01579         } else {
01580             flp->langs = xstrdup("");
01581         }
01582 
01583         flp->flags = fl->currentFlags;
01584         flp->specdFlags = fl->currentSpecdFlags;
01585         flp->verifyFlags = fl->currentVerifyFlags;
01586 
01587         if (multiLib
01588             && !(flp->flags & RPMFILE_MULTILIB_MASK)
01589             && !parseForRegexMultiLib(fileURL))
01590             flp->flags |= multiLib;
01591 
01592 
01593         /* Hard links need be counted only once. */
01594         if (S_ISREG(flp->fl_mode) && flp->fl_nlink > 1) {
01595             FileListRec ilp;
01596             for (i = 0;  i < fl->fileListRecsUsed; i++) {
01597                 ilp = fl->fileList + i;
01598                 if (!S_ISREG(ilp->fl_mode))
01599                     continue;
01600                 if (flp->fl_nlink != ilp->fl_nlink)
01601                     continue;
01602                 if (flp->fl_ino != ilp->fl_ino)
01603                     continue;
01604                 if (flp->fl_dev != ilp->fl_dev)
01605                     continue;
01606                 break;
01607             }
01608         } else
01609             i = fl->fileListRecsUsed;
01610 
01611         if (S_ISREG(flp->fl_mode) && i >= fl->fileListRecsUsed)
01612             fl->totalFileSize += flp->fl_size;
01613     }
01614 
01615     fl->fileListRecsUsed++;
01616     fl->fileCount++;
01617 
01618     return 0;
01619 }
01620 
01624 static int processBinaryFile(/*@unused@*/ Package pkg, FileList fl,
01625                 const char * fileURL)
01626         /*@modifies fl->processingFailed,
01627                 fl->fileList, fl->fileListRecsAlloced, fl->fileListRecsUsed,
01628                 fl->totalFileSize, fl->fileCount, fl->inFtw, fl->isDir @*/
01629 {
01630     int doGlob;
01631     const char *diskURL = NULL;
01632     int rc = 0;
01633     
01634     doGlob = myGlobPatternP(fileURL);
01635 
01636     /* Check that file starts with leading "/" */
01637     {   const char * fileName;
01638         (void) urlPath(fileURL, &fileName);
01639         if (*fileName != '/') {
01640             rpmError(RPMERR_BADSPEC, _("File needs leading \"/\": %s\n"),
01641                         fileName);
01642             rc = 1;
01643             goto exit;
01644         }
01645     }
01646     
01647     /* Copy file name or glob pattern removing multiple "/" chars. */
01648     /*
01649      * Note: rpmGetPath should guarantee a "canonical" path. That means
01650      * that the following pathologies should be weeded out:
01651      *          //bin//sh
01652      *          //usr//bin/
01653      *          /.././../usr/../bin//./sh
01654      */
01655     diskURL = rpmGenPath(fl->buildRootURL, NULL, fileURL);
01656 
01657     if (doGlob) {
01658         const char ** argv = NULL;
01659         int argc = 0;
01660         int i;
01661 
01662         if (fl->noGlob) {
01663             rpmError(RPMERR_BADSPEC, _("Glob not permitted: %s\n"),
01664                         diskURL);
01665             rc = 1;
01666             goto exit;
01667         }
01668 
01669         rc = rpmGlob(diskURL, &argc, &argv);
01670         if (rc == 0 && argc >= 1 && !myGlobPatternP(argv[0])) {
01671             for (i = 0; i < argc; i++) {
01672                 rc = addFile(fl, argv[i], NULL);
01673                 argv[i] = _free(argv[i]);
01674             }
01675             argv = _free(argv);
01676         } else {
01677             rpmError(RPMERR_BADSPEC, _("File not found by glob: %s\n"),
01678                         diskURL);
01679             rc = 1;
01680         }
01681     } else {
01682         rc = addFile(fl, diskURL, NULL);
01683     }
01684 
01685 exit:
01686     diskURL = _free(diskURL);
01687     if (rc)
01688         fl->processingFailed = 1;
01689     return rc;
01690 }
01691 
01694 static int processPackageFiles(Spec spec, Package pkg,
01695                                int installSpecialDoc, int test)
01696         /*@modifies spec->macros,
01697                 pkg->cpioList, pkg->fileList, pkg->specialDoc, pkg->header */
01698 {
01699     HGE_t hge = (HGE_t)headerGetEntryMinMemory;
01700     struct FileList_s fl;
01701     char *s, **files, **fp;
01702     const char *fileName;
01703     char buf[BUFSIZ];
01704     struct AttrRec_s arbuf;
01705     AttrRec specialDocAttrRec = &arbuf;
01706     char *specialDoc = NULL;
01707 
01708 #ifdef MULTILIB
01709     multiLib = rpmExpandNumeric("%{_multilibno}");
01710     if (multiLib)
01711         multiLib = RPMFILE_MULTILIB(multiLib);
01712 #endif /* MULTILIB */
01713     
01714     nullAttrRec(specialDocAttrRec);
01715     pkg->cpioList = NULL;
01716 
01717     if (pkg->fileFile) {
01718         const char *ffn;
01719         FILE * f;
01720         FD_t fd;
01721 
01722         /* XXX W2DO? urlPath might be useful here. */
01723         if (*pkg->fileFile == '/') {
01724             ffn = rpmGetPath(pkg->fileFile, NULL);
01725         } else {
01726             /* XXX FIXME: add %{_buildsubdir} */
01727             ffn = rpmGetPath("%{_builddir}/",
01728                 (spec->buildSubdir ? spec->buildSubdir : "") ,
01729                 "/", pkg->fileFile, NULL);
01730         }
01731         fd = Fopen(ffn, "r.fpio");
01732 
01733         if (fd == NULL || Ferror(fd)) {
01734             rpmError(RPMERR_BADFILENAME,
01735                 _("Could not open %%files file %s: %s\n"),
01736                 ffn, Fstrerror(fd));
01737             return RPMERR_BADFILENAME;
01738         }
01739         ffn = _free(ffn);
01740 
01741         /*@+voidabstract@*/ f = fdGetFp(fd); /*@=voidabstract@*/
01742         if (f != NULL)
01743         while (fgets(buf, sizeof(buf), f)) {
01744             handleComments(buf);
01745             if (expandMacros(spec, spec->macros, buf, sizeof(buf))) {
01746                 rpmError(RPMERR_BADSPEC, _("line: %s\n"), buf);
01747                 return RPMERR_BADSPEC;
01748             }
01749             appendStringBuf(pkg->fileList, buf);
01750         }
01751         (void) Fclose(fd);
01752     }
01753     
01754     /* Init the file list structure */
01755     memset(&fl, 0, sizeof(fl));
01756 
01757     /* XXX spec->buildRootURL == NULL, then xstrdup("") is returned */
01758     fl.buildRootURL = rpmGenPath(spec->rootURL, spec->buildRootURL, NULL);
01759 
01760     if (hge(pkg->header, RPMTAG_DEFAULTPREFIX, NULL, (void **)&fl.prefix, NULL))
01761         fl.prefix = xstrdup(fl.prefix);
01762     else
01763         fl.prefix = NULL;
01764 
01765     fl.fileCount = 0;
01766     fl.totalFileSize = 0;
01767     fl.processingFailed = 0;
01768 
01769     fl.passedSpecialDoc = 0;
01770     fl.isSpecialDoc = 0;
01771 
01772     fl.isDir = 0;
01773     fl.inFtw = 0;
01774     fl.currentFlags = 0;
01775     fl.currentVerifyFlags = 0;
01776     
01777     fl.noGlob = 0;
01778     fl.devtype = 0;
01779     fl.devmajor = 0;
01780     fl.devminor = 0;
01781 
01782     nullAttrRec(&fl.cur_ar);
01783     nullAttrRec(&fl.def_ar);
01784 
01785     fl.defVerifyFlags = RPMVERIFY_ALL;
01786     fl.nLangs = 0;
01787     fl.currentLangs = NULL;
01788 
01789     fl.currentSpecdFlags = 0;
01790     fl.defSpecdFlags = 0;
01791 
01792     fl.docDirCount = 0;
01793     fl.docDirs[fl.docDirCount++] = xstrdup("/usr/doc");
01794     fl.docDirs[fl.docDirCount++] = xstrdup("/usr/man");
01795     fl.docDirs[fl.docDirCount++] = xstrdup("/usr/info");
01796     fl.docDirs[fl.docDirCount++] = xstrdup("/usr/X11R6/man");
01797     fl.docDirs[fl.docDirCount++] = xstrdup("/usr/share/doc");
01798     fl.docDirs[fl.docDirCount++] = xstrdup("/usr/share/man");
01799     fl.docDirs[fl.docDirCount++] = xstrdup("/usr/share/info");
01800     fl.docDirs[fl.docDirCount++] = rpmGetPath("%{_docdir}", NULL);
01801     fl.docDirs[fl.docDirCount++] = rpmGetPath("%{_mandir}", NULL);
01802     fl.docDirs[fl.docDirCount++] = rpmGetPath("%{_infodir}", NULL);
01803     
01804     fl.fileList = NULL;
01805     fl.fileListRecsAlloced = 0;
01806     fl.fileListRecsUsed = 0;
01807 
01808     s = getStringBuf(pkg->fileList);
01809     files = splitString(s, strlen(s), '\n');
01810 
01811     for (fp = files; *fp != NULL; fp++) {
01812         s = *fp;
01813         SKIPSPACE(s);
01814         if (*s == '\0')
01815             continue;
01816         fileName = NULL;
01817         /*@-nullpass@*/ /* LCL: buf is NULL ?!? */
01818         strcpy(buf, s);
01819         /*@=nullpass@*/
01820         
01821         /* Reset for a new line in %files */
01822         fl.isDir = 0;
01823         fl.inFtw = 0;
01824         fl.currentFlags = 0;
01825         /* turn explicit flags into %def'd ones (gosh this is hacky...) */
01826         fl.currentSpecdFlags = ((unsigned)fl.defSpecdFlags) >> 8;
01827         fl.currentVerifyFlags = fl.defVerifyFlags;
01828         fl.isSpecialDoc = 0;
01829 
01830         fl.noGlob = 0;
01831         fl.devtype = 0;
01832         fl.devmajor = 0;
01833         fl.devminor = 0;
01834 
01835         /* XXX should reset to %deflang value */
01836         if (fl.currentLangs) {
01837             int i;
01838             for (i = 0; i < fl.nLangs; i++)
01839                 /*@-unqualifiedtrans@*/
01840                 fl.currentLangs[i] = _free(fl.currentLangs[i]);
01841                 /*@=unqualifiedtrans@*/
01842             fl.currentLangs = _free(fl.currentLangs);
01843         }
01844         fl.nLangs = 0;
01845 
01846         dupAttrRec(&fl.def_ar, &fl.cur_ar);
01847 
01848         /*@-nullpass@*/ /* LCL: buf is NULL ?!? */
01849         if (parseForVerify(buf, &fl))
01850             continue;
01851         if (parseForAttr(buf, &fl))
01852             continue;
01853         if (parseForDev(buf, &fl))
01854             continue;
01855         if (parseForConfig(buf, &fl))
01856             continue;
01857         if (parseForLang(buf, &fl))
01858             continue;
01859         /*@-nullstate@*/        /* FIX: pkg->fileFile might be NULL */
01860         if (parseForSimple(spec, pkg, buf, &fl, &fileName))
01861         /*@=nullstate@*/
01862             continue;
01863         /*@=nullpass@*/
01864         if (fileName == NULL)
01865             continue;
01866 
01867         if (fl.isSpecialDoc) {
01868             /* Save this stuff for last */
01869             specialDoc = _free(specialDoc);
01870             specialDoc = xstrdup(fileName);
01871             dupAttrRec(&fl.cur_ar, specialDocAttrRec);
01872         } else {
01873             /*@-nullstate@*/    /* FIX: pkg->fileFile might be NULL */
01874             (void) processBinaryFile(pkg, &fl, fileName);
01875             /*@=nullstate@*/
01876         }
01877     }
01878 
01879     /* Now process special doc, if there is one */
01880     if (specialDoc) {
01881         if (installSpecialDoc) {
01882             (void) doScript(spec, RPMBUILD_STRINGBUF, "%doc", pkg->specialDoc, test);
01883         }
01884 
01885         /* Reset for %doc */
01886         fl.isDir = 0;
01887         fl.inFtw = 0;
01888         fl.currentFlags = 0;
01889         fl.currentVerifyFlags = 0;
01890 
01891         fl.noGlob = 0;
01892         fl.devtype = 0;
01893         fl.devmajor = 0;
01894         fl.devminor = 0;
01895 
01896         /* XXX should reset to %deflang value */
01897         if (fl.currentLangs) {
01898             int i;
01899             for (i = 0; i < fl.nLangs; i++)
01900                 /*@-unqualifiedtrans@*/
01901                 fl.currentLangs[i] = _free(fl.currentLangs[i]);
01902                 /*@=unqualifiedtrans@*/
01903             fl.currentLangs = _free(fl.currentLangs);
01904         }
01905         fl.nLangs = 0;
01906 
01907         dupAttrRec(specialDocAttrRec, &fl.cur_ar);
01908         freeAttrRec(specialDocAttrRec);
01909 
01910         /*@-nullstate@*/        /* FIX: pkg->fileFile might be NULL */
01911         (void) processBinaryFile(pkg, &fl, specialDoc);
01912         /*@=nullstate@*/
01913 
01914         specialDoc = _free(specialDoc);
01915     }
01916     
01917     freeSplitString(files);
01918 
01919     if (fl.processingFailed)
01920         goto exit;
01921 
01922     /* Verify that file attributes scope over hardlinks correctly. */
01923     checkHardLinks(&fl);
01924 
01925     genCpioListAndHeader(&fl, (TFI_t *)&pkg->cpioList, pkg->header, 0);
01926 
01927     if (spec->timeCheck)
01928         timeCheck(spec->timeCheck, pkg->header);
01929     
01930 exit:
01931     fl.buildRootURL = _free(fl.buildRootURL);
01932     fl.prefix = _free(fl.prefix);
01933 
01934     freeAttrRec(&fl.cur_ar);
01935     freeAttrRec(&fl.def_ar);
01936 
01937     if (fl.currentLangs) {
01938         int i;
01939         for (i = 0; i < fl.nLangs; i++)
01940             /*@-unqualifiedtrans@*/
01941             fl.currentLangs[i] = _free(fl.currentLangs[i]);
01942             /*@=unqualifiedtrans@*/
01943         fl.currentLangs = _free(fl.currentLangs);
01944     }
01945 
01946     fl.fileList = freeFileList(fl.fileList, fl.fileListRecsUsed);
01947     while (fl.docDirCount--)
01948         fl.docDirs[fl.docDirCount] = _free(fl.docDirs[fl.docDirCount]);
01949     return fl.processingFailed;
01950 }
01951 
01952 void initSourceHeader(Spec spec)
01953 {
01954     HeaderIterator hi;
01955     int_32 tag, type, count;
01956     const void * ptr;
01957 
01958     spec->sourceHeader = headerNew();
01959     /* Only specific tags are added to the source package header */
01960     for (hi = headerInitIterator(spec->packages->header);
01961         headerNextIterator(hi, &tag, &type, &ptr, &count);
01962         ptr = headerFreeData(ptr, type))
01963     {
01964         switch (tag) {
01965         case RPMTAG_NAME:
01966         case RPMTAG_VERSION:
01967         case RPMTAG_RELEASE:
01968         case RPMTAG_EPOCH:
01969         case RPMTAG_SUMMARY:
01970         case RPMTAG_DESCRIPTION:
01971         case RPMTAG_PACKAGER:
01972         case RPMTAG_DISTRIBUTION:
01973         case RPMTAG_DISTURL:
01974         case RPMTAG_VENDOR:
01975         case RPMTAG_LICENSE:
01976         case RPMTAG_GROUP:
01977         case RPMTAG_OS:
01978         case RPMTAG_ARCH:
01979         case RPMTAG_CHANGELOGTIME:
01980         case RPMTAG_CHANGELOGNAME:
01981         case RPMTAG_CHANGELOGTEXT:
01982         case RPMTAG_URL:
01983         case HEADER_I18NTABLE:
01984             if (ptr)
01985                 (void)headerAddEntry(spec->sourceHeader, tag, type, ptr, count);
01986             break;
01987         default:
01988             /* do not copy */
01989             break;
01990         }
01991     }
01992     hi = headerFreeIterator(hi);
01993 
01994     /* Add the build restrictions */
01995     for (hi = headerInitIterator(spec->buildRestrictions);
01996         headerNextIterator(hi, &tag, &type, &ptr, &count);
01997         ptr = headerFreeData(ptr, type))
01998     {
01999         if (ptr)
02000             (void) headerAddEntry(spec->sourceHeader, tag, type, ptr, count);
02001     }
02002     hi = headerFreeIterator(hi);
02003 
02004     if (spec->BANames && spec->BACount > 0) {
02005         (void) headerAddEntry(spec->sourceHeader, RPMTAG_BUILDARCHS,
02006                        RPM_STRING_ARRAY_TYPE,
02007                        spec->BANames, spec->BACount);
02008     }
02009 }
02010 
02011 int processSourceFiles(Spec spec)
02012 {
02013     struct Source *srcPtr;
02014     StringBuf sourceFiles;
02015     int x, isSpec = 1;
02016     struct FileList_s fl;
02017     char *s, **files, **fp;
02018     Package pkg;
02019 
02020     sourceFiles = newStringBuf();
02021 
02022     /* XXX
02023      * XXX This is where the source header for noarch packages needs
02024      * XXX to be initialized.
02025      */
02026     if (spec->sourceHeader == NULL)
02027         initSourceHeader(spec);
02028 
02029     /* Construct the file list and source entries */
02030     appendLineStringBuf(sourceFiles, spec->specFile);
02031     if (spec->sourceHeader != NULL)
02032     for (srcPtr = spec->sources; srcPtr != NULL; srcPtr = srcPtr->next) {
02033         if (srcPtr->flags & RPMBUILD_ISSOURCE) {
02034             (void) headerAddOrAppendEntry(spec->sourceHeader, RPMTAG_SOURCE,
02035                                    RPM_STRING_ARRAY_TYPE, &srcPtr->source, 1);
02036             if (srcPtr->flags & RPMBUILD_ISNO) {
02037                 (void) headerAddOrAppendEntry(spec->sourceHeader, RPMTAG_NOSOURCE,
02038                                        RPM_INT32_TYPE, &srcPtr->num, 1);
02039             }
02040         }
02041         if (srcPtr->flags & RPMBUILD_ISPATCH) {
02042             (void) headerAddOrAppendEntry(spec->sourceHeader, RPMTAG_PATCH,
02043                                    RPM_STRING_ARRAY_TYPE, &srcPtr->source, 1);
02044             if (srcPtr->flags & RPMBUILD_ISNO) {
02045                 (void) headerAddOrAppendEntry(spec->sourceHeader, RPMTAG_NOPATCH,
02046                                        RPM_INT32_TYPE, &srcPtr->num, 1);
02047             }
02048         }
02049 
02050       { const char * sfn;
02051         sfn = rpmGetPath( ((srcPtr->flags & RPMBUILD_ISNO) ? "!" : ""),
02052                 "%{_sourcedir}/", srcPtr->source, NULL);
02053         appendLineStringBuf(sourceFiles, sfn);
02054         sfn = _free(sfn);
02055       }
02056     }
02057 
02058     for (pkg = spec->packages; pkg != NULL; pkg = pkg->next) {
02059         for (srcPtr = pkg->icon; srcPtr != NULL; srcPtr = srcPtr->next) {
02060             const char * sfn;
02061             sfn = rpmGetPath( ((srcPtr->flags & RPMBUILD_ISNO) ? "!" : ""),
02062                 "%{_sourcedir}/", srcPtr->source, NULL);
02063             appendLineStringBuf(sourceFiles, sfn);
02064             sfn = _free(sfn);
02065         }
02066     }
02067 
02068     spec->sourceCpioList = NULL;
02069 
02070     fl.fileList = xcalloc((spec->numSources + 1), sizeof(*fl.fileList));
02071     fl.processingFailed = 0;
02072     fl.fileListRecsUsed = 0;
02073     fl.totalFileSize = 0;
02074     fl.prefix = NULL;
02075     fl.buildRootURL = NULL;
02076 
02077     s = getStringBuf(sourceFiles);
02078     files = splitString(s, strlen(s), '\n');
02079 
02080     /* The first source file is the spec file */
02081     x = 0;
02082     for (fp = files; *fp != NULL; fp++) {
02083         const char * diskURL, *diskPath;
02084         FileListRec flp;
02085 
02086         diskURL = *fp;
02087         SKIPSPACE(diskURL);
02088         if (! *diskURL)
02089             continue;
02090 
02091         flp = &fl.fileList[x];
02092 
02093         flp->flags = isSpec ? RPMFILE_SPECFILE : 0;
02094         /* files with leading ! are no source files */
02095         if (*diskURL == '!') {
02096             flp->flags |= RPMFILE_GHOST;
02097             diskURL++;
02098         }
02099 
02100         (void) urlPath(diskURL, &diskPath);
02101 
02102         flp->diskURL = xstrdup(diskURL);
02103         diskPath = strrchr(diskPath, '/');
02104         if (diskPath)
02105             diskPath++;
02106         else
02107             diskPath = diskURL;
02108 
02109         flp->fileURL = xstrdup(diskPath);
02110         flp->verifyFlags = RPMVERIFY_ALL;
02111 
02112         if (Stat(diskURL, &flp->fl_st)) {
02113             rpmError(RPMERR_BADSPEC, _("Bad file: %s: %s\n"),
02114                 diskURL, strerror(errno));
02115             fl.processingFailed = 1;
02116         }
02117 
02118         flp->uname = getUname(flp->fl_uid);
02119         flp->gname = getGname(flp->fl_gid);
02120         flp->langs = xstrdup("");
02121         
02122         fl.totalFileSize += flp->fl_size;
02123         
02124         if (! (flp->uname && flp->gname)) {
02125             rpmError(RPMERR_BADSPEC, _("Bad owner/group: %s\n"), diskURL);
02126             fl.processingFailed = 1;
02127         }
02128 
02129         isSpec = 0;
02130         x++;
02131     }
02132     fl.fileListRecsUsed = x;
02133     freeSplitString(files);
02134 
02135     if (! fl.processingFailed) {
02136         if (spec->sourceHeader != NULL)
02137             genCpioListAndHeader(&fl, (TFI_t *)&spec->sourceCpioList,
02138                         spec->sourceHeader, 1);
02139     }
02140 
02141     sourceFiles = freeStringBuf(sourceFiles);
02142     fl.fileList = freeFileList(fl.fileList, fl.fileListRecsUsed);
02143     return fl.processingFailed;
02144 }
02145 
02148 static StringBuf getOutputFrom(char * dir, char * argv[],
02149                         const char * writePtr, int writeBytesLeft,
02150                         int failNonZero)
02151         /*@*/
02152 {
02153     int progPID;
02154     int toProg[2];
02155     int fromProg[2];
02156     int status;
02157     void *oldhandler;
02158     StringBuf readBuff;
02159     int done;
02160 
02161     oldhandler = signal(SIGPIPE, SIG_IGN);
02162 
02163     toProg[0] = toProg[1] = 0;
02164     (void) pipe(toProg);
02165     fromProg[0] = fromProg[1] = 0;
02166     (void) pipe(fromProg);
02167     
02168     if (!(progPID = fork())) {
02169         (void) close(toProg[1]);
02170         (void) close(fromProg[0]);
02171         
02172         (void) dup2(toProg[0], STDIN_FILENO);   /* Make stdin the in pipe */
02173         (void) dup2(fromProg[1], STDOUT_FILENO); /* Make stdout the out pipe */
02174 
02175         (void) close(toProg[0]);
02176         (void) close(fromProg[1]);
02177 
02178         if (dir) {
02179             (void) chdir(dir);
02180         }
02181         
02182         (void) execvp(argv[0], argv);
02183         /* XXX this error message is probably not seen. */
02184         rpmError(RPMERR_EXEC, _("Couldn't exec %s: %s\n"),
02185                 argv[0], strerror(errno));
02186         _exit(RPMERR_EXEC);
02187     }
02188     if (progPID < 0) {
02189         rpmError(RPMERR_FORK, _("Couldn't fork %s: %s\n"),
02190                 argv[0], strerror(errno));
02191         return NULL;
02192     }
02193 
02194     (void) close(toProg[0]);
02195     (void) close(fromProg[1]);
02196 
02197     /* Do not block reading or writing from/to prog. */
02198     (void) fcntl(fromProg[0], F_SETFL, O_NONBLOCK);
02199     (void) fcntl(toProg[1], F_SETFL, O_NONBLOCK);
02200     
02201     readBuff = newStringBuf();
02202 
02203     do {
02204         fd_set ibits, obits;
02205         struct timeval tv;
02206         int nfd, nbw, nbr;
02207         int rc;
02208 
02209         done = 0;
02210 top:
02211         /* XXX the select is mainly a timer since all I/O is non-blocking */
02212         FD_ZERO(&ibits);
02213         FD_ZERO(&obits);
02214         if (fromProg[0] >= 0) {
02215             FD_SET(fromProg[0], &ibits);
02216         }
02217         if (toProg[1] >= 0) {
02218             FD_SET(toProg[1], &obits);
02219         }
02220         tv.tv_sec = 1;
02221         tv.tv_usec = 0;
02222         nfd = ((fromProg[0] > toProg[1]) ? fromProg[0] : toProg[1]);
02223         if ((rc = select(nfd, &ibits, &obits, NULL, &tv)) < 0) {
02224             if (errno == EINTR)
02225                 goto top;
02226             break;
02227         }
02228 
02229         /* Write any data to program */
02230         if (toProg[1] >= 0 && FD_ISSET(toProg[1], &obits)) {
02231           if (writeBytesLeft) {
02232             if ((nbw = write(toProg[1], writePtr,
02233                     (1024<writeBytesLeft) ? 1024 : writeBytesLeft)) < 0) {
02234                 if (errno != EAGAIN) {
02235                     perror("getOutputFrom()");
02236                     exit(EXIT_FAILURE);
02237                 }
02238                 nbw = 0;
02239             }
02240             writeBytesLeft -= nbw;
02241             writePtr += nbw;
02242           } else if (toProg[1] >= 0) {  /* close write fd */
02243             (void) close(toProg[1]);
02244             toProg[1] = -1;
02245           }
02246         }
02247         
02248         /* Read any data from prog */
02249         {   char buf[BUFSIZ+1];
02250             while ((nbr = read(fromProg[0], buf, sizeof(buf)-1)) > 0) {
02251                 buf[nbr] = '\0';
02252                 appendStringBuf(readBuff, buf);
02253             }
02254         }
02255 
02256         /* terminate on (non-blocking) EOF or error */
02257         done = (nbr == 0 || (nbr < 0 && errno != EAGAIN));
02258 
02259     } while (!done);
02260 
02261     /* Clean up */
02262     if (toProg[1] >= 0)
02263         (void) close(toProg[1]);
02264     if (fromProg[0] >= 0)
02265         (void) close(fromProg[0]);
02266     (void) signal(SIGPIPE, oldhandler);
02267 
02268     /* Collect status from prog */
02269     (void)waitpid(progPID, &status, 0);
02270     if (failNonZero && (!WIFEXITED(status) || WEXITSTATUS(status))) {
02271         rpmError(RPMERR_EXEC, _("%s failed\n"), argv[0]);
02272         return NULL;
02273     }
02274     if (writeBytesLeft) {
02275         rpmError(RPMERR_EXEC, _("failed to write all data to %s\n"), argv[0]);
02276         return NULL;
02277     }
02278     return readBuff;
02279 }
02280 
02283 typedef struct {
02284 /*@observer@*/ /*@null@*/ const char * msg;
02285 /*@observer@*/ const char * argv[4];
02286     rpmTag ntag;
02287     rpmTag vtag;
02288     rpmTag ftag;
02289     int mask;
02290     int xor;
02291 } DepMsg_t;
02292 
02295 /*@-exportlocal -exportheadervar@*/
02296 DepMsg_t depMsgs[] = {
02297   { "Provides",         { "%{__find_provides}", NULL, NULL, NULL },
02298         RPMTAG_PROVIDENAME, RPMTAG_PROVIDEVERSION, RPMTAG_PROVIDEFLAGS,
02299         0, -1 },
02300   { "PreReq",           { NULL, NULL, NULL, NULL },
02301         RPMTAG_REQUIRENAME, RPMTAG_REQUIREVERSION, RPMTAG_REQUIREFLAGS,
02302         RPMSENSE_PREREQ, 0 },
02303   { "Requires(interp)", { NULL, "interp", NULL, NULL },
02304         -1, -1, RPMTAG_REQUIREFLAGS,
02305         _notpre(RPMSENSE_INTERP), 0 },
02306   { "Requires(rpmlib)", { NULL, "rpmlib", NULL, NULL },
02307         -1, -1, RPMTAG_REQUIREFLAGS,
02308         _notpre(RPMSENSE_RPMLIB), 0 },
02309   { "Requires(verify)", { NULL, "verify", NULL, NULL },
02310         -1, -1, RPMTAG_REQUIREFLAGS,
02311         RPMSENSE_SCRIPT_VERIFY, 0 },
02312   { "Requires(pre)",    { NULL, "pre", NULL, NULL },
02313         -1, -1, RPMTAG_REQUIREFLAGS,
02314         _notpre(RPMSENSE_SCRIPT_PRE), 0 },
02315   { "Requires(post)",   { NULL, "post", NULL, NULL },
02316         -1, -1, RPMTAG_REQUIREFLAGS,
02317         _notpre(RPMSENSE_SCRIPT_POST), 0 },
02318   { "Requires(preun)",  { NULL, "preun", NULL, NULL },
02319         -1, -1, RPMTAG_REQUIREFLAGS,
02320         _notpre(RPMSENSE_SCRIPT_PREUN), 0 },
02321   { "Requires(postun)", { NULL, "postun", NULL, NULL },
02322         -1, -1, RPMTAG_REQUIREFLAGS,
02323         _notpre(RPMSENSE_SCRIPT_POSTUN), 0 },
02324   { "Requires",         { "%{__find_requires}", NULL, NULL, NULL },
02325         -1, -1, RPMTAG_REQUIREFLAGS,    /* XXX inherit name/version arrays */
02326         RPMSENSE_PREREQ, RPMSENSE_PREREQ },
02327   { "Conflicts",        { "%{__find_conflicts}", NULL, NULL, NULL },
02328         RPMTAG_CONFLICTNAME, RPMTAG_CONFLICTVERSION, RPMTAG_CONFLICTFLAGS,
02329         0, -1 },
02330   { "Obsoletes",        { "%{__find_obsoletes}", NULL, NULL, NULL },
02331         RPMTAG_OBSOLETENAME, RPMTAG_OBSOLETEVERSION, RPMTAG_OBSOLETEFLAGS,
02332         0, -1 },
02333   { NULL,               { NULL, NULL, NULL, NULL },     0, 0, 0, 0, 0 }
02334 };
02335 /*@=exportlocal =exportheadervar@*/
02336 
02339 static int generateDepends(Spec spec, Package pkg, TFI_t cpioList, int multiLib)
02340         /*@modifies cpioList @*/
02341 {
02342     TFI_t fi = cpioList;
02343     StringBuf writeBuf;
02344     int writeBytes;
02345     StringBuf readBuf;
02346     DepMsg_t *dm;
02347     char *myargv[4];
02348     int failnonzero = 0;
02349     int rc = 0;
02350     int i;
02351 
02352     if (!(fi && fi->fc > 0))
02353         return 0;
02354 
02355     if (! (pkg->autoReq || pkg->autoProv))
02356         return 0;
02357     
02358     writeBuf = newStringBuf();
02359     for (i = 0, writeBytes = 0; i < fi->fc; i++) {
02360 
02361         if (fi->fmapflags && multiLib == 2) {
02362             if (!(fi->fmapflags[i] & CPIO_MULTILIB))
02363                 continue;
02364             fi->fmapflags[i] &= ~CPIO_MULTILIB;
02365         }
02366 
02367         appendStringBuf(writeBuf, fi->dnl[fi->dil[i]]);
02368         writeBytes += strlen(fi->dnl[fi->dil[i]]);
02369         appendLineStringBuf(writeBuf, fi->bnl[i]);
02370         writeBytes += strlen(fi->bnl[i]) + 1;
02371     }
02372 
02373     for (dm = depMsgs; dm->msg != NULL; dm++) {
02374         int tag, tagflags;
02375 
02376         tag = (dm->ftag > 0) ? dm->ftag : dm->ntag;
02377         tagflags = 0;
02378 
02379         switch(tag) {
02380         case RPMTAG_PROVIDEFLAGS:
02381             if (!pkg->autoProv)
02382                 continue;
02383             failnonzero = 1;
02384             tagflags = RPMSENSE_FIND_PROVIDES;
02385             break;
02386         case RPMTAG_REQUIREFLAGS:
02387             if (!pkg->autoReq)
02388                 continue;
02389             failnonzero = 0;
02390             tagflags = RPMSENSE_FIND_REQUIRES;
02391             break;
02392         default:
02393             continue;
02394             /*@notreached@*/ break;
02395         }
02396 
02397         /* Get the script name to run */
02398         /*@-nullderef@*/        /* FIX: double indirection. @*/
02399         myargv[0] = (dm->argv[0] ? rpmExpand(dm->argv[0], NULL) : NULL);
02400         /*@=nullderef@*/
02401 
02402         if (!(myargv[0] && *myargv[0] != '%')) {
02403             myargv[0] = _free(myargv[0]);
02404             continue;
02405         }
02406 
02407         rpmMessage(RPMMESS_NORMAL, _("Finding  %s: (using %s)...\n"),
02408                 dm->msg, myargv[0]);
02409 
02410 #if 0
02411         if (*myargv[0] != '/') {        /* XXX FIXME: stat script here */
02412             myargv[0] = _free(myargv[0]);
02413             continue;
02414         }
02415 #endif
02416 
02417         /* Expand rest of script arguments (if any) */
02418         for (i = 1; i < 4; i++) {
02419             /*@-nullderef@*/    /* FIX: double indirection. @*/
02420             myargv[i] = dm->argv[i] ? rpmExpand(dm->argv[i], NULL) : NULL;
02421             /*@=nullderef@*/
02422         }
02423 
02424         readBuf = getOutputFrom(NULL, myargv,
02425                         getStringBuf(writeBuf), writeBytes, failnonzero);
02426 
02427         /* Free expanded args */
02428         for (i = 0; i < 4; i++)
02429             myargv[i] = _free(myargv[i]);
02430 
02431         if (readBuf == NULL) {
02432             rc = RPMERR_EXEC;
02433             rpmError(rc, _("Failed to find %s:\n"), dm->msg);
02434             break;
02435         }
02436 
02437         /* Parse dependencies into header */
02438         tagflags &= ~RPMSENSE_MULTILIB;
02439         if (multiLib > 1)
02440             tagflags |=  RPMSENSE_MULTILIB;
02441         else
02442             tagflags &= ~RPMSENSE_MULTILIB;
02443         rc = parseRCPOT(spec, pkg, getStringBuf(readBuf), tag, 0, tagflags);
02444         readBuf = freeStringBuf(readBuf);
02445 
02446         if (rc) {
02447             rpmError(rc, _("Failed to find %s:\n"), dm->msg);
02448             break;
02449         }
02450     }
02451 
02452     writeBuf = freeStringBuf(writeBuf);
02453     return rc;
02454 }
02455 
02458 static void printDepMsg(DepMsg_t * dm, int count, const char ** names,
02459                 const char ** versions, int *flags)
02460         /*@modifies fileSystem @*/
02461 {
02462     int hasVersions = (versions != NULL);
02463     int hasFlags = (flags != NULL);
02464     int bingo = 0;
02465     int i;
02466 
02467     for (i = 0; i < count; i++, names++, versions++, flags++) {
02468         if (hasFlags && !((*flags & dm->mask) ^ dm->xor))
02469             continue;
02470         if (bingo == 0) {
02471             rpmMessage(RPMMESS_NORMAL, "%s:", (dm->msg ? dm->msg : ""));
02472             bingo = 1;
02473         }
02474         rpmMessage(RPMMESS_NORMAL, " %s", *names);
02475 
02476         if (hasFlags && isDependsMULTILIB(*flags))
02477             rpmMessage(RPMMESS_NORMAL, " (multilib)");
02478 
02479         if (hasVersions && !(*versions != NULL && **versions != '\0'))
02480             continue;
02481         if (!(hasFlags && (*flags && RPMSENSE_SENSEMASK)))
02482             continue;
02483 
02484         rpmMessage(RPMMESS_NORMAL, " ");
02485         if (*flags & RPMSENSE_LESS)
02486             rpmMessage(RPMMESS_NORMAL, "<");
02487         if (*flags & RPMSENSE_GREATER)
02488             rpmMessage(RPMMESS_NORMAL, ">");
02489         if (*flags & RPMSENSE_EQUAL)
02490             rpmMessage(RPMMESS_NORMAL, "=");
02491 
02492         rpmMessage(RPMMESS_NORMAL, " %s", *versions);
02493     }
02494     if (bingo)
02495         rpmMessage(RPMMESS_NORMAL, "\n");
02496 }
02497 
02500 static void printDeps(Header h)
02501         /*@modifies fileSystem @*/
02502 {
02503     HGE_t hge = (HGE_t)headerGetEntryMinMemory;
02504     HFD_t hfd = headerFreeData;
02505     const char ** names = NULL;
02506     rpmTagType dnt = -1;
02507     const char ** versions = NULL;
02508     rpmTagType dvt = -1;
02509     int * flags = NULL;
02510     DepMsg_t * dm;
02511     int count;
02512 
02513     for (dm = depMsgs; dm->msg != NULL; dm++) {
02514         switch (dm->ntag) {
02515         case 0:
02516             names = hfd(names, dnt);
02517             break;
02518         case -1:
02519             break;
02520         default:
02521             names = hfd(names, dnt);
02522             if (!hge(h, dm->ntag, &dnt, (void **) &names, &count))
02523                 continue;
02524             break;
02525         }
02526         switch (dm->vtag) {
02527         case 0:
02528             versions = hfd(versions, dvt);
02529             break;
02530         case -1:
02531             break;
02532         default:
02533             versions = hfd(versions, dvt);
02534             (void) hge(h, dm->vtag, &dvt, (void **) &versions, NULL);
02535             break;
02536         }
02537         switch (dm->ftag) {
02538         case 0:
02539             flags = NULL;
02540             break;
02541         case -1:
02542             break;
02543         default:
02544             (void) hge(h, dm->ftag, NULL, (void **) &flags, NULL);
02545             break;
02546         }
02547         printDepMsg(dm, count, names, versions, flags);
02548     }
02549     names = hfd(names, dnt);
02550     versions = hfd(versions, dvt);
02551 }
02552 
02553 int processBinaryFiles(Spec spec, int installSpecialDoc, int test)
02554 {
02555     Package pkg;
02556     int res = 0;
02557     
02558     for (pkg = spec->packages; pkg != NULL; pkg = pkg->next) {
02559         const char *n, *v, *r;
02560         int rc;
02561 
02562         if (pkg->fileList == NULL)
02563             continue;
02564 
02565         (void) headerNVR(pkg->header, &n, &v, &r);
02566         rpmMessage(RPMMESS_NORMAL, _("Processing files: %s-%s-%s\n"), n, v, r);
02567                    
02568         if ((rc = processPackageFiles(spec, pkg, installSpecialDoc, test)))
02569             res = rc;
02570 
02571     /* XXX This should be added always so that packages look alike.
02572      * XXX However, there is logic in files.c/depends.c that checks for
02573      * XXX existence (rather than value) that will need to change as well.
02574      */
02575         if (headerIsEntry(pkg->header, RPMTAG_MULTILIBS)) {
02576             (void) generateDepends(spec, pkg, pkg->cpioList, 1);
02577             (void) generateDepends(spec, pkg, pkg->cpioList, 2);
02578         } else
02579             (void) generateDepends(spec, pkg, pkg->cpioList, 0);
02580         printDeps(pkg->header);
02581     }
02582 
02583     return res;
02584 }

Generated at Wed Mar 27 03:56:47 2002 for rpm by doxygen1.2.8.1 written by Dimitri van Heesch, © 1997-2001