# 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     char nlangs[BUFSIZ];
    01045     FileListRec ilp, jlp;
    01046     int i, j;
    01047     int rc = 0;
    01048
    01049     for (i = 0;  i < fl->fileListRecsUsed; i++) {
    01050         char *te;
    01051
    01052         ilp = fl->fileList + i;
    01053
    01054         /* Is this a hard link? */
    01055         if (!(S_ISREG(ilp->fl_mode) && ilp->fl_nlink > 1))
    01056             continue;
    01057
    01058         /* Find all members of hardlink set. */
    01059         for (j = i + 1; j < fl->fileListRecsUsed; j++) {
    01060             jlp = fl->fileList + j;
    01061
    01062             /* Member of same hardlink set? */
    01063             if (!S_ISREG(jlp->fl_mode))
    01064                 /*@innercontinue@*/ continue;
    01065             if (ilp->fl_nlink != jlp->fl_nlink)
    01066                 /*@innercontinue@*/ continue;
    01067             if (ilp->fl_ino != jlp->fl_ino)
    01068                 /*@innercontinue@*/ continue;
    01069             if (ilp->fl_dev != jlp->fl_dev)
    01070                 /*@innercontinue@*/ continue;
    01071
    01072             /* Identical locale coloring? */
    01073             if (!strcmp(ilp->langs, jlp->langs))
    01074                 continue;
    01075             return 1;
    01076         }
    01077     }
    01078     return 0;
    01079 }
    01080
    01086 static void genCpioListAndHeader(/*@partial@*/ FileList fl,
    01087                 TFI_t * cpioList, Header h, int isSrc)
    01088         /*@globals rpmGlobalMacroContext,
    01089                 fileSystem @*/
    01090         /*@modifies h, *cpioList, fl->processingFailed, fl->fileList,
    01091                 rpmGlobalMacroContext, fileSystem @*/
    01092 {
    01093     int _addDotSlash = !(isSrc || rpmExpandNumeric("%{_noPayloadPrefix}"));
    01094     uint_32 multiLibMask = 0;
    01095     int apathlen = 0;
    01096     int dpathlen = 0;
    01097     int skipLen = 0;
    01098     FileListRec flp;
    01099     char buf[BUFSIZ];
    01100     int i;
    01101
    01102     /* Sort the big list */
    01103     qsort(fl->fileList, fl->fileListRecsUsed,
    01104           sizeof(*(fl->fileList)), compareFileListRecs);
    01105
    01106     /* Generate the header. */
    01107     if (! isSrc) {
    01108         skipLen = 1;
    01109         if (fl->prefix)
    01110             skipLen += strlen(fl->prefix);
    01111     }
    01112
    01113     for (i = 0, flp = fl->fileList; i < fl->fileListRecsUsed; i++, flp++) {
    01114         char *s;
    01115
    01116         /* Merge duplicate entries. */
    01117         while (i < (fl->fileListRecsUsed - 1) &&
    01118             !strcmp(flp->fileURL, flp[1].fileURL)) {
    01119
    01120             /* Two entries for the same file found, merge the entries. */
    01121             /* Note that an %exclude is a duplication of a file reference */
    01122
    01123             /* file flags */
    01124             flp[1].flags |= flp->flags;
    01125
    01126             if (!(flp[1].flags & RPMFILE_EXCLUDE))
    01127                 rpmMessage(RPMMESS_WARNING, _("File listed twice: %s\n"),
    01128                         flp->fileURL);
    01129
    01130             /* file mode */
    01131             if (S_ISDIR(flp->fl_mode)) {
    01132                 if ((flp[1].specdFlags & (SPECD_DIRMODE | SPECD_DEFDIRMODE)) <
    01133                     (flp->specdFlags & (SPECD_DIRMODE | SPECD_DEFDIRMODE)))
    01134                         flp[1].fl_mode = flp->fl_mode;
    01135             } else {
    01136                 if ((flp[1].specdFlags & (SPECD_FILEMODE | SPECD_DEFFILEMODE)) <
    01137                     (flp->specdFlags & (SPECD_FILEMODE | SPECD_DEFFILEMODE)))
    01138                         flp[1].fl_mode = flp->fl_mode;
    01139             }
    01140
    01141             /* uid */
    01142             if ((flp[1].specdFlags & (SPECD_UID | SPECD_DEFUID)) <
    01143                 (flp->specdFlags & (SPECD_UID | SPECD_DEFUID)))
    01144             {
    01145                 flp[1].fl_uid = flp->fl_uid;
    01146                 flp[1].uname = flp->uname;
    01147             }
    01148
    01149             /* gid */
    01150             if ((flp[1].specdFlags & (SPECD_GID | SPECD_DEFGID)) <
    01151                 (flp->specdFlags & (SPECD_GID | SPECD_DEFGID)))
    01152             {
    01153                 flp[1].fl_gid = flp->fl_gid;
    01154                 flp[1].gname = flp->gname;
    01155             }
    01156
    01157             /* verify flags */
    01158             if ((flp[1].specdFlags & (SPECD_VERIFY | SPECD_DEFVERIFY)) <
    01159                 (flp->specdFlags & (SPECD_VERIFY | SPECD_DEFVERIFY)))
    01160                     flp[1].verifyFlags = flp->verifyFlags;
    01161
    01162             /* XXX to-do: language */
    01163
    01164             flp++; i++;
    01165         }
    01166
    01167         /* Skip files that were marked with %exclude. */
    01168         if (flp->flags & RPMFILE_EXCLUDE) continue;
    01169
    01170         /* Omit '/' and/or URL prefix, leave room for "./" prefix */
    01171         apathlen += (strlen(flp->fileURL) - skipLen + (_addDotSlash ? 3 : 1));
    01172
    01173         /* Leave room for both dirname and basename NUL's */
    01174         dpathlen += (strlen(flp->diskURL) + 2);
    01175
    01176         if (flp->flags & RPMFILE_MULTILIB_MASK)
    01177             multiLibMask |=
    01178                 (1u << ((flp->flags & RPMFILE_MULTILIB_MASK))
    01179                       >> RPMFILE_MULTILIB_SHIFT);
    01180
    01181         /*
    01182          * Make the header, the OLDFILENAMES will get converted to a
    01183          * compressed file list write before we write the actual package to
    01184          * disk.
    01185          */
    01186         (void) headerAddOrAppendEntry(h, RPMTAG_OLDFILENAMES, RPM_STRING_ARRAY_TYPE,
    01187                                &(flp->fileURL), 1);
    01188
    01189 /*@-sizeoftype@*/
    01190       if (sizeof(flp->fl_size) != sizeof(uint_32)) {
    01191         uint_32 psize = (uint_32)flp->fl_size;
    01192         (void) headerAddOrAppendEntry(h, RPMTAG_FILESIZES, RPM_INT32_TYPE,
    01193                                &(psize), 1);
    01194       } else {
    01195         (void) headerAddOrAppendEntry(h, RPMTAG_FILESIZES, RPM_INT32_TYPE,
    01196                                &(flp->fl_size), 1);
    01197       }
    01198         (void) headerAddOrAppendEntry(h, RPMTAG_FILEUSERNAME, RPM_STRING_ARRAY_TYPE,
    01199                                &(flp->uname), 1);
    01200         (void) headerAddOrAppendEntry(h, RPMTAG_FILEGROUPNAME, RPM_STRING_ARRAY_TYPE,
    01201                                &(flp->gname), 1);
    01202       if (sizeof(flp->fl_mtime) != sizeof(uint_32)) {
    01203         uint_32 mtime = (uint_32)flp->fl_mtime;
    01204         (void) headerAddOrAppendEntry(h, RPMTAG_FILEMTIMES, RPM_INT32_TYPE,
    01205                                &(mtime), 1);
    01206       } else {
    01207         (void) headerAddOrAppendEntry(h, RPMTAG_FILEMTIMES, RPM_INT32_TYPE,
    01208                                &(flp->fl_mtime), 1);
    01209       }
    01210       if (sizeof(flp->fl_mode) != sizeof(uint_16)) {
    01211         uint_16 pmode = (uint_16)flp->fl_mode;
    01212         (void) headerAddOrAppendEntry(h, RPMTAG_FILEMODES, RPM_INT16_TYPE,
    01213                                &(pmode), 1);
    01214       } else {
    01215         (void) headerAddOrAppendEntry(h, RPMTAG_FILEMODES, RPM_INT16_TYPE,
    01216                                &(flp->fl_mode), 1);
    01217       }
    01218       if (sizeof(flp->fl_rdev) != sizeof(uint_16)) {
    01219         uint_16 prdev = (uint_16)flp->fl_rdev;
    01220         (void) headerAddOrAppendEntry(h, RPMTAG_FILERDEVS, RPM_INT16_TYPE,
    01221                                &(prdev), 1);
    01222       } else {
    01223         (void) headerAddOrAppendEntry(h, RPMTAG_FILERDEVS, RPM_INT16_TYPE,
    01224                                &(flp->fl_rdev), 1);
    01225       }
    01226       if (sizeof(flp->fl_dev) != sizeof(uint_32)) {
    01227         uint_32 pdevice = (uint_32)flp->fl_dev;
    01228         (void) headerAddOrAppendEntry(h, RPMTAG_FILEDEVICES, RPM_INT32_TYPE,
    01229                                &(pdevice), 1);
    01230       } else {
    01231         (void) headerAddOrAppendEntry(h, RPMTAG_FILEDEVICES, RPM_INT32_TYPE,
    01232                                &(flp->fl_dev), 1);
    01233       }
    01234       if (sizeof(flp->fl_ino) != sizeof(uint_32)) {
    01235         uint_32 ino = (uint_32)flp->fl_ino;
    01236         (void) headerAddOrAppendEntry(h, RPMTAG_FILEINODES, RPM_INT32_TYPE,
    01237                                 &(ino), 1);
    01238       } else {
    01239         (void) headerAddOrAppendEntry(h, RPMTAG_FILEINODES, RPM_INT32_TYPE,
    01240                                 &(flp->fl_ino), 1);
    01241       }
    01242 /*@=sizeoftype@*/
    01243
    01244         (void) headerAddOrAppendEntry(h, RPMTAG_FILELANGS, RPM_STRING_ARRAY_TYPE,
    01245                                &(flp->langs),  1);
    01246
    01247         /* We used to add these, but they should not be needed */
    01248         /* (void) headerAddOrAppendEntry(h, RPMTAG_FILEUIDS,
    01249          *                 RPM_INT32_TYPE, &(flp->fl_uid), 1);
    01250          * (void) headerAddOrAppendEntry(h, RPMTAG_FILEGIDS,
    01251          *                 RPM_INT32_TYPE, &(flp->fl_gid), 1);
    01252          */
    01253
    01254         buf[0] = '\0';
    01255         if (S_ISREG(flp->fl_mode))
    01256             (void) domd5(flp->diskURL, buf, 1);
    01257         s = buf;
    01258         (void) headerAddOrAppendEntry(h, RPMTAG_FILEMD5S, RPM_STRING_ARRAY_TYPE,
    01259                                &s, 1);
    01260
    01261         buf[0] = '\0';
    01262         if (S_ISLNK(flp->fl_mode)) {
    01263             buf[Readlink(flp->diskURL, buf, BUFSIZ)] = '\0';
    01264             if (fl->buildRootURL) {
    01265                 const char * buildRoot;
    01266                 (void) urlPath(fl->buildRootURL, &buildRoot);
    01267
    01268                 if (buf[0] == '/' && strcmp(buildRoot, "/") &&
    01269                     !strncmp(buf, buildRoot, strlen(buildRoot))) {
    01270                      rpmError(RPMERR_BADSPEC,
    01271                                 _("Symlink points to BuildRoot: %s -> %s\n"),
    01272                                 flp->fileURL, buf);
    01273                     fl->processingFailed = 1;
    01274                 }
    01275             }
    01276         }
    01277         s = buf;
    01278         (void) headerAddOrAppendEntry(h, RPMTAG_FILELINKTOS, RPM_STRING_ARRAY_TYPE,
    01279                                &s, 1);
    01280
    01281         if (flp->flags & RPMFILE_GHOST) {
    01282             flp->verifyFlags &= ~(RPMVERIFY_MD5 | RPMVERIFY_FILESIZE |
    01283                                 RPMVERIFY_LINKTO | RPMVERIFY_MTIME);
    01284         }
    01285         (void) headerAddOrAppendEntry(h, RPMTAG_FILEVERIFYFLAGS, RPM_INT32_TYPE,
    01286                                &(flp->verifyFlags), 1);
    01287
    01288         if (!isSrc && isDoc(fl, flp->fileURL))
    01289             flp->flags |= RPMFILE_DOC;
    01290         /* XXX Should directories have %doc/%config attributes? (#14531) */
    01291         if (S_ISDIR(flp->fl_mode))
    01292             flp->flags &= ~(RPMFILE_CONFIG|RPMFILE_DOC);
    01293
    01294         (void) headerAddOrAppendEntry(h, RPMTAG_FILEFLAGS, RPM_INT32_TYPE,
    01295                                &(flp->flags), 1);
    01296
    01297     }
    01298     (void) headerAddEntry(h, RPMTAG_SIZE, RPM_INT32_TYPE,
    01299                    &(fl->totalFileSize), 1);
    01300
    01301     /* XXX This should be added always so that packages look alike.
    01302      * XXX However, there is logic in files.c/depends.c that checks for
    01303      * XXX existence (rather than value) that will need to change as well.
    01304      */
    01305     if (multiLibMask)
    01306         (void) headerAddEntry(h, RPMTAG_MULTILIBS, RPM_INT32_TYPE,
    01307                        &multiLibMask, 1);
    01308
    01309     if (_addDotSlash)
    01310         (void) rpmlibNeedsFeature(h, "PayloadFilesHavePrefix", "4.0-1");
    01311
    01312     /* Choose how filenames are represented. */
    01313     if (_noDirTokens)
    01314         expandFilelist(h);
    01315     else {
    01316         compressFilelist(h);
    01317         /* Binary packages with dirNames cannot be installed by legacy rpm. */
    01318         (void) rpmlibNeedsFeature(h, "CompressedFileNames", "3.0.4-1");
    01319     }
    01320
    01321   { TFI_t fi = xcalloc(1, sizeof(*fi));
    01322     char * a, * d;
    01323
    01324     fi->type = TR_ADDED;
    01325     loadFi(h, fi);
    01326     fi->dnl = _free(fi->dnl);
    01327     fi->bnl = _free(fi->bnl);
    01328
    01329     fi->dnl = xmalloc(fi->fc * sizeof(*fi->dnl) + dpathlen);
    01330     d = (char *)(fi->dnl + fi->fc);
    01331     *d = '\0';
    01332
    01333     fi->bnl = xmalloc(fi->fc * (sizeof(*fi->bnl) + sizeof(*fi->dil)));
    01334     /*@-dependenttrans@*/ /* FIX: artifact of spoofing headerGetEntry */
    01335     fi->dil = (int *)(fi->bnl + fi->fc);
    01336     /*@=dependenttrans@*/
    01337
    01338     fi->apath = xmalloc(fi->fc * sizeof(*fi->apath) + apathlen);
    01339     a = (char *)(fi->apath + fi->fc);
    01340     *a = '\0';
    01341
    01342     fi->actions = xcalloc(sizeof(*fi->actions), fi->fc);
    01343     fi->fmapflags = xcalloc(sizeof(*fi->fmapflags), fi->fc);
    01344     fi->astriplen = 0;
    01345     if (fl->buildRootURL)
    01346         fi->astriplen = strlen(fl->buildRootURL);
    01347     fi->striplen = 0;
    01348     fi->fuser = NULL;
    01349     fi->fuids = xcalloc(sizeof(*fi->fuids), fi->fc);
    01350     fi->fgroup = NULL;
    01351     fi->fgids = xcalloc(sizeof(*fi->fgids), fi->fc);
    01352
    01353     /* Make the cpio list */
    01354     for (i = 0, flp = fl->fileList; i < fi->fc; i++, flp++) {
    01355         char * b;
    01356
    01357         /* Skip (possible) duplicate file entries, use last entry info. */
    01358         while (((flp - fl->fileList) < (fl->fileListRecsUsed - 1)) &&
    01359                 !strcmp(flp->fileURL, flp[1].fileURL))
    01360             flp++;
    01361
    01362         if (flp->flags & RPMFILE_EXCLUDE) {
    01363             i--;
    01364             continue;
    01365         }
    01366
    01367         /* Create disk directory and base name. */
    01368         fi->dil[i] = i;
    01369         /*@-dependenttrans@*/ /* FIX: artifact of spoofing headerGetEntry */
    01370         fi->dnl[fi->dil[i]] = d;
    01371         /*@=dependenttrans@*/
    01372 #ifdef IA64_SUCKS_ROCKS
    01373         (void) stpcpy(d, flp->diskURL);
    01374         d += strlen(d);
    01375 #else
    01376         d = stpcpy(d, flp->diskURL);
    01377 #endif
    01378
    01379         /* Make room for the dirName NUL, find start of baseName. */
    01380         for (b = d; b > fi->dnl[fi->dil[i]] && *b != '/'; b--)
    01381             b[1] = b[0];
    01382         b++;            /* dirname's end in '/' */
    01383         *b++ = '\0';    /* terminate dirname, b points to basename */
    01384         fi->bnl[i] = b;
    01385         d += 2;         /* skip both dirname and basename NUL's */
    01386
    01387         /* Create archive path, normally adding "./" */
    01388         /*@-dependenttrans@*/   /* FIX: xstrdup? nah ... */
    01389         fi->apath[i] = a;
    01390         /*@=dependenttrans@*/
    01391         if (_addDotSlash) {
    01392 #ifdef IA64_SUCKS_ROCKS
    01393             (void) stpcpy(a, "./");
    01394             a += strlen(a);
    01395 #else
    01396             a = stpcpy(a, "./");
    01397 #endif
    01398         }
    01399 #ifdef IA64_SUCKS_ROCKS
    01400         (void) stpcpy(a, (flp->fileURL + skipLen));
    01401         a += strlen(a);
    01402 #else
    01403         a = stpcpy(a, (flp->fileURL + skipLen));
    01404 #endif
    01405         a++;            /* skip apath NUL */
    01406
    01407         if (flp->flags & RPMFILE_GHOST) {
    01408             fi->actions[i] = FA_SKIP;
    01409             continue;
    01410         }
    01411         fi->actions[i] = FA_COPYOUT;
    01412         fi->fuids[i] = getUidS(flp->uname);
    01413         fi->fgids[i] = getGidS(flp->gname);
    01414         if (fi->fuids[i] == (uid_t)-1) fi->fuids[i] = 0;
    01415         if (fi->fgids[i] == (gid_t)-1) fi->fgids[i] = 0;
    01416         fi->fmapflags[i] = CPIO_MAP_PATH |
    01417                 CPIO_MAP_TYPE | CPIO_MAP_MODE | CPIO_MAP_UID | CPIO_MAP_GID;
    01418         if (isSrc)
    01419             fi->fmapflags[i] |= CPIO_FOLLOW_SYMLINKS;
    01420         if (flp->flags & RPMFILE_MULTILIB_MASK)
    01421             fi->fmapflags[i] |= CPIO_MULTILIB;
    01422
    01423     }
    01424     /*@-branchstate@*/
    01425     if (cpioList)
    01426         *cpioList = fi;
    01427     else
    01428         fi = _free(fi);
    01429     /*@=branchstate@*/
    01430   }
    01431 }
    01432
    01435 static /*@null@*/ FileListRec freeFileList(/*@only@*/ FileListRec fileList,
    01436                         int count)
    01437         /*@*/
    01438 {
    01439     while (count--) {
    01440         fileList[count].diskURL = _free(fileList[count].diskURL);
    01441         fileList[count].fileURL = _free(fileList[count].fileURL);
    01442         fileList[count].langs = _free(fileList[count].langs);
    01443     }
    01444     fileList = _free(fileList);
    01445     return NULL;
    01446 }
    01447
    01451 static int addFile(FileList fl, const char * diskURL, struct stat * statp)
    01452         /*@globals rpmGlobalMacroContext,
    01453                 fileSystem@*/
    01454         /*@modifies *statp, *fl, fl->processingFailed,
    01455                 fl->fileList, fl->fileListRecsAlloced, fl->fileListRecsUsed,
    01456                 fl->totalFileSize, fl->fileCount, fl->inFtw, fl->isDir,
    01457                 rpmGlobalMacroContext, fileSystem @*/
    01458 {
    01459     const char *fileURL = diskURL;
    01460     struct stat statbuf;
    01461     mode_t fileMode;
    01462     uid_t fileUid;
    01463     gid_t fileGid;
    01464     const char *fileUname;
    01465     const char *fileGname;
    01466     char *lang;
    01467
    01468     /* Path may have prepended buildRootURL, so locate the original filename. */
    01469     /*
    01470      * XXX There are 3 types of entry into addFile:
    01471      *
    01472      *  From                    diskUrl                 statp
    01473      *  =====================================================
    01474      *  processBinaryFile       path                    NULL
    01475      *  processBinaryFile       glob result path        NULL
    01476      *  myftw                   path                    stat
    01477      *
    01478      */
    01479     {   const char *fileName;
    01480         (void) urlPath(fileURL, &fileName);
    01481         if (fl->buildRootURL && strcmp(fl->buildRootURL, "/"))
    01482             fileURL += strlen(fl->buildRootURL);
    01483     }
    01484
    01485     /* XXX make sure '/' can be packaged also */
    01486     /*@-branchstate@*/
    01487     if (*fileURL == '\0')
    01488         fileURL = "/";
    01489     /*@=branchstate@*/
    01490
    01491     /* If we are using a prefix, validate the file */
    01492     if (!fl->inFtw && fl->prefix) {
    01493         const char *prefixTest;
    01494         const char *prefixPtr = fl->prefix;
    01495
    01496         (void) urlPath(fileURL, &prefixTest);
    01497         while (*prefixPtr && *prefixTest && (*prefixTest == *prefixPtr)) {
    01498             prefixPtr++;
    01499             prefixTest++;
    01500         }
    01501         if (*prefixPtr || (*prefixTest && *prefixTest != '/')) {
    01502             rpmError(RPMERR_BADSPEC, _("File doesn't match prefix (%s): %s\n"),
    01503                      fl->prefix, fileURL);
    01504             fl->processingFailed = 1;
    01505             return RPMERR_BADSPEC;
    01506         }
    01507     }
    01508
    01509     if (statp == NULL) {
    01510         statp = &statbuf;
    01511         memset(statp, 0, sizeof(*statp));
    01512         if (fl->devtype) {
    01513             time_t now = time(NULL);
    01514
    01515             /* XXX hack up a stat structure for a %dev(...) directive. */
    01516             statp->st_nlink = 1;
    01517             statp->st_rdev =
    01518                 ((fl->devmajor & 0xff) << 8) | (fl->devminor & 0xff);
    01519             statp->st_dev = statp->st_rdev;
    01520             statp->st_mode = (fl->devtype == 'b' ? S_IFBLK : S_IFCHR);
    01521             statp->st_mode |= (fl->cur_ar.ar_fmode & 0777);
    01522             statp->st_atime = now;
    01523             statp->st_mtime = now;
    01524             statp->st_ctime = now;
    01525         } else if (Lstat(diskURL, statp)) {
    01526             rpmError(RPMERR_BADSPEC, _("File not found: %s\n"), diskURL);
    01527             fl->processingFailed = 1;
    01528             return RPMERR_BADSPEC;
    01529         }
    01530     }
    01531
    01532     if ((! fl->isDir) && S_ISDIR(statp->st_mode)) {
    01533         /* We use our own ftw() call, because ftw() uses stat()    */
    01534         /* instead of lstat(), which causes it to follow symlinks! */
    01535         /* It also has better callback support.                    */
    01536
    01537         fl->inFtw = 1;  /* Flag to indicate file has buildRootURL prefixed */
    01538         fl->isDir = 1;  /* Keep it from following myftw() again         */
    01539         (void) myftw(diskURL, 16, (myftwFunc) addFile, fl);
    01540         fl->isDir = 0;
    01541         fl->inFtw = 0;
    01542         return 0;
    01543     }
    01544
    01545     fileMode = statp->st_mode;
    01546     fileUid = statp->st_uid;
    01547     fileGid = statp->st_gid;
    01548
    01549     if (S_ISDIR(fileMode) && fl->cur_ar.ar_dmodestr) {
    01550         fileMode &= S_IFMT;
    01551         fileMode |= fl->cur_ar.ar_dmode;
    01552     } else if (fl->cur_ar.ar_fmodestr != NULL) {
    01553         fileMode &= S_IFMT;
    01554         fileMode |= fl->cur_ar.ar_fmode;
    01555     }
    01556     if (fl->cur_ar.ar_user) {
    01557         fileUname = getUnameS(fl->cur_ar.ar_user);
    01558     } else {
    01559         fileUname = getUname(fileUid);
    01560     }
    01561     if (fl->cur_ar.ar_group) {
    01562         fileGname = getGnameS(fl->cur_ar.ar_group);
    01563     } else {
    01564         fileGname = getGname(fileGid);
    01565     }
    01566
    01567 #if 0   /* XXX this looks dumb to me */
    01568     if (! (fileUname && fileGname)) {
    01569         rpmError(RPMERR_BADSPEC, _("Bad owner/group: %s\n"), diskName);
    01570         fl->processingFailed = 1;
    01571         return RPMERR_BADSPEC;
    01572     }
    01573 #else
    01574     /* Default user/group to builder's user/group */
    01575     if (fileUname == NULL)
    01576         fileUname = getUname(getuid());
    01577     if (fileGname == NULL)
    01578         fileGname = getGname(getgid());
    01579 #endif
    01580
    01581 #ifdef  DYING   /* XXX duplicates with %exclude, use psm.c output instead. */
    01582     rpmMessage(RPMMESS_DEBUG, _("File%5d: %07o %s.%s\t %s\n"), fl->fileCount,
    01583         (unsigned)fileMode, fileUname, fileGname, fileURL);
    01584 #endif
    01585
    01586     /* Add to the file list */
    01587     if (fl->fileListRecsUsed == fl->fileListRecsAlloced) {
    01588         fl->fileListRecsAlloced += 128;
    01589         fl->fileList = xrealloc(fl->fileList,
    01590                         fl->fileListRecsAlloced * sizeof(*(fl->fileList)));
    01591     }
    01592
    01593     {   FileListRec flp = &fl->fileList[fl->fileListRecsUsed];
    01594         int i;
    01595
    01596         flp->fl_st = *statp;    /* structure assignment */
    01597         flp->fl_mode = fileMode;
    01598         flp->fl_uid = fileUid;
    01599         flp->fl_gid = fileGid;
    01600
    01601         flp->fileURL = xstrdup(fileURL);
    01602         flp->diskURL = xstrdup(diskURL);
    01603         flp->uname = fileUname;
    01604         flp->gname = fileGname;
    01605
    01606         if (fl->currentLangs && fl->nLangs > 0) {
    01607             char * ncl;
    01608             size_t nl = 0;
    01609
    01610             for (i = 0; i < fl->nLangs; i++)
    01611                 nl += strlen(fl->currentLangs[i]) + 1;
    01612
    01613             flp->langs = ncl = xmalloc(nl);
    01614             for (i = 0; i < fl->nLangs; i++) {
    01615                 const char *ocl;
    01616                 if (i)  *ncl++ = '|';
    01617                 for (ocl = fl->currentLangs[i]; *ocl != '\0'; ocl++)
    01618                         *ncl++ = *ocl;
    01619                 *ncl = '\0';
    01620             }
    01621         } else if (! parseForRegexLang(fileURL, &lang)) {
    01622             flp->langs = xstrdup(lang);
    01623         } else {
    01624             flp->langs = xstrdup("");
    01625         }
    01626
    01627         flp->flags = fl->currentFlags;
    01628         flp->specdFlags = fl->currentSpecdFlags;
    01629         flp->verifyFlags = fl->currentVerifyFlags;
    01630
    01631         if (multiLib
    01632             && !(flp->flags & RPMFILE_MULTILIB_MASK)
    01633             && !parseForRegexMultiLib(fileURL))
    01634             flp->flags |= multiLib;
    01635
    01636
    01637         /* Hard links need be counted only once. */
    01638         if (S_ISREG(flp->fl_mode) && flp->fl_nlink > 1) {
    01639             FileListRec ilp;
    01640             for (i = 0;  i < fl->fileListRecsUsed; i++) {
    01641                 ilp = fl->fileList + i;
    01642                 if (!S_ISREG(ilp->fl_mode))
    01643                     continue;
    01644                 if (flp->fl_nlink != ilp->fl_nlink)
    01645                     continue;
    01646                 if (flp->fl_ino != ilp->fl_ino)
    01647                     continue;
    01648                 if (flp->fl_dev != ilp->fl_dev)
    01649                     continue;
    01650                 break;
    01651             }
    01652         } else
    01653             i = fl->fileListRecsUsed;
    01654
    01655         if (S_ISREG(flp->fl_mode) && i >= fl->fileListRecsUsed)
    01656             fl->totalFileSize += flp->fl_size;
    01657     }
    01658
    01659     fl->fileListRecsUsed++;
    01660     fl->fileCount++;
    01661
    01662     return 0;
    01663 }
    01664
    01668 static int processBinaryFile(/*@unused@*/ Package pkg, FileList fl,
    01669                 const char * fileURL)
    01670         /*@globals rpmGlobalMacroContext,
    01671                 fileSystem@*/
    01672         /*@modifies *fl, fl->processingFailed,
    01673                 fl->fileList, fl->fileListRecsAlloced, fl->fileListRecsUsed,
    01674                 fl->totalFileSize, fl->fileCount, fl->inFtw, fl->isDir,
    01675                 rpmGlobalMacroContext, fileSystem @*/
    01676 {
    01677     int doGlob;
    01678     const char *diskURL = NULL;
    01679     int rc = 0;
    01680
    01681     doGlob = myGlobPatternP(fileURL);
    01682
    01683     /* Check that file starts with leading "/" */
    01684     {   const char * fileName;
    01685         (void) urlPath(fileURL, &fileName);
    01686         if (*fileName != '/') {
    01687             rpmError(RPMERR_BADSPEC, _("File needs leading \"/\": %s\n"),
    01688                         fileName);
    01689             rc = 1;
    01690             goto exit;
    01691         }
    01692     }
    01693
    01694     /* Copy file name or glob pattern removing multiple "/" chars. */
    01695     /*
    01696      * Note: rpmGetPath should guarantee a "canonical" path. That means
    01697      * that the following pathologies should be weeded out:
    01698      *          //bin//sh
    01699      *          //usr//bin/
    01700      *          /.././../usr/../bin//./sh
    01701      */
    01702     diskURL = rpmGenPath(fl->buildRootURL, NULL, fileURL);
    01703
    01704     if (doGlob) {
    01705         const char ** argv = NULL;
    01706         int argc = 0;
    01707         int i;
    01708
    01709         if (fl->noGlob) {
    01710             rpmError(RPMERR_BADSPEC, _("Glob not permitted: %s\n"),
    01711                         diskURL);
    01712             rc = 1;
    01713             goto exit;
    01714         }
    01715
    01716         /*@-branchstate@*/
    01717         rc = rpmGlob(diskURL, &argc, &argv);
    01718         if (rc == 0 && argc >= 1 && !myGlobPatternP(argv[0])) {
    01719             for (i = 0; i < argc; i++) {
    01720                 rc = addFile(fl, argv[i], NULL);
    01721                 argv[i] = _free(argv[i]);
    01722             }
    01723             argv = _free(argv);
    01724         } else {
    01725             rpmError(RPMERR_BADSPEC, _("File not found by glob: %s\n"),
    01726                         diskURL);
    01727             rc = 1;
    01728         }
    01729         /*@=branchstate@*/
    01730     } else {
    01731         rc = addFile(fl, diskURL, NULL);
    01732     }
    01733
    01734 exit:
    01735     diskURL = _free(diskURL);
    01736     if (rc)
    01737         fl->processingFailed = 1;
    01738     return rc;
    01739 }
    01740
    01743 static int processPackageFiles(Spec spec, Package pkg,
    01744                                int installSpecialDoc, int test)
    01745         /*@globals rpmGlobalMacroContext,
    01746                 fileSystem, internalState@*/
    01747         /*@modifies spec->macros,
    01748                 pkg->cpioList, pkg->fileList, pkg->specialDoc, pkg->header,
    01749                 rpmGlobalMacroContext, fileSystem, internalState @*/
    01750 {
    01751     HGE_t hge = (HGE_t)headerGetEntryMinMemory;
    01752     struct FileList_s fl;
    01753     char *s, **files, **fp;
    01754     const char *fileName;
    01755     char buf[BUFSIZ];
    01756     struct AttrRec_s arbuf;
    01757     AttrRec specialDocAttrRec = &arbuf;
    01758     char *specialDoc = NULL;
    01759
    01760 #ifdef MULTILIB
    01761     multiLib = rpmExpandNumeric("%{_multilibno}");
    01762     if (multiLib)
    01763         multiLib = RPMFILE_MULTILIB(multiLib);
    01764 #endif /* MULTILIB */
    01765
    01766     nullAttrRec(specialDocAttrRec);
    01767     pkg->cpioList = NULL;
    01768
    01769     if (pkg->fileFile) {
    01770         const char *ffn;
    01771         FILE * f;
    01772         FD_t fd;
    01773
    01774         /* XXX W2DO? urlPath might be useful here. */
    01775         if (*pkg->fileFile == '/') {
    01776             ffn = rpmGetPath(pkg->fileFile, NULL);
    01777         } else {
    01778             /* XXX FIXME: add %{_buildsubdir} */
    01779             ffn = rpmGetPath("%{_builddir}/",
    01780                 (spec->buildSubdir ? spec->buildSubdir : "") ,
    01781                 "/", pkg->fileFile, NULL);
    01782         }
    01783         fd = Fopen(ffn, "r.fpio");
    01784
    01785         if (fd == NULL || Ferror(fd)) {
    01786             rpmError(RPMERR_BADFILENAME,
    01787                 _("Could not open %%files file %s: %s\n"),
    01788                 ffn, Fstrerror(fd));
    01789             return RPMERR_BADFILENAME;
    01790         }
    01791         ffn = _free(ffn);
    01792
    01793         /*@+voidabstract@*/ f = fdGetFp(fd); /*@=voidabstract@*/
    01794         if (f != NULL)
    01795         while (fgets(buf, sizeof(buf), f)) {
    01796             handleComments(buf);
    01797             if (expandMacros(spec, spec->macros, buf, sizeof(buf))) {
    01798                 rpmError(RPMERR_BADSPEC, _("line: %s\n"), buf);
    01799                 return RPMERR_BADSPEC;
    01800             }
    01801             appendStringBuf(pkg->fileList, buf);
    01802         }
    01803         (void) Fclose(fd);
    01804     }
    01805
    01806     /* Init the file list structure */
    01807     memset(&fl, 0, sizeof(fl));
    01808
    01809     /* XXX spec->buildRootURL == NULL, then xstrdup("") is returned */
    01810     fl.buildRootURL = rpmGenPath(spec->rootURL, spec->buildRootURL, NULL);
    01811
    01812     if (hge(pkg->header, RPMTAG_DEFAULTPREFIX, NULL, (void **)&fl.prefix, NULL))
    01813         fl.prefix = xstrdup(fl.prefix);
    01814     else
    01815         fl.prefix = NULL;
    01816
    01817     fl.fileCount = 0;
    01818     fl.totalFileSize = 0;
    01819     fl.processingFailed = 0;
    01820
    01821     fl.passedSpecialDoc = 0;
    01822     fl.isSpecialDoc = 0;
    01823
    01824     fl.isDir = 0;
    01825     fl.inFtw = 0;
    01826     fl.currentFlags = 0;
    01827     fl.currentVerifyFlags = 0;
    01828
    01829     fl.noGlob = 0;
    01830     fl.devtype = 0;
    01831     fl.devmajor = 0;
    01832     fl.devminor = 0;
    01833
    01834     nullAttrRec(&fl.cur_ar);
    01835     nullAttrRec(&fl.def_ar);
    01836
    01837     fl.defVerifyFlags = RPMVERIFY_ALL;
    01838     fl.nLangs = 0;
    01839     fl.currentLangs = NULL;
    01840
    01841     fl.currentSpecdFlags = 0;
    01842     fl.defSpecdFlags = 0;
    01843
    01844     fl.docDirCount = 0;
    01845     fl.docDirs[fl.docDirCount++] = xstrdup("/usr/doc");
    01846     fl.docDirs[fl.docDirCount++] = xstrdup("/usr/man");
    01847     fl.docDirs[fl.docDirCount++] = xstrdup("/usr/info");
    01848     fl.docDirs[fl.docDirCount++] = xstrdup("/usr/X11R6/man");
    01849     fl.docDirs[fl.docDirCount++] = xstrdup("/usr/share/doc");
    01850     fl.docDirs[fl.docDirCount++] = xstrdup("/usr/share/man");
    01851     fl.docDirs[fl.docDirCount++] = xstrdup("/usr/share/info");
    01852     fl.docDirs[fl.docDirCount++] = rpmGetPath("%{_docdir}", NULL);
    01853     fl.docDirs[fl.docDirCount++] = rpmGetPath("%{_mandir}", NULL);
    01854     fl.docDirs[fl.docDirCount++] = rpmGetPath("%{_infodir}", NULL);
    01855
    01856     fl.fileList = NULL;
    01857     fl.fileListRecsAlloced = 0;
    01858     fl.fileListRecsUsed = 0;
    01859
    01860     s = getStringBuf(pkg->fileList);
    01861     files = splitString(s, strlen(s), '\n');
    01862
    01863     for (fp = files; *fp != NULL; fp++) {
    01864         s = *fp;
    01865         SKIPSPACE(s);
    01866         if (*s == '\0')
    01867             continue;
    01868         fileName = NULL;
    01869         /*@-nullpass@*/ /* LCL: buf is NULL ?!? */
    01870         strcpy(buf, s);
    01871         /*@=nullpass@*/
    01872
    01873         /* Reset for a new line in %files */
    01874         fl.isDir = 0;
    01875         fl.inFtw = 0;
    01876         fl.currentFlags = 0;
    01877         /* turn explicit flags into %def'd ones (gosh this is hacky...) */
    01878         fl.currentSpecdFlags = ((unsigned)fl.defSpecdFlags) >> 8;
    01879         fl.currentVerifyFlags = fl.defVerifyFlags;
    01880         fl.isSpecialDoc = 0;
    01881
    01882         fl.noGlob = 0;
    01883         fl.devtype = 0;
    01884         fl.devmajor = 0;
    01885         fl.devminor = 0;
    01886
    01887         /* XXX should reset to %deflang value */
    01888         if (fl.currentLangs) {
    01889             int i;
    01890             for (i = 0; i < fl.nLangs; i++)
    01891                 /*@-unqualifiedtrans@*/
    01892                 fl.currentLangs[i] = _free(fl.currentLangs[i]);
    01893                 /*@=unqualifiedtrans@*/
    01894             fl.currentLangs = _free(fl.currentLangs);
    01895         }
    01896         fl.nLangs = 0;
    01897
    01898         dupAttrRec(&fl.def_ar, &fl.cur_ar);
    01899
    01900         /*@-nullpass@*/ /* LCL: buf is NULL ?!? */
    01901         if (parseForVerify(buf, &fl))
    01902             continue;
    01903         if (parseForAttr(buf, &fl))
    01904             continue;
    01905         if (parseForDev(buf, &fl))
    01906             continue;
    01907         if (parseForConfig(buf, &fl))
    01908             continue;
    01909         if (parseForLang(buf, &fl))
    01910             continue;
    01911         /*@-nullstate@*/        /* FIX: pkg->fileFile might be NULL */
    01912         if (parseForSimple(spec, pkg, buf, &fl, &fileName))
    01913         /*@=nullstate@*/
    01914             continue;
    01915         /*@=nullpass@*/
    01916         if (fileName == NULL)
    01917             continue;
    01918
    01919         /*@-branchstate@*/
    01920         if (fl.isSpecialDoc) {
    01921             /* Save this stuff for last */
    01922             specialDoc = _free(specialDoc);
    01923             specialDoc = xstrdup(fileName);
    01924             dupAttrRec(&fl.cur_ar, specialDocAttrRec);
    01925         } else {
    01926             /*@-nullstate@*/    /* FIX: pkg->fileFile might be NULL */
    01927             (void) processBinaryFile(pkg, &fl, fileName);
    01928             /*@=nullstate@*/
    01929         }
    01930         /*@=branchstate@*/
    01931     }
    01932
    01933     /* Now process special doc, if there is one */
    01934     if (specialDoc) {
    01935         if (installSpecialDoc) {
    01936             (void) doScript(spec, RPMBUILD_STRINGBUF, "%doc", pkg->specialDoc, test);
    01937         }
    01938
    01939         /* Reset for %doc */
    01940         fl.isDir = 0;
    01941         fl.inFtw = 0;
    01942         fl.currentFlags = 0;
    01943         fl.currentVerifyFlags = 0;
    01944
    01945         fl.noGlob = 0;
    01946         fl.devtype = 0;
    01947         fl.devmajor = 0;
    01948         fl.devminor = 0;
    01949
    01950         /* XXX should reset to %deflang value */
    01951         if (fl.currentLangs) {
    01952             int i;
    01953             for (i = 0; i < fl.nLangs; i++)
    01954                 /*@-unqualifiedtrans@*/
    01955                 fl.currentLangs[i] = _free(fl.currentLangs[i]);
    01956                 /*@=unqualifiedtrans@*/
    01957             fl.currentLangs = _free(fl.currentLangs);
    01958         }
    01959         fl.nLangs = 0;
    01960
    01961         dupAttrRec(specialDocAttrRec, &fl.cur_ar);
    01962         freeAttrRec(specialDocAttrRec);
    01963
    01964         /*@-nullstate@*/        /* FIX: pkg->fileFile might be NULL */
    01965         (void) processBinaryFile(pkg, &fl, specialDoc);
    01966         /*@=nullstate@*/
    01967
    01968         specialDoc = _free(specialDoc);
    01969     }
    01970
    01971     freeSplitString(files);
    01972
    01973     if (fl.processingFailed)
    01974         goto exit;
    01975
    01976     /* Verify that file attributes scope over hardlinks correctly. */
    01977     if (checkHardLinks(&fl))
    01978         (void) rpmlibNeedsFeature(pkg->header,
    01979                         "PartialHardlinkSets", "4.0.4-1");
    01980
    01981     genCpioListAndHeader(&fl, (TFI_t *)&pkg->cpioList, pkg->header, 0);
    01982
    01983     if (spec->timeCheck)
    01984         timeCheck(spec->timeCheck, pkg->header);
    01985
    01986 exit:
    01987     fl.buildRootURL = _free(fl.buildRootURL);
    01988     fl.prefix = _free(fl.prefix);
    01989
    01990     freeAttrRec(&fl.cur_ar);
    01991     freeAttrRec(&fl.def_ar);
    01992
    01993     if (fl.currentLangs) {
    01994         int i;
    01995         for (i = 0; i < fl.nLangs; i++)
    01996             /*@-unqualifiedtrans@*/
    01997             fl.currentLangs[i] = _free(fl.currentLangs[i]);
    01998             /*@=unqualifiedtrans@*/
    01999         fl.currentLangs = _free(fl.currentLangs);
    02000     }
    02001
    02002     fl.fileList = freeFileList(fl.fileList, fl.fileListRecsUsed);
    02003     while (fl.docDirCount--)
    02004         fl.docDirs[fl.docDirCount] = _free(fl.docDirs[fl.docDirCount]);
    02005     return fl.processingFailed;
    02006 }
    02007
    02008 void initSourceHeader(Spec spec)
    02009 {
    02010     HeaderIterator hi;
    02011     int_32 tag, type, count;
    02012     const void * ptr;
    02013
    02014     spec->sourceHeader = headerNew();
    02015     /* Only specific tags are added to the source package header */
    02016     /*@-branchstate@*/
    02017     for (hi = headerInitIterator(spec->packages->header);
    02018         headerNextIterator(hi, &tag, &type, &ptr, &count);
    02019         ptr = headerFreeData(ptr, type))
    02020     {
    02021         switch (tag) {
    02022         case RPMTAG_NAME:
    02023         case RPMTAG_VERSION:
    02024         case RPMTAG_RELEASE:
    02025         case RPMTAG_EPOCH:
    02026         case RPMTAG_SUMMARY:
    02027         case RPMTAG_DESCRIPTION:
    02028         case RPMTAG_PACKAGER:
    02029         case RPMTAG_DISTRIBUTION:
    02030         case RPMTAG_DISTURL:
    02031         case RPMTAG_VENDOR:
    02032         case RPMTAG_LICENSE:
    02033         case RPMTAG_GROUP:
    02034         case RPMTAG_OS:
    02035         case RPMTAG_ARCH:
    02036         case RPMTAG_CHANGELOGTIME:
    02037         case RPMTAG_CHANGELOGNAME:
    02038         case RPMTAG_CHANGELOGTEXT:
    02039         case RPMTAG_URL:
    02040         case HEADER_I18NTABLE:
    02041             if (ptr)
    02042                 (void)headerAddEntry(spec->sourceHeader, tag, type, ptr, count);
    02043             /*@switchbreak@*/ break;
    02044         default:
    02045             /* do not copy */
    02046             /*@switchbreak@*/ break;
    02047         }
    02048     }
    02049     hi = headerFreeIterator(hi);
    02050     /*@=branchstate@*/
    02051
    02052     /* Add the build restrictions */
    02053     /*@-branchstate@*/
    02054     for (hi = headerInitIterator(spec->buildRestrictions);
    02055         headerNextIterator(hi, &tag, &type, &ptr, &count);
    02056         ptr = headerFreeData(ptr, type))
    02057     {
    02058         if (ptr)
    02059             (void) headerAddEntry(spec->sourceHeader, tag, type, ptr, count);
    02060     }
    02061     hi = headerFreeIterator(hi);
    02062     /*@=branchstate@*/
    02063
    02064     if (spec->BANames && spec->BACount > 0) {
    02065         (void) headerAddEntry(spec->sourceHeader, RPMTAG_BUILDARCHS,
    02066                        RPM_STRING_ARRAY_TYPE,
    02067                        spec->BANames, spec->BACount);
    02068     }
    02069 }
    02070
    02071 int processSourceFiles(Spec spec)
    02072 {
    02073     struct Source *srcPtr;
    02074     StringBuf sourceFiles;
    02075     int x, isSpec = 1;
    02076     struct FileList_s fl;
    02077     char *s, **files, **fp;
    02078     Package pkg;
    02079
    02080     sourceFiles = newStringBuf();
    02081
    02082     /* XXX
    02083      * XXX This is where the source header for noarch packages needs
    02084      * XXX to be initialized.
    02085      */
    02086     if (spec->sourceHeader == NULL)
    02087         initSourceHeader(spec);
    02088
    02089     /* Construct the file list and source entries */
    02090     appendLineStringBuf(sourceFiles, spec->specFile);
    02091     if (spec->sourceHeader != NULL)
    02092     for (srcPtr = spec->sources; srcPtr != NULL; srcPtr = srcPtr->next) {
    02093         if (srcPtr->flags & RPMBUILD_ISSOURCE) {
    02094             (void) headerAddOrAppendEntry(spec->sourceHeader, RPMTAG_SOURCE,
    02095                                    RPM_STRING_ARRAY_TYPE, &srcPtr->source, 1);
    02096             if (srcPtr->flags & RPMBUILD_ISNO) {
    02097                 (void) headerAddOrAppendEntry(spec->sourceHeader, RPMTAG_NOSOURCE,
    02098                                        RPM_INT32_TYPE, &srcPtr->num, 1);
    02099             }
    02100         }
    02101         if (srcPtr->flags & RPMBUILD_ISPATCH) {
    02102             (void) headerAddOrAppendEntry(spec->sourceHeader, RPMTAG_PATCH,
    02103                                    RPM_STRING_ARRAY_TYPE, &srcPtr->source, 1);
    02104             if (srcPtr->flags & RPMBUILD_ISNO) {
    02105                 (void) headerAddOrAppendEntry(spec->sourceHeader, RPMTAG_NOPATCH,
    02106                                        RPM_INT32_TYPE, &srcPtr->num, 1);
    02107             }
    02108         }
    02109
    02110       { const char * sfn;
    02111         sfn = rpmGetPath( ((srcPtr->flags & RPMBUILD_ISNO) ? "!" : ""),
    02112                 "%{_sourcedir}/", srcPtr->source, NULL);
    02113         appendLineStringBuf(sourceFiles, sfn);
    02114         sfn = _free(sfn);
    02115       }
    02116     }
    02117
    02118     for (pkg = spec->packages; pkg != NULL; pkg = pkg->next) {
    02119         for (srcPtr = pkg->icon; srcPtr != NULL; srcPtr = srcPtr->next) {
    02120             const char * sfn;
    02121             sfn = rpmGetPath( ((srcPtr->flags & RPMBUILD_ISNO) ? "!" : ""),
    02122                 "%{_sourcedir}/", srcPtr->source, NULL);
    02123             appendLineStringBuf(sourceFiles, sfn);
    02124             sfn = _free(sfn);
    02125         }
    02126     }
    02127
    02128     spec->sourceCpioList = NULL;
    02129
    02130     fl.fileList = xcalloc((spec->numSources + 1), sizeof(*fl.fileList));
    02131     fl.processingFailed = 0;
    02132     fl.fileListRecsUsed = 0;
    02133     fl.totalFileSize = 0;
    02134     fl.prefix = NULL;
    02135     fl.buildRootURL = NULL;
    02136
    02137     s = getStringBuf(sourceFiles);
    02138     files = splitString(s, strlen(s), '\n');
    02139
    02140     /* The first source file is the spec file */
    02141     x = 0;
    02142     for (fp = files; *fp != NULL; fp++) {
    02143         const char * diskURL, *diskPath;
    02144         FileListRec flp;
    02145
    02146         diskURL = *fp;
    02147         SKIPSPACE(diskURL);
    02148         if (! *diskURL)
    02149             continue;
    02150
    02151         flp = &fl.fileList[x];
    02152
    02153         flp->flags = isSpec ? RPMFILE_SPECFILE : 0;
    02154         /* files with leading ! are no source files */
    02155         if (*diskURL == '!') {
    02156             flp->flags |= RPMFILE_GHOST;
    02157             diskURL++;
    02158         }
    02159
    02160         (void) urlPath(diskURL, &diskPath);
    02161
    02162         flp->diskURL = xstrdup(diskURL);
    02163         diskPath = strrchr(diskPath, '/');
    02164         if (diskPath)
    02165             diskPath++;
    02166         else
    02167             diskPath = diskURL;
    02168
    02169         flp->fileURL = xstrdup(diskPath);
    02170         flp->verifyFlags = RPMVERIFY_ALL;
    02171
    02172         if (Stat(diskURL, &flp->fl_st)) {
    02173             rpmError(RPMERR_BADSPEC, _("Bad file: %s: %s\n"),
    02174                 diskURL, strerror(errno));
    02175             fl.processingFailed = 1;
    02176         }
    02177
    02178         flp->uname = getUname(flp->fl_uid);
    02179         flp->gname = getGname(flp->fl_gid);
    02180         flp->langs = xstrdup("");
    02181
    02182         fl.totalFileSize += flp->fl_size;
    02183
    02184         if (! (flp->uname && flp->gname)) {
    02185             rpmError(RPMERR_BADSPEC, _("Bad owner/group: %s\n"), diskURL);
    02186             fl.processingFailed = 1;
    02187         }
    02188
    02189         isSpec = 0;
    02190         x++;
    02191     }
    02192     fl.fileListRecsUsed = x;
    02193     freeSplitString(files);
    02194
    02195     if (! fl.processingFailed) {
    02196         if (spec->sourceHeader != NULL)
    02197             genCpioListAndHeader(&fl, (TFI_t *)&spec->sourceCpioList,
    02198                         spec->sourceHeader, 1);
    02199     }
    02200
    02201     sourceFiles = freeStringBuf(sourceFiles);
    02202     fl.fileList = freeFileList(fl.fileList, fl.fileListRecsUsed);
    02203     return fl.processingFailed;
    02204 }
    02205
    02208 static StringBuf getOutputFrom(char * dir, char * argv[],
    02209                         const char * writePtr, int writeBytesLeft,
    02210                         int failNonZero)
    02211         /*@globals fileSystem, internalState@*/
    02212         /*@modifies fileSystem, internalState@*/
    02213 {
    02214     int progPID;
    02215     int toProg[2];
    02216     int fromProg[2];
    02217     int status;
    02218     void *oldhandler;
    02219     StringBuf readBuff;
    02220     int done;
    02221
    02222     /*@-type@*/ /* FIX: cast? */
    02223     oldhandler = signal(SIGPIPE, SIG_IGN);
    02224     /*@=type@*/
    02225
    02226     toProg[0] = toProg[1] = 0;
    02227     (void) pipe(toProg);
    02228     fromProg[0] = fromProg[1] = 0;
    02229     (void) pipe(fromProg);
    02230
    02231     if (!(progPID = fork())) {
    02232         (void) close(toProg[1]);
    02233         (void) close(fromProg[0]);
    02234
    02235         (void) dup2(toProg[0], STDIN_FILENO);   /* Make stdin the in pipe */
    02236         (void) dup2(fromProg[1], STDOUT_FILENO); /* Make stdout the out pipe */
    02237
    02238         (void) close(toProg[0]);
    02239         (void) close(fromProg[1]);
    02240
    02241         if (dir) {
    02242             (void) chdir(dir);
    02243         }
    02244
    02245         (void) execvp(argv[0], argv);
    02246         /* XXX this error message is probably not seen. */
    02247         rpmError(RPMERR_EXEC, _("Couldn't exec %s: %s\n"),
    02248                 argv[0], strerror(errno));
    02249         _exit(RPMERR_EXEC);
    02250     }
    02251     if (progPID < 0) {
    02252         rpmError(RPMERR_FORK, _("Couldn't fork %s: %s\n"),
    02253                 argv[0], strerror(errno));
    02254         return NULL;
    02255     }
    02256
    02257     (void) close(toProg[0]);
    02258     (void) close(fromProg[1]);
    02259
    02260     /* Do not block reading or writing from/to prog. */
    02261     (void) fcntl(fromProg[0], F_SETFL, O_NONBLOCK);
    02262     (void) fcntl(toProg[1], F_SETFL, O_NONBLOCK);
    02263
    02264     readBuff = newStringBuf();
    02265
    02266     do {
    02267         fd_set ibits, obits;
    02268         struct timeval tv;
    02269         int nfd, nbw, nbr;
    02270         int rc;
    02271
    02272         done = 0;
    02273 top:
    02274         /* XXX the select is mainly a timer since all I/O is non-blocking */
    02275         FD_ZERO(&ibits);
    02276         FD_ZERO(&obits);
    02277         if (fromProg[0] >= 0) {
    02278             FD_SET(fromProg[0], &ibits);
    02279         }
    02280         if (toProg[1] >= 0) {
    02281             FD_SET(toProg[1], &obits);
    02282         }
    02283         tv.tv_sec = 1;
    02284         tv.tv_usec = 0;
    02285         nfd = ((fromProg[0] > toProg[1]) ? fromProg[0] : toProg[1]);
    02286         if ((rc = select(nfd, &ibits, &obits, NULL, &tv)) < 0) {
    02287             if (errno == EINTR)
    02288                 goto top;
    02289             break;
    02290         }
    02291
    02292         /* Write any data to program */
    02293         if (toProg[1] >= 0 && FD_ISSET(toProg[1], &obits)) {
    02294           if (writeBytesLeft) {
    02295             if ((nbw = write(toProg[1], writePtr,
    02296                     (1024<writeBytesLeft) ? 1024 : writeBytesLeft)) < 0) {
    02297                 if (errno != EAGAIN) {
    02298                     perror("getOutputFrom()");
    02299                     exit(EXIT_FAILURE);
    02300                 }
    02301                 nbw = 0;
    02302             }
    02303             writeBytesLeft -= nbw;
    02304             writePtr += nbw;
    02305           } else if (toProg[1] >= 0) {  /* close write fd */
    02306             (void) close(toProg[1]);
    02307             toProg[1] = -1;
    02308           }
    02309         }
    02310
    02311         /* Read any data from prog */
    02312         {   char buf[BUFSIZ+1];
    02313             while ((nbr = read(fromProg[0], buf, sizeof(buf)-1)) > 0) {
    02314                 buf[nbr] = '\0';
    02315                 appendStringBuf(readBuff, buf);
    02316             }
    02317         }
    02318
    02319         /* terminate on (non-blocking) EOF or error */
    02320         done = (nbr == 0 || (nbr < 0 && errno != EAGAIN));
    02321
    02322     } while (!done);
    02323
    02324     /* Clean up */
    02325     if (toProg[1] >= 0)
    02326         (void) close(toProg[1]);
    02327     if (fromProg[0] >= 0)
    02328         (void) close(fromProg[0]);
    02329     /*@-type@*/ /* FIX: cast? */
    02330     (void) signal(SIGPIPE, oldhandler);
    02331     /*@=type@*/
    02332
    02333     /* Collect status from prog */
    02334     (void)waitpid(progPID, &status, 0);
    02335     if (failNonZero && (!WIFEXITED(status) || WEXITSTATUS(status))) {
    02336         rpmError(RPMERR_EXEC, _("%s failed\n"), argv[0]);
    02337         return NULL;
    02338     }
    02339     if (writeBytesLeft) {
    02340         rpmError(RPMERR_EXEC, _("failed to write all data to %s\n"), argv[0]);
    02341         return NULL;
    02342     }
    02343     return readBuff;
    02344 }
    02345
    02348 typedef struct {
    02349 /*@observer@*/ /*@null@*/ const char * msg;
    02350 /*@observer@*/ const char * argv[4];
    02351     rpmTag ntag;
    02352     rpmTag vtag;
    02353     rpmTag ftag;
    02354     int mask;
    02355     int xor;
    02356 } DepMsg_t;
    02357
    02360 /*@-exportlocal -exportheadervar@*/
    02361 /*@unchecked@*/
    02362 DepMsg_t depMsgs[] = {
    02363   { "Provides",         { "%{__find_provides}", NULL, NULL, NULL },
    02364         RPMTAG_PROVIDENAME, RPMTAG_PROVIDEVERSION, RPMTAG_PROVIDEFLAGS,
    02365         0, -1 },
    02366   { "PreReq",           { NULL, NULL, NULL, NULL },
    02367         RPMTAG_REQUIRENAME, RPMTAG_REQUIREVERSION, RPMTAG_REQUIREFLAGS,
    02368         RPMSENSE_PREREQ, 0 },
    02369   { "Requires(interp)", { NULL, "interp", NULL, NULL },
    02370         -1, -1, RPMTAG_REQUIREFLAGS,
    02371         _notpre(RPMSENSE_INTERP), 0 },
    02372   { "Requires(rpmlib)", { NULL, "rpmlib", NULL, NULL },
    02373         -1, -1, RPMTAG_REQUIREFLAGS,
    02374         _notpre(RPMSENSE_RPMLIB), 0 },
    02375   { "Requires(verify)", { NULL, "verify", NULL, NULL },
    02376         -1, -1, RPMTAG_REQUIREFLAGS,
    02377         RPMSENSE_SCRIPT_VERIFY, 0 },
    02378   { "Requires(pre)",    { NULL, "pre", NULL, NULL },
    02379         -1, -1, RPMTAG_REQUIREFLAGS,
    02380         _notpre(RPMSENSE_SCRIPT_PRE), 0 },
    02381   { "Requires(post)",   { NULL, "post", NULL, NULL },
    02382         -1, -1, RPMTAG_REQUIREFLAGS,
    02383         _notpre(RPMSENSE_SCRIPT_POST), 0 },
    02384   { "Requires(preun)",  { NULL, "preun", NULL, NULL },
    02385         -1, -1, RPMTAG_REQUIREFLAGS,
    02386         _notpre(RPMSENSE_SCRIPT_PREUN), 0 },
    02387   { "Requires(postun)", { NULL, "postun", NULL, NULL },
    02388         -1, -1, RPMTAG_REQUIREFLAGS,
    02389         _notpre(RPMSENSE_SCRIPT_POSTUN), 0 },
    02390   { "Requires",         { "%{__find_requires}", NULL, NULL, NULL },
    02391         -1, -1, RPMTAG_REQUIREFLAGS,    /* XXX inherit name/version arrays */
    02392         RPMSENSE_PREREQ, RPMSENSE_PREREQ },
    02393   { "Conflicts",        { "%{__find_conflicts}", NULL, NULL, NULL },
    02394         RPMTAG_CONFLICTNAME, RPMTAG_CONFLICTVERSION, RPMTAG_CONFLICTFLAGS,
    02395         0, -1 },
    02396   { "Obsoletes",        { "%{__find_obsoletes}", NULL, NULL, NULL },
    02397         RPMTAG_OBSOLETENAME, RPMTAG_OBSOLETEVERSION, RPMTAG_OBSOLETEFLAGS,
    02398         0, -1 },
    02399   { NULL,               { NULL, NULL, NULL, NULL },     0, 0, 0, 0, 0 }
    02400 };
    02401 /*@=exportlocal =exportheadervar@*/
    02402
    02405 static int generateDepends(Spec spec, Package pkg, TFI_t cpioList, int multiLib)
    02406         /*@globals rpmGlobalMacroContext,
    02407                 fileSystem, internalState @*/
    02408         /*@modifies cpioList, rpmGlobalMacroContext,
    02409                 fileSystem, internalState @*/
    02410 {
    02411     TFI_t fi = cpioList;
    02412     StringBuf writeBuf;
    02413     int writeBytes;
    02414     StringBuf readBuf;
    02415     DepMsg_t *dm;
    02416     char ** myargv;
    02417     int failnonzero = 0;
    02418     int rc = 0;
    02419     int ac;
    02420     int i;
    02421
    02422     myargv = xcalloc(5, sizeof(*myargv));
    02423
    02424     if (!(fi && fi->fc > 0))
    02425         return 0;
    02426
    02427     if (! (pkg->autoReq || pkg->autoProv))
    02428         return 0;
    02429
    02430     writeBuf = newStringBuf();
    02431     for (i = 0, writeBytes = 0; i < fi->fc; i++) {
    02432
    02433         if (fi->fmapflags && multiLib == 2) {
    02434             if (!(fi->fmapflags[i] & CPIO_MULTILIB))
    02435                 continue;
    02436             fi->fmapflags[i] &= ~CPIO_MULTILIB;
    02437         }
    02438
    02439         appendStringBuf(writeBuf, fi->dnl[fi->dil[i]]);
    02440         writeBytes += strlen(fi->dnl[fi->dil[i]]);
    02441         appendLineStringBuf(writeBuf, fi->bnl[i]);
    02442         writeBytes += strlen(fi->bnl[i]) + 1;
    02443     }
    02444
    02445     for (dm = depMsgs; dm->msg != NULL; dm++) {
    02446         int tag, tagflags;
    02447
    02448         tag = (dm->ftag > 0) ? dm->ftag : dm->ntag;
    02449         tagflags = 0;
    02450
    02451         switch(tag) {
    02452         case RPMTAG_PROVIDEFLAGS:
    02453             if (!pkg->autoProv)
    02454                 continue;
    02455             failnonzero = 1;
    02456             tagflags = RPMSENSE_FIND_PROVIDES;
    02457             /*@switchbreak@*/ break;
    02458         case RPMTAG_REQUIREFLAGS:
    02459             if (!pkg->autoReq)
    02460                 continue;
    02461             failnonzero = 0;
    02462             tagflags = RPMSENSE_FIND_REQUIRES;
    02463             /*@switchbreak@*/ break;
    02464         default:
    02465             continue;
    02466             /*@notreached@*/ /*@switchbreak@*/ break;
    02467         }
    02468
    02469         /* Get the script name (and possible args) to run */
    02470         if (dm->argv[0] != NULL) {
    02471             const char ** av;
    02472             char * s;
    02473
    02474             /*@-nullderef@*/    /* FIX: double indirection. @*/
    02475             s = rpmExpand(dm->argv[0], NULL);
    02476             /*@=nullderef@*/
    02477             if (!(s != NULL && *s != '%' && *s != '\0')) {
    02478                 s = _free(s);
    02479                 continue;
    02480             }
    02481
    02482             if (!(i = poptParseArgvString(s, &ac, (const char ***)&av))
    02483             && ac > 0 && av != NULL)
    02484             {
    02485                 myargv = xrealloc(myargv, (ac + 5) * sizeof(*myargv));
    02486                 for (i = 0; i < ac; i++)
    02487                     myargv[i] = xstrdup(av[i]);
    02488             }
    02489             av = _free(av);
    02490             s = _free(s);
    02491         }
    02492
    02493         if (myargv[0] == NULL)
    02494             continue;
    02495
    02496         rpmMessage(RPMMESS_NORMAL, _("Finding  %s: (using %s)...\n"),
    02497                 dm->msg, myargv[0]);
    02498
    02499 #if 0
    02500         if (*myargv[0] != '/') {        /* XXX FIXME: stat script here */
    02501             myargv[0] = _free(myargv[0]);
    02502             continue;
    02503         }
    02504 #endif
    02505
    02506         /* Expand rest of script arguments (if any) */
    02507         for (i = 1; i < 4; i++) {
    02508             if (dm->argv[i] == NULL)
    02509                 break;
    02510             /*@-nullderef@*/    /* FIX: double indirection. @*/
    02511             myargv[ac++] = rpmExpand(dm->argv[i], NULL);
    02512             /*@=nullderef@*/
    02513         }
    02514
    02515         myargv[ac] = NULL;
    02516         readBuf = getOutputFrom(NULL, myargv,
    02517                         getStringBuf(writeBuf), writeBytes, failnonzero);
    02518
    02519         /* Free expanded args */
    02520         for (i = 0; i < ac; i++)
    02521             myargv[i] = _free(myargv[i]);
    02522
    02523         if (readBuf == NULL) {
    02524             rc = RPMERR_EXEC;
    02525             rpmError(rc, _("Failed to find %s:\n"), dm->msg);
    02526             break;
    02527         }
    02528
    02529         /* Parse dependencies into header */
    02530         tagflags &= ~RPMSENSE_MULTILIB;
    02531         if (multiLib > 1)
    02532             tagflags |=  RPMSENSE_MULTILIB;
    02533         else
    02534             tagflags &= ~RPMSENSE_MULTILIB;
    02535         rc = parseRCPOT(spec, pkg, getStringBuf(readBuf), tag, 0, tagflags);
    02536         readBuf = freeStringBuf(readBuf);
    02537
    02538         if (rc) {
    02539             rpmError(rc, _("Failed to find %s:\n"), dm->msg);
    02540             break;
    02541         }
    02542     }
    02543
    02544     writeBuf = freeStringBuf(writeBuf);
    02545     myargv = _free(myargv);
    02546     return rc;
    02547 }
    02548
    02551 static void printDepMsg(DepMsg_t * dm, int count, const char ** names,
    02552                 const char ** versions, int *flags)
    02553         /*@*/
    02554 {
    02555     int hasVersions = (versions != NULL);
    02556     int hasFlags = (flags != NULL);
    02557     int bingo = 0;
    02558     int i;
    02559
    02560     for (i = 0; i < count; i++, names++, versions++, flags++) {
    02561         if (hasFlags && !((*flags & dm->mask) ^ dm->xor))
    02562             continue;
    02563         if (bingo == 0) {
    02564             rpmMessage(RPMMESS_NORMAL, "%s:", (dm->msg ? dm->msg : ""));
    02565             bingo = 1;
    02566         }
    02567         rpmMessage(RPMMESS_NORMAL, " %s", *names);
    02568
    02569         if (hasFlags && isDependsMULTILIB(*flags))
    02570             rpmMessage(RPMMESS_NORMAL, " (multilib)");
    02571
    02572         if (hasVersions && !(*versions != NULL && **versions != '\0'))
    02573             continue;
    02574         if (!(hasFlags && (*flags && RPMSENSE_SENSEMASK)))
    02575             continue;
    02576
    02577         rpmMessage(RPMMESS_NORMAL, " ");
    02578         if (*flags & RPMSENSE_LESS)
    02579             rpmMessage(RPMMESS_NORMAL, "<");
    02580         if (*flags & RPMSENSE_GREATER)
    02581             rpmMessage(RPMMESS_NORMAL, ">");
    02582         if (*flags & RPMSENSE_EQUAL)
    02583             rpmMessage(RPMMESS_NORMAL, "=");
    02584
    02585         rpmMessage(RPMMESS_NORMAL, " %s", *versions);
    02586     }
    02587     if (bingo)
    02588         rpmMessage(RPMMESS_NORMAL, "\n");
    02589 }
    02590
    02593 static void printDeps(Header h)
    02594         /*@*/
    02595 {
    02596     HGE_t hge = (HGE_t)headerGetEntryMinMemory;
    02597     HFD_t hfd = headerFreeData;
    02598     const char ** names = NULL;
    02599     rpmTagType dnt = -1;
    02600     const char ** versions = NULL;
    02601     rpmTagType dvt = -1;
    02602     int * flags = NULL;
    02603     DepMsg_t * dm;
    02604     int count, xx;
    02605
    02606     for (dm = depMsgs; dm->msg != NULL; dm++) {
    02607         switch (dm->ntag) {
    02608         case 0:
    02609             names = hfd(names, dnt);
    02610             /*@switchbreak@*/ break;
    02611         case -1:
    02612             /*@switchbreak@*/ break;
    02613         default:
    02614             names = hfd(names, dnt);
    02615             if (!hge(h, dm->ntag, &dnt, (void **) &names, &count))
    02616                 continue;
    02617             /*@switchbreak@*/ break;
    02618         }
    02619         switch (dm->vtag) {
    02620         case 0:
    02621             versions = hfd(versions, dvt);
    02622             /*@switchbreak@*/ break;
    02623         case -1:
    02624             /*@switchbreak@*/ break;
    02625         default:
    02626             versions = hfd(versions, dvt);
    02627             xx = hge(h, dm->vtag, &dvt, (void **) &versions, NULL);
    02628             /*@switchbreak@*/ break;
    02629         }
    02630         switch (dm->ftag) {
    02631         case 0:
    02632             flags = NULL;
    02633             /*@switchbreak@*/ break;
    02634         case -1:
    02635             /*@switchbreak@*/ break;
    02636         default:
    02637             xx = hge(h, dm->ftag, NULL, (void **) &flags, NULL);
    02638             /*@switchbreak@*/ break;
    02639         }
    02640         /*@-noeffect@*/
    02641         printDepMsg(dm, count, names, versions, flags);
    02642         /*@=noeffect@*/
    02643     }
    02644     names = hfd(names, dnt);
    02645     versions = hfd(versions, dvt);
    02646 }
    02647
    02648 int processBinaryFiles(Spec spec, int installSpecialDoc, int test)
    02649 {
    02650     Package pkg;
    02651     int res = 0;
    02652
    02653     for (pkg = spec->packages; pkg != NULL; pkg = pkg->next) {
    02654         const char *n, *v, *r;
    02655         int rc;
    02656
    02657         if (pkg->fileList == NULL)
    02658             continue;
    02659
    02660         (void) headerNVR(pkg->header, &n, &v, &r);
    02661         rpmMessage(RPMMESS_NORMAL, _("Processing files: %s-%s-%s\n"), n, v, r);
    02662
    02663         if ((rc = processPackageFiles(spec, pkg, installSpecialDoc, test)))
    02664             res = rc;
    02665
    02666     /* XXX This should be added always so that packages look alike.
    02667      * XXX However, there is logic in files.c/depends.c that checks for
    02668      * XXX existence (rather than value) that will need to change as well.
    02669      */
    02670         if (headerIsEntry(pkg->header, RPMTAG_MULTILIBS)) {
    02671             (void) generateDepends(spec, pkg, pkg->cpioList, 1);
    02672             (void) generateDepends(spec, pkg, pkg->cpioList, 2);
    02673         } else
    02674             (void) generateDepends(spec, pkg, pkg->cpioList, 0);
    02675         /*@-noeffect@*/
    02676         printDeps(pkg->header);
    02677         /*@=noeffect@*/
    02678     }
    02679
    02680     return res;
    02681 }