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

Generated on 19 Jul 2013 for rpm by  doxygen 1.4.7