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

Generated on Wed Sep 4 12:49:49 2002 for rpm by doxygen1.2.14 written by Dimitri van Heesch, © 1997-2002