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

Generated on Wed Mar 13 15:34:46 2002 for rpm by doxygen1.2.14 written by Dimitri van Heesch, © 1997-2002