rpm
4.5
|
00001 00007 #include "system.h" 00008 00009 #define MYALLPERMS 07777 00010 00011 #include <regex.h> 00012 00013 #include <rpmio_internal.h> 00014 #include <fts.h> 00015 00016 #include <rpmbuild.h> 00017 00018 #include "cpio.h" 00019 00020 #include "argv.h" 00021 #include "rpmfc.h" 00022 00023 #define _RPMFI_INTERNAL 00024 #include "rpmfi.h" 00025 00026 #define _RPMTE_INTERNAL 00027 #include "rpmte.h" 00028 00029 #include "buildio.h" 00030 00031 #include "legacy.h" /* XXX dodigest */ 00032 #include "misc.h" 00033 #include "debug.h" 00034 00035 /*@access Header @*/ 00036 /*@access rpmfi @*/ 00037 /*@access rpmte @*/ 00038 /*@access FD_t @*/ 00039 /*@access StringBuf @*/ /* compared with NULL */ 00040 00041 #define SKIPWHITE(_x) {while(*(_x) && (xisspace(*_x) || *(_x) == ',')) (_x)++;} 00042 #define SKIPNONWHITE(_x){while(*(_x) &&!(xisspace(*_x) || *(_x) == ',')) (_x)++;} 00043 00044 #define MAXDOCDIR 1024 00045 00048 typedef enum specdFlags_e { 00049 SPECD_DEFFILEMODE = (1 << 0), 00050 SPECD_DEFDIRMODE = (1 << 1), 00051 SPECD_DEFUID = (1 << 2), 00052 SPECD_DEFGID = (1 << 3), 00053 SPECD_DEFVERIFY = (1 << 4), 00054 00055 SPECD_FILEMODE = (1 << 8), 00056 SPECD_DIRMODE = (1 << 9), 00057 SPECD_UID = (1 << 10), 00058 SPECD_GID = (1 << 11), 00059 SPECD_VERIFY = (1 << 12) 00060 } specdFlags; 00061 00064 typedef struct FileListRec_s { 00065 struct stat fl_st; 00066 #define fl_dev fl_st.st_dev 00067 #define fl_ino fl_st.st_ino 00068 #define fl_mode fl_st.st_mode 00069 #define fl_nlink fl_st.st_nlink 00070 #define fl_uid fl_st.st_uid 00071 #define fl_gid fl_st.st_gid 00072 #define fl_rdev fl_st.st_rdev 00073 #define fl_size fl_st.st_size 00074 #define fl_mtime fl_st.st_mtime 00075 00076 /*@only@*/ 00077 const char *diskURL; /* get file from here */ 00078 /*@only@*/ 00079 const char *fileURL; /* filename in cpio archive */ 00080 /*@observer@*/ 00081 const char *uname; 00082 /*@observer@*/ 00083 const char *gname; 00084 unsigned flags; 00085 specdFlags specdFlags; /* which attributes have been explicitly specified. */ 00086 unsigned verifyFlags; 00087 /*@only@*/ 00088 const char *langs; /* XXX locales separated with | */ 00089 } * FileListRec; 00090 00093 typedef struct AttrRec_s { 00094 /*@null@*/ 00095 const char *ar_fmodestr; 00096 /*@null@*/ 00097 const char *ar_dmodestr; 00098 /*@null@*/ 00099 const char *ar_user; 00100 /*@null@*/ 00101 const char *ar_group; 00102 mode_t ar_fmode; 00103 mode_t ar_dmode; 00104 } * AttrRec; 00105 00106 /*@-readonlytrans@*/ 00107 /*@unchecked@*/ /*@observer@*/ 00108 static struct AttrRec_s root_ar = { NULL, NULL, "root", "root", 0, 0 }; 00109 /*@=readonlytrans@*/ 00110 00111 /* list of files */ 00112 /*@unchecked@*/ /*@only@*/ /*@null@*/ 00113 static StringBuf check_fileList = NULL; 00114 00118 typedef struct FileList_s { 00119 /*@only@*/ 00120 const char * buildRootURL; 00121 /*@only@*/ 00122 const char * prefix; 00123 00124 int fileCount; 00125 int totalFileSize; 00126 int processingFailed; 00127 00128 int passedSpecialDoc; 00129 int isSpecialDoc; 00130 00131 int noGlob; 00132 unsigned devtype; 00133 unsigned devmajor; 00134 int devminor; 00135 00136 int isDir; 00137 int inFtw; 00138 int currentFlags; 00139 specdFlags currentSpecdFlags; 00140 int currentVerifyFlags; 00141 struct AttrRec_s cur_ar; 00142 struct AttrRec_s def_ar; 00143 specdFlags defSpecdFlags; 00144 int defVerifyFlags; 00145 int nLangs; 00146 /*@only@*/ /*@null@*/ 00147 const char ** currentLangs; 00148 00149 /* Hard coded limit of MAXDOCDIR docdirs. */ 00150 /* If you break it you are doing something wrong. */ 00151 const char * docDirs[MAXDOCDIR]; 00152 int docDirCount; 00153 00154 /*@only@*/ 00155 FileListRec fileList; 00156 int fileListRecsAlloced; 00157 int fileListRecsUsed; 00158 } * FileList; 00159 00162 static void nullAttrRec(/*@out@*/ AttrRec ar) /*@modifies ar @*/ 00163 { 00164 ar->ar_fmodestr = NULL; 00165 ar->ar_dmodestr = NULL; 00166 ar->ar_user = NULL; 00167 ar->ar_group = NULL; 00168 ar->ar_fmode = 0; 00169 ar->ar_dmode = 0; 00170 } 00171 00174 static void freeAttrRec(AttrRec ar) /*@modifies ar @*/ 00175 { 00176 ar->ar_fmodestr = _free(ar->ar_fmodestr); 00177 ar->ar_dmodestr = _free(ar->ar_dmodestr); 00178 ar->ar_user = _free(ar->ar_user); 00179 ar->ar_group = _free(ar->ar_group); 00180 /* XXX doesn't free ar (yet) */ 00181 /*@-nullstate@*/ 00182 return; 00183 /*@=nullstate@*/ 00184 } 00185 00188 static void dupAttrRec(const AttrRec oar, /*@in@*/ /*@out@*/ AttrRec nar) 00189 /*@modifies nar @*/ 00190 { 00191 if (oar == nar) 00192 return; 00193 freeAttrRec(nar); 00194 nar->ar_fmodestr = (oar->ar_fmodestr ? xstrdup(oar->ar_fmodestr) : NULL); 00195 nar->ar_dmodestr = (oar->ar_dmodestr ? xstrdup(oar->ar_dmodestr) : NULL); 00196 nar->ar_user = (oar->ar_user ? xstrdup(oar->ar_user) : NULL); 00197 nar->ar_group = (oar->ar_group ? xstrdup(oar->ar_group) : NULL); 00198 nar->ar_fmode = oar->ar_fmode; 00199 nar->ar_dmode = oar->ar_dmode; 00200 } 00201 00202 #if 0 00203 00205 static void dumpAttrRec(const char * msg, AttrRec ar) 00206 /*@globals fileSystem@*/ 00207 /*@modifies fileSystem @*/ 00208 { 00209 if (msg) 00210 fprintf(stderr, "%s:\t", msg); 00211 fprintf(stderr, "(%s, %s, %s, %s)\n", 00212 ar->ar_fmodestr, 00213 ar->ar_user, 00214 ar->ar_group, 00215 ar->ar_dmodestr); 00216 } 00217 #endif 00218 00223 /*@-boundswrite@*/ 00224 /*@null@*/ 00225 static char *strtokWithQuotes(/*@null@*/ char *s, char *delim) 00226 /*@modifies *s @*/ 00227 { 00228 static char *olds = NULL; 00229 char *token; 00230 00231 if (s == NULL) 00232 s = olds; 00233 if (s == NULL) 00234 return NULL; 00235 00236 /* Skip leading delimiters */ 00237 s += strspn(s, delim); 00238 if (*s == '\0') 00239 return NULL; 00240 00241 /* Find the end of the token. */ 00242 token = s; 00243 if (*token == '"') { 00244 token++; 00245 /* Find next " char */ 00246 s = strchr(token, '"'); 00247 } else { 00248 s = strpbrk(token, delim); 00249 } 00250 00251 /* Terminate it */ 00252 if (s == NULL) { 00253 /* This token finishes the string */ 00254 olds = strchr(token, '\0'); 00255 } else { 00256 /* Terminate the token and make olds point past it */ 00257 *s = '\0'; 00258 olds = s+1; 00259 } 00260 00261 /*@-retalias -temptrans @*/ 00262 return token; 00263 /*@=retalias =temptrans @*/ 00264 } 00265 /*@=boundswrite@*/ 00266 00269 static void timeCheck(int tc, Header h) 00270 /*@globals internalState @*/ 00271 /*@modifies internalState @*/ 00272 { 00273 HGE_t hge = (HGE_t)headerGetEntryMinMemory; 00274 HFD_t hfd = headerFreeData; 00275 int * mtime; 00276 const char ** files; 00277 rpmTagType fnt; 00278 int count, x; 00279 time_t currentTime = time(NULL); 00280 00281 x = hge(h, RPMTAG_OLDFILENAMES, &fnt, &files, &count); 00282 x = hge(h, RPMTAG_FILEMTIMES, NULL, &mtime, NULL); 00283 00284 /*@-boundsread@*/ 00285 for (x = 0; x < count; x++) { 00286 if ((currentTime - mtime[x]) > tc) 00287 rpmMessage(RPMMESS_WARNING, _("TIMECHECK failure: %s\n"), files[x]); 00288 } 00289 files = hfd(files, fnt); 00290 /*@=boundsread@*/ 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 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 /*@-boundswrite@*/ 00325 static int parseForVerify(char * buf, FileList fl) 00326 /*@modifies buf, fl->processingFailed, 00327 fl->currentVerifyFlags, fl->defVerifyFlags, 00328 fl->currentSpecdFlags, fl->defSpecdFlags @*/ 00329 { 00330 char *p, *pe, *q; 00331 const char *name; 00332 int *resultVerify; 00333 int negated; 00334 int verifyFlags; 00335 specdFlags * specdFlags; 00336 00337 if ((p = strstr(buf, (name = "%verify"))) != NULL) { 00338 resultVerify = &(fl->currentVerifyFlags); 00339 specdFlags = &fl->currentSpecdFlags; 00340 } else if ((p = strstr(buf, (name = "%defverify"))) != NULL) { 00341 resultVerify = &(fl->defVerifyFlags); 00342 specdFlags = &fl->defSpecdFlags; 00343 } else 00344 return 0; 00345 00346 for (pe = p; (pe-p) < strlen(name); pe++) 00347 *pe = ' '; 00348 00349 SKIPSPACE(pe); 00350 00351 if (*pe != '(') { 00352 rpmError(RPMERR_BADSPEC, _("Missing '(' in %s %s\n"), name, pe); 00353 fl->processingFailed = 1; 00354 return RPMERR_BADSPEC; 00355 } 00356 00357 /* Bracket %*verify args */ 00358 *pe++ = ' '; 00359 for (p = pe; *pe && *pe != ')'; pe++) 00360 {}; 00361 00362 if (*pe == '\0') { 00363 rpmError(RPMERR_BADSPEC, _("Missing ')' in %s(%s\n"), name, p); 00364 fl->processingFailed = 1; 00365 return RPMERR_BADSPEC; 00366 } 00367 00368 /* Localize. Erase parsed string */ 00369 q = alloca((pe-p) + 1); 00370 strncpy(q, p, pe-p); 00371 q[pe-p] = '\0'; 00372 while (p <= pe) 00373 *p++ = ' '; 00374 00375 negated = 0; 00376 verifyFlags = RPMVERIFY_NONE; 00377 00378 for (p = q; *p != '\0'; p = pe) { 00379 SKIPWHITE(p); 00380 if (*p == '\0') 00381 break; 00382 pe = p; 00383 SKIPNONWHITE(pe); 00384 if (*pe != '\0') 00385 *pe++ = '\0'; 00386 00387 { VFA_t *vfa; 00388 for (vfa = verifyAttrs; vfa->attribute != NULL; vfa++) { 00389 if (strcmp(p, vfa->attribute)) 00390 /*@innercontinue@*/ continue; 00391 verifyFlags |= vfa->flag; 00392 /*@innerbreak@*/ break; 00393 } 00394 if (vfa->attribute) 00395 continue; 00396 } 00397 00398 if (!strcmp(p, "not")) { 00399 negated ^= 1; 00400 } else { 00401 rpmError(RPMERR_BADSPEC, _("Invalid %s token: %s\n"), name, p); 00402 fl->processingFailed = 1; 00403 return RPMERR_BADSPEC; 00404 } 00405 } 00406 00407 *resultVerify = negated ? ~(verifyFlags) : verifyFlags; 00408 *specdFlags |= SPECD_VERIFY; 00409 00410 return 0; 00411 } 00412 /*@=boundswrite@*/ 00413 00414 #define isAttrDefault(_ars) ((_ars)[0] == '-' && (_ars)[1] == '\0') 00415 00422 /*@-boundswrite@*/ 00423 static int parseForDev(char * buf, FileList fl) 00424 /*@modifies buf, fl->processingFailed, 00425 fl->noGlob, fl->devtype, fl->devmajor, fl->devminor @*/ 00426 { 00427 const char * name; 00428 const char * errstr = NULL; 00429 char *p, *pe, *q; 00430 int rc = RPMERR_BADSPEC; /* assume error */ 00431 00432 if ((p = strstr(buf, (name = "%dev"))) == NULL) 00433 return 0; 00434 00435 for (pe = p; (pe-p) < strlen(name); pe++) 00436 *pe = ' '; 00437 SKIPSPACE(pe); 00438 00439 if (*pe != '(') { 00440 errstr = "'('"; 00441 goto exit; 00442 } 00443 00444 /* Bracket %dev args */ 00445 *pe++ = ' '; 00446 for (p = pe; *pe && *pe != ')'; pe++) 00447 {}; 00448 if (*pe != ')') { 00449 errstr = "')'"; 00450 goto exit; 00451 } 00452 00453 /* Localize. Erase parsed string */ 00454 q = alloca((pe-p) + 1); 00455 strncpy(q, p, pe-p); 00456 q[pe-p] = '\0'; 00457 while (p <= pe) 00458 *p++ = ' '; 00459 00460 p = q; SKIPWHITE(p); 00461 pe = p; SKIPNONWHITE(pe); if (*pe != '\0') *pe++ = '\0'; 00462 if (*p == 'b') 00463 fl->devtype = 'b'; 00464 else if (*p == 'c') 00465 fl->devtype = 'c'; 00466 else { 00467 errstr = "devtype"; 00468 goto exit; 00469 } 00470 00471 p = pe; SKIPWHITE(p); 00472 pe = p; SKIPNONWHITE(pe); if (*pe != '\0') *pe++ = '\0'; 00473 for (pe = p; *pe && xisdigit(*pe); pe++) 00474 {} ; 00475 if (*pe == '\0') { 00476 fl->devmajor = atoi(p); 00477 /*@-unsignedcompare @*/ /* LCL: ge is ok */ 00478 if (!(fl->devmajor >= 0 && fl->devmajor < 256)) { 00479 errstr = "devmajor"; 00480 goto exit; 00481 } 00482 /*@=unsignedcompare @*/ 00483 pe++; 00484 } else { 00485 errstr = "devmajor"; 00486 goto exit; 00487 } 00488 00489 p = pe; SKIPWHITE(p); 00490 pe = p; SKIPNONWHITE(pe); if (*pe != '\0') *pe++ = '\0'; 00491 for (pe = p; *pe && xisdigit(*pe); pe++) 00492 {} ; 00493 if (*pe == '\0') { 00494 fl->devminor = atoi(p); 00495 if (!(fl->devminor >= 0 && fl->devminor < 256)) { 00496 errstr = "devminor"; 00497 goto exit; 00498 } 00499 pe++; 00500 } else { 00501 errstr = "devminor"; 00502 goto exit; 00503 } 00504 00505 fl->noGlob = 1; 00506 00507 rc = 0; 00508 00509 exit: 00510 if (rc) { 00511 rpmError(RPMERR_BADSPEC, _("Missing %s in %s %s\n"), errstr, name, p); 00512 fl->processingFailed = 1; 00513 } 00514 return rc; 00515 } 00516 /*@=boundswrite@*/ 00517 00524 /*@-boundswrite@*/ 00525 static int parseForAttr(char * buf, FileList fl) 00526 /*@modifies buf, fl->processingFailed, 00527 fl->cur_ar, fl->def_ar, 00528 fl->currentSpecdFlags, fl->defSpecdFlags @*/ 00529 { 00530 const char *name; 00531 char *p, *pe, *q; 00532 int x; 00533 struct AttrRec_s arbuf; 00534 AttrRec ar = &arbuf, ret_ar; 00535 specdFlags * specdFlags; 00536 00537 if ((p = strstr(buf, (name = "%attr"))) != NULL) { 00538 ret_ar = &(fl->cur_ar); 00539 specdFlags = &fl->currentSpecdFlags; 00540 } else if ((p = strstr(buf, (name = "%defattr"))) != NULL) { 00541 ret_ar = &(fl->def_ar); 00542 specdFlags = &fl->defSpecdFlags; 00543 } else 00544 return 0; 00545 00546 for (pe = p; (pe-p) < strlen(name); pe++) 00547 *pe = ' '; 00548 00549 SKIPSPACE(pe); 00550 00551 if (*pe != '(') { 00552 rpmError(RPMERR_BADSPEC, _("Missing '(' in %s %s\n"), name, pe); 00553 fl->processingFailed = 1; 00554 return RPMERR_BADSPEC; 00555 } 00556 00557 /* Bracket %*attr args */ 00558 *pe++ = ' '; 00559 for (p = pe; *pe && *pe != ')'; pe++) 00560 {}; 00561 00562 if (ret_ar == &(fl->def_ar)) { /* %defattr */ 00563 q = pe; 00564 q++; 00565 SKIPSPACE(q); 00566 if (*q != '\0') { 00567 rpmError(RPMERR_BADSPEC, 00568 _("Non-white space follows %s(): %s\n"), name, q); 00569 fl->processingFailed = 1; 00570 return RPMERR_BADSPEC; 00571 } 00572 } 00573 00574 /* Localize. Erase parsed string */ 00575 q = alloca((pe-p) + 1); 00576 strncpy(q, p, pe-p); 00577 q[pe-p] = '\0'; 00578 while (p <= pe) 00579 *p++ = ' '; 00580 00581 nullAttrRec(ar); 00582 00583 p = q; SKIPWHITE(p); 00584 if (*p != '\0') { 00585 pe = p; SKIPNONWHITE(pe); if (*pe != '\0') *pe++ = '\0'; 00586 ar->ar_fmodestr = p; 00587 p = pe; SKIPWHITE(p); 00588 } 00589 if (*p != '\0') { 00590 pe = p; SKIPNONWHITE(pe); if (*pe != '\0') *pe++ = '\0'; 00591 ar->ar_user = p; 00592 p = pe; SKIPWHITE(p); 00593 } 00594 if (*p != '\0') { 00595 pe = p; SKIPNONWHITE(pe); if (*pe != '\0') *pe++ = '\0'; 00596 ar->ar_group = p; 00597 p = pe; SKIPWHITE(p); 00598 } 00599 if (*p != '\0' && ret_ar == &(fl->def_ar)) { /* %defattr */ 00600 pe = p; SKIPNONWHITE(pe); if (*pe != '\0') *pe++ = '\0'; 00601 ar->ar_dmodestr = p; 00602 p = pe; SKIPWHITE(p); 00603 } 00604 00605 if (!(ar->ar_fmodestr && ar->ar_user && ar->ar_group) || *p != '\0') { 00606 rpmError(RPMERR_BADSPEC, _("Bad syntax: %s(%s)\n"), name, q); 00607 fl->processingFailed = 1; 00608 return RPMERR_BADSPEC; 00609 } 00610 00611 /* Do a quick test on the mode argument and adjust for "-" */ 00612 if (ar->ar_fmodestr && !isAttrDefault(ar->ar_fmodestr)) { 00613 unsigned int ui; 00614 x = sscanf(ar->ar_fmodestr, "%o", &ui); 00615 if ((x == 0) || (ar->ar_fmode & ~MYALLPERMS)) { 00616 rpmError(RPMERR_BADSPEC, _("Bad mode spec: %s(%s)\n"), name, q); 00617 fl->processingFailed = 1; 00618 return RPMERR_BADSPEC; 00619 } 00620 ar->ar_fmode = ui; 00621 } else 00622 ar->ar_fmodestr = NULL; 00623 00624 if (ar->ar_dmodestr && !isAttrDefault(ar->ar_dmodestr)) { 00625 unsigned int ui; 00626 x = sscanf(ar->ar_dmodestr, "%o", &ui); 00627 if ((x == 0) || (ar->ar_dmode & ~MYALLPERMS)) { 00628 rpmError(RPMERR_BADSPEC, _("Bad dirmode spec: %s(%s)\n"), name, q); 00629 fl->processingFailed = 1; 00630 return RPMERR_BADSPEC; 00631 } 00632 ar->ar_dmode = ui; 00633 } else 00634 ar->ar_dmodestr = NULL; 00635 00636 if (!(ar->ar_user && !isAttrDefault(ar->ar_user))) 00637 ar->ar_user = NULL; 00638 00639 if (!(ar->ar_group && !isAttrDefault(ar->ar_group))) 00640 ar->ar_group = NULL; 00641 00642 dupAttrRec(ar, ret_ar); 00643 00644 /* XXX fix all this */ 00645 *specdFlags |= SPECD_UID | SPECD_GID | SPECD_FILEMODE | SPECD_DIRMODE; 00646 00647 return 0; 00648 } 00649 /*@=boundswrite@*/ 00650 00657 /*@-boundswrite@*/ 00658 static int parseForConfig(char * buf, FileList fl) 00659 /*@modifies buf, fl->processingFailed, fl->currentFlags @*/ 00660 { 00661 char *p, *pe, *q; 00662 const char *name; 00663 00664 if ((p = strstr(buf, (name = "%config"))) == NULL) 00665 return 0; 00666 00667 fl->currentFlags |= RPMFILE_CONFIG; 00668 00669 /* Erase "%config" token. */ 00670 for (pe = p; (pe-p) < strlen(name); pe++) 00671 *pe = ' '; 00672 SKIPSPACE(pe); 00673 if (*pe != '(') 00674 return 0; 00675 00676 /* Bracket %config args */ 00677 *pe++ = ' '; 00678 for (p = pe; *pe && *pe != ')'; pe++) 00679 {}; 00680 00681 if (*pe == '\0') { 00682 rpmError(RPMERR_BADSPEC, _("Missing ')' in %s(%s\n"), name, p); 00683 fl->processingFailed = 1; 00684 return RPMERR_BADSPEC; 00685 } 00686 00687 /* Localize. Erase parsed string. */ 00688 q = alloca((pe-p) + 1); 00689 strncpy(q, p, pe-p); 00690 q[pe-p] = '\0'; 00691 while (p <= pe) 00692 *p++ = ' '; 00693 00694 for (p = q; *p != '\0'; p = pe) { 00695 SKIPWHITE(p); 00696 if (*p == '\0') 00697 break; 00698 pe = p; 00699 SKIPNONWHITE(pe); 00700 if (*pe != '\0') 00701 *pe++ = '\0'; 00702 if (!strcmp(p, "missingok")) { 00703 fl->currentFlags |= RPMFILE_MISSINGOK; 00704 } else if (!strcmp(p, "noreplace")) { 00705 fl->currentFlags |= RPMFILE_NOREPLACE; 00706 } else { 00707 rpmError(RPMERR_BADSPEC, _("Invalid %s token: %s\n"), name, p); 00708 fl->processingFailed = 1; 00709 return RPMERR_BADSPEC; 00710 } 00711 } 00712 00713 return 0; 00714 } 00715 /*@=boundswrite@*/ 00716 00719 static int langCmp(const void * ap, const void * bp) 00720 /*@*/ 00721 { 00722 /*@-boundsread@*/ 00723 return strcmp(*(const char **)ap, *(const char **)bp); 00724 /*@=boundsread@*/ 00725 } 00726 00733 /*@-bounds@*/ 00734 static int parseForLang(char * buf, FileList fl) 00735 /*@modifies buf, fl->processingFailed, 00736 fl->currentLangs, fl->nLangs @*/ 00737 { 00738 char *p, *pe, *q; 00739 const char *name; 00740 00741 while ((p = strstr(buf, (name = "%lang"))) != NULL) { 00742 00743 for (pe = p; (pe-p) < strlen(name); pe++) 00744 *pe = ' '; 00745 SKIPSPACE(pe); 00746 00747 if (*pe != '(') { 00748 rpmError(RPMERR_BADSPEC, _("Missing '(' in %s %s\n"), name, pe); 00749 fl->processingFailed = 1; 00750 return RPMERR_BADSPEC; 00751 } 00752 00753 /* Bracket %lang args */ 00754 *pe++ = ' '; 00755 for (pe = p; *pe && *pe != ')'; pe++) 00756 {}; 00757 00758 if (*pe == '\0') { 00759 rpmError(RPMERR_BADSPEC, _("Missing ')' in %s(%s\n"), name, p); 00760 fl->processingFailed = 1; 00761 return RPMERR_BADSPEC; 00762 } 00763 00764 /* Localize. Erase parsed string. */ 00765 q = alloca((pe-p) + 1); 00766 strncpy(q, p, pe-p); 00767 q[pe-p] = '\0'; 00768 while (p <= pe) 00769 *p++ = ' '; 00770 00771 /* Parse multiple arguments from %lang */ 00772 for (p = q; *p != '\0'; p = pe) { 00773 char *newp; 00774 size_t np; 00775 int i; 00776 00777 SKIPWHITE(p); 00778 pe = p; 00779 SKIPNONWHITE(pe); 00780 00781 np = pe - p; 00782 00783 /* Sanity check on locale lengths */ 00784 if (np < 1 || (np == 1 && *p != 'C') || np >= 32) { 00785 rpmError(RPMERR_BADSPEC, 00786 _("Unusual locale length: \"%.*s\" in %%lang(%s)\n"), 00787 (int)np, p, q); 00788 fl->processingFailed = 1; 00789 return RPMERR_BADSPEC; 00790 } 00791 00792 /* Check for duplicate locales */ 00793 if (fl->currentLangs != NULL) 00794 for (i = 0; i < fl->nLangs; i++) { 00795 if (strncmp(fl->currentLangs[i], p, np)) 00796 /*@innercontinue@*/ continue; 00797 rpmError(RPMERR_BADSPEC, _("Duplicate locale %.*s in %%lang(%s)\n"), 00798 (int)np, p, q); 00799 fl->processingFailed = 1; 00800 return RPMERR_BADSPEC; 00801 } 00802 00803 /* Add new locale */ 00804 fl->currentLangs = xrealloc(fl->currentLangs, 00805 (fl->nLangs + 1) * sizeof(*fl->currentLangs)); 00806 newp = xmalloc( np+1 ); 00807 strncpy(newp, p, np); 00808 newp[np] = '\0'; 00809 fl->currentLangs[fl->nLangs++] = newp; 00810 if (*pe == ',') pe++; /* skip , if present */ 00811 } 00812 } 00813 00814 /* Insure that locales are sorted. */ 00815 if (fl->currentLangs) 00816 qsort(fl->currentLangs, fl->nLangs, sizeof(*fl->currentLangs), langCmp); 00817 00818 return 0; 00819 } 00820 /*@=bounds@*/ 00821 00824 /*@-boundswrite@*/ 00825 static int parseForRegexLang(const char * fileName, /*@out@*/ char ** lang) 00826 /*@globals rpmGlobalMacroContext, h_errno @*/ 00827 /*@modifies *lang, rpmGlobalMacroContext @*/ 00828 { 00829 static int initialized = 0; 00830 static int hasRegex = 0; 00831 static regex_t compiledPatt; 00832 static char buf[BUFSIZ]; 00833 int x; 00834 regmatch_t matches[2]; 00835 const char *s; 00836 00837 if (! initialized) { 00838 const char *patt = rpmExpand("%{?_langpatt}", NULL); 00839 int rc = 0; 00840 if (!(patt && *patt != '\0')) 00841 rc = 1; 00842 else if (regcomp(&compiledPatt, patt, REG_EXTENDED)) 00843 rc = -1; 00844 patt = _free(patt); 00845 if (rc) 00846 return rc; 00847 hasRegex = 1; 00848 initialized = 1; 00849 } 00850 00851 memset(matches, 0, sizeof(matches)); 00852 if (! hasRegex || regexec(&compiledPatt, fileName, 2, matches, REG_NOTEOL)) 00853 return 1; 00854 00855 /* Got match */ 00856 s = fileName + matches[1].rm_eo - 1; 00857 x = matches[1].rm_eo - matches[1].rm_so; 00858 buf[x] = '\0'; 00859 while (x) { 00860 buf[--x] = *s--; 00861 } 00862 if (lang) 00863 *lang = buf; 00864 return 0; 00865 } 00866 /*@=boundswrite@*/ 00867 00870 /*@-exportlocal -exportheadervar@*/ 00871 /*@unchecked@*/ 00872 VFA_t virtualFileAttributes[] = { 00873 { "%dir", 0, 0 }, /* XXX why not RPMFILE_DIR? */ 00874 { "%doc", 0, RPMFILE_DOC }, 00875 { "%ghost", 0, RPMFILE_GHOST }, 00876 { "%exclude", 0, RPMFILE_EXCLUDE }, 00877 { "%readme", 0, RPMFILE_README }, 00878 { "%license", 0, RPMFILE_LICENSE }, 00879 { "%pubkey", 0, RPMFILE_PUBKEY }, 00880 { "%policy", 0, RPMFILE_POLICY }, 00881 00882 #if WHY_NOT 00883 { "%icon", 0, RPMFILE_ICON }, 00884 { "%spec", 0, RPMFILE_SPEC }, 00885 { "%config", 0, RPMFILE_CONFIG }, 00886 { "%missingok", 0, RPMFILE_CONFIG|RPMFILE_MISSINGOK }, 00887 { "%noreplace", 0, RPMFILE_CONFIG|RPMFILE_NOREPLACE }, 00888 #endif 00889 00890 { NULL, 0, 0 } 00891 }; 00892 /*@=exportlocal =exportheadervar@*/ 00893 00903 /*@-boundswrite@*/ 00904 static int parseForSimple(/*@unused@*/Spec spec, Package pkg, char * buf, 00905 FileList fl, /*@out@*/ const char ** fileName) 00906 /*@globals rpmGlobalMacroContext, h_errno @*/ 00907 /*@modifies buf, fl->processingFailed, *fileName, 00908 fl->currentFlags, 00909 fl->docDirs, fl->docDirCount, fl->isDir, 00910 fl->passedSpecialDoc, fl->isSpecialDoc, 00911 pkg->specialDoc, rpmGlobalMacroContext @*/ 00912 { 00913 char *s, *t; 00914 int res, specialDoc = 0; 00915 char specialDocBuf[BUFSIZ]; 00916 00917 specialDocBuf[0] = '\0'; 00918 *fileName = NULL; 00919 res = 0; 00920 00921 t = buf; 00922 while ((s = strtokWithQuotes(t, " \t\n")) != NULL) { 00923 t = NULL; 00924 if (!strcmp(s, "%docdir")) { 00925 s = strtokWithQuotes(NULL, " \t\n"); 00926 if (fl->docDirCount == MAXDOCDIR) { 00927 rpmError(RPMERR_INTERNAL, _("Hit limit for %%docdir\n")); 00928 fl->processingFailed = 1; 00929 res = 1; 00930 } 00931 00932 if (s != NULL) 00933 fl->docDirs[fl->docDirCount++] = xstrdup(s); 00934 if (s == NULL || strtokWithQuotes(NULL, " \t\n")) { 00935 rpmError(RPMERR_INTERNAL, _("Only one arg for %%docdir\n")); 00936 fl->processingFailed = 1; 00937 res = 1; 00938 } 00939 break; 00940 } 00941 #if defined(__LCLINT__) 00942 assert(s != NULL); 00943 #endif 00944 00945 /* Set flags for virtual file attributes */ 00946 { VFA_t *vfa; 00947 for (vfa = virtualFileAttributes; vfa->attribute != NULL; vfa++) { 00948 if (strcmp(s, vfa->attribute)) 00949 /*@innercontinue@*/ continue; 00950 if (!vfa->flag) { 00951 if (!strcmp(s, "%dir")) 00952 fl->isDir = 1; /* XXX why not RPMFILE_DIR? */ 00953 } else { 00954 if (vfa->not) 00955 fl->currentFlags &= ~vfa->flag; 00956 else 00957 fl->currentFlags |= vfa->flag; 00958 } 00959 00960 /*@innerbreak@*/ break; 00961 } 00962 /* if we got an attribute, continue with next token */ 00963 if (vfa->attribute != NULL) 00964 continue; 00965 } 00966 00967 if (*fileName) { 00968 /* We already got a file -- error */ 00969 rpmError(RPMERR_BADSPEC, _("Two files on one line: %s\n"), 00970 *fileName); 00971 fl->processingFailed = 1; 00972 res = 1; 00973 } 00974 00975 /*@-branchstate@*/ 00976 if (*s != '/') { 00977 if (fl->currentFlags & RPMFILE_DOC) { 00978 specialDoc = 1; 00979 strcat(specialDocBuf, " "); 00980 strcat(specialDocBuf, s); 00981 } else 00982 if (fl->currentFlags & (RPMFILE_POLICY|RPMFILE_PUBKEY|RPMFILE_ICON)) 00983 { 00984 *fileName = s; 00985 } else { 00986 const char * sfn = NULL; 00987 int urltype = urlPath(s, &sfn); 00988 switch (urltype) { 00989 default: /* relative path, not in %doc and not a URL */ 00990 rpmError(RPMERR_BADSPEC, 00991 _("File must begin with \"/\": %s\n"), s); 00992 fl->processingFailed = 1; 00993 res = 1; 00994 /*@switchbreak@*/ break; 00995 case URL_IS_PATH: 00996 *fileName = s; 00997 /*@switchbreak@*/ break; 00998 } 00999 } 01000 } else { 01001 *fileName = s; 01002 } 01003 /*@=branchstate@*/ 01004 } 01005 01006 if (specialDoc) { 01007 if (*fileName || (fl->currentFlags & ~(RPMFILE_DOC))) { 01008 rpmError(RPMERR_BADSPEC, 01009 _("Can't mix special %%doc with other forms: %s\n"), 01010 (*fileName ? *fileName : "")); 01011 fl->processingFailed = 1; 01012 res = 1; 01013 } else { 01014 /* XXX WATCHOUT: buf is an arg */ 01015 { static char *_docdir_fmt= 0; 01016 static int oneshot = 0; 01017 const char *ddir, *fmt, *errstr; 01018 if (!oneshot) { 01019 _docdir_fmt = rpmExpand("%{?_docdir_fmt}", NULL); 01020 if (!_docdir_fmt || !*_docdir_fmt) 01021 _docdir_fmt = "%{NAME}-%{VERSION}"; 01022 oneshot = 1; 01023 } 01024 fmt = headerSprintf(pkg->header, _docdir_fmt, rpmTagTable, rpmHeaderFormats, &errstr); 01025 if (!fmt) { 01026 rpmError(RPMERR_BADSPEC, _("illegal _docdir_fmt: %s\n"), errstr); 01027 fl->processingFailed = 1; 01028 res = 1; 01029 } 01030 ddir = rpmGetPath("%{_docdir}/", fmt, NULL); 01031 strcpy(buf, ddir); 01032 ddir = _free(ddir); 01033 } 01034 01035 /* XXX FIXME: this is easy to do as macro expansion */ 01036 01037 if (! fl->passedSpecialDoc) { 01038 char *compress_doc; 01039 01040 pkg->specialDoc = newStringBuf(); 01041 appendStringBuf(pkg->specialDoc, "DOCDIR=\"$RPM_BUILD_ROOT\""); 01042 appendLineStringBuf(pkg->specialDoc, buf); 01043 appendLineStringBuf(pkg->specialDoc, "export DOCDIR"); 01044 appendLineStringBuf(pkg->specialDoc, "rm -rf \"$DOCDIR\""); 01045 appendLineStringBuf(pkg->specialDoc, MKDIR_P " \"$DOCDIR\""); 01046 01047 compress_doc = rpmExpand("%{__compress_doc}", NULL); 01048 if (compress_doc && *compress_doc != '%') 01049 appendLineStringBuf(pkg->specialDoc, compress_doc); 01050 compress_doc = _free(compress_doc); 01051 01052 /*@-temptrans@*/ 01053 *fileName = buf; 01054 /*@=temptrans@*/ 01055 fl->passedSpecialDoc = 1; 01056 fl->isSpecialDoc = 1; 01057 } 01058 01059 appendStringBuf(pkg->specialDoc, "cp -pr "); 01060 appendStringBuf(pkg->specialDoc, specialDocBuf); 01061 appendLineStringBuf(pkg->specialDoc, " \"$DOCDIR\""); 01062 01063 { 01064 char *compress_doc; 01065 01066 compress_doc = rpmExpand("%{__compress_doc}", NULL); 01067 if (compress_doc && *compress_doc != '%') 01068 appendLineStringBuf(pkg->specialDoc, compress_doc); 01069 if (compress_doc) 01070 free(compress_doc); 01071 } 01072 } 01073 } 01074 01075 return res; 01076 } 01077 /*@=boundswrite@*/ 01078 01081 static int compareFileListRecs(const void * ap, const void * bp) /*@*/ 01082 { 01083 const char *aurl = ((FileListRec)ap)->fileURL; 01084 const char *a = NULL; 01085 const char *burl = ((FileListRec)bp)->fileURL; 01086 const char *b = NULL; 01087 (void) urlPath(aurl, &a); 01088 (void) urlPath(burl, &b); 01089 return strcmp(a, b); 01090 } 01091 01099 static int isDoc(FileList fl, const char * fileName) /*@*/ 01100 { 01101 int x = fl->docDirCount; 01102 01103 while (x--) { 01104 if (strstr(fileName, fl->docDirs[x]) == fileName) 01105 return 1; 01106 } 01107 return 0; 01108 } 01109 01116 static int checkHardLinks(FileList fl) 01117 /*@*/ 01118 { 01119 FileListRec ilp, jlp; 01120 int i, j; 01121 01122 for (i = 0; i < fl->fileListRecsUsed; i++) { 01123 ilp = fl->fileList + i; 01124 if (!(S_ISREG(ilp->fl_mode) && ilp->fl_nlink > 1)) 01125 continue; 01126 if (ilp->flags & (RPMFILE_EXCLUDE | RPMFILE_GHOST)) 01127 continue; 01128 01129 for (j = i + 1; j < fl->fileListRecsUsed; j++) { 01130 jlp = fl->fileList + j; 01131 if (!S_ISREG(jlp->fl_mode)) 01132 /*@innercontinue@*/ continue; 01133 if (ilp->fl_nlink != jlp->fl_nlink) 01134 /*@innercontinue@*/ continue; 01135 if (ilp->fl_ino != jlp->fl_ino) 01136 /*@innercontinue@*/ continue; 01137 if (ilp->fl_dev != jlp->fl_dev) 01138 /*@innercontinue@*/ continue; 01139 if (jlp->flags & (RPMFILE_EXCLUDE | RPMFILE_GHOST)) 01140 continue; 01141 return 1; 01142 } 01143 } 01144 return 0; 01145 } 01146 01147 /*@-boundsread@*/ 01148 static int dncmp(const void * a, const void * b) 01149 /*@*/ 01150 { 01151 const char ** aurlp = a; 01152 const char ** burlp = b; 01153 const char * adn; 01154 const char * bdn; 01155 (void) urlPath(*aurlp, &adn); 01156 (void) urlPath(*burlp, &bdn); 01157 return strcmp(adn, bdn); 01158 } 01159 /*@=boundsread@*/ 01160 01161 /*@-bounds@*/ 01166 static void compressFilelist(Header h) 01167 /*@modifies h @*/ 01168 { 01169 HGE_t hge = (HGE_t)headerGetEntryMinMemory; 01170 HAE_t hae = (HAE_t)headerAddEntry; 01171 HRE_t hre = (HRE_t)headerRemoveEntry; 01172 HFD_t hfd = headerFreeData; 01173 char ** fileNames; 01174 const char * fn; 01175 const char ** dirNames; 01176 const char ** baseNames; 01177 int_32 * dirIndexes; 01178 rpmTagType fnt; 01179 int count; 01180 int i, xx; 01181 int dirIndex = -1; 01182 01183 /* 01184 * This assumes the file list is already sorted, and begins with a 01185 * single '/'. That assumption isn't critical, but it makes things go 01186 * a bit faster. 01187 */ 01188 01189 if (headerIsEntry(h, RPMTAG_DIRNAMES)) { 01190 xx = hre(h, RPMTAG_OLDFILENAMES); 01191 return; /* Already converted. */ 01192 } 01193 01194 if (!hge(h, RPMTAG_OLDFILENAMES, &fnt, &fileNames, &count)) 01195 return; /* no file list */ 01196 if (fileNames == NULL || count <= 0) 01197 return; 01198 01199 dirNames = alloca(sizeof(*dirNames) * count); /* worst case */ 01200 baseNames = alloca(sizeof(*dirNames) * count); 01201 dirIndexes = alloca(sizeof(*dirIndexes) * count); 01202 01203 (void) urlPath(fileNames[0], &fn); 01204 if (fn[0] != '/') { 01205 /* HACK. Source RPM, so just do things differently */ 01206 dirIndex = 0; 01207 dirNames[dirIndex] = ""; 01208 for (i = 0; i < count; i++) { 01209 dirIndexes[i] = dirIndex; 01210 baseNames[i] = fileNames[i]; 01211 } 01212 goto exit; 01213 } 01214 01215 /*@-branchstate@*/ 01216 for (i = 0; i < count; i++) { 01217 const char ** needle; 01218 char savechar; 01219 char * baseName; 01220 int 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 /*@=branchstate@*/ 01245 01246 exit: 01247 if (count > 0) { 01248 xx = hae(h, RPMTAG_DIRINDEXES, RPM_INT32_TYPE, dirIndexes, count); 01249 xx = hae(h, RPMTAG_BASENAMES, RPM_STRING_ARRAY_TYPE, 01250 baseNames, count); 01251 xx = hae(h, RPMTAG_DIRNAMES, RPM_STRING_ARRAY_TYPE, 01252 dirNames, dirIndex + 1); 01253 } 01254 01255 fileNames = hfd(fileNames, fnt); 01256 01257 xx = hre(h, RPMTAG_OLDFILENAMES); 01258 } 01259 /*@=bounds@*/ 01260 01270 /*@-bounds@*/ 01271 static void genCpioListAndHeader(/*@partial@*/ FileList fl, 01272 rpmfi * fip, Header h, int isSrc) 01273 /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/ 01274 /*@modifies h, *fip, fl->processingFailed, fl->fileList, 01275 rpmGlobalMacroContext, fileSystem, internalState @*/ 01276 { 01277 const char * apath; 01278 int _addDotSlash = !isSrc; 01279 int apathlen = 0; 01280 int dpathlen = 0; 01281 int skipLen = 0; 01282 security_context_t scon = NULL; 01283 const char * sxfn; 01284 size_t fnlen; 01285 FileListRec flp; 01286 char buf[BUFSIZ]; 01287 int i, xx; 01288 01289 /* Sort the big list */ 01290 qsort(fl->fileList, fl->fileListRecsUsed, 01291 sizeof(*(fl->fileList)), compareFileListRecs); 01292 01293 /* Generate the header. */ 01294 if (! isSrc) { 01295 skipLen = 1; 01296 if (fl->prefix) 01297 skipLen += strlen(fl->prefix); 01298 } 01299 01300 sxfn = rpmGetPath("%{?_build_file_context_path}", NULL); 01301 if (sxfn != NULL && *sxfn != '\0') 01302 xx = matchpathcon_init(sxfn); 01303 01304 for (i = 0, flp = fl->fileList; i < fl->fileListRecsUsed; i++, flp++) { 01305 const char *s; 01306 01307 /* Merge duplicate entries. */ 01308 while (i < (fl->fileListRecsUsed - 1) && 01309 !strcmp(flp->fileURL, flp[1].fileURL)) { 01310 01311 /* Two entries for the same file found, merge the entries. */ 01312 /* Note that an %exclude is a duplication of a file reference */ 01313 01314 /* file flags */ 01315 flp[1].flags |= flp->flags; 01316 01317 if (!(flp[1].flags & RPMFILE_EXCLUDE)) 01318 rpmMessage(RPMMESS_WARNING, _("File listed twice: %s\n"), 01319 flp->fileURL); 01320 01321 /* file mode */ 01322 if (S_ISDIR(flp->fl_mode)) { 01323 if ((flp[1].specdFlags & (SPECD_DIRMODE | SPECD_DEFDIRMODE)) < 01324 (flp->specdFlags & (SPECD_DIRMODE | SPECD_DEFDIRMODE))) 01325 flp[1].fl_mode = flp->fl_mode; 01326 } else { 01327 if ((flp[1].specdFlags & (SPECD_FILEMODE | SPECD_DEFFILEMODE)) < 01328 (flp->specdFlags & (SPECD_FILEMODE | SPECD_DEFFILEMODE))) 01329 flp[1].fl_mode = flp->fl_mode; 01330 } 01331 01332 /* uid */ 01333 if ((flp[1].specdFlags & (SPECD_UID | SPECD_DEFUID)) < 01334 (flp->specdFlags & (SPECD_UID | SPECD_DEFUID))) 01335 { 01336 flp[1].fl_uid = flp->fl_uid; 01337 flp[1].uname = flp->uname; 01338 } 01339 01340 /* gid */ 01341 if ((flp[1].specdFlags & (SPECD_GID | SPECD_DEFGID)) < 01342 (flp->specdFlags & (SPECD_GID | SPECD_DEFGID))) 01343 { 01344 flp[1].fl_gid = flp->fl_gid; 01345 flp[1].gname = flp->gname; 01346 } 01347 01348 /* verify flags */ 01349 if ((flp[1].specdFlags & (SPECD_VERIFY | SPECD_DEFVERIFY)) < 01350 (flp->specdFlags & (SPECD_VERIFY | SPECD_DEFVERIFY))) 01351 flp[1].verifyFlags = flp->verifyFlags; 01352 01353 /* XXX to-do: language */ 01354 01355 flp++; i++; 01356 } 01357 01358 /* Skip files that were marked with %exclude. */ 01359 if (flp->flags & RPMFILE_EXCLUDE) continue; 01360 01361 /* Omit '/' and/or URL prefix, leave room for "./" prefix */ 01362 (void) urlPath(flp->fileURL, &apath); 01363 apathlen += (strlen(apath) - skipLen + (_addDotSlash ? 3 : 1)); 01364 01365 /* Leave room for both dirname and basename NUL's */ 01366 dpathlen += (strlen(flp->diskURL) + 2); 01367 01368 /* 01369 * Make the header, the OLDFILENAMES will get converted to a 01370 * compressed file list write before we write the actual package to 01371 * disk. 01372 */ 01373 (void) headerAddOrAppendEntry(h, RPMTAG_OLDFILENAMES, RPM_STRING_ARRAY_TYPE, 01374 &(flp->fileURL), 1); 01375 01376 /*@-sizeoftype@*/ 01377 if (sizeof(flp->fl_size) != sizeof(uint_32)) { 01378 uint_32 psize = (uint_32)flp->fl_size; 01379 (void) headerAddOrAppendEntry(h, RPMTAG_FILESIZES, RPM_INT32_TYPE, 01380 &(psize), 1); 01381 } else { 01382 (void) headerAddOrAppendEntry(h, RPMTAG_FILESIZES, RPM_INT32_TYPE, 01383 &(flp->fl_size), 1); 01384 } 01385 (void) headerAddOrAppendEntry(h, RPMTAG_FILEUSERNAME, RPM_STRING_ARRAY_TYPE, 01386 &(flp->uname), 1); 01387 (void) headerAddOrAppendEntry(h, RPMTAG_FILEGROUPNAME, RPM_STRING_ARRAY_TYPE, 01388 &(flp->gname), 1); 01389 if (sizeof(flp->fl_mtime) != sizeof(uint_32)) { 01390 uint_32 mtime = (uint_32)flp->fl_mtime; 01391 (void) headerAddOrAppendEntry(h, RPMTAG_FILEMTIMES, RPM_INT32_TYPE, 01392 &(mtime), 1); 01393 } else { 01394 (void) headerAddOrAppendEntry(h, RPMTAG_FILEMTIMES, RPM_INT32_TYPE, 01395 &(flp->fl_mtime), 1); 01396 } 01397 if (sizeof(flp->fl_mode) != sizeof(uint_16)) { 01398 uint_16 pmode = (uint_16)flp->fl_mode; 01399 (void) headerAddOrAppendEntry(h, RPMTAG_FILEMODES, RPM_INT16_TYPE, 01400 &(pmode), 1); 01401 } else { 01402 (void) headerAddOrAppendEntry(h, RPMTAG_FILEMODES, RPM_INT16_TYPE, 01403 &(flp->fl_mode), 1); 01404 } 01405 if (sizeof(flp->fl_rdev) != sizeof(uint_16)) { 01406 uint_16 prdev = (uint_16)flp->fl_rdev; 01407 (void) headerAddOrAppendEntry(h, RPMTAG_FILERDEVS, RPM_INT16_TYPE, 01408 &(prdev), 1); 01409 } else { 01410 (void) headerAddOrAppendEntry(h, RPMTAG_FILERDEVS, RPM_INT16_TYPE, 01411 &(flp->fl_rdev), 1); 01412 } 01413 if (sizeof(flp->fl_dev) != sizeof(uint_32)) { 01414 uint_32 pdevice = (uint_32)flp->fl_dev; 01415 (void) headerAddOrAppendEntry(h, RPMTAG_FILEDEVICES, RPM_INT32_TYPE, 01416 &(pdevice), 1); 01417 } else { 01418 (void) headerAddOrAppendEntry(h, RPMTAG_FILEDEVICES, RPM_INT32_TYPE, 01419 &(flp->fl_dev), 1); 01420 } 01421 if (sizeof(flp->fl_ino) != sizeof(uint_32)) { 01422 uint_32 ino = (uint_32)flp->fl_ino; 01423 (void) headerAddOrAppendEntry(h, RPMTAG_FILEINODES, RPM_INT32_TYPE, 01424 &(ino), 1); 01425 } else { 01426 (void) headerAddOrAppendEntry(h, RPMTAG_FILEINODES, RPM_INT32_TYPE, 01427 &(flp->fl_ino), 1); 01428 } 01429 /*@=sizeoftype@*/ 01430 01431 (void) headerAddOrAppendEntry(h, RPMTAG_FILELANGS, RPM_STRING_ARRAY_TYPE, 01432 &(flp->langs), 1); 01433 01434 { static uint_32 source_file_dalgo = 0; 01435 static uint_32 binary_file_dalgo = 0; 01436 static int oneshot = 0; 01437 uint_32 dalgo = 0; 01438 01439 if (!oneshot) { 01440 source_file_dalgo = 01441 rpmExpandNumeric("%{?_build_source_file_digest_algo}"); 01442 binary_file_dalgo = 01443 rpmExpandNumeric("%{?_build_binary_file_digest_algo}"); 01444 oneshot++; 01445 } 01446 01447 dalgo = (isSrc ? source_file_dalgo : binary_file_dalgo); 01448 switch (dalgo) { 01449 case PGPHASHALGO_SHA1: 01450 case PGPHASHALGO_RIPEMD160: 01451 case PGPHASHALGO_MD2: 01452 case PGPHASHALGO_TIGER192: 01453 case PGPHASHALGO_SHA256: 01454 case PGPHASHALGO_SHA384: 01455 case PGPHASHALGO_SHA512: 01456 case PGPHASHALGO_MD4: 01457 case PGPHASHALGO_RIPEMD128: 01458 case PGPHASHALGO_CRC32: 01459 case PGPHASHALGO_ADLER32: 01460 case PGPHASHALGO_CRC64: 01461 (void) rpmlibNeedsFeature(h, "FileDigestParameterized", "4.4.6-1"); 01462 /*@switchbreak@*/ break; 01463 case PGPHASHALGO_MD5: 01464 case PGPHASHALGO_HAVAL_5_160: /* XXX unimplemented */ 01465 default: 01466 dalgo = PGPHASHALGO_MD5; 01467 /*@switchbreak@*/ break; 01468 } 01469 01470 buf[0] = '\0'; 01471 if (S_ISREG(flp->fl_mode)) 01472 (void) dodigest(dalgo, flp->diskURL, (unsigned char *)buf, 1, NULL); 01473 s = buf; 01474 (void) headerAddOrAppendEntry(h, RPMTAG_FILEDIGESTS, RPM_STRING_ARRAY_TYPE, 01475 &s, 1); 01476 (void) headerAddOrAppendEntry(h, RPMTAG_FILEDIGESTALGOS, RPM_INT32_TYPE, 01477 &dalgo, 1); 01478 } 01479 01480 buf[0] = '\0'; 01481 if (S_ISLNK(flp->fl_mode)) { 01482 int xx = Readlink(flp->diskURL, buf, BUFSIZ); 01483 if (xx >= 0) 01484 buf[xx] = '\0'; 01485 if (fl->buildRootURL) { 01486 const char * buildRoot; 01487 (void) urlPath(fl->buildRootURL, &buildRoot); 01488 01489 if (buf[0] == '/' && strcmp(buildRoot, "/") && 01490 !strncmp(buf, buildRoot, strlen(buildRoot))) { 01491 rpmError(RPMERR_BADSPEC, 01492 _("Symlink points to BuildRoot: %s -> %s\n"), 01493 flp->fileURL, buf); 01494 fl->processingFailed = 1; 01495 } 01496 } 01497 } 01498 s = buf; 01499 (void) headerAddOrAppendEntry(h, RPMTAG_FILELINKTOS, RPM_STRING_ARRAY_TYPE, 01500 &s, 1); 01501 01502 if (flp->flags & RPMFILE_GHOST) { 01503 flp->verifyFlags &= ~(RPMVERIFY_MD5 | RPMVERIFY_FILESIZE | 01504 RPMVERIFY_LINKTO | RPMVERIFY_MTIME); 01505 } 01506 (void) headerAddOrAppendEntry(h, RPMTAG_FILEVERIFYFLAGS, RPM_INT32_TYPE, 01507 &(flp->verifyFlags), 1); 01508 01509 if (!isSrc && isDoc(fl, flp->fileURL)) 01510 flp->flags |= RPMFILE_DOC; 01511 /* XXX Should directories have %doc/%config attributes? (#14531) */ 01512 if (S_ISDIR(flp->fl_mode)) 01513 flp->flags &= ~(RPMFILE_CONFIG|RPMFILE_DOC); 01514 01515 (void) headerAddOrAppendEntry(h, RPMTAG_FILEFLAGS, RPM_INT32_TYPE, 01516 &(flp->flags), 1); 01517 01518 /* Add file security context to package. */ 01519 { 01520 mode_t fmode = (uint_16)flp->fl_mode; 01521 static const char *nocon = ""; 01522 if (matchpathcon(flp->fileURL, fmode, &scon) || scon == NULL) 01523 scon = nocon; 01524 (void) headerAddOrAppendEntry(h, RPMTAG_FILECONTEXTS, RPM_STRING_ARRAY_TYPE, 01525 &scon, 1); 01526 if (scon != nocon) 01527 freecon(scon); 01528 } 01529 } 01530 sxfn = _free(sxfn); 01531 01532 compressFilelist(h); 01533 01534 { int scareMem = 0; 01535 rpmts ts = NULL; /* XXX FIXME drill rpmts ts all the way down here */ 01536 rpmfi fi = rpmfiNew(ts, h, RPMTAG_BASENAMES, scareMem); 01537 char * a, * d; 01538 01539 if (fi == NULL) return; /* XXX can't happen */ 01540 01541 /*@-onlytrans@*/ 01542 fi->te = xcalloc(1, sizeof(*fi->te)); 01543 /*@=onlytrans@*/ 01544 fi->te->type = TR_ADDED; 01545 01546 fi->dnl = _free(fi->dnl); 01547 fi->bnl = _free(fi->bnl); 01548 if (!scareMem) fi->dil = _free(fi->dil); 01549 01550 /* XXX Insure at least 1 byte is always allocated. */ 01551 fi->dnl = xmalloc(fi->fc * sizeof(*fi->dnl) + dpathlen + 1); 01552 d = (char *)(fi->dnl + fi->fc); 01553 *d = '\0'; 01554 01555 fi->bnl = xmalloc(fi->fc * (sizeof(*fi->bnl) + sizeof(*fi->dil))); 01556 /*@-dependenttrans@*/ /* FIX: artifact of spoofing headerGetEntry */ 01557 fi->dil = (!scareMem) 01558 ? xcalloc(sizeof(*fi->dil), fi->fc) 01559 : (int *)(fi->bnl + fi->fc); 01560 /*@=dependenttrans@*/ 01561 01562 /* XXX Insure at least 1 byte is always allocated. */ 01563 fi->apath = xmalloc(fi->fc * sizeof(*fi->apath) + apathlen + 1); 01564 a = (char *)(fi->apath + fi->fc); 01565 *a = '\0'; 01566 01567 fi->actions = xcalloc(sizeof(*fi->actions), fi->fc); 01568 fi->fmapflags = xcalloc(sizeof(*fi->fmapflags), fi->fc); 01569 fi->astriplen = 0; 01570 if (fl->buildRootURL) 01571 fi->astriplen = strlen(fl->buildRootURL); 01572 fi->striplen = 0; 01573 fi->fuser = NULL; 01574 fi->fgroup = NULL; 01575 01576 /* Make the cpio list */ 01577 if (fi->dil != NULL) /* XXX can't happen */ 01578 for (i = 0, flp = fl->fileList; i < fi->fc; i++, flp++) { 01579 char * b; 01580 01581 /* Skip (possible) duplicate file entries, use last entry info. */ 01582 while (((flp - fl->fileList) < (fl->fileListRecsUsed - 1)) && 01583 !strcmp(flp->fileURL, flp[1].fileURL)) 01584 flp++; 01585 01586 if (flp->flags & RPMFILE_EXCLUDE) { 01587 i--; 01588 continue; 01589 } 01590 01591 if ((fnlen = strlen(flp->diskURL) + 1) > fi->fnlen) 01592 fi->fnlen = fnlen; 01593 01594 /* Create disk directory and base name. */ 01595 fi->dil[i] = i; 01596 /*@-dependenttrans@*/ /* FIX: artifact of spoofing headerGetEntry */ 01597 fi->dnl[fi->dil[i]] = d; 01598 /*@=dependenttrans@*/ 01599 d = stpcpy(d, flp->diskURL); 01600 01601 /* Make room for the dirName NUL, find start of baseName. */ 01602 for (b = d; b > fi->dnl[fi->dil[i]] && *b != '/'; b--) 01603 b[1] = b[0]; 01604 b++; /* dirname's end in '/' */ 01605 *b++ = '\0'; /* terminate dirname, b points to basename */ 01606 fi->bnl[i] = b; 01607 d += 2; /* skip both dirname and basename NUL's */ 01608 01609 /* Create archive path, normally adding "./" */ 01610 /*@-dependenttrans@*/ /* FIX: xstrdup? nah ... */ 01611 fi->apath[i] = a; 01612 /*@=dependenttrans@*/ 01613 if (_addDotSlash) 01614 a = stpcpy(a, "./"); 01615 (void) urlPath(flp->fileURL, &apath); 01616 a = stpcpy(a, (apath + skipLen)); 01617 a++; /* skip apath NUL */ 01618 01619 if (flp->flags & RPMFILE_GHOST) { 01620 fi->actions[i] = FA_SKIP; 01621 continue; 01622 } 01623 fi->actions[i] = FA_COPYOUT; 01624 fi->fmapflags[i] = CPIO_MAP_PATH | 01625 CPIO_MAP_TYPE | CPIO_MAP_MODE | CPIO_MAP_UID | CPIO_MAP_GID; 01626 if (isSrc) 01627 fi->fmapflags[i] |= CPIO_FOLLOW_SYMLINKS; 01628 01629 if (S_ISREG(flp->fl_mode)) { 01630 int bingo = 1; 01631 /* Hard links need be tallied only once. */ 01632 if (flp->fl_nlink > 1) { 01633 FileListRec jlp = flp + 1; 01634 int j = i + 1; 01635 for (; (unsigned)j < fi->fc; j++, jlp++) { 01636 if (!S_ISREG(jlp->fl_mode)) 01637 continue; 01638 if (flp->fl_nlink != jlp->fl_nlink) 01639 continue; 01640 if (flp->fl_ino != jlp->fl_ino) 01641 continue; 01642 if (flp->fl_dev != jlp->fl_dev) 01643 continue; 01644 if (jlp->flags & (RPMFILE_EXCLUDE | RPMFILE_GHOST)) 01645 continue; 01646 bingo = 0; /* don't tally hardlink yet. */ 01647 break; 01648 } 01649 } 01650 if (bingo) 01651 fl->totalFileSize += flp->fl_size; 01652 } 01653 } 01654 01655 (void) headerAddEntry(h, RPMTAG_SIZE, RPM_INT32_TYPE, 01656 &(fl->totalFileSize), 1); 01657 01658 /*@-branchstate -compdef@*/ 01659 if (fip) 01660 *fip = fi; 01661 else 01662 fi = rpmfiFree(fi); 01663 /*@=branchstate =compdef@*/ 01664 } 01665 } 01666 /*@=bounds@*/ 01667 01670 /*@-boundswrite@*/ 01671 static /*@null@*/ FileListRec freeFileList(/*@only@*/ FileListRec fileList, 01672 int count) 01673 /*@*/ 01674 { 01675 while (count--) { 01676 fileList[count].diskURL = _free(fileList[count].diskURL); 01677 fileList[count].fileURL = _free(fileList[count].fileURL); 01678 fileList[count].langs = _free(fileList[count].langs); 01679 } 01680 fileList = _free(fileList); 01681 return NULL; 01682 } 01683 /*@=boundswrite@*/ 01684 01685 /* forward ref */ 01686 static int recurseDir(FileList fl, const char * diskURL) 01687 /*@globals check_fileList, rpmGlobalMacroContext, h_errno, 01688 fileSystem, internalState @*/ 01689 /*@modifies *fl, fl->processingFailed, 01690 fl->fileList, fl->fileListRecsAlloced, fl->fileListRecsUsed, 01691 fl->totalFileSize, fl->fileCount, fl->inFtw, fl->isDir, 01692 check_fileList, rpmGlobalMacroContext, 01693 fileSystem, internalState @*/; 01694 01702 /*@-boundswrite@*/ 01703 static int addFile(FileList fl, const char * diskURL, 01704 /*@null@*/ struct stat * statp) 01705 /*@globals check_fileList, rpmGlobalMacroContext, h_errno, 01706 fileSystem, internalState @*/ 01707 /*@modifies *statp, *fl, fl->processingFailed, 01708 fl->fileList, fl->fileListRecsAlloced, fl->fileListRecsUsed, 01709 fl->totalFileSize, fl->fileCount, 01710 check_fileList, rpmGlobalMacroContext, 01711 fileSystem, internalState @*/ 01712 { 01713 const char *fn = xstrdup(diskURL); 01714 const char *fileURL = fn; 01715 struct stat statbuf; 01716 mode_t fileMode; 01717 uid_t fileUid; 01718 gid_t fileGid; 01719 const char *fileUname; 01720 const char *fileGname; 01721 char *lang; 01722 01723 /* Path may have prepended buildRootURL, so locate the original filename. */ 01724 /* 01725 * XXX There are 3 types of entry into addFile: 01726 * 01727 * From diskUrl statp 01728 * ===================================================== 01729 * processBinaryFile path NULL 01730 * processBinaryFile glob result path NULL 01731 * recurseDir path stat 01732 * 01733 */ 01734 /*@-branchstate@*/ 01735 { const char *fileName; 01736 int urltype = urlPath(fileURL, &fileName); 01737 switch (urltype) { 01738 case URL_IS_PATH: 01739 fileURL += (fileName - fileURL); 01740 if (fl->buildRootURL && strcmp(fl->buildRootURL, "/")) { 01741 size_t nb = strlen(fl->buildRootURL); 01742 const char * s = fileURL + nb; 01743 char * t = (char *) fileURL; 01744 (void) memmove(t, s, nb); 01745 } 01746 fileURL = fn; 01747 break; 01748 default: 01749 if (fl->buildRootURL && strcmp(fl->buildRootURL, "/")) 01750 fileURL += strlen(fl->buildRootURL); 01751 break; 01752 } 01753 } 01754 /*@=branchstate@*/ 01755 01756 /* XXX make sure '/' can be packaged also */ 01757 /*@-branchstate@*/ 01758 if (*fileURL == '\0') 01759 fileURL = "/"; 01760 /*@=branchstate@*/ 01761 01762 /* If we are using a prefix, validate the file */ 01763 if (!fl->inFtw && fl->prefix) { 01764 const char *prefixTest; 01765 const char *prefixPtr = fl->prefix; 01766 01767 (void) urlPath(fileURL, &prefixTest); 01768 while (*prefixPtr && *prefixTest && (*prefixTest == *prefixPtr)) { 01769 prefixPtr++; 01770 prefixTest++; 01771 } 01772 if (*prefixPtr || (*prefixTest && *prefixTest != '/')) { 01773 rpmError(RPMERR_BADSPEC, _("File doesn't match prefix (%s): %s\n"), 01774 fl->prefix, fileURL); 01775 fl->processingFailed = 1; 01776 return RPMERR_BADSPEC; 01777 } 01778 } 01779 01780 if (statp == NULL) { 01781 statp = &statbuf; 01782 memset(statp, 0, sizeof(*statp)); 01783 if (fl->devtype) { 01784 time_t now = time(NULL); 01785 01786 /* XXX hack up a stat structure for a %dev(...) directive. */ 01787 statp->st_nlink = 1; 01788 statp->st_rdev = 01789 ((fl->devmajor & 0xff) << 8) | (fl->devminor & 0xff); 01790 statp->st_dev = statp->st_rdev; 01791 statp->st_mode = (fl->devtype == 'b' ? S_IFBLK : S_IFCHR); 01792 statp->st_mode |= (fl->cur_ar.ar_fmode & 0777); 01793 statp->st_atime = now; 01794 statp->st_mtime = now; 01795 statp->st_ctime = now; 01796 } else if (Lstat(diskURL, statp)) { 01797 rpmError(RPMERR_BADSPEC, _("File not found: %s\n"), diskURL); 01798 fl->processingFailed = 1; 01799 return RPMERR_BADSPEC; 01800 } 01801 } 01802 01803 if ((! fl->isDir) && S_ISDIR(statp->st_mode)) { 01804 /*@-nullstate@*/ /* FIX: fl->buildRootURL may be NULL */ 01805 return recurseDir(fl, diskURL); 01806 /*@=nullstate@*/ 01807 } 01808 01809 fileMode = statp->st_mode; 01810 fileUid = statp->st_uid; 01811 fileGid = statp->st_gid; 01812 01813 if (S_ISDIR(fileMode) && fl->cur_ar.ar_dmodestr) { 01814 fileMode &= S_IFMT; 01815 fileMode |= fl->cur_ar.ar_dmode; 01816 } else if (fl->cur_ar.ar_fmodestr != NULL) { 01817 fileMode &= S_IFMT; 01818 fileMode |= fl->cur_ar.ar_fmode; 01819 } 01820 if (fl->cur_ar.ar_user) { 01821 fileUname = getUnameS(fl->cur_ar.ar_user); 01822 } else { 01823 fileUname = getUname(fileUid); 01824 } 01825 if (fl->cur_ar.ar_group) { 01826 fileGname = getGnameS(fl->cur_ar.ar_group); 01827 } else { 01828 fileGname = getGname(fileGid); 01829 } 01830 01831 /* Default user/group to builder's user/group */ 01832 if (fileUname == NULL) 01833 fileUname = getUname(getuid()); 01834 if (fileGname == NULL) 01835 fileGname = getGname(getgid()); 01836 01837 /* S_XXX macro must be consistent with type in find call at check-files script */ 01838 if (check_fileList && (S_ISREG(fileMode) || S_ISLNK(fileMode))) { 01839 const char * diskfn = NULL; 01840 (void) urlPath(diskURL, &diskfn); 01841 appendStringBuf(check_fileList, diskfn); 01842 appendStringBuf(check_fileList, "\n"); 01843 } 01844 01845 /* Add to the file list */ 01846 if (fl->fileListRecsUsed == fl->fileListRecsAlloced) { 01847 fl->fileListRecsAlloced += 128; 01848 fl->fileList = xrealloc(fl->fileList, 01849 fl->fileListRecsAlloced * sizeof(*(fl->fileList))); 01850 } 01851 01852 { FileListRec flp = &fl->fileList[fl->fileListRecsUsed]; 01853 int i; 01854 01855 flp->fl_st = *statp; /* structure assignment */ 01856 flp->fl_mode = fileMode; 01857 flp->fl_uid = fileUid; 01858 flp->fl_gid = fileGid; 01859 01860 flp->fileURL = xstrdup(fileURL); 01861 flp->diskURL = xstrdup(diskURL); 01862 flp->uname = fileUname; 01863 flp->gname = fileGname; 01864 01865 if (fl->currentLangs && fl->nLangs > 0) { 01866 char * ncl; 01867 size_t nl = 0; 01868 01869 for (i = 0; i < fl->nLangs; i++) 01870 nl += strlen(fl->currentLangs[i]) + 1; 01871 01872 flp->langs = ncl = xmalloc(nl); 01873 for (i = 0; i < fl->nLangs; i++) { 01874 const char *ocl; 01875 if (i) *ncl++ = '|'; 01876 for (ocl = fl->currentLangs[i]; *ocl != '\0'; ocl++) 01877 *ncl++ = *ocl; 01878 *ncl = '\0'; 01879 } 01880 } else if (! parseForRegexLang(fileURL, &lang)) { 01881 flp->langs = xstrdup(lang); 01882 } else { 01883 flp->langs = xstrdup(""); 01884 } 01885 01886 flp->flags = fl->currentFlags; 01887 flp->specdFlags = fl->currentSpecdFlags; 01888 flp->verifyFlags = fl->currentVerifyFlags; 01889 } 01890 01891 fl->fileListRecsUsed++; 01892 fl->fileCount++; 01893 /*@i@*/ fn = _free(fn); 01894 01895 return 0; 01896 } 01897 /*@=boundswrite@*/ 01898 01905 static int recurseDir(FileList fl, const char * diskURL) 01906 { 01907 char * ftsSet[2]; 01908 FTS * ftsp; 01909 FTSENT * fts; 01910 int myFtsOpts = (FTS_COMFOLLOW | FTS_NOCHDIR | FTS_PHYSICAL); 01911 int rc = RPMERR_BADSPEC; 01912 01913 fl->inFtw = 1; /* Flag to indicate file has buildRootURL prefixed */ 01914 fl->isDir = 1; /* Keep it from following myftw() again */ 01915 01916 ftsSet[0] = (char *) diskURL; 01917 ftsSet[1] = NULL; 01918 ftsp = Fts_open(ftsSet, myFtsOpts, NULL); 01919 while ((fts = Fts_read(ftsp)) != NULL) { 01920 switch (fts->fts_info) { 01921 case FTS_D: /* preorder directory */ 01922 case FTS_F: /* regular file */ 01923 case FTS_SL: /* symbolic link */ 01924 case FTS_SLNONE: /* symbolic link without target */ 01925 case FTS_DEFAULT: /* none of the above */ 01926 rc = addFile(fl, fts->fts_accpath, fts->fts_statp); 01927 /*@switchbreak@*/ break; 01928 case FTS_DOT: /* dot or dot-dot */ 01929 case FTS_DP: /* postorder directory */ 01930 rc = 0; 01931 /*@switchbreak@*/ break; 01932 case FTS_NS: /* stat(2) failed */ 01933 case FTS_DNR: /* unreadable directory */ 01934 case FTS_ERR: /* error; errno is set */ 01935 case FTS_DC: /* directory that causes cycles */ 01936 case FTS_NSOK: /* no stat(2) requested */ 01937 case FTS_INIT: /* initialized only */ 01938 case FTS_W: /* whiteout object */ 01939 default: 01940 rc = RPMERR_BADSPEC; 01941 /*@switchbreak@*/ break; 01942 } 01943 if (rc) 01944 break; 01945 } 01946 (void) Fts_close(ftsp); 01947 01948 fl->isDir = 0; 01949 fl->inFtw = 0; 01950 01951 return rc; 01952 } 01953 01962 static int processMetadataFile(Package pkg, FileList fl, const char * fileURL, 01963 rpmTag tag) 01964 /*@globals check_fileList, rpmGlobalMacroContext, h_errno, 01965 fileSystem, internalState @*/ 01966 /*@modifies pkg->header, *fl, fl->processingFailed, 01967 fl->fileList, fl->fileListRecsAlloced, fl->fileListRecsUsed, 01968 fl->totalFileSize, fl->fileCount, 01969 check_fileList, rpmGlobalMacroContext, 01970 fileSystem, internalState @*/ 01971 { 01972 const char * buildURL = "%{_builddir}/%{?buildsubdir}/"; 01973 const char * fn = NULL; 01974 const char * apkt = NULL; 01975 const unsigned char * pkt = NULL; 01976 ssize_t pktlen = 0; 01977 int absolute = 0; 01978 int rc = 1; 01979 int xx; 01980 01981 (void) urlPath(fileURL, &fn); 01982 if (*fn == '/') { 01983 fn = rpmGenPath(fl->buildRootURL, NULL, fn); 01984 absolute = 1; 01985 } else 01986 fn = rpmGenPath(buildURL, NULL, fn); 01987 01988 /*@-branchstate@*/ 01989 switch (tag) { 01990 default: 01991 rpmError(RPMERR_BADSPEC, _("%s: can't load unknown tag (%d).\n"), 01992 fn, tag); 01993 goto exit; 01994 /*@notreached@*/ break; 01995 case RPMTAG_PUBKEYS: 01996 if ((rc = pgpReadPkts(fn, &pkt, &pktlen)) <= 0) { 01997 rpmError(RPMERR_BADSPEC, _("%s: public key read failed.\n"), fn); 01998 goto exit; 01999 } 02000 if (rc != PGPARMOR_PUBKEY) { 02001 rpmError(RPMERR_BADSPEC, _("%s: not an armored public key.\n"), fn); 02002 goto exit; 02003 } 02004 apkt = pgpArmorWrap(PGPARMOR_PUBKEY, pkt, pktlen); 02005 break; 02006 case RPMTAG_POLICIES: 02007 if ((rc = rpmioSlurp(fn, &pkt, &pktlen)) != 0) { 02008 rpmError(RPMERR_BADSPEC, _("%s: *.te policy read failed.\n"), fn); 02009 goto exit; 02010 } 02011 apkt = (const char *) pkt; /* XXX unsigned char */ 02012 pkt = NULL; 02013 break; 02014 } 02015 /*@=branchstate@*/ 02016 02017 xx = headerAddOrAppendEntry(pkg->header, tag, 02018 RPM_STRING_ARRAY_TYPE, &apkt, 1); 02019 02020 rc = 0; 02021 if (absolute) 02022 rc = addFile(fl, fn, NULL); 02023 02024 exit: 02025 apkt = _free(apkt); 02026 pkt = _free(pkt); 02027 fn = _free(fn); 02028 if (rc) { 02029 fl->processingFailed = 1; 02030 rc = RPMERR_BADSPEC; 02031 } 02032 return rc; 02033 } 02034 02042 static int processBinaryFile(/*@unused@*/ Package pkg, FileList fl, 02043 const char * fileURL) 02044 /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/ 02045 /*@modifies *fl, fl->processingFailed, 02046 fl->fileList, fl->fileListRecsAlloced, fl->fileListRecsUsed, 02047 fl->totalFileSize, fl->fileCount, 02048 rpmGlobalMacroContext, fileSystem, internalState @*/ 02049 { 02050 int quote = 1; /* XXX permit quoted glob characters. */ 02051 int doGlob; 02052 const char *diskURL = NULL; 02053 int rc = 0; 02054 02055 doGlob = Glob_pattern_p(fileURL, quote); 02056 02057 /* Check that file starts with leading "/" */ 02058 { const char * fileName; 02059 (void) urlPath(fileURL, &fileName); 02060 if (*fileName != '/') { 02061 rpmError(RPMERR_BADSPEC, _("File needs leading \"/\": %s\n"), 02062 fileName); 02063 rc = 1; 02064 goto exit; 02065 } 02066 } 02067 02068 /* Copy file name or glob pattern removing multiple "/" chars. */ 02069 /* 02070 * Note: rpmGetPath should guarantee a "canonical" path. That means 02071 * that the following pathologies should be weeded out: 02072 * //bin//sh 02073 * //usr//bin/ 02074 * /.././../usr/../bin//./sh 02075 */ 02076 diskURL = rpmGenPath(fl->buildRootURL, NULL, fileURL); 02077 02078 if (doGlob) { 02079 const char ** argv = NULL; 02080 int argc = 0; 02081 int i; 02082 02083 /* XXX for %dev marker in file manifest only */ 02084 if (fl->noGlob) { 02085 rpmError(RPMERR_BADSPEC, _("Glob not permitted: %s\n"), 02086 diskURL); 02087 rc = 1; 02088 goto exit; 02089 } 02090 02091 /*@-branchstate@*/ 02092 rc = rpmGlob(diskURL, &argc, &argv); 02093 if (rc == 0 && argc >= 1) { 02094 for (i = 0; i < argc; i++) { 02095 rc = addFile(fl, argv[i], NULL); 02096 /*@-boundswrite@*/ 02097 argv[i] = _free(argv[i]); 02098 /*@=boundswrite@*/ 02099 } 02100 argv = _free(argv); 02101 } else { 02102 rpmError(RPMERR_BADSPEC, _("File not found by glob: %s\n"), 02103 diskURL); 02104 rc = 1; 02105 goto exit; 02106 } 02107 /*@=branchstate@*/ 02108 } else { 02109 rc = addFile(fl, diskURL, NULL); 02110 } 02111 02112 exit: 02113 diskURL = _free(diskURL); 02114 if (rc) { 02115 fl->processingFailed = 1; 02116 rc = RPMERR_BADSPEC; 02117 } 02118 return rc; 02119 } 02120 02123 /*@-boundswrite@*/ 02124 static int processPackageFiles(Spec spec, Package pkg, 02125 int installSpecialDoc, int test) 02126 /*@globals rpmGlobalMacroContext, h_errno, 02127 fileSystem, internalState@*/ 02128 /*@modifies spec->macros, 02129 pkg->cpioList, pkg->fileList, pkg->specialDoc, pkg->header, 02130 rpmGlobalMacroContext, fileSystem, internalState @*/ 02131 { 02132 HGE_t hge = (HGE_t)headerGetEntryMinMemory; 02133 struct FileList_s fl; 02134 char *s, **files, **fp; 02135 const char *fileName; 02136 char buf[BUFSIZ]; 02137 struct AttrRec_s arbuf; 02138 AttrRec specialDocAttrRec = &arbuf; 02139 char *specialDoc = NULL; 02140 02141 nullAttrRec(specialDocAttrRec); 02142 pkg->cpioList = NULL; 02143 02144 if (pkg->fileFile) { 02145 const char *ffn; 02146 FILE * f; 02147 FD_t fd; 02148 02149 /* XXX W2DO? urlPath might be useful here. */ 02150 if (*pkg->fileFile == '/') { 02151 ffn = rpmGetPath(pkg->fileFile, NULL); 02152 } else { 02153 /* XXX FIXME: add %{buildsubdir} */ 02154 ffn = rpmGetPath("%{_builddir}/", 02155 (spec->buildSubdir ? spec->buildSubdir : "") , 02156 "/", pkg->fileFile, NULL); 02157 } 02158 fd = Fopen(ffn, "r.fpio"); 02159 02160 if (fd == NULL || Ferror(fd)) { 02161 rpmError(RPMERR_BADFILENAME, 02162 _("Could not open %%files file %s: %s\n"), 02163 ffn, Fstrerror(fd)); 02164 return RPMERR_BADFILENAME; 02165 } 02166 ffn = _free(ffn); 02167 02168 /*@+voidabstract@*/ f = fdGetFp(fd); /*@=voidabstract@*/ 02169 if (f != NULL) 02170 while (fgets(buf, sizeof(buf), f)) { 02171 handleComments(buf); 02172 if (expandMacros(spec, spec->macros, buf, sizeof(buf))) { 02173 rpmError(RPMERR_BADSPEC, _("line: %s\n"), buf); 02174 return RPMERR_BADSPEC; 02175 } 02176 appendStringBuf(pkg->fileList, buf); 02177 } 02178 (void) Fclose(fd); 02179 } 02180 02181 /* Init the file list structure */ 02182 memset(&fl, 0, sizeof(fl)); 02183 02184 fl.buildRootURL = rpmGenPath(spec->rootURL, "%{?buildroot}", NULL); 02185 02186 if (hge(pkg->header, RPMTAG_DEFAULTPREFIX, NULL, &fl.prefix, NULL)) 02187 fl.prefix = xstrdup(fl.prefix); 02188 else 02189 fl.prefix = NULL; 02190 02191 fl.fileCount = 0; 02192 fl.totalFileSize = 0; 02193 fl.processingFailed = 0; 02194 02195 fl.passedSpecialDoc = 0; 02196 fl.isSpecialDoc = 0; 02197 02198 fl.isDir = 0; 02199 fl.inFtw = 0; 02200 fl.currentFlags = 0; 02201 fl.currentVerifyFlags = 0; 02202 02203 fl.noGlob = 0; 02204 fl.devtype = 0; 02205 fl.devmajor = 0; 02206 fl.devminor = 0; 02207 02208 nullAttrRec(&fl.cur_ar); 02209 nullAttrRec(&fl.def_ar); 02210 dupAttrRec(&root_ar, &fl.def_ar); /* XXX assume %defattr(-,root,root) */ 02211 02212 fl.defVerifyFlags = RPMVERIFY_ALL; 02213 fl.nLangs = 0; 02214 fl.currentLangs = NULL; 02215 02216 fl.currentSpecdFlags = 0; 02217 fl.defSpecdFlags = 0; 02218 02219 fl.docDirCount = 0; 02220 fl.docDirs[fl.docDirCount++] = xstrdup("/usr/doc"); 02221 fl.docDirs[fl.docDirCount++] = xstrdup("/usr/man"); 02222 fl.docDirs[fl.docDirCount++] = xstrdup("/usr/info"); 02223 fl.docDirs[fl.docDirCount++] = xstrdup("/usr/X11R6/man"); 02224 fl.docDirs[fl.docDirCount++] = xstrdup("/usr/share/doc"); 02225 fl.docDirs[fl.docDirCount++] = xstrdup("/usr/share/man"); 02226 fl.docDirs[fl.docDirCount++] = xstrdup("/usr/share/info"); 02227 fl.docDirs[fl.docDirCount++] = xstrdup("/usr/src/examples"); 02228 fl.docDirs[fl.docDirCount++] = rpmGetPath("%{_docdir}", NULL); 02229 fl.docDirs[fl.docDirCount++] = rpmGetPath("%{_mandir}", NULL); 02230 fl.docDirs[fl.docDirCount++] = rpmGetPath("%{_infodir}", NULL); 02231 fl.docDirs[fl.docDirCount++] = rpmGetPath("%{_javadocdir}", NULL); 02232 fl.docDirs[fl.docDirCount++] = rpmGetPath("%{_examplesdir}", NULL); 02233 02234 fl.fileList = NULL; 02235 fl.fileListRecsAlloced = 0; 02236 fl.fileListRecsUsed = 0; 02237 02238 s = getStringBuf(pkg->fileList); 02239 files = splitString(s, strlen(s), '\n'); 02240 02241 for (fp = files; *fp != NULL; fp++) { 02242 s = *fp; 02243 SKIPSPACE(s); 02244 if (*s == '\0') 02245 continue; 02246 fileName = NULL; 02247 /*@-nullpass@*/ /* LCL: buf is NULL ?!? */ 02248 strcpy(buf, s); 02249 /*@=nullpass@*/ 02250 02251 /* Reset for a new line in %files */ 02252 fl.isDir = 0; 02253 fl.inFtw = 0; 02254 fl.currentFlags = 0; 02255 /* turn explicit flags into %def'd ones (gosh this is hacky...) */ 02256 fl.currentSpecdFlags = ((unsigned)fl.defSpecdFlags) >> 8; 02257 fl.currentVerifyFlags = fl.defVerifyFlags; 02258 fl.isSpecialDoc = 0; 02259 02260 fl.noGlob = 0; 02261 fl.devtype = 0; 02262 fl.devmajor = 0; 02263 fl.devminor = 0; 02264 02265 /* XXX should reset to %deflang value */ 02266 if (fl.currentLangs) { 02267 int i; 02268 for (i = 0; i < fl.nLangs; i++) 02269 /*@-unqualifiedtrans@*/ 02270 fl.currentLangs[i] = _free(fl.currentLangs[i]); 02271 /*@=unqualifiedtrans@*/ 02272 fl.currentLangs = _free(fl.currentLangs); 02273 } 02274 fl.nLangs = 0; 02275 02276 dupAttrRec(&fl.def_ar, &fl.cur_ar); 02277 02278 /*@-nullpass@*/ /* LCL: buf is NULL ?!? */ 02279 if (parseForVerify(buf, &fl)) 02280 continue; 02281 if (parseForAttr(buf, &fl)) 02282 continue; 02283 if (parseForDev(buf, &fl)) 02284 continue; 02285 if (parseForConfig(buf, &fl)) 02286 continue; 02287 if (parseForLang(buf, &fl)) 02288 continue; 02289 /*@-nullstate@*/ /* FIX: pkg->fileFile might be NULL */ 02290 if (parseForSimple(spec, pkg, buf, &fl, &fileName)) 02291 /*@=nullstate@*/ 02292 continue; 02293 /*@=nullpass@*/ 02294 if (fileName == NULL) 02295 continue; 02296 02297 /*@-branchstate@*/ 02298 if (fl.isSpecialDoc) { 02299 /* Save this stuff for last */ 02300 specialDoc = _free(specialDoc); 02301 specialDoc = xstrdup(fileName); 02302 dupAttrRec(&fl.cur_ar, specialDocAttrRec); 02303 } else if (fl.currentFlags & RPMFILE_PUBKEY) { 02304 /*@-nullstate@*/ /* FIX: pkg->fileFile might be NULL */ 02305 (void) processMetadataFile(pkg, &fl, fileName, RPMTAG_PUBKEYS); 02306 /*@=nullstate@*/ 02307 } else if (fl.currentFlags & RPMFILE_POLICY) { 02308 /*@-nullstate@*/ /* FIX: pkg->fileFile might be NULL */ 02309 (void) processMetadataFile(pkg, &fl, fileName, RPMTAG_POLICIES); 02310 /*@=nullstate@*/ 02311 } else { 02312 /*@-nullstate@*/ /* FIX: pkg->fileFile might be NULL */ 02313 (void) processBinaryFile(pkg, &fl, fileName); 02314 /*@=nullstate@*/ 02315 } 02316 /*@=branchstate@*/ 02317 } 02318 02319 /* Now process special doc, if there is one */ 02320 if (specialDoc) { 02321 if (installSpecialDoc) { 02322 int _missing_doc_files_terminate_build = 02323 rpmExpandNumeric("%{?_missing_doc_files_terminate_build}"); 02324 int rc; 02325 02326 rc = doScript(spec, RPMBUILD_STRINGBUF, "%doc", pkg->specialDoc, test); 02327 if (rc && _missing_doc_files_terminate_build) 02328 fl.processingFailed = rc; 02329 } 02330 02331 /* Reset for %doc */ 02332 fl.isDir = 0; 02333 fl.inFtw = 0; 02334 fl.currentFlags = 0; 02335 fl.currentVerifyFlags = fl.defVerifyFlags; 02336 02337 fl.noGlob = 0; 02338 fl.devtype = 0; 02339 fl.devmajor = 0; 02340 fl.devminor = 0; 02341 02342 /* XXX should reset to %deflang value */ 02343 if (fl.currentLangs) { 02344 int i; 02345 for (i = 0; i < fl.nLangs; i++) 02346 /*@-unqualifiedtrans@*/ 02347 fl.currentLangs[i] = _free(fl.currentLangs[i]); 02348 /*@=unqualifiedtrans@*/ 02349 fl.currentLangs = _free(fl.currentLangs); 02350 } 02351 fl.nLangs = 0; 02352 02353 dupAttrRec(specialDocAttrRec, &fl.cur_ar); 02354 freeAttrRec(specialDocAttrRec); 02355 02356 /*@-nullstate@*/ /* FIX: pkg->fileFile might be NULL */ 02357 (void) processBinaryFile(pkg, &fl, specialDoc); 02358 /*@=nullstate@*/ 02359 02360 specialDoc = _free(specialDoc); 02361 } 02362 02363 freeSplitString(files); 02364 02365 if (fl.processingFailed) 02366 goto exit; 02367 02368 /* Verify that file attributes scope over hardlinks correctly. */ 02369 if (checkHardLinks(&fl) && !rpmExpandNumeric("%{_hack_dontneed_PartialHardlinkSets}")) 02370 (void) rpmlibNeedsFeature(pkg->header, 02371 "PartialHardlinkSets", "4.0.4-1"); 02372 02373 genCpioListAndHeader(&fl, &pkg->cpioList, pkg->header, 0); 02374 02375 if (spec->timeCheck) 02376 timeCheck(spec->timeCheck, pkg->header); 02377 02378 exit: 02379 fl.buildRootURL = _free(fl.buildRootURL); 02380 fl.prefix = _free(fl.prefix); 02381 02382 freeAttrRec(&fl.cur_ar); 02383 freeAttrRec(&fl.def_ar); 02384 02385 if (fl.currentLangs) { 02386 int i; 02387 for (i = 0; i < fl.nLangs; i++) 02388 /*@-unqualifiedtrans@*/ 02389 fl.currentLangs[i] = _free(fl.currentLangs[i]); 02390 /*@=unqualifiedtrans@*/ 02391 fl.currentLangs = _free(fl.currentLangs); 02392 } 02393 02394 fl.fileList = freeFileList(fl.fileList, fl.fileListRecsUsed); 02395 02396 while (fl.docDirCount--) 02397 fl.docDirs[fl.docDirCount] = _free(fl.docDirs[fl.docDirCount]); 02398 return fl.processingFailed; 02399 } 02400 /*@=boundswrite@*/ 02401 02402 int initSourceHeader(Spec spec, StringBuf *sfp) 02403 { 02404 HeaderIterator hi; 02405 int_32 tag, type, count; 02406 const void * ptr; 02407 StringBuf sourceFiles; 02408 struct Source *srcPtr; 02409 02410 /* Only specific tags are added to the source package header */ 02411 /*@-branchstate@*/ 02412 if (!spec->sourceHdrInit) { 02413 for (hi = headerInitIterator(spec->packages->header); 02414 headerNextIterator(hi, &tag, &type, &ptr, &count); 02415 ptr = headerFreeData(ptr, type)) 02416 { 02417 switch (tag) { 02418 case RPMTAG_NAME: 02419 case RPMTAG_VERSION: 02420 case RPMTAG_RELEASE: 02421 case RPMTAG_EPOCH: 02422 case RPMTAG_SUMMARY: 02423 case RPMTAG_DESCRIPTION: 02424 case RPMTAG_PACKAGER: 02425 case RPMTAG_DISTRIBUTION: 02426 case RPMTAG_DISTURL: 02427 case RPMTAG_VENDOR: 02428 case RPMTAG_LICENSE: 02429 case RPMTAG_GROUP: 02430 case RPMTAG_OS: 02431 case RPMTAG_ARCH: 02432 case RPMTAG_CHANGELOGTIME: 02433 case RPMTAG_CHANGELOGNAME: 02434 case RPMTAG_CHANGELOGTEXT: 02435 case RPMTAG_URL: 02436 case RPMTAG_ICON: 02437 case RPMTAG_GIF: 02438 case RPMTAG_XPM: 02439 case HEADER_I18NTABLE: 02440 if (ptr) 02441 (void)headerAddEntry(spec->sourceHeader, tag, type, ptr, count); 02442 /*@switchbreak@*/ break; 02443 default: 02444 /* do not copy */ 02445 /*@switchbreak@*/ break; 02446 } 02447 } 02448 hi = headerFreeIterator(hi); 02449 /*@=branchstate@*/ 02450 02451 if (spec->BANames && spec->BACount > 0) { 02452 (void) headerAddEntry(spec->sourceHeader, RPMTAG_BUILDARCHS, 02453 RPM_STRING_ARRAY_TYPE, 02454 spec->BANames, spec->BACount); 02455 } 02456 } 02457 02458 if (sfp != NULL && *sfp != NULL) 02459 sourceFiles = *sfp; 02460 else 02461 sourceFiles = newStringBuf(); 02462 02463 /* Construct the source/patch tag entries */ 02464 appendLineStringBuf(sourceFiles, spec->specFile); 02465 if (spec->sourceHeader != NULL) 02466 for (srcPtr = spec->sources; srcPtr != NULL; srcPtr = srcPtr->next) { 02467 { const char * sfn; 02468 sfn = rpmGetPath( ((srcPtr->flags & RPMFILE_GHOST) ? "!" : ""), 02469 "%{_sourcedir}/", srcPtr->source, NULL); 02470 appendLineStringBuf(sourceFiles, sfn); 02471 sfn = _free(sfn); 02472 } 02473 02474 if (spec->sourceHdrInit) 02475 continue; 02476 02477 if (srcPtr->flags & RPMFILE_SOURCE) { 02478 (void) headerAddOrAppendEntry(spec->sourceHeader, RPMTAG_SOURCE, 02479 RPM_STRING_ARRAY_TYPE, &srcPtr->source, 1); 02480 if (srcPtr->flags & RPMFILE_GHOST) { 02481 (void) headerAddOrAppendEntry(spec->sourceHeader, RPMTAG_NOSOURCE, 02482 RPM_INT32_TYPE, &srcPtr->num, 1); 02483 } 02484 } 02485 if (srcPtr->flags & RPMFILE_PATCH) { 02486 (void) headerAddOrAppendEntry(spec->sourceHeader, RPMTAG_PATCH, 02487 RPM_STRING_ARRAY_TYPE, &srcPtr->source, 1); 02488 if (srcPtr->flags & RPMFILE_GHOST) { 02489 (void) headerAddOrAppendEntry(spec->sourceHeader, RPMTAG_NOPATCH, 02490 RPM_INT32_TYPE, &srcPtr->num, 1); 02491 } 02492 } 02493 } 02494 02495 if (sfp == NULL) 02496 sourceFiles = freeStringBuf(sourceFiles); 02497 02498 spec->sourceHdrInit = 1; 02499 02500 return 0; 02501 } 02502 02503 int processSourceFiles(Spec spec) 02504 { 02505 StringBuf sourceFiles, *sfp = &sourceFiles; 02506 int x, isSpec = 1; 02507 struct FileList_s fl; 02508 char **files, **fp; 02509 int rc; 02510 char *_srcdefattr; 02511 char buf[BUFSIZ]; 02512 02513 _srcdefattr = rpmExpand("%{?_srcdefattr}", NULL); 02514 02515 02516 *sfp = newStringBuf(); 02517 x = initSourceHeader(spec, sfp); 02518 02519 /* Init the file list structure */ 02520 memset(&fl, 0, sizeof(fl)); 02521 if (_srcdefattr && *_srcdefattr) { 02522 sprintf(buf, "%%defattr %s", _srcdefattr); 02523 parseForAttr(buf, &fl); 02524 } 02525 02526 /* Construct the SRPM file list. */ 02527 fl.fileList = xcalloc((spec->numSources + 1), sizeof(*fl.fileList)); 02528 rc = fl.processingFailed = 0; 02529 fl.fileListRecsUsed = 0; 02530 fl.totalFileSize = 0; 02531 fl.prefix = NULL; 02532 fl.buildRootURL = NULL; 02533 02534 { const char *s = getStringBuf(*sfp); 02535 files = splitString(s, strlen(s), '\n'); 02536 } 02537 02538 /* The first source file is the spec file */ 02539 x = 0; 02540 for (fp = files; *fp != NULL; fp++) { 02541 const char * diskURL, *diskPath; 02542 FileListRec flp; 02543 02544 diskURL = *fp; 02545 SKIPSPACE(diskURL); 02546 if (! *diskURL) 02547 continue; 02548 02549 flp = &fl.fileList[x]; 02550 02551 flp->flags = isSpec ? RPMFILE_SPECFILE : 0; 02552 /* files with leading ! are no source files */ 02553 if (*diskURL == '!') { 02554 flp->flags |= RPMFILE_GHOST; 02555 diskURL++; 02556 } 02557 02558 (void) urlPath(diskURL, &diskPath); 02559 02560 flp->diskURL = xstrdup(diskURL); 02561 diskPath = strrchr(diskPath, '/'); 02562 if (diskPath) 02563 diskPath++; 02564 else 02565 diskPath = diskURL; 02566 02567 flp->fileURL = xstrdup(diskPath); 02568 flp->verifyFlags = RPMVERIFY_ALL; 02569 02570 if (Stat(diskURL, &flp->fl_st)) { 02571 rpmError(RPMERR_BADSPEC, _("Bad file: %s: %s\n"), 02572 diskURL, strerror(errno)); 02573 rc = fl.processingFailed = 1; 02574 } 02575 02576 if (fl.def_ar.ar_fmodestr) { 02577 flp->fl_mode &= S_IFMT; 02578 flp->fl_mode |= fl.def_ar.ar_fmode; 02579 } 02580 02581 flp->uname = fl.def_ar.ar_user ? 02582 getUnameS(fl.def_ar.ar_user): 02583 getUname(flp->fl_uid); 02584 02585 flp->gname = fl.def_ar.ar_group ? 02586 getGnameS(fl.def_ar.ar_group) : 02587 getGname(flp->fl_gid); 02588 02589 flp->langs = xstrdup(""); 02590 02591 if (! (flp->uname && flp->gname)) { 02592 rpmError(RPMERR_BADSPEC, _("Bad owner/group: %s\n"), diskURL); 02593 rc = fl.processingFailed = 1; 02594 } 02595 02596 isSpec = 0; 02597 x++; 02598 } 02599 fl.fileListRecsUsed = x; 02600 freeSplitString(files); 02601 02602 if (rc) 02603 goto exit; 02604 02605 spec->sourceCpioList = NULL; 02606 genCpioListAndHeader(&fl, &spec->sourceCpioList, spec->sourceHeader, 1); 02607 02608 exit: 02609 *sfp = freeStringBuf(*sfp); 02610 fl.fileList = freeFileList(fl.fileList, fl.fileListRecsUsed); 02611 _free(_srcdefattr); 02612 freeAttrRec(&fl.def_ar); 02613 return rc; 02614 } 02615 02621 static int checkFiles(StringBuf fileList) 02622 /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/ 02623 /*@modifies rpmGlobalMacroContext, fileSystem, internalState @*/ 02624 { 02625 /*@-readonlytrans@*/ 02626 static const char * av_ckfile[] = { "%{?__check_files}", NULL }; 02627 /*@=readonlytrans@*/ 02628 StringBuf sb_stdout = NULL; 02629 const char * s; 02630 int rc; 02631 02632 s = rpmExpand(av_ckfile[0], NULL); 02633 if (!(s && *s)) { 02634 rc = -1; 02635 goto exit; 02636 } 02637 rc = 0; 02638 02639 rpmMessage(RPMMESS_NORMAL, _("Checking for unpackaged file(s): %s\n"), s); 02640 02641 /*@-boundswrite@*/ 02642 rc = rpmfcExec(av_ckfile, fileList, &sb_stdout, 0); 02643 /*@=boundswrite@*/ 02644 if (rc < 0) 02645 goto exit; 02646 02647 if (sb_stdout) { 02648 int _unpackaged_files_terminate_build = 02649 rpmExpandNumeric("%{?_unpackaged_files_terminate_build}"); 02650 const char * t; 02651 02652 t = getStringBuf(sb_stdout); 02653 if ((*t != '\0') && (*t != '\n')) { 02654 rc = (_unpackaged_files_terminate_build) ? 1 : 0; 02655 rpmMessage((rc ? RPMMESS_ERROR : RPMMESS_WARNING), 02656 _("Installed (but unpackaged) file(s) found:\n%s"), t); 02657 } 02658 } 02659 02660 exit: 02661 sb_stdout = freeStringBuf(sb_stdout); 02662 s = _free(s); 02663 return rc; 02664 } 02665 02666 /*@-incondefs@*/ 02667 int processBinaryFiles(Spec spec, int installSpecialDoc, int test) 02668 /*@globals check_fileList @*/ 02669 /*@modifies check_fileList @*/ 02670 { 02671 Package pkg; 02672 int res = 0; 02673 02674 check_fileList = newStringBuf(); 02675 02676 for (pkg = spec->packages; pkg != NULL; pkg = pkg->next) { 02677 const char *n, *v, *r; 02678 int rc; 02679 02680 if (pkg->fileList == NULL) 02681 continue; 02682 02683 (void) headerMacrosLoad(pkg->header); 02684 02685 (void) headerNVR(pkg->header, &n, &v, &r); 02686 rpmMessage(RPMMESS_NORMAL, _("Processing files: %s-%s-%s\n"), n, v, r); 02687 02688 if ((rc = processPackageFiles(spec, pkg, installSpecialDoc, test))) 02689 res = rc; 02690 02691 /* Finalize package scriptlets before extracting dependencies. */ 02692 if ((rc = processScriptFiles(spec, pkg))) 02693 res = rc; 02694 02695 if ((rc = rpmfcGenerateDepends(spec, pkg))) 02696 res = rc; 02697 02698 /* XXX this should be earlier for deps to be entirely sorted. */ 02699 providePackageNVR(pkg->header); 02700 02701 (void) headerMacrosUnload(pkg->header); 02702 } 02703 02704 /* Now we have in fileList list of files from all packages. 02705 * We pass it to a script which does the work of finding missing 02706 * and duplicated files. 02707 */ 02708 02709 if (res == 0) { 02710 if (checkFiles(check_fileList) > 0) 02711 res = 1; 02712 } 02713 02714 check_fileList = freeStringBuf(check_fileList); 02715 02716 return res; 02717 } 02718 /*@=incondefs@*/