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 
00013 #include <rpmio_internal.h>
00014 #include <fts.h>
00015 
00016 #include <rpmbuild.h>
00017 
00018 #include "cpio.h"
00019 
00020 #include "argv.h"
00021 #include "rpmfc.h"
00022 
00023 #define _RPMFI_INTERNAL
00024 #include "rpmfi.h"
00025 
00026 #include <selinux/selinux.h>
00027 
00028 #define _RPMTE_INTERNAL
00029 #include "rpmte.h"
00030 
00031 #include "buildio.h"
00032 
00033 #include "legacy.h"     /* XXX domd5, expandFileList, compressFileList */
00034 #include "misc.h"
00035 #include "debug.h"
00036 
00037 /*@access Header @*/
00038 /*@access rpmfi @*/
00039 /*@access rpmte @*/
00040 /*@access FD_t @*/
00041 /*@access StringBuf @*/         /* compared with NULL */
00042 
00043 #define SKIPWHITE(_x)   {while(*(_x) && (xisspace(*_x) || *(_x) == ',')) (_x)++;}
00044 #define SKIPNONWHITE(_x){while(*(_x) &&!(xisspace(*_x) || *(_x) == ',')) (_x)++;}
00045 
00046 #define MAXDOCDIR 1024
00047 
00050 typedef enum specdFlags_e {
00051     SPECD_DEFFILEMODE   = (1 << 0),
00052     SPECD_DEFDIRMODE    = (1 << 1),
00053     SPECD_DEFUID        = (1 << 2),
00054     SPECD_DEFGID        = (1 << 3),
00055     SPECD_DEFVERIFY     = (1 << 4),
00056 
00057     SPECD_FILEMODE      = (1 << 8),
00058     SPECD_DIRMODE       = (1 << 9),
00059     SPECD_UID           = (1 << 10),
00060     SPECD_GID           = (1 << 11),
00061     SPECD_VERIFY        = (1 << 12)
00062 } specdFlags;
00063 
00066 typedef struct FileListRec_s {
00067     struct stat fl_st;
00068 #define fl_dev  fl_st.st_dev
00069 #define fl_ino  fl_st.st_ino
00070 #define fl_mode fl_st.st_mode
00071 #define fl_nlink fl_st.st_nlink
00072 #define fl_uid  fl_st.st_uid
00073 #define fl_gid  fl_st.st_gid
00074 #define fl_rdev fl_st.st_rdev
00075 #define fl_size fl_st.st_size
00076 #define fl_mtime fl_st.st_mtime
00077 
00078 /*@only@*/
00079     const char *diskURL;        /* get file from here       */
00080 /*@only@*/
00081     const char *fileURL;        /* filename in cpio archive */
00082 /*@observer@*/
00083     const char *uname;
00084 /*@observer@*/
00085     const char *gname;
00086     unsigned    flags;
00087     specdFlags  specdFlags;     /* which attributes have been explicitly specified. */
00088     unsigned    verifyFlags;
00089 /*@only@*/
00090     const char *langs;          /* XXX locales separated with | */
00091 } * FileListRec;
00092 
00095 typedef struct AttrRec_s {
00096 /*@null@*/
00097     const char *ar_fmodestr;
00098 /*@null@*/
00099     const char *ar_dmodestr;
00100 /*@null@*/
00101     const char *ar_user;
00102 /*@null@*/
00103     const char *ar_group;
00104     mode_t      ar_fmode;
00105     mode_t      ar_dmode;
00106 } * AttrRec;
00107 
00108 /*@-readonlytrans@*/
00109 /*@unchecked@*/ /*@observer@*/
00110 static struct AttrRec_s root_ar = { NULL, NULL, "root", "root", 0, 0 };
00111 /*@=readonlytrans@*/
00112 
00113 /* list of files */
00114 /*@unchecked@*/ /*@only@*/ /*@null@*/
00115 static StringBuf check_fileList = NULL;
00116 
00120 typedef struct FileList_s {
00121 /*@only@*/
00122     const char * buildRootURL;
00123 /*@only@*/
00124     const char * prefix;
00125 
00126     int fileCount;
00127     int totalFileSize;
00128     int processingFailed;
00129 
00130     int passedSpecialDoc;
00131     int isSpecialDoc;
00132 
00133     int noGlob;
00134     unsigned devtype;
00135     unsigned devmajor;
00136     int devminor;
00137     
00138     int isDir;
00139     int inFtw;
00140     int currentFlags;
00141     specdFlags currentSpecdFlags;
00142     int currentVerifyFlags;
00143     struct AttrRec_s cur_ar;
00144     struct AttrRec_s def_ar;
00145     specdFlags defSpecdFlags;
00146     int defVerifyFlags;
00147     int nLangs;
00148 /*@only@*/ /*@null@*/
00149     const char ** currentLangs;
00150 
00151     /* Hard coded limit of MAXDOCDIR docdirs.         */
00152     /* If you break it you are doing something wrong. */
00153     const char * docDirs[MAXDOCDIR];
00154     int docDirCount;
00155     
00156 /*@only@*/
00157     FileListRec fileList;
00158     int fileListRecsAlloced;
00159     int fileListRecsUsed;
00160 } * FileList;
00161 
00164 static void nullAttrRec(/*@out@*/ AttrRec ar)   /*@modifies ar @*/
00165 {
00166     ar->ar_fmodestr = NULL;
00167     ar->ar_dmodestr = NULL;
00168     ar->ar_user = NULL;
00169     ar->ar_group = NULL;
00170     ar->ar_fmode = 0;
00171     ar->ar_dmode = 0;
00172 }
00173 
00176 static void freeAttrRec(AttrRec ar)     /*@modifies ar @*/
00177 {
00178     ar->ar_fmodestr = _free(ar->ar_fmodestr);
00179     ar->ar_dmodestr = _free(ar->ar_dmodestr);
00180     ar->ar_user = _free(ar->ar_user);
00181     ar->ar_group = _free(ar->ar_group);
00182     /* XXX doesn't free ar (yet) */
00183     /*@-nullstate@*/
00184     return;
00185     /*@=nullstate@*/
00186 }
00187 
00190 static void dupAttrRec(const AttrRec oar, /*@in@*/ /*@out@*/ AttrRec nar)
00191         /*@modifies nar @*/
00192 {
00193     if (oar == nar)
00194         return;
00195     freeAttrRec(nar);
00196     nar->ar_fmodestr = (oar->ar_fmodestr ? xstrdup(oar->ar_fmodestr) : NULL);
00197     nar->ar_dmodestr = (oar->ar_dmodestr ? xstrdup(oar->ar_dmodestr) : NULL);
00198     nar->ar_user = (oar->ar_user ? xstrdup(oar->ar_user) : NULL);
00199     nar->ar_group = (oar->ar_group ? xstrdup(oar->ar_group) : NULL);
00200     nar->ar_fmode = oar->ar_fmode;
00201     nar->ar_dmode = oar->ar_dmode;
00202 }
00203 
00204 #if 0
00205 
00207 static void dumpAttrRec(const char * msg, AttrRec ar)
00208         /*@globals fileSystem@*/
00209         /*@modifies fileSystem @*/
00210 {
00211     if (msg)
00212         fprintf(stderr, "%s:\t", msg);
00213     fprintf(stderr, "(%s, %s, %s, %s)\n",
00214         ar->ar_fmodestr,
00215         ar->ar_user,
00216         ar->ar_group,
00217         ar->ar_dmodestr);
00218 }
00219 #endif
00220 
00225 /*@-boundswrite@*/
00226 /*@null@*/
00227 static char *strtokWithQuotes(/*@null@*/ 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     if (s == NULL)
00236         return NULL;
00237 
00238     /* Skip leading delimiters */
00239     s += strspn(s, delim);
00240     if (*s == '\0')
00241         return NULL;
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 not;
00300     int flag;
00301 } VFA_t;
00302 
00305 /*@-exportlocal -exportheadervar@*/
00306 /*@unchecked@*/
00307 VFA_t verifyAttrs[] = {
00308     { "md5",    0,      RPMVERIFY_MD5 },
00309     { "size",   0,      RPMVERIFY_FILESIZE },
00310     { "link",   0,      RPMVERIFY_LINKTO },
00311     { "user",   0,      RPMVERIFY_USER },
00312     { "group",  0,      RPMVERIFY_GROUP },
00313     { "mtime",  0,      RPMVERIFY_MTIME },
00314     { "mode",   0,      RPMVERIFY_MODE },
00315     { "rdev",   0,      RPMVERIFY_RDEV },
00316     { NULL, 0,  0 }
00317 };
00318 /*@=exportlocal =exportheadervar@*/
00319 
00326 /*@-boundswrite@*/
00327 static int parseForVerify(char * buf, FileList fl)
00328         /*@modifies buf, fl->processingFailed,
00329                 fl->currentVerifyFlags, fl->defVerifyFlags,
00330                 fl->currentSpecdFlags, fl->defSpecdFlags @*/
00331 {
00332     char *p, *pe, *q;
00333     const char *name;
00334     int *resultVerify;
00335     int negated;
00336     int verifyFlags;
00337     specdFlags * specdFlags;
00338 
00339     if ((p = strstr(buf, (name = "%verify"))) != NULL) {
00340         resultVerify = &(fl->currentVerifyFlags);
00341         specdFlags = &fl->currentSpecdFlags;
00342     } else if ((p = strstr(buf, (name = "%defverify"))) != NULL) {
00343         resultVerify = &(fl->defVerifyFlags);
00344         specdFlags = &fl->defSpecdFlags;
00345     } else
00346         return 0;
00347 
00348     for (pe = p; (pe-p) < strlen(name); pe++)
00349         *pe = ' ';
00350 
00351     SKIPSPACE(pe);
00352 
00353     if (*pe != '(') {
00354         rpmError(RPMERR_BADSPEC, _("Missing '(' in %s %s\n"), name, pe);
00355         fl->processingFailed = 1;
00356         return RPMERR_BADSPEC;
00357     }
00358 
00359     /* Bracket %*verify args */
00360     *pe++ = ' ';
00361     for (p = pe; *pe && *pe != ')'; pe++)
00362         {};
00363 
00364     if (*pe == '\0') {
00365         rpmError(RPMERR_BADSPEC, _("Missing ')' in %s(%s\n"), name, p);
00366         fl->processingFailed = 1;
00367         return RPMERR_BADSPEC;
00368     }
00369 
00370     /* Localize. Erase parsed string */
00371     q = alloca((pe-p) + 1);
00372     strncpy(q, p, pe-p);
00373     q[pe-p] = '\0';
00374     while (p <= pe)
00375         *p++ = ' ';
00376 
00377     negated = 0;
00378     verifyFlags = RPMVERIFY_NONE;
00379 
00380     for (p = q; *p != '\0'; p = pe) {
00381         SKIPWHITE(p);
00382         if (*p == '\0')
00383             break;
00384         pe = p;
00385         SKIPNONWHITE(pe);
00386         if (*pe != '\0')
00387             *pe++ = '\0';
00388 
00389         {   VFA_t *vfa;
00390             for (vfa = verifyAttrs; vfa->attribute != NULL; vfa++) {
00391                 if (strcmp(p, vfa->attribute))
00392                     /*@innercontinue@*/ continue;
00393                 verifyFlags |= vfa->flag;
00394                 /*@innerbreak@*/ break;
00395             }
00396             if (vfa->attribute)
00397                 continue;
00398         }
00399 
00400         if (!strcmp(p, "not")) {
00401             negated ^= 1;
00402         } else {
00403             rpmError(RPMERR_BADSPEC, _("Invalid %s token: %s\n"), name, p);
00404             fl->processingFailed = 1;
00405             return RPMERR_BADSPEC;
00406         }
00407     }
00408 
00409     *resultVerify = negated ? ~(verifyFlags) : verifyFlags;
00410     *specdFlags |= SPECD_VERIFY;
00411 
00412     return 0;
00413 }
00414 /*@=boundswrite@*/
00415 
00416 #define isAttrDefault(_ars)     ((_ars)[0] == '-' && (_ars)[1] == '\0')
00417 
00424 /*@-boundswrite@*/
00425 static int parseForDev(char * buf, FileList fl)
00426         /*@modifies buf, fl->processingFailed,
00427                 fl->noGlob, fl->devtype, fl->devmajor, fl->devminor @*/
00428 {
00429     const char * name;
00430     const char * errstr = NULL;
00431     char *p, *pe, *q;
00432     int rc = RPMERR_BADSPEC;    /* assume error */
00433 
00434     if ((p = strstr(buf, (name = "%dev"))) == NULL)
00435         return 0;
00436 
00437     for (pe = p; (pe-p) < strlen(name); pe++)
00438         *pe = ' ';
00439     SKIPSPACE(pe);
00440 
00441     if (*pe != '(') {
00442         errstr = "'('";
00443         goto exit;
00444     }
00445 
00446     /* Bracket %dev args */
00447     *pe++ = ' ';
00448     for (p = pe; *pe && *pe != ')'; pe++)
00449         {};
00450     if (*pe != ')') {
00451         errstr = "')'";
00452         goto exit;
00453     }
00454 
00455     /* Localize. Erase parsed string */
00456     q = alloca((pe-p) + 1);
00457     strncpy(q, p, pe-p);
00458     q[pe-p] = '\0';
00459     while (p <= pe)
00460         *p++ = ' ';
00461 
00462     p = q; SKIPWHITE(p);
00463     pe = p; SKIPNONWHITE(pe); if (*pe != '\0') *pe++ = '\0';
00464     if (*p == 'b')
00465         fl->devtype = 'b';
00466     else if (*p == 'c')
00467         fl->devtype = 'c';
00468     else {
00469         errstr = "devtype";
00470         goto exit;
00471     }
00472 
00473     p = pe; SKIPWHITE(p);
00474     pe = p; SKIPNONWHITE(pe); if (*pe != '\0') *pe++ = '\0';
00475     for (pe = p; *pe && xisdigit(*pe); pe++)
00476         {} ;
00477     if (*pe == '\0') {
00478         fl->devmajor = atoi(p);
00479         /*@-unsignedcompare @*/ /* LCL: ge is ok */
00480         if (!(fl->devmajor >= 0 && fl->devmajor < 256)) {
00481             errstr = "devmajor";
00482             goto exit;
00483         }
00484         /*@=unsignedcompare @*/
00485         pe++;
00486     } else {
00487         errstr = "devmajor";
00488         goto exit;
00489     }
00490 
00491     p = pe; SKIPWHITE(p);
00492     pe = p; SKIPNONWHITE(pe); if (*pe != '\0') *pe++ = '\0';
00493     for (pe = p; *pe && xisdigit(*pe); pe++)
00494         {} ;
00495     if (*pe == '\0') {
00496         fl->devminor = atoi(p);
00497         if (!(fl->devminor >= 0 && fl->devminor < 256)) {
00498             errstr = "devminor";
00499             goto exit;
00500         }
00501         pe++;
00502     } else {
00503         errstr = "devminor";
00504         goto exit;
00505     }
00506 
00507     fl->noGlob = 1;
00508 
00509     rc = 0;
00510 
00511 exit:
00512     if (rc) {
00513         rpmError(RPMERR_BADSPEC, _("Missing %s in %s %s\n"), errstr, name, p);
00514         fl->processingFailed = 1;
00515     }
00516     return rc;
00517 }
00518 /*@=boundswrite@*/
00519 
00526 /*@-boundswrite@*/
00527 static int parseForAttr(char * buf, FileList fl)
00528         /*@modifies buf, fl->processingFailed,
00529                 fl->cur_ar, fl->def_ar,
00530                 fl->currentSpecdFlags, fl->defSpecdFlags @*/
00531 {
00532     const char *name;
00533     char *p, *pe, *q;
00534     int x;
00535     struct AttrRec_s arbuf;
00536     AttrRec ar = &arbuf, ret_ar;
00537     specdFlags * specdFlags;
00538 
00539     if ((p = strstr(buf, (name = "%attr"))) != NULL) {
00540         ret_ar = &(fl->cur_ar);
00541         specdFlags = &fl->currentSpecdFlags;
00542     } else if ((p = strstr(buf, (name = "%defattr"))) != NULL) {
00543         ret_ar = &(fl->def_ar);
00544         specdFlags = &fl->defSpecdFlags;
00545     } else
00546         return 0;
00547 
00548     for (pe = p; (pe-p) < strlen(name); pe++)
00549         *pe = ' ';
00550 
00551     SKIPSPACE(pe);
00552 
00553     if (*pe != '(') {
00554         rpmError(RPMERR_BADSPEC, _("Missing '(' in %s %s\n"), name, pe);
00555         fl->processingFailed = 1;
00556         return RPMERR_BADSPEC;
00557     }
00558 
00559     /* Bracket %*attr args */
00560     *pe++ = ' ';
00561     for (p = pe; *pe && *pe != ')'; pe++)
00562         {};
00563 
00564     if (ret_ar == &(fl->def_ar)) {      /* %defattr */
00565         q = pe;
00566         q++;
00567         SKIPSPACE(q);
00568         if (*q != '\0') {
00569             rpmError(RPMERR_BADSPEC,
00570                      _("Non-white space follows %s(): %s\n"), name, q);
00571             fl->processingFailed = 1;
00572             return RPMERR_BADSPEC;
00573         }
00574     }
00575 
00576     /* Localize. Erase parsed string */
00577     q = alloca((pe-p) + 1);
00578     strncpy(q, p, pe-p);
00579     q[pe-p] = '\0';
00580     while (p <= pe)
00581         *p++ = ' ';
00582 
00583     nullAttrRec(ar);
00584 
00585     p = q; SKIPWHITE(p);
00586     if (*p != '\0') {
00587         pe = p; SKIPNONWHITE(pe); if (*pe != '\0') *pe++ = '\0';
00588         ar->ar_fmodestr = p;
00589         p = pe; SKIPWHITE(p);
00590     }
00591     if (*p != '\0') {
00592         pe = p; SKIPNONWHITE(pe); if (*pe != '\0') *pe++ = '\0';
00593         ar->ar_user = p;
00594         p = pe; SKIPWHITE(p);
00595     }
00596     if (*p != '\0') {
00597         pe = p; SKIPNONWHITE(pe); if (*pe != '\0') *pe++ = '\0';
00598         ar->ar_group = p;
00599         p = pe; SKIPWHITE(p);
00600     }
00601     if (*p != '\0' && ret_ar == &(fl->def_ar)) {        /* %defattr */
00602         pe = p; SKIPNONWHITE(pe); if (*pe != '\0') *pe++ = '\0';
00603         ar->ar_dmodestr = p;
00604         p = pe; SKIPWHITE(p);
00605     }
00606 
00607     if (!(ar->ar_fmodestr && ar->ar_user && ar->ar_group) || *p != '\0') {
00608         rpmError(RPMERR_BADSPEC, _("Bad syntax: %s(%s)\n"), name, q);
00609         fl->processingFailed = 1;
00610         return RPMERR_BADSPEC;
00611     }
00612 
00613     /* Do a quick test on the mode argument and adjust for "-" */
00614     if (ar->ar_fmodestr && !isAttrDefault(ar->ar_fmodestr)) {
00615         unsigned int ui;
00616         x = sscanf(ar->ar_fmodestr, "%o", &ui);
00617         if ((x == 0) || (ar->ar_fmode & ~MYALLPERMS)) {
00618             rpmError(RPMERR_BADSPEC, _("Bad mode spec: %s(%s)\n"), name, q);
00619             fl->processingFailed = 1;
00620             return RPMERR_BADSPEC;
00621         }
00622         ar->ar_fmode = ui;
00623     } else
00624         ar->ar_fmodestr = NULL;
00625 
00626     if (ar->ar_dmodestr && !isAttrDefault(ar->ar_dmodestr)) {
00627         unsigned int ui;
00628         x = sscanf(ar->ar_dmodestr, "%o", &ui);
00629         if ((x == 0) || (ar->ar_dmode & ~MYALLPERMS)) {
00630             rpmError(RPMERR_BADSPEC, _("Bad dirmode spec: %s(%s)\n"), name, q);
00631             fl->processingFailed = 1;
00632             return RPMERR_BADSPEC;
00633         }
00634         ar->ar_dmode = ui;
00635     } else
00636         ar->ar_dmodestr = NULL;
00637 
00638     if (!(ar->ar_user && !isAttrDefault(ar->ar_user)))
00639         ar->ar_user = NULL;
00640 
00641     if (!(ar->ar_group && !isAttrDefault(ar->ar_group)))
00642         ar->ar_group = NULL;
00643 
00644     dupAttrRec(ar, ret_ar);
00645 
00646     /* XXX fix all this */
00647     *specdFlags |= SPECD_UID | SPECD_GID | SPECD_FILEMODE | SPECD_DIRMODE;
00648     
00649     return 0;
00650 }
00651 /*@=boundswrite@*/
00652 
00659 /*@-boundswrite@*/
00660 static int parseForConfig(char * buf, FileList fl)
00661         /*@modifies buf, fl->processingFailed, 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     /* Erase "%config" token. */
00672     for (pe = p; (pe-p) < strlen(name); pe++)
00673         *pe = ' ';
00674     SKIPSPACE(pe);
00675     if (*pe != '(')
00676         return 0;
00677 
00678     /* Bracket %config args */
00679     *pe++ = ' ';
00680     for (p = pe; *pe && *pe != ')'; pe++)
00681         {};
00682 
00683     if (*pe == '\0') {
00684         rpmError(RPMERR_BADSPEC, _("Missing ')' in %s(%s\n"), name, p);
00685         fl->processingFailed = 1;
00686         return RPMERR_BADSPEC;
00687     }
00688 
00689     /* Localize. Erase parsed string. */
00690     q = alloca((pe-p) + 1);
00691     strncpy(q, p, pe-p);
00692     q[pe-p] = '\0';
00693     while (p <= pe)
00694         *p++ = ' ';
00695 
00696     for (p = q; *p != '\0'; p = pe) {
00697         SKIPWHITE(p);
00698         if (*p == '\0')
00699             break;
00700         pe = p;
00701         SKIPNONWHITE(pe);
00702         if (*pe != '\0')
00703             *pe++ = '\0';
00704         if (!strcmp(p, "missingok")) {
00705             fl->currentFlags |= RPMFILE_MISSINGOK;
00706         } else if (!strcmp(p, "noreplace")) {
00707             fl->currentFlags |= RPMFILE_NOREPLACE;
00708         } else {
00709             rpmError(RPMERR_BADSPEC, _("Invalid %s token: %s\n"), name, p);
00710             fl->processingFailed = 1;
00711             return RPMERR_BADSPEC;
00712         }
00713     }
00714 
00715     return 0;
00716 }
00717 /*@=boundswrite@*/
00718 
00721 static int langCmp(const void * ap, const void * bp)
00722         /*@*/
00723 {
00724 /*@-boundsread@*/
00725     return strcmp(*(const char **)ap, *(const char **)bp);
00726 /*@=boundsread@*/
00727 }
00728 
00735 /*@-bounds@*/
00736 static int parseForLang(char * buf, FileList fl)
00737         /*@modifies buf, fl->processingFailed,
00738                 fl->currentLangs, fl->nLangs @*/
00739 {
00740     char *p, *pe, *q;
00741     const char *name;
00742 
00743   while ((p = strstr(buf, (name = "%lang"))) != NULL) {
00744 
00745     for (pe = p; (pe-p) < strlen(name); pe++)
00746         *pe = ' ';
00747     SKIPSPACE(pe);
00748 
00749     if (*pe != '(') {
00750         rpmError(RPMERR_BADSPEC, _("Missing '(' in %s %s\n"), name, pe);
00751         fl->processingFailed = 1;
00752         return RPMERR_BADSPEC;
00753     }
00754 
00755     /* Bracket %lang args */
00756     *pe++ = ' ';
00757     for (pe = p; *pe && *pe != ')'; pe++)
00758         {};
00759 
00760     if (*pe == '\0') {
00761         rpmError(RPMERR_BADSPEC, _("Missing ')' in %s(%s\n"), name, p);
00762         fl->processingFailed = 1;
00763         return RPMERR_BADSPEC;
00764     }
00765 
00766     /* Localize. Erase parsed string. */
00767     q = alloca((pe-p) + 1);
00768     strncpy(q, p, pe-p);
00769     q[pe-p] = '\0';
00770     while (p <= pe)
00771         *p++ = ' ';
00772 
00773     /* Parse multiple arguments from %lang */
00774     for (p = q; *p != '\0'; p = pe) {
00775         char *newp;
00776         size_t np;
00777         int i;
00778 
00779         SKIPWHITE(p);
00780         pe = p;
00781         SKIPNONWHITE(pe);
00782 
00783         np = pe - p;
00784         
00785         /* Sanity check on locale lengths */
00786         if (np < 1 || (np == 1 && *p != 'C') || np >= 32) {
00787             rpmError(RPMERR_BADSPEC,
00788                 _("Unusual locale length: \"%.*s\" in %%lang(%s)\n"),
00789                 (int)np, p, q);
00790             fl->processingFailed = 1;
00791             return RPMERR_BADSPEC;
00792         }
00793 
00794         /* Check for duplicate locales */
00795         if (fl->currentLangs != NULL)
00796         for (i = 0; i < fl->nLangs; i++) {
00797             if (strncmp(fl->currentLangs[i], p, np))
00798                 /*@innercontinue@*/ continue;
00799             rpmError(RPMERR_BADSPEC, _("Duplicate locale %.*s in %%lang(%s)\n"),
00800                 (int)np, p, q);
00801             fl->processingFailed = 1;
00802             return RPMERR_BADSPEC;
00803         }
00804 
00805         /* Add new locale */
00806         fl->currentLangs = xrealloc(fl->currentLangs,
00807                                 (fl->nLangs + 1) * sizeof(*fl->currentLangs));
00808         newp = xmalloc( np+1 );
00809         strncpy(newp, p, np);
00810         newp[np] = '\0';
00811         fl->currentLangs[fl->nLangs++] = newp;
00812         if (*pe == ',') pe++;   /* skip , if present */
00813     }
00814   }
00815 
00816     /* Insure that locales are sorted. */
00817     if (fl->currentLangs)
00818         qsort(fl->currentLangs, fl->nLangs, sizeof(*fl->currentLangs), langCmp);
00819 
00820     return 0;
00821 }
00822 /*@=bounds@*/
00823 
00826 /*@-boundswrite@*/
00827 static int parseForRegexLang(const char * fileName, /*@out@*/ char ** lang)
00828         /*@globals rpmGlobalMacroContext, h_errno @*/
00829         /*@modifies *lang, rpmGlobalMacroContext @*/
00830 {
00831     static int initialized = 0;
00832     static int hasRegex = 0;
00833     static regex_t compiledPatt;
00834     static char buf[BUFSIZ];
00835     int x;
00836     regmatch_t matches[2];
00837     const char *s;
00838 
00839     if (! initialized) {
00840         const char *patt = rpmExpand("%{?_langpatt}", NULL);
00841         int rc = 0;
00842         if (!(patt && *patt != '\0'))
00843             rc = 1;
00844         else if (regcomp(&compiledPatt, patt, REG_EXTENDED))
00845             rc = -1;
00846         patt = _free(patt);
00847         if (rc)
00848             return rc;
00849         hasRegex = 1;
00850         initialized = 1;
00851     }
00852     
00853     memset(matches, 0, sizeof(matches));
00854     if (! hasRegex || regexec(&compiledPatt, fileName, 2, matches, REG_NOTEOL))
00855         return 1;
00856 
00857     /* Got match */
00858     s = fileName + matches[1].rm_eo - 1;
00859     x = matches[1].rm_eo - matches[1].rm_so;
00860     buf[x] = '\0';
00861     while (x) {
00862         buf[--x] = *s--;
00863     }
00864     if (lang)
00865         *lang = buf;
00866     return 0;
00867 }
00868 /*@=boundswrite@*/
00869 
00872 /*@-exportlocal -exportheadervar@*/
00873 /*@unchecked@*/
00874 VFA_t virtualFileAttributes[] = {
00875         { "%dir",       0,      0 },    /* XXX why not RPMFILE_DIR? */
00876         { "%doc",       0,      RPMFILE_DOC },
00877         { "%ghost",     0,      RPMFILE_GHOST },
00878         { "%exclude",   0,      RPMFILE_EXCLUDE },
00879         { "%readme",    0,      RPMFILE_README },
00880         { "%license",   0,      RPMFILE_LICENSE },
00881         { "%pubkey",    0,      RPMFILE_PUBKEY },
00882         { "%policy",    0,      RPMFILE_POLICY },
00883 
00884 #if WHY_NOT
00885         { "%icon",      0,      RPMFILE_ICON },
00886         { "%spec",      0,      RPMFILE_SPEC },
00887         { "%config",    0,      RPMFILE_CONFIG },
00888         { "%missingok", 0,      RPMFILE_CONFIG|RPMFILE_MISSINGOK },
00889         { "%noreplace", 0,      RPMFILE_CONFIG|RPMFILE_NOREPLACE },
00890 #endif
00891 
00892         { NULL, 0, 0 }
00893 };
00894 /*@=exportlocal =exportheadervar@*/
00895 
00905 /*@-boundswrite@*/
00906 static int parseForSimple(/*@unused@*/Spec spec, Package pkg, char * buf,
00907                           FileList fl, /*@out@*/ const char ** fileName)
00908         /*@globals rpmGlobalMacroContext, h_errno @*/
00909         /*@modifies buf, fl->processingFailed, *fileName,
00910                 fl->currentFlags,
00911                 fl->docDirs, fl->docDirCount, fl->isDir,
00912                 fl->passedSpecialDoc, fl->isSpecialDoc,
00913                 pkg->specialDoc, rpmGlobalMacroContext @*/
00914 {
00915     char *s, *t;
00916     int res, specialDoc = 0;
00917     char specialDocBuf[BUFSIZ];
00918 
00919     specialDocBuf[0] = '\0';
00920     *fileName = NULL;
00921     res = 0;
00922 
00923     t = buf;
00924     while ((s = strtokWithQuotes(t, " \t\n")) != NULL) {
00925         t = NULL;
00926         if (!strcmp(s, "%docdir")) {
00927             s = strtokWithQuotes(NULL, " \t\n");
00928             if (fl->docDirCount == MAXDOCDIR) {
00929                 rpmError(RPMERR_INTERNAL, _("Hit limit for %%docdir\n"));
00930                 fl->processingFailed = 1;
00931                 res = 1;
00932             }
00933         
00934             if (s != NULL)
00935                 fl->docDirs[fl->docDirCount++] = xstrdup(s);
00936             if (s == NULL || strtokWithQuotes(NULL, " \t\n")) {
00937                 rpmError(RPMERR_INTERNAL, _("Only one arg for %%docdir\n"));
00938                 fl->processingFailed = 1;
00939                 res = 1;
00940             }
00941             break;
00942         }
00943 #if defined(__LCLINT__)
00944         assert(s != NULL);
00945 #endif
00946 
00947     /* Set flags for virtual file attributes */
00948     {   VFA_t *vfa;
00949         for (vfa = virtualFileAttributes; vfa->attribute != NULL; vfa++) {
00950             if (strcmp(s, vfa->attribute))
00951                 /*@innercontinue@*/ continue;
00952             if (!vfa->flag) {
00953                 if (!strcmp(s, "%dir"))
00954                     fl->isDir = 1;      /* XXX why not RPMFILE_DIR? */
00955             } else {
00956                 if (vfa->not)
00957                     fl->currentFlags &= ~vfa->flag;
00958                 else
00959                     fl->currentFlags |= vfa->flag;
00960             }
00961 
00962             /*@innerbreak@*/ break;
00963         }
00964         /* if we got an attribute, continue with next token */
00965         if (vfa->attribute != NULL)
00966             continue;
00967     }
00968 
00969         if (*fileName) {
00970             /* We already got a file -- error */
00971             rpmError(RPMERR_BADSPEC, _("Two files on one line: %s\n"),
00972                 *fileName);
00973             fl->processingFailed = 1;
00974             res = 1;
00975         }
00976 
00977         /*@-branchstate@*/
00978         if (*s != '/') {
00979             if (fl->currentFlags & RPMFILE_DOC) {
00980                 specialDoc = 1;
00981                 strcat(specialDocBuf, " ");
00982                 strcat(specialDocBuf, s);
00983             } else
00984             if (fl->currentFlags & (RPMFILE_POLICY|RPMFILE_PUBKEY|RPMFILE_ICON))
00985             {
00986                 *fileName = s;
00987             } else {
00988                 /* not in %doc, does not begin with / -- error */
00989                 rpmError(RPMERR_BADSPEC,
00990                     _("File must begin with \"/\": %s\n"), s);
00991                 fl->processingFailed = 1;
00992                 res = 1;
00993             }
00994         } else {
00995             *fileName = s;
00996         }
00997         /*@=branchstate@*/
00998     }
00999 
01000     if (specialDoc) {
01001         if (*fileName || (fl->currentFlags & ~(RPMFILE_DOC))) {
01002             rpmError(RPMERR_BADSPEC,
01003                      _("Can't mix special %%doc with other forms: %s\n"),
01004                      (*fileName ? *fileName : ""));
01005             fl->processingFailed = 1;
01006             res = 1;
01007         } else {
01008         /* XXX WATCHOUT: buf is an arg */
01009             {   const char *ddir, *n, *v;
01010 
01011                 (void) headerNVR(pkg->header, &n, &v, NULL);
01012 
01013                 ddir = rpmGetPath("%{_docdir}/", n, "-", v, NULL);
01014                 strcpy(buf, ddir);
01015                 ddir = _free(ddir);
01016             }
01017 
01018         /* XXX FIXME: this is easy to do as macro expansion */
01019 
01020             if (! fl->passedSpecialDoc) {
01021                 pkg->specialDoc = newStringBuf();
01022                 appendStringBuf(pkg->specialDoc, "DOCDIR=$RPM_BUILD_ROOT");
01023                 appendLineStringBuf(pkg->specialDoc, buf);
01024                 appendLineStringBuf(pkg->specialDoc, "export DOCDIR");
01025                 appendLineStringBuf(pkg->specialDoc, "rm -rf $DOCDIR");
01026                 appendLineStringBuf(pkg->specialDoc, MKDIR_P " $DOCDIR");
01027 
01028                 /*@-temptrans@*/
01029                 *fileName = buf;
01030                 /*@=temptrans@*/
01031                 fl->passedSpecialDoc = 1;
01032                 fl->isSpecialDoc = 1;
01033             }
01034 
01035             appendStringBuf(pkg->specialDoc, "cp -pr ");
01036             appendStringBuf(pkg->specialDoc, specialDocBuf);
01037             appendLineStringBuf(pkg->specialDoc, " $DOCDIR");
01038         }
01039     }
01040 
01041     return res;
01042 }
01043 /*@=boundswrite@*/
01044 
01047 static int compareFileListRecs(const void * ap, const void * bp)        /*@*/
01048 {
01049     const char *a = ((FileListRec)ap)->fileURL;
01050     const char *b = ((FileListRec)bp)->fileURL;
01051     return strcmp(a, b);
01052 }
01053 
01061 static int isDoc(FileList fl, const char * fileName)    /*@*/
01062 {
01063     int x = fl->docDirCount;
01064 
01065     while (x--) {
01066         if (strstr(fileName, fl->docDirs[x]) == fileName)
01067             return 1;
01068     }
01069     return 0;
01070 }
01071 
01078 static int checkHardLinks(FileList fl)
01079         /*@*/
01080 {
01081     FileListRec ilp, jlp;
01082     int i, j;
01083 
01084     for (i = 0;  i < fl->fileListRecsUsed; i++) {
01085         ilp = fl->fileList + i;
01086         if (!(S_ISREG(ilp->fl_mode) && ilp->fl_nlink > 1))
01087             continue;
01088 
01089         for (j = i + 1; j < fl->fileListRecsUsed; j++) {
01090             jlp = fl->fileList + j;
01091             if (!S_ISREG(jlp->fl_mode))
01092                 /*@innercontinue@*/ continue;
01093             if (ilp->fl_nlink != jlp->fl_nlink)
01094                 /*@innercontinue@*/ continue;
01095             if (ilp->fl_ino != jlp->fl_ino)
01096                 /*@innercontinue@*/ continue;
01097             if (ilp->fl_dev != jlp->fl_dev)
01098                 /*@innercontinue@*/ continue;
01099             return 1;
01100         }
01101     }
01102     return 0;
01103 }
01104 
01114 /*@-bounds@*/
01115 static void genCpioListAndHeader(/*@partial@*/ FileList fl,
01116                 rpmfi * fip, Header h, int isSrc)
01117         /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/
01118         /*@modifies h, *fip, fl->processingFailed, fl->fileList,
01119                 rpmGlobalMacroContext, fileSystem, internalState @*/
01120 {
01121     int _addDotSlash = !(isSrc || rpmExpandNumeric("%{_noPayloadPrefix}"));
01122     int apathlen = 0;
01123     int dpathlen = 0;
01124     int skipLen = 0;
01125     security_context_t scon = NULL;
01126     const char * sxfn;
01127     size_t fnlen;
01128     FileListRec flp;
01129     char buf[BUFSIZ];
01130     int i;
01131     
01132     /* Sort the big list */
01133     qsort(fl->fileList, fl->fileListRecsUsed,
01134           sizeof(*(fl->fileList)), compareFileListRecs);
01135     
01136     /* Generate the header. */
01137     if (! isSrc) {
01138         skipLen = 1;
01139         if (fl->prefix)
01140             skipLen += strlen(fl->prefix);
01141     }
01142 
01143     sxfn = rpmGetPath("%{?_build_file_context_path}", NULL);
01144     if (sxfn != NULL && *sxfn != '\0')
01145         matchpathcon_init(sxfn);
01146 
01147     for (i = 0, flp = fl->fileList; i < fl->fileListRecsUsed; i++, flp++) {
01148         const char *s;
01149 
01150         /* Merge duplicate entries. */
01151         while (i < (fl->fileListRecsUsed - 1) &&
01152             !strcmp(flp->fileURL, flp[1].fileURL)) {
01153 
01154             /* Two entries for the same file found, merge the entries. */
01155             /* Note that an %exclude is a duplication of a file reference */
01156 
01157             /* file flags */
01158             flp[1].flags |= flp->flags; 
01159 
01160             if (!(flp[1].flags & RPMFILE_EXCLUDE))
01161                 rpmMessage(RPMMESS_WARNING, _("File listed twice: %s\n"),
01162                         flp->fileURL);
01163    
01164             /* file mode */
01165             if (S_ISDIR(flp->fl_mode)) {
01166                 if ((flp[1].specdFlags & (SPECD_DIRMODE | SPECD_DEFDIRMODE)) <
01167                     (flp->specdFlags & (SPECD_DIRMODE | SPECD_DEFDIRMODE)))
01168                         flp[1].fl_mode = flp->fl_mode;
01169             } else {
01170                 if ((flp[1].specdFlags & (SPECD_FILEMODE | SPECD_DEFFILEMODE)) <
01171                     (flp->specdFlags & (SPECD_FILEMODE | SPECD_DEFFILEMODE)))
01172                         flp[1].fl_mode = flp->fl_mode;
01173             }
01174 
01175             /* uid */
01176             if ((flp[1].specdFlags & (SPECD_UID | SPECD_DEFUID)) <
01177                 (flp->specdFlags & (SPECD_UID | SPECD_DEFUID)))
01178             {
01179                 flp[1].fl_uid = flp->fl_uid;
01180                 flp[1].uname = flp->uname;
01181             }
01182 
01183             /* gid */
01184             if ((flp[1].specdFlags & (SPECD_GID | SPECD_DEFGID)) <
01185                 (flp->specdFlags & (SPECD_GID | SPECD_DEFGID)))
01186             {
01187                 flp[1].fl_gid = flp->fl_gid;
01188                 flp[1].gname = flp->gname;
01189             }
01190 
01191             /* verify flags */
01192             if ((flp[1].specdFlags & (SPECD_VERIFY | SPECD_DEFVERIFY)) <
01193                 (flp->specdFlags & (SPECD_VERIFY | SPECD_DEFVERIFY)))
01194                     flp[1].verifyFlags = flp->verifyFlags;
01195 
01196             /* XXX to-do: language */
01197 
01198             flp++; i++;
01199         }
01200 
01201         /* Skip files that were marked with %exclude. */
01202         if (flp->flags & RPMFILE_EXCLUDE) continue;
01203 
01204         /* Omit '/' and/or URL prefix, leave room for "./" prefix */
01205         apathlen += (strlen(flp->fileURL) - skipLen + (_addDotSlash ? 3 : 1));
01206 
01207         /* Leave room for both dirname and basename NUL's */
01208         dpathlen += (strlen(flp->diskURL) + 2);
01209 
01210         /*
01211          * Make the header, the OLDFILENAMES will get converted to a 
01212          * compressed file list write before we write the actual package to
01213          * disk.
01214          */
01215         (void) headerAddOrAppendEntry(h, RPMTAG_OLDFILENAMES, RPM_STRING_ARRAY_TYPE,
01216                                &(flp->fileURL), 1);
01217 
01218 /*@-sizeoftype@*/
01219       if (sizeof(flp->fl_size) != sizeof(uint_32)) {
01220         uint_32 psize = (uint_32)flp->fl_size;
01221         (void) headerAddOrAppendEntry(h, RPMTAG_FILESIZES, RPM_INT32_TYPE,
01222                                &(psize), 1);
01223       } else {
01224         (void) headerAddOrAppendEntry(h, RPMTAG_FILESIZES, RPM_INT32_TYPE,
01225                                &(flp->fl_size), 1);
01226       }
01227         (void) headerAddOrAppendEntry(h, RPMTAG_FILEUSERNAME, RPM_STRING_ARRAY_TYPE,
01228                                &(flp->uname), 1);
01229         (void) headerAddOrAppendEntry(h, RPMTAG_FILEGROUPNAME, RPM_STRING_ARRAY_TYPE,
01230                                &(flp->gname), 1);
01231       if (sizeof(flp->fl_mtime) != sizeof(uint_32)) {
01232         uint_32 mtime = (uint_32)flp->fl_mtime;
01233         (void) headerAddOrAppendEntry(h, RPMTAG_FILEMTIMES, RPM_INT32_TYPE,
01234                                &(mtime), 1);
01235       } else {
01236         (void) headerAddOrAppendEntry(h, RPMTAG_FILEMTIMES, RPM_INT32_TYPE,
01237                                &(flp->fl_mtime), 1);
01238       }
01239       if (sizeof(flp->fl_mode) != sizeof(uint_16)) {
01240         uint_16 pmode = (uint_16)flp->fl_mode;
01241         (void) headerAddOrAppendEntry(h, RPMTAG_FILEMODES, RPM_INT16_TYPE,
01242                                &(pmode), 1);
01243       } else {
01244         (void) headerAddOrAppendEntry(h, RPMTAG_FILEMODES, RPM_INT16_TYPE,
01245                                &(flp->fl_mode), 1);
01246       }
01247       if (sizeof(flp->fl_rdev) != sizeof(uint_16)) {
01248         uint_16 prdev = (uint_16)flp->fl_rdev;
01249         (void) headerAddOrAppendEntry(h, RPMTAG_FILERDEVS, RPM_INT16_TYPE,
01250                                &(prdev), 1);
01251       } else {
01252         (void) headerAddOrAppendEntry(h, RPMTAG_FILERDEVS, RPM_INT16_TYPE,
01253                                &(flp->fl_rdev), 1);
01254       }
01255       if (sizeof(flp->fl_dev) != sizeof(uint_32)) {
01256         uint_32 pdevice = (uint_32)flp->fl_dev;
01257         (void) headerAddOrAppendEntry(h, RPMTAG_FILEDEVICES, RPM_INT32_TYPE,
01258                                &(pdevice), 1);
01259       } else {
01260         (void) headerAddOrAppendEntry(h, RPMTAG_FILEDEVICES, RPM_INT32_TYPE,
01261                                &(flp->fl_dev), 1);
01262       }
01263       if (sizeof(flp->fl_ino) != sizeof(uint_32)) {
01264         uint_32 ino = (uint_32)flp->fl_ino;
01265         (void) headerAddOrAppendEntry(h, RPMTAG_FILEINODES, RPM_INT32_TYPE,
01266                                 &(ino), 1);
01267       } else {
01268         (void) headerAddOrAppendEntry(h, RPMTAG_FILEINODES, RPM_INT32_TYPE,
01269                                 &(flp->fl_ino), 1);
01270       }
01271 /*@=sizeoftype@*/
01272 
01273         (void) headerAddOrAppendEntry(h, RPMTAG_FILELANGS, RPM_STRING_ARRAY_TYPE,
01274                                &(flp->langs),  1);
01275         
01276         /* We used to add these, but they should not be needed */
01277         /* (void) headerAddOrAppendEntry(h, RPMTAG_FILEUIDS,
01278          *                 RPM_INT32_TYPE, &(flp->fl_uid), 1);
01279          * (void) headerAddOrAppendEntry(h, RPMTAG_FILEGIDS,
01280          *                 RPM_INT32_TYPE, &(flp->fl_gid), 1);
01281          */
01282         
01283         buf[0] = '\0';
01284         if (S_ISREG(flp->fl_mode))
01285             (void) domd5(flp->diskURL, buf, 1, NULL);
01286         s = buf;
01287         (void) headerAddOrAppendEntry(h, RPMTAG_FILEMD5S, RPM_STRING_ARRAY_TYPE,
01288                                &s, 1);
01289         
01290         buf[0] = '\0';
01291         if (S_ISLNK(flp->fl_mode)) {
01292             buf[Readlink(flp->diskURL, buf, BUFSIZ)] = '\0';
01293             if (fl->buildRootURL) {
01294                 const char * buildRoot;
01295                 (void) urlPath(fl->buildRootURL, &buildRoot);
01296 
01297                 if (buf[0] == '/' && strcmp(buildRoot, "/") &&
01298                     !strncmp(buf, buildRoot, strlen(buildRoot))) {
01299                      rpmError(RPMERR_BADSPEC,
01300                                 _("Symlink points to BuildRoot: %s -> %s\n"),
01301                                 flp->fileURL, buf);
01302                     fl->processingFailed = 1;
01303                 }
01304             }
01305         }
01306         s = buf;
01307         (void) headerAddOrAppendEntry(h, RPMTAG_FILELINKTOS, RPM_STRING_ARRAY_TYPE,
01308                                &s, 1);
01309         
01310         if (flp->flags & RPMFILE_GHOST) {
01311             flp->verifyFlags &= ~(RPMVERIFY_MD5 | RPMVERIFY_FILESIZE |
01312                                 RPMVERIFY_LINKTO | RPMVERIFY_MTIME);
01313         }
01314         (void) headerAddOrAppendEntry(h, RPMTAG_FILEVERIFYFLAGS, RPM_INT32_TYPE,
01315                                &(flp->verifyFlags), 1);
01316         
01317         if (!isSrc && isDoc(fl, flp->fileURL))
01318             flp->flags |= RPMFILE_DOC;
01319         /* XXX Should directories have %doc/%config attributes? (#14531) */
01320         if (S_ISDIR(flp->fl_mode))
01321             flp->flags &= ~(RPMFILE_CONFIG|RPMFILE_DOC);
01322 
01323         (void) headerAddOrAppendEntry(h, RPMTAG_FILEFLAGS, RPM_INT32_TYPE,
01324                                &(flp->flags), 1);
01325 
01326         /* Add file security context to package. */
01327         mode_t fmode = (uint_16)flp->fl_mode;
01328         int rc = matchpathcon(flp->fileURL, fmode, &scon);
01329         if ( rc == 0 && scon != NULL) {
01330             (void) headerAddOrAppendEntry(h, RPMTAG_FILECONTEXTS, RPM_STRING_ARRAY_TYPE, &scon, 1);
01331             freecon(scon);
01332         }
01333         else  {
01334             const char *nocon = "";
01335             (void) headerAddOrAppendEntry(h, RPMTAG_FILECONTEXTS, RPM_STRING_ARRAY_TYPE, &nocon, 1);
01336         }
01337 
01338 
01339     }
01340     sxfn = _free(sxfn);
01341 
01342     (void) headerAddEntry(h, RPMTAG_SIZE, RPM_INT32_TYPE,
01343                    &(fl->totalFileSize), 1);
01344 
01345     if (_addDotSlash)
01346         (void) rpmlibNeedsFeature(h, "PayloadFilesHavePrefix", "4.0-1");
01347 
01348     /* Choose how filenames are represented. */
01349     if (_noDirTokens)
01350         expandFilelist(h);
01351     else {
01352         compressFilelist(h);
01353         /* Binary packages with dirNames cannot be installed by legacy rpm. */
01354         (void) rpmlibNeedsFeature(h, "CompressedFileNames", "3.0.4-1");
01355     }
01356 
01357   { int scareMem = 0;
01358     rpmts ts = NULL;    /* XXX FIXME drill rpmts ts all the way down here */
01359     rpmfi fi = rpmfiNew(ts, h, RPMTAG_BASENAMES, scareMem);
01360     char * a, * d;
01361 
01362     if (fi == NULL) return;             /* XXX can't happen */
01363 
01364 /*@-onlytrans@*/
01365     fi->te = xcalloc(1, sizeof(*fi->te));
01366 /*@=onlytrans@*/
01367     fi->te->type = TR_ADDED;
01368 
01369     fi->dnl = _free(fi->dnl);
01370     fi->bnl = _free(fi->bnl);
01371     if (!scareMem) fi->dil = _free(fi->dil);
01372 
01373     fi->dnl = xmalloc(fi->fc * sizeof(*fi->dnl) + dpathlen);
01374     d = (char *)(fi->dnl + fi->fc);
01375     *d = '\0';
01376 
01377     fi->bnl = xmalloc(fi->fc * (sizeof(*fi->bnl) + sizeof(*fi->dil)));
01378 /*@-dependenttrans@*/ /* FIX: artifact of spoofing headerGetEntry */
01379     fi->dil = (!scareMem)
01380         ? xcalloc(sizeof(*fi->dil), fi->fc)
01381         : (int *)(fi->bnl + fi->fc);
01382 /*@=dependenttrans@*/
01383 
01384     fi->apath = xmalloc(fi->fc * sizeof(*fi->apath) + apathlen);
01385     a = (char *)(fi->apath + fi->fc);
01386     *a = '\0';
01387 
01388     fi->actions = xcalloc(sizeof(*fi->actions), fi->fc);
01389     fi->fmapflags = xcalloc(sizeof(*fi->fmapflags), fi->fc);
01390     fi->astriplen = 0;
01391     if (fl->buildRootURL)
01392         fi->astriplen = strlen(fl->buildRootURL);
01393     fi->striplen = 0;
01394     fi->fuser = NULL;
01395     fi->fgroup = NULL;
01396 
01397     /* Make the cpio list */
01398     if (fi->dil != NULL)        /* XXX can't happen */
01399     for (i = 0, flp = fl->fileList; i < fi->fc; i++, flp++) {
01400         char * b;
01401 
01402         /* Skip (possible) duplicate file entries, use last entry info. */
01403         while (((flp - fl->fileList) < (fl->fileListRecsUsed - 1)) &&
01404                 !strcmp(flp->fileURL, flp[1].fileURL))
01405             flp++;
01406 
01407         if (flp->flags & RPMFILE_EXCLUDE) {
01408             i--;
01409             continue;
01410         }
01411 
01412         if ((fnlen = strlen(flp->diskURL) + 1) > fi->fnlen)
01413             fi->fnlen = fnlen;
01414 
01415         /* Create disk directory and base name. */
01416         fi->dil[i] = i;
01417 /*@-dependenttrans@*/ /* FIX: artifact of spoofing headerGetEntry */
01418         fi->dnl[fi->dil[i]] = d;
01419 /*@=dependenttrans@*/
01420         d = stpcpy(d, flp->diskURL);
01421 
01422         /* Make room for the dirName NUL, find start of baseName. */
01423         for (b = d; b > fi->dnl[fi->dil[i]] && *b != '/'; b--)
01424             b[1] = b[0];
01425         b++;            /* dirname's end in '/' */
01426         *b++ = '\0';    /* terminate dirname, b points to basename */
01427         fi->bnl[i] = b;
01428         d += 2;         /* skip both dirname and basename NUL's */
01429 
01430         /* Create archive path, normally adding "./" */
01431         /*@-dependenttrans@*/   /* FIX: xstrdup? nah ... */
01432         fi->apath[i] = a;
01433         /*@=dependenttrans@*/
01434         if (_addDotSlash)
01435             a = stpcpy(a, "./");
01436         a = stpcpy(a, (flp->fileURL + skipLen));
01437         a++;            /* skip apath NUL */
01438 
01439         if (flp->flags & RPMFILE_GHOST) {
01440             fi->actions[i] = FA_SKIP;
01441             continue;
01442         }
01443         fi->actions[i] = FA_COPYOUT;
01444         fi->fmapflags[i] = CPIO_MAP_PATH |
01445                 CPIO_MAP_TYPE | CPIO_MAP_MODE | CPIO_MAP_UID | CPIO_MAP_GID;
01446         if (isSrc)
01447             fi->fmapflags[i] |= CPIO_FOLLOW_SYMLINKS;
01448 
01449     }
01450     /*@-branchstate -compdef@*/
01451     if (fip)
01452         *fip = fi;
01453     else
01454         fi = rpmfiFree(fi);
01455     /*@=branchstate =compdef@*/
01456   }
01457 }
01458 /*@=bounds@*/
01459 
01462 /*@-boundswrite@*/
01463 static /*@null@*/ FileListRec freeFileList(/*@only@*/ FileListRec fileList,
01464                         int count)
01465         /*@*/
01466 {
01467     while (count--) {
01468         fileList[count].diskURL = _free(fileList[count].diskURL);
01469         fileList[count].fileURL = _free(fileList[count].fileURL);
01470         fileList[count].langs = _free(fileList[count].langs);
01471     }
01472     fileList = _free(fileList);
01473     return NULL;
01474 }
01475 /*@=boundswrite@*/
01476 
01477 /* forward ref */
01478 static int recurseDir(FileList fl, const char * diskURL)
01479         /*@globals check_fileList, rpmGlobalMacroContext, h_errno,
01480                 fileSystem, internalState @*/
01481         /*@modifies *fl, fl->processingFailed,
01482                 fl->fileList, fl->fileListRecsAlloced, fl->fileListRecsUsed,
01483                 fl->totalFileSize, fl->fileCount, fl->inFtw, fl->isDir,
01484                 check_fileList, rpmGlobalMacroContext,
01485                 fileSystem, internalState @*/;
01486 
01494 /*@-boundswrite@*/
01495 static int addFile(FileList fl, const char * diskURL,
01496                 /*@null@*/ struct stat * statp)
01497         /*@globals check_fileList, rpmGlobalMacroContext, h_errno,
01498                 fileSystem, internalState @*/
01499         /*@modifies *statp, *fl, fl->processingFailed,
01500                 fl->fileList, fl->fileListRecsAlloced, fl->fileListRecsUsed,
01501                 fl->totalFileSize, fl->fileCount,
01502                 check_fileList, rpmGlobalMacroContext,
01503                 fileSystem, internalState @*/
01504 {
01505     const char *fileURL = diskURL;
01506     struct stat statbuf;
01507     mode_t fileMode;
01508     uid_t fileUid;
01509     gid_t fileGid;
01510     const char *fileUname;
01511     const char *fileGname;
01512     char *lang;
01513     
01514     /* Path may have prepended buildRootURL, so locate the original filename. */
01515     /*
01516      * XXX There are 3 types of entry into addFile:
01517      *
01518      *  From                    diskUrl                 statp
01519      *  =====================================================
01520      *  processBinaryFile       path                    NULL
01521      *  processBinaryFile       glob result path        NULL
01522      *  myftw                   path                    stat
01523      *
01524      */
01525     {   const char *fileName;
01526         (void) urlPath(fileURL, &fileName);
01527         if (fl->buildRootURL && strcmp(fl->buildRootURL, "/"))
01528             fileURL += strlen(fl->buildRootURL);
01529     }
01530 
01531     /* XXX make sure '/' can be packaged also */
01532     /*@-branchstate@*/
01533     if (*fileURL == '\0')
01534         fileURL = "/";
01535     /*@=branchstate@*/
01536 
01537     /* If we are using a prefix, validate the file */
01538     if (!fl->inFtw && fl->prefix) {
01539         const char *prefixTest;
01540         const char *prefixPtr = fl->prefix;
01541 
01542         (void) urlPath(fileURL, &prefixTest);
01543         while (*prefixPtr && *prefixTest && (*prefixTest == *prefixPtr)) {
01544             prefixPtr++;
01545             prefixTest++;
01546         }
01547         if (*prefixPtr || (*prefixTest && *prefixTest != '/')) {
01548             rpmError(RPMERR_BADSPEC, _("File doesn't match prefix (%s): %s\n"),
01549                      fl->prefix, fileURL);
01550             fl->processingFailed = 1;
01551             return RPMERR_BADSPEC;
01552         }
01553     }
01554 
01555     if (statp == NULL) {
01556         statp = &statbuf;
01557         memset(statp, 0, sizeof(*statp));
01558         if (fl->devtype) {
01559             time_t now = time(NULL);
01560 
01561             /* XXX hack up a stat structure for a %dev(...) directive. */
01562             statp->st_nlink = 1;
01563             statp->st_rdev =
01564                 ((fl->devmajor & 0xff) << 8) | (fl->devminor & 0xff);
01565             statp->st_dev = statp->st_rdev;
01566             statp->st_mode = (fl->devtype == 'b' ? S_IFBLK : S_IFCHR);
01567             statp->st_mode |= (fl->cur_ar.ar_fmode & 0777);
01568             statp->st_atime = now;
01569             statp->st_mtime = now;
01570             statp->st_ctime = now;
01571         } else if (Lstat(diskURL, statp)) {
01572             rpmError(RPMERR_BADSPEC, _("File not found: %s\n"), diskURL);
01573             fl->processingFailed = 1;
01574             return RPMERR_BADSPEC;
01575         }
01576     }
01577 
01578     if ((! fl->isDir) && S_ISDIR(statp->st_mode)) {
01579 /*@-nullstate@*/ /* FIX: fl->buildRootURL may be NULL */
01580         return recurseDir(fl, diskURL);
01581 /*@=nullstate@*/
01582     }
01583 
01584     fileMode = statp->st_mode;
01585     fileUid = statp->st_uid;
01586     fileGid = statp->st_gid;
01587 
01588     if (S_ISDIR(fileMode) && fl->cur_ar.ar_dmodestr) {
01589         fileMode &= S_IFMT;
01590         fileMode |= fl->cur_ar.ar_dmode;
01591     } else if (fl->cur_ar.ar_fmodestr != NULL) {
01592         fileMode &= S_IFMT;
01593         fileMode |= fl->cur_ar.ar_fmode;
01594     }
01595     if (fl->cur_ar.ar_user) {
01596         fileUname = getUnameS(fl->cur_ar.ar_user);
01597     } else {
01598         fileUname = getUname(fileUid);
01599     }
01600     if (fl->cur_ar.ar_group) {
01601         fileGname = getGnameS(fl->cur_ar.ar_group);
01602     } else {
01603         fileGname = getGname(fileGid);
01604     }
01605         
01606     /* Default user/group to builder's user/group */
01607     if (fileUname == NULL)
01608         fileUname = getUname(getuid());
01609     if (fileGname == NULL)
01610         fileGname = getGname(getgid());
01611     
01612     /* S_XXX macro must be consistent with type in find call at check-files script */
01613     if (check_fileList && (S_ISREG(fileMode) || S_ISLNK(fileMode))) {
01614         appendStringBuf(check_fileList, diskURL);
01615         appendStringBuf(check_fileList, "\n");
01616     }
01617 
01618     /* Add to the file list */
01619     if (fl->fileListRecsUsed == fl->fileListRecsAlloced) {
01620         fl->fileListRecsAlloced += 128;
01621         fl->fileList = xrealloc(fl->fileList,
01622                         fl->fileListRecsAlloced * sizeof(*(fl->fileList)));
01623     }
01624             
01625     {   FileListRec flp = &fl->fileList[fl->fileListRecsUsed];
01626         int i;
01627 
01628         flp->fl_st = *statp;    /* structure assignment */
01629         flp->fl_mode = fileMode;
01630         flp->fl_uid = fileUid;
01631         flp->fl_gid = fileGid;
01632 
01633         flp->fileURL = xstrdup(fileURL);
01634         flp->diskURL = xstrdup(diskURL);
01635         flp->uname = fileUname;
01636         flp->gname = fileGname;
01637 
01638         if (fl->currentLangs && fl->nLangs > 0) {
01639             char * ncl;
01640             size_t nl = 0;
01641             
01642             for (i = 0; i < fl->nLangs; i++)
01643                 nl += strlen(fl->currentLangs[i]) + 1;
01644 
01645             flp->langs = ncl = xmalloc(nl);
01646             for (i = 0; i < fl->nLangs; i++) {
01647                 const char *ocl;
01648                 if (i)  *ncl++ = '|';
01649                 for (ocl = fl->currentLangs[i]; *ocl != '\0'; ocl++)
01650                         *ncl++ = *ocl;
01651                 *ncl = '\0';
01652             }
01653         } else if (! parseForRegexLang(fileURL, &lang)) {
01654             flp->langs = xstrdup(lang);
01655         } else {
01656             flp->langs = xstrdup("");
01657         }
01658 
01659         flp->flags = fl->currentFlags;
01660         flp->specdFlags = fl->currentSpecdFlags;
01661         flp->verifyFlags = fl->currentVerifyFlags;
01662 
01663         /* Hard links need be counted only once. */
01664         if (S_ISREG(flp->fl_mode) && flp->fl_nlink > 1) {
01665             FileListRec ilp;
01666             for (i = 0;  i < fl->fileListRecsUsed; i++) {
01667                 ilp = fl->fileList + i;
01668                 if (!S_ISREG(ilp->fl_mode))
01669                     continue;
01670                 if (flp->fl_nlink != ilp->fl_nlink)
01671                     continue;
01672                 if (flp->fl_ino != ilp->fl_ino)
01673                     continue;
01674                 if (flp->fl_dev != ilp->fl_dev)
01675                     continue;
01676                 break;
01677             }
01678         } else
01679             i = fl->fileListRecsUsed;
01680 
01681         if (!(flp->flags & RPMFILE_EXCLUDE) && S_ISREG(flp->fl_mode) && i >= fl->fileListRecsUsed) 
01682             fl->totalFileSize += flp->fl_size;
01683     }
01684 
01685     fl->fileListRecsUsed++;
01686     fl->fileCount++;
01687 
01688     return 0;
01689 }
01690 /*@=boundswrite@*/
01691 
01698 static int recurseDir(FileList fl, const char * diskURL)
01699 {
01700     char * ftsSet[2];
01701     FTS * ftsp;
01702     FTSENT * fts;
01703     int myFtsOpts = (FTS_COMFOLLOW | FTS_NOCHDIR | FTS_PHYSICAL);
01704     int rc = RPMERR_BADSPEC;
01705 
01706     fl->inFtw = 1;  /* Flag to indicate file has buildRootURL prefixed */
01707     fl->isDir = 1;  /* Keep it from following myftw() again         */
01708 
01709     ftsSet[0] = (char *) diskURL;
01710     ftsSet[1] = NULL;
01711     ftsp = Fts_open(ftsSet, myFtsOpts, NULL);
01712     while ((fts = Fts_read(ftsp)) != NULL) {
01713         switch (fts->fts_info) {
01714         case FTS_D:             /* preorder directory */
01715         case FTS_F:             /* regular file */
01716         case FTS_SL:            /* symbolic link */
01717         case FTS_SLNONE:        /* symbolic link without target */
01718         case FTS_DEFAULT:       /* none of the above */
01719             rc = addFile(fl, fts->fts_accpath, fts->fts_statp);
01720             /*@switchbreak@*/ break;
01721         case FTS_DOT:           /* dot or dot-dot */
01722         case FTS_DP:            /* postorder directory */
01723             rc = 0;
01724             /*@switchbreak@*/ break;
01725         case FTS_NS:            /* stat(2) failed */
01726         case FTS_DNR:           /* unreadable directory */
01727         case FTS_ERR:           /* error; errno is set */
01728         case FTS_DC:            /* directory that causes cycles */
01729         case FTS_NSOK:          /* no stat(2) requested */
01730         case FTS_INIT:          /* initialized only */
01731         case FTS_W:             /* whiteout object */
01732         default:
01733             rc = RPMERR_BADSPEC;
01734             /*@switchbreak@*/ break;
01735         }
01736         if (rc)
01737             break;
01738     }
01739     (void) Fts_close(ftsp);
01740 
01741     fl->isDir = 0;
01742     fl->inFtw = 0;
01743 
01744     return rc;
01745 }
01746 
01755 static int processMetadataFile(Package pkg, FileList fl, const char * fileURL,
01756                 rpmTag tag)
01757         /*@globals check_fileList, rpmGlobalMacroContext, h_errno,
01758                 fileSystem, internalState @*/
01759         /*@modifies pkg->header, *fl, fl->processingFailed,
01760                 fl->fileList, fl->fileListRecsAlloced, fl->fileListRecsUsed,
01761                 fl->totalFileSize, fl->fileCount,
01762                 check_fileList, rpmGlobalMacroContext,
01763                 fileSystem, internalState @*/
01764 {
01765     const char * buildURL = "%{_builddir}/%{?buildsubdir}/";
01766     const char * fn = NULL;
01767     const char * apkt = NULL;
01768     const unsigned char * pkt = NULL;
01769     ssize_t pktlen = 0;
01770     int absolute = 0;
01771     int rc = 1;
01772     int xx;
01773 
01774     (void) urlPath(fileURL, &fn);
01775     if (*fn == '/') {
01776         fn = rpmGenPath(fl->buildRootURL, NULL, fn);
01777         absolute = 1;
01778     } else
01779         fn = rpmGenPath(buildURL, NULL, fn);
01780 
01781 /*@-branchstate@*/
01782     switch (tag) {
01783     default:
01784         rpmError(RPMERR_BADSPEC, _("%s: can't load unknown tag (%d).\n"),
01785                 fn, tag);
01786         goto exit;
01787         /*@notreached@*/ break;
01788     case RPMTAG_PUBKEYS:
01789         if ((rc = pgpReadPkts(fn, &pkt, &pktlen)) <= 0) {
01790             rpmError(RPMERR_BADSPEC, _("%s: public key read failed.\n"), fn);
01791             goto exit;
01792         }
01793         if (rc != PGPARMOR_PUBKEY) {
01794             rpmError(RPMERR_BADSPEC, _("%s: not an armored public key.\n"), fn);
01795             goto exit;
01796         }
01797         apkt = pgpArmorWrap(PGPARMOR_PUBKEY, pkt, pktlen);
01798         break;
01799     case RPMTAG_POLICIES:
01800         if ((rc = rpmioSlurp(fn, &pkt, &pktlen)) != 0) {
01801             rpmError(RPMERR_BADSPEC, _("%s: *.te policy read failed.\n"), fn);
01802             goto exit;
01803         }
01804         apkt = (const char *) pkt;      /* XXX unsigned char */
01805         pkt = NULL;
01806         break;
01807     }
01808 /*@=branchstate@*/
01809 
01810     xx = headerAddOrAppendEntry(pkg->header, tag,
01811                 RPM_STRING_ARRAY_TYPE, &apkt, 1);
01812 
01813     rc = 0;
01814     if (absolute)
01815         rc = addFile(fl, fn, NULL);
01816 
01817 exit:
01818     apkt = _free(apkt);
01819     pkt = _free(pkt);
01820     fn = _free(fn);
01821     if (rc) {
01822         fl->processingFailed = 1;
01823         rc = RPMERR_BADSPEC;
01824     }
01825     return rc;
01826 }
01827 
01835 static int processBinaryFile(/*@unused@*/ Package pkg, FileList fl,
01836                 const char * fileURL)
01837         /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/
01838         /*@modifies *fl, fl->processingFailed,
01839                 fl->fileList, fl->fileListRecsAlloced, fl->fileListRecsUsed,
01840                 fl->totalFileSize, fl->fileCount,
01841                 rpmGlobalMacroContext, fileSystem, internalState @*/
01842 {
01843     int quote = 1;      /* XXX permit quoted glob characters. */
01844     int doGlob;
01845     const char *diskURL = NULL;
01846     int rc = 0;
01847     
01848     doGlob = Glob_pattern_p(fileURL, quote);
01849 
01850     /* Check that file starts with leading "/" */
01851     {   const char * fileName;
01852         (void) urlPath(fileURL, &fileName);
01853         if (*fileName != '/') {
01854             rpmError(RPMERR_BADSPEC, _("File needs leading \"/\": %s\n"),
01855                         fileName);
01856             rc = 1;
01857             goto exit;
01858         }
01859     }
01860     
01861     /* Copy file name or glob pattern removing multiple "/" chars. */
01862     /*
01863      * Note: rpmGetPath should guarantee a "canonical" path. That means
01864      * that the following pathologies should be weeded out:
01865      *          //bin//sh
01866      *          //usr//bin/
01867      *          /.././../usr/../bin//./sh
01868      */
01869     diskURL = rpmGenPath(fl->buildRootURL, NULL, fileURL);
01870 
01871     if (doGlob) {
01872         const char ** argv = NULL;
01873         int argc = 0;
01874         int i;
01875 
01876         /* XXX for %dev marker in file manifest only */
01877         if (fl->noGlob) {
01878             rpmError(RPMERR_BADSPEC, _("Glob not permitted: %s\n"),
01879                         diskURL);
01880             rc = 1;
01881             goto exit;
01882         }
01883 
01884         /*@-branchstate@*/
01885         rc = rpmGlob(diskURL, &argc, &argv);
01886         if (rc == 0 && argc >= 1 && !Glob_pattern_p(argv[0], quote)) {
01887             for (i = 0; i < argc; i++) {
01888                 rc = addFile(fl, argv[i], NULL);
01889 /*@-boundswrite@*/
01890                 argv[i] = _free(argv[i]);
01891 /*@=boundswrite@*/
01892             }
01893             argv = _free(argv);
01894         } else {
01895             rpmError(RPMERR_BADSPEC, _("File not found by glob: %s\n"),
01896                         diskURL);
01897             rc = 1;
01898             goto exit;
01899         }
01900         /*@=branchstate@*/
01901     } else {
01902         rc = addFile(fl, diskURL, NULL);
01903     }
01904 
01905 exit:
01906     diskURL = _free(diskURL);
01907     if (rc) {
01908         fl->processingFailed = 1;
01909         rc = RPMERR_BADSPEC;
01910     }
01911     return rc;
01912 }
01913 
01916 /*@-boundswrite@*/
01917 static int processPackageFiles(Spec spec, Package pkg,
01918                                int installSpecialDoc, int test)
01919         /*@globals rpmGlobalMacroContext, h_errno,
01920                 fileSystem, internalState@*/
01921         /*@modifies spec->macros,
01922                 pkg->cpioList, pkg->fileList, pkg->specialDoc, pkg->header,
01923                 rpmGlobalMacroContext, fileSystem, internalState @*/
01924 {
01925     HGE_t hge = (HGE_t)headerGetEntryMinMemory;
01926     struct FileList_s fl;
01927     char *s, **files, **fp;
01928     const char *fileName;
01929     char buf[BUFSIZ];
01930     struct AttrRec_s arbuf;
01931     AttrRec specialDocAttrRec = &arbuf;
01932     char *specialDoc = NULL;
01933 
01934     nullAttrRec(specialDocAttrRec);
01935     pkg->cpioList = NULL;
01936 
01937     if (pkg->fileFile) {
01938         const char *ffn;
01939         FILE * f;
01940         FD_t fd;
01941 
01942         /* XXX W2DO? urlPath might be useful here. */
01943         if (*pkg->fileFile == '/') {
01944             ffn = rpmGetPath(pkg->fileFile, NULL);
01945         } else {
01946             /* XXX FIXME: add %{_buildsubdir} */
01947             ffn = rpmGetPath("%{_builddir}/",
01948                 (spec->buildSubdir ? spec->buildSubdir : "") ,
01949                 "/", pkg->fileFile, NULL);
01950         }
01951         fd = Fopen(ffn, "r.fpio");
01952 
01953         if (fd == NULL || Ferror(fd)) {
01954             rpmError(RPMERR_BADFILENAME,
01955                 _("Could not open %%files file %s: %s\n"),
01956                 ffn, Fstrerror(fd));
01957             return RPMERR_BADFILENAME;
01958         }
01959         ffn = _free(ffn);
01960 
01961         /*@+voidabstract@*/ f = fdGetFp(fd); /*@=voidabstract@*/
01962         if (f != NULL)
01963         while (fgets(buf, sizeof(buf), f)) {
01964             handleComments(buf);
01965             if (expandMacros(spec, spec->macros, buf, sizeof(buf))) {
01966                 rpmError(RPMERR_BADSPEC, _("line: %s\n"), buf);
01967                 return RPMERR_BADSPEC;
01968             }
01969             appendStringBuf(pkg->fileList, buf);
01970         }
01971         (void) Fclose(fd);
01972     }
01973     
01974     /* Init the file list structure */
01975     memset(&fl, 0, sizeof(fl));
01976 
01977     /* XXX spec->buildRootURL == NULL, then xstrdup("") is returned */
01978     fl.buildRootURL = rpmGenPath(spec->rootURL, spec->buildRootURL, NULL);
01979 
01980     if (hge(pkg->header, RPMTAG_DEFAULTPREFIX, NULL, (void **)&fl.prefix, NULL))
01981         fl.prefix = xstrdup(fl.prefix);
01982     else
01983         fl.prefix = NULL;
01984 
01985     fl.fileCount = 0;
01986     fl.totalFileSize = 0;
01987     fl.processingFailed = 0;
01988 
01989     fl.passedSpecialDoc = 0;
01990     fl.isSpecialDoc = 0;
01991 
01992     fl.isDir = 0;
01993     fl.inFtw = 0;
01994     fl.currentFlags = 0;
01995     fl.currentVerifyFlags = 0;
01996     
01997     fl.noGlob = 0;
01998     fl.devtype = 0;
01999     fl.devmajor = 0;
02000     fl.devminor = 0;
02001 
02002     nullAttrRec(&fl.cur_ar);
02003     nullAttrRec(&fl.def_ar);
02004     dupAttrRec(&root_ar, &fl.def_ar);   /* XXX assume %defattr(-,root,root) */
02005 
02006     fl.defVerifyFlags = RPMVERIFY_ALL;
02007     fl.nLangs = 0;
02008     fl.currentLangs = NULL;
02009 
02010     fl.currentSpecdFlags = 0;
02011     fl.defSpecdFlags = 0;
02012 
02013     fl.docDirCount = 0;
02014     fl.docDirs[fl.docDirCount++] = xstrdup("/usr/doc");
02015     fl.docDirs[fl.docDirCount++] = xstrdup("/usr/man");
02016     fl.docDirs[fl.docDirCount++] = xstrdup("/usr/info");
02017     fl.docDirs[fl.docDirCount++] = xstrdup("/usr/X11R6/man");
02018     fl.docDirs[fl.docDirCount++] = xstrdup("/usr/share/doc");
02019     fl.docDirs[fl.docDirCount++] = xstrdup("/usr/share/man");
02020     fl.docDirs[fl.docDirCount++] = xstrdup("/usr/share/info");
02021     fl.docDirs[fl.docDirCount++] = rpmGetPath("%{_docdir}", NULL);
02022     fl.docDirs[fl.docDirCount++] = rpmGetPath("%{_mandir}", NULL);
02023     fl.docDirs[fl.docDirCount++] = rpmGetPath("%{_infodir}", NULL);
02024     fl.docDirs[fl.docDirCount++] = rpmGetPath("%{_javadocdir}", NULL);
02025     
02026     fl.fileList = NULL;
02027     fl.fileListRecsAlloced = 0;
02028     fl.fileListRecsUsed = 0;
02029 
02030     s = getStringBuf(pkg->fileList);
02031     files = splitString(s, strlen(s), '\n');
02032 
02033     for (fp = files; *fp != NULL; fp++) {
02034         s = *fp;
02035         SKIPSPACE(s);
02036         if (*s == '\0')
02037             continue;
02038         fileName = NULL;
02039         /*@-nullpass@*/ /* LCL: buf is NULL ?!? */
02040         strcpy(buf, s);
02041         /*@=nullpass@*/
02042         
02043         /* Reset for a new line in %files */
02044         fl.isDir = 0;
02045         fl.inFtw = 0;
02046         fl.currentFlags = 0;
02047         /* turn explicit flags into %def'd ones (gosh this is hacky...) */
02048         fl.currentSpecdFlags = ((unsigned)fl.defSpecdFlags) >> 8;
02049         fl.currentVerifyFlags = fl.defVerifyFlags;
02050         fl.isSpecialDoc = 0;
02051 
02052         fl.noGlob = 0;
02053         fl.devtype = 0;
02054         fl.devmajor = 0;
02055         fl.devminor = 0;
02056 
02057         /* XXX should reset to %deflang value */
02058         if (fl.currentLangs) {
02059             int i;
02060             for (i = 0; i < fl.nLangs; i++)
02061                 /*@-unqualifiedtrans@*/
02062                 fl.currentLangs[i] = _free(fl.currentLangs[i]);
02063                 /*@=unqualifiedtrans@*/
02064             fl.currentLangs = _free(fl.currentLangs);
02065         }
02066         fl.nLangs = 0;
02067 
02068         dupAttrRec(&fl.def_ar, &fl.cur_ar);
02069 
02070         /*@-nullpass@*/ /* LCL: buf is NULL ?!? */
02071         if (parseForVerify(buf, &fl))
02072             continue;
02073         if (parseForAttr(buf, &fl))
02074             continue;
02075         if (parseForDev(buf, &fl))
02076             continue;
02077         if (parseForConfig(buf, &fl))
02078             continue;
02079         if (parseForLang(buf, &fl))
02080             continue;
02081         /*@-nullstate@*/        /* FIX: pkg->fileFile might be NULL */
02082         if (parseForSimple(spec, pkg, buf, &fl, &fileName))
02083         /*@=nullstate@*/
02084             continue;
02085         /*@=nullpass@*/
02086         if (fileName == NULL)
02087             continue;
02088 
02089         /*@-branchstate@*/
02090         if (fl.isSpecialDoc) {
02091             /* Save this stuff for last */
02092             specialDoc = _free(specialDoc);
02093             specialDoc = xstrdup(fileName);
02094             dupAttrRec(&fl.cur_ar, specialDocAttrRec);
02095         } else if (fl.currentFlags & RPMFILE_PUBKEY) {
02096 /*@-nullstate@*/        /* FIX: pkg->fileFile might be NULL */
02097             (void) processMetadataFile(pkg, &fl, fileName, RPMTAG_PUBKEYS);
02098 /*@=nullstate@*/
02099         } else if (fl.currentFlags & RPMFILE_POLICY) {
02100 /*@-nullstate@*/        /* FIX: pkg->fileFile might be NULL */
02101             (void) processMetadataFile(pkg, &fl, fileName, RPMTAG_POLICIES);
02102 /*@=nullstate@*/
02103         } else {
02104 /*@-nullstate@*/        /* FIX: pkg->fileFile might be NULL */
02105             (void) processBinaryFile(pkg, &fl, fileName);
02106 /*@=nullstate@*/
02107         }
02108         /*@=branchstate@*/
02109     }
02110 
02111     /* Now process special doc, if there is one */
02112     if (specialDoc) {
02113         if (installSpecialDoc) {
02114             int _missing_doc_files_terminate_build =
02115                     rpmExpandNumeric("%{?_missing_doc_files_terminate_build}");
02116             int rc;
02117 
02118             rc = doScript(spec, RPMBUILD_STRINGBUF, "%doc", pkg->specialDoc, test);
02119             if (rc && _missing_doc_files_terminate_build)
02120                 fl.processingFailed = rc;
02121         }
02122 
02123         /* Reset for %doc */
02124         fl.isDir = 0;
02125         fl.inFtw = 0;
02126         fl.currentFlags = 0;
02127         fl.currentVerifyFlags = 0;
02128 
02129         fl.noGlob = 0;
02130         fl.devtype = 0;
02131         fl.devmajor = 0;
02132         fl.devminor = 0;
02133 
02134         /* XXX should reset to %deflang value */
02135         if (fl.currentLangs) {
02136             int i;
02137             for (i = 0; i < fl.nLangs; i++)
02138                 /*@-unqualifiedtrans@*/
02139                 fl.currentLangs[i] = _free(fl.currentLangs[i]);
02140                 /*@=unqualifiedtrans@*/
02141             fl.currentLangs = _free(fl.currentLangs);
02142         }
02143         fl.nLangs = 0;
02144 
02145         dupAttrRec(specialDocAttrRec, &fl.cur_ar);
02146         freeAttrRec(specialDocAttrRec);
02147 
02148         /*@-nullstate@*/        /* FIX: pkg->fileFile might be NULL */
02149         (void) processBinaryFile(pkg, &fl, specialDoc);
02150         /*@=nullstate@*/
02151 
02152         specialDoc = _free(specialDoc);
02153     }
02154     
02155     freeSplitString(files);
02156 
02157     if (fl.processingFailed)
02158         goto exit;
02159 
02160     /* Verify that file attributes scope over hardlinks correctly. */
02161     if (checkHardLinks(&fl))
02162         (void) rpmlibNeedsFeature(pkg->header,
02163                         "PartialHardlinkSets", "4.0.4-1");
02164 
02165     genCpioListAndHeader(&fl, &pkg->cpioList, pkg->header, 0);
02166 
02167     if (spec->timeCheck)
02168         timeCheck(spec->timeCheck, pkg->header);
02169     
02170 exit:
02171     fl.buildRootURL = _free(fl.buildRootURL);
02172     fl.prefix = _free(fl.prefix);
02173 
02174     freeAttrRec(&fl.cur_ar);
02175     freeAttrRec(&fl.def_ar);
02176 
02177     if (fl.currentLangs) {
02178         int i;
02179         for (i = 0; i < fl.nLangs; i++)
02180             /*@-unqualifiedtrans@*/
02181             fl.currentLangs[i] = _free(fl.currentLangs[i]);
02182             /*@=unqualifiedtrans@*/
02183         fl.currentLangs = _free(fl.currentLangs);
02184     }
02185 
02186     fl.fileList = freeFileList(fl.fileList, fl.fileListRecsUsed);
02187     while (fl.docDirCount--)
02188         fl.docDirs[fl.docDirCount] = _free(fl.docDirs[fl.docDirCount]);
02189     return fl.processingFailed;
02190 }
02191 /*@=boundswrite@*/
02192 
02193 void initSourceHeader(Spec spec)
02194 {
02195     HeaderIterator hi;
02196     int_32 tag, type, count;
02197     const void * ptr;
02198 
02199     spec->sourceHeader = headerNew();
02200     /* Only specific tags are added to the source package header */
02201     /*@-branchstate@*/
02202     for (hi = headerInitIterator(spec->packages->header);
02203         headerNextIterator(hi, &tag, &type, &ptr, &count);
02204         ptr = headerFreeData(ptr, type))
02205     {
02206         switch (tag) {
02207         case RPMTAG_NAME:
02208         case RPMTAG_VERSION:
02209         case RPMTAG_RELEASE:
02210         case RPMTAG_EPOCH:
02211         case RPMTAG_SUMMARY:
02212         case RPMTAG_DESCRIPTION:
02213         case RPMTAG_PACKAGER:
02214         case RPMTAG_DISTRIBUTION:
02215         case RPMTAG_DISTURL:
02216         case RPMTAG_VENDOR:
02217         case RPMTAG_LICENSE:
02218         case RPMTAG_GROUP:
02219         case RPMTAG_OS:
02220         case RPMTAG_ARCH:
02221         case RPMTAG_CHANGELOGTIME:
02222         case RPMTAG_CHANGELOGNAME:
02223         case RPMTAG_CHANGELOGTEXT:
02224         case RPMTAG_URL:
02225         case HEADER_I18NTABLE:
02226             if (ptr)
02227                 (void)headerAddEntry(spec->sourceHeader, tag, type, ptr, count);
02228             /*@switchbreak@*/ break;
02229         default:
02230             /* do not copy */
02231             /*@switchbreak@*/ break;
02232         }
02233     }
02234     hi = headerFreeIterator(hi);
02235     /*@=branchstate@*/
02236 
02237     /* Add the build restrictions */
02238     /*@-branchstate@*/
02239     for (hi = headerInitIterator(spec->buildRestrictions);
02240         headerNextIterator(hi, &tag, &type, &ptr, &count);
02241         ptr = headerFreeData(ptr, type))
02242     {
02243         if (ptr)
02244             (void) headerAddEntry(spec->sourceHeader, tag, type, ptr, count);
02245     }
02246     hi = headerFreeIterator(hi);
02247     /*@=branchstate@*/
02248 
02249     if (spec->BANames && spec->BACount > 0) {
02250         (void) headerAddEntry(spec->sourceHeader, RPMTAG_BUILDARCHS,
02251                        RPM_STRING_ARRAY_TYPE,
02252                        spec->BANames, spec->BACount);
02253     }
02254 }
02255 
02256 int processSourceFiles(Spec spec)
02257 {
02258     struct Source *srcPtr;
02259     StringBuf sourceFiles;
02260     int x, isSpec = 1;
02261     struct FileList_s fl;
02262     char *s, **files, **fp;
02263     Package pkg;
02264 
02265     sourceFiles = newStringBuf();
02266 
02267     /* XXX
02268      * XXX This is where the source header for noarch packages needs
02269      * XXX to be initialized.
02270      */
02271     if (spec->sourceHeader == NULL)
02272         initSourceHeader(spec);
02273 
02274     /* Construct the file list and source entries */
02275     appendLineStringBuf(sourceFiles, spec->specFile);
02276     if (spec->sourceHeader != NULL)
02277     for (srcPtr = spec->sources; srcPtr != NULL; srcPtr = srcPtr->next) {
02278         if (srcPtr->flags & RPMBUILD_ISSOURCE) {
02279             (void) headerAddOrAppendEntry(spec->sourceHeader, RPMTAG_SOURCE,
02280                                    RPM_STRING_ARRAY_TYPE, &srcPtr->source, 1);
02281             if (srcPtr->flags & RPMBUILD_ISNO) {
02282                 (void) headerAddOrAppendEntry(spec->sourceHeader, RPMTAG_NOSOURCE,
02283                                        RPM_INT32_TYPE, &srcPtr->num, 1);
02284             }
02285         }
02286         if (srcPtr->flags & RPMBUILD_ISPATCH) {
02287             (void) headerAddOrAppendEntry(spec->sourceHeader, RPMTAG_PATCH,
02288                                    RPM_STRING_ARRAY_TYPE, &srcPtr->source, 1);
02289             if (srcPtr->flags & RPMBUILD_ISNO) {
02290                 (void) headerAddOrAppendEntry(spec->sourceHeader, RPMTAG_NOPATCH,
02291                                        RPM_INT32_TYPE, &srcPtr->num, 1);
02292             }
02293         }
02294 
02295       { const char * sfn;
02296         sfn = rpmGetPath( ((srcPtr->flags & RPMBUILD_ISNO) ? "!" : ""),
02297                 "%{_sourcedir}/", srcPtr->source, NULL);
02298         appendLineStringBuf(sourceFiles, sfn);
02299         sfn = _free(sfn);
02300       }
02301     }
02302 
02303     for (pkg = spec->packages; pkg != NULL; pkg = pkg->next) {
02304         for (srcPtr = pkg->icon; srcPtr != NULL; srcPtr = srcPtr->next) {
02305             const char * sfn;
02306             sfn = rpmGetPath( ((srcPtr->flags & RPMBUILD_ISNO) ? "!" : ""),
02307                 "%{_sourcedir}/", srcPtr->source, NULL);
02308             appendLineStringBuf(sourceFiles, sfn);
02309             sfn = _free(sfn);
02310         }
02311     }
02312 
02313     spec->sourceCpioList = NULL;
02314 
02315     fl.fileList = xcalloc((spec->numSources + 1), sizeof(*fl.fileList));
02316     fl.processingFailed = 0;
02317     fl.fileListRecsUsed = 0;
02318     fl.totalFileSize = 0;
02319     fl.prefix = NULL;
02320     fl.buildRootURL = NULL;
02321 
02322     s = getStringBuf(sourceFiles);
02323     files = splitString(s, strlen(s), '\n');
02324 
02325     /* The first source file is the spec file */
02326     x = 0;
02327     for (fp = files; *fp != NULL; fp++) {
02328         const char * diskURL, *diskPath;
02329         FileListRec flp;
02330 
02331         diskURL = *fp;
02332         SKIPSPACE(diskURL);
02333         if (! *diskURL)
02334             continue;
02335 
02336         flp = &fl.fileList[x];
02337 
02338         flp->flags = isSpec ? RPMFILE_SPECFILE : 0;
02339         /* files with leading ! are no source files */
02340         if (*diskURL == '!') {
02341             flp->flags |= RPMFILE_GHOST;
02342             diskURL++;
02343         }
02344 
02345         (void) urlPath(diskURL, &diskPath);
02346 
02347         flp->diskURL = xstrdup(diskURL);
02348         diskPath = strrchr(diskPath, '/');
02349         if (diskPath)
02350             diskPath++;
02351         else
02352             diskPath = diskURL;
02353 
02354         flp->fileURL = xstrdup(diskPath);
02355         flp->verifyFlags = RPMVERIFY_ALL;
02356 
02357         if (Stat(diskURL, &flp->fl_st)) {
02358             rpmError(RPMERR_BADSPEC, _("Bad file: %s: %s\n"),
02359                 diskURL, strerror(errno));
02360             fl.processingFailed = 1;
02361         }
02362 
02363         flp->uname = getUname(flp->fl_uid);
02364         flp->gname = getGname(flp->fl_gid);
02365         flp->langs = xstrdup("");
02366         
02367         fl.totalFileSize += flp->fl_size;
02368         
02369         if (! (flp->uname && flp->gname)) {
02370             rpmError(RPMERR_BADSPEC, _("Bad owner/group: %s\n"), diskURL);
02371             fl.processingFailed = 1;
02372         }
02373 
02374         isSpec = 0;
02375         x++;
02376     }
02377     fl.fileListRecsUsed = x;
02378     freeSplitString(files);
02379 
02380     if (! fl.processingFailed) {
02381         if (spec->sourceHeader != NULL)
02382             genCpioListAndHeader(&fl, &spec->sourceCpioList,
02383                         spec->sourceHeader, 1);
02384     }
02385 
02386     sourceFiles = freeStringBuf(sourceFiles);
02387     fl.fileList = freeFileList(fl.fileList, fl.fileListRecsUsed);
02388     return fl.processingFailed;
02389 }
02390 
02396 static int checkFiles(StringBuf fileList)
02397         /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/
02398         /*@modifies rpmGlobalMacroContext, fileSystem, internalState @*/
02399 {
02400 /*@-readonlytrans@*/
02401     static const char * av_ckfile[] = { "%{?__check_files}", NULL };
02402 /*@=readonlytrans@*/
02403     StringBuf sb_stdout = NULL;
02404     const char * s;
02405     int rc;
02406     
02407     s = rpmExpand(av_ckfile[0], NULL);
02408     if (!(s && *s)) {
02409         rc = -1;
02410         goto exit;
02411     }
02412     rc = 0;
02413 
02414     rpmMessage(RPMMESS_NORMAL, _("Checking for unpackaged file(s): %s\n"), s);
02415 
02416 /*@-boundswrite@*/
02417     rc = rpmfcExec(av_ckfile, fileList, &sb_stdout, 0);
02418 /*@=boundswrite@*/
02419     if (rc < 0)
02420         goto exit;
02421     
02422     if (sb_stdout) {
02423         int _unpackaged_files_terminate_build =
02424                 rpmExpandNumeric("%{?_unpackaged_files_terminate_build}");
02425         const char * t;
02426 
02427         t = getStringBuf(sb_stdout);
02428         if ((*t != '\0') && (*t != '\n')) {
02429             rc = (_unpackaged_files_terminate_build) ? 1 : 0;
02430             rpmMessage((rc ? RPMMESS_ERROR : RPMMESS_WARNING),
02431                 _("Installed (but unpackaged) file(s) found:\n%s"), t);
02432         }
02433     }
02434     
02435 exit:
02436     sb_stdout = freeStringBuf(sb_stdout);
02437     s = _free(s);
02438     return rc;
02439 }
02440 
02441 /*@-incondefs@*/
02442 int processBinaryFiles(Spec spec, int installSpecialDoc, int test)
02443         /*@globals check_fileList @*/
02444         /*@modifies check_fileList @*/
02445 {
02446     Package pkg;
02447     int res = 0;
02448     
02449     check_fileList = newStringBuf();
02450     
02451     for (pkg = spec->packages; pkg != NULL; pkg = pkg->next) {
02452         const char *n, *v, *r;
02453         int rc;
02454 
02455         if (pkg->fileList == NULL)
02456             continue;
02457 
02458         (void) headerNVR(pkg->header, &n, &v, &r);
02459         rpmMessage(RPMMESS_NORMAL, _("Processing files: %s-%s-%s\n"), n, v, r);
02460                    
02461         if ((rc = processPackageFiles(spec, pkg, installSpecialDoc, test)))
02462             res = rc;
02463 
02464         (void) rpmfcGenerateDepends(spec, pkg);
02465 
02466     }
02467 
02468     /* Now we have in fileList list of files from all packages.
02469      * We pass it to a script which does the work of finding missing
02470      * and duplicated files.
02471      */
02472     
02473     if (res == 0)  {
02474         if (checkFiles(check_fileList) > 0)
02475             res = 1;
02476     }
02477     
02478     check_fileList = freeStringBuf(check_fileList);
02479     
02480     return res;
02481 }
02482 /*@=incondefs@*/

Generated on Wed Jan 28 12:45:23 2009 for rpm by  doxygen 1.4.7