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            {
01010                 static char *_docdir_fmt= 0;
01011                 static int oneshot = 0;
01012                 const char *ddir, *fmt, *errstr;
01013                 if (!oneshot) {
01014                     _docdir_fmt = rpmExpand("%{?_docdir_fmt}", NULL);
01015                     if (!_docdir_fmt || !*_docdir_fmt)
01016                         _docdir_fmt = "%{NAME}-%{VERSION}";
01017                     oneshot = 1;
01018                 }
01019                 fmt = headerSprintf(pkg->header, _docdir_fmt, rpmTagTable, rpmHeaderFormats, &errstr);
01020                 if (!fmt) {
01021                     rpmError(RPMERR_BADSPEC, _("illegal _docdir_fmt: %s\n"), errstr);
01022                     fl->processingFailed = 1;
01023                     res = 1;
01024                 }
01025                 ddir = rpmGetPath("%{_docdir}/", fmt, NULL);
01026                 strcpy(buf, ddir);
01027                 ddir = _free(ddir);
01028             }
01029 
01030         /* XXX FIXME: this is easy to do as macro expansion */
01031 
01032             if (! fl->passedSpecialDoc) {
01033                 pkg->specialDoc = newStringBuf();
01034                 appendStringBuf(pkg->specialDoc, "DOCDIR=$RPM_BUILD_ROOT");
01035                 appendLineStringBuf(pkg->specialDoc, buf);
01036                 appendLineStringBuf(pkg->specialDoc, "export DOCDIR");
01037                 appendLineStringBuf(pkg->specialDoc, "rm -rf $DOCDIR");
01038                 appendLineStringBuf(pkg->specialDoc, MKDIR_P " $DOCDIR");
01039 
01040                 /*@-temptrans@*/
01041                 *fileName = buf;
01042                 /*@=temptrans@*/
01043                 fl->passedSpecialDoc = 1;
01044                 fl->isSpecialDoc = 1;
01045             }
01046 
01047             appendStringBuf(pkg->specialDoc, "cp -pr ");
01048             appendStringBuf(pkg->specialDoc, specialDocBuf);
01049             appendLineStringBuf(pkg->specialDoc, " $DOCDIR");
01050         }
01051     }
01052 
01053     return res;
01054 }
01055 /*@=boundswrite@*/
01056 
01059 static int compareFileListRecs(const void * ap, const void * bp)        /*@*/
01060 {
01061     const char *a = ((FileListRec)ap)->fileURL;
01062     const char *b = ((FileListRec)bp)->fileURL;
01063     return strcmp(a, b);
01064 }
01065 
01072 static int isDoc(FileList fl, const char * fileName)    /*@*/
01073 {
01074     int x = fl->docDirCount;
01075     size_t k, l;
01076 
01077     k = strlen(fileName);
01078     while (x--) {
01079         l = strlen(fl->docDirs[x]);
01080         if (l < k && strncmp(fileName, fl->docDirs[x], l) == 0 && fileName[l] == '/')
01081             return 1;
01082     }
01083     return 0;
01084 }
01085 
01092 static int checkHardLinks(FileList fl)
01093         /*@*/
01094 {
01095     FileListRec ilp, jlp;
01096     int i, j;
01097 
01098     for (i = 0;  i < fl->fileListRecsUsed; i++) {
01099         ilp = fl->fileList + i;
01100         if (!(S_ISREG(ilp->fl_mode) && ilp->fl_nlink > 1))
01101             continue;
01102 
01103         for (j = i + 1; j < fl->fileListRecsUsed; j++) {
01104             jlp = fl->fileList + j;
01105             if (!S_ISREG(jlp->fl_mode))
01106                 /*@innercontinue@*/ continue;
01107             if (ilp->fl_nlink != jlp->fl_nlink)
01108                 /*@innercontinue@*/ continue;
01109             if (ilp->fl_ino != jlp->fl_ino)
01110                 /*@innercontinue@*/ continue;
01111             if (ilp->fl_dev != jlp->fl_dev)
01112                 /*@innercontinue@*/ continue;
01113             return 1;
01114         }
01115     }
01116     return 0;
01117 }
01118 
01128 /*@-bounds@*/
01129 static void genCpioListAndHeader(/*@partial@*/ FileList fl,
01130                 rpmfi * fip, Header h, int isSrc)
01131         /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/
01132         /*@modifies h, *fip, fl->processingFailed, fl->fileList,
01133                 rpmGlobalMacroContext, fileSystem, internalState @*/
01134 {
01135     int _addDotSlash = !(isSrc || rpmExpandNumeric("%{_noPayloadPrefix}"));
01136     int apathlen = 0;
01137     int dpathlen = 0;
01138     int skipLen = 0;
01139     security_context_t scon = NULL;
01140     const char * sxfn;
01141     size_t fnlen;
01142     FileListRec flp;
01143     char buf[BUFSIZ];
01144     int i;
01145     
01146     /* Sort the big list */
01147     qsort(fl->fileList, fl->fileListRecsUsed,
01148           sizeof(*(fl->fileList)), compareFileListRecs);
01149     
01150     /* Generate the header. */
01151     if (! isSrc) {
01152         skipLen = 1;
01153         if (fl->prefix)
01154             skipLen += strlen(fl->prefix);
01155     }
01156 
01157     sxfn = rpmGetPath("%{?_build_file_context_path}", NULL);
01158     if (sxfn != NULL && *sxfn != '\0')
01159         matchpathcon_init(sxfn);
01160 
01161     for (i = 0, flp = fl->fileList; i < fl->fileListRecsUsed; i++, flp++) {
01162         const 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         /*
01225          * Make the header, the OLDFILENAMES will get converted to a 
01226          * compressed file list write before we write the actual package to
01227          * disk.
01228          */
01229         (void) headerAddOrAppendEntry(h, RPMTAG_OLDFILENAMES, RPM_STRING_ARRAY_TYPE,
01230                                &(flp->fileURL), 1);
01231 
01232 /*@-sizeoftype@*/
01233       if (sizeof(flp->fl_size) != sizeof(uint_32)) {
01234         uint_32 psize = (uint_32)flp->fl_size;
01235         (void) headerAddOrAppendEntry(h, RPMTAG_FILESIZES, RPM_INT32_TYPE,
01236                                &(psize), 1);
01237       } else {
01238         (void) headerAddOrAppendEntry(h, RPMTAG_FILESIZES, RPM_INT32_TYPE,
01239                                &(flp->fl_size), 1);
01240       }
01241         (void) headerAddOrAppendEntry(h, RPMTAG_FILEUSERNAME, RPM_STRING_ARRAY_TYPE,
01242                                &(flp->uname), 1);
01243         (void) headerAddOrAppendEntry(h, RPMTAG_FILEGROUPNAME, RPM_STRING_ARRAY_TYPE,
01244                                &(flp->gname), 1);
01245       if (sizeof(flp->fl_mtime) != sizeof(uint_32)) {
01246         uint_32 mtime = (uint_32)flp->fl_mtime;
01247         (void) headerAddOrAppendEntry(h, RPMTAG_FILEMTIMES, RPM_INT32_TYPE,
01248                                &(mtime), 1);
01249       } else {
01250         (void) headerAddOrAppendEntry(h, RPMTAG_FILEMTIMES, RPM_INT32_TYPE,
01251                                &(flp->fl_mtime), 1);
01252       }
01253       if (sizeof(flp->fl_mode) != sizeof(uint_16)) {
01254         uint_16 pmode = (uint_16)flp->fl_mode;
01255         (void) headerAddOrAppendEntry(h, RPMTAG_FILEMODES, RPM_INT16_TYPE,
01256                                &(pmode), 1);
01257       } else {
01258         (void) headerAddOrAppendEntry(h, RPMTAG_FILEMODES, RPM_INT16_TYPE,
01259                                &(flp->fl_mode), 1);
01260       }
01261       if (sizeof(flp->fl_rdev) != sizeof(uint_16)) {
01262         uint_16 prdev = (uint_16)flp->fl_rdev;
01263         (void) headerAddOrAppendEntry(h, RPMTAG_FILERDEVS, RPM_INT16_TYPE,
01264                                &(prdev), 1);
01265       } else {
01266         (void) headerAddOrAppendEntry(h, RPMTAG_FILERDEVS, RPM_INT16_TYPE,
01267                                &(flp->fl_rdev), 1);
01268       }
01269       if (sizeof(flp->fl_dev) != sizeof(uint_32)) {
01270         uint_32 pdevice = (uint_32)flp->fl_dev;
01271         (void) headerAddOrAppendEntry(h, RPMTAG_FILEDEVICES, RPM_INT32_TYPE,
01272                                &(pdevice), 1);
01273       } else {
01274         (void) headerAddOrAppendEntry(h, RPMTAG_FILEDEVICES, RPM_INT32_TYPE,
01275                                &(flp->fl_dev), 1);
01276       }
01277       if (sizeof(flp->fl_ino) != sizeof(uint_32)) {
01278         uint_32 ino = (uint_32)flp->fl_ino;
01279         (void) headerAddOrAppendEntry(h, RPMTAG_FILEINODES, RPM_INT32_TYPE,
01280                                 &(ino), 1);
01281       } else {
01282         (void) headerAddOrAppendEntry(h, RPMTAG_FILEINODES, RPM_INT32_TYPE,
01283                                 &(flp->fl_ino), 1);
01284       }
01285 /*@=sizeoftype@*/
01286 
01287         (void) headerAddOrAppendEntry(h, RPMTAG_FILELANGS, RPM_STRING_ARRAY_TYPE,
01288                                &(flp->langs),  1);
01289         
01290         /* We used to add these, but they should not be needed */
01291         /* (void) headerAddOrAppendEntry(h, RPMTAG_FILEUIDS,
01292          *                 RPM_INT32_TYPE, &(flp->fl_uid), 1);
01293          * (void) headerAddOrAppendEntry(h, RPMTAG_FILEGIDS,
01294          *                 RPM_INT32_TYPE, &(flp->fl_gid), 1);
01295          */
01296         
01297         buf[0] = '\0';
01298         if (S_ISREG(flp->fl_mode))
01299             (void) domd5(flp->diskURL, buf, 1, NULL);
01300         s = buf;
01301         (void) headerAddOrAppendEntry(h, RPMTAG_FILEMD5S, RPM_STRING_ARRAY_TYPE,
01302                                &s, 1);
01303         
01304         buf[0] = '\0';
01305         if (S_ISLNK(flp->fl_mode)) {
01306             buf[Readlink(flp->diskURL, buf, BUFSIZ)] = '\0';
01307             if (fl->buildRootURL) {
01308                 const char * buildRoot;
01309                 (void) urlPath(fl->buildRootURL, &buildRoot);
01310 
01311                 if (buf[0] == '/' && strcmp(buildRoot, "/") &&
01312                     !strncmp(buf, buildRoot, strlen(buildRoot))) {
01313                      rpmError(RPMERR_BADSPEC,
01314                                 _("Symlink points to BuildRoot: %s -> %s\n"),
01315                                 flp->fileURL, buf);
01316                     fl->processingFailed = 1;
01317                 }
01318             }
01319         }
01320         s = buf;
01321         (void) headerAddOrAppendEntry(h, RPMTAG_FILELINKTOS, RPM_STRING_ARRAY_TYPE,
01322                                &s, 1);
01323         
01324         if (flp->flags & RPMFILE_GHOST) {
01325             flp->verifyFlags &= ~(RPMVERIFY_MD5 | RPMVERIFY_FILESIZE |
01326                                 RPMVERIFY_LINKTO | RPMVERIFY_MTIME);
01327         }
01328         (void) headerAddOrAppendEntry(h, RPMTAG_FILEVERIFYFLAGS, RPM_INT32_TYPE,
01329                                &(flp->verifyFlags), 1);
01330         
01331         if (!isSrc && isDoc(fl, flp->fileURL))
01332             flp->flags |= RPMFILE_DOC;
01333         /* XXX Should directories have %doc/%config attributes? (#14531) */
01334         if (S_ISDIR(flp->fl_mode))
01335             flp->flags &= ~(RPMFILE_CONFIG|RPMFILE_DOC);
01336 
01337         (void) headerAddOrAppendEntry(h, RPMTAG_FILEFLAGS, RPM_INT32_TYPE,
01338                                &(flp->flags), 1);
01339 
01340         /* Add file security context to package. */
01341         mode_t fmode = (uint_16)flp->fl_mode;
01342         int rc = matchpathcon(flp->fileURL, fmode, &scon);
01343         if ( rc == 0 && scon != NULL) {
01344             (void) headerAddOrAppendEntry(h, RPMTAG_FILECONTEXTS, RPM_STRING_ARRAY_TYPE, &scon, 1);
01345             freecon(scon);
01346         }
01347         else  {
01348             const char *nocon = "";
01349             (void) headerAddOrAppendEntry(h, RPMTAG_FILECONTEXTS, RPM_STRING_ARRAY_TYPE, &nocon, 1);
01350         }
01351 
01352 
01353     }
01354     sxfn = _free(sxfn);
01355 
01356     (void) headerAddEntry(h, RPMTAG_SIZE, RPM_INT32_TYPE,
01357                    &(fl->totalFileSize), 1);
01358 
01359     if (_addDotSlash)
01360         (void) rpmlibNeedsFeature(h, "PayloadFilesHavePrefix", "4.0-1");
01361 
01362     /* Choose how filenames are represented. */
01363     if (_noDirTokens)
01364         expandFilelist(h);
01365     else {
01366         compressFilelist(h);
01367         /* Binary packages with dirNames cannot be installed by legacy rpm. */
01368         (void) rpmlibNeedsFeature(h, "CompressedFileNames", "3.0.4-1");
01369     }
01370 
01371   { int scareMem = 0;
01372     rpmts ts = NULL;    /* XXX FIXME drill rpmts ts all the way down here */
01373     rpmfi fi = rpmfiNew(ts, h, RPMTAG_BASENAMES, scareMem);
01374     char * a, * d;
01375 
01376     if (fi == NULL) return;             /* XXX can't happen */
01377 
01378 /*@-onlytrans@*/
01379     fi->te = xcalloc(1, sizeof(*fi->te));
01380 /*@=onlytrans@*/
01381     fi->te->type = TR_ADDED;
01382 
01383     fi->dnl = _free(fi->dnl);
01384     fi->bnl = _free(fi->bnl);
01385     if (!scareMem) fi->dil = _free(fi->dil);
01386 
01387     fi->dnl = xmalloc(fi->fc * sizeof(*fi->dnl) + dpathlen);
01388     d = (char *)(fi->dnl + fi->fc);
01389     *d = '\0';
01390 
01391     fi->bnl = xmalloc(fi->fc * (sizeof(*fi->bnl) + sizeof(*fi->dil)));
01392 /*@-dependenttrans@*/ /* FIX: artifact of spoofing headerGetEntry */
01393     fi->dil = (!scareMem)
01394         ? xcalloc(sizeof(*fi->dil), fi->fc)
01395         : (int *)(fi->bnl + fi->fc);
01396 /*@=dependenttrans@*/
01397 
01398     fi->apath = xmalloc(fi->fc * sizeof(*fi->apath) + apathlen + 1);
01399     a = (char *)(fi->apath + fi->fc);
01400     *a = '\0';
01401 
01402     fi->actions = xcalloc(sizeof(*fi->actions), fi->fc);
01403     fi->fmapflags = xcalloc(sizeof(*fi->fmapflags), fi->fc);
01404     fi->astriplen = 0;
01405     if (fl->buildRootURL)
01406         fi->astriplen = strlen(fl->buildRootURL);
01407     fi->striplen = 0;
01408     fi->fuser = NULL;
01409     fi->fgroup = NULL;
01410 
01411     /* Make the cpio list */
01412     if (fi->dil != NULL)        /* XXX can't happen */
01413     for (i = 0, flp = fl->fileList; i < fi->fc; i++, flp++) {
01414         char * b;
01415 
01416         /* Skip (possible) duplicate file entries, use last entry info. */
01417         while (((flp - fl->fileList) < (fl->fileListRecsUsed - 1)) &&
01418                 !strcmp(flp->fileURL, flp[1].fileURL))
01419             flp++;
01420 
01421         if (flp->flags & RPMFILE_EXCLUDE) {
01422             i--;
01423             continue;
01424         }
01425 
01426         if ((fnlen = strlen(flp->diskURL) + 1) > fi->fnlen)
01427             fi->fnlen = fnlen;
01428 
01429         /* Create disk directory and base name. */
01430         fi->dil[i] = i;
01431 /*@-dependenttrans@*/ /* FIX: artifact of spoofing headerGetEntry */
01432         fi->dnl[fi->dil[i]] = d;
01433 /*@=dependenttrans@*/
01434         d = stpcpy(d, flp->diskURL);
01435 
01436         /* Make room for the dirName NUL, find start of baseName. */
01437         for (b = d; b > fi->dnl[fi->dil[i]] && *b != '/'; b--)
01438             b[1] = b[0];
01439         b++;            /* dirname's end in '/' */
01440         *b++ = '\0';    /* terminate dirname, b points to basename */
01441         fi->bnl[i] = b;
01442         d += 2;         /* skip both dirname and basename NUL's */
01443 
01444         /* Create archive path, normally adding "./" */
01445         /*@-dependenttrans@*/   /* FIX: xstrdup? nah ... */
01446         fi->apath[i] = a;
01447         /*@=dependenttrans@*/
01448         if (_addDotSlash)
01449             a = stpcpy(a, "./");
01450         a = stpcpy(a, (flp->fileURL + skipLen));
01451         a++;            /* skip apath NUL */
01452 
01453         if (flp->flags & RPMFILE_GHOST) {
01454             fi->actions[i] = FA_SKIP;
01455             continue;
01456         }
01457         fi->actions[i] = FA_COPYOUT;
01458         fi->fmapflags[i] = CPIO_MAP_PATH |
01459                 CPIO_MAP_TYPE | CPIO_MAP_MODE | CPIO_MAP_UID | CPIO_MAP_GID;
01460         if (isSrc)
01461             fi->fmapflags[i] |= CPIO_FOLLOW_SYMLINKS;
01462 
01463     }
01464     /*@-branchstate -compdef@*/
01465     if (fip)
01466         *fip = fi;
01467     else
01468         fi = rpmfiFree(fi);
01469     /*@=branchstate =compdef@*/
01470   }
01471 }
01472 /*@=bounds@*/
01473 
01476 /*@-boundswrite@*/
01477 static /*@null@*/ FileListRec freeFileList(/*@only@*/ FileListRec fileList,
01478                         int count)
01479         /*@*/
01480 {
01481     while (count--) {
01482         fileList[count].diskURL = _free(fileList[count].diskURL);
01483         fileList[count].fileURL = _free(fileList[count].fileURL);
01484         fileList[count].langs = _free(fileList[count].langs);
01485     }
01486     fileList = _free(fileList);
01487     return NULL;
01488 }
01489 /*@=boundswrite@*/
01490 
01491 /* forward ref */
01492 static int recurseDir(FileList fl, const char * diskURL)
01493         /*@globals check_fileList, rpmGlobalMacroContext, h_errno,
01494                 fileSystem, internalState @*/
01495         /*@modifies *fl, fl->processingFailed,
01496                 fl->fileList, fl->fileListRecsAlloced, fl->fileListRecsUsed,
01497                 fl->totalFileSize, fl->fileCount, fl->inFtw, fl->isDir,
01498                 check_fileList, rpmGlobalMacroContext,
01499                 fileSystem, internalState @*/;
01500 
01508 /*@-boundswrite@*/
01509 static int addFile(FileList fl, const char * diskURL,
01510                 /*@null@*/ struct stat * statp)
01511         /*@globals check_fileList, rpmGlobalMacroContext, h_errno,
01512                 fileSystem, internalState @*/
01513         /*@modifies *statp, *fl, fl->processingFailed,
01514                 fl->fileList, fl->fileListRecsAlloced, fl->fileListRecsUsed,
01515                 fl->totalFileSize, fl->fileCount,
01516                 check_fileList, rpmGlobalMacroContext,
01517                 fileSystem, internalState @*/
01518 {
01519     const char *fileURL = diskURL;
01520     struct stat statbuf;
01521     mode_t fileMode;
01522     uid_t fileUid;
01523     gid_t fileGid;
01524     const char *fileUname;
01525     const char *fileGname;
01526     char *lang;
01527     
01528     /* Path may have prepended buildRootURL, so locate the original filename. */
01529     /*
01530      * XXX There are 3 types of entry into addFile:
01531      *
01532      *  From                    diskUrl                 statp
01533      *  =====================================================
01534      *  processBinaryFile       path                    NULL
01535      *  processBinaryFile       glob result path        NULL
01536      *  myftw                   path                    stat
01537      *
01538      */
01539     {   const char *fileName;
01540         (void) urlPath(fileURL, &fileName);
01541         if (fl->buildRootURL && strcmp(fl->buildRootURL, "/"))
01542             fileURL += strlen(fl->buildRootURL);
01543     }
01544 
01545     /* XXX make sure '/' can be packaged also */
01546     /*@-branchstate@*/
01547     if (*fileURL == '\0')
01548         fileURL = "/";
01549     /*@=branchstate@*/
01550 
01551     /* If we are using a prefix, validate the file */
01552     if (!fl->inFtw && fl->prefix) {
01553         const char *prefixTest;
01554         const char *prefixPtr = fl->prefix;
01555 
01556         (void) urlPath(fileURL, &prefixTest);
01557         while (*prefixPtr && *prefixTest && (*prefixTest == *prefixPtr)) {
01558             prefixPtr++;
01559             prefixTest++;
01560         }
01561         if (*prefixPtr || (*prefixTest && *prefixTest != '/')) {
01562             rpmError(RPMERR_BADSPEC, _("File doesn't match prefix (%s): %s\n"),
01563                      fl->prefix, fileURL);
01564             fl->processingFailed = 1;
01565             return RPMERR_BADSPEC;
01566         }
01567     }
01568 
01569     if (statp == NULL) {
01570         statp = &statbuf;
01571         memset(statp, 0, sizeof(*statp));
01572         if (fl->devtype) {
01573             time_t now = time(NULL);
01574 
01575             /* XXX hack up a stat structure for a %dev(...) directive. */
01576             statp->st_nlink = 1;
01577             statp->st_rdev =
01578                 ((fl->devmajor & 0xff) << 8) | (fl->devminor & 0xff);
01579             statp->st_dev = statp->st_rdev;
01580             statp->st_mode = (fl->devtype == 'b' ? S_IFBLK : S_IFCHR);
01581             statp->st_mode |= (fl->cur_ar.ar_fmode & 0777);
01582             statp->st_atime = now;
01583             statp->st_mtime = now;
01584             statp->st_ctime = now;
01585         } else if (Lstat(diskURL, statp)) {
01586             rpmError(RPMERR_BADSPEC, _("File not found: %s\n"), diskURL);
01587             fl->processingFailed = 1;
01588             return RPMERR_BADSPEC;
01589         }
01590     }
01591 
01592     if ((! fl->isDir) && S_ISDIR(statp->st_mode)) {
01593 /*@-nullstate@*/ /* FIX: fl->buildRootURL may be NULL */
01594         return recurseDir(fl, diskURL);
01595 /*@=nullstate@*/
01596     }
01597 
01598     fileMode = statp->st_mode;
01599     fileUid = statp->st_uid;
01600     fileGid = statp->st_gid;
01601 
01602     if (S_ISDIR(fileMode) && fl->cur_ar.ar_dmodestr) {
01603         fileMode &= S_IFMT;
01604         fileMode |= fl->cur_ar.ar_dmode;
01605     } else if (fl->cur_ar.ar_fmodestr != NULL) {
01606         fileMode &= S_IFMT;
01607         fileMode |= fl->cur_ar.ar_fmode;
01608     }
01609     if (fl->cur_ar.ar_user) {
01610         fileUname = getUnameS(fl->cur_ar.ar_user);
01611     } else {
01612         fileUname = getUname(fileUid);
01613     }
01614     if (fl->cur_ar.ar_group) {
01615         fileGname = getGnameS(fl->cur_ar.ar_group);
01616     } else {
01617         fileGname = getGname(fileGid);
01618     }
01619         
01620     /* Default user/group to builder's user/group */
01621     if (fileUname == NULL)
01622         fileUname = getUname(getuid());
01623     if (fileGname == NULL)
01624         fileGname = getGname(getgid());
01625     
01626     /* S_XXX macro must be consistent with type in find call at check-files script */
01627     if (check_fileList && (S_ISREG(fileMode) || S_ISLNK(fileMode))) {
01628         appendStringBuf(check_fileList, diskURL);
01629         appendStringBuf(check_fileList, "\n");
01630     }
01631 
01632     /* Add to the file list */
01633     if (fl->fileListRecsUsed == fl->fileListRecsAlloced) {
01634         fl->fileListRecsAlloced += 128;
01635         fl->fileList = xrealloc(fl->fileList,
01636                         fl->fileListRecsAlloced * sizeof(*(fl->fileList)));
01637     }
01638             
01639     {   FileListRec flp = &fl->fileList[fl->fileListRecsUsed];
01640         int i;
01641 
01642         flp->fl_st = *statp;    /* structure assignment */
01643         flp->fl_mode = fileMode;
01644         flp->fl_uid = fileUid;
01645         flp->fl_gid = fileGid;
01646 
01647         flp->fileURL = xstrdup(fileURL);
01648         flp->diskURL = xstrdup(diskURL);
01649         flp->uname = fileUname;
01650         flp->gname = fileGname;
01651 
01652         if (fl->currentLangs && fl->nLangs > 0) {
01653             char * ncl;
01654             size_t nl = 0;
01655             
01656             for (i = 0; i < fl->nLangs; i++)
01657                 nl += strlen(fl->currentLangs[i]) + 1;
01658 
01659             flp->langs = ncl = xmalloc(nl);
01660             for (i = 0; i < fl->nLangs; i++) {
01661                 const char *ocl;
01662                 if (i)  *ncl++ = '|';
01663                 for (ocl = fl->currentLangs[i]; *ocl != '\0'; ocl++)
01664                         *ncl++ = *ocl;
01665                 *ncl = '\0';
01666             }
01667         } else if (! parseForRegexLang(fileURL, &lang)) {
01668             flp->langs = xstrdup(lang);
01669         } else {
01670             flp->langs = xstrdup("");
01671         }
01672 
01673         flp->flags = fl->currentFlags;
01674         flp->specdFlags = fl->currentSpecdFlags;
01675         flp->verifyFlags = fl->currentVerifyFlags;
01676 
01677         /* Hard links need be counted only once. */
01678         if (S_ISREG(flp->fl_mode) && flp->fl_nlink > 1) {
01679             FileListRec ilp;
01680             for (i = 0;  i < fl->fileListRecsUsed; i++) {
01681                 ilp = fl->fileList + i;
01682                 if (!S_ISREG(ilp->fl_mode))
01683                     continue;
01684                 if (flp->fl_nlink != ilp->fl_nlink)
01685                     continue;
01686                 if (flp->fl_ino != ilp->fl_ino)
01687                     continue;
01688                 if (flp->fl_dev != ilp->fl_dev)
01689                     continue;
01690                 break;
01691             }
01692         } else
01693             i = fl->fileListRecsUsed;
01694 
01695         if (!(flp->flags & RPMFILE_EXCLUDE) && S_ISREG(flp->fl_mode) && i >= fl->fileListRecsUsed) 
01696             fl->totalFileSize += flp->fl_size;
01697     }
01698 
01699     fl->fileListRecsUsed++;
01700     fl->fileCount++;
01701 
01702     return 0;
01703 }
01704 /*@=boundswrite@*/
01705 
01712 static int recurseDir(FileList fl, const char * diskURL)
01713 {
01714     char * ftsSet[2];
01715     FTS * ftsp;
01716     FTSENT * fts;
01717     int myFtsOpts = (FTS_COMFOLLOW | FTS_NOCHDIR | FTS_PHYSICAL);
01718     int rc = RPMERR_BADSPEC;
01719 
01720     fl->inFtw = 1;  /* Flag to indicate file has buildRootURL prefixed */
01721     fl->isDir = 1;  /* Keep it from following myftw() again         */
01722 
01723     ftsSet[0] = (char *) diskURL;
01724     ftsSet[1] = NULL;
01725     ftsp = Fts_open(ftsSet, myFtsOpts, NULL);
01726     while ((fts = Fts_read(ftsp)) != NULL) {
01727         switch (fts->fts_info) {
01728         case FTS_D:             /* preorder directory */
01729         case FTS_F:             /* regular file */
01730         case FTS_SL:            /* symbolic link */
01731         case FTS_SLNONE:        /* symbolic link without target */
01732         case FTS_DEFAULT:       /* none of the above */
01733             rc = addFile(fl, fts->fts_accpath, fts->fts_statp);
01734             /*@switchbreak@*/ break;
01735         case FTS_DOT:           /* dot or dot-dot */
01736         case FTS_DP:            /* postorder directory */
01737             rc = 0;
01738             /*@switchbreak@*/ break;
01739         case FTS_NS:            /* stat(2) failed */
01740         case FTS_DNR:           /* unreadable directory */
01741         case FTS_ERR:           /* error; errno is set */
01742         case FTS_DC:            /* directory that causes cycles */
01743         case FTS_NSOK:          /* no stat(2) requested */
01744         case FTS_INIT:          /* initialized only */
01745         case FTS_W:             /* whiteout object */
01746         default:
01747             rc = RPMERR_BADSPEC;
01748             /*@switchbreak@*/ break;
01749         }
01750         if (rc)
01751             break;
01752     }
01753     (void) Fts_close(ftsp);
01754 
01755     fl->isDir = 0;
01756     fl->inFtw = 0;
01757 
01758     return rc;
01759 }
01760 
01769 static int processMetadataFile(Package pkg, FileList fl, const char * fileURL,
01770                 rpmTag tag)
01771         /*@globals check_fileList, rpmGlobalMacroContext, h_errno,
01772                 fileSystem, internalState @*/
01773         /*@modifies pkg->header, *fl, fl->processingFailed,
01774                 fl->fileList, fl->fileListRecsAlloced, fl->fileListRecsUsed,
01775                 fl->totalFileSize, fl->fileCount,
01776                 check_fileList, rpmGlobalMacroContext,
01777                 fileSystem, internalState @*/
01778 {
01779     const char * buildURL = "%{_builddir}/%{?buildsubdir}/";
01780     const char * fn = NULL;
01781     const char * apkt = NULL;
01782     const unsigned char * pkt = NULL;
01783     ssize_t pktlen = 0;
01784     int absolute = 0;
01785     int rc = 1;
01786     int xx;
01787 
01788     (void) urlPath(fileURL, &fn);
01789     if (*fn == '/') {
01790         fn = rpmGenPath(fl->buildRootURL, NULL, fn);
01791         absolute = 1;
01792     } else
01793         fn = rpmGenPath(buildURL, NULL, fn);
01794 
01795 /*@-branchstate@*/
01796     switch (tag) {
01797     default:
01798         rpmError(RPMERR_BADSPEC, _("%s: can't load unknown tag (%d).\n"),
01799                 fn, tag);
01800         goto exit;
01801         /*@notreached@*/ break;
01802     case RPMTAG_PUBKEYS:
01803         if ((rc = pgpReadPkts(fn, &pkt, &pktlen)) <= 0) {
01804             rpmError(RPMERR_BADSPEC, _("%s: public key read failed.\n"), fn);
01805             goto exit;
01806         }
01807         if (rc != PGPARMOR_PUBKEY) {
01808             rpmError(RPMERR_BADSPEC, _("%s: not an armored public key.\n"), fn);
01809             goto exit;
01810         }
01811         apkt = pgpArmorWrap(PGPARMOR_PUBKEY, pkt, pktlen);
01812         break;
01813     case RPMTAG_POLICIES:
01814         if ((rc = rpmioSlurp(fn, &pkt, &pktlen)) != 0) {
01815             rpmError(RPMERR_BADSPEC, _("%s: *.te policy read failed.\n"), fn);
01816             goto exit;
01817         }
01818         apkt = (const char *) pkt;      /* XXX unsigned char */
01819         pkt = NULL;
01820         break;
01821     }
01822 /*@=branchstate@*/
01823 
01824     xx = headerAddOrAppendEntry(pkg->header, tag,
01825                 RPM_STRING_ARRAY_TYPE, &apkt, 1);
01826 
01827     rc = 0;
01828     if (absolute)
01829         rc = addFile(fl, fn, NULL);
01830 
01831 exit:
01832     apkt = _free(apkt);
01833     pkt = _free(pkt);
01834     fn = _free(fn);
01835     if (rc) {
01836         fl->processingFailed = 1;
01837         rc = RPMERR_BADSPEC;
01838     }
01839     return rc;
01840 }
01841 
01849 static int processBinaryFile(/*@unused@*/ Package pkg, FileList fl,
01850                 const char * fileURL)
01851         /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/
01852         /*@modifies *fl, fl->processingFailed,
01853                 fl->fileList, fl->fileListRecsAlloced, fl->fileListRecsUsed,
01854                 fl->totalFileSize, fl->fileCount,
01855                 rpmGlobalMacroContext, fileSystem, internalState @*/
01856 {
01857     int quote = 1;      /* XXX permit quoted glob characters. */
01858     int doGlob;
01859     const char *diskURL = NULL;
01860     int rc = 0;
01861     
01862     doGlob = Glob_pattern_p(fileURL, quote);
01863 
01864     /* Check that file starts with leading "/" */
01865     {   const char * fileName;
01866         (void) urlPath(fileURL, &fileName);
01867         if (*fileName != '/') {
01868             rpmError(RPMERR_BADSPEC, _("File needs leading \"/\": %s\n"),
01869                         fileName);
01870             rc = 1;
01871             goto exit;
01872         }
01873     }
01874     
01875     /* Copy file name or glob pattern removing multiple "/" chars. */
01876     /*
01877      * Note: rpmGetPath should guarantee a "canonical" path. That means
01878      * that the following pathologies should be weeded out:
01879      *          //bin//sh
01880      *          //usr//bin/
01881      *          /.././../usr/../bin//./sh
01882      */
01883     diskURL = rpmGenPath(fl->buildRootURL, NULL, fileURL);
01884 
01885     if (doGlob) {
01886         const char ** argv = NULL;
01887         int argc = 0;
01888         int i;
01889 
01890         /* XXX for %dev marker in file manifest only */
01891         if (fl->noGlob) {
01892             rpmError(RPMERR_BADSPEC, _("Glob not permitted: %s\n"),
01893                         diskURL);
01894             rc = 1;
01895             goto exit;
01896         }
01897 
01898         /*@-branchstate@*/
01899         rc = rpmGlob(diskURL, &argc, &argv);
01900         if (rc == 0 && argc >= 1 && !Glob_pattern_p(argv[0], quote)) {
01901             for (i = 0; i < argc; i++) {
01902                 rc = addFile(fl, argv[i], NULL);
01903 /*@-boundswrite@*/
01904                 argv[i] = _free(argv[i]);
01905 /*@=boundswrite@*/
01906             }
01907             argv = _free(argv);
01908         } else {
01909             rpmError(RPMERR_BADSPEC, _("File not found by glob: %s\n"),
01910                         diskURL);
01911             rc = 1;
01912             goto exit;
01913         }
01914         /*@=branchstate@*/
01915     } else {
01916         rc = addFile(fl, diskURL, NULL);
01917     }
01918 
01919 exit:
01920     diskURL = _free(diskURL);
01921     if (rc) {
01922         fl->processingFailed = 1;
01923         rc = RPMERR_BADSPEC;
01924     }
01925     return rc;
01926 }
01927 
01930 /*@-boundswrite@*/
01931 static int processPackageFiles(Spec spec, Package pkg,
01932                                int installSpecialDoc, int test)
01933         /*@globals rpmGlobalMacroContext, h_errno,
01934                 fileSystem, internalState@*/
01935         /*@modifies spec->macros,
01936                 pkg->cpioList, pkg->fileList, pkg->specialDoc, pkg->header,
01937                 rpmGlobalMacroContext, fileSystem, internalState @*/
01938 {
01939     HGE_t hge = (HGE_t)headerGetEntryMinMemory;
01940     struct FileList_s fl;
01941     char *s, **files, **fp;
01942     const char *fileName;
01943     char buf[BUFSIZ];
01944     struct AttrRec_s arbuf;
01945     AttrRec specialDocAttrRec = &arbuf;
01946     char *specialDoc = NULL;
01947 
01948     nullAttrRec(specialDocAttrRec);
01949     pkg->cpioList = NULL;
01950 
01951     if (pkg->fileFile) {
01952         const char *ffn;
01953         FILE * f;
01954         FD_t fd;
01955 
01956         /* XXX W2DO? urlPath might be useful here. */
01957         if (*pkg->fileFile == '/') {
01958             ffn = rpmGetPath(pkg->fileFile, NULL);
01959         } else {
01960             /* XXX FIXME: add %{buildsubdir} */
01961             ffn = rpmGetPath("%{_builddir}/",
01962                 (spec->buildSubdir ? spec->buildSubdir : "") ,
01963                 "/", pkg->fileFile, NULL);
01964         }
01965         fd = Fopen(ffn, "r.fpio");
01966 
01967         if (fd == NULL || Ferror(fd)) {
01968             rpmError(RPMERR_BADFILENAME,
01969                 _("Could not open %%files file %s: %s\n"),
01970                 ffn, Fstrerror(fd));
01971             return RPMERR_BADFILENAME;
01972         }
01973         ffn = _free(ffn);
01974 
01975         /*@+voidabstract@*/ f = fdGetFp(fd); /*@=voidabstract@*/
01976         if (f != NULL)
01977         while (fgets(buf, sizeof(buf), f)) {
01978             handleComments(buf);
01979             if (expandMacros(spec, spec->macros, buf, sizeof(buf))) {
01980                 rpmError(RPMERR_BADSPEC, _("line: %s\n"), buf);
01981                 return RPMERR_BADSPEC;
01982             }
01983             appendStringBuf(pkg->fileList, buf);
01984         }
01985         (void) Fclose(fd);
01986     }
01987     
01988     /* Init the file list structure */
01989     memset(&fl, 0, sizeof(fl));
01990 
01991     /* XXX spec->buildRootURL == NULL, then xstrdup("") is returned */
01992     fl.buildRootURL = rpmGenPath(spec->rootURL, spec->buildRootURL, NULL);
01993 
01994     if (hge(pkg->header, RPMTAG_DEFAULTPREFIX, NULL, (void **)&fl.prefix, NULL))
01995         fl.prefix = xstrdup(fl.prefix);
01996     else
01997         fl.prefix = NULL;
01998 
01999     fl.fileCount = 0;
02000     fl.totalFileSize = 0;
02001     fl.processingFailed = 0;
02002 
02003     fl.passedSpecialDoc = 0;
02004     fl.isSpecialDoc = 0;
02005 
02006     fl.isDir = 0;
02007     fl.inFtw = 0;
02008     fl.currentFlags = 0;
02009     fl.currentVerifyFlags = 0;
02010     
02011     fl.noGlob = 0;
02012     fl.devtype = 0;
02013     fl.devmajor = 0;
02014     fl.devminor = 0;
02015 
02016     nullAttrRec(&fl.cur_ar);
02017     nullAttrRec(&fl.def_ar);
02018     dupAttrRec(&root_ar, &fl.def_ar);   /* XXX assume %defattr(-,root,root) */
02019 
02020     fl.defVerifyFlags = RPMVERIFY_ALL;
02021     fl.nLangs = 0;
02022     fl.currentLangs = NULL;
02023 
02024     fl.currentSpecdFlags = 0;
02025     fl.defSpecdFlags = 0;
02026 
02027     fl.docDirCount = 0;
02028     fl.docDirs[fl.docDirCount++] = xstrdup("/usr/doc");
02029     fl.docDirs[fl.docDirCount++] = xstrdup("/usr/man");
02030     fl.docDirs[fl.docDirCount++] = xstrdup("/usr/info");
02031     fl.docDirs[fl.docDirCount++] = xstrdup("/usr/X11R6/man");
02032     fl.docDirs[fl.docDirCount++] = xstrdup("/usr/share/doc");
02033     fl.docDirs[fl.docDirCount++] = xstrdup("/usr/share/man");
02034     fl.docDirs[fl.docDirCount++] = xstrdup("/usr/share/info");
02035     fl.docDirs[fl.docDirCount++] = xstrdup("/usr/share/gtk-doc/html");
02036     fl.docDirs[fl.docDirCount++] = rpmGetPath("%{_docdir}", NULL);
02037     fl.docDirs[fl.docDirCount++] = rpmGetPath("%{_mandir}", NULL);
02038     fl.docDirs[fl.docDirCount++] = rpmGetPath("%{_infodir}", NULL);
02039     fl.docDirs[fl.docDirCount++] = rpmGetPath("%{_javadocdir}", NULL);
02040     
02041     fl.fileList = NULL;
02042     fl.fileListRecsAlloced = 0;
02043     fl.fileListRecsUsed = 0;
02044 
02045     s = getStringBuf(pkg->fileList);
02046     files = splitString(s, strlen(s), '\n');
02047 
02048     for (fp = files; *fp != NULL; fp++) {
02049         s = *fp;
02050         SKIPSPACE(s);
02051         if (*s == '\0')
02052             continue;
02053         fileName = NULL;
02054         /*@-nullpass@*/ /* LCL: buf is NULL ?!? */
02055         strcpy(buf, s);
02056         /*@=nullpass@*/
02057         
02058         /* Reset for a new line in %files */
02059         fl.isDir = 0;
02060         fl.inFtw = 0;
02061         fl.currentFlags = 0;
02062         /* turn explicit flags into %def'd ones (gosh this is hacky...) */
02063         fl.currentSpecdFlags = ((unsigned)fl.defSpecdFlags) >> 8;
02064         fl.currentVerifyFlags = fl.defVerifyFlags;
02065         fl.isSpecialDoc = 0;
02066 
02067         fl.noGlob = 0;
02068         fl.devtype = 0;
02069         fl.devmajor = 0;
02070         fl.devminor = 0;
02071 
02072         /* XXX should reset to %deflang value */
02073         if (fl.currentLangs) {
02074             int i;
02075             for (i = 0; i < fl.nLangs; i++)
02076                 /*@-unqualifiedtrans@*/
02077                 fl.currentLangs[i] = _free(fl.currentLangs[i]);
02078                 /*@=unqualifiedtrans@*/
02079             fl.currentLangs = _free(fl.currentLangs);
02080         }
02081         fl.nLangs = 0;
02082 
02083         dupAttrRec(&fl.def_ar, &fl.cur_ar);
02084 
02085         /*@-nullpass@*/ /* LCL: buf is NULL ?!? */
02086         if (parseForVerify(buf, &fl))
02087             continue;
02088         if (parseForAttr(buf, &fl))
02089             continue;
02090         if (parseForDev(buf, &fl))
02091             continue;
02092         if (parseForConfig(buf, &fl))
02093             continue;
02094         if (parseForLang(buf, &fl))
02095             continue;
02096         /*@-nullstate@*/        /* FIX: pkg->fileFile might be NULL */
02097         if (parseForSimple(spec, pkg, buf, &fl, &fileName))
02098         /*@=nullstate@*/
02099             continue;
02100         /*@=nullpass@*/
02101         if (fileName == NULL)
02102             continue;
02103 
02104         /*@-branchstate@*/
02105         if (fl.isSpecialDoc) {
02106             /* Save this stuff for last */
02107             specialDoc = _free(specialDoc);
02108             specialDoc = xstrdup(fileName);
02109             dupAttrRec(&fl.cur_ar, specialDocAttrRec);
02110         } else if (fl.currentFlags & RPMFILE_PUBKEY) {
02111 /*@-nullstate@*/        /* FIX: pkg->fileFile might be NULL */
02112             (void) processMetadataFile(pkg, &fl, fileName, RPMTAG_PUBKEYS);
02113 /*@=nullstate@*/
02114         } else if (fl.currentFlags & RPMFILE_POLICY) {
02115 /*@-nullstate@*/        /* FIX: pkg->fileFile might be NULL */
02116             (void) processMetadataFile(pkg, &fl, fileName, RPMTAG_POLICIES);
02117 /*@=nullstate@*/
02118         } else {
02119 /*@-nullstate@*/        /* FIX: pkg->fileFile might be NULL */
02120             (void) processBinaryFile(pkg, &fl, fileName);
02121 /*@=nullstate@*/
02122         }
02123         /*@=branchstate@*/
02124     }
02125 
02126     /* Now process special doc, if there is one */
02127     if (specialDoc) {
02128         if (installSpecialDoc) {
02129             int _missing_doc_files_terminate_build =
02130                     rpmExpandNumeric("%{?_missing_doc_files_terminate_build}");
02131             int rc;
02132 
02133             rc = doScript(spec, RPMBUILD_STRINGBUF, "%doc", pkg->specialDoc, test);
02134             if (rc && _missing_doc_files_terminate_build)
02135                 fl.processingFailed = rc;
02136         }
02137 
02138         /* Reset for %doc */
02139         fl.isDir = 0;
02140         fl.inFtw = 0;
02141         fl.currentFlags = 0;
02142         fl.currentVerifyFlags = fl.defVerifyFlags;
02143 
02144         fl.noGlob = 0;
02145         fl.devtype = 0;
02146         fl.devmajor = 0;
02147         fl.devminor = 0;
02148 
02149         /* XXX should reset to %deflang value */
02150         if (fl.currentLangs) {
02151             int i;
02152             for (i = 0; i < fl.nLangs; i++)
02153                 /*@-unqualifiedtrans@*/
02154                 fl.currentLangs[i] = _free(fl.currentLangs[i]);
02155                 /*@=unqualifiedtrans@*/
02156             fl.currentLangs = _free(fl.currentLangs);
02157         }
02158         fl.nLangs = 0;
02159 
02160         dupAttrRec(specialDocAttrRec, &fl.cur_ar);
02161         freeAttrRec(specialDocAttrRec);
02162 
02163         /*@-nullstate@*/        /* FIX: pkg->fileFile might be NULL */
02164         (void) processBinaryFile(pkg, &fl, specialDoc);
02165         /*@=nullstate@*/
02166 
02167         specialDoc = _free(specialDoc);
02168     }
02169     
02170     freeSplitString(files);
02171 
02172     if (fl.processingFailed)
02173         goto exit;
02174 
02175     /* Verify that file attributes scope over hardlinks correctly. */
02176     if (checkHardLinks(&fl))
02177         (void) rpmlibNeedsFeature(pkg->header,
02178                         "PartialHardlinkSets", "4.0.4-1");
02179 
02180     genCpioListAndHeader(&fl, &pkg->cpioList, pkg->header, 0);
02181 
02182     if (spec->timeCheck)
02183         timeCheck(spec->timeCheck, pkg->header);
02184     
02185 exit:
02186     fl.buildRootURL = _free(fl.buildRootURL);
02187     fl.prefix = _free(fl.prefix);
02188 
02189     freeAttrRec(&fl.cur_ar);
02190     freeAttrRec(&fl.def_ar);
02191 
02192     if (fl.currentLangs) {
02193         int i;
02194         for (i = 0; i < fl.nLangs; i++)
02195             /*@-unqualifiedtrans@*/
02196             fl.currentLangs[i] = _free(fl.currentLangs[i]);
02197             /*@=unqualifiedtrans@*/
02198         fl.currentLangs = _free(fl.currentLangs);
02199     }
02200 
02201     fl.fileList = freeFileList(fl.fileList, fl.fileListRecsUsed);
02202     while (fl.docDirCount--)
02203         fl.docDirs[fl.docDirCount] = _free(fl.docDirs[fl.docDirCount]);
02204     return fl.processingFailed;
02205 }
02206 /*@=boundswrite@*/
02207 
02208 void initSourceHeader(Spec spec)
02209 {
02210     HeaderIterator hi;
02211     int_32 tag, type, count;
02212     const void * ptr;
02213 
02214     spec->sourceHeader = headerNew();
02215     /* Only specific tags are added to the source package header */
02216     /*@-branchstate@*/
02217     for (hi = headerInitIterator(spec->packages->header);
02218         headerNextIterator(hi, &tag, &type, &ptr, &count);
02219         ptr = headerFreeData(ptr, type))
02220     {
02221         switch (tag) {
02222         case RPMTAG_NAME:
02223         case RPMTAG_VERSION:
02224         case RPMTAG_RELEASE:
02225         case RPMTAG_EPOCH:
02226         case RPMTAG_SUMMARY:
02227         case RPMTAG_DESCRIPTION:
02228         case RPMTAG_PACKAGER:
02229         case RPMTAG_DISTRIBUTION:
02230         case RPMTAG_DISTURL:
02231         case RPMTAG_VENDOR:
02232         case RPMTAG_LICENSE:
02233         case RPMTAG_GROUP:
02234         case RPMTAG_OS:
02235         case RPMTAG_ARCH:
02236         case RPMTAG_CHANGELOGTIME:
02237         case RPMTAG_CHANGELOGNAME:
02238         case RPMTAG_CHANGELOGTEXT:
02239         case RPMTAG_URL:
02240         case HEADER_I18NTABLE:
02241             if (ptr)
02242                 (void)headerAddEntry(spec->sourceHeader, tag, type, ptr, count);
02243             /*@switchbreak@*/ break;
02244         default:
02245             /* do not copy */
02246             /*@switchbreak@*/ break;
02247         }
02248     }
02249     hi = headerFreeIterator(hi);
02250     /*@=branchstate@*/
02251 
02252     /* Add the build restrictions */
02253     /*@-branchstate@*/
02254     for (hi = headerInitIterator(spec->buildRestrictions);
02255         headerNextIterator(hi, &tag, &type, &ptr, &count);
02256         ptr = headerFreeData(ptr, type))
02257     {
02258         if (ptr)
02259             (void) headerAddEntry(spec->sourceHeader, tag, type, ptr, count);
02260     }
02261     hi = headerFreeIterator(hi);
02262     /*@=branchstate@*/
02263 
02264     if (spec->BANames && spec->BACount > 0) {
02265         (void) headerAddEntry(spec->sourceHeader, RPMTAG_BUILDARCHS,
02266                        RPM_STRING_ARRAY_TYPE,
02267                        spec->BANames, spec->BACount);
02268     }
02269 }
02270 
02271 int processSourceFiles(Spec spec)
02272 {
02273     struct Source *srcPtr;
02274     StringBuf sourceFiles;
02275     int x, isSpec = 1;
02276     struct FileList_s fl;
02277     char *s, **files, **fp;
02278     Package pkg;
02279     static char *_srcdefattr;
02280     static int oneshot;
02281 
02282     if (!oneshot) {
02283         _srcdefattr = rpmExpand("%{?_srcdefattr}", NULL);
02284         if (_srcdefattr && !*_srcdefattr)
02285             _srcdefattr = _free(_srcdefattr);
02286         oneshot = 1;
02287     }
02288     sourceFiles = newStringBuf();
02289 
02290     /* XXX
02291      * XXX This is where the source header for noarch packages needs
02292      * XXX to be initialized.
02293      */
02294     if (spec->sourceHeader == NULL)
02295         initSourceHeader(spec);
02296 
02297     /* Construct the file list and source entries */
02298     appendLineStringBuf(sourceFiles, spec->specFile);
02299     if (spec->sourceHeader != NULL)
02300     for (srcPtr = spec->sources; srcPtr != NULL; srcPtr = srcPtr->next) {
02301         if (srcPtr->flags & RPMBUILD_ISSOURCE) {
02302             (void) headerAddOrAppendEntry(spec->sourceHeader, RPMTAG_SOURCE,
02303                                    RPM_STRING_ARRAY_TYPE, &srcPtr->source, 1);
02304             if (srcPtr->flags & RPMBUILD_ISNO) {
02305                 (void) headerAddOrAppendEntry(spec->sourceHeader, RPMTAG_NOSOURCE,
02306                                        RPM_INT32_TYPE, &srcPtr->num, 1);
02307             }
02308         }
02309         if (srcPtr->flags & RPMBUILD_ISPATCH) {
02310             (void) headerAddOrAppendEntry(spec->sourceHeader, RPMTAG_PATCH,
02311                                    RPM_STRING_ARRAY_TYPE, &srcPtr->source, 1);
02312             if (srcPtr->flags & RPMBUILD_ISNO) {
02313                 (void) headerAddOrAppendEntry(spec->sourceHeader, RPMTAG_NOPATCH,
02314                                        RPM_INT32_TYPE, &srcPtr->num, 1);
02315             }
02316         }
02317 
02318       { const char * sfn;
02319         sfn = rpmGetPath( ((srcPtr->flags & RPMBUILD_ISNO) ? "!" : ""),
02320                 "%{_sourcedir}/", srcPtr->source, NULL);
02321         appendLineStringBuf(sourceFiles, sfn);
02322         sfn = _free(sfn);
02323       }
02324     }
02325 
02326     for (pkg = spec->packages; pkg != NULL; pkg = pkg->next) {
02327         for (srcPtr = pkg->icon; srcPtr != NULL; srcPtr = srcPtr->next) {
02328             const char * sfn;
02329             sfn = rpmGetPath( ((srcPtr->flags & RPMBUILD_ISNO) ? "!" : ""),
02330                 "%{_sourcedir}/", srcPtr->source, NULL);
02331             appendLineStringBuf(sourceFiles, sfn);
02332             sfn = _free(sfn);
02333         }
02334     }
02335 
02336     spec->sourceCpioList = NULL;
02337 
02338     /* Init the file list structure */
02339     memset(&fl, 0, sizeof(fl));
02340     if (_srcdefattr) {
02341         char *a = xmalloc(strlen(_srcdefattr) + 9 + 1);
02342         strcpy(a, "%defattr ");
02343         strcpy(a + 9, _srcdefattr);
02344         parseForAttr(a, &fl);
02345         a = _free(a);
02346     }
02347     fl.fileList = xcalloc((spec->numSources + 1), sizeof(*fl.fileList));
02348     fl.processingFailed = 0;
02349     fl.fileListRecsUsed = 0;
02350     fl.totalFileSize = 0;
02351     fl.prefix = NULL;
02352     fl.buildRootURL = NULL;
02353 
02354     s = getStringBuf(sourceFiles);
02355     files = splitString(s, strlen(s), '\n');
02356 
02357     /* The first source file is the spec file */
02358     x = 0;
02359     for (fp = files; *fp != NULL; fp++) {
02360         const char * diskURL, *diskPath;
02361         FileListRec flp;
02362 
02363         diskURL = *fp;
02364         SKIPSPACE(diskURL);
02365         if (! *diskURL)
02366             continue;
02367 
02368         flp = &fl.fileList[x];
02369 
02370         flp->flags = isSpec ? RPMFILE_SPECFILE : 0;
02371         /* files with leading ! are no source files */
02372         if (*diskURL == '!') {
02373             flp->flags |= RPMFILE_GHOST;
02374             diskURL++;
02375         }
02376 
02377         (void) urlPath(diskURL, &diskPath);
02378 
02379         flp->diskURL = xstrdup(diskURL);
02380         diskPath = strrchr(diskPath, '/');
02381         if (diskPath)
02382             diskPath++;
02383         else
02384             diskPath = diskURL;
02385 
02386         flp->fileURL = xstrdup(diskPath);
02387         flp->verifyFlags = RPMVERIFY_ALL;
02388 
02389         if (Stat(diskURL, &flp->fl_st)) {
02390             rpmError(RPMERR_BADSPEC, _("Bad file: %s: %s\n"),
02391                 diskURL, strerror(errno));
02392             fl.processingFailed = 1;
02393         }
02394 
02395         if (fl.def_ar.ar_fmodestr) {
02396             flp->fl_mode &= S_IFMT;
02397             flp->fl_mode |= fl.def_ar.ar_fmode;
02398         }
02399         if (fl.def_ar.ar_user) {
02400             flp->uname = getUnameS(fl.def_ar.ar_user);
02401         } else {
02402             flp->uname = getUname(flp->fl_uid);
02403         }
02404         if (fl.def_ar.ar_group) {
02405             flp->gname = getGnameS(fl.def_ar.ar_group);
02406         } else {
02407             flp->gname = getGname(flp->fl_gid);
02408         }
02409         flp->langs = xstrdup("");
02410         
02411         fl.totalFileSize += flp->fl_size;
02412         
02413         if (! (flp->uname && flp->gname)) {
02414             rpmError(RPMERR_BADSPEC, _("Bad owner/group: %s\n"), diskURL);
02415             fl.processingFailed = 1;
02416         }
02417 
02418         isSpec = 0;
02419         x++;
02420     }
02421     fl.fileListRecsUsed = x;
02422     freeSplitString(files);
02423 
02424     if (! fl.processingFailed) {
02425         if (spec->sourceHeader != NULL)
02426             genCpioListAndHeader(&fl, &spec->sourceCpioList,
02427                         spec->sourceHeader, 1);
02428     }
02429 
02430     sourceFiles = freeStringBuf(sourceFiles);
02431     fl.fileList = freeFileList(fl.fileList, fl.fileListRecsUsed);
02432     freeAttrRec(&fl.def_ar);
02433     return fl.processingFailed;
02434 }
02435 
02441 static int checkFiles(StringBuf fileList)
02442         /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/
02443         /*@modifies rpmGlobalMacroContext, fileSystem, internalState @*/
02444 {
02445 /*@-readonlytrans@*/
02446     static const char * av_ckfile[] = { "%{?__check_files}", NULL };
02447 /*@=readonlytrans@*/
02448     StringBuf sb_stdout = NULL;
02449     const char * s;
02450     int rc;
02451     
02452     s = rpmExpand(av_ckfile[0], NULL);
02453     if (!(s && *s)) {
02454         rc = -1;
02455         goto exit;
02456     }
02457     rc = 0;
02458 
02459     rpmMessage(RPMMESS_NORMAL, _("Checking for unpackaged file(s): %s\n"), s);
02460 
02461 /*@-boundswrite@*/
02462     rc = rpmfcExec(av_ckfile, fileList, &sb_stdout, 0);
02463 /*@=boundswrite@*/
02464     if (rc < 0)
02465         goto exit;
02466     
02467     if (sb_stdout) {
02468         int _unpackaged_files_terminate_build =
02469                 rpmExpandNumeric("%{?_unpackaged_files_terminate_build}");
02470         const char * t;
02471 
02472         t = getStringBuf(sb_stdout);
02473         if ((*t != '\0') && (*t != '\n')) {
02474             rc = (_unpackaged_files_terminate_build) ? 1 : 0;
02475             rpmMessage((rc ? RPMMESS_ERROR : RPMMESS_WARNING),
02476                 _("Installed (but unpackaged) file(s) found:\n%s"), t);
02477         }
02478     }
02479     
02480 exit:
02481     sb_stdout = freeStringBuf(sb_stdout);
02482     s = _free(s);
02483     return rc;
02484 }
02485 
02486 /*@-incondefs@*/
02487 int processBinaryFiles(Spec spec, int installSpecialDoc, int test)
02488         /*@globals check_fileList @*/
02489         /*@modifies check_fileList @*/
02490 {
02491     Package pkg;
02492     int res = 0;
02493     
02494     check_fileList = newStringBuf();
02495     
02496     for (pkg = spec->packages; pkg != NULL; pkg = pkg->next) {
02497         const char *n, *v, *r;
02498         int rc;
02499 
02500         if (pkg->fileList == NULL)
02501             continue;
02502 
02503         (void) headerNVR(pkg->header, &n, &v, &r);
02504         rpmMessage(RPMMESS_NORMAL, _("Processing files: %s-%s-%s\n"), n, v, r);
02505                    
02506         if ((rc = processPackageFiles(spec, pkg, installSpecialDoc, test)))
02507             res = rc;
02508 
02509         if ((rc = rpmfcGenerateDepends(spec, pkg)))
02510             res = rc;
02511     }
02512 
02513     /* Now we have in fileList list of files from all packages.
02514      * We pass it to a script which does the work of finding missing
02515      * and duplicated files.
02516      */
02517     
02518     
02519     if (checkFiles(check_fileList) > 0) {
02520         if (res == 0)
02521             res = 1;
02522     }
02523     
02524     check_fileList = freeStringBuf(check_fileList);
02525     
02526     return res;
02527 }
02528 /*@=incondefs@*/

Generated on Fri Oct 12 08:44:53 2007 for rpm by  doxygen 1.5.2