Main Page   Modules   Data Structures   File List   Data Fields   Globals   Related Pages  

build/files.c

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

Generated on Sun Feb 2 23:31:58 2003 for rpm by doxygen1.2.18