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