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

Generated at Tue Dec 23 04:54:11 2003 for rpm by doxygen1.2.8.1 written by Dimitri van Heesch, © 1997-2001