Main Page   Modules   Compound List   File List   Compound Members   File Members   Related Pages  

build/files.c

Go to the documentation of this file.
00001 
00007 #include "system.h"
00008 
00009 #define MYALLPERMS      07777
00010 
00011 #include <regex.h>
00012 #include <signal.h>     /* getOutputFrom() */
00013 
00014 #include <rpmio_internal.h>
00015 #include <rpmbuild.h>
00016 #include <rpmmacro.h>
00017 
00018 #include "buildio.h"
00019 
00020 #include "myftw.h"
00021 #include "md5.h"
00022 #include "debug.h"
00023 
00024 #define SKIPWHITE(_x)   {while(*(_x) && (isspace(*_x) || *(_x) == ',')) (_x)++;}
00025 #define SKIPNONWHITE(_x){while(*(_x) &&!(isspace(*_x) || *(_x) == ',')) (_x)++;}
00026 
00027 #define MAXDOCDIR 1024
00028 
00031 typedef struct {
00032     struct stat fl_st;
00033 #define fl_dev  fl_st.st_dev
00034 #define fl_ino  fl_st.st_ino
00035 #define fl_mode fl_st.st_mode
00036 #define fl_nlink fl_st.st_nlink /* unused */
00037 #define fl_uid  fl_st.st_uid
00038 #define fl_gid  fl_st.st_gid
00039 #define fl_rdev fl_st.st_rdev
00040 #define fl_size fl_st.st_size
00041 #define fl_mtime fl_st.st_mtime
00042 
00043     const char *diskURL;        /* get file from here       */
00044     const char *fileURL;        /* filename in cpio archive */
00045     /*@observer@*/ const char *uname;
00046     /*@observer@*/ const char *gname;
00047     int         flags;
00048     int         verifyFlags;
00049     const char *langs;  /* XXX locales separated with | */
00050 } FileListRec;
00051 
00054 typedef struct {
00055     const char *ar_fmodestr;
00056     const char *ar_dmodestr;
00057     const char *ar_user;
00058     const char *ar_group;
00059     mode_t      ar_fmode;
00060     mode_t      ar_dmode;
00061 } AttrRec;
00062 
00065 static int multiLib = 0;        /* MULTILIB */
00066 
00070 struct FileList {
00071     const char *buildRootURL;
00072     const char *prefix;
00073 
00074     int fileCount;
00075     int totalFileSize;
00076     int processingFailed;
00077 
00078     int passedSpecialDoc;
00079     int isSpecialDoc;
00080     
00081     int isDir;
00082     int inFtw;
00083     int currentFlags;
00084     int currentVerifyFlags;
00085     AttrRec cur_ar;
00086     AttrRec def_ar;
00087     int defVerifyFlags;
00088     int nLangs;
00089     /*@only@*/ const char **currentLangs;
00090 
00091     /* Hard coded limit of MAXDOCDIR docdirs.         */
00092     /* If you break it you are doing something wrong. */
00093     const char *docDirs[MAXDOCDIR];
00094     int docDirCount;
00095     
00096     FileListRec *fileList;
00097     int fileListRecsAlloced;
00098     int fileListRecsUsed;
00099 };
00100 
00103 static void nullAttrRec(/*@out@*/AttrRec *ar)
00104 {
00105     ar->ar_fmodestr = NULL;
00106     ar->ar_dmodestr = NULL;
00107     ar->ar_user = NULL;
00108     ar->ar_group = NULL;
00109     ar->ar_fmode = 0;
00110     ar->ar_dmode = 0;
00111 }
00112 
00115 static void freeAttrRec(AttrRec *ar)
00116 {
00117     FREE(ar->ar_fmodestr);
00118     FREE(ar->ar_dmodestr);
00119     FREE(ar->ar_user);
00120     FREE(ar->ar_group);
00121     /* XXX doesn't free ar (yet) */
00122 }
00123 
00126 static void dupAttrRec(AttrRec *oar, /*@out@*/ AttrRec *nar)
00127 {
00128     if (oar == nar)     /* XXX pathological paranoia */
00129         return;
00130     freeAttrRec(nar);
00131     nar->ar_fmodestr = (oar->ar_fmodestr ? xstrdup(oar->ar_fmodestr) : NULL);
00132     nar->ar_dmodestr = (oar->ar_dmodestr ? xstrdup(oar->ar_dmodestr) : NULL);
00133     nar->ar_user = (oar->ar_user ? xstrdup(oar->ar_user) : NULL);
00134     nar->ar_group = (oar->ar_group ? xstrdup(oar->ar_group) : NULL);
00135     nar->ar_fmode = oar->ar_fmode;
00136     nar->ar_dmode = oar->ar_dmode;
00137 }
00138 
00139 #if 0
00140 
00142 static void dumpAttrRec(const char *msg, AttrRec *ar) {
00143     if (msg)
00144         fprintf(stderr, "%s:\t", msg);
00145     fprintf(stderr, "(%s, %s, %s, %s)\n",
00146         ar->ar_fmodestr,
00147         ar->ar_user,
00148         ar->ar_group,
00149         ar->ar_dmodestr);
00150 }
00151 #endif
00152 
00153 /* strtokWithQuotes() modified from glibc strtok() */
00154 /* Copyright (C) 1991, 1996 Free Software Foundation, Inc.
00155    This file is part of the GNU C Library.
00156 
00157    The GNU C Library is free software; you can redistribute it and/or
00158    modify it under the terms of the GNU Library General Public License as
00159    published by the Free Software Foundation; either version 2 of the
00160    License, or (at your option) any later version.
00161 
00162    The GNU C Library is distributed in the hope that it will be useful,
00163    but WITHOUT ANY WARRANTY; without even the implied warranty of
00164    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00165    Library General Public License for more details.
00166 
00167    You should have received a copy of the GNU Library General Public
00168    License along with the GNU C Library; see the file COPYING.LIB.  If
00169    not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
00170    Boston, MA 02111-1307, USA.  */
00171 
00174 static char *strtokWithQuotes(char *s, char *delim)
00175 {
00176     static char *olds = NULL;
00177     char *token;
00178 
00179     if (s == NULL) {
00180         s = olds;
00181     }
00182 
00183     /* Skip leading delimiters */
00184     s += strspn(s, delim);
00185     if (*s == '\0') {
00186         return NULL;
00187     }
00188 
00189     /* Find the end of the token.  */
00190     token = s;
00191     if (*token == '"') {
00192         token++;
00193         /* Find next " char */
00194         s = strchr(token, '"');
00195     } else {
00196         s = strpbrk(token, delim);
00197     }
00198 
00199     /* Terminate it */
00200     if (s == NULL) {
00201         /* This token finishes the string */
00202         olds = strchr(token, '\0');
00203     } else {
00204         /* Terminate the token and make olds point past it */
00205         *s = '\0';
00206         olds = s+1;
00207     }
00208 
00209     return token;
00210 }
00211 
00214 static void timeCheck(int tc, Header h)
00215 {
00216     int *mtime;
00217     char **files;
00218     int count, x, currentTime;
00219 
00220     headerGetEntry(h, RPMTAG_OLDFILENAMES, NULL, (void **) &files, &count);
00221     headerGetEntry(h, RPMTAG_FILEMTIMES, NULL, (void **) &mtime, NULL);
00222 
00223     currentTime = time(NULL);
00224     
00225     for (x = 0; x < count; x++) {
00226         if (currentTime - mtime[x] > tc) {
00227             rpmMessage(RPMMESS_WARNING, _("TIMECHECK failure: %s\n"), files[x]);
00228         }
00229     }
00230     FREE(files);
00231 }
00232 
00235 typedef struct VFA {
00236         char *  attribute;
00237         int     flag;
00238 } VFA_t;
00239 
00242 VFA_t verifyAttrs[] = {
00243         { "md5",        RPMVERIFY_MD5 },
00244         { "size",       RPMVERIFY_FILESIZE },
00245         { "link",       RPMVERIFY_LINKTO },
00246         { "user",       RPMVERIFY_USER },
00247         { "group",      RPMVERIFY_GROUP },
00248         { "mtime",      RPMVERIFY_MTIME },
00249         { "mode",       RPMVERIFY_MODE },
00250         { "rdev",       RPMVERIFY_RDEV },
00251         { NULL, 0 }
00252 };
00253 
00257 static int parseForVerify(char *buf, struct FileList *fl)
00258 {
00259     char *p, *pe, *q;
00260     const char *name;
00261     int *resultVerify;
00262     int not;
00263     int verifyFlags;
00264 
00265     if ((p = strstr(buf, (name = "%verify"))) != NULL) {
00266         resultVerify = &(fl->currentVerifyFlags);
00267     } else if ((p = strstr(buf, (name = "%defverify"))) != NULL) {
00268         resultVerify = &(fl->defVerifyFlags);
00269     } else
00270         return 0;
00271 
00272     for (pe = p; (pe-p) < strlen(name); pe++)
00273         *pe = ' ';
00274 
00275     SKIPSPACE(pe);
00276 
00277     if (*pe != '(') {
00278         rpmError(RPMERR_BADSPEC, _("Missing '(' in %s %s\n"), name, pe);
00279         fl->processingFailed = 1;
00280         return RPMERR_BADSPEC;
00281     }
00282 
00283     /* Bracket %*verify args */
00284     *pe++ = ' ';
00285     for (p = pe; *pe && *pe != ')'; pe++)
00286         ;
00287 
00288     if (*pe == '\0') {
00289         rpmError(RPMERR_BADSPEC, _("Missing ')' in %s(%s\n"), name, p);
00290         fl->processingFailed = 1;
00291         return RPMERR_BADSPEC;
00292     }
00293 
00294     /* Localize. Erase parsed string */
00295     q = alloca((pe-p) + 1);
00296     strncpy(q, p, pe-p);
00297     q[pe-p] = '\0';
00298     while (p <= pe)
00299         *p++ = ' ';
00300 
00301     not = 0;
00302     verifyFlags = RPMVERIFY_NONE;
00303 
00304     for (p = q; *p; p = pe) {
00305         SKIPWHITE(p);
00306         if (*p == '\0')
00307             break;
00308         pe = p;
00309         SKIPNONWHITE(pe);
00310         if (*pe)
00311             *pe++ = '\0';
00312 
00313         {   VFA_t *vfa;
00314             for (vfa = verifyAttrs; vfa->attribute != NULL; vfa++) {
00315                 if (strcmp(p, vfa->attribute))
00316                     continue;
00317                 verifyFlags |= vfa->flag;
00318                 break;
00319             }
00320             if (vfa->attribute)
00321                 continue;
00322         }
00323 
00324         if (!strcmp(p, "not")) {
00325             not ^= 1;
00326         } else {
00327             rpmError(RPMERR_BADSPEC, _("Invalid %s token: %s\n"), name, p);
00328             fl->processingFailed = 1;
00329             return RPMERR_BADSPEC;
00330         }
00331     }
00332 
00333     *resultVerify = not ? ~(verifyFlags) : verifyFlags;
00334 
00335     return 0;
00336 }
00337 
00338 #define isAttrDefault(_ars)     ((_ars)[0] == '-' && (_ars)[1] == '\0')
00339 
00343 static int parseForAttr(char *buf, struct FileList *fl)
00344 {
00345     char *p, *pe, *q;
00346     const char *name;
00347     int x;
00348     AttrRec arbuf, *ar = &arbuf, *ret_ar;
00349 
00350     if ((p = strstr(buf, (name = "%attr"))) != NULL) {
00351         ret_ar = &(fl->cur_ar);
00352     } else if ((p = strstr(buf, (name = "%defattr"))) != NULL) {
00353         ret_ar = &(fl->def_ar);
00354     } else
00355         return 0;
00356 
00357     for (pe = p; (pe-p) < strlen(name); pe++)
00358         *pe = ' ';
00359 
00360     SKIPSPACE(pe);
00361 
00362     if (*pe != '(') {
00363         rpmError(RPMERR_BADSPEC, _("Missing '(' in %s %s\n"), name, pe);
00364         fl->processingFailed = 1;
00365         return RPMERR_BADSPEC;
00366     }
00367 
00368     /* Bracket %*attr args */
00369     *pe++ = ' ';
00370     for (p = pe; *pe && *pe != ')'; pe++)
00371         ;
00372 
00373     if (ret_ar == &(fl->def_ar)) {      /* %defattr */
00374         q = pe;
00375         q++;
00376         SKIPSPACE(q);
00377         if (*q) {
00378             rpmError(RPMERR_BADSPEC,
00379                      _("Non-white space follows %s(): %s\n"), name, q);
00380             fl->processingFailed = 1;
00381             return RPMERR_BADSPEC;
00382         }
00383     }
00384 
00385     /* Localize. Erase parsed string */
00386     q = alloca((pe-p) + 1);
00387     strncpy(q, p, pe-p);
00388     q[pe-p] = '\0';
00389     while (p <= pe)
00390         *p++ = ' ';
00391 
00392     nullAttrRec(ar);
00393 
00394     p = q; SKIPWHITE(p);
00395     if (*p) {
00396         pe = p; SKIPNONWHITE(pe); if (*pe) *pe++ = '\0';
00397         ar->ar_fmodestr = p;
00398         p = pe; SKIPWHITE(p);
00399     }
00400     if (*p) {
00401         pe = p; SKIPNONWHITE(pe); if (*pe) *pe++ = '\0';
00402         ar->ar_user = p;
00403         p = pe; SKIPWHITE(p);
00404     }
00405     if (*p) {
00406         pe = p; SKIPNONWHITE(pe); if (*pe) *pe++ = '\0';
00407         ar->ar_group = p;
00408         p = pe; SKIPWHITE(p);
00409     }
00410     if (*p && ret_ar == &(fl->def_ar)) {        /* %defattr */
00411         pe = p; SKIPNONWHITE(pe); if (*pe) *pe++ = '\0';
00412         ar->ar_dmodestr = p;
00413         p = pe; SKIPWHITE(p);
00414     }
00415 
00416     if (!(ar->ar_fmodestr && ar->ar_user && ar->ar_group) || *p != '\0') {
00417         rpmError(RPMERR_BADSPEC, _("Bad syntax: %s(%s)\n"), name, q);
00418         fl->processingFailed = 1;
00419         return RPMERR_BADSPEC;
00420     }
00421 
00422     /* Do a quick test on the mode argument and adjust for "-" */
00423     if (ar->ar_fmodestr && !isAttrDefault(ar->ar_fmodestr)) {
00424         unsigned int ui;
00425         x = sscanf(ar->ar_fmodestr, "%o", &ui);
00426         if ((x == 0) || (ar->ar_fmode & ~MYALLPERMS)) {
00427             rpmError(RPMERR_BADSPEC, _("Bad mode spec: %s(%s)\n"), name, q);
00428             fl->processingFailed = 1;
00429             return RPMERR_BADSPEC;
00430         }
00431         ar->ar_fmode = ui;
00432     } else
00433         ar->ar_fmodestr = NULL;
00434 
00435     if (ar->ar_dmodestr && !isAttrDefault(ar->ar_dmodestr)) {
00436         unsigned int ui;
00437         x = sscanf(ar->ar_dmodestr, "%o", &ui);
00438         if ((x == 0) || (ar->ar_dmode & ~MYALLPERMS)) {
00439             rpmError(RPMERR_BADSPEC, _("Bad dirmode spec: %s(%s)\n"), name, q);
00440             fl->processingFailed = 1;
00441             return RPMERR_BADSPEC;
00442         }
00443         ar->ar_dmode = ui;
00444     } else
00445         ar->ar_dmodestr = NULL;
00446 
00447     if (!(ar->ar_user && !isAttrDefault(ar->ar_user)))
00448         ar->ar_user = NULL;
00449 
00450     if (!(ar->ar_group && !isAttrDefault(ar->ar_group)))
00451         ar->ar_group = NULL;
00452 
00453     dupAttrRec(ar, ret_ar);
00454     
00455     return 0;
00456 }
00457 
00461 static int parseForConfig(char *buf, struct FileList *fl)
00462 {
00463     char *p, *pe, *q;
00464     const char *name;
00465 
00466     if ((p = strstr(buf, (name = "%config"))) == NULL)
00467         return 0;
00468 
00469     fl->currentFlags = RPMFILE_CONFIG;
00470 
00471     for (pe = p; (pe-p) < strlen(name); pe++)
00472         *pe = ' ';
00473     SKIPSPACE(pe);
00474     if (*pe != '(')
00475         return 0;
00476 
00477     /* Bracket %config args */
00478     *pe++ = ' ';
00479     for (p = pe; *pe && *pe != ')'; pe++)
00480         ;
00481 
00482     if (*pe == '\0') {
00483         rpmError(RPMERR_BADSPEC, _("Missing ')' in %s(%s\n"), name, p);
00484         fl->processingFailed = 1;
00485         return RPMERR_BADSPEC;
00486     }
00487 
00488     /* Localize. Erase parsed string */
00489     q = alloca((pe-p) + 1);
00490     strncpy(q, p, pe-p);
00491     q[pe-p] = '\0';
00492     while (p <= pe)
00493         *p++ = ' ';
00494 
00495     for (p = q; *p; p = pe) {
00496         SKIPWHITE(p);
00497         if (*p == '\0')
00498             break;
00499         pe = p;
00500         SKIPNONWHITE(pe);
00501         if (*pe)
00502             *pe++ = '\0';
00503         if (!strcmp(p, "missingok")) {
00504             fl->currentFlags |= RPMFILE_MISSINGOK;
00505         } else if (!strcmp(p, "noreplace")) {
00506             fl->currentFlags |= RPMFILE_NOREPLACE;
00507         } else {
00508             rpmError(RPMERR_BADSPEC, _("Invalid %s token: %s\n"), name, p);
00509             fl->processingFailed = 1;
00510             return RPMERR_BADSPEC;
00511         }
00512     }
00513 
00514     return 0;
00515 }
00516 
00519 static int langCmp(const void * ap, const void *bp) {
00520     return strcmp(*(const char **)ap, *(const char **)bp);
00521 }
00522 
00526 static int parseForLang(char *buf, struct FileList *fl)
00527 {
00528     char *p, *pe, *q;
00529     const char *name;
00530 
00531   while ((p = strstr(buf, (name = "%lang"))) != NULL) {
00532 
00533     for (pe = p; (pe-p) < strlen(name); pe++)
00534         *pe = ' ';
00535     SKIPSPACE(pe);
00536 
00537     if (*pe != '(') {
00538         rpmError(RPMERR_BADSPEC, _("Missing '(' in %s %s\n"), name, pe);
00539         fl->processingFailed = 1;
00540         return RPMERR_BADSPEC;
00541     }
00542 
00543     /* Bracket %lang args */
00544     *pe++ = ' ';
00545     for (pe = p; *pe && *pe != ')'; pe++)
00546         ;
00547 
00548     if (*pe == '\0') {
00549         rpmError(RPMERR_BADSPEC, _("Missing ')' in %s(%s\n"), name, p);
00550         fl->processingFailed = 1;
00551         return RPMERR_BADSPEC;
00552     }
00553 
00554     /* Localize. Erase parsed string */
00555     q = alloca((pe-p) + 1);
00556     strncpy(q, p, pe-p);
00557     q[pe-p] = '\0';
00558     while (p <= pe)
00559         *p++ = ' ';
00560 
00561     /* Parse multiple arguments from %lang */
00562     for (p = q; *p; p = pe) {
00563         char *newp;
00564         size_t np;
00565         int i;
00566 
00567         SKIPWHITE(p);
00568         pe = p;
00569         SKIPNONWHITE(pe);
00570 
00571         np = pe - p;
00572         
00573         /* Sanity check on locale lengths */
00574         if (np < 1 || (np == 1 && *p != 'C') || np >= 32) {
00575             rpmError(RPMERR_BADSPEC,
00576                 _("Unusual locale length: \"%.*s\" in %%lang(%s)\n"),
00577                 (int)np, p, q);
00578             fl->processingFailed = 1;
00579             return RPMERR_BADSPEC;
00580         }
00581 
00582         /* Check for duplicate locales */
00583         for (i = 0; i < fl->nLangs; i++) {
00584             if (strncmp(fl->currentLangs[i], p, np))
00585                 continue;
00586             rpmError(RPMERR_BADSPEC, _("Duplicate locale %.*s in %%lang(%s)\n"),
00587                 (int)np, p, q);
00588             fl->processingFailed = 1;
00589             return RPMERR_BADSPEC;
00590         }
00591 
00592         /* Add new locale */
00593         fl->currentLangs = (const char **) ((fl->currentLangs == NULL)
00594           ? xmalloc(sizeof(*fl->currentLangs))
00595           : xrealloc(fl->currentLangs,((fl->nLangs+1)*sizeof(*fl->currentLangs))));
00596         newp = xmalloc( np+1 );
00597         strncpy(newp, p, np);
00598         newp[np] = '\0';
00599         fl->currentLangs[fl->nLangs++] = newp;
00600         if (*pe == ',') pe++;   /* skip , if present */
00601     }
00602   }
00603 
00604     /* Insure that locales are sorted. */
00605     if (fl->currentLangs)
00606         qsort(fl->currentLangs, fl->nLangs, sizeof(*fl->currentLangs), langCmp);
00607 
00608     return 0;
00609 }
00610 
00613 static int parseForRegexLang(const char *fileName, /*@out@*/char **lang)
00614 {
00615     static int initialized = 0;
00616     static int hasRegex = 0;
00617     static regex_t compiledPatt;
00618     static char buf[BUFSIZ];
00619     int x;
00620     regmatch_t matches[2];
00621     const char *s;
00622 
00623     if (! initialized) {
00624         const char *patt = rpmExpand("%{_langpatt}", NULL);
00625         int rc = 0;
00626         if (!(patt && *patt != '%'))
00627             rc = 1;
00628         else if (regcomp(&compiledPatt, patt, REG_EXTENDED))
00629             rc = -1;
00630         free((void *)patt);
00631         if (rc)
00632             return rc;
00633         hasRegex = 1;
00634         initialized = 1;
00635     }
00636     
00637     if (! hasRegex || regexec(&compiledPatt, fileName, 2, matches, REG_NOTEOL))
00638         return 1;
00639 
00640     /* Got match */
00641     s = fileName + matches[1].rm_eo - 1;
00642     x = matches[1].rm_eo - matches[1].rm_so;
00643     buf[x] = '\0';
00644     while (x) {
00645         buf[--x] = *s--;
00646     }
00647     if (lang)
00648         *lang = buf;
00649     return 0;
00650 }
00651 
00654 static int parseForRegexMultiLib(const char *fileName)
00655 {
00656     static int initialized = 0;
00657     static int hasRegex = 0;
00658     static regex_t compiledPatt;
00659 
00660     if (! initialized) {
00661         const char *patt;
00662         int rc = 0;
00663 
00664         initialized = 1;
00665         patt = rpmExpand("%{_multilibpatt}", NULL);
00666         if (!(patt && *patt != '%'))
00667             rc = 1;
00668         else if (regcomp(&compiledPatt, patt, REG_EXTENDED | REG_NOSUB))
00669             rc = -1;
00670         free((void *)patt);
00671         if (rc)
00672             return rc;
00673         hasRegex = 1;
00674     }
00675 
00676     if (! hasRegex || regexec(&compiledPatt, fileName, 0, NULL, 0))
00677         return 1;
00678 
00679     return 0;
00680 }
00681 
00684 VFA_t virtualFileAttributes[] = {
00685         { "%dir",       0 },    /* XXX why not RPMFILE_DIR? */
00686         { "%doc",       RPMFILE_DOC },
00687         { "%ghost",     RPMFILE_GHOST },
00688         { "%readme",    RPMFILE_README },
00689         { "%license",   RPMFILE_LICENSE },
00690         { "%multilib",  0 },
00691 
00692 #if WHY_NOT
00693         { "%spec",      RPMFILE_SPEC },
00694         { "%config",    RPMFILE_CONFIG },
00695         { "%donotuse",  RPMFILE_DONOTUSE },     /* XXX WTFO? */
00696         { "%missingok", RPMFILE_CONFIG|RPMFILE_MISSINGOK },
00697         { "%noreplace", RPMFILE_CONFIG|RPMFILE_NOREPLACE },
00698 #endif
00699 
00700         { NULL, 0 }
00701 };
00702 
00706 static int parseForSimple(/*@unused@*/Spec spec, Package pkg, char *buf,
00707                           struct FileList *fl, const char **fileName)
00708 {
00709     char *s, *t;
00710     int res, specialDoc = 0;
00711     char specialDocBuf[BUFSIZ];
00712 
00713     specialDocBuf[0] = '\0';
00714     *fileName = NULL;
00715     res = 0;
00716 
00717     t = buf;
00718     while ((s = strtokWithQuotes(t, " \t\n")) != NULL) {
00719         t = NULL;
00720         if (!strcmp(s, "%docdir")) {
00721             s = strtokWithQuotes(NULL, " \t\n");
00722             if (fl->docDirCount == MAXDOCDIR) {
00723                 rpmError(RPMERR_INTERNAL, _("Hit limit for %%docdir\n"));
00724                 fl->processingFailed = 1;
00725                 res = 1;
00726             }
00727             fl->docDirs[fl->docDirCount++] = xstrdup(s);
00728             if (strtokWithQuotes(NULL, " \t\n")) {
00729                 rpmError(RPMERR_INTERNAL, _("Only one arg for %%docdir\n"));
00730                 fl->processingFailed = 1;
00731                 res = 1;
00732             }
00733             break;
00734         }
00735 
00736     /* Set flags for virtual file attributes */
00737     {   VFA_t *vfa;
00738         for (vfa = virtualFileAttributes; vfa->attribute != NULL; vfa++) {
00739             if (strcmp(s, vfa->attribute))
00740                 continue;
00741             if (!vfa->flag) {
00742                 if (!strcmp(s, "%dir"))
00743                     fl->isDir = 1;      /* XXX why not RPMFILE_DIR? */
00744                 else if (!strcmp(s, "%multilib"))
00745                     fl->currentFlags |= multiLib;
00746             } else
00747                 fl->currentFlags |= vfa->flag;
00748             break;
00749         }
00750         /* if we got an attribute, continue with next token */
00751         if (vfa->attribute != NULL)
00752             continue;
00753     }
00754 
00755         if (*fileName) {
00756             /* We already got a file -- error */
00757             rpmError(RPMERR_BADSPEC, _("Two files on one line: %s\n"),
00758                 *fileName);
00759             fl->processingFailed = 1;
00760             res = 1;
00761         }
00762 
00763         if (*s != '/') {
00764             if (fl->currentFlags & RPMFILE_DOC) {
00765                 specialDoc = 1;
00766                 strcat(specialDocBuf, " ");
00767                 strcat(specialDocBuf, s);
00768             } else {
00769                 /* not in %doc, does not begin with / -- error */
00770                 rpmError(RPMERR_BADSPEC,
00771                     _("File must begin with \"/\": %s\n"), s);
00772                 fl->processingFailed = 1;
00773                 res = 1;
00774             }
00775         } else {
00776             *fileName = s;
00777         }
00778     }
00779 
00780     if (specialDoc) {
00781         if (*fileName || (fl->currentFlags & ~(RPMFILE_DOC))) {
00782             rpmError(RPMERR_BADSPEC,
00783                      _("Can't mix special %%doc with other forms: %s\n"),
00784                      *fileName);
00785             fl->processingFailed = 1;
00786             res = 1;
00787         } else {
00788         /* XXX WATCHOUT: buf is an arg */
00789             {   const char *ddir, *n, *v;
00790 
00791                 headerNVR(pkg->header, &n, &v, NULL);
00792 
00793                 ddir = rpmGetPath("%{_docdir}/", n, "-", v, NULL);
00794                 strcpy(buf, ddir);
00795                 free((void *)ddir);
00796             }
00797 
00798         /* XXX FIXME: this is easy to do as macro expansion */
00799 
00800             if (! fl->passedSpecialDoc) {
00801                 pkg->specialDoc = newStringBuf();
00802                 appendStringBuf(pkg->specialDoc, "DOCDIR=$RPM_BUILD_ROOT");
00803                 appendLineStringBuf(pkg->specialDoc, buf);
00804                 appendLineStringBuf(pkg->specialDoc, "export DOCDIR");
00805                 appendLineStringBuf(pkg->specialDoc, "rm -rf $DOCDIR");
00806                 appendLineStringBuf(pkg->specialDoc, MKDIR_P " $DOCDIR");
00807 
00808                 *fileName = buf;
00809                 fl->passedSpecialDoc = 1;
00810                 fl->isSpecialDoc = 1;
00811             }
00812 
00813             appendStringBuf(pkg->specialDoc, "cp -pr ");
00814             appendStringBuf(pkg->specialDoc, specialDocBuf);
00815             appendLineStringBuf(pkg->specialDoc, " $DOCDIR");
00816         }
00817     }
00818 
00819     return res;
00820 }
00821 
00824 static int compareFileListRecs(const void *ap, const void *bp)
00825 {
00826     const char *a = ((FileListRec *)ap)->fileURL;
00827     const char *b = ((FileListRec *)bp)->fileURL;
00828     return strcmp(a, b);
00829 }
00830 
00834 static int isDoc(struct FileList *fl, const char *fileName)
00835 {
00836     int x = fl->docDirCount;
00837 
00838     while (x--) {
00839         if (strstr(fileName, fl->docDirs[x]) == fileName) {
00840             return 1;
00841         }
00842     }
00843     return 0;
00844 }
00845 
00851 static void checkHardLinks(struct FileList *fl)
00852 {
00853     char nlangs[BUFSIZ];
00854     FileListRec *ilp, *jlp;
00855     int i, j;
00856 
00857     for (i = 0;  i < fl->fileListRecsUsed; i++) {
00858         char *te;
00859 
00860         ilp = fl->fileList + i;
00861         if (!(S_ISREG(ilp->fl_mode) && ilp->fl_nlink > 1))
00862             continue;
00863         if (ilp->flags & RPMFILE_SPECFILE)
00864             continue;
00865 
00866         te = nlangs;
00867         *te = '\0';
00868         for (j = i + 1; j < fl->fileListRecsUsed; j++) {
00869             jlp = fl->fileList + j;
00870             if (!S_ISREG(jlp->fl_mode))
00871                 continue;
00872             if (ilp->fl_nlink != jlp->fl_nlink)
00873                 continue;
00874             if (ilp->fl_ino != jlp->fl_ino)
00875                 continue;
00876             if (ilp->fl_dev != jlp->fl_dev)
00877                 continue;
00878             if (!strcmp(ilp->langs, jlp->langs)) {
00879                 jlp->flags |= RPMFILE_SPECFILE;
00880                 continue;
00881             }
00882             if (te == nlangs)
00883                 te = stpcpy(te, ilp->langs);
00884             *te++ = '|';
00885             te = stpcpy(te, jlp->langs);
00886         }
00887 
00888         /* Are locales distributed over hard links correctly? */
00889         if (te == nlangs)
00890             continue;
00891 
00892         free((void *)ilp->langs);
00893         ilp->langs = xstrdup(nlangs);
00894         for (j = i + 1; j < fl->fileListRecsUsed; j++) {
00895             jlp = fl->fileList + j;
00896             if (!S_ISREG(jlp->fl_mode))
00897                 continue;
00898             if (ilp->fl_nlink != jlp->fl_nlink)
00899                 continue;
00900             if (ilp->fl_ino != jlp->fl_ino)
00901                 continue;
00902             if (ilp->fl_dev != jlp->fl_dev)
00903                 continue;
00904             jlp->flags |= RPMFILE_SPECFILE;
00905             free((void *)jlp->langs);
00906             jlp->langs = xstrdup(nlangs);
00907         }
00908     }
00909 
00910     for (i = 0;  i < fl->fileListRecsUsed; i++) {
00911         ilp = fl->fileList + i;
00912         ilp->flags &= ~RPMFILE_SPECFILE;
00913     }
00914 }
00915 
00920 static void genCpioListAndHeader(struct FileList *fl,
00921                                  struct cpioFileMapping **cpioList,
00922                                  int *cpioCount, Header h, int isSrc)
00923 {
00924     int skipLen;
00925     int count;
00926     FileListRec *flp;
00927     struct cpioFileMapping *clp;
00928     char *s;
00929     char buf[BUFSIZ];
00930     uint_32 multiLibMask = 0;
00931     
00932     /* Sort the big list */
00933     qsort(fl->fileList, fl->fileListRecsUsed,
00934           sizeof(*(fl->fileList)), compareFileListRecs);
00935     
00936     /* Generate the cpio list and the header */
00937     skipLen = 0;
00938     if (! isSrc) {
00939         skipLen = 1;
00940         if (fl->prefix)
00941             skipLen += strlen(fl->prefix);
00942     }
00943 
00944     *cpioCount = 0;
00945     clp = *cpioList = xmalloc(sizeof(**cpioList) * fl->fileListRecsUsed);
00946 
00947     for (flp = fl->fileList, count = fl->fileListRecsUsed; count > 0; flp++, count--) {
00948         if ((count > 1) && !strcmp(flp->fileURL, flp[1].fileURL)) {
00949             rpmError(RPMERR_BADSPEC, _("File listed twice: %s\n"),
00950                 flp->fileURL);
00951             fl->processingFailed = 1;
00952         }
00953 
00954         if (flp->flags & RPMFILE_MULTILIB_MASK)
00955             multiLibMask |=
00956                 (1 << ((flp->flags & RPMFILE_MULTILIB_MASK))
00957                       >> RPMFILE_MULTILIB_SHIFT);
00958 
00959         /* Make the cpio list */
00960         if (! (flp->flags & RPMFILE_GHOST)) {
00961             clp->fsPath = xstrdup(flp->diskURL);
00962   /* XXX legacy requires './' payload prefix to be omitted from rpm packages. */
00963             {   char * t = buf;
00964                 if (!isSrc && !rpmExpandNumeric("%{_noPayloadPrefix}")) {
00965                     t = stpcpy(t, "./");
00966                     rpmlibNeedsFeature(h, "PayloadFilesHavePrefix", "4.0-1");
00967                 }
00968                 t = stpcpy(t, (flp->fileURL + skipLen));
00969                 clp->archivePath = xstrdup(buf);
00970             }
00971             clp->finalMode = flp->fl_mode;
00972             clp->finalUid = flp->fl_uid;
00973             clp->finalGid = flp->fl_gid;
00974             clp->mapFlags = CPIO_MAP_PATH | CPIO_MAP_MODE |
00975                 CPIO_MAP_UID | CPIO_MAP_GID;
00976 
00977             if (isSrc)
00978                 clp->mapFlags |= CPIO_FOLLOW_SYMLINKS;
00979             if (flp->flags & RPMFILE_MULTILIB_MASK)
00980                 clp->mapFlags |= CPIO_MULTILIB;
00981 
00982             clp++;
00983             (*cpioCount)++;
00984         }
00985         
00986         /* Make the header, the OLDFILENAMES will get converted to a 
00987            compressed file list write before we write the actual package to
00988            disk. */
00989         headerAddOrAppendEntry(h, RPMTAG_OLDFILENAMES, RPM_STRING_ARRAY_TYPE,
00990                                &(flp->fileURL), 1);
00991 
00992       if (sizeof(flp->fl_size) != sizeof(uint_32)) {
00993         uint_32 psize = (uint_32)flp->fl_size;
00994         headerAddOrAppendEntry(h, RPMTAG_FILESIZES, RPM_INT32_TYPE,
00995                                &(psize), 1);
00996       } else {
00997         headerAddOrAppendEntry(h, RPMTAG_FILESIZES, RPM_INT32_TYPE,
00998                                &(flp->fl_size), 1);
00999       }
01000         headerAddOrAppendEntry(h, RPMTAG_FILEUSERNAME, RPM_STRING_ARRAY_TYPE,
01001                                &(flp->uname), 1);
01002         headerAddOrAppendEntry(h, RPMTAG_FILEGROUPNAME, RPM_STRING_ARRAY_TYPE,
01003                                &(flp->gname), 1);
01004         headerAddOrAppendEntry(h, RPMTAG_FILEMTIMES, RPM_INT32_TYPE,
01005                                &(flp->fl_mtime), 1);
01006       if (sizeof(flp->fl_mode) != sizeof(uint_16)) {
01007         uint_16 pmode = (uint_16)flp->fl_mode;
01008         headerAddOrAppendEntry(h, RPMTAG_FILEMODES, RPM_INT16_TYPE,
01009                                &(pmode), 1);
01010       } else {
01011         headerAddOrAppendEntry(h, RPMTAG_FILEMODES, RPM_INT16_TYPE,
01012                                &(flp->fl_mode), 1);
01013       }
01014       if (sizeof(flp->fl_rdev) != sizeof(uint_16)) {
01015         uint_16 prdev = (uint_16)flp->fl_rdev;
01016         headerAddOrAppendEntry(h, RPMTAG_FILERDEVS, RPM_INT16_TYPE,
01017                                &(prdev), 1);
01018       } else {
01019         headerAddOrAppendEntry(h, RPMTAG_FILERDEVS, RPM_INT16_TYPE,
01020                                &(flp->fl_rdev), 1);
01021       }
01022       if (sizeof(flp->fl_dev) != sizeof(uint_32)) {
01023         uint_32 pdevice = (uint_32)flp->fl_dev;
01024         headerAddOrAppendEntry(h, RPMTAG_FILEDEVICES, RPM_INT32_TYPE,
01025                                &(pdevice), 1);
01026       } else {
01027         headerAddOrAppendEntry(h, RPMTAG_FILEDEVICES, RPM_INT32_TYPE,
01028                                &(flp->fl_dev), 1);
01029       }
01030         headerAddOrAppendEntry(h, RPMTAG_FILEINODES, RPM_INT32_TYPE,
01031                                &(flp->fl_ino), 1);
01032 
01033         headerAddOrAppendEntry(h, RPMTAG_FILELANGS, RPM_STRING_ARRAY_TYPE,
01034                                &(flp->langs),  1);
01035         
01036         /* We used to add these, but they should not be needed */
01037         /* headerAddOrAppendEntry(h, RPMTAG_FILEUIDS,
01038          *                 RPM_INT32_TYPE, &(flp->fl_uid), 1);
01039          * headerAddOrAppendEntry(h, RPMTAG_FILEGIDS,
01040          *                 RPM_INT32_TYPE, &(flp->fl_gid), 1);
01041          */
01042         
01043         buf[0] = '\0';
01044         if (S_ISREG(flp->fl_mode))
01045             mdfile(flp->diskURL, buf);
01046         s = buf;
01047         headerAddOrAppendEntry(h, RPMTAG_FILEMD5S, RPM_STRING_ARRAY_TYPE,
01048                                &s, 1);
01049         
01050         buf[0] = '\0';
01051         if (S_ISLNK(flp->fl_mode)) {
01052             buf[Readlink(flp->diskURL, buf, BUFSIZ)] = '\0';
01053             if (fl->buildRootURL) {
01054                 const char * buildRoot;
01055                 (void) urlPath(fl->buildRootURL, &buildRoot);
01056 
01057                 if (buf[0] == '/' && strcmp(buildRoot, "/") &&
01058                     !strncmp(buf, buildRoot, strlen(buildRoot))) {
01059                      rpmError(RPMERR_BADSPEC,
01060                                 _("Symlink points to BuildRoot: %s -> %s\n"),
01061                                 flp->fileURL, buf);
01062                     fl->processingFailed = 1;
01063                 }
01064             }
01065         }
01066         s = buf;
01067         headerAddOrAppendEntry(h, RPMTAG_FILELINKTOS, RPM_STRING_ARRAY_TYPE,
01068                                &s, 1);
01069         
01070         if (flp->flags & RPMFILE_GHOST) {
01071             flp->verifyFlags &= ~(RPMVERIFY_MD5 | RPMVERIFY_FILESIZE |
01072                                 RPMVERIFY_LINKTO | RPMVERIFY_MTIME);
01073         }
01074         headerAddOrAppendEntry(h, RPMTAG_FILEVERIFYFLAGS, RPM_INT32_TYPE,
01075                                &(flp->verifyFlags), 1);
01076         
01077         if (!isSrc && isDoc(fl, flp->fileURL))
01078             flp->flags |= RPMFILE_DOC;
01079         /* XXX Should directories have %doc/%config attributes? (#14531) */
01080         if (S_ISDIR(flp->fl_mode))
01081             flp->flags &= ~(RPMFILE_CONFIG|RPMFILE_DOC);
01082 
01083         headerAddOrAppendEntry(h, RPMTAG_FILEFLAGS, RPM_INT32_TYPE,
01084                                &(flp->flags), 1);
01085     }
01086     headerAddEntry(h, RPMTAG_SIZE, RPM_INT32_TYPE,
01087                    &(fl->totalFileSize), 1);
01088     /* XXX This should be added always so that packages look alike.
01089      * XXX However, there is logic in files.c/depends.c that checks for
01090      * XXX existence (rather than value) that will need to change as well.
01091      */
01092     if (multiLibMask)
01093         headerAddEntry(h, RPMTAG_MULTILIBS, RPM_INT32_TYPE,
01094                        &multiLibMask, 1);
01095 }
01096 
01099 static void freeFileList(FileListRec *fileList, int count)
01100 {
01101     while (count--) {
01102         FREE(fileList[count].diskURL);
01103         FREE(fileList[count].fileURL);
01104         FREE(fileList[count].langs);
01105     }
01106     FREE(fileList);
01107 }
01108 
01112 static int addFile(struct FileList *fl, const char * diskURL, struct stat *statp)
01113 {
01114     const char *fileURL = diskURL;
01115     struct stat statbuf;
01116     mode_t fileMode;
01117     uid_t fileUid;
01118     gid_t fileGid;
01119     const char *fileUname;
01120     const char *fileGname;
01121     char *lang;
01122     
01123     /* Path may have prepended buildRootURL, so locate the original filename. */
01124     /*
01125      * XXX There are 3 types of entry into addFile:
01126      *
01127      *  From                    diskUrl                 statp
01128      *  =====================================================
01129      *  processBinaryFile       path                    NULL
01130      *  processBinaryFile       glob result path        NULL
01131      *  myftw                   path                    stat
01132      *
01133      */
01134     {   const char *fileName;
01135         (void) urlPath(fileURL, &fileName);
01136         if (fl->buildRootURL && strcmp(fl->buildRootURL, "/"))
01137             fileURL += strlen(fl->buildRootURL);
01138     }
01139 
01140     /* XXX make sure '/' can be packaged also */
01141     if (*fileURL == '\0')
01142         fileURL = "/";
01143 
01144     /* If we are using a prefix, validate the file */
01145     if (!fl->inFtw && fl->prefix) {
01146         const char *prefixTest;
01147         const char *prefixPtr = fl->prefix;
01148 
01149         (void) urlPath(fileURL, &prefixTest);
01150         while (*prefixPtr && *prefixTest && (*prefixTest == *prefixPtr)) {
01151             prefixPtr++;
01152             prefixTest++;
01153         }
01154         if (*prefixPtr || (*prefixTest && *prefixTest != '/')) {
01155             rpmError(RPMERR_BADSPEC, _("File doesn't match prefix (%s): %s\n"),
01156                      fl->prefix, fileURL);
01157             fl->processingFailed = 1;
01158             return RPMERR_BADSPEC;
01159         }
01160     }
01161 
01162     if (statp == NULL) {
01163         statp = &statbuf;
01164         if (Lstat(diskURL, statp)) {
01165             rpmError(RPMERR_BADSPEC, _("File not found: %s\n"), diskURL);
01166             fl->processingFailed = 1;
01167             return RPMERR_BADSPEC;
01168         }
01169     }
01170 
01171     if ((! fl->isDir) && S_ISDIR(statp->st_mode)) {
01172         /* We use our own ftw() call, because ftw() uses stat()    */
01173         /* instead of lstat(), which causes it to follow symlinks! */
01174         /* It also has better callback support.                    */
01175         
01176         fl->inFtw = 1;  /* Flag to indicate file has buildRootURL prefixed */
01177         fl->isDir = 1;  /* Keep it from following myftw() again         */
01178         myftw(diskURL, 16, (myftwFunc) addFile, fl);
01179         fl->isDir = 0;
01180         fl->inFtw = 0;
01181         return 0;
01182     }
01183 
01184     fileMode = statp->st_mode;
01185     fileUid = statp->st_uid;
01186     fileGid = statp->st_gid;
01187 
01188     if (S_ISDIR(fileMode) && fl->cur_ar.ar_dmodestr) {
01189         fileMode &= S_IFMT;
01190         fileMode |= fl->cur_ar.ar_dmode;
01191     } else if (fl->cur_ar.ar_fmodestr != NULL) {
01192         fileMode &= S_IFMT;
01193         fileMode |= fl->cur_ar.ar_fmode;
01194     }
01195     if (fl->cur_ar.ar_user) {
01196         fileUname = getUnameS(fl->cur_ar.ar_user);
01197     } else {
01198         fileUname = getUname(fileUid);
01199     }
01200     if (fl->cur_ar.ar_group) {
01201         fileGname = getGnameS(fl->cur_ar.ar_group);
01202     } else {
01203         fileGname = getGname(fileGid);
01204     }
01205         
01206 #if 0   /* XXX this looks dumb to me */
01207     if (! (fileUname && fileGname)) {
01208         rpmError(RPMERR_BADSPEC, _("Bad owner/group: %s\n"), diskName);
01209         fl->processingFailed = 1;
01210         return RPMERR_BADSPEC;
01211     }
01212 #else
01213     /* Default user/group to builder's user/group */
01214     if (fileUname == NULL)
01215         fileUname = getUname(getuid());
01216     if (fileGname == NULL)
01217         fileGname = getGname(getgid());
01218 #endif
01219     
01220     rpmMessage(RPMMESS_DEBUG, _("File %4d: %07o %s.%s\t %s\n"), fl->fileCount,
01221         fileMode, fileUname, fileGname, fileURL);
01222 
01223     /* Add to the file list */
01224     if (fl->fileListRecsUsed == fl->fileListRecsAlloced) {
01225         fl->fileListRecsAlloced += 128;
01226         fl->fileList = xrealloc(fl->fileList,
01227                         fl->fileListRecsAlloced * sizeof(*(fl->fileList)));
01228     }
01229             
01230     {   FileListRec * flp = &fl->fileList[fl->fileListRecsUsed];
01231 
01232         flp->fl_st = *statp;    /* structure assignment */
01233         flp->fl_mode = fileMode;
01234         flp->fl_uid = fileUid;
01235         flp->fl_gid = fileGid;
01236 
01237         flp->fileURL = xstrdup(fileURL);
01238         flp->diskURL = xstrdup(diskURL);
01239         flp->uname = fileUname;
01240         flp->gname = fileGname;
01241 
01242         if (fl->currentLangs && fl->nLangs > 0) {
01243             char *ncl;
01244             size_t nl = 0;
01245             int i;
01246             
01247             for (i = 0; i < fl->nLangs; i++)
01248                 nl += strlen(fl->currentLangs[i]) + 1;
01249 
01250             flp->langs = ncl = xmalloc(nl);
01251             for (i = 0; i < fl->nLangs; i++) {
01252                 const char *ocl;
01253                 if (i)  *ncl++ = '|';
01254                 for (ocl = fl->currentLangs[i]; *ocl; ocl++)
01255                         *ncl++ = *ocl;
01256                 *ncl = '\0';
01257             }
01258         } else if (! parseForRegexLang(fileURL, &lang)) {
01259             flp->langs = xstrdup(lang);
01260         } else {
01261             flp->langs = xstrdup("");
01262         }
01263 
01264         flp->flags = fl->currentFlags;
01265         flp->verifyFlags = fl->currentVerifyFlags;
01266 
01267         if (multiLib
01268             && !(flp->flags & RPMFILE_MULTILIB_MASK)
01269             && !parseForRegexMultiLib(fileURL))
01270             flp->flags |= multiLib;
01271 
01272         fl->totalFileSize += flp->fl_size;
01273     }
01274 
01275     fl->fileListRecsUsed++;
01276     fl->fileCount++;
01277 
01278     return 0;
01279 }
01280 
01284 static int processBinaryFile(/*@unused@*/Package pkg, struct FileList *fl,
01285         const char *fileURL)
01286 {
01287     int doGlob;
01288     const char *diskURL = NULL;
01289     int rc = 0;
01290     
01291     doGlob = myGlobPatternP(fileURL);
01292 
01293     /* Check that file starts with leading "/" */
01294     {   const char * fileName;
01295         (void) urlPath(fileURL, &fileName);
01296         if (*fileName != '/') {
01297             rpmError(RPMERR_BADSPEC, _("File needs leading \"/\": %s\n"),
01298                         fileName);
01299             rc = 1;
01300             goto exit;
01301         }
01302     }
01303     
01304     /* Copy file name or glob pattern removing multiple "/" chars. */
01305     /*
01306      * Note: rpmGetPath should guarantee a "canonical" path. That means
01307      * that the following pathologies should be weeded out:
01308      *          //bin//sh
01309      *          //usr//bin/
01310      *          /.././../usr/../bin//./sh
01311      */
01312     diskURL = rpmGenPath(fl->buildRootURL, NULL, fileURL);
01313 
01314     if (doGlob) {
01315         const char ** argv = NULL;
01316         int argc = 0;
01317         int i;
01318 
01319         rc = rpmGlob(diskURL, &argc, &argv);
01320         if (rc == 0 && argc >= 1 && !myGlobPatternP(argv[0])) {
01321             for (i = 0; i < argc; i++) {
01322                 rc = addFile(fl, argv[i], NULL);
01323                 free((void *)argv[i]);
01324             }
01325             free((void *)argv);
01326         } else {
01327             rpmError(RPMERR_BADSPEC, _("File not found by glob: %s\n"),
01328                         diskURL);
01329             rc = 1;
01330         }
01331     } else {
01332         rc = addFile(fl, diskURL, NULL);
01333     }
01334 
01335 exit:
01336     if (diskURL)
01337         free((void *)diskURL);
01338     if (rc)
01339         fl->processingFailed = 1;
01340     return rc;
01341 }
01342 
01345 static int processPackageFiles(Spec spec, Package pkg,
01346                                int installSpecialDoc, int test)
01347 {
01348     struct FileList fl;
01349     char *s, **files, **fp;
01350     const char *fileName;
01351     char buf[BUFSIZ];
01352     AttrRec specialDocAttrRec;
01353     char *specialDoc = NULL;
01354 
01355 #ifdef MULTILIB
01356     multiLib = rpmExpandNumeric("%{_multilibno}");
01357     if (multiLib)
01358         multiLib = RPMFILE_MULTILIB(multiLib);
01359 #endif /* MULTILIB */
01360     
01361     nullAttrRec(&specialDocAttrRec);
01362     pkg->cpioList = NULL;
01363     pkg->cpioCount = 0;
01364 
01365     if (pkg->fileFile) {
01366         const char *ffn;
01367         FD_t fd;
01368 
01369         /* XXX W2DO? urlPath might be useful here. */
01370         if (*pkg->fileFile == '/') {
01371             ffn = rpmGetPath(pkg->fileFile, NULL);
01372         } else {
01373             /* XXX FIXME: add %{_buildsubdir} */
01374             ffn = rpmGetPath("%{_builddir}/",
01375                 (spec->buildSubdir ? spec->buildSubdir : "") ,
01376                 "/", pkg->fileFile, NULL);
01377         }
01378         fd = Fopen(ffn, "r.fpio");
01379 
01380         if (fd == NULL || Ferror(fd)) {
01381             rpmError(RPMERR_BADFILENAME,
01382                 _("Could not open %%files file %s: %s\n"),
01383                 ffn, Fstrerror(fd));
01384             return RPMERR_BADFILENAME;
01385         }
01386         free((void *)ffn);
01387 
01388         while (fgets(buf, sizeof(buf), (FILE *)fdGetFp(fd))) {
01389             handleComments(buf);
01390             if (expandMacros(spec, spec->macros, buf, sizeof(buf))) {
01391                 rpmError(RPMERR_BADSPEC, _("line: %s\n"), buf);
01392                 return RPMERR_BADSPEC;
01393             }
01394             appendStringBuf(pkg->fileList, buf);
01395         }
01396         Fclose(fd);
01397     }
01398     
01399     /* Init the file list structure */
01400 
01401     /* XXX spec->buildRootURL == NULL, then xstrdup("") is returned */
01402     fl.buildRootURL = rpmGenPath(spec->rootURL, spec->buildRootURL, NULL);
01403 
01404     if (headerGetEntry(pkg->header, RPMTAG_DEFAULTPREFIX,
01405                        NULL, (void **)&fl.prefix, NULL)) {
01406         fl.prefix = xstrdup(fl.prefix);
01407     } else {
01408         fl.prefix = NULL;
01409     }
01410 
01411     fl.fileCount = 0;
01412     fl.totalFileSize = 0;
01413     fl.processingFailed = 0;
01414 
01415     fl.passedSpecialDoc = 0;
01416     fl.isSpecialDoc = 0;
01417 
01418     fl.isDir = 0;
01419     fl.inFtw = 0;
01420     fl.currentFlags = 0;
01421     fl.currentVerifyFlags = 0;
01422     
01423     nullAttrRec(&fl.cur_ar);
01424     nullAttrRec(&fl.def_ar);
01425 
01426     fl.defVerifyFlags = RPMVERIFY_ALL;
01427     fl.nLangs = 0;
01428     fl.currentLangs = NULL;
01429 
01430     fl.docDirCount = 0;
01431     fl.docDirs[fl.docDirCount++] = xstrdup("/usr/doc");
01432     fl.docDirs[fl.docDirCount++] = xstrdup("/usr/man");
01433     fl.docDirs[fl.docDirCount++] = xstrdup("/usr/info");
01434     fl.docDirs[fl.docDirCount++] = xstrdup("/usr/X11R6/man");
01435     fl.docDirs[fl.docDirCount++] = xstrdup("/usr/share/doc");
01436     fl.docDirs[fl.docDirCount++] = xstrdup("/usr/share/man");
01437     fl.docDirs[fl.docDirCount++] = xstrdup("/usr/share/info");
01438     fl.docDirs[fl.docDirCount++] = rpmGetPath("%{_docdir}", NULL);
01439     fl.docDirs[fl.docDirCount++] = rpmGetPath("%{_mandir}", NULL);
01440     fl.docDirs[fl.docDirCount++] = rpmGetPath("%{_infodir}", NULL);
01441     
01442     fl.fileList = NULL;
01443     fl.fileListRecsAlloced = 0;
01444     fl.fileListRecsUsed = 0;
01445 
01446     s = getStringBuf(pkg->fileList);
01447     files = splitString(s, strlen(s), '\n');
01448 
01449     for (fp = files; *fp != NULL; fp++) {
01450         s = *fp;
01451         SKIPSPACE(s);
01452         if (*s == '\0')
01453             continue;
01454         fileName = NULL;
01455         strcpy(buf, s);
01456         
01457         /* Reset for a new line in %files */
01458         fl.isDir = 0;
01459         fl.inFtw = 0;
01460         fl.currentFlags = 0;
01461         fl.currentVerifyFlags = fl.defVerifyFlags;
01462         fl.isSpecialDoc = 0;
01463 
01464         /* XXX should reset to %deflang value */
01465         if (fl.currentLangs) {
01466             int i;
01467             for (i = 0; i < fl.nLangs; i++)
01468                 free((void *)fl.currentLangs[i]);
01469             FREE(fl.currentLangs);
01470         }
01471         fl.nLangs = 0;
01472 
01473         dupAttrRec(&fl.def_ar, &fl.cur_ar);
01474 
01475         if (parseForVerify(buf, &fl))
01476             continue;
01477         if (parseForAttr(buf, &fl))
01478             continue;
01479         if (parseForConfig(buf, &fl))
01480             continue;
01481         if (parseForLang(buf, &fl))
01482             continue;
01483         if (parseForSimple(spec, pkg, buf, &fl, &fileName))
01484             continue;
01485         if (fileName == NULL)
01486             continue;
01487 
01488         if (fl.isSpecialDoc) {
01489             /* Save this stuff for last */
01490             FREE(specialDoc);
01491             specialDoc = xstrdup(fileName);
01492             dupAttrRec(&fl.cur_ar, &specialDocAttrRec);
01493         } else {
01494             processBinaryFile(pkg, &fl, fileName);
01495         }
01496     }
01497 
01498     /* Now process special doc, if there is one */
01499     if (specialDoc) {
01500         if (installSpecialDoc) {
01501             doScript(spec, RPMBUILD_STRINGBUF, "%doc", pkg->specialDoc, test);
01502         }
01503 
01504         /* Reset for %doc */
01505         fl.isDir = 0;
01506         fl.inFtw = 0;
01507         fl.currentFlags = 0;
01508         fl.currentVerifyFlags = 0;
01509 
01510         /* XXX should reset to %deflang value */
01511         if (fl.currentLangs) {
01512             int i;
01513             for (i = 0; i < fl.nLangs; i++)
01514                 free((void *)fl.currentLangs[i]);
01515             FREE(fl.currentLangs);
01516         }
01517         fl.nLangs = 0;
01518 
01519         dupAttrRec(&specialDocAttrRec, &fl.cur_ar);
01520         freeAttrRec(&specialDocAttrRec);
01521 
01522         processBinaryFile(pkg, &fl, specialDoc);
01523 
01524         FREE(specialDoc);
01525     }
01526     
01527     freeSplitString(files);
01528 
01529     if (fl.processingFailed)
01530         goto exit;
01531 
01532     /* Verify that file attributes scope over hardlinks correctly. */
01533     checkHardLinks(&fl);
01534 
01535     genCpioListAndHeader(&fl, &(pkg->cpioList), &(pkg->cpioCount),
01536                              pkg->header, 0);
01537 
01538     if (spec->timeCheck)
01539         timeCheck(spec->timeCheck, pkg->header);
01540     
01541 exit:
01542     FREE(fl.buildRootURL);
01543     FREE(fl.prefix);
01544 
01545     freeAttrRec(&fl.cur_ar);
01546     freeAttrRec(&fl.def_ar);
01547 
01548     if (fl.currentLangs) {
01549         int i;
01550         for (i = 0; i < fl.nLangs; i++)
01551             free((void *)fl.currentLangs[i]);
01552         FREE(fl.currentLangs);
01553     }
01554 
01555     freeFileList(fl.fileList, fl.fileListRecsUsed);
01556     while (fl.docDirCount--) {
01557         FREE(fl.docDirs[fl.docDirCount]);
01558     }
01559     return fl.processingFailed;
01560 }
01561 
01562 void initSourceHeader(Spec spec)
01563 {
01564     HeaderIterator hi;
01565     int_32 tag, type, count;
01566     const void * ptr;
01567 
01568     spec->sourceHeader = headerNew();
01569     /* Only specific tags are added to the source package header */
01570     for (hi = headerInitIterator(spec->packages->header);
01571         headerNextIterator(hi, &tag, &type, &ptr, &count);
01572         ptr = headerFreeData(ptr, type))
01573     {
01574         switch (tag) {
01575         case RPMTAG_NAME:
01576         case RPMTAG_VERSION:
01577         case RPMTAG_RELEASE:
01578         case RPMTAG_EPOCH:
01579         case RPMTAG_SUMMARY:
01580         case RPMTAG_DESCRIPTION:
01581         case RPMTAG_PACKAGER:
01582         case RPMTAG_DISTRIBUTION:
01583         case RPMTAG_DISTURL:
01584         case RPMTAG_VENDOR:
01585         case RPMTAG_LICENSE:
01586         case RPMTAG_GROUP:
01587         case RPMTAG_OS:
01588         case RPMTAG_ARCH:
01589         case RPMTAG_CHANGELOGTIME:
01590         case RPMTAG_CHANGELOGNAME:
01591         case RPMTAG_CHANGELOGTEXT:
01592         case RPMTAG_URL:
01593         case HEADER_I18NTABLE:
01594             headerAddEntry(spec->sourceHeader, tag, type, ptr, count);
01595             break;
01596         default:
01597             /* do not copy */
01598             break;
01599         }
01600     }
01601     headerFreeIterator(hi);
01602 
01603     /* Add the build restrictions */
01604     for (hi = headerInitIterator(spec->buildRestrictions);
01605         headerNextIterator(hi, &tag, &type, &ptr, &count);
01606         ptr = headerFreeData(ptr, type))
01607     {
01608         headerAddEntry(spec->sourceHeader, tag, type, ptr, count);
01609     }
01610     headerFreeIterator(hi);
01611 
01612     if (spec->buildArchitectureCount) {
01613         headerAddEntry(spec->sourceHeader, RPMTAG_BUILDARCHS,
01614                        RPM_STRING_ARRAY_TYPE,
01615                        spec->buildArchitectures, spec->buildArchitectureCount);
01616     }
01617 }
01618 
01619 int processSourceFiles(Spec spec)
01620 {
01621     struct Source *srcPtr;
01622     StringBuf sourceFiles;
01623     int x, isSpec = 1;
01624     struct FileList fl;
01625     char *s, **files, **fp;
01626     Package pkg;
01627 
01628     sourceFiles = newStringBuf();
01629 
01630     /* XXX
01631      * XXX This is where the source header for noarch packages needs
01632      * XXX to be initialized.
01633      */
01634     if (spec->sourceHeader == NULL)
01635         initSourceHeader(spec);
01636 
01637     /* Construct the file list and source entries */
01638     appendLineStringBuf(sourceFiles, spec->specFile);
01639     for (srcPtr = spec->sources; srcPtr != NULL; srcPtr = srcPtr->next) {
01640         if (srcPtr->flags & RPMBUILD_ISSOURCE) {
01641             headerAddOrAppendEntry(spec->sourceHeader, RPMTAG_SOURCE,
01642                                    RPM_STRING_ARRAY_TYPE, &srcPtr->source, 1);
01643             if (srcPtr->flags & RPMBUILD_ISNO) {
01644                 headerAddOrAppendEntry(spec->sourceHeader, RPMTAG_NOSOURCE,
01645                                        RPM_INT32_TYPE, &srcPtr->num, 1);
01646             }
01647         }
01648         if (srcPtr->flags & RPMBUILD_ISPATCH) {
01649             headerAddOrAppendEntry(spec->sourceHeader, RPMTAG_PATCH,
01650                                    RPM_STRING_ARRAY_TYPE, &srcPtr->source, 1);
01651             if (srcPtr->flags & RPMBUILD_ISNO) {
01652                 headerAddOrAppendEntry(spec->sourceHeader, RPMTAG_NOPATCH,
01653                                        RPM_INT32_TYPE, &srcPtr->num, 1);
01654             }
01655         }
01656 
01657       { const char *s;
01658         s = rpmGetPath( ((srcPtr->flags & RPMBUILD_ISNO) ? "!" : ""),
01659                 "%{_sourcedir}/", srcPtr->source, NULL);
01660         appendLineStringBuf(sourceFiles, s);
01661         free((void *)s);
01662       }
01663     }
01664 
01665     for (pkg = spec->packages; pkg != NULL; pkg = pkg->next) {
01666         for (srcPtr = pkg->icon; srcPtr != NULL; srcPtr = srcPtr->next) {
01667             const char *s;
01668             s = rpmGetPath( ((srcPtr->flags & RPMBUILD_ISNO) ? "!" : ""),
01669                 "%{_sourcedir}/", srcPtr->source, NULL);
01670             appendLineStringBuf(sourceFiles, s);
01671             free((void *)s);
01672         }
01673     }
01674 
01675     spec->sourceCpioList = NULL;
01676     spec->sourceCpioCount = 0;
01677 
01678     fl.fileList = xmalloc((spec->numSources + 1) * sizeof(FileListRec));
01679     fl.processingFailed = 0;
01680     fl.fileListRecsUsed = 0;
01681     fl.totalFileSize = 0;
01682     fl.prefix = NULL;
01683 
01684     s = getStringBuf(sourceFiles);
01685     files = splitString(s, strlen(s), '\n');
01686 
01687     /* The first source file is the spec file */
01688     x = 0;
01689     for (fp = files; *fp != NULL; fp++) {
01690         const char * diskURL, *diskPath;
01691         FileListRec *flp;
01692 
01693         diskURL = *fp;
01694         SKIPSPACE(diskURL);
01695         if (! *diskURL)
01696             continue;
01697 
01698         flp = &fl.fileList[x];
01699 
01700         flp->flags = isSpec ? RPMFILE_SPECFILE : 0;
01701         /* files with leading ! are no source files */
01702         if (*diskURL == '!') {
01703             flp->flags |= RPMFILE_GHOST;
01704             diskURL++;
01705         }
01706 
01707         urlPath(diskURL, &diskPath);
01708 
01709         flp->diskURL = xstrdup(diskURL);
01710         diskPath = strrchr(diskPath, '/');
01711         if (diskPath)
01712             diskPath++;
01713         else
01714             diskPath = diskURL;
01715 
01716         flp->fileURL = xstrdup(diskPath);
01717         flp->verifyFlags = RPMVERIFY_ALL;
01718 
01719         if (Stat(diskURL, &flp->fl_st)) {
01720             rpmError(RPMERR_BADSPEC, _("Bad file: %s: %s\n"),
01721                 diskURL, strerror(errno));
01722             fl.processingFailed = 1;
01723         }
01724 
01725         flp->uname = getUname(flp->fl_uid);
01726         flp->gname = getGname(flp->fl_gid);
01727         flp->langs = xstrdup("");
01728         
01729         fl.totalFileSize += flp->fl_size;
01730         
01731         if (! (flp->uname && flp->gname)) {
01732             rpmError(RPMERR_BADSPEC, _("Bad owner/group: %s\n"), diskURL);
01733             fl.processingFailed = 1;
01734         }
01735 
01736         isSpec = 0;
01737         x++;
01738     }
01739     fl.fileListRecsUsed = x;
01740     freeSplitString(files);
01741 
01742     if (! fl.processingFailed) {
01743         genCpioListAndHeader(&fl, &(spec->sourceCpioList),
01744                              &(spec->sourceCpioCount), spec->sourceHeader, 1);
01745     }
01746 
01747     freeStringBuf(sourceFiles);
01748     freeFileList(fl.fileList, fl.fileListRecsUsed);
01749     return fl.processingFailed;
01750 }
01751 
01754 static StringBuf getOutputFrom(char *dir, char *argv[],
01755                         const char *writePtr, int writeBytesLeft,
01756                         int failNonZero)
01757 {
01758     int progPID;
01759     int toProg[2];
01760     int fromProg[2];
01761     int status;
01762     void *oldhandler;
01763     StringBuf readBuff;
01764     int done;
01765 
01766     oldhandler = signal(SIGPIPE, SIG_IGN);
01767 
01768     toProg[0] = toProg[1] = 0;
01769     pipe(toProg);
01770     fromProg[0] = fromProg[1] = 0;
01771     pipe(fromProg);
01772     
01773     if (!(progPID = fork())) {
01774         close(toProg[1]);
01775         close(fromProg[0]);
01776         
01777         dup2(toProg[0], STDIN_FILENO);   /* Make stdin the in pipe */
01778         dup2(fromProg[1], STDOUT_FILENO); /* Make stdout the out pipe */
01779 
01780         close(toProg[0]);
01781         close(fromProg[1]);
01782 
01783         if (dir) {
01784             chdir(dir);
01785         }
01786         
01787         execvp(argv[0], argv);
01788         /* XXX this error message is probably not seen. */
01789         rpmError(RPMERR_EXEC, _("Couldn't exec %s: %s\n"),
01790                 argv[0], strerror(errno));
01791         _exit(RPMERR_EXEC);
01792     }
01793     if (progPID < 0) {
01794         rpmError(RPMERR_FORK, _("Couldn't fork %s: %s\n"),
01795                 argv[0], strerror(errno));
01796         return NULL;
01797     }
01798 
01799     close(toProg[0]);
01800     close(fromProg[1]);
01801 
01802     /* Do not block reading or writing from/to prog. */
01803     fcntl(fromProg[0], F_SETFL, O_NONBLOCK);
01804     fcntl(toProg[1], F_SETFL, O_NONBLOCK);
01805     
01806     readBuff = newStringBuf();
01807 
01808     do {
01809         fd_set ibits, obits;
01810         struct timeval tv;
01811         int nfd, nbw, nbr;
01812         int rc;
01813 
01814         done = 0;
01815 top:
01816         /* XXX the select is mainly a timer since all I/O is non-blocking */
01817         FD_ZERO(&ibits);
01818         FD_ZERO(&obits);
01819         if (fromProg[0] >= 0) {
01820             FD_SET(fromProg[0], &ibits);
01821         }
01822         if (toProg[1] >= 0) {
01823             FD_SET(toProg[1], &obits);
01824         }
01825         tv.tv_sec = 1;
01826         tv.tv_usec = 0;
01827         nfd = ((fromProg[0] > toProg[1]) ? fromProg[0] : toProg[1]);
01828         if ((rc = select(nfd, &ibits, &obits, NULL, &tv)) < 0) {
01829             if (errno == EINTR)
01830                 goto top;
01831             break;
01832         }
01833 
01834         /* Write any data to program */
01835         if (toProg[1] >= 0 && FD_ISSET(toProg[1], &obits)) {
01836           if (writeBytesLeft) {
01837             if ((nbw = write(toProg[1], writePtr,
01838                     (1024<writeBytesLeft) ? 1024 : writeBytesLeft)) < 0) {
01839                 if (errno != EAGAIN) {
01840                     perror("getOutputFrom()");
01841                     exit(EXIT_FAILURE);
01842                 }
01843                 nbw = 0;
01844             }
01845             writeBytesLeft -= nbw;
01846             writePtr += nbw;
01847           } else if (toProg[1] >= 0) {  /* close write fd */
01848             close(toProg[1]);
01849             toProg[1] = -1;
01850           }
01851         }
01852         
01853         /* Read any data from prog */
01854         {   char buf[BUFSIZ+1];
01855             while ((nbr = read(fromProg[0], buf, sizeof(buf)-1)) > 0) {
01856                 buf[nbr] = '\0';
01857                 appendStringBuf(readBuff, buf);
01858             }
01859         }
01860 
01861         /* terminate on (non-blocking) EOF or error */
01862         done = (nbr == 0 || (nbr < 0 && errno != EAGAIN));
01863 
01864     } while (!done);
01865 
01866     /* Clean up */
01867     if (toProg[1] >= 0)
01868         close(toProg[1]);
01869     if (fromProg[0] >= 0)
01870         close(fromProg[0]);
01871     (void)signal(SIGPIPE, oldhandler);
01872 
01873     /* Collect status from prog */
01874     (void)waitpid(progPID, &status, 0);
01875     if (failNonZero && (!WIFEXITED(status) || WEXITSTATUS(status))) {
01876         rpmError(RPMERR_EXEC, _("%s failed\n"), argv[0]);
01877         return NULL;
01878     }
01879     if (writeBytesLeft) {
01880         rpmError(RPMERR_EXEC, _("failed to write all data to %s\n"), argv[0]);
01881         return NULL;
01882     }
01883     return readBuff;
01884 }
01885 
01888 typedef struct {
01889     const char *msg;
01890     const char *argv[4];
01891     int ntag;
01892     int vtag;
01893     int ftag;
01894     int mask;
01895     int xor;
01896 } DepMsg_t;
01897 
01900 DepMsg_t depMsgs[] = {
01901   { "Provides",         { "%{__find_provides}", NULL, NULL, NULL },
01902         RPMTAG_PROVIDENAME, RPMTAG_PROVIDEVERSION, RPMTAG_PROVIDEFLAGS,
01903         0, -1 },
01904   { "PreReq",           { NULL, NULL, NULL, NULL },
01905         RPMTAG_REQUIRENAME, RPMTAG_REQUIREVERSION, RPMTAG_REQUIREFLAGS,
01906         RPMSENSE_PREREQ, 0 },
01907   { "Requires(interp)", { NULL, "interp", NULL, NULL },
01908         -1, -1, RPMTAG_REQUIREFLAGS,
01909         _notpre(RPMSENSE_INTERP), 0 },
01910   { "Requires(rpmlib)", { NULL, "rpmlib", NULL, NULL },
01911         -1, -1, RPMTAG_REQUIREFLAGS,
01912         _notpre(RPMSENSE_RPMLIB), 0 },
01913   { "Requires(verify)", { NULL, "verify", NULL, NULL },
01914         -1, -1, RPMTAG_REQUIREFLAGS,
01915         RPMSENSE_SCRIPT_VERIFY, 0 },
01916   { "Requires(pre)",    { NULL, "pre", NULL, NULL },
01917         -1, -1, RPMTAG_REQUIREFLAGS,
01918         _notpre(RPMSENSE_SCRIPT_PRE), 0 },
01919   { "Requires(post)",   { NULL, "post", NULL, NULL },
01920         -1, -1, RPMTAG_REQUIREFLAGS,
01921         _notpre(RPMSENSE_SCRIPT_POST), 0 },
01922   { "Requires(preun)",  { NULL, "preun", NULL, NULL },
01923         -1, -1, RPMTAG_REQUIREFLAGS,
01924         _notpre(RPMSENSE_SCRIPT_PREUN), 0 },
01925   { "Requires(postun)", { NULL, "postun", NULL, NULL },
01926         -1, -1, RPMTAG_REQUIREFLAGS,
01927         _notpre(RPMSENSE_SCRIPT_POSTUN), 0 },
01928   { "Requires",         { "%{__find_requires}", NULL, NULL, NULL },
01929         -1, -1, RPMTAG_REQUIREFLAGS,    /* XXX inherit name/version arrays */
01930         RPMSENSE_PREREQ, RPMSENSE_PREREQ },
01931   { "Conflicts",        { "%{__find_conflicts}", NULL, NULL, NULL },
01932         RPMTAG_CONFLICTNAME, RPMTAG_CONFLICTVERSION, RPMTAG_CONFLICTFLAGS,
01933         0, -1 },
01934   { "Obsoletes",        { "%{__find_obsoletes}", NULL, NULL, NULL },
01935         RPMTAG_OBSOLETENAME, RPMTAG_OBSOLETEVERSION, RPMTAG_OBSOLETEFLAGS,
01936         0, -1 },
01937   { NULL,               { NULL, NULL, NULL, NULL },     0, 0, 0, 0, 0 }
01938 };
01939 
01942 static int generateDepends(Spec spec, Package pkg,
01943                            struct cpioFileMapping *cpioList, int cpioCount,
01944                            int multiLib)
01945 {
01946     StringBuf writeBuf;
01947     int writeBytes;
01948     StringBuf readBuf;
01949     DepMsg_t *dm;
01950     char *myargv[4];
01951     int failnonzero = 0;
01952     int rc = 0;
01953 
01954     if (cpioCount <= 0)
01955         return 0;
01956 
01957     if (! (pkg->autoReq || pkg->autoProv))
01958         return 0;
01959     
01960     writeBuf = newStringBuf();
01961     for (writeBytes = 0; cpioCount--; cpioList++) {
01962 
01963         if (multiLib == 2) {
01964             if (!(cpioList->mapFlags & CPIO_MULTILIB))
01965                 continue;
01966             cpioList->mapFlags &= ~CPIO_MULTILIB;
01967         }
01968 
01969         writeBytes += strlen(cpioList->fsPath) + 1;
01970         appendLineStringBuf(writeBuf, cpioList->fsPath);
01971     }
01972 
01973     for (dm = depMsgs; dm->msg != NULL; dm++) {
01974         int i, tag, tagflags;
01975 
01976         tag = (dm->ftag > 0) ? dm->ftag : dm->ntag;
01977         tagflags = 0;
01978 
01979         switch(tag) {
01980         case RPMTAG_PROVIDEFLAGS:
01981             if (!pkg->autoProv)
01982                 continue;
01983             failnonzero = 1;
01984             tagflags = RPMSENSE_FIND_PROVIDES;
01985             break;
01986         case RPMTAG_REQUIREFLAGS:
01987             if (!pkg->autoReq)
01988                 continue;
01989             failnonzero = 0;
01990             tagflags = RPMSENSE_FIND_REQUIRES;
01991             break;
01992         default:
01993             continue;
01994             /*@notreached@*/ break;
01995         }
01996 
01997         /* Get the script name to run */
01998         myargv[0] = (dm->argv[0] ? rpmExpand(dm->argv[0], NULL) : NULL);
01999 
02000         if (!(myargv[0] && *myargv[0] != '%')) {
02001             free(myargv[0]);
02002             continue;
02003         }
02004 
02005         rpmMessage(RPMMESS_NORMAL, _("Finding  %s: (using %s)...\n"),
02006                 dm->msg, myargv[0]);
02007 
02008 #if 0
02009         if (*myargv[0] != '/') {        /* XXX FIXME: stat script here */
02010             free(myargv[0]);
02011             myargv[0] = NULL;
02012             continue;
02013         }
02014 #endif
02015 
02016         /* Expand rest of script arguments (if any) */
02017         for (i = 1; i < 4; i++) {
02018             myargv[i] = dm->argv[i] ? rpmExpand(dm->argv[i], NULL) : NULL;
02019         }
02020 
02021         readBuf = getOutputFrom(NULL, myargv,
02022                         getStringBuf(writeBuf), writeBytes, failnonzero);
02023 
02024         /* Free expanded args */
02025         for (i = 0; i < 4; i++) {
02026             if (myargv[i] == NULL) continue;
02027             free(myargv[i]);
02028             myargv[i] = NULL;
02029         }
02030 
02031         if (readBuf == NULL) {
02032             rc = RPMERR_EXEC;
02033             rpmError(rc, _("Failed to find %s:\n"), dm->msg);
02034             break;
02035         }
02036 
02037         /* Parse dependencies into header */
02038         tagflags &= ~RPMSENSE_MULTILIB;
02039         if (multiLib > 1)
02040             tagflags |=  RPMSENSE_MULTILIB;
02041         else
02042             tagflags &= ~RPMSENSE_MULTILIB;
02043         rc = parseRCPOT(spec, pkg, getStringBuf(readBuf), tag, 0, tagflags);
02044         freeStringBuf(readBuf);
02045 
02046         if (rc) {
02047             rpmError(rc, _("Failed to find %s:\n"), dm->msg);
02048             break;
02049         }
02050     }
02051 
02052     freeStringBuf(writeBuf);
02053     return rc;
02054 }
02055 
02058 static void printDepMsg(DepMsg_t *dm, int count, const char **names,
02059         const char **versions, int *flags)
02060 {
02061     int hasVersions = (versions != NULL);
02062     int hasFlags = (flags != NULL);
02063     int bingo = 0;
02064     int i;
02065 
02066     for (i = 0; i < count; i++, names++, versions++, flags++) {
02067         if (hasFlags && !((*flags & dm->mask) ^ dm->xor))
02068             continue;
02069         if (bingo == 0) {
02070             rpmMessage(RPMMESS_NORMAL, "%s:", dm->msg);
02071             bingo = 1;
02072         }
02073         rpmMessage(RPMMESS_NORMAL, " %s", *names);
02074 
02075         if (hasFlags && isDependsMULTILIB(*flags))
02076             rpmMessage(RPMMESS_NORMAL, " (multilib)");
02077 
02078         if (hasVersions && !(*versions != NULL && **versions != '\0'))
02079             continue;
02080         if (!(hasFlags && (*flags && RPMSENSE_SENSEMASK)))
02081             continue;
02082 
02083         rpmMessage(RPMMESS_NORMAL, " ");
02084         if (*flags & RPMSENSE_LESS)
02085             rpmMessage(RPMMESS_NORMAL, "<");
02086         if (*flags & RPMSENSE_GREATER)
02087             rpmMessage(RPMMESS_NORMAL, ">");
02088         if (*flags & RPMSENSE_EQUAL)
02089             rpmMessage(RPMMESS_NORMAL, "=");
02090 
02091         rpmMessage(RPMMESS_NORMAL, " %s", *versions);
02092     }
02093     if (bingo)
02094         rpmMessage(RPMMESS_NORMAL, "\n");
02095 }
02096 
02099 static void printDeps(Header h)
02100 {
02101     const char **names = NULL;
02102     const char **versions = NULL;
02103     int *flags = NULL;
02104     DepMsg_t *dm;
02105     int type, count;
02106 
02107     for (dm = depMsgs; dm->msg != NULL; dm++) {
02108         switch (dm->ntag) {
02109         case 0:
02110             FREE(names);
02111             break;
02112         case -1:
02113             break;
02114         default:
02115             FREE(names);
02116             if (!headerGetEntry(h, dm->ntag, &type, (void **) &names, &count))
02117                 continue;
02118             break;
02119         }
02120         switch (dm->vtag) {
02121         case 0:
02122             FREE(versions);
02123             break;
02124         case -1:
02125             break;
02126         default:
02127             FREE(versions);
02128             headerGetEntry(h, dm->vtag, NULL, (void **) &versions, NULL);
02129             break;
02130         }
02131         switch (dm->ftag) {
02132         case 0:
02133             flags = NULL;
02134             break;
02135         case -1:
02136             break;
02137         default:
02138             headerGetEntry(h, dm->ftag, NULL, (void **) &flags, NULL);
02139             break;
02140         }
02141         printDepMsg(dm, count, names, versions, flags);
02142     }
02143     FREE(names);
02144     FREE(versions);
02145 }
02146 
02147 int processBinaryFiles(Spec spec, int installSpecialDoc, int test)
02148 {
02149     Package pkg;
02150     int res = 0;
02151     
02152     for (pkg = spec->packages; pkg != NULL; pkg = pkg->next) {
02153         const char *n, *v, *r;
02154         int rc;
02155 
02156         if (pkg->fileList == NULL)
02157             continue;
02158 
02159         headerNVR(pkg->header, &n, &v, &r);
02160         rpmMessage(RPMMESS_NORMAL, _("Processing files: %s-%s-%s\n"), n, v, r);
02161                    
02162         if ((rc = processPackageFiles(spec, pkg, installSpecialDoc, test)))
02163             res = rc;
02164 
02165     /* XXX This should be added always so that packages look alike.
02166      * XXX However, there is logic in files.c/depends.c that checks for
02167      * XXX existence (rather than value) that will need to change as well.
02168      */
02169         if (headerGetEntry(pkg->header, RPMTAG_MULTILIBS, NULL, NULL, NULL)) {
02170             generateDepends(spec, pkg, pkg->cpioList, pkg->cpioCount, 1);
02171             generateDepends(spec, pkg, pkg->cpioList, pkg->cpioCount, 2);
02172         } else
02173             generateDepends(spec, pkg, pkg->cpioList, pkg->cpioCount, 0);
02174         printDeps(pkg->header);
02175         
02176     }
02177 
02178     return res;
02179 }

Generated at Mon May 21 08:53:38 2001 for rpm by doxygen1.2.6 written by Dimitri van Heesch, © 1997-2001