rpm 5.3.12
|
00001 00007 #include "system.h" 00008 00009 #define MYALLPERMS 07777 00010 00011 #if defined(WITH_PCRE) && defined(WITH_PCRE_POSIX) 00012 #include <pcreposix.h> 00013 #else 00014 #include <regex.h> 00015 #endif 00016 00017 #define _RPMIOB_INTERNAL 00018 #include <rpmiotypes.h> 00019 #include <rpmio_internal.h> /* XXX fdGetFp */ 00020 #include <rpmbf.h> 00021 #include <rpmcb.h> 00022 #define _RPMSX_INTERNAL /* XXX permit disabling. */ 00023 #include <rpmsx.h> 00024 #include <fts.h> 00025 #include <argv.h> 00026 00027 #include "iosm.h" 00028 #define _RPMTAG_INTERNAL /* XXX rpmTags->aTags */ 00029 #define _RPMFI_INTERNAL 00030 #include <rpmbuild.h> 00031 00032 #define _RPMTE_INTERNAL 00033 #include <rpmte.h> 00034 00035 #include "rpmfc.h" 00036 00037 #include "buildio.h" 00038 00039 #include "legacy.h" /* XXX dodigest */ 00040 #include "debug.h" 00041 00042 /*@access Header @*/ 00043 /*@access rpmfi @*/ 00044 /*@access rpmte @*/ 00045 /*@access FD_t @*/ 00046 00047 #define SKIPWHITE(_x) {while(*(_x) && (xisspace(*_x) || *(_x) == ',')) (_x)++;} 00048 #define SKIPNONWHITE(_x){while(*(_x) &&!(xisspace(*_x) || *(_x) == ',')) (_x)++;} 00049 00050 #define MAXDOCDIR 1024 00051 00054 typedef enum specdFlags_e { 00055 SPECD_DEFFILEMODE = (1 << 0), 00056 SPECD_DEFDIRMODE = (1 << 1), 00057 SPECD_DEFUID = (1 << 2), 00058 SPECD_DEFGID = (1 << 3), 00059 SPECD_DEFVERIFY = (1 << 4), 00060 00061 SPECD_FILEMODE = (1 << 8), 00062 SPECD_DIRMODE = (1 << 9), 00063 SPECD_UID = (1 << 10), 00064 SPECD_GID = (1 << 11), 00065 SPECD_VERIFY = (1 << 12) 00066 } specdFlags; 00067 00070 typedef struct FileListRec_s { 00071 struct stat fl_st; 00072 #define fl_dev fl_st.st_dev 00073 #define fl_ino fl_st.st_ino 00074 #define fl_mode fl_st.st_mode 00075 #define fl_nlink fl_st.st_nlink 00076 #define fl_uid fl_st.st_uid 00077 #define fl_gid fl_st.st_gid 00078 #define fl_rdev fl_st.st_rdev 00079 #define fl_size fl_st.st_size 00080 #define fl_mtime fl_st.st_mtime 00081 00082 /*@only@*/ 00083 const char *diskURL; /* get file from here */ 00084 /*@only@*/ 00085 const char *fileURL; /* filename in cpio archive */ 00086 /*@observer@*/ 00087 const char *uname; 00088 /*@observer@*/ 00089 const char *gname; 00090 unsigned flags; 00091 specdFlags specdFlags; /* which attributes have been explicitly specified. */ 00092 unsigned verifyFlags; 00093 /*@only@*/ 00094 const char *langs; /* XXX locales separated with | */ 00095 } * FileListRec; 00096 00099 typedef struct AttrRec_s { 00100 /*@null@*/ 00101 const char *ar_fmodestr; 00102 /*@null@*/ 00103 const char *ar_dmodestr; 00104 /*@null@*/ 00105 const char *ar_user; 00106 /*@null@*/ 00107 const char *ar_group; 00108 mode_t ar_fmode; 00109 mode_t ar_dmode; 00110 } * AttrRec; 00111 00112 /*@-readonlytrans@*/ 00113 /*@unchecked@*/ /*@observer@*/ 00114 static struct AttrRec_s root_ar = { NULL, NULL, "root", "root", 0, 0 }; 00115 /*@=readonlytrans@*/ 00116 00120 typedef struct FileList_s { 00121 /*@only@*/ 00122 const char * buildRootURL; 00123 /*@only@*/ 00124 const char * prefix; 00125 00126 int fileCount; 00127 int totalFileSize; 00128 int processingFailed; 00129 00130 int passedSpecialDoc; 00131 int isSpecialDoc; 00132 00133 int noGlob; 00134 unsigned devtype; 00135 unsigned devmajor; 00136 int devminor; 00137 00138 int isDir; 00139 int inFtw; 00140 int currentFlags; 00141 specdFlags currentSpecdFlags; 00142 unsigned currentVerifyFlags; 00143 struct AttrRec_s cur_ar; 00144 struct AttrRec_s def_ar; 00145 specdFlags defSpecdFlags; 00146 unsigned defVerifyFlags; 00147 int nLangs; 00148 /*@only@*/ /*@null@*/ 00149 const char ** currentLangs; 00150 00151 /* Hard coded limit of MAXDOCDIR docdirs. */ 00152 /* If you break it you are doing something wrong. */ 00153 const char * docDirs[MAXDOCDIR]; 00154 int docDirCount; 00155 00156 /*@only@*/ 00157 FileListRec fileList; 00158 int fileListRecsAlloced; 00159 int fileListRecsUsed; 00160 } * FileList; 00161 00164 static void nullAttrRec(/*@out@*/ AttrRec ar) /*@modifies ar @*/ 00165 { 00166 ar->ar_fmodestr = NULL; 00167 ar->ar_dmodestr = NULL; 00168 ar->ar_user = NULL; 00169 ar->ar_group = NULL; 00170 ar->ar_fmode = 0; 00171 ar->ar_dmode = 0; 00172 } 00173 00176 static void freeAttrRec(AttrRec ar) /*@modifies ar @*/ 00177 { 00178 ar->ar_fmodestr = _free(ar->ar_fmodestr); 00179 ar->ar_dmodestr = _free(ar->ar_dmodestr); 00180 ar->ar_user = _free(ar->ar_user); 00181 ar->ar_group = _free(ar->ar_group); 00182 /* XXX doesn't free ar (yet) */ 00183 /*@-nullstate@*/ 00184 return; 00185 /*@=nullstate@*/ 00186 } 00187 00190 static void dupAttrRec(const AttrRec oar, /*@in@*/ /*@out@*/ AttrRec nar) 00191 /*@modifies nar @*/ 00192 { 00193 if (oar == nar) 00194 return; 00195 freeAttrRec(nar); 00196 nar->ar_fmodestr = (oar->ar_fmodestr ? xstrdup(oar->ar_fmodestr) : NULL); 00197 nar->ar_dmodestr = (oar->ar_dmodestr ? xstrdup(oar->ar_dmodestr) : NULL); 00198 nar->ar_user = (oar->ar_user ? xstrdup(oar->ar_user) : NULL); 00199 nar->ar_group = (oar->ar_group ? xstrdup(oar->ar_group) : NULL); 00200 nar->ar_fmode = oar->ar_fmode; 00201 nar->ar_dmode = oar->ar_dmode; 00202 } 00203 00204 #if 0 00205 00207 static void dumpAttrRec(const char * msg, AttrRec ar) 00208 /*@globals fileSystem@*/ 00209 /*@modifies fileSystem @*/ 00210 { 00211 if (msg) 00212 fprintf(stderr, "%s:\t", msg); 00213 fprintf(stderr, "(%s, %s, %s, %s)\n", 00214 ar->ar_fmodestr, 00215 ar->ar_user, 00216 ar->ar_group, 00217 ar->ar_dmodestr); 00218 } 00219 #endif 00220 00226 /*@null@*/ 00227 static char *strtokWithQuotes(/*@null@*/ char *s, const char *delim) 00228 /*@modifies *s @*/ 00229 { 00230 static char *olds = NULL; 00231 char *token; 00232 00233 if (s == NULL) 00234 s = olds; 00235 if (s == NULL) 00236 return NULL; 00237 00238 /* Skip leading delimiters */ 00239 s += strspn(s, delim); 00240 if (*s == '\0') 00241 return NULL; 00242 00243 /* Find the end of the token. */ 00244 token = s; 00245 if (*token == '"') { 00246 token++; 00247 /* Find next " char */ 00248 s = strchr(token, '"'); 00249 } else { 00250 s = strpbrk(token, delim); 00251 } 00252 00253 /* Terminate it */ 00254 if (s == NULL) { 00255 /* This token finishes the string */ 00256 olds = strchr(token, '\0'); 00257 } else { 00258 /* Terminate the token and make olds point past it */ 00259 *s = '\0'; 00260 olds = s+1; 00261 } 00262 00263 /*@-retalias -temptrans @*/ 00264 return token; 00265 /*@=retalias =temptrans @*/ 00266 } 00267 00270 static void timeCheck(int tc, Header h) 00271 /*@globals internalState @*/ 00272 /*@modifies internalState @*/ 00273 { 00274 HE_t he = memset(alloca(sizeof(*he)), 0, sizeof(*he)); 00275 rpmuint32_t currentTime = (rpmuint32_t) time(NULL); 00276 rpmuint32_t * mtime; 00277 int xx; 00278 size_t i; 00279 00280 he->tag = RPMTAG_FILEMTIMES; 00281 xx = headerGet(h, he, 0); 00282 mtime = he->p.ui32p; 00283 he->tag = RPMTAG_OLDFILENAMES; 00284 xx = headerGet(h, he, 0); 00285 00286 for (i = 0; i < he->c; i++) { 00287 xx = currentTime - mtime[i]; 00288 if (xx < 0) xx = -xx; 00289 if (xx > tc) 00290 rpmlog(RPMLOG_WARNING, _("TIMECHECK failure: %s\n"), he->p.argv[i]); 00291 } 00292 he->p.ptr = _free(he->p.ptr); 00293 mtime = _free(mtime); 00294 } 00295 00298 typedef struct VFA { 00299 /*@observer@*/ /*@null@*/ const char * attribute; 00300 int not; 00301 int flag; 00302 } VFA_t; 00303 00306 /*@-exportlocal -exportheadervar@*/ 00307 /*@unchecked@*/ 00308 static VFA_t verifyAttrs[] = { 00309 { "md5", 0, RPMVERIFY_FDIGEST }, /* XXX legacy syntax */ 00310 { "size", 0, RPMVERIFY_FILESIZE }, 00311 { "link", 0, RPMVERIFY_LINKTO }, 00312 { "user", 0, RPMVERIFY_USER }, 00313 { "group", 0, RPMVERIFY_GROUP }, 00314 { "mtime", 0, RPMVERIFY_MTIME }, 00315 { "mode", 0, RPMVERIFY_MODE }, 00316 { "rdev", 0, RPMVERIFY_RDEV }, 00317 { "digest", 0, RPMVERIFY_FDIGEST }, 00318 { "hmac", 0, RPMVERIFY_HMAC }, 00319 { NULL, 0, 0 } 00320 }; 00321 /*@=exportlocal =exportheadervar@*/ 00322 00329 static rpmRC parseForVerify(char * buf, FileList fl) 00330 /*@modifies buf, fl->processingFailed, 00331 fl->currentVerifyFlags, fl->defVerifyFlags, 00332 fl->currentSpecdFlags, fl->defSpecdFlags @*/ 00333 { 00334 char *p, *pe, *q; 00335 const char *name; 00336 unsigned *resultVerify; 00337 int negated; 00338 unsigned verifyFlags; 00339 specdFlags * specdFlags; 00340 00341 if ((p = strstr(buf, (name = "%verify"))) != NULL) { 00342 resultVerify = &(fl->currentVerifyFlags); 00343 specdFlags = &fl->currentSpecdFlags; 00344 } else if ((p = strstr(buf, (name = "%defverify"))) != NULL) { 00345 resultVerify = &(fl->defVerifyFlags); 00346 specdFlags = &fl->defSpecdFlags; 00347 } else 00348 return RPMRC_OK; 00349 00350 for (pe = p; (size_t)(pe-p) < strlen(name); pe++) 00351 *pe = ' '; 00352 00353 SKIPSPACE(pe); 00354 00355 if (*pe != '(') { 00356 rpmlog(RPMLOG_ERR, _("Missing '(' in %s %s\n"), name, pe); 00357 fl->processingFailed = 1; 00358 return RPMRC_FAIL; 00359 } 00360 00361 /* Bracket %*verify args */ 00362 *pe++ = ' '; 00363 for (p = pe; *pe && *pe != ')'; pe++) 00364 {}; 00365 00366 if (*pe == '\0') { 00367 rpmlog(RPMLOG_ERR, _("Missing ')' in %s(%s\n"), name, p); 00368 fl->processingFailed = 1; 00369 return RPMRC_FAIL; 00370 } 00371 00372 /* Localize. Erase parsed string */ 00373 q = alloca((pe-p) + 1); 00374 strncpy(q, p, pe-p); 00375 q[pe-p] = '\0'; 00376 while (p <= pe) 00377 *p++ = ' '; 00378 00379 negated = 0; 00380 verifyFlags = RPMVERIFY_NONE; 00381 00382 for (p = q; *p != '\0'; p = pe) { 00383 SKIPWHITE(p); 00384 if (*p == '\0') 00385 break; 00386 pe = p; 00387 SKIPNONWHITE(pe); 00388 if (*pe != '\0') 00389 *pe++ = '\0'; 00390 00391 { VFA_t *vfa; 00392 for (vfa = verifyAttrs; vfa->attribute != NULL; vfa++) { 00393 if (strcmp(p, vfa->attribute)) 00394 /*@innercontinue@*/ continue; 00395 verifyFlags |= vfa->flag; 00396 verifyFlags &= ~RPMVERIFY_FDIGEST; 00397 /*@innerbreak@*/ break; 00398 } 00399 if (vfa->attribute) 00400 continue; 00401 } 00402 00403 if (!strcmp(p, "not")) { 00404 negated ^= 1; 00405 } else { 00406 rpmlog(RPMLOG_ERR, _("Invalid %s token: %s\n"), name, p); 00407 fl->processingFailed = 1; 00408 return RPMRC_FAIL; 00409 } 00410 } 00411 00412 *resultVerify = negated ? ~(verifyFlags) : verifyFlags; 00413 if (negated) { 00414 /* Make sure "no digest" implies "no hmac" */ 00415 if (!(*resultVerify & RPMVERIFY_FDIGEST)) 00416 *resultVerify &= ~RPMVERIFY_HMAC; 00417 } else { 00418 /* Make sure "hmac" implies "no digest" */ 00419 if (*resultVerify & RPMVERIFY_HMAC) 00420 *resultVerify &= ~RPMVERIFY_FDIGEST; 00421 } 00422 *specdFlags |= SPECD_VERIFY; 00423 00424 return RPMRC_OK; 00425 } 00426 00427 #define isAttrDefault(_ars) ((_ars)[0] == '-' && (_ars)[1] == '\0') 00428 00435 static rpmRC parseForDev(char * buf, FileList fl) 00436 /*@modifies buf, fl->processingFailed, 00437 fl->noGlob, fl->devtype, fl->devmajor, fl->devminor @*/ 00438 { 00439 const char * name; 00440 const char * errstr = NULL; 00441 char *p, *pe, *q; 00442 rpmRC rc = RPMRC_FAIL; /* assume error */ 00443 00444 if ((p = strstr(buf, (name = "%dev"))) == NULL) 00445 return RPMRC_OK; 00446 00447 for (pe = p; (size_t)(pe-p) < strlen(name); pe++) 00448 *pe = ' '; 00449 SKIPSPACE(pe); 00450 00451 if (*pe != '(') { 00452 errstr = "'('"; 00453 goto exit; 00454 } 00455 00456 /* Bracket %dev args */ 00457 *pe++ = ' '; 00458 for (p = pe; *pe && *pe != ')'; pe++) 00459 {}; 00460 if (*pe != ')') { 00461 errstr = "')'"; 00462 goto exit; 00463 } 00464 00465 /* Localize. Erase parsed string */ 00466 q = alloca((pe-p) + 1); 00467 strncpy(q, p, pe-p); 00468 q[pe-p] = '\0'; 00469 while (p <= pe) 00470 *p++ = ' '; 00471 00472 p = q; SKIPWHITE(p); 00473 pe = p; SKIPNONWHITE(pe); if (*pe != '\0') *pe++ = '\0'; 00474 if (*p == 'b') 00475 fl->devtype = 'b'; 00476 else if (*p == 'c') 00477 fl->devtype = 'c'; 00478 else { 00479 errstr = "devtype"; 00480 goto exit; 00481 } 00482 00483 p = pe; SKIPWHITE(p); 00484 pe = p; SKIPNONWHITE(pe); if (*pe != '\0') *pe++ = '\0'; 00485 for (pe = p; *pe && xisdigit(*pe); pe++) 00486 {} ; 00487 if (*pe == '\0') { 00488 fl->devmajor = atoi(p); 00489 /*@-unsignedcompare @*/ /* LCL: ge is ok */ 00490 if (!((int)fl->devmajor >= 0 && (int)fl->devmajor < 256)) { 00491 errstr = "devmajor"; 00492 goto exit; 00493 } 00494 /*@=unsignedcompare @*/ 00495 pe++; 00496 } else { 00497 errstr = "devmajor"; 00498 goto exit; 00499 } 00500 00501 p = pe; SKIPWHITE(p); 00502 pe = p; SKIPNONWHITE(pe); if (*pe != '\0') *pe++ = '\0'; 00503 for (pe = p; *pe && xisdigit(*pe); pe++) 00504 {} ; 00505 if (*pe == '\0') { 00506 fl->devminor = atoi(p); 00507 if (!(fl->devminor >= 0 && fl->devminor < 256)) { 00508 errstr = "devminor"; 00509 goto exit; 00510 } 00511 pe++; 00512 } else { 00513 errstr = "devminor"; 00514 goto exit; 00515 } 00516 00517 fl->noGlob = 1; 00518 00519 rc = 0; 00520 00521 exit: 00522 if (rc) { 00523 rpmlog(RPMLOG_ERR, _("Missing %s in %s %s\n"), errstr, name, p); 00524 fl->processingFailed = 1; 00525 } 00526 return rc; 00527 } 00528 00535 static rpmRC parseForAttr(char * buf, FileList fl) 00536 /*@modifies buf, fl->processingFailed, 00537 fl->cur_ar, fl->def_ar, 00538 fl->currentSpecdFlags, fl->defSpecdFlags @*/ 00539 { 00540 const char *name; 00541 char *p, *pe, *q; 00542 int x; 00543 struct AttrRec_s arbuf; 00544 AttrRec ar = &arbuf, ret_ar; 00545 specdFlags * specdFlags; 00546 00547 if ((p = strstr(buf, (name = "%attr"))) != NULL) { 00548 ret_ar = &(fl->cur_ar); 00549 specdFlags = &fl->currentSpecdFlags; 00550 } else if ((p = strstr(buf, (name = "%defattr"))) != NULL) { 00551 ret_ar = &(fl->def_ar); 00552 specdFlags = &fl->defSpecdFlags; 00553 } else 00554 return RPMRC_OK; 00555 00556 for (pe = p; (size_t)(pe-p) < strlen(name); pe++) 00557 *pe = ' '; 00558 00559 SKIPSPACE(pe); 00560 00561 if (*pe != '(') { 00562 rpmlog(RPMLOG_ERR, _("Missing '(' in %s %s\n"), name, pe); 00563 fl->processingFailed = 1; 00564 return RPMRC_FAIL; 00565 } 00566 00567 /* Bracket %*attr args */ 00568 *pe++ = ' '; 00569 for (p = pe; *pe && *pe != ')'; pe++) 00570 {}; 00571 00572 if (ret_ar == &(fl->def_ar)) { /* %defattr */ 00573 q = pe; 00574 q++; 00575 SKIPSPACE(q); 00576 if (*q != '\0') { 00577 rpmlog(RPMLOG_ERR, 00578 _("Non-white space follows %s(): %s\n"), name, q); 00579 fl->processingFailed = 1; 00580 return RPMRC_FAIL; 00581 } 00582 } 00583 00584 /* Localize. Erase parsed string */ 00585 q = alloca((pe-p) + 1); 00586 strncpy(q, p, pe-p); 00587 q[pe-p] = '\0'; 00588 while (p <= pe) 00589 *p++ = ' '; 00590 00591 nullAttrRec(ar); 00592 00593 p = q; SKIPWHITE(p); 00594 if (*p != '\0') { 00595 pe = p; SKIPNONWHITE(pe); if (*pe != '\0') *pe++ = '\0'; 00596 ar->ar_fmodestr = p; 00597 p = pe; SKIPWHITE(p); 00598 } 00599 if (*p != '\0') { 00600 pe = p; SKIPNONWHITE(pe); if (*pe != '\0') *pe++ = '\0'; 00601 ar->ar_user = p; 00602 p = pe; SKIPWHITE(p); 00603 } 00604 if (*p != '\0') { 00605 pe = p; SKIPNONWHITE(pe); if (*pe != '\0') *pe++ = '\0'; 00606 ar->ar_group = p; 00607 p = pe; SKIPWHITE(p); 00608 } 00609 if (*p != '\0' && ret_ar == &(fl->def_ar)) { /* %defattr */ 00610 pe = p; SKIPNONWHITE(pe); if (*pe != '\0') *pe++ = '\0'; 00611 ar->ar_dmodestr = p; 00612 p = pe; SKIPWHITE(p); 00613 } 00614 00615 if (!(ar->ar_fmodestr && ar->ar_user && ar->ar_group) || *p != '\0') { 00616 rpmlog(RPMLOG_ERR, _("Bad syntax: %s(%s)\n"), name, q); 00617 fl->processingFailed = 1; 00618 return RPMRC_FAIL; 00619 } 00620 00621 /* Do a quick test on the mode argument and adjust for "-" */ 00622 if (ar->ar_fmodestr && !isAttrDefault(ar->ar_fmodestr)) { 00623 unsigned int ui; 00624 x = sscanf(ar->ar_fmodestr, "%o", &ui); 00625 if ((x == 0) || (ar->ar_fmode & ~MYALLPERMS)) { 00626 rpmlog(RPMLOG_ERR, _("Bad mode spec: %s(%s)\n"), name, q); 00627 fl->processingFailed = 1; 00628 return RPMRC_FAIL; 00629 } 00630 ar->ar_fmode = ui; 00631 } else 00632 ar->ar_fmodestr = NULL; 00633 00634 if (ar->ar_dmodestr && !isAttrDefault(ar->ar_dmodestr)) { 00635 unsigned int ui; 00636 x = sscanf(ar->ar_dmodestr, "%o", &ui); 00637 if ((x == 0) || (ar->ar_dmode & ~MYALLPERMS)) { 00638 rpmlog(RPMLOG_ERR, _("Bad dirmode spec: %s(%s)\n"), name, q); 00639 fl->processingFailed = 1; 00640 return RPMRC_FAIL; 00641 } 00642 ar->ar_dmode = ui; 00643 } else 00644 ar->ar_dmodestr = NULL; 00645 00646 if (!(ar->ar_user && !isAttrDefault(ar->ar_user))) 00647 ar->ar_user = NULL; 00648 00649 if (!(ar->ar_group && !isAttrDefault(ar->ar_group))) 00650 ar->ar_group = NULL; 00651 00652 dupAttrRec(ar, ret_ar); 00653 00654 /* XXX fix all this */ 00655 *specdFlags |= SPECD_UID | SPECD_GID | SPECD_FILEMODE | SPECD_DIRMODE; 00656 00657 return RPMRC_OK; 00658 } 00659 00666 static rpmRC parseForConfig(char * buf, FileList fl) 00667 /*@modifies buf, fl->processingFailed, fl->currentFlags @*/ 00668 { 00669 char *p, *pe, *q; 00670 const char *name; 00671 00672 if ((p = strstr(buf, (name = "%config"))) == NULL) 00673 return RPMRC_OK; 00674 00675 fl->currentFlags |= RPMFILE_CONFIG; 00676 00677 /* Erase "%config" token. */ 00678 for (pe = p; (size_t)(pe-p) < strlen(name); pe++) 00679 *pe = ' '; 00680 SKIPSPACE(pe); 00681 if (*pe != '(') 00682 return RPMRC_OK; 00683 00684 /* Bracket %config args */ 00685 *pe++ = ' '; 00686 for (p = pe; *pe && *pe != ')'; pe++) 00687 {}; 00688 00689 if (*pe == '\0') { 00690 rpmlog(RPMLOG_ERR, _("Missing ')' in %s(%s\n"), name, p); 00691 fl->processingFailed = 1; 00692 return RPMRC_FAIL; 00693 } 00694 00695 /* Localize. Erase parsed string. */ 00696 q = alloca((pe-p) + 1); 00697 strncpy(q, p, pe-p); 00698 q[pe-p] = '\0'; 00699 while (p <= pe) 00700 *p++ = ' '; 00701 00702 for (p = q; *p != '\0'; p = pe) { 00703 SKIPWHITE(p); 00704 if (*p == '\0') 00705 break; 00706 pe = p; 00707 SKIPNONWHITE(pe); 00708 if (*pe != '\0') 00709 *pe++ = '\0'; 00710 if (!strcmp(p, "missingok")) { 00711 fl->currentFlags |= RPMFILE_MISSINGOK; 00712 } else if (!strcmp(p, "noreplace")) { 00713 fl->currentFlags |= RPMFILE_NOREPLACE; 00714 } else { 00715 rpmlog(RPMLOG_ERR, _("Invalid %s token: %s\n"), name, p); 00716 fl->processingFailed = 1; 00717 return RPMRC_FAIL; 00718 } 00719 } 00720 00721 return RPMRC_OK; 00722 } 00723 00726 static int langCmp(const void * ap, const void * bp) 00727 /*@*/ 00728 { 00729 return strcmp(*(const char **)ap, *(const char **)bp); 00730 } 00731 00738 static rpmRC parseForLang(char * buf, FileList fl) 00739 /*@modifies buf, fl->processingFailed, 00740 fl->currentLangs, fl->nLangs @*/ 00741 { 00742 char *p, *pe, *q; 00743 const char *name; 00744 00745 while ((p = strstr(buf, (name = "%lang"))) != NULL) { 00746 00747 for (pe = p; (size_t)(pe-p) < strlen(name); pe++) 00748 *pe = ' '; 00749 SKIPSPACE(pe); 00750 00751 if (*pe != '(') { 00752 rpmlog(RPMLOG_ERR, _("Missing '(' in %s %s\n"), name, pe); 00753 fl->processingFailed = 1; 00754 return RPMRC_FAIL; 00755 } 00756 00757 /* Bracket %lang args */ 00758 *pe++ = ' '; 00759 for (pe = p; *pe && *pe != ')'; pe++) 00760 {}; 00761 00762 if (*pe == '\0') { 00763 rpmlog(RPMLOG_ERR, _("Missing ')' in %s(%s\n"), name, p); 00764 fl->processingFailed = 1; 00765 return RPMRC_FAIL; 00766 } 00767 00768 /* Localize. Erase parsed string. */ 00769 q = alloca((pe-p) + 1); 00770 strncpy(q, p, pe-p); 00771 q[pe-p] = '\0'; 00772 while (p <= pe) 00773 *p++ = ' '; 00774 00775 /* Parse multiple arguments from %lang */ 00776 for (p = q; *p != '\0'; p = pe) { 00777 char *newp; 00778 size_t np; 00779 int i; 00780 00781 SKIPWHITE(p); 00782 pe = p; 00783 SKIPNONWHITE(pe); 00784 00785 np = pe - p; 00786 00787 /* Sanity check on locale lengths */ 00788 if (np < 1 || (np == 1 && *p != 'C') || np >= 32) { 00789 rpmlog(RPMLOG_ERR, 00790 _("Unusual locale length: \"%.*s\" in %%lang(%s)\n"), 00791 (int)np, p, q); 00792 fl->processingFailed = 1; 00793 return RPMRC_FAIL; 00794 } 00795 00796 /* Check for duplicate locales */ 00797 if (fl->currentLangs != NULL) 00798 for (i = 0; i < fl->nLangs; i++) { 00799 if (strncmp(fl->currentLangs[i], p, np)) 00800 /*@innercontinue@*/ continue; 00801 rpmlog(RPMLOG_ERR, _("Duplicate locale %.*s in %%lang(%s)\n"), 00802 (int)np, p, q); 00803 fl->processingFailed = 1; 00804 return RPMRC_FAIL; 00805 } 00806 00807 /* Add new locale */ 00808 fl->currentLangs = xrealloc(fl->currentLangs, 00809 (fl->nLangs + 1) * sizeof(*fl->currentLangs)); 00810 newp = xmalloc( np+1 ); 00811 strncpy(newp, p, np); 00812 newp[np] = '\0'; 00813 fl->currentLangs[fl->nLangs++] = newp; 00814 if (*pe == ',') pe++; /* skip , if present */ 00815 } 00816 } 00817 00818 /* Insure that locales are sorted. */ 00819 if (fl->currentLangs) 00820 qsort(fl->currentLangs, fl->nLangs, sizeof(*fl->currentLangs), langCmp); 00821 00822 return RPMRC_OK; 00823 } 00824 00827 static int parseForRegexLang(const char * fileName, /*@out@*/ char ** lang) 00828 /*@globals rpmGlobalMacroContext, h_errno, internalState @*/ 00829 /*@modifies *lang, rpmGlobalMacroContext, internalState @*/ 00830 { 00831 static int initialized = 0; 00832 static int hasRegex = 0; 00833 static regex_t compiledPatt; 00834 static char buf[BUFSIZ]; 00835 int x; 00836 regmatch_t matches[2]; 00837 const char *s; 00838 00839 if (! initialized) { 00840 const char *patt = rpmExpand("%{?_langpatt}", NULL); 00841 int rc = 0; 00842 if (!(patt && *patt != '\0')) 00843 rc = 1; 00844 else if (regcomp(&compiledPatt, patt, REG_EXTENDED)) 00845 rc = -1; 00846 patt = _free(patt); 00847 if (rc) 00848 return rc; 00849 hasRegex = 1; 00850 initialized = 1; 00851 } 00852 00853 memset(matches, 0, sizeof(matches)); 00854 if (! hasRegex || regexec(&compiledPatt, fileName, 2, matches, REG_NOTEOL)) 00855 return 1; 00856 00857 /* Got match */ 00858 s = fileName + matches[1].rm_eo - 1; 00859 x = (int)matches[1].rm_eo - (int)matches[1].rm_so; 00860 buf[x] = '\0'; 00861 while (x) { 00862 buf[--x] = *s--; 00863 } 00864 if (lang) 00865 *lang = buf; 00866 return 0; 00867 } 00868 00871 /*@-exportlocal -exportheadervar@*/ 00872 /*@unchecked@*/ 00873 static VFA_t virtualFileAttributes[] = { 00874 { "%dir", 0, 0 }, /* XXX why not RPMFILE_DIR? */ 00875 { "%doc", 0, RPMFILE_DOC }, 00876 { "%ghost", 0, RPMFILE_GHOST }, 00877 { "%exclude", 0, RPMFILE_EXCLUDE }, 00878 { "%readme", 0, RPMFILE_README }, 00879 { "%license", 0, RPMFILE_LICENSE }, 00880 { "%pubkey", 0, RPMFILE_PUBKEY }, 00881 { "%policy", 0, RPMFILE_POLICY }, 00882 { "%optional", 0, RPMFILE_OPTIONAL }, 00883 { "%remove", 0, RPMFILE_REMOVE }, 00884 00885 #if WHY_NOT 00886 { "%icon", 0, RPMFILE_ICON }, 00887 { "%spec", 0, RPMFILE_SPEC }, 00888 { "%config", 0, RPMFILE_CONFIG }, 00889 { "%missingok", 0, RPMFILE_CONFIG|RPMFILE_MISSINGOK }, 00890 { "%noreplace", 0, RPMFILE_CONFIG|RPMFILE_NOREPLACE }, 00891 #endif 00892 00893 { NULL, 0, 0 } 00894 }; 00895 /*@=exportlocal =exportheadervar@*/ 00896 00906 static rpmRC parseForSimple(/*@unused@*/ Spec spec, Package pkg, 00907 char * buf, FileList fl, /*@out@*/ const char ** fileName) 00908 /*@globals rpmGlobalMacroContext, h_errno, internalState @*/ 00909 /*@modifies buf, fl->processingFailed, *fileName, 00910 fl->currentFlags, 00911 fl->docDirs, fl->docDirCount, fl->isDir, 00912 fl->passedSpecialDoc, fl->isSpecialDoc, 00913 pkg->header, pkg->specialDoc, 00914 rpmGlobalMacroContext, internalState @*/ 00915 { 00916 char *s, *t; 00917 int specialDoc = 0; 00918 char specialDocBuf[BUFSIZ]; 00919 rpmRC res = RPMRC_OK; /* assume success */ 00920 00921 specialDocBuf[0] = '\0'; 00922 *fileName = NULL; 00923 00924 t = buf; 00925 while ((s = strtokWithQuotes(t, " \t\n")) != NULL) { 00926 t = NULL; 00927 if (!strcmp(s, "%docdir")) { 00928 s = strtokWithQuotes(NULL, " \t\n"); 00929 if (fl->docDirCount == MAXDOCDIR) { 00930 rpmlog(RPMLOG_CRIT, _("Hit limit for %%docdir\n")); 00931 fl->processingFailed = 1; 00932 res = RPMRC_FAIL; 00933 } 00934 00935 if (s != NULL) 00936 fl->docDirs[fl->docDirCount++] = xstrdup(s); 00937 if (s == NULL || strtokWithQuotes(NULL, " \t\n")) { 00938 rpmlog(RPMLOG_CRIT, _("Only one arg for %%docdir\n")); 00939 fl->processingFailed = 1; 00940 res = RPMRC_FAIL; 00941 } 00942 break; 00943 } 00944 #if defined(__LCLINT__) 00945 assert(s != NULL); 00946 #endif 00947 00948 /* Set flags for virtual file attributes */ 00949 { VFA_t *vfa; 00950 for (vfa = virtualFileAttributes; vfa->attribute != NULL; vfa++) { 00951 if (strcmp(s, vfa->attribute)) 00952 /*@innercontinue@*/ continue; 00953 if (!vfa->flag) { 00954 if (!strcmp(s, "%dir")) 00955 fl->isDir = 1; /* XXX why not RPMFILE_DIR? */ 00956 } else { 00957 if (vfa->not) 00958 fl->currentFlags &= ~vfa->flag; 00959 else 00960 fl->currentFlags |= vfa->flag; 00961 } 00962 00963 /*@innerbreak@*/ break; 00964 } 00965 /* if we got an attribute, continue with next token */ 00966 if (vfa->attribute != NULL) 00967 continue; 00968 } 00969 00970 if (*fileName) { 00971 /* We already got a file -- error */ 00972 rpmlog(RPMLOG_ERR, _("Two files on one line: %s\n"), 00973 *fileName); 00974 fl->processingFailed = 1; 00975 res = RPMRC_FAIL; 00976 } 00977 00978 if (*s != '/') { 00979 if (fl->currentFlags & RPMFILE_DOC) { 00980 specialDoc = 1; 00981 strcat(specialDocBuf, " "); 00982 strcat(specialDocBuf, s); 00983 } else 00984 if (fl->currentFlags & (RPMFILE_POLICY|RPMFILE_PUBKEY|RPMFILE_ICON)) 00985 { 00986 *fileName = s; 00987 } else { 00988 const char * sfn = NULL; 00989 int urltype = urlPath(s, &sfn); 00990 switch (urltype) { 00991 default: /* relative path, not in %doc and not a URL */ 00992 rpmlog(RPMLOG_ERR, 00993 _("File must begin with \"/\": %s\n"), s); 00994 fl->processingFailed = 1; 00995 res = RPMRC_FAIL; 00996 /*@switchbreak@*/ break; 00997 case URL_IS_PATH: 00998 *fileName = s; 00999 /*@switchbreak@*/ break; 01000 } 01001 } 01002 } else { 01003 *fileName = s; 01004 } 01005 } 01006 01007 if (specialDoc) { 01008 if (*fileName || (fl->currentFlags & ~(RPMFILE_DOC))) { 01009 rpmlog(RPMLOG_ERR, 01010 _("Can't mix special %%doc with other forms: %s\n"), 01011 (*fileName ? *fileName : "")); 01012 fl->processingFailed = 1; 01013 res = RPMRC_FAIL; 01014 } else { 01015 /* XXX WATCHOUT: buf is an arg */ 01016 { 01017 /*@only@*/ 01018 static char *_docdir_fmt = NULL; /* XXX memleak */ 01019 static int oneshot = 0; 01020 const char *ddir, *fmt, *errstr; 01021 if (!oneshot) { 01022 _docdir_fmt = rpmExpand("%{?_docdir_fmt}", NULL); 01023 if (!(_docdir_fmt && *_docdir_fmt)) 01024 _docdir_fmt = _free(_docdir_fmt); 01025 oneshot = 1; 01026 } 01027 if (_docdir_fmt == NULL) 01028 _docdir_fmt = xstrdup("%{NAME}-%{VERSION}"); 01029 fmt = headerSprintf(pkg->header, _docdir_fmt, NULL, rpmHeaderFormats, &errstr); 01030 if (fmt == NULL) { 01031 rpmlog(RPMLOG_ERR, _("illegal _docdir_fmt: %s\n"), errstr); 01032 fl->processingFailed = 1; 01033 res = RPMRC_FAIL; 01034 } else { 01035 ddir = rpmGetPath("%{_docdir}/", fmt, NULL); 01036 strcpy(buf, ddir); 01037 ddir = _free(ddir); 01038 fmt = _free(fmt); 01039 } 01040 } 01041 01042 /* XXX FIXME: this is easy to do as macro expansion */ 01043 01044 if (! fl->passedSpecialDoc) { 01045 char *compress_doc; 01046 char *mkdir_p; 01047 01048 pkg->specialDoc = rpmiobNew(0); 01049 pkg->specialDoc = rpmiobAppend(pkg->specialDoc, "DOCDIR=\"$RPM_BUILD_ROOT\"", 0); 01050 pkg->specialDoc = rpmiobAppend(pkg->specialDoc, buf, 1); 01051 pkg->specialDoc = rpmiobAppend(pkg->specialDoc, "export DOCDIR", 1); 01052 mkdir_p = rpmExpand("%{?__mkdir_p}%{!?__mkdir_p:mkdir -p}", NULL); 01053 if (!mkdir_p) 01054 mkdir_p = xstrdup("mkdir -p"); 01055 pkg->specialDoc = rpmiobAppend(pkg->specialDoc, mkdir_p, 0); 01056 mkdir_p = _free(mkdir_p); 01057 pkg->specialDoc = rpmiobAppend(pkg->specialDoc, " \"$DOCDIR\"", 1); 01058 01059 compress_doc = rpmExpand("%{__compress_doc}", NULL); 01060 if (compress_doc && *compress_doc != '%') 01061 pkg->specialDoc = rpmiobAppend(pkg->specialDoc, compress_doc, 1); 01062 compress_doc = _free(compress_doc); 01063 01064 /*@-temptrans@*/ 01065 *fileName = buf; 01066 /*@=temptrans@*/ 01067 fl->passedSpecialDoc = 1; 01068 fl->isSpecialDoc = 1; 01069 } 01070 01071 pkg->specialDoc = rpmiobAppend(pkg->specialDoc, "cp -pr ", 0); 01072 pkg->specialDoc = rpmiobAppend(pkg->specialDoc, specialDocBuf, 0); 01073 pkg->specialDoc = rpmiobAppend(pkg->specialDoc, " \"$DOCDIR\"", 1); 01074 } 01075 } 01076 01077 return res; 01078 } 01079 01082 static int compareFileListRecs(const void * ap, const void * bp) /*@*/ 01083 { 01084 const char *aurl = ((FileListRec)ap)->fileURL; 01085 const char *a = NULL; 01086 const char *burl = ((FileListRec)bp)->fileURL; 01087 const char *b = NULL; 01088 (void) urlPath(aurl, &a); 01089 (void) urlPath(burl, &b); 01090 return strcmp(a, b); 01091 } 01092 01099 static int isDoc(FileList fl, const char * fileName) /*@*/ 01100 { 01101 int x = fl->docDirCount; 01102 size_t k, l; 01103 01104 k = strlen(fileName); 01105 while (x--) { 01106 l = strlen(fl->docDirs[x]); 01107 if (l < k && strncmp(fileName, fl->docDirs[x], l) == 0 && fileName[l] == '/') 01108 return 1; 01109 } 01110 return 0; 01111 } 01112 01119 static int checkHardLinks(FileList fl) 01120 /*@*/ 01121 { 01122 FileListRec ilp, jlp; 01123 int i, j; 01124 01125 for (i = 0; i < fl->fileListRecsUsed; i++) { 01126 ilp = fl->fileList + i; 01127 if (!(S_ISREG(ilp->fl_mode) && ilp->fl_nlink > 1)) 01128 continue; 01129 if (ilp->flags & (RPMFILE_EXCLUDE | RPMFILE_GHOST)) 01130 continue; 01131 01132 for (j = i + 1; j < fl->fileListRecsUsed; j++) { 01133 jlp = fl->fileList + j; 01134 if (!S_ISREG(jlp->fl_mode)) 01135 /*@innercontinue@*/ continue; 01136 if (ilp->fl_nlink != jlp->fl_nlink) 01137 /*@innercontinue@*/ continue; 01138 if (ilp->fl_ino != jlp->fl_ino) 01139 /*@innercontinue@*/ continue; 01140 if (ilp->fl_dev != jlp->fl_dev) 01141 /*@innercontinue@*/ continue; 01142 if (jlp->flags & (RPMFILE_EXCLUDE | RPMFILE_GHOST)) 01143 /*@innercontinue@*/ continue; 01144 return 1; 01145 } 01146 } 01147 return 0; 01148 } 01149 01150 static int dncmp(const void * a, const void * b) 01151 /*@*/ 01152 { 01153 const char ** aurlp = (const char **)a; 01154 const char ** burlp = (const char **)b; 01155 const char * adn; 01156 const char * bdn; 01157 (void) urlPath(*aurlp, &adn); 01158 (void) urlPath(*burlp, &bdn); 01159 return strcmp(adn, bdn); 01160 } 01161 01166 static void compressFilelist(Header h) 01167 /*@globals internalState @*/ 01168 /*@modifies h, internalState @*/ 01169 { 01170 HE_t he = memset(alloca(sizeof(*he)), 0, sizeof(*he)); 01171 const char ** fileNames; 01172 const char * fn; 01173 const char ** dirNames; 01174 const char ** baseNames; 01175 rpmuint32_t * dirIndexes; 01176 int count; 01177 int dirIndex = -1; 01178 int xx; 01179 int i; 01180 01181 /* 01182 * This assumes the file list is already sorted, and begins with a 01183 * single '/'. That assumption isn't critical, but it makes things go 01184 * a bit faster. 01185 */ 01186 01187 if (headerIsEntry(h, RPMTAG_DIRNAMES)) { 01188 he->tag = RPMTAG_OLDFILENAMES; 01189 xx = headerDel(h, he, 0); 01190 return; /* Already converted. */ 01191 } 01192 01193 he->tag = RPMTAG_OLDFILENAMES; 01194 xx = headerGet(h, he, 0); 01195 fileNames = he->p.argv; 01196 count = he->c; 01197 if (!xx || fileNames == NULL || count <= 0) 01198 return; /* no file list */ 01199 01200 dirNames = alloca(sizeof(*dirNames) * count); /* worst case */ 01201 baseNames = alloca(sizeof(*dirNames) * count); 01202 dirIndexes = alloca(sizeof(*dirIndexes) * count); 01203 01204 (void) urlPath(fileNames[0], &fn); 01205 if (fn[0] != '/') { 01206 /* HACK. Source RPM, so just do things differently */ 01207 dirIndex = 0; 01208 dirNames[dirIndex] = ""; 01209 for (i = 0; i < count; i++) { 01210 dirIndexes[i] = dirIndex; 01211 baseNames[i] = fileNames[i]; 01212 } 01213 goto exit; 01214 } 01215 01216 for (i = 0; i < count; i++) { 01217 const char ** needle; 01218 char savechar; 01219 char * baseName; 01220 size_t len; 01221 01222 if (fileNames[i] == NULL) /* XXX can't happen */ 01223 continue; 01224 baseName = strrchr(fileNames[i], '/') + 1; 01225 len = baseName - fileNames[i]; 01226 needle = dirNames; 01227 savechar = *baseName; 01228 *baseName = '\0'; 01229 /*@-compdef@*/ 01230 if (dirIndex < 0 || 01231 (needle = bsearch(&fileNames[i], dirNames, dirIndex + 1, sizeof(dirNames[0]), dncmp)) == NULL) { 01232 char *s = alloca(len + 1); 01233 memcpy(s, fileNames[i], len + 1); 01234 s[len] = '\0'; 01235 dirIndexes[i] = ++dirIndex; 01236 dirNames[dirIndex] = s; 01237 } else 01238 dirIndexes[i] = needle - dirNames; 01239 /*@=compdef@*/ 01240 01241 *baseName = savechar; 01242 baseNames[i] = baseName; 01243 } 01244 01245 exit: 01246 if (count > 0) { 01247 he->tag = RPMTAG_DIRINDEXES; 01248 he->t = RPM_UINT32_TYPE; 01249 he->p.ui32p = dirIndexes; 01250 he->c = count; 01251 xx = headerPut(h, he, 0); 01252 01253 he->tag = RPMTAG_BASENAMES; 01254 he->t = RPM_STRING_ARRAY_TYPE; 01255 he->p.argv = baseNames; 01256 he->c = count; 01257 xx = headerPut(h, he, 0); 01258 01259 he->tag = RPMTAG_DIRNAMES; 01260 he->t = RPM_STRING_ARRAY_TYPE; 01261 he->p.argv = dirNames; 01262 he->c = dirIndex + 1; 01263 xx = headerPut(h, he, 0); 01264 } 01265 01266 fileNames = _free(fileNames); 01267 01268 he->tag = RPMTAG_OLDFILENAMES; 01269 xx = headerDel(h, he, 0); 01270 } 01271 01272 static rpmuint32_t getDigestAlgo(Header h, int isSrc) 01273 /*@modifies h @*/ 01274 { 01275 HE_t he = memset(alloca(sizeof(*he)), 0, sizeof(*he)); 01276 static rpmuint32_t source_file_dalgo = 0; 01277 static rpmuint32_t binary_file_dalgo = 0; 01278 static int oneshot = 0; 01279 rpmuint32_t dalgo = 0; 01280 int xx; 01281 01282 if (!oneshot) { 01283 source_file_dalgo = 01284 rpmExpandNumeric("%{?_build_source_file_digest_algo}"); 01285 binary_file_dalgo = 01286 rpmExpandNumeric("%{?_build_binary_file_digest_algo}"); 01287 oneshot++; 01288 } 01289 01290 dalgo = (isSrc ? source_file_dalgo : binary_file_dalgo); 01291 switch (dalgo) { 01292 case PGPHASHALGO_SHA1: 01293 case PGPHASHALGO_MD2: 01294 case PGPHASHALGO_SHA256: 01295 case PGPHASHALGO_SHA384: 01296 case PGPHASHALGO_SHA512: 01297 (void) rpmlibNeedsFeature(h, "FileDigests", "4.6.0-1"); 01298 he->tag = RPMTAG_FILEDIGESTALGO; 01299 he->t = RPM_UINT32_TYPE; 01300 he->p.ui32p = &dalgo; 01301 he->c = 1; 01302 xx = headerPut(h, he, 0); 01303 /*@fallthgrough@*/ 01304 case PGPHASHALGO_RIPEMD160: 01305 case PGPHASHALGO_TIGER192: 01306 case PGPHASHALGO_MD4: 01307 case PGPHASHALGO_RIPEMD128: 01308 case PGPHASHALGO_CRC32: 01309 case PGPHASHALGO_ADLER32: 01310 case PGPHASHALGO_CRC64: 01311 (void) rpmlibNeedsFeature(h, "FileDigestParameterized", "4.4.6-1"); 01312 /*@switchbreak@*/ break; 01313 case PGPHASHALGO_MD5: 01314 case PGPHASHALGO_HAVAL_5_160: /* XXX unimplemented */ 01315 default: 01316 dalgo = PGPHASHALGO_MD5; 01317 /*@switchbreak@*/ break; 01318 } 01319 01320 return dalgo; 01321 } 01322 01332 static void genCpioListAndHeader(/*@partial@*/ FileList fl, 01333 rpmfi * fip, Header h, int isSrc) 01334 /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/ 01335 /*@modifies h, *fip, fl->processingFailed, fl->fileList, 01336 fl->totalFileSize, 01337 rpmGlobalMacroContext, fileSystem, internalState @*/ 01338 { 01339 HE_t he = memset(alloca(sizeof(*he)), 0, sizeof(*he)); 01340 const char * apath; 01341 rpmuint16_t ui16; 01342 rpmuint32_t ui32; 01343 int _addDotSlash = !isSrc; 01344 int apathlen = 0; 01345 int dpathlen = 0; 01346 int skipLen = 0; 01347 rpmsx sx = rpmsxNew("%{?_build_file_context_path}", 0); 01348 FileListRec flp; 01349 rpmuint32_t dalgo = getDigestAlgo(h, isSrc); 01350 char buf[BUFSIZ]; 01351 int i, xx; 01352 01353 memset(buf, 0, sizeof(buf)); /* XXX valgrind on rhel6 beta pickier */ 01354 01355 /* Sort the big list */ 01356 if (fl->fileListRecsUsed > 1) 01357 qsort(fl->fileList, fl->fileListRecsUsed, 01358 sizeof(*(fl->fileList)), compareFileListRecs); 01359 01360 /* Generate the header. */ 01361 if (! isSrc) { 01362 skipLen = 1; 01363 if (fl->prefix) 01364 skipLen += strlen(fl->prefix); 01365 } 01366 01367 for (i = 0, flp = fl->fileList; i < fl->fileListRecsUsed; i++, flp++) { 01368 const char *s; 01369 01370 /* Merge duplicate entries. */ 01371 while (i < (fl->fileListRecsUsed - 1) && 01372 !strcmp(flp->fileURL, flp[1].fileURL)) { 01373 01374 /* Two entries for the same file found, merge the entries. */ 01375 /* Note that an %exclude is a duplication of a file reference */ 01376 01377 /* file flags */ 01378 flp[1].flags |= flp->flags; 01379 01380 if (!(flp[1].flags & RPMFILE_EXCLUDE)) 01381 rpmlog(RPMLOG_WARNING, _("File listed twice: %s\n"), 01382 flp->fileURL); 01383 01384 /* file mode */ 01385 if (S_ISDIR(flp->fl_mode)) { 01386 if ((flp[1].specdFlags & (SPECD_DIRMODE | SPECD_DEFDIRMODE)) < 01387 (flp->specdFlags & (SPECD_DIRMODE | SPECD_DEFDIRMODE))) 01388 flp[1].fl_mode = flp->fl_mode; 01389 } else { 01390 if ((flp[1].specdFlags & (SPECD_FILEMODE | SPECD_DEFFILEMODE)) < 01391 (flp->specdFlags & (SPECD_FILEMODE | SPECD_DEFFILEMODE))) 01392 flp[1].fl_mode = flp->fl_mode; 01393 } 01394 01395 /* uid */ 01396 if ((flp[1].specdFlags & (SPECD_UID | SPECD_DEFUID)) < 01397 (flp->specdFlags & (SPECD_UID | SPECD_DEFUID))) 01398 { 01399 flp[1].fl_uid = flp->fl_uid; 01400 flp[1].uname = flp->uname; 01401 } 01402 01403 /* gid */ 01404 if ((flp[1].specdFlags & (SPECD_GID | SPECD_DEFGID)) < 01405 (flp->specdFlags & (SPECD_GID | SPECD_DEFGID))) 01406 { 01407 flp[1].fl_gid = flp->fl_gid; 01408 flp[1].gname = flp->gname; 01409 } 01410 01411 /* verify flags */ 01412 if ((flp[1].specdFlags & (SPECD_VERIFY | SPECD_DEFVERIFY)) < 01413 (flp->specdFlags & (SPECD_VERIFY | SPECD_DEFVERIFY))) 01414 flp[1].verifyFlags = flp->verifyFlags; 01415 01416 /* XXX to-do: language */ 01417 01418 flp++; i++; 01419 } 01420 01421 /* Skip files that were marked with %exclude. */ 01422 if (flp->flags & RPMFILE_EXCLUDE) continue; 01423 01424 /* Omit '/' and/or URL prefix, leave room for "./" prefix */ 01425 (void) urlPath(flp->fileURL, &apath); 01426 apathlen += (strlen(apath) - skipLen + (_addDotSlash ? 3 : 1)); 01427 01428 /* Leave room for both dirname and basename NUL's */ 01429 dpathlen += (strlen(flp->diskURL) + 2); 01430 01431 /* 01432 * Make the header, the OLDFILENAMES will get converted to a 01433 * compressed file list write before we write the actual package to 01434 * disk. 01435 */ 01436 he->tag = RPMTAG_OLDFILENAMES; 01437 he->t = RPM_STRING_ARRAY_TYPE; 01438 he->p.argv = &flp->fileURL; 01439 he->c = 1; 01440 he->append = 1; 01441 xx = headerPut(h, he, 0); 01442 he->append = 0; 01443 01444 /*@-sizeoftype@*/ 01445 ui32 = (rpmuint32_t) flp->fl_size; 01446 he->tag = RPMTAG_FILESIZES; 01447 he->t = RPM_UINT32_TYPE; 01448 he->p.ui32p = &ui32; 01449 he->c = 1; 01450 he->append = 1; 01451 xx = headerPut(h, he, 0); 01452 he->append = 0; 01453 01454 he->tag = RPMTAG_FILEUSERNAME; 01455 he->t = RPM_STRING_ARRAY_TYPE; 01456 he->p.argv = &flp->uname; 01457 he->c = 1; 01458 he->append = 1; 01459 xx = headerPut(h, he, 0); 01460 he->append = 0; 01461 01462 he->tag = RPMTAG_FILEGROUPNAME; 01463 he->t = RPM_STRING_ARRAY_TYPE; 01464 he->p.argv = &flp->gname; 01465 he->c = 1; 01466 he->append = 1; 01467 xx = headerPut(h, he, 0); 01468 he->append = 0; 01469 01470 ui32 = (rpmuint32_t) flp->fl_mtime; 01471 he->tag = RPMTAG_FILEMTIMES; 01472 he->t = RPM_UINT32_TYPE; 01473 he->p.ui32p = &ui32; 01474 he->c = 1; 01475 he->append = 1; 01476 xx = headerPut(h, he, 0); 01477 he->append = 0; 01478 01479 ui16 = (rpmuint16_t)flp->fl_mode; 01480 he->tag = RPMTAG_FILEMODES; 01481 he->t = RPM_UINT16_TYPE; 01482 he->p.ui16p = &ui16; 01483 he->c = 1; 01484 he->append = 1; 01485 xx = headerPut(h, he, 0); 01486 he->append = 0; 01487 01488 ui16 = (rpmuint16_t) flp->fl_rdev; 01489 he->tag = RPMTAG_FILERDEVS; 01490 he->t = RPM_UINT16_TYPE; 01491 he->p.ui16p = &ui16; 01492 he->c = 1; 01493 he->append = 1; 01494 xx = headerPut(h, he, 0); 01495 he->append = 0; 01496 01497 ui32 = (rpmuint32_t) flp->fl_dev; 01498 he->tag = RPMTAG_FILEDEVICES; 01499 he->t = RPM_UINT32_TYPE; 01500 he->p.ui32p = &ui32; 01501 he->c = 1; 01502 he->append = 1; 01503 xx = headerPut(h, he, 0); 01504 he->append = 0; 01505 01506 ui32 = (rpmuint32_t) flp->fl_ino; 01507 he->tag = RPMTAG_FILEINODES; 01508 he->t = RPM_UINT32_TYPE; 01509 he->p.ui32p = &ui32; 01510 he->c = 1; 01511 he->append = 1; 01512 xx = headerPut(h, he, 0); 01513 he->append = 0; 01514 01515 /*@=sizeoftype@*/ 01516 01517 he->tag = RPMTAG_FILELANGS; 01518 he->t = RPM_STRING_ARRAY_TYPE; 01519 he->p.argv = &flp->langs; 01520 he->c = 1; 01521 he->append = 1; 01522 xx = headerPut(h, he, 0); 01523 he->append = 0; 01524 01525 buf[0] = '\0'; 01526 if (S_ISREG(flp->fl_mode)) { 01527 unsigned dflags = 0x01; /* asAscii */ 01528 #define _mask (RPMVERIFY_FDIGEST|RPMVERIFY_HMAC) 01529 if ((flp->verifyFlags & _mask) == RPMVERIFY_HMAC) 01530 dflags |= 0x02; /* doHmac */ 01531 #undef _mask 01532 (void) dodigest(dalgo, flp->diskURL, (unsigned char *)buf, 01533 dflags, NULL); 01534 } 01535 s = buf; 01536 01537 he->tag = RPMTAG_FILEDIGESTS; 01538 he->t = RPM_STRING_ARRAY_TYPE; 01539 he->p.argv = &s; 01540 he->c = 1; 01541 he->append = 1; 01542 xx = headerPut(h, he, 0); 01543 he->append = 0; 01544 01545 if (!(_rpmbuildFlags & 4)) { 01546 ui32 = dalgo; 01547 he->tag = RPMTAG_FILEDIGESTALGOS; 01548 he->t = RPM_UINT32_TYPE; 01549 he->p.ui32p = &ui32; 01550 he->c = 1; 01551 he->append = 1; 01552 xx = headerPut(h, he, 0); 01553 he->append = 0; 01554 } 01555 01556 buf[0] = '\0'; 01557 if (S_ISLNK(flp->fl_mode)) { 01558 xx = Readlink(flp->diskURL, buf, BUFSIZ); 01559 if (xx >= 0) 01560 buf[xx] = '\0'; 01561 if (fl->buildRootURL) { 01562 const char * buildRoot; 01563 (void) urlPath(fl->buildRootURL, &buildRoot); 01564 01565 if (buf[0] == '/' && strcmp(buildRoot, "/") && 01566 !strncmp(buf, buildRoot, strlen(buildRoot))) { 01567 rpmlog(RPMLOG_ERR, 01568 _("Symlink points to BuildRoot: %s -> %s\n"), 01569 flp->fileURL, buf); 01570 fl->processingFailed = 1; 01571 } 01572 } 01573 } 01574 s = buf; 01575 he->tag = RPMTAG_FILELINKTOS; 01576 he->t = RPM_STRING_ARRAY_TYPE; 01577 he->p.argv = &s; 01578 he->c = 1; 01579 he->append = 1; 01580 xx = headerPut(h, he, 0); 01581 he->append = 0; 01582 01583 if (flp->flags & RPMFILE_GHOST) { 01584 flp->verifyFlags &= ~(RPMVERIFY_FDIGEST | RPMVERIFY_FILESIZE | 01585 RPMVERIFY_LINKTO | RPMVERIFY_MTIME); 01586 } 01587 ui32 = flp->verifyFlags; 01588 he->tag = RPMTAG_FILEVERIFYFLAGS; 01589 he->t = RPM_UINT32_TYPE; 01590 he->p.ui32p = &ui32; 01591 he->c = 1; 01592 he->append = 1; 01593 xx = headerPut(h, he, 0); 01594 he->append = 0; 01595 01596 if (!isSrc && isDoc(fl, flp->fileURL)) 01597 flp->flags |= RPMFILE_DOC; 01598 /* XXX Should directories have %doc/%config attributes? (#14531) */ 01599 if (S_ISDIR(flp->fl_mode)) 01600 flp->flags &= ~(RPMFILE_CONFIG|RPMFILE_DOC); 01601 01602 ui32 = flp->flags; 01603 he->tag = RPMTAG_FILEFLAGS; 01604 he->t = RPM_UINT32_TYPE; 01605 he->p.ui32p = &ui32; 01606 he->c = 1; 01607 he->append = 1; 01608 xx = headerPut(h, he, 0); 01609 he->append = 0; 01610 01611 /* Add file security context to package. */ 01612 if (sx && sx->fn && *sx->fn && !(_rpmbuildFlags & 4)) { 01613 const char * scon = rpmsxMatch(sx, flp->fileURL, flp->fl_mode); 01614 if (scon) { 01615 he->tag = RPMTAG_FILECONTEXTS; 01616 he->t = RPM_STRING_ARRAY_TYPE; 01617 he->p.argv = &scon; 01618 he->c = 1; 01619 he->append = 1; 01620 xx = headerPut(h, he, 0); 01621 he->append = 0; 01622 } 01623 scon = _free(scon); /* XXX freecon(scon) instead()? */ 01624 } 01625 } 01626 01627 sx = rpmsxFree(sx); 01628 01629 if (_rpmbuildFlags & 4) { 01630 (void) rpmlibNeedsFeature(h, "PayloadFilesHavePrefix", "4.0-1"); 01631 (void) rpmlibNeedsFeature(h, "CompressedFileNames", "3.0.4-1"); 01632 } 01633 01634 compressFilelist(h); 01635 01636 { static int scareMem = 0; 01637 void * ts = NULL; /* XXX FIXME drill rpmts ts all the way down here */ 01638 rpmfi fi = rpmfiNew(ts, h, RPMTAG_BASENAMES, scareMem); 01639 char * a, * d; 01640 01641 if (fi == NULL) return; /* XXX can't happen */ 01642 01643 /*@-onlytrans@*/ 01644 fi->te = xcalloc(1, sizeof(*((rpmte)fi->te))); 01645 /*@=onlytrans@*/ 01646 ((rpmte)fi->te)->type = TR_ADDED; 01647 01648 fi->dnl = _free(fi->dnl); 01649 fi->bnl = _free(fi->bnl); 01650 if (!scareMem) fi->dil = _free(fi->dil); 01651 01652 /* XXX Insure at least 1 byte is always allocated. */ 01653 fi->dnl = xmalloc(fi->fc * sizeof(*fi->dnl) + dpathlen + 1); 01654 d = (char *)(fi->dnl + fi->fc); 01655 *d = '\0'; 01656 01657 fi->bnl = xmalloc(fi->fc * (sizeof(*fi->bnl) + sizeof(*fi->dil))); 01658 /*@-dependenttrans@*/ /* FIX: artifact of spoofing header tag store */ 01659 fi->dil = (!scareMem) 01660 ? xcalloc(sizeof(*fi->dil), fi->fc) 01661 : (rpmuint32_t *)(fi->bnl + fi->fc); 01662 /*@=dependenttrans@*/ 01663 01664 /* XXX Insure at least 1 byte is always allocated. */ 01665 fi->apath = xmalloc(fi->fc * sizeof(*fi->apath) + apathlen + 1); 01666 a = (char *)(fi->apath + fi->fc); 01667 *a = '\0'; 01668 01669 fi->actions = _free(fi->actions); /* XXX memory leak */ 01670 fi->actions = xcalloc(sizeof(*fi->actions), fi->fc); 01671 fi->fmapflags = xcalloc(sizeof(*fi->fmapflags), fi->fc); 01672 fi->astriplen = 0; 01673 if (fl->buildRootURL) 01674 fi->astriplen = strlen(fl->buildRootURL); 01675 fi->striplen = 0; 01676 fi->fuser = _free(fi->fuser); 01677 fi->fgroup = _free(fi->fgroup); 01678 01679 /* Make the cpio list */ 01680 if (fi->dil != NULL) /* XXX can't happen */ 01681 for (i = 0, flp = fl->fileList; (unsigned)i < fi->fc; i++, flp++) { 01682 char * b; 01683 01684 /* Skip (possible) duplicate file entries, use last entry info. */ 01685 while (((flp - fl->fileList) < (fl->fileListRecsUsed - 1)) && 01686 !strcmp(flp->fileURL, flp[1].fileURL)) 01687 flp++; 01688 01689 if (flp->flags & RPMFILE_EXCLUDE) { 01690 i--; 01691 continue; 01692 } 01693 01694 { 01695 /* this fi uses diskURL (with buildroot), not fileURL */ 01696 size_t fnlen = strlen(flp->diskURL); 01697 if (fnlen > fi->fnlen) { 01698 /* fnlen-sized buffer must not be allocated yet */ 01699 assert(fi->fn == NULL); 01700 fi->fnlen = fnlen; 01701 } 01702 } 01703 01704 /* Create disk directory and base name. */ 01705 fi->dil[i] = i; 01706 /*@-dependenttrans@*/ /* FIX: artifact of spoofing header tag store */ 01707 fi->dnl[fi->dil[i]] = d; 01708 /*@=dependenttrans@*/ 01709 d = stpcpy(d, flp->diskURL); 01710 01711 /* Make room for the dirName NUL, find start of baseName. */ 01712 for (b = d; b > fi->dnl[fi->dil[i]] && *b != '/'; b--) 01713 b[1] = b[0]; 01714 b++; /* dirname's end in '/' */ 01715 *b++ = '\0'; /* terminate dirname, b points to basename */ 01716 fi->bnl[i] = b; 01717 d += 2; /* skip both dirname and basename NUL's */ 01718 01719 /* Create archive path, normally adding "./" */ 01720 /*@-dependenttrans@*/ /* FIX: xstrdup? nah ... */ 01721 fi->apath[i] = a; 01722 /*@=dependenttrans@*/ 01723 if (_addDotSlash) 01724 a = stpcpy(a, "./"); 01725 (void) urlPath(flp->fileURL, &apath); 01726 a = stpcpy(a, (apath + skipLen)); 01727 a++; /* skip apath NUL */ 01728 01729 if (flp->flags & RPMFILE_GHOST) { 01730 fi->actions[i] = FA_SKIP; 01731 continue; 01732 } 01733 fi->actions[i] = FA_COPYOUT; 01734 fi->fmapflags[i] = IOSM_MAP_PATH | 01735 IOSM_MAP_TYPE | IOSM_MAP_MODE | IOSM_MAP_UID | IOSM_MAP_GID; 01736 if (isSrc) 01737 fi->fmapflags[i] |= IOSM_FOLLOW_SYMLINKS; 01738 01739 if (S_ISREG(flp->fl_mode)) { 01740 int bingo = 1; 01741 /* Hard links need be tallied only once. */ 01742 if (flp->fl_nlink > 1) { 01743 FileListRec jlp = flp + 1; 01744 int j = i + 1; 01745 for (; (unsigned)j < fi->fc; j++, jlp++) { 01746 /* follow outer loop logic */ 01747 while (((jlp - fl->fileList) < (fl->fileListRecsUsed - 1)) && 01748 !strcmp(jlp->fileURL, jlp[1].fileURL)) 01749 jlp++; 01750 if (jlp->flags & RPMFILE_EXCLUDE) { 01751 j--; 01752 /*@innercontinue@*/ continue; 01753 } 01754 if (jlp->flags & RPMFILE_GHOST) 01755 /*@innercontinue@*/ continue; 01756 if (!S_ISREG(jlp->fl_mode)) 01757 /*@innercontinue@*/ continue; 01758 if (flp->fl_nlink != jlp->fl_nlink) 01759 /*@innercontinue@*/ continue; 01760 if (flp->fl_ino != jlp->fl_ino) 01761 /*@innercontinue@*/ continue; 01762 if (flp->fl_dev != jlp->fl_dev) 01763 /*@innercontinue@*/ continue; 01764 bingo = 0; /* don't tally hardlink yet. */ 01765 /*@innerbreak@*/ break; 01766 } 01767 } 01768 if (bingo) 01769 fl->totalFileSize += flp->fl_size; 01770 } 01771 } 01772 01773 ui32 = fl->totalFileSize; 01774 he->tag = RPMTAG_SIZE; 01775 he->t = RPM_UINT32_TYPE; 01776 he->p.ui32p = &ui32; 01777 he->c = 1; 01778 xx = headerPut(h, he, 0); 01779 01780 /*@-compdef@*/ 01781 if (fip) 01782 *fip = fi; 01783 else 01784 fi = rpmfiFree(fi); 01785 /*@=compdef@*/ 01786 } 01787 } 01788 01791 static /*@null@*/ FileListRec freeFileList(/*@only@*/ FileListRec fileList, 01792 int count) 01793 /*@*/ 01794 { 01795 while (count--) { 01796 fileList[count].diskURL = _free(fileList[count].diskURL); 01797 fileList[count].fileURL = _free(fileList[count].fileURL); 01798 fileList[count].langs = _free(fileList[count].langs); 01799 } 01800 fileList = _free(fileList); 01801 return NULL; 01802 } 01803 01804 /* forward ref */ 01805 static rpmRC recurseDir(FileList fl, const char * diskURL) 01806 /*@globals rpmGlobalMacroContext, h_errno, 01807 fileSystem, internalState @*/ 01808 /*@modifies *fl, fl->processingFailed, 01809 fl->fileList, fl->fileListRecsAlloced, fl->fileListRecsUsed, 01810 fl->totalFileSize, fl->fileCount, fl->inFtw, fl->isDir, 01811 rpmGlobalMacroContext, 01812 fileSystem, internalState @*/; 01813 01821 static int addFile(FileList fl, const char * diskURL, 01822 /*@null@*/ struct stat * statp) 01823 /*@globals rpmGlobalMacroContext, h_errno, 01824 fileSystem, internalState @*/ 01825 /*@modifies *statp, *fl, fl->processingFailed, 01826 fl->fileList, fl->fileListRecsAlloced, fl->fileListRecsUsed, 01827 fl->totalFileSize, fl->fileCount, 01828 rpmGlobalMacroContext, 01829 fileSystem, internalState @*/ 01830 { 01831 const char *fn = xstrdup(diskURL); 01832 const char *fileURL = fn; 01833 struct stat statbuf; 01834 mode_t fileMode; 01835 uid_t fileUid; 01836 gid_t fileGid; 01837 const char *fileUname; 01838 const char *fileGname; 01839 char *lang; 01840 rpmRC rc = RPMRC_OK; 01841 01842 /* Path may have prepended buildRootURL, so locate the original filename. */ 01843 /* 01844 * XXX There are 3 types of entry into addFile: 01845 * 01846 * From diskUrl statp 01847 * ===================================================== 01848 * processBinaryFile path NULL 01849 * processBinaryFile glob result path NULL 01850 * recurseDir path stat 01851 * 01852 */ 01853 { const char *fileName; 01854 int urltype = urlPath(fileURL, &fileName); 01855 switch (urltype) { 01856 case URL_IS_PATH: 01857 fileURL += (fileName - fileURL); 01858 if (fl->buildRootURL && strcmp(fl->buildRootURL, "/")) { 01859 size_t nb = strlen(fl->buildRootURL); 01860 const char * s = fileURL + nb; 01861 char * t = (char *) fileURL; 01862 (void) memmove(t, s, nb); 01863 } 01864 fileURL = fn; 01865 break; 01866 default: 01867 if (fl->buildRootURL && strcmp(fl->buildRootURL, "/")) 01868 fileURL += strlen(fl->buildRootURL); 01869 break; 01870 } 01871 } 01872 01873 /* XXX make sure '/' can be packaged also */ 01874 if (*fileURL == '\0') 01875 fileURL = "/"; 01876 01877 /* If we are using a prefix, validate the file */ 01878 if (!fl->inFtw && fl->prefix) { 01879 const char *prefixTest; 01880 const char *prefixPtr = fl->prefix; 01881 01882 (void) urlPath(fileURL, &prefixTest); 01883 while (*prefixPtr && *prefixTest && (*prefixTest == *prefixPtr)) { 01884 prefixPtr++; 01885 prefixTest++; 01886 } 01887 if (*prefixPtr || (*prefixTest && *prefixTest != '/')) { 01888 rpmlog(RPMLOG_ERR, _("File doesn't match prefix (%s): %s\n"), 01889 fl->prefix, fileURL); 01890 fl->processingFailed = 1; 01891 rc = RPMRC_FAIL; 01892 goto exit; 01893 } 01894 } 01895 01896 if (statp == NULL) { 01897 statp = &statbuf; 01898 memset(statp, 0, sizeof(*statp)); 01899 if (fl->devtype) { 01900 time_t now = time(NULL); 01901 01902 /* XXX hack up a stat structure for a %dev(...) directive. */ 01903 statp->st_nlink = 1; 01904 statp->st_rdev = 01905 ((fl->devmajor & 0xff) << 8) | (fl->devminor & 0xff); 01906 statp->st_dev = statp->st_rdev; 01907 statp->st_mode = (fl->devtype == 'b' ? S_IFBLK : S_IFCHR); 01908 statp->st_mode |= (fl->cur_ar.ar_fmode & 0777); 01909 statp->st_atime = now; 01910 statp->st_mtime = now; 01911 statp->st_ctime = now; 01912 } else if (Lstat(diskURL, statp)) { 01913 if (fl->currentFlags & RPMFILE_OPTIONAL) { 01914 rpmlog(RPMLOG_WARNING, _("Optional file not found: %s\n"), diskURL); 01915 rc = RPMRC_OK; 01916 } else { 01917 rpmlog(RPMLOG_ERR, _("File not found: %s\n"), diskURL); 01918 fl->processingFailed = 1; 01919 rc = RPMRC_FAIL; 01920 } 01921 goto exit; 01922 } 01923 } 01924 01925 if ((! fl->isDir) && S_ISDIR(statp->st_mode)) { 01926 /*@-nullstate@*/ /* FIX: fl->buildRootURL may be NULL */ 01927 rc = recurseDir(fl, diskURL); 01928 goto exit; 01929 /*@=nullstate@*/ 01930 } 01931 01932 fileMode = statp->st_mode; 01933 fileUid = statp->st_uid; 01934 fileGid = statp->st_gid; 01935 01936 if (S_ISDIR(fileMode) && fl->cur_ar.ar_dmodestr) { 01937 fileMode &= S_IFMT; 01938 fileMode |= fl->cur_ar.ar_dmode; 01939 } else if (fl->cur_ar.ar_fmodestr != NULL) { 01940 fileMode &= S_IFMT; 01941 fileMode |= fl->cur_ar.ar_fmode; 01942 } 01943 if (fl->cur_ar.ar_user) { 01944 fileUname = getUnameS(fl->cur_ar.ar_user); 01945 } else { 01946 fileUname = getUname(fileUid); 01947 } 01948 if (fl->cur_ar.ar_group) { 01949 fileGname = getGnameS(fl->cur_ar.ar_group); 01950 } else { 01951 fileGname = getGname(fileGid); 01952 } 01953 01954 /* Default user/group to builder's user/group */ 01955 if (fileUname == NULL) 01956 fileUname = getUname(getuid()); 01957 if (fileGname == NULL) 01958 fileGname = getGname(getgid()); 01959 01960 /* Add to the file list */ 01961 if (fl->fileListRecsUsed == fl->fileListRecsAlloced) { 01962 fl->fileListRecsAlloced += 128; 01963 fl->fileList = xrealloc(fl->fileList, 01964 fl->fileListRecsAlloced * sizeof(*(fl->fileList))); 01965 } 01966 01967 { FileListRec flp = &fl->fileList[fl->fileListRecsUsed]; 01968 int i; 01969 01970 flp->fl_st = *statp; /* structure assignment */ 01971 flp->fl_mode = fileMode; 01972 flp->fl_uid = fileUid; 01973 flp->fl_gid = fileGid; 01974 01975 flp->fileURL = xstrdup(fileURL); 01976 flp->diskURL = xstrdup(diskURL); 01977 flp->uname = fileUname; 01978 flp->gname = fileGname; 01979 01980 if (fl->currentLangs && fl->nLangs > 0) { 01981 char * ncl; 01982 size_t nl = 0; 01983 01984 for (i = 0; i < fl->nLangs; i++) 01985 nl += strlen(fl->currentLangs[i]) + 1; 01986 01987 flp->langs = ncl = xmalloc(nl); 01988 for (i = 0; i < fl->nLangs; i++) { 01989 const char *ocl; 01990 if (i) *ncl++ = '|'; 01991 for (ocl = fl->currentLangs[i]; *ocl != '\0'; ocl++) 01992 *ncl++ = *ocl; 01993 *ncl = '\0'; 01994 } 01995 } else if (! parseForRegexLang(fileURL, &lang)) { 01996 flp->langs = xstrdup(lang); 01997 } else { 01998 flp->langs = xstrdup(""); 01999 } 02000 02001 flp->flags = fl->currentFlags; 02002 flp->specdFlags = fl->currentSpecdFlags; 02003 flp->verifyFlags = fl->currentVerifyFlags; 02004 } 02005 02006 fl->fileListRecsUsed++; 02007 fl->fileCount++; 02008 02009 exit: 02010 /*@i@*/ fn = _free(fn); 02011 return rc; 02012 } 02013 02020 static rpmRC recurseDir(FileList fl, const char * diskURL) 02021 { 02022 char * ftsSet[2]; 02023 FTS * ftsp; 02024 FTSENT * fts; 02025 int myFtsOpts = (FTS_COMFOLLOW | FTS_NOCHDIR | FTS_PHYSICAL); 02026 rpmRC rc = RPMRC_FAIL; 02027 02028 fl->inFtw = 1; /* Flag to indicate file has buildRootURL prefixed */ 02029 fl->isDir = 1; /* Keep it from following myftw() again */ 02030 02031 ftsSet[0] = (char *) diskURL; 02032 ftsSet[1] = NULL; 02033 ftsp = Fts_open(ftsSet, myFtsOpts, NULL); 02034 while ((fts = Fts_read(ftsp)) != NULL) { 02035 switch (fts->fts_info) { 02036 case FTS_D: /* preorder directory */ 02037 case FTS_F: /* regular file */ 02038 case FTS_SL: /* symbolic link */ 02039 case FTS_SLNONE: /* symbolic link without target */ 02040 case FTS_DEFAULT: /* none of the above */ 02041 rc = addFile(fl, fts->fts_accpath, fts->fts_statp); 02042 /*@switchbreak@*/ break; 02043 case FTS_DOT: /* dot or dot-dot */ 02044 case FTS_DP: /* postorder directory */ 02045 rc = RPMRC_OK; 02046 /*@switchbreak@*/ break; 02047 case FTS_NS: /* stat(2) failed */ 02048 case FTS_DNR: /* unreadable directory */ 02049 case FTS_ERR: /* error; errno is set */ 02050 case FTS_DC: /* directory that causes cycles */ 02051 case FTS_NSOK: /* no stat(2) requested */ 02052 case FTS_INIT: /* initialized only */ 02053 case FTS_W: /* whiteout object */ 02054 default: 02055 rc = RPMRC_FAIL; 02056 /*@switchbreak@*/ break; 02057 } 02058 if (rc != RPMRC_OK) 02059 break; 02060 } 02061 (void) Fts_close(ftsp); 02062 02063 fl->isDir = 0; 02064 fl->inFtw = 0; 02065 02066 return rc; 02067 } 02068 02077 static rpmRC processMetadataFile(Package pkg, FileList fl, const char * fileURL, 02078 rpmTag tag) 02079 /*@globals rpmGlobalMacroContext, h_errno, 02080 fileSystem, internalState @*/ 02081 /*@modifies pkg->header, *fl, fl->processingFailed, 02082 fl->fileList, fl->fileListRecsAlloced, fl->fileListRecsUsed, 02083 fl->totalFileSize, fl->fileCount, 02084 rpmGlobalMacroContext, 02085 fileSystem, internalState @*/ 02086 { 02087 HE_t he = memset(alloca(sizeof(*he)), 0, sizeof(*he)); 02088 const char * buildURL = "%{_builddir}/%{?buildsubdir}/"; 02089 const char * fn = NULL; 02090 const char * apkt = NULL; 02091 rpmiob iob = NULL; 02092 rpmuint8_t * pkt = NULL; 02093 ssize_t pktlen = 0; 02094 int absolute = 0; 02095 rpmRC rc = RPMRC_FAIL; 02096 int xx; 02097 02098 (void) urlPath(fileURL, &fn); 02099 if (*fn == '/') { 02100 fn = rpmGenPath(fl->buildRootURL, NULL, fn); 02101 absolute = 1; 02102 } else 02103 fn = rpmGenPath(buildURL, NULL, fn); 02104 02105 switch (tag) { 02106 default: 02107 rpmlog(RPMLOG_ERR, _("%s: can't load unknown tag (%d).\n"), 02108 fn, tag); 02109 goto exit; 02110 /*@notreached@*/ break; 02111 case RPMTAG_PUBKEYS: 02112 if ((xx = pgpReadPkts(fn, &pkt, (size_t *)&pktlen)) <= 0) { 02113 rpmlog(RPMLOG_ERR, _("%s: public key read failed.\n"), fn); 02114 goto exit; 02115 } 02116 if (xx != PGPARMOR_PUBKEY) { 02117 rpmlog(RPMLOG_ERR, _("%s: not an armored public key.\n"), fn); 02118 goto exit; 02119 } 02120 apkt = pgpArmorWrap(PGPARMOR_PUBKEY, pkt, pktlen); 02121 break; 02122 case RPMTAG_POLICIES: 02123 xx = rpmiobSlurp(fn, &iob); 02124 if (!(xx == 0 && iob != NULL)) { 02125 rpmlog(RPMLOG_ERR, _("%s: *.te policy read failed.\n"), fn); 02126 goto exit; 02127 } 02128 apkt = (const char *) iob->b; /* XXX unsigned char */ 02129 /* XXX steal the I/O buffer */ 02130 iob->b = (rpmuint8_t *)xcalloc(1, sizeof(*iob->b)); 02131 iob->blen = 0; 02132 break; 02133 } 02134 02135 he->tag = tag; 02136 he->t = RPM_STRING_ARRAY_TYPE; 02137 he->p.argv = &apkt; 02138 he->c = 1; 02139 he->append = 1; 02140 xx = headerPut(pkg->header, he, 0); 02141 he->append = 0; 02142 02143 rc = RPMRC_OK; 02144 if (absolute) 02145 rc = addFile(fl, fn, NULL); 02146 02147 exit: 02148 apkt = _free(apkt); 02149 pkt = _free(pkt); 02150 iob = rpmiobFree(iob); 02151 fn = _free(fn); 02152 if (rc != RPMRC_OK) 02153 fl->processingFailed = 1; 02154 return rc; 02155 } 02156 02164 static rpmRC processBinaryFile(/*@unused@*/ Package pkg, FileList fl, 02165 const char * fileURL) 02166 /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/ 02167 /*@modifies *fl, fl->processingFailed, 02168 fl->fileList, fl->fileListRecsAlloced, fl->fileListRecsUsed, 02169 fl->totalFileSize, fl->fileCount, 02170 rpmGlobalMacroContext, fileSystem, internalState @*/ 02171 { 02172 int quote = 1; /* XXX permit quoted glob characters. */ 02173 int doGlob; 02174 const char *diskURL = NULL; 02175 rpmRC rc = RPMRC_OK; 02176 int xx; 02177 02178 doGlob = Glob_pattern_p(fileURL, quote); 02179 02180 /* Check that file starts with leading "/" */ 02181 { const char * fileName; 02182 (void) urlPath(fileURL, &fileName); 02183 if (*fileName != '/') { 02184 rpmlog(RPMLOG_ERR, _("File needs leading \"/\": %s\n"), 02185 fileName); 02186 rc = RPMRC_FAIL; 02187 goto exit; 02188 } 02189 } 02190 02191 /* Copy file name or glob pattern removing multiple "/" chars. */ 02192 /* 02193 * Note: rpmGetPath should guarantee a "canonical" path. That means 02194 * that the following pathologies should be weeded out: 02195 * //bin//sh 02196 * //usr//bin/ 02197 * /.././../usr/../bin//./sh 02198 */ 02199 diskURL = rpmGenPath(fl->buildRootURL, NULL, fileURL); 02200 02201 if (doGlob) { 02202 const char ** argv = NULL; 02203 int argc = 0; 02204 int i; 02205 02206 /* XXX for %dev marker in file manifest only */ 02207 if (fl->noGlob) { 02208 rpmlog(RPMLOG_ERR, _("Glob not permitted: %s\n"), 02209 diskURL); 02210 rc = RPMRC_FAIL; 02211 goto exit; 02212 } 02213 02214 xx = rpmGlob(diskURL, &argc, &argv); 02215 if (xx == 0 && argc >= 1) { 02216 for (i = 0; i < argc; i++) { 02217 rc = addFile(fl, argv[i], NULL); 02218 argv[i] = _free(argv[i]); 02219 } 02220 argv = _free(argv); 02221 } else { 02222 if (fl->currentFlags & RPMFILE_OPTIONAL) { 02223 rpmlog(RPMLOG_WARNING, _("Optional file not found by glob: %s\n"), 02224 diskURL); 02225 rc = RPMRC_OK; 02226 } else { 02227 rpmlog(RPMLOG_ERR, _("File not found by glob: %s\n"), 02228 diskURL); 02229 rc = RPMRC_FAIL; 02230 } 02231 goto exit; 02232 } 02233 } else 02234 rc = addFile(fl, diskURL, NULL); 02235 02236 exit: 02237 diskURL = _free(diskURL); 02238 if (rc != RPMRC_OK) 02239 fl->processingFailed = 1; 02240 return rc; 02241 } 02242 02245 static rpmRC processPackageFiles(Spec spec, Package pkg, 02246 int installSpecialDoc, int test) 02247 /*@globals rpmGlobalMacroContext, h_errno, 02248 fileSystem, internalState@*/ 02249 /*@modifies spec->macros, 02250 pkg->fi, pkg->fileList, pkg->specialDoc, pkg->header, 02251 rpmGlobalMacroContext, fileSystem, internalState @*/ 02252 { 02253 HE_t he = memset(alloca(sizeof(*he)), 0, sizeof(*he)); 02254 struct FileList_s fl; 02255 ARGV_t files = NULL; 02256 ARGV_t fp; 02257 const char *fileName; 02258 char buf[BUFSIZ]; 02259 struct AttrRec_s arbuf; 02260 AttrRec specialDocAttrRec = &arbuf; 02261 char *specialDoc = NULL; 02262 int xx; 02263 02264 nullAttrRec(specialDocAttrRec); 02265 pkg->fi = NULL; 02266 02267 if (pkg->fileFile) { 02268 char *saveptr = NULL; 02269 char *filesFiles = xstrdup(pkg->fileFile); 02270 /*@-unrecog@*/ 02271 char *token = strtok_r(filesFiles, ",", &saveptr); 02272 /*@=unrecog@*/ 02273 do { 02274 const char *ffn; 02275 FILE * f; 02276 FD_t fd; 02277 02278 /* XXX W2DO? urlPath might be useful here. */ 02279 if (*token == '/') { 02280 ffn = rpmGetPath(token, NULL); 02281 } else { 02282 /* XXX FIXME: add %{buildsubdir} */ 02283 ffn = rpmGetPath("%{_builddir}/", 02284 (spec->buildSubdir ? spec->buildSubdir : "") , 02285 "/", token, NULL); 02286 } 02287 02288 fd = Fopen(ffn, "r.fpio"); 02289 02290 if (fd == NULL || Ferror(fd)) { 02291 rpmlog(RPMLOG_ERR, 02292 _("Could not open %%files file %s: %s\n"), 02293 ffn, Fstrerror(fd)); 02294 return RPMRC_FAIL; 02295 } 02296 ffn = _free(ffn); 02297 02298 /*@+voidabstract@*/ f = fdGetFp(fd); /*@=voidabstract@*/ 02299 if (f != NULL) { 02300 while (fgets(buf, (int)sizeof(buf), f)) { 02301 handleComments(buf); 02302 if (expandMacros(spec, spec->macros, buf, sizeof(buf))) { 02303 rpmlog(RPMLOG_ERR, _("line: %s\n"), buf); 02304 return RPMRC_FAIL; 02305 } 02306 pkg->fileList = rpmiobAppend(pkg->fileList, buf, 0); 02307 } 02308 } 02309 (void) Fclose(fd); 02310 } while((token = strtok_r(NULL, ",", &saveptr)) != NULL); 02311 filesFiles = _free(filesFiles); 02312 } 02313 02314 /* Init the file list structure */ 02315 memset(&fl, 0, sizeof(fl)); 02316 02317 fl.buildRootURL = rpmGenPath(spec->rootURL, "%{?buildroot}", NULL); 02318 02319 he->tag = RPMTAG_DEFAULTPREFIX; 02320 xx = headerGet(pkg->header, he, 0); 02321 fl.prefix = he->p.str; 02322 02323 fl.fileCount = 0; 02324 fl.totalFileSize = 0; 02325 fl.processingFailed = 0; 02326 02327 fl.passedSpecialDoc = 0; 02328 fl.isSpecialDoc = 0; 02329 02330 fl.isDir = 0; 02331 fl.inFtw = 0; 02332 fl.currentFlags = 0; 02333 fl.currentVerifyFlags = 0; 02334 02335 fl.noGlob = 0; 02336 fl.devtype = 0; 02337 fl.devmajor = 0; 02338 fl.devminor = 0; 02339 02340 nullAttrRec(&fl.cur_ar); 02341 nullAttrRec(&fl.def_ar); 02342 dupAttrRec(&root_ar, &fl.def_ar); /* XXX assume %defattr(-,root,root) */ 02343 02344 fl.defVerifyFlags = RPMVERIFY_ALL; 02345 fl.nLangs = 0; 02346 fl.currentLangs = NULL; 02347 02348 fl.currentSpecdFlags = 0; 02349 fl.defSpecdFlags = 0; 02350 02351 fl.docDirCount = 0; 02352 #if defined(RPM_VENDOR_OPENPKG) /* no-default-doc-files */ 02353 /* do not declare any files as %doc files by default. */ 02354 #else 02355 fl.docDirs[fl.docDirCount++] = xstrdup("/usr/doc"); 02356 fl.docDirs[fl.docDirCount++] = xstrdup("/usr/man"); 02357 fl.docDirs[fl.docDirCount++] = xstrdup("/usr/info"); 02358 fl.docDirs[fl.docDirCount++] = xstrdup("/usr/X11R6/man"); 02359 fl.docDirs[fl.docDirCount++] = xstrdup("/usr/share/doc"); 02360 fl.docDirs[fl.docDirCount++] = xstrdup("/usr/share/man"); 02361 fl.docDirs[fl.docDirCount++] = xstrdup("/usr/share/info"); 02362 fl.docDirs[fl.docDirCount++] = xstrdup("/usr/src/examples"); 02363 fl.docDirs[fl.docDirCount++] = rpmGetPath("%{_docdir}", NULL); 02364 fl.docDirs[fl.docDirCount++] = rpmGetPath("%{_mandir}", NULL); 02365 fl.docDirs[fl.docDirCount++] = rpmGetPath("%{_infodir}", NULL); 02366 fl.docDirs[fl.docDirCount++] = rpmGetPath("%{_javadocdir}", NULL); 02367 fl.docDirs[fl.docDirCount++] = rpmGetPath("%{_examplesdir}", NULL); 02368 #endif 02369 02370 fl.fileList = NULL; 02371 fl.fileListRecsAlloced = 0; 02372 fl.fileListRecsUsed = 0; 02373 02374 xx = argvSplit(&files, rpmiobStr(pkg->fileList), "\n"); 02375 02376 for (fp = files; *fp != NULL; fp++) { 02377 const char * s; 02378 s = *fp; 02379 SKIPSPACE(s); 02380 if (*s == '\0') 02381 continue; 02382 fileName = NULL; 02383 /*@-nullpass@*/ /* LCL: buf is NULL ?!? */ 02384 strncpy(buf, s, sizeof(buf)-1); 02385 buf[sizeof(buf)-1] = '\0'; 02386 /*@=nullpass@*/ 02387 02388 /* Reset for a new line in %files */ 02389 fl.isDir = 0; 02390 fl.inFtw = 0; 02391 fl.currentFlags = 0; 02392 /* turn explicit flags into %def'd ones (gosh this is hacky...) */ 02393 fl.currentSpecdFlags = ((unsigned)fl.defSpecdFlags) >> 8; 02394 fl.currentVerifyFlags = fl.defVerifyFlags; 02395 fl.isSpecialDoc = 0; 02396 02397 fl.noGlob = 0; 02398 fl.devtype = 0; 02399 fl.devmajor = 0; 02400 fl.devminor = 0; 02401 02402 /* XXX should reset to %deflang value */ 02403 if (fl.currentLangs) { 02404 int i; 02405 for (i = 0; i < fl.nLangs; i++) 02406 /*@-unqualifiedtrans@*/ 02407 fl.currentLangs[i] = _free(fl.currentLangs[i]); 02408 /*@=unqualifiedtrans@*/ 02409 fl.currentLangs = _free(fl.currentLangs); 02410 } 02411 fl.nLangs = 0; 02412 02413 dupAttrRec(&fl.def_ar, &fl.cur_ar); 02414 02415 /*@-nullpass@*/ /* LCL: buf is NULL ?!? */ 02416 if (parseForVerify(buf, &fl) != RPMRC_OK) 02417 continue; 02418 if (parseForAttr(buf, &fl) != RPMRC_OK) 02419 continue; 02420 if (parseForDev(buf, &fl) != RPMRC_OK) 02421 continue; 02422 if (parseForConfig(buf, &fl) != RPMRC_OK) 02423 continue; 02424 if (parseForLang(buf, &fl) != RPMRC_OK) 02425 continue; 02426 /*@-nullstate@*/ /* FIX: pkg->fileFile might be NULL */ 02427 if (parseForSimple(spec, pkg, buf, &fl, &fileName) != RPMRC_OK) 02428 /*@=nullstate@*/ 02429 continue; 02430 /*@=nullpass@*/ 02431 if (fileName == NULL) 02432 continue; 02433 02434 if (fl.isSpecialDoc) { 02435 /* Save this stuff for last */ 02436 specialDoc = _free(specialDoc); 02437 specialDoc = xstrdup(fileName); 02438 dupAttrRec(&fl.cur_ar, specialDocAttrRec); 02439 } else if (fl.currentFlags & RPMFILE_PUBKEY) { 02440 /*@-nullstate@*/ /* FIX: pkg->fileFile might be NULL */ 02441 (void) processMetadataFile(pkg, &fl, fileName, RPMTAG_PUBKEYS); 02442 /*@=nullstate@*/ 02443 } else if (fl.currentFlags & RPMFILE_POLICY) { 02444 /*@-nullstate@*/ /* FIX: pkg->fileFile might be NULL */ 02445 (void) processMetadataFile(pkg, &fl, fileName, RPMTAG_POLICIES); 02446 /*@=nullstate@*/ 02447 } else { 02448 /*@-nullstate@*/ /* FIX: pkg->fileFile might be NULL */ 02449 (void) processBinaryFile(pkg, &fl, fileName); 02450 /*@=nullstate@*/ 02451 } 02452 } 02453 02454 /* Now process special doc, if there is one */ 02455 if (specialDoc) { 02456 if (installSpecialDoc) { 02457 int _missing_doc_files_terminate_build = 02458 rpmExpandNumeric("%{?_missing_doc_files_terminate_build}"); 02459 rpmRC rc; 02460 02461 rc = doScript(spec, RPMBUILD_STRINGBUF, "%doc", pkg->specialDoc, test); 02462 if (rc != RPMRC_OK && _missing_doc_files_terminate_build) 02463 fl.processingFailed = 1; 02464 } 02465 02466 /* Reset for %doc */ 02467 fl.isDir = 0; 02468 fl.inFtw = 0; 02469 fl.currentFlags = 0; 02470 fl.currentVerifyFlags = fl.defVerifyFlags; 02471 02472 fl.noGlob = 0; 02473 fl.devtype = 0; 02474 fl.devmajor = 0; 02475 fl.devminor = 0; 02476 02477 /* XXX should reset to %deflang value */ 02478 if (fl.currentLangs) { 02479 int i; 02480 for (i = 0; i < fl.nLangs; i++) 02481 /*@-unqualifiedtrans@*/ 02482 fl.currentLangs[i] = _free(fl.currentLangs[i]); 02483 /*@=unqualifiedtrans@*/ 02484 fl.currentLangs = _free(fl.currentLangs); 02485 } 02486 fl.nLangs = 0; 02487 02488 dupAttrRec(specialDocAttrRec, &fl.cur_ar); 02489 freeAttrRec(specialDocAttrRec); 02490 02491 /*@-nullstate@*/ /* FIX: pkg->fileFile might be NULL */ 02492 (void) processBinaryFile(pkg, &fl, specialDoc); 02493 /*@=nullstate@*/ 02494 02495 specialDoc = _free(specialDoc); 02496 } 02497 02498 files = argvFree(files); 02499 02500 if (fl.processingFailed) 02501 goto exit; 02502 02503 /* Verify that file attributes scope over hardlinks correctly. */ 02504 if (checkHardLinks(&fl)) 02505 (void) rpmlibNeedsFeature(pkg->header, 02506 "PartialHardlinkSets", "4.0.4-1"); 02507 02508 /* XXX should tags be added if filelist is empty? */ 02509 genCpioListAndHeader(&fl, &pkg->fi, pkg->header, 0); 02510 02511 if (spec->timeCheck) 02512 timeCheck(spec->timeCheck, pkg->header); 02513 02514 exit: 02515 fl.buildRootURL = _free(fl.buildRootURL); 02516 fl.prefix = _free(fl.prefix); 02517 02518 freeAttrRec(&fl.cur_ar); 02519 freeAttrRec(&fl.def_ar); 02520 02521 if (fl.currentLangs) { 02522 int i; 02523 for (i = 0; i < fl.nLangs; i++) 02524 /*@-unqualifiedtrans@*/ 02525 fl.currentLangs[i] = _free(fl.currentLangs[i]); 02526 /*@=unqualifiedtrans@*/ 02527 fl.currentLangs = _free(fl.currentLangs); 02528 } 02529 02530 fl.fileList = freeFileList(fl.fileList, fl.fileListRecsUsed); 02531 while (fl.docDirCount--) 02532 fl.docDirs[fl.docDirCount] = _free(fl.docDirs[fl.docDirCount]); 02533 return (fl.processingFailed ? RPMRC_FAIL : RPMRC_OK); 02534 } 02535 02536 int initSourceHeader(Spec spec, rpmiob *sfp) 02537 { 02538 HE_t he = memset(alloca(sizeof(*he)), 0, sizeof(*he)); 02539 HeaderIterator hi; 02540 rpmiob sourceFiles; 02541 struct Source *srcPtr; 02542 static rpmTag classTag = 0xffffffff; 02543 int xx; 02544 size_t i; 02545 02546 if (classTag == 0xffffffff) 02547 classTag = tagValue("Class"); 02548 02549 /* Only specific tags are added to the source package header */ 02550 if (spec->packages && !spec->sourceHdrInit) { 02551 for (hi = headerInit(spec->packages->header); 02552 headerNext(hi, he, 0); 02553 he->p.ptr = _free(he->p.ptr)) 02554 { 02555 switch (he->tag) { 02556 case RPMTAG_NAME: 02557 case RPMTAG_VERSION: 02558 case RPMTAG_RELEASE: 02559 case RPMTAG_DISTEPOCH: 02560 case RPMTAG_EPOCH: 02561 case RPMTAG_SUMMARY: 02562 case RPMTAG_DESCRIPTION: 02563 case RPMTAG_PACKAGER: 02564 case RPMTAG_DISTRIBUTION: 02565 case RPMTAG_DISTURL: 02566 case RPMTAG_VENDOR: 02567 case RPMTAG_LICENSE: 02568 case RPMTAG_GROUP: 02569 case RPMTAG_OS: 02570 case RPMTAG_ARCH: 02571 case RPMTAG_CHANGELOGTIME: 02572 case RPMTAG_CHANGELOGNAME: 02573 case RPMTAG_CHANGELOGTEXT: 02574 case RPMTAG_URL: 02575 case RPMTAG_BUGURL: 02576 case RPMTAG_ICON: 02577 case RPMTAG_GIF: 02578 case RPMTAG_XPM: 02579 case HEADER_I18NTABLE: 02580 #if defined(RPM_VENDOR_OPENPKG) /* propagate-provides-to-srpms */ 02581 /* make sure the "Provides" headers are available for querying from the .src.rpm files. */ 02582 case RPMTAG_PROVIDENAME: 02583 case RPMTAG_PROVIDEVERSION: 02584 case RPMTAG_PROVIDEFLAGS: 02585 #endif 02586 if (he->p.ptr) 02587 xx = headerPut(spec->sourceHeader, he, 0); 02588 /*@switchbreak@*/ break; 02589 default: 02590 if (classTag == he->tag && he->p.ptr != NULL) 02591 xx = headerPut(spec->sourceHeader, he, 0); 02592 /*@switchbreak@*/ break; 02593 } 02594 } 02595 hi = headerFini(hi); 02596 02597 if (spec->BANames && spec->BACount > 0) { 02598 he->tag = RPMTAG_BUILDARCHS; 02599 he->t = RPM_STRING_ARRAY_TYPE; 02600 he->p.argv = spec->BANames; 02601 he->c = spec->BACount; 02602 xx = headerPut(spec->sourceHeader, he, 0); 02603 } 02604 02605 /* Load arbitrary tags into srpm header. */ 02606 if (spec->foo) 02607 for (i = 0; i < spec->nfoo; i++) { 02608 const char * str = spec->foo[i].str; 02609 rpmTag tag = spec->foo[i].tag; 02610 rpmiob iob = spec->foo[i].iob; 02611 char * s; 02612 02613 if (str == NULL || iob == NULL) 02614 continue; 02615 02616 /* XXX Special case %track interpreter for now. */ 02617 if (!xstrcasecmp(str, "track")) { 02618 he->p.str = rpmExpand("%{?__vcheck}", NULL); 02619 if (!(he->p.str != NULL && he->p.str[0] != '\0')) { 02620 he->p.str = _free(he->p.str); 02621 continue; 02622 } 02623 he->tag = tagValue("Trackprog"); 02624 he->t = RPM_STRING_TYPE; 02625 he->c = 1; 02626 xx = headerPut(spec->sourceHeader, he, 0); 02627 he->p.str = _free(he->p.str); 02628 } 02629 02630 s = rpmiobStr(iob); 02631 he->tag = tag; 02632 he->append = headerIsEntry(spec->sourceHeader, tag); 02633 if (he->append) { 02634 he->t = RPM_STRING_ARRAY_TYPE; 02635 he->p.argv = (const char **) &s; 02636 he->c = 1; 02637 } else { 02638 he->t = RPM_STRING_TYPE; 02639 he->p.str = s; 02640 he->c = 1; 02641 } 02642 xx = headerPut(spec->sourceHeader, he, 0); 02643 he->append = 0; 02644 } 02645 } 02646 02647 if (sfp != NULL && *sfp != NULL) 02648 sourceFiles = *sfp; 02649 else 02650 sourceFiles = rpmiobNew(0); 02651 02652 /* Construct the source/patch tag entries */ 02653 if (spec->specFile != NULL) /* XXX segfault avoidance */ 02654 sourceFiles = rpmiobAppend(sourceFiles, spec->specFile, 1); 02655 if (spec->sourceHeader != NULL) 02656 for (srcPtr = spec->sources; srcPtr != NULL; srcPtr = srcPtr->next) { 02657 { const char * sfn; 02658 /*@-nullpass@*/ /* XXX getSourceDir returns NULL with bad flags. */ 02659 sfn = rpmGetPath( ((srcPtr->flags & RPMFILE_GHOST) ? "!" : ""), 02660 #if defined(RPM_VENDOR_OPENPKG) /* splitted-source-directory */ 02661 getSourceDir(srcPtr->flags, srcPtr->source), srcPtr->source, NULL); 02662 #else 02663 getSourceDir(srcPtr->flags), srcPtr->source, NULL); 02664 #endif 02665 /*@=nullpass@*/ 02666 sourceFiles = rpmiobAppend(sourceFiles, sfn, 1); 02667 sfn = _free(sfn); 02668 } 02669 02670 if (spec->sourceHdrInit) 02671 continue; 02672 02673 if (srcPtr->flags & RPMFILE_SOURCE) { 02674 he->tag = RPMTAG_SOURCE; 02675 he->t = RPM_STRING_ARRAY_TYPE; 02676 he->p.argv = &srcPtr->source; 02677 he->c = 1; 02678 he->append = 1; 02679 xx = headerPut(spec->sourceHeader, he, 0); 02680 he->append = 0; 02681 if (srcPtr->flags & RPMFILE_GHOST) { 02682 he->tag = RPMTAG_NOSOURCE; 02683 he->t = RPM_UINT32_TYPE; 02684 he->p.ui32p = &srcPtr->num; 02685 he->c = 1; 02686 he->append = 1; 02687 xx = headerPut(spec->sourceHeader, he, 0); 02688 he->append = 0; 02689 } 02690 } 02691 if (srcPtr->flags & RPMFILE_PATCH) { 02692 he->tag = RPMTAG_PATCH; 02693 he->t = RPM_STRING_ARRAY_TYPE; 02694 he->p.argv = &srcPtr->source; 02695 he->c = 1; 02696 he->append = 1; 02697 xx = headerPut(spec->sourceHeader, he, 0); 02698 he->append = 0; 02699 if (srcPtr->flags & RPMFILE_GHOST) { 02700 he->tag = RPMTAG_NOPATCH; 02701 he->t = RPM_UINT32_TYPE; 02702 he->p.ui32p = &srcPtr->num; 02703 he->c = 1; 02704 he->append = 1; 02705 xx = headerPut(spec->sourceHeader, he, 0); 02706 he->append = 0; 02707 } 02708 } 02709 } 02710 02711 if (sfp == NULL) 02712 sourceFiles = rpmiobFree(sourceFiles); 02713 02714 spec->sourceHdrInit = 1; 02715 02716 /*@-usereleased@*/ 02717 return 0; 02718 /*@=usereleased@*/ 02719 } 02720 02721 int processSourceFiles(Spec spec) 02722 { 02723 rpmiob sourceFiles, *sfp = &sourceFiles; 02724 int x, isSpec = 1; 02725 struct FileList_s fl; 02726 ARGV_t files = NULL; 02727 ARGV_t fp; 02728 int rc; 02729 /* srcdefattr: needed variables */ 02730 char _srcdefattr_buf[BUFSIZ]; 02731 char * _srcdefattr = rpmExpand("%{?_srcdefattr}", NULL); 02732 int xx; 02733 02734 *sfp = rpmiobNew(0); 02735 x = initSourceHeader(spec, sfp); 02736 02737 /* srcdefattr: initialize file list structure */ 02738 memset(&fl, 0, sizeof(fl)); 02739 if (_srcdefattr && *_srcdefattr) { 02740 xx = snprintf(_srcdefattr_buf, sizeof(_srcdefattr_buf), "%%defattr %s", _srcdefattr); 02741 _srcdefattr_buf[sizeof(_srcdefattr_buf)-1] = '\0'; 02742 xx = parseForAttr(_srcdefattr_buf, &fl); 02743 } 02744 02745 /* Construct the SRPM file list. */ 02746 fl.fileList = xcalloc((spec->numSources + 1), sizeof(*fl.fileList)); 02747 rc = fl.processingFailed = 0; 02748 fl.fileListRecsUsed = 0; 02749 fl.totalFileSize = 0; 02750 fl.prefix = NULL; 02751 fl.buildRootURL = NULL; 02752 02753 xx = argvSplit(&files, rpmiobStr(*sfp), "\n"); 02754 02755 /* The first source file is the spec file */ 02756 x = 0; 02757 for (fp = files; *fp != NULL; fp++) { 02758 const char * diskURL, *diskPath; 02759 FileListRec flp; 02760 02761 diskURL = *fp; 02762 SKIPSPACE(diskURL); 02763 if (! *diskURL) 02764 continue; 02765 02766 flp = &fl.fileList[x]; 02767 02768 flp->flags = isSpec ? RPMFILE_SPECFILE : 0; 02769 /* files with leading ! are no source files */ 02770 if (*diskURL == '!') { 02771 flp->flags |= RPMFILE_GHOST; 02772 diskURL++; 02773 } 02774 02775 (void) urlPath(diskURL, &diskPath); 02776 02777 flp->diskURL = xstrdup(diskURL); 02778 diskPath = strrchr(diskPath, '/'); 02779 if (diskPath) 02780 diskPath++; 02781 else 02782 diskPath = diskURL; 02783 02784 flp->fileURL = xstrdup(diskPath); 02785 flp->verifyFlags = RPMVERIFY_ALL; 02786 02787 if (Stat(diskURL, &flp->fl_st)) { 02788 rpmlog(RPMLOG_ERR, _("Bad file: %s: %s\n"), 02789 diskURL, strerror(errno)); 02790 rc = fl.processingFailed = 1; 02791 } 02792 02793 #if defined(RPM_VENDOR_OPENPKG) /* support-srcdefattr */ 02794 /* srcdefattr: allow to set SRPM file attributes via %{_srcdefattr} macro */ 02795 if (fl.def_ar.ar_fmodestr) { 02796 flp->fl_mode &= S_IFMT; 02797 flp->fl_mode |= fl.def_ar.ar_fmode; 02798 } 02799 flp->uname = fl.def_ar.ar_user ? getUnameS(fl.def_ar.ar_user) : getUname(flp->fl_uid); 02800 flp->gname = fl.def_ar.ar_group ? getGnameS(fl.def_ar.ar_group) : getGname(flp->fl_gid); 02801 #else 02802 flp->uname = getUname(flp->fl_uid); 02803 flp->gname = getGname(flp->fl_gid); 02804 #endif 02805 flp->langs = xstrdup(""); 02806 02807 if (! (flp->uname && flp->gname)) { 02808 rpmlog(RPMLOG_ERR, _("Bad owner/group: %s\n"), diskURL); 02809 rc = fl.processingFailed = 1; 02810 } 02811 02812 isSpec = 0; 02813 x++; 02814 } 02815 fl.fileListRecsUsed = x; 02816 files = argvFree(files); 02817 02818 if (rc) 02819 goto exit; 02820 02821 /* XXX should tags be added if filelist is empty? */ 02822 spec->fi = NULL; 02823 genCpioListAndHeader(&fl, &spec->fi, spec->sourceHeader, 1); 02824 02825 exit: 02826 *sfp = rpmiobFree(*sfp); 02827 fl.fileList = freeFileList(fl.fileList, fl.fileListRecsUsed); 02828 _srcdefattr = _free(_srcdefattr); 02829 return rc; 02830 } 02831 02837 static int checkUnpackagedFiles(Spec spec) 02838 /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/ 02839 /*@modifies *spec->packages, 02840 rpmGlobalMacroContext, fileSystem, internalState @*/ 02841 { 02842 /*@-readonlytrans@*/ 02843 static const char * av_ckfile[] = { "%{?__check_files}", NULL }; 02844 /*@=readonlytrans@*/ 02845 rpmiob iob_stdout = NULL; 02846 const char * s; 02847 int rc; 02848 rpmiob fileList = NULL; 02849 Package pkg; 02850 int n = 0; 02851 02852 s = rpmExpand(av_ckfile[0], NULL); 02853 if (!(s && *s)) { 02854 rc = -1; 02855 goto exit; 02856 } 02857 rc = 0; 02858 02859 /* initialize fileList */ 02860 fileList = rpmiobNew(0); 02861 for (pkg = spec->packages; pkg != NULL; pkg = pkg->next) { 02862 int i; 02863 #ifndef DYING /* XXX rpmfiNew is necessary here. why?!? */ 02864 rpmfi fi = rpmfiNew(NULL, pkg->header, RPMTAG_BASENAMES, 0); 02865 #else 02866 rpmfi fi = rpmfiLink(pkg->fi, __FUNCTION__); 02867 #endif 02868 fi = rpmfiInit(fi, 0); 02869 while ((i = rpmfiNext(fi)) >= 0) { 02870 const char *fn = rpmfiFN(fi); 02871 fileList = rpmiobAppend(fileList, fn, 1); 02872 n++; 02873 } 02874 fi = rpmfiFree(fi); 02875 } 02876 02877 if (n == 0) { 02878 /* no packaged files, and buildroot may not exist - 02879 * no need to run check */ 02880 rc = -1; 02881 goto exit; 02882 } 02883 02884 rpmlog(RPMLOG_NOTICE, _("Checking for unpackaged file(s): %s\n"), s); 02885 02886 rc = rpmfcExec(av_ckfile, fileList, &iob_stdout, 0); 02887 if (rc < 0) 02888 goto exit; 02889 02890 if (iob_stdout) { 02891 int _unpackaged_files_terminate_build = 02892 rpmExpandNumeric("%{?_unpackaged_files_terminate_build}"); 02893 const char * t; 02894 02895 t = rpmiobStr(iob_stdout); 02896 if ((*t != '\0') && (*t != '\n')) { 02897 rc = (_unpackaged_files_terminate_build) ? 1 : 0; 02898 rpmlog((rc ? RPMLOG_ERR : RPMLOG_WARNING), 02899 _("Installed (but unpackaged) file(s) found:\n%s"), t); 02900 } 02901 } 02902 02903 exit: 02904 fileList = rpmiobFree(fileList); 02905 iob_stdout = rpmiobFree(iob_stdout); 02906 s = _free(s); 02907 return rc; 02908 } 02909 02910 /* auxiliary function for checkDuplicateFiles() */ 02911 /* XXX need to pass Header because fi->h is NULL */ 02912 static int fiIntersect(/*@null@*/ rpmfi fi1, /*@null@*/ rpmfi fi2) 02913 /*@globals internalState @*/ 02914 /*@modifies fi1, fi2, internalState @*/ 02915 { 02916 int n = 0; 02917 int i1, i2; 02918 const char *fn1, *fn2; 02919 rpmiob dups = NULL; 02920 02921 if ((fi1 = rpmfiInit(fi1, 0)) != NULL) 02922 while ((i1 = rpmfiNext(fi1)) >= 0) { 02923 if (S_ISDIR(rpmfiFMode(fi1))) 02924 continue; 02925 fn1 = rpmfiFN(fi1); 02926 if ((fi2 = rpmfiInit(fi2, 0)) != NULL) 02927 while ((i2 = rpmfiNext(fi2)) >= 0) { 02928 if (S_ISDIR(rpmfiFMode(fi2))) 02929 /*@innercontinue@*/ continue; 02930 fn2 = rpmfiFN(fi2); 02931 if (strcmp(fn1, fn2)) 02932 /*@innercontinue@*/ continue; 02933 if (!dups) 02934 dups = rpmiobNew(0); 02935 dups = rpmiobAppend(dups, "\t", 0); 02936 dups = rpmiobAppend(dups, fn1, 1); 02937 n++; 02938 } 02939 } 02940 02941 if (n > 0) { 02942 const char *N1, *N2; 02943 HE_t he = memset(alloca(sizeof(*he)), 0, sizeof(*he)); 02944 02945 he->tag = RPMTAG_NVRA; 02946 N1 = (headerGet(fi1->h, he, 0) ? he->p.str : NULL); 02947 he->tag = RPMTAG_NVRA; 02948 N2 = (headerGet(fi2->h, he, 0) ? he->p.str : NULL); 02949 02950 rpmlog(RPMLOG_WARNING, 02951 _("File(s) packaged into both %s and %s:\n%s"), 02952 N1, N2, rpmiobStr(dups)); 02953 02954 N1 = _free(N1); 02955 N2 = _free(N2); 02956 dups = rpmiobFree(dups); 02957 } 02958 02959 return n; 02960 } 02961 02967 static int checkDuplicateFiles(Spec spec) 02968 /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/ 02969 /*@modifies *spec->packages, 02970 rpmGlobalMacroContext, fileSystem, internalState @*/ 02971 { 02972 int n = 0; 02973 Package pkg1, pkg2; 02974 02975 if (spec->packages) /* XXX segfault avoidance */ 02976 for (pkg1 = spec->packages; pkg1->next; pkg1 = pkg1->next) { 02977 #ifdef DYING 02978 rpmfi fi1 = rpmfiNew(NULL, pkg1->header, RPMTAG_BASENAMES, 0); 02979 #else 02980 rpmfi fi1 = rpmfiLink(pkg1->fi, __FUNCTION__); 02981 #endif 02982 if (fi1 == NULL) continue; 02983 (void) rpmfiSetHeader(fi1, pkg1->header); 02984 for (pkg2 = pkg1->next; pkg2; pkg2 = pkg2->next) { 02985 #ifdef DYING 02986 rpmfi fi2 = rpmfiNew(NULL, pkg2->header, RPMTAG_BASENAMES, 0); 02987 #else 02988 rpmfi fi2 = rpmfiLink(pkg2->fi, __FUNCTION__); 02989 #endif 02990 if (fi2 == NULL) continue; 02991 (void) rpmfiSetHeader(fi2, pkg2->header); 02992 n += fiIntersect(fi1, fi2); 02993 (void) rpmfiSetHeader(fi2, NULL); 02994 fi2 = rpmfiFree(fi2); 02995 } 02996 (void) rpmfiSetHeader(fi1, NULL); 02997 fi1 = rpmfiFree(fi1); 02998 } 02999 return n; 03000 } 03001 03002 /* auxiliary function: check if directory d is packaged */ 03003 static inline int packagedDir(Package pkg, const char *d) 03004 /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/ 03005 /*@modifies pkg->header, 03006 rpmGlobalMacroContext, fileSystem, internalState @*/ 03007 { 03008 return rpmbfChk(rpmfiFNBF(pkg->fi), d, strlen(d)); 03009 } 03010 03011 /* auxiliary function: find unpackaged subdirectories 03012 * 03013 * E.g. consider this %files section: 03014 * %dir /A 03015 * /A/B/C/D 03016 * Now directories "/A/B" and "/A/B/C" should also be packaged. 03017 */ 03018 static int pkgUnpackagedSubdirs(Package pkg) 03019 /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/ 03020 /*@modifies pkg->header, 03021 rpmGlobalMacroContext, fileSystem, internalState @*/ 03022 { 03023 int n = 0; 03024 int i, j; 03025 char **unpackaged = NULL; 03026 char *fn; 03027 #ifdef DYING 03028 rpmfi fi = rpmfiNew(NULL, pkg->header, RPMTAG_BASENAMES, 0); 03029 #else 03030 rpmfi fi = rpmfiLink(pkg->fi, __FUNCTION__); 03031 #endif 03032 03033 if (rpmfiFC(fi) <= 1) { 03034 fi = rpmfiFree(fi); 03035 return 0; 03036 } 03037 fn = alloca(rpmfiFNMaxLen(fi) + 1); 03038 03039 fi = rpmfiInit(fi, 0); 03040 while ((i = rpmfiNext(fi)) >= 0) { 03041 int found = 0; 03042 /* make local copy of file name */ 03043 char *p = fn; 03044 strcpy(fn, rpmfiFN(fi)); 03045 /* find the first path component that is packaged */ 03046 while ((p = strchr(p + 1, '/'))) { 03047 *p = '\0'; 03048 found = packagedDir(pkg, fn); 03049 *p = '/'; 03050 if (found) 03051 /*@innerbreak@*/ break; 03052 } 03053 if (!found) 03054 continue; 03055 /* other path components should be packaged, too */ 03056 if (p != NULL) 03057 while ((p = strchr(p + 1, '/'))) { 03058 *p = '\0'; 03059 if (packagedDir(pkg, fn)) { 03060 *p = '/'; 03061 /*@innercontinue@*/ continue; 03062 } 03063 /* might be already added */ 03064 found = 0; 03065 for (j = 0; j < n; j++) 03066 if (strcmp(fn, unpackaged[j]) == 0) { 03067 found = 1; 03068 /*@innerbreak@*/ break; 03069 } 03070 if (found) { 03071 *p = '/'; 03072 /*@innercontinue@*/ continue; 03073 } 03074 unpackaged = xrealloc(unpackaged, sizeof(*unpackaged) * (n + 1)); 03075 unpackaged[n++] = xstrdup(fn); 03076 *p = '/'; 03077 } 03078 } 03079 fi = rpmfiFree(fi); 03080 03081 if (n > 0) { 03082 const char *N; 03083 HE_t he = memset(alloca(sizeof(*he)), 0, sizeof(*he)); 03084 rpmiob list = rpmiobNew(0); 03085 03086 he->tag = RPMTAG_NVRA; 03087 N = (headerGet(pkg->header, he, 0) ? he->p.str : NULL); 03088 03089 for (i = 0; i < n; i++) { 03090 list = rpmiobAppend(list, "\t", 0); 03091 list = rpmiobAppend(list, unpackaged[i], 1); 03092 unpackaged[i] = _free(unpackaged[i]); 03093 } 03094 unpackaged = _free(unpackaged); 03095 03096 rpmlog(RPMLOG_WARNING, 03097 _("Unpackaged subdir(s) in %s:\n%s"), 03098 N, rpmiobStr(list)); 03099 03100 N = _free(N); 03101 list = rpmiobFree(list); 03102 } 03103 03104 return n; 03105 } 03106 03112 static int checkUnpackagedSubdirs(Spec spec) 03113 /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/ 03114 /*@modifies *spec->packages, 03115 rpmGlobalMacroContext, fileSystem, internalState @*/ 03116 { 03117 int n = 0; 03118 Package pkg; 03119 03120 for (pkg = spec->packages; pkg; pkg = pkg->next) 03121 n += pkgUnpackagedSubdirs(pkg); 03122 return n; 03123 } 03124 03125 /*@-incondefs@*/ 03126 rpmRC processBinaryFiles(Spec spec, int installSpecialDoc, int test) 03127 { 03128 HE_t he = memset(alloca(sizeof(*he)), 0, sizeof(*he)); 03129 Package pkg; 03130 rpmRC res = RPMRC_OK; 03131 03132 for (pkg = spec->packages; pkg != NULL; pkg = pkg->next) { 03133 int rc; 03134 03135 if (pkg->fileList == NULL) 03136 continue; 03137 03138 (void) headerMacrosLoad(pkg->header); 03139 03140 he->tag = RPMTAG_NVRA; 03141 rc = headerGet(pkg->header, he, 0); 03142 rpmlog(RPMLOG_NOTICE, _("Processing files: %s\n"), he->p.str); 03143 he->p.ptr = _free(he->p.ptr); 03144 03145 if ((rc = processPackageFiles(spec, pkg, installSpecialDoc, test))) { 03146 res = RPMRC_FAIL; 03147 (void) headerMacrosUnload(pkg->header); 03148 break; 03149 } 03150 03151 /* Finalize package scriptlets before extracting dependencies. */ 03152 if ((rc = processScriptFiles(spec, pkg))) { 03153 res = rc; 03154 (void) headerMacrosUnload(pkg->header); 03155 break; 03156 } 03157 03158 if ((rc = rpmfcGenerateDepends(spec, pkg))) { 03159 res = RPMRC_FAIL; 03160 (void) headerMacrosUnload(pkg->header); 03161 break; 03162 } 03163 03164 /* XXX this should be earlier for deps to be entirely sorted. */ 03165 providePackageNVR(pkg->header); 03166 03167 (void) headerMacrosUnload(pkg->header); 03168 } 03169 03170 if (res == RPMRC_OK) { 03171 if (checkUnpackagedFiles(spec) > 0) 03172 res = RPMRC_FAIL; 03173 (void) checkDuplicateFiles(spec); 03174 (void) checkUnpackagedSubdirs(spec); 03175 } 03176 03177 return res; 03178 } 03179 /*@=incondefs@*/