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@*/