rpm 5.3.12
|
00001 #include "system.h" 00002 00003 #include <signal.h> /* getOutputFrom() */ 00004 00005 #include <rpmio.h> 00006 #include <rpmiotypes.h> /* XXX fnpyKey */ 00007 #include <rpmlog.h> 00008 #include <rpmurl.h> 00009 #include <rpmmg.h> 00010 #include <argv.h> 00011 #define _MIRE_INTERNAL 00012 #include <mire.h> 00013 00014 #include <rpmtag.h> 00015 #define _RPMEVR_INTERNAL 00016 #include <rpmbuild.h> 00017 00018 #define _RPMNS_INTERNAL 00019 #include <rpmns.h> 00020 00021 #define _RPMFC_INTERNAL 00022 #include <rpmfc.h> 00023 00024 #define _RPMDS_INTERNAL 00025 #include <rpmds.h> 00026 #include <rpmfi.h> 00027 00028 #include "debug.h" 00029 00030 /*@access rpmds @*/ 00031 /*@access miRE @*/ 00032 00033 /*@unchecked@*/ 00034 static int _filter_values = 1; 00035 /*@unchecked@*/ 00036 static int _filter_execs = 1; 00037 00040 static int rpmfcExpandAppend(/*@out@*/ ARGV_t * argvp, const ARGV_t av) 00041 /*@globals rpmGlobalMacroContext, h_errno, internalState @*/ 00042 /*@modifies *argvp, rpmGlobalMacroContext, internalState @*/ 00043 /*@requires maxRead(argvp) >= 0 @*/ 00044 { 00045 ARGV_t argv = *argvp; 00046 int argc = argvCount(argv); 00047 int ac = argvCount(av); 00048 int i; 00049 00050 argv = xrealloc(argv, (argc + ac + 1) * sizeof(*argv)); 00051 for (i = 0; i < ac; i++) 00052 argv[argc + i] = rpmExpand(av[i], NULL); 00053 argv[argc + ac] = NULL; 00054 *argvp = argv; 00055 return 0; 00056 } 00057 00068 /*@null@*/ 00069 static rpmiob getOutputFrom(/*@null@*/ const char * dir, ARGV_t argv, 00070 const char * writePtr, size_t writeBytesLeft, 00071 int failNonZero) 00072 /*@globals h_errno, fileSystem, internalState@*/ 00073 /*@modifies fileSystem, internalState@*/ 00074 { 00075 pid_t child, reaped; 00076 int toProg[2]; 00077 int fromProg[2]; 00078 int status; 00079 void *oldhandler; 00080 rpmiob iob = NULL; 00081 int done; 00082 00083 /*@-type@*/ /* FIX: cast? */ 00084 oldhandler = signal(SIGPIPE, SIG_IGN); 00085 /*@=type@*/ 00086 00087 toProg[0] = toProg[1] = 0; 00088 fromProg[0] = fromProg[1] = 0; 00089 if (pipe(toProg) < 0 || pipe(fromProg) < 0) { 00090 rpmlog(RPMLOG_ERR, _("Couldn't create pipe for %s: %m\n"), argv[0]); 00091 return NULL; 00092 } 00093 00094 if (!(child = fork())) { 00095 (void) close(toProg[1]); 00096 (void) close(fromProg[0]); 00097 00098 (void) dup2(toProg[0], STDIN_FILENO); /* Make stdin the in pipe */ 00099 (void) dup2(fromProg[1], STDOUT_FILENO); /* Make stdout the out pipe */ 00100 00101 (void) close(toProg[0]); 00102 (void) close(fromProg[1]); 00103 00104 if (dir) { 00105 (void) Chdir(dir); 00106 } 00107 00108 rpmlog(RPMLOG_DEBUG, D_("\texecv(%s) pid %d\n"), 00109 argv[0], (unsigned)getpid()); 00110 00111 unsetenv("MALLOC_CHECK_"); 00112 (void) execvp(argv[0], (char *const *)argv); 00113 /* XXX this error message is probably not seen. */ 00114 rpmlog(RPMLOG_ERR, _("Couldn't exec %s: %s\n"), 00115 argv[0], strerror(errno)); 00116 _exit(EXIT_FAILURE); 00117 } 00118 if (child < 0) { 00119 rpmlog(RPMLOG_ERR, _("Couldn't fork %s: %s\n"), 00120 argv[0], strerror(errno)); 00121 return NULL; 00122 } 00123 00124 (void) close(toProg[0]); 00125 (void) close(fromProg[1]); 00126 00127 /* Do not block reading or writing from/to prog. */ 00128 (void) fcntl(fromProg[0], F_SETFL, O_NONBLOCK); 00129 (void) fcntl(toProg[1], F_SETFL, O_NONBLOCK); 00130 00131 iob = rpmiobNew(0); 00132 00133 do { 00134 fd_set ibits, obits; 00135 struct timeval tv; 00136 int nfd; 00137 ssize_t nbr; 00138 ssize_t nbw; 00139 int rc; 00140 00141 done = 0; 00142 top: 00143 FD_ZERO(&ibits); 00144 FD_ZERO(&obits); 00145 if (fromProg[0] >= 0) { 00146 FD_SET(fromProg[0], &ibits); 00147 } 00148 if (toProg[1] >= 0) { 00149 FD_SET(toProg[1], &obits); 00150 } 00151 /* XXX values set to limit spinning with perl doing ~100 forks/sec. */ 00152 tv.tv_sec = 0; 00153 tv.tv_usec = 10000; 00154 nfd = ((fromProg[0] > toProg[1]) ? fromProg[0] : toProg[1]); 00155 if ((rc = select(nfd, &ibits, &obits, NULL, &tv)) < 0) { 00156 if (errno == EINTR) 00157 goto top; 00158 break; 00159 } 00160 00161 /* Write any data to program */ 00162 if (toProg[1] >= 0 && FD_ISSET(toProg[1], &obits)) { 00163 if (writePtr && writeBytesLeft > 0) { 00164 if ((nbw = write(toProg[1], writePtr, 00165 ((size_t)1024<writeBytesLeft) ? (size_t)1024 : writeBytesLeft)) < 0) 00166 { 00167 if (errno != EAGAIN) { 00168 perror("getOutputFrom()"); 00169 exit(EXIT_FAILURE); 00170 } 00171 nbw = 0; 00172 } 00173 writeBytesLeft -= nbw; 00174 writePtr += nbw; 00175 } else if (toProg[1] >= 0) { /* close write fd */ 00176 (void) close(toProg[1]); 00177 toProg[1] = -1; 00178 } 00179 } 00180 00181 /* Read any data from prog */ 00182 { char buf[BUFSIZ+1]; 00183 while ((nbr = read(fromProg[0], buf, sizeof(buf)-1)) > 0) { 00184 buf[nbr] = '\0'; 00185 iob = rpmiobAppend(iob, buf, 0); 00186 } 00187 } 00188 00189 /* terminate on (non-blocking) EOF or error */ 00190 done = (nbr == 0 || (nbr < 0 && errno != EAGAIN)); 00191 00192 } while (!done); 00193 00194 /* Clean up */ 00195 if (toProg[1] >= 0) 00196 (void) close(toProg[1]); 00197 if (fromProg[0] >= 0) 00198 (void) close(fromProg[0]); 00199 /*@-type@*/ /* FIX: cast? */ 00200 (void) signal(SIGPIPE, oldhandler); 00201 /*@=type@*/ 00202 00203 /* Collect status from prog */ 00204 reaped = waitpid(child, &status, 0); 00205 rpmlog(RPMLOG_DEBUG, D_("\twaitpid(%d) rc %d status %x\n"), 00206 (unsigned)child, (unsigned)reaped, status); 00207 00208 if (failNonZero && (!WIFEXITED(status) || WEXITSTATUS(status))) { 00209 const char *cmd = argvJoin(argv, ' '); 00210 int rc = (WIFEXITED(status) ? WEXITSTATUS(status) : -1); 00211 00212 rpmlog(RPMLOG_ERR, _("Command \"%s\" failed, exit(%d)\n"), cmd, rc); 00213 cmd = _free(cmd); 00214 iob = rpmiobFree(iob); 00215 return NULL; 00216 } 00217 if (writeBytesLeft) { 00218 rpmlog(RPMLOG_ERR, _("failed to write all data to %s\n"), argv[0]); 00219 iob = rpmiobFree(iob); 00220 return NULL; 00221 } 00222 return iob; 00223 } 00224 00225 int rpmfcExec(ARGV_t av, rpmiob iob_stdin, rpmiob * iob_stdoutp, 00226 int failnonzero) 00227 { 00228 const char * s = NULL; 00229 ARGV_t xav = NULL; 00230 ARGV_t pav = NULL; 00231 int pac = 0; 00232 int ec = -1; 00233 rpmiob iob = NULL; 00234 const char * buf_stdin = NULL; 00235 size_t buf_stdin_len = 0; 00236 int xx; 00237 00238 if (iob_stdoutp) 00239 *iob_stdoutp = NULL; 00240 if (!(av && *av)) 00241 goto exit; 00242 00243 /* Find path to executable with (possible) args. */ 00244 s = rpmExpand(av[0], NULL); 00245 if (!(s && *s)) 00246 goto exit; 00247 00248 /* Parse args buried within expanded executable. */ 00249 pac = 0; 00250 xx = poptParseArgvString(s, &pac, (const char ***)&pav); 00251 if (!(xx == 0 && pac > 0 && pav != NULL)) 00252 goto exit; 00253 00254 /* Build argv, appending args to the executable args. */ 00255 xav = NULL; 00256 xx = argvAppend(&xav, pav); 00257 if (av[1]) 00258 xx = rpmfcExpandAppend(&xav, av + 1); 00259 00260 if (iob_stdin != NULL) { 00261 buf_stdin = rpmiobStr(iob_stdin); 00262 buf_stdin_len = rpmiobLen(iob_stdin); 00263 } 00264 00265 /* Read output from exec'd helper. */ 00266 iob = getOutputFrom(NULL, xav, buf_stdin, buf_stdin_len, failnonzero); 00267 00268 if (iob_stdoutp != NULL) { 00269 *iob_stdoutp = iob; 00270 iob = NULL; /* XXX don't free */ 00271 } 00272 00273 ec = 0; 00274 00275 exit: 00276 iob = rpmiobFree(iob); 00277 xav = argvFree(xav); 00278 pav = _free(pav); /* XXX popt mallocs in single blob. */ 00279 s = _free(s); 00280 return ec; 00281 } 00282 00285 static int rpmfcSaveArg(/*@out@*/ ARGV_t * argvp, const char * key) 00286 /*@modifies *argvp @*/ 00287 /*@requires maxSet(argvp) >= 0 @*/ 00288 { 00289 int rc = 0; 00290 00291 if (argvSearch(*argvp, key, NULL) == NULL) { 00292 rc = argvAdd(argvp, key); 00293 rc = argvSort(*argvp, NULL); 00294 } 00295 return rc; 00296 } 00297 00300 static char * rpmfcFileDep(/*@returned@*/ char * buf, size_t ix, 00301 /*@null@*/ rpmds ds) 00302 /*@globals internalState @*/ 00303 /*@modifies buf, internalState @*/ 00304 /*@requires maxSet(buf) >= 0 @*/ 00305 { 00306 rpmTag tagN = rpmdsTagN(ds); 00307 char deptype = 'X'; 00308 00309 buf[0] = '\0'; 00310 switch (tagN) { 00311 default: 00312 assert(0); 00313 /*@notreached@*/ break; 00314 case RPMTAG_PROVIDENAME: 00315 deptype = 'P'; 00316 break; 00317 case RPMTAG_REQUIRENAME: 00318 deptype = 'R'; 00319 break; 00320 } 00321 /*@-nullpass@*/ 00322 if (ds != NULL) 00323 sprintf(buf, "%08u%c %s %s 0x%08x", (unsigned)ix, deptype, 00324 rpmdsN(ds), rpmdsEVR(ds), rpmdsFlags(ds)); 00325 /*@=nullpass@*/ 00326 return buf; 00327 }; 00328 00329 /*@null@*/ 00330 static void * rpmfcExpandRegexps(const char * str, int * nmirep) 00331 /*@globals rpmGlobalMacroContext, h_errno, internalState @*/ 00332 /*@modifies *nmirep, rpmGlobalMacroContext, internalState @*/ 00333 { 00334 ARGV_t av = NULL; 00335 int ac = 0; 00336 miRE mire = NULL; 00337 int nmire = 0; 00338 const char * s; 00339 int xx; 00340 int i; 00341 00342 s = rpmExpand(str, NULL); 00343 if (s && *s) { 00344 xx = poptParseArgvString(s, &ac, (const char ***)&av); 00345 s = _free(s); 00346 } 00347 if (ac == 0 || av == NULL || *av == NULL) { 00348 s = _free(s); 00349 goto exit; 00350 } 00351 00352 for (i = 0; i < ac; i++) { 00353 xx = mireAppend(RPMMIRE_REGEX, 0, av[i], NULL, &mire, &nmire); 00354 /* XXX add REG_NOSUB? better error msg? */ 00355 if (xx) { 00356 rpmlog(RPMLOG_NOTICE, 00357 _("Compilation of pattern '%s'" 00358 " (expanded from '%s') failed. Skipping ...\n"), 00359 av[i], str); 00360 nmire--; /* XXX does this actually skip?!? */ 00361 } 00362 } 00363 if (nmire == 0) 00364 mire = mireFree(mire); 00365 00366 exit: 00367 av = _free(av); 00368 if (nmirep) 00369 *nmirep = nmire; 00370 return mire; 00371 } 00372 00373 static int rpmfcMatchRegexps(void * mires, int nmire, 00374 const char * str, char deptype) 00375 /*@modifies mires @*/ 00376 { 00377 miRE mire = mires; 00378 int xx; 00379 int i; 00380 00381 for (i = 0; i < nmire; i++) { 00382 #ifdef DYING /* XXX noisy. use --miredebug if you need this spewage */ 00383 rpmlog(RPMLOG_DEBUG, D_("Checking %c: '%s'\n"), deptype, str); 00384 #endif 00385 if ((xx = mireRegexec(mire + i, str, 0)) < 0) 00386 continue; 00387 rpmlog(RPMLOG_NOTICE, _("Skipping %c: '%s'\n"), deptype, str); 00388 return 1; 00389 } 00390 return 0; 00391 } 00392 00393 /*@null@*/ 00394 static void * rpmfcFreeRegexps(/*@only@*/ void * mires, int nmire) 00395 /*@modifies mires @*/ 00396 { 00397 miRE mire = mires; 00398 /*@-refcounttrans@*/ 00399 return mireFreeAll(mire, nmire); 00400 /*@=refcounttrans@*/ 00401 } 00402 00410 static int rpmfcHelper(rpmfc fc, unsigned char deptype, const char * nsdep) 00411 /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/ 00412 /*@modifies fc, rpmGlobalMacroContext, fileSystem, internalState @*/ 00413 { 00414 miRE mire = NULL; 00415 int nmire = 0; 00416 const char * fn = fc->fn[fc->ix]; 00417 char buf[BUFSIZ]; 00418 rpmiob iob_stdout = NULL; 00419 rpmiob iob_stdin; 00420 const char *av[2]; 00421 rpmds * depsp, ds; 00422 const char * N; 00423 const char * EVR; 00424 rpmTag tagN; 00425 evrFlags Flags; 00426 evrFlags dsContext; 00427 ARGV_t pav; 00428 const char * s; 00429 int pac; 00430 int xx; 00431 int i; 00432 00433 switch (deptype) { 00434 default: 00435 return -1; 00436 /*@notreached@*/ break; 00437 case 'P': 00438 if (fc->skipProv) 00439 return 0; 00440 xx = snprintf(buf, sizeof(buf), "%%{?__%s_provides}", nsdep); 00441 depsp = &fc->provides; 00442 dsContext = RPMSENSE_FIND_PROVIDES; 00443 tagN = RPMTAG_PROVIDENAME; 00444 mire = fc->Pmires; 00445 nmire = fc->Pnmire; 00446 break; 00447 case 'R': 00448 if (fc->skipReq) 00449 return 0; 00450 xx = snprintf(buf, sizeof(buf), "%%{?__%s_requires}", nsdep); 00451 depsp = &fc->requires; 00452 dsContext = RPMSENSE_FIND_REQUIRES; 00453 tagN = RPMTAG_REQUIRENAME; 00454 mire = fc->Rmires; 00455 nmire = fc->Rnmire; 00456 break; 00457 } 00458 buf[sizeof(buf)-1] = '\0'; 00459 av[0] = buf; 00460 av[1] = NULL; 00461 00462 iob_stdin = rpmiobNew(0); 00463 iob_stdin = rpmiobAppend(iob_stdin, fn, 1); 00464 iob_stdout = NULL; 00465 xx = rpmfcExec(av, iob_stdin, &iob_stdout, 0); 00466 iob_stdin = rpmiobFree(iob_stdin); 00467 00468 if (xx == 0 && iob_stdout != NULL) { 00469 pav = NULL; 00470 xx = argvSplit(&pav, rpmiobStr(iob_stdout), " \t\n\r"); 00471 pac = argvCount(pav); 00472 if (pav) 00473 for (i = 0; i < pac; i++) { 00474 N = pav[i]; 00475 EVR = ""; 00476 Flags = dsContext; 00477 if (pav[i+1] && strchr("=<>", *pav[i+1])) { 00478 i++; 00479 for (s = pav[i]; *s; s++) { 00480 switch(*s) { 00481 default: 00482 assert(*s != '\0'); 00483 /*@switchbreak@*/ break; 00484 case '=': 00485 Flags |= RPMSENSE_EQUAL; 00486 /*@switchbreak@*/ break; 00487 case '<': 00488 Flags |= RPMSENSE_LESS; 00489 /*@switchbreak@*/ break; 00490 case '>': 00491 Flags |= RPMSENSE_GREATER; 00492 /*@switchbreak@*/ break; 00493 } 00494 } 00495 i++; 00496 EVR = pav[i]; 00497 assert(EVR != NULL); 00498 } 00499 00500 if (_filter_values && rpmfcMatchRegexps(mire, nmire, N, deptype)) 00501 continue; 00502 00503 /* Add tracking dependency for versioned Provides: */ 00504 if (!fc->tracked && deptype == 'P' && *EVR != '\0') { 00505 ds = rpmdsSingle(RPMTAG_REQUIRENAME, 00506 "rpmlib(VersionedDependencies)", "3.0.3-1", 00507 RPMSENSE_RPMLIB|(RPMSENSE_LESS|RPMSENSE_EQUAL)); 00508 xx = rpmdsMerge(&fc->requires, ds); 00509 (void)rpmdsFree(ds); 00510 ds = NULL; 00511 fc->tracked = 1; 00512 } 00513 00514 ds = rpmdsSingle(tagN, N, EVR, Flags); 00515 00516 #if defined(RPM_VENDOR_MANDRIVA) /* filter-overlapping-dependencies */ 00517 int overlap = 0; 00518 if (*depsp && rpmExpandNumeric("%{?_use_internal_dependency_generator}")) { 00519 int ix = rpmdsSearch(*depsp, ds); 00520 if (ix >= 0) { 00521 EVR_t lEVR = rpmEVRnew(RPMSENSE_ANY, 0), 00522 rEVR = rpmEVRnew(RPMSENSE_ANY, 0); 00523 00524 rpmdsSetIx(*depsp, ix); 00525 00526 rpmEVRparse(rpmdsEVR(*depsp), lEVR); 00527 rpmEVRparse(EVR, rEVR); 00528 lEVR->Flags = rpmdsFlags(*depsp) | RPMSENSE_EQUAL; 00529 rEVR->Flags = Flags | RPMSENSE_EQUAL; 00530 00531 if (rpmEVRcompare(lEVR, rEVR) < 0) { 00532 (*depsp)->EVR[(*depsp)->i] = EVR; 00533 (*depsp)->Flags[(*depsp)->i] = Flags; 00534 overlap = 1; 00535 } 00536 lEVR = rpmEVRfree(lEVR); 00537 rEVR = rpmEVRfree(rEVR); 00538 } 00539 } 00540 if (!overlap) 00541 #endif 00542 /* Add to package dependencies. */ 00543 xx = rpmdsMerge(depsp, ds); 00544 00545 /* Add to file dependencies. */ 00546 xx = rpmfcSaveArg(&fc->ddict, rpmfcFileDep(buf, fc->ix, ds)); 00547 00548 (void)rpmdsFree(ds); 00549 ds = NULL; 00550 } 00551 00552 pav = argvFree(pav); 00553 } 00554 iob_stdout = rpmiobFree(iob_stdout); 00555 00556 return 0; 00557 } 00558 00561 /*@-nullassign@*/ 00562 /*@unchecked@*/ /*@observer@*/ 00563 static struct rpmfcTokens_s rpmfcTokens[] = { 00564 { "directory", RPMFC_DIRECTORY|RPMFC_INCLUDE }, 00565 00566 { " shared object", RPMFC_LIBRARY }, 00567 { " executable", RPMFC_EXECUTABLE }, 00568 { " statically linked", RPMFC_STATIC }, 00569 { " not stripped", RPMFC_NOTSTRIPPED }, 00570 { " archive", RPMFC_ARCHIVE }, 00571 00572 { "MIPS, N32 MIPS32", RPMFC_ELFMIPSN32|RPMFC_INCLUDE }, 00573 { "ELF 32-bit", RPMFC_ELF32|RPMFC_INCLUDE }, 00574 { "ELF 64-bit", RPMFC_ELF64|RPMFC_INCLUDE }, 00575 00576 { " script", RPMFC_SCRIPT }, 00577 { " text", RPMFC_TEXT }, 00578 { " document", RPMFC_DOCUMENT }, 00579 00580 { " compressed", RPMFC_COMPRESSED }, 00581 00582 { "troff or preprocessor input", RPMFC_MANPAGE|RPMFC_INCLUDE }, 00583 { "GNU Info", RPMFC_MANPAGE|RPMFC_INCLUDE }, 00584 00585 { "perl script text", RPMFC_PERL|RPMFC_INCLUDE }, 00586 { "Perl5 module source text", RPMFC_PERL|RPMFC_MODULE|RPMFC_INCLUDE }, 00587 00588 { "PHP script text", RPMFC_PHP|RPMFC_INCLUDE }, 00589 00590 /* XXX "a /usr/bin/python -t script text executable" */ 00591 /* XXX "python 2.3 byte-compiled" */ 00592 { " /usr/bin/python", RPMFC_PYTHON|RPMFC_INCLUDE }, 00593 { "python ", RPMFC_PYTHON|RPMFC_INCLUDE }, 00594 00595 { "libtool library ", RPMFC_LIBTOOL|RPMFC_INCLUDE }, 00596 { "pkgconfig ", RPMFC_PKGCONFIG|RPMFC_INCLUDE }, 00597 00598 { "Bourne ", RPMFC_BOURNE|RPMFC_INCLUDE }, 00599 { "Bourne-Again ", RPMFC_BOURNE|RPMFC_INCLUDE }, 00600 00601 { "Java ", RPMFC_JAVA|RPMFC_INCLUDE }, 00602 00603 { "Mono/.Net assembly", RPMFC_MONO|RPMFC_INCLUDE }, 00604 00605 { "ruby script text", RPMFC_RUBY|RPMFC_INCLUDE }, 00606 { "Ruby script text", RPMFC_RUBY|RPMFC_INCLUDE }, 00607 00608 { "current ar archive", RPMFC_STATIC|RPMFC_LIBRARY|RPMFC_ARCHIVE|RPMFC_INCLUDE }, 00609 00610 { "Zip archive data", RPMFC_COMPRESSED|RPMFC_ARCHIVE|RPMFC_INCLUDE }, 00611 { "tar archive", RPMFC_ARCHIVE|RPMFC_INCLUDE }, 00612 { "cpio archive", RPMFC_ARCHIVE|RPMFC_INCLUDE }, 00613 { "RPM v3", RPMFC_ARCHIVE|RPMFC_INCLUDE }, 00614 { "RPM v4", RPMFC_ARCHIVE|RPMFC_INCLUDE }, 00615 00616 { " image", RPMFC_IMAGE|RPMFC_INCLUDE }, 00617 { " font", RPMFC_FONT|RPMFC_INCLUDE }, 00618 { " Font", RPMFC_FONT|RPMFC_INCLUDE }, 00619 00620 { " commands", RPMFC_SCRIPT|RPMFC_INCLUDE }, 00621 { " script", RPMFC_SCRIPT|RPMFC_INCLUDE }, 00622 00623 { "empty", RPMFC_WHITE|RPMFC_INCLUDE }, 00624 00625 { "HTML", RPMFC_WHITE|RPMFC_INCLUDE }, 00626 { "SGML", RPMFC_WHITE|RPMFC_INCLUDE }, 00627 { "XML", RPMFC_WHITE|RPMFC_INCLUDE }, 00628 00629 { " program text", RPMFC_WHITE|RPMFC_INCLUDE }, 00630 { " source", RPMFC_WHITE|RPMFC_INCLUDE }, 00631 { "GLS_BINARY_LSB_FIRST", RPMFC_WHITE|RPMFC_INCLUDE }, 00632 { " DB ", RPMFC_WHITE|RPMFC_INCLUDE }, 00633 00634 { "ASCII English text", RPMFC_WHITE|RPMFC_INCLUDE }, 00635 { "ASCII text", RPMFC_WHITE|RPMFC_INCLUDE }, 00636 { "ISO-8859 text", RPMFC_WHITE|RPMFC_INCLUDE }, 00637 00638 { "symbolic link to", RPMFC_SYMLINK }, 00639 { "socket", RPMFC_DEVICE }, 00640 { "special", RPMFC_DEVICE }, 00641 00642 { "ASCII", RPMFC_WHITE }, 00643 { "ISO-8859", RPMFC_WHITE }, 00644 00645 { "data", RPMFC_WHITE }, 00646 00647 { "application", RPMFC_WHITE }, 00648 { "boot", RPMFC_WHITE }, 00649 { "catalog", RPMFC_WHITE }, 00650 { "code", RPMFC_WHITE }, 00651 { "file", RPMFC_WHITE }, 00652 { "format", RPMFC_WHITE }, 00653 { "message", RPMFC_WHITE }, 00654 { "program", RPMFC_WHITE }, 00655 00656 { "broken symbolic link to ", RPMFC_WHITE|RPMFC_ERROR }, 00657 { "can't read", RPMFC_WHITE|RPMFC_ERROR }, 00658 { "can't stat", RPMFC_WHITE|RPMFC_ERROR }, 00659 { "executable, can't read", RPMFC_WHITE|RPMFC_ERROR }, 00660 { "core file", RPMFC_WHITE|RPMFC_ERROR }, 00661 00662 { NULL, RPMFC_BLACK } 00663 }; 00664 /*@=nullassign@*/ 00665 00666 int rpmfcColoring(const char * fmstr) 00667 { 00668 rpmfcToken fct; 00669 int fcolor = RPMFC_BLACK; 00670 00671 for (fct = rpmfcTokens; fct->token != NULL; fct++) { 00672 if (strstr(fmstr, fct->token) == NULL) 00673 continue; 00674 fcolor |= fct->colors; 00675 if (fcolor & RPMFC_INCLUDE) 00676 return fcolor; 00677 } 00678 return fcolor; 00679 } 00680 00681 void rpmfcPrint(const char * msg, rpmfc fc, FILE * fp) 00682 { 00683 int fcolor; 00684 int ndx; 00685 int cx; 00686 int dx; 00687 size_t fx; 00688 00689 unsigned nprovides; 00690 unsigned nrequires; 00691 00692 if (fp == NULL) fp = stderr; 00693 00694 if (msg) 00695 fprintf(fp, "===================================== %s\n", msg); 00696 00697 nprovides = rpmdsCount(fc->provides); 00698 nrequires = rpmdsCount(fc->requires); 00699 00700 if (fc) 00701 for (fx = 0; fx < fc->nfiles; fx++) { 00702 assert(fx < fc->fcdictx->nvals); 00703 cx = fc->fcdictx->vals[fx]; 00704 assert(fx < fc->fcolor->nvals); 00705 fcolor = fc->fcolor->vals[fx]; 00706 00707 fprintf(fp, "%3d %s", (int)fx, fc->fn[fx]); 00708 if (fcolor != RPMFC_BLACK) 00709 fprintf(fp, "\t0x%x", fc->fcolor->vals[fx]); 00710 else 00711 fprintf(fp, "\t%s", fc->cdict[cx]); 00712 fprintf(fp, "\n"); 00713 00714 if (fc->fddictx == NULL || fc->fddictn == NULL) 00715 continue; 00716 00717 assert(fx < fc->fddictx->nvals); 00718 dx = fc->fddictx->vals[fx]; 00719 assert(fx < fc->fddictn->nvals); 00720 ndx = fc->fddictn->vals[fx]; 00721 00722 while (ndx-- > 0) { 00723 const char * depval; 00724 unsigned char deptype; 00725 unsigned ix; 00726 00727 ix = fc->ddictx->vals[dx++]; 00728 deptype = ((ix >> 24) & 0xff); 00729 ix &= 0x00ffffff; 00730 depval = NULL; 00731 switch (deptype) { 00732 default: 00733 assert(depval != NULL); 00734 /*@switchbreak@*/ break; 00735 case 'P': 00736 if (nprovides > 0) { 00737 assert(ix < nprovides); 00738 (void) rpmdsSetIx(fc->provides, ix-1); 00739 if (rpmdsNext(fc->provides) >= 0) 00740 depval = rpmdsDNEVR(fc->provides); 00741 } 00742 /*@switchbreak@*/ break; 00743 case 'R': 00744 if (nrequires > 0) { 00745 assert(ix < nrequires); 00746 (void) rpmdsSetIx(fc->requires, ix-1); 00747 if (rpmdsNext(fc->requires) >= 0) 00748 depval = rpmdsDNEVR(fc->requires); 00749 } 00750 /*@switchbreak@*/ break; 00751 } 00752 if (depval) 00753 fprintf(fp, "\t%s\n", depval); 00754 } 00755 } 00756 } 00757 00763 static int rpmfcSCRIPT(rpmfc fc) 00764 /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/ 00765 /*@modifies fc, rpmGlobalMacroContext, fileSystem, internalState @*/ 00766 { 00767 const char * fn = fc->fn[fc->ix]; 00768 const char * bn; 00769 rpmds ds; 00770 char buf[BUFSIZ]; 00771 FILE * fp; 00772 char * s, * se; 00773 int i; 00774 int is_executable; 00775 int xx; 00776 const char * defaultdocdir = NULL; 00777 00778 /* Extract dependencies only from files with executable bit set. */ 00779 { struct stat sb, * st = &sb; 00780 if (stat(fn, st) != 0) 00781 return -1; 00782 is_executable = (int)(st->st_mode & (S_IXUSR|S_IXGRP|S_IXOTH)); 00783 } 00784 00785 fp = fopen(fn, "r"); 00786 if (fp == NULL || ferror(fp)) { 00787 if (fp) (void) fclose(fp); 00788 return -1; 00789 } 00790 00791 /* Look for #! interpreter in first 10 lines. */ 00792 for (i = 0; i < 10; i++) { 00793 00794 s = fgets(buf, sizeof(buf) - 1, fp); 00795 if (s == NULL || ferror(fp) || feof(fp)) 00796 break; 00797 s[sizeof(buf)-1] = '\0'; 00798 if (!(s[0] == '#' && s[1] == '!')) 00799 continue; 00800 s += 2; 00801 00802 while (*s && strchr(" \t\n\r", *s) != NULL) 00803 s++; 00804 if (*s == '\0') 00805 continue; 00806 if (*s != '/') 00807 continue; 00808 00809 for (se = s+1; *se; se++) { 00810 if (strchr(" \t\n\r", *se) != NULL) 00811 /*@innerbreak@*/ break; 00812 } 00813 *se = '\0'; 00814 se++; 00815 00816 if (!_filter_values 00817 || (!fc->skipReq 00818 && !rpmfcMatchRegexps(fc->Rmires, fc->Rnmire, s, 'R'))) 00819 if (is_executable) { 00820 /* Add to package requires. */ 00821 ds = rpmdsSingle(RPMTAG_REQUIRENAME, s, "", RPMSENSE_FIND_REQUIRES); 00822 xx = rpmdsMerge(&fc->requires, ds); 00823 00824 /* Add to file requires. */ 00825 xx = rpmfcSaveArg(&fc->ddict, rpmfcFileDep(se, fc->ix, ds)); 00826 00827 (void)rpmdsFree(ds); 00828 ds = NULL; 00829 } 00830 00831 /* Set color based on interpreter name. */ 00832 /* XXX magic token should have already done this?!? */ 00833 /*@-moduncon@*/ 00834 bn = basename(s); 00835 /*@=moduncon@*/ 00836 if (!strcmp(bn, "perl")) 00837 fc->fcolor->vals[fc->ix] |= RPMFC_PERL; 00838 else if (!strncmp(bn, "python", sizeof("python")-1)) 00839 fc->fcolor->vals[fc->ix] |= RPMFC_PYTHON; 00840 else if (!strncmp(bn, "php", sizeof("php")-1)) 00841 fc->fcolor->vals[fc->ix] |= RPMFC_PHP; 00842 else if (!strncmp(bn, "ruby", sizeof("ruby")-1)) 00843 fc->fcolor->vals[fc->ix] |= RPMFC_RUBY; 00844 00845 break; 00846 } 00847 00848 (void) fclose(fp); 00849 00850 if (fc->fcolor->vals[fc->ix] & RPMFC_PERL) { 00851 defaultdocdir = rpmExpand("%{?_defaultdocdir}", NULL); 00852 if (defaultdocdir == NULL || *defaultdocdir == '\0') 00853 defaultdocdir = "/usr/share/doc"; 00854 00855 if (strncmp(fn, defaultdocdir, sizeof(defaultdocdir)-1)) { 00856 if (fc->fcolor->vals[fc->ix] & RPMFC_MODULE) 00857 xx = rpmfcHelper(fc, 'P', "perl"); 00858 if (is_executable || (fc->fcolor->vals[fc->ix] & RPMFC_MODULE)) 00859 xx = rpmfcHelper(fc, 'R', "perl"); 00860 } 00861 } else 00862 if (fc->fcolor->vals[fc->ix] & RPMFC_PYTHON) { 00863 xx = rpmfcHelper(fc, 'P', "python"); 00864 #ifdef NOTYET 00865 if (is_executable) 00866 #endif 00867 xx = rpmfcHelper(fc, 'R', "python"); 00868 } else 00869 if (fc->fcolor->vals[fc->ix] & RPMFC_LIBTOOL) { 00870 xx = rpmfcHelper(fc, 'P', "libtool"); 00871 #ifdef NOTYET 00872 if (is_executable) 00873 #endif 00874 xx = rpmfcHelper(fc, 'R', "libtool"); 00875 } else 00876 if (fc->fcolor->vals[fc->ix] & RPMFC_PKGCONFIG) { 00877 xx = rpmfcHelper(fc, 'P', "pkgconfig"); 00878 #ifdef NOTYET 00879 if (is_executable) 00880 #endif 00881 xx = rpmfcHelper(fc, 'R', "pkgconfig"); 00882 } else 00883 if (fc->fcolor->vals[fc->ix] & RPMFC_BOURNE) { 00884 #ifdef NOTYET 00885 xx = rpmfcHelper(fc, 'P', "executable"); 00886 #endif 00887 if (is_executable) 00888 xx = rpmfcHelper(fc, 'R', "executable"); 00889 } else 00890 if (fc->fcolor->vals[fc->ix] & RPMFC_PHP) { 00891 xx = rpmfcHelper(fc, 'P', "php"); 00892 if (is_executable) 00893 xx = rpmfcHelper(fc, 'R', "php"); 00894 } else 00895 if (fc->fcolor->vals[fc->ix] & RPMFC_MONO) { 00896 xx = rpmfcHelper(fc, 'P', "mono"); 00897 if (is_executable) 00898 xx = rpmfcHelper(fc, 'R', "mono"); 00899 } else 00900 if (fc->fcolor->vals[fc->ix] & RPMFC_RUBY) { 00901 xx = rpmfcHelper(fc, 'P', "ruby"); 00902 #ifdef NOTYET 00903 if (is_executable) 00904 #endif 00905 xx = rpmfcHelper(fc, 'R', "ruby"); 00906 } else 00907 if ((fc->fcolor->vals[fc->ix] & (RPMFC_MODULE|RPMFC_LIBRARY)) && 00908 strstr(fn, "/gstreamer")) { 00909 xx = rpmfcHelper(fc, 'P', "gstreamer"); 00910 /* XXX: currently of no use, but for the sake of consistency... */ 00911 xx = rpmfcHelper(fc, 'R', "gstreamer"); 00912 #if defined(RPM_VENDOR_MANDRIVA) 00913 } else 00914 if ((fc->fcolor->vals[fc->ix] & RPMFC_MODULE)) { 00915 miRE mire = mireNew(RPMMIRE_REGEX, RPMTAG_FILEPATHS); 00916 if (!mireRegcomp(mire, "^.*(/lib/modules/|/var/lib/dkms/).*\\.ko(\\.gz|\\.xz)?$")) 00917 if (mireRegexec(mire, fc->fn[fc->ix], (size_t) 0) >= 0) { 00918 fc->fcolor->vals[fc->ix] |= (RPMFC_MODULE|RPMFC_SCRIPT); 00919 xx = rpmfcHelper(fc, 'P', "kernel"); 00920 /* XXX: currently of no use, but for the sake of consistency... */ 00921 xx = rpmfcHelper(fc, 'R', "kernel"); 00922 } 00923 mire = mireFree(mire); 00924 #endif 00925 } 00926 00927 /*@-observertrans@*/ 00928 defaultdocdir = _free(defaultdocdir) ; 00929 /*@=observertrans@*/ 00930 return 0; 00931 } 00932 00939 static int rpmfcMergePR(void * context, rpmds ds) 00940 /*@globals fileSystem, internalState @*/ 00941 /*@modifies ds, fileSystem, internalState @*/ 00942 { 00943 rpmfc fc = context; 00944 char buf[BUFSIZ]; 00945 int rc = 0; 00946 00947 if (_rpmfc_debug < 0) 00948 fprintf(stderr, "*** rpmfcMergePR(%p, %p) %s\n", context, ds, tagName(rpmdsTagN(ds))); 00949 switch(rpmdsTagN(ds)) { 00950 default: 00951 rc = -1; 00952 break; 00953 case RPMTAG_PROVIDENAME: 00954 if (!_filter_values 00955 || (!fc->skipProv 00956 && !rpmfcMatchRegexps(fc->Pmires, fc->Pnmire, ds->N[0], 'P'))) 00957 { 00958 /* Add to package provides. */ 00959 rc = rpmdsMerge(&fc->provides, ds); 00960 00961 /* Add to file dependencies. */ 00962 buf[0] = '\0'; 00963 rc = rpmfcSaveArg(&fc->ddict, rpmfcFileDep(buf, fc->ix, ds)); 00964 } 00965 break; 00966 case RPMTAG_REQUIRENAME: 00967 if (!_filter_values 00968 || (!fc->skipReq 00969 && !rpmfcMatchRegexps(fc->Rmires, fc->Rnmire, ds->N[0], 'R'))) 00970 { 00971 /* Add to package requires. */ 00972 rc = rpmdsMerge(&fc->requires, ds); 00973 00974 /* Add to file dependencies. */ 00975 buf[0] = '\0'; 00976 rc = rpmfcSaveArg(&fc->ddict, rpmfcFileDep(buf, fc->ix, ds)); 00977 } 00978 break; 00979 } 00980 return rc; 00981 } 00982 00988 static int rpmfcELF(rpmfc fc) 00989 /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/ 00990 /*@modifies rpmGlobalMacroContext, fileSystem, internalState @*/ 00991 { 00992 const char * fn = fc->fn[fc->ix]; 00993 int flags = 0; 00994 00995 if (fc->skipProv) 00996 flags |= RPMELF_FLAG_SKIPPROVIDES; 00997 if (fc->skipReq) 00998 flags |= RPMELF_FLAG_SKIPREQUIRES; 00999 01000 return rpmdsELF(fn, flags, rpmfcMergePR, fc); 01001 } 01002 01003 #if defined(RPM_VENDOR_MANDRIVA) 01004 01013 extern int rpmdsSymlink(const char * fn, int flags, 01014 int (*add) (void * context, rpmds ds), void * context) 01015 /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/ 01016 /*@modifies rpmGlobalMacroContext, fileSystem, internalState @*/; 01017 01018 static int rpmfcSYMLINK(rpmfc fc) 01019 /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/ 01020 /*@modifies rpmGlobalMacroContext, fileSystem, internalState @*/ 01021 { 01022 const char * fn = fc->fn[fc->ix]; 01023 int flags = 0; 01024 01025 if (fc->skipProv) 01026 flags |= RPMELF_FLAG_SKIPPROVIDES; 01027 if (fc->skipReq) 01028 flags |= RPMELF_FLAG_SKIPREQUIRES; 01029 /* XXX: Remove symlink classifier from linker scripts now that we've been 01030 * able to feed it to the generator. 01031 */ 01032 if (fc->fcolor->vals[fc->ix] == (RPMFC_WHITE|RPMFC_INCLUDE|RPMFC_TEXT|RPMFC_SYMLINK)) 01033 fc->fcolor->vals[fc->ix] &= ~RPMFC_SYMLINK; 01034 01035 return rpmdsSymlink(fn, flags, rpmfcMergePR, fc); 01036 } 01037 #endif /* RPM_VENDOR_MANDRIVA */ 01038 01039 typedef struct rpmfcApplyTbl_s { 01040 int (*func) (rpmfc fc); 01041 int colormask; 01042 } * rpmfcApplyTbl; 01043 01047 /*@-nullassign@*/ 01048 /*@unchecked@*/ 01049 static struct rpmfcApplyTbl_s rpmfcApplyTable[] = { 01050 { rpmfcELF, RPMFC_ELF }, 01051 { rpmfcSCRIPT, (RPMFC_SCRIPT|RPMFC_PERL|RPMFC_PYTHON|RPMFC_LIBTOOL|RPMFC_PKGCONFIG|RPMFC_BOURNE|RPMFC_JAVA|RPMFC_PHP|RPMFC_MONO) }, 01052 #if defined(RPM_VENDOR_MANDRIVA) 01053 { rpmfcSYMLINK, RPMFC_SYMLINK }, 01054 #endif 01055 { NULL, 0 } 01056 }; 01057 /*@=nullassign@*/ 01058 01059 rpmRC rpmfcApply(rpmfc fc) 01060 { 01061 rpmfcApplyTbl fcat; 01062 const char * s; 01063 char * se; 01064 rpmds ds; 01065 const char * fn; 01066 const char * N; 01067 const char * EVR; 01068 evrFlags Flags; 01069 unsigned char deptype; 01070 int nddict; 01071 int previx; 01072 unsigned int val; 01073 int dix; 01074 int ix; 01075 int i; 01076 int xx; 01077 int skipping; 01078 01079 miRE mire; 01080 int skipProv = fc->skipProv; 01081 int skipReq = fc->skipReq; 01082 int j; 01083 01084 if (_filter_execs) { 01085 fc->PFnmire = 0; 01086 fc->PFmires = rpmfcExpandRegexps("%{?__noautoprovfiles}", &fc->PFnmire); 01087 if (fc->PFnmire > 0) 01088 rpmlog(RPMLOG_DEBUG, D_("added %d %%__noautoprovfiles patterns.\n"), 01089 fc->PFnmire); 01090 fc->RFnmire = 0; 01091 fc->RFmires = rpmfcExpandRegexps("%{?__noautoreqfiles}", &fc->RFnmire); 01092 if (fc->RFnmire > 0) 01093 rpmlog(RPMLOG_DEBUG, D_("added %d %%__noautoreqfiles patterns.\n"), 01094 fc->RFnmire); 01095 fc->Pnmire = 0; 01096 fc->Pmires = rpmfcExpandRegexps("%{?__noautoprov}", &fc->Pnmire); 01097 if (fc->Pnmire > 0) 01098 rpmlog(RPMLOG_DEBUG, D_("added %d %%__noautoprov patterns.\n"), 01099 fc->Pnmire); 01100 fc->Rnmire = 0; 01101 fc->Rmires = rpmfcExpandRegexps("%{?__noautoreq}", &fc->Rnmire); 01102 if (fc->Rnmire > 0) 01103 rpmlog(RPMLOG_DEBUG, D_("added %d %%__noautoreq patterns.\n"), 01104 fc->Rnmire); 01105 } 01106 01107 /* Make sure something didn't go wrong previously! */ 01108 assert(fc->fn != NULL); 01109 /* Generate package and per-file dependencies. */ 01110 for (fc->ix = 0; fc->fn[fc->ix] != NULL; fc->ix++) { 01111 01112 /* XXX Insure that /usr/lib{,64}/python files are marked RPMFC_PYTHON */ 01113 /* XXX HACK: classification by path is intrinsically stupid. */ 01114 { fn = strstr(fc->fn[fc->ix], "/usr/lib"); 01115 if (fn) { 01116 fn += sizeof("/usr/lib")-1; 01117 if ((fn[0] == '3' && fn[1] == '2') || 01118 (fn[0] == '6' && fn[1] == '4')) 01119 fn += 2; 01120 if (!strncmp(fn, "/python", sizeof("/python")-1)) 01121 fc->fcolor->vals[fc->ix] |= RPMFC_PYTHON; 01122 else if (!strncmp(fn, "/ruby", sizeof("/ruby")-1)) { 01123 fc->fcolor->vals[fc->ix] |= RPMFC_RUBY; 01124 if ((fn = strstr(fn, "/specifications/")) && 01125 (fn = strrchr(fn, '.')) && !strcmp(fn, ".gemspec")) 01126 fc->fcolor->vals[fc->ix] |= RPMFC_MODULE; 01127 } 01128 /* XXX: lacking better, more generic classifier... */ 01129 else if (!strncmp(fn, "/gstreamer", sizeof("/gstreamer")-1) && 01130 fc->fcolor->vals[fc->ix] & RPMFC_LIBRARY) 01131 fc->fcolor->vals[fc->ix] |= (RPMFC_MODULE|RPMFC_SCRIPT); 01132 #if defined(RPM_VENDOR_MANDRIVA) 01133 } else { 01134 miRE mire = mireNew(RPMMIRE_REGEX, RPMTAG_FILEPATHS); 01135 if (!mireRegcomp(mire, "^.*(/lib/modules/|/var/lib/dkms/).*\\.ko(\\.gz|\\.xz)?$")) 01136 if (mireRegexec(mire, fc->fn[fc->ix], (size_t) 0) >= 0) 01137 fc->fcolor->vals[fc->ix] |= (RPMFC_MODULE|RPMFC_SCRIPT); 01138 mire = mireFree(mire); 01139 #endif 01140 } 01141 } 01142 01143 if (fc->fcolor->vals[fc->ix]) 01144 for (fcat = rpmfcApplyTable; fcat->func != NULL; fcat++) { 01145 if (!(fc->fcolor->vals[fc->ix] & fcat->colormask)) 01146 /*@innercontinue@*/ continue; 01147 01148 if (_filter_execs) { 01149 fc->skipProv = skipProv; 01150 fc->skipReq = skipReq; 01151 if ((mire = fc->PFmires) != NULL) 01152 for (j = 0; j < fc->PFnmire; j++, mire++) { 01153 fn = fc->fn[fc->ix] + fc->brlen; 01154 if ((xx = mireRegexec(mire, fn, 0)) < 0) 01155 /*@innercontinue@*/ continue; 01156 rpmlog(RPMLOG_NOTICE, _("skipping %s provides detection\n"), 01157 fn); 01158 fc->skipProv = 1; 01159 /*@innerbreak@*/ break; 01160 } 01161 if ((mire = fc->RFmires) != NULL) 01162 for (j = 0; j < fc->RFnmire; j++, mire++) { 01163 fn = fc->fn[fc->ix] + fc->brlen; 01164 if ((xx = mireRegexec(mire, fn, 0)) < 0) 01165 /*@innercontinue@*/ continue; 01166 rpmlog(RPMLOG_NOTICE, _("skipping %s requires detection\n"), 01167 fn); 01168 fc->skipReq = 1; 01169 /*@innerbreak@*/ break; 01170 } 01171 } 01172 01173 xx = (*fcat->func) (fc); 01174 } 01175 } 01176 01177 if (_filter_execs) { 01178 fc->PFmires = rpmfcFreeRegexps(fc->PFmires, fc->PFnmire); 01179 fc->RFmires = rpmfcFreeRegexps(fc->RFmires, fc->RFnmire); 01180 fc->Pmires = rpmfcFreeRegexps(fc->Pmires, fc->Pnmire); 01181 fc->Rmires = rpmfcFreeRegexps(fc->Rmires, fc->Rnmire); 01182 } 01183 fc->skipProv = skipProv; 01184 fc->skipReq = skipReq; 01185 01186 /* Generate per-file indices into package dependencies. */ 01187 nddict = argvCount(fc->ddict); 01188 previx = -1; 01189 for (i = 0; i < nddict; i++) { 01190 s = fc->ddict[i]; 01191 01192 /* Parse out (file#,deptype,N,EVR,Flags) */ 01193 ix = strtol(s, &se, 10); 01194 assert(se != NULL); 01195 deptype = *se++; 01196 se++; 01197 N = se; 01198 while (*se && *se != ' ') 01199 se++; 01200 *se++ = '\0'; 01201 EVR = se; 01202 while (*se && *se != ' ') 01203 se++; 01204 *se++ = '\0'; 01205 Flags = strtol(se, NULL, 16); 01206 01207 dix = -1; 01208 skipping = 0; 01209 switch (deptype) { 01210 default: 01211 /*@switchbreak@*/ break; 01212 case 'P': 01213 skipping = fc->skipProv; 01214 ds = rpmdsSingle(RPMTAG_PROVIDENAME, N, EVR, Flags); 01215 dix = rpmdsFind(fc->provides, ds); 01216 (void)rpmdsFree(ds); 01217 ds = NULL; 01218 /*@switchbreak@*/ break; 01219 case 'R': 01220 skipping = fc->skipReq; 01221 ds = rpmdsSingle(RPMTAG_REQUIRENAME, N, EVR, Flags); 01222 dix = rpmdsFind(fc->requires, ds); 01223 (void)rpmdsFree(ds); 01224 ds = NULL; 01225 /*@switchbreak@*/ break; 01226 } 01227 01228 /* XXX assertion incorrect while generating -debuginfo deps. */ 01229 #if 0 01230 assert(dix >= 0); 01231 #else 01232 if (dix < 0) 01233 continue; 01234 #endif 01235 01236 val = (deptype << 24) | (dix & 0x00ffffff); 01237 xx = argiAdd(&fc->ddictx, -1, val); 01238 01239 if (previx != ix) { 01240 previx = ix; 01241 xx = argiAdd(&fc->fddictx, ix, argiCount(fc->ddictx)-1); 01242 } 01243 if (fc->fddictn && fc->fddictn->vals && !skipping) 01244 fc->fddictn->vals[ix]++; 01245 } 01246 01247 return RPMRC_OK; 01248 } 01249 01250 rpmRC rpmfcClassify(rpmfc fc, ARGV_t argv, rpmuint16_t * fmode) 01251 { 01252 ARGV_t fcav = NULL; 01253 ARGV_t dav; 01254 rpmmg mg = NULL; 01255 const char * s, * se; 01256 size_t slen; 01257 int fcolor; 01258 int xx; 01259 const char * magicfile = NULL; 01260 01261 if (fc == NULL || argv == NULL) 01262 return RPMRC_OK; 01263 01264 magicfile = rpmExpand("%{?_rpmfc_magic_path}", NULL); 01265 if (magicfile == NULL || *magicfile == '\0') 01266 magicfile = _free(magicfile); 01267 01268 mg = rpmmgNew(magicfile, 0); 01269 assert(mg != NULL); /* XXX figger a proper return path. */ 01270 01271 fc->nfiles = argvCount(argv); 01272 01273 /* Initialize the per-file dictionary indices. */ 01274 xx = argiAdd(&fc->fddictx, fc->nfiles-1, 0); 01275 xx = argiAdd(&fc->fddictn, fc->nfiles-1, 0); 01276 01277 /* Build (sorted) file class dictionary. */ 01278 xx = argvAdd(&fc->cdict, ""); 01279 xx = argvAdd(&fc->cdict, "directory"); 01280 01281 for (fc->ix = 0; fc->ix < fc->nfiles; fc->ix++) { 01282 const char * ftype; 01283 int freeftype; 01284 rpmuint16_t mode = (fmode ? fmode[fc->ix] : 0); 01285 int urltype; 01286 01287 ftype = ""; freeftype = 0; 01288 urltype = urlPath(argv[fc->ix], &s); 01289 assert(s != NULL && *s == '/'); 01290 slen = strlen(s); 01291 01292 switch (mode & S_IFMT) { 01293 case S_IFCHR: ftype = "character special"; /*@switchbreak@*/ break; 01294 case S_IFBLK: ftype = "block special"; /*@switchbreak@*/ break; 01295 #if defined(S_IFIFO) 01296 case S_IFIFO: ftype = "fifo (named pipe)"; /*@switchbreak@*/ break; 01297 #endif 01298 #if defined(S_IFSOCK) 01299 /*@-unrecog@*/ 01300 case S_IFSOCK: ftype = "socket"; /*@switchbreak@*/ break; 01301 /*@=unrecog@*/ 01302 #endif 01303 case S_IFDIR: 01304 case S_IFLNK: 01305 case S_IFREG: 01306 default: 01307 01308 #define _suffix(_s, _x) \ 01309 (slen >= sizeof(_x) && !strcmp((_s)+slen-(sizeof(_x)-1), (_x))) 01310 01311 /* XXX all files with extension ".pm" are perl modules for now. */ 01312 if (_suffix(s, ".pm")) 01313 ftype = "Perl5 module source text"; 01314 01315 /* XXX all files with extension ".jar" are java archives for now. */ 01316 else if (_suffix(s, ".jar")) 01317 ftype = "Java archive file"; 01318 01319 /* XXX all files with extension ".class" are java class files for now. */ 01320 else if (_suffix(s, ".class")) 01321 ftype = "Java class file"; 01322 01323 /* XXX all files with extension ".la" are libtool for now. */ 01324 else if (_suffix(s, ".la")) 01325 ftype = "libtool library file"; 01326 01327 /* XXX all files with extension ".pc" are pkgconfig for now. */ 01328 else if (_suffix(s, ".pc")) 01329 ftype = "pkgconfig file"; 01330 01331 /* XXX all files with extension ".php" are PHP for now. */ 01332 else if (_suffix(s, ".php")) 01333 ftype = "PHP script text"; 01334 01335 /* XXX skip all files in /dev/ which are (or should be) %dev dummies. */ 01336 else if (slen >= fc->brlen+sizeof("/dev/") && !strncmp(s+fc->brlen, "/dev/", sizeof("/dev/")-1)) 01337 ftype = ""; 01338 else if (magicfile) { 01339 ftype = rpmmgFile(mg, s); 01340 assert(ftype != NULL); /* XXX never happens, rpmmgFile() returns "" */ 01341 freeftype = 1; 01342 } 01343 /*@switchbreak@*/ break; 01344 } 01345 01346 se = ftype; 01347 01348 if (_rpmfc_debug) /* XXX noisy */ 01349 rpmlog(RPMLOG_DEBUG, "%s: %s\n", s, se); 01350 01351 /* Save the path. */ 01352 xx = argvAdd(&fc->fn, s); 01353 01354 /* Save the file type string. */ 01355 xx = argvAdd(&fcav, se); 01356 01357 /* Add (filtered) entry to sorted class dictionary. */ 01358 fcolor = rpmfcColoring(se); 01359 01360 /* Quick&dirty hack for linker scripts replacing regular 01361 * symlinks. Better *really* needs to be done ASAP. 01362 */ 01363 #if defined(RPM_VENDOR_MANDRIVA) 01364 if (fcolor == (RPMFC_WHITE|RPMFC_INCLUDE|RPMFC_TEXT)) { 01365 char * fn; 01366 01367 if ((fn = strrchr(s, '.')) && !strcmp(fn, ".so")) { 01368 FILE * fp = fopen(s, "r"); 01369 char buf[BUFSIZ]; 01370 char * in; 01371 if (fp == NULL || ferror(fp)) { 01372 if (fp) (void) fclose(fp); 01373 } 01374 while ((in = fgets(buf, sizeof(buf) - 1, fp))) { 01375 in[sizeof(buf)-1] = '\0'; 01376 if (ferror(fp) || feof(fp)) 01377 break; 01378 if ((fn = strstr(in, "GROUP")) && 01379 (fn = strchr(fn, '(')) && (fn = strchr(in, '/'))) { 01380 fcolor |= RPMFC_SYMLINK; 01381 break; 01382 } 01383 } 01384 if (fp) 01385 fclose(fp); 01386 } 01387 } 01388 #endif 01389 xx = argiAdd(&fc->fcolor, (int)fc->ix, fcolor); 01390 01391 if (fcolor != RPMFC_WHITE && (fcolor & RPMFC_INCLUDE)) 01392 xx = rpmfcSaveArg(&fc->cdict, se); 01393 01394 /*@-modobserver -observertrans @*/ /* XXX mixed types in variable */ 01395 if (freeftype) 01396 ftype = _free(ftype); 01397 /*@=modobserver =observertrans @*/ 01398 } 01399 01400 /* Build per-file class index array. */ 01401 fc->fknown = 0; 01402 for (fc->ix = 0; fc->ix < fc->nfiles; fc->ix++) { 01403 se = fcav[fc->ix]; 01404 assert(se != NULL); 01405 01406 dav = argvSearch(fc->cdict, se, NULL); 01407 if (dav) { 01408 xx = argiAdd(&fc->fcdictx, (int)fc->ix, (dav - fc->cdict)); 01409 fc->fknown++; 01410 } else { 01411 xx = argiAdd(&fc->fcdictx, (int)fc->ix, 0); 01412 fc->fwhite++; 01413 } 01414 } 01415 01416 fcav = argvFree(fcav); 01417 01418 mg = rpmmgFree(mg); 01419 rpmlog(RPMLOG_DEBUG, 01420 D_("categorized %d files into %u classes (using %s).\n"), 01421 (unsigned)fc->nfiles, argvCount(fc->cdict), magicfile); 01422 magicfile = _free(magicfile); 01423 01424 return RPMRC_OK; 01425 } 01426 01429 typedef struct DepMsg_s * DepMsg_t; 01430 01433 struct DepMsg_s { 01434 /*@observer@*/ /*@null@*/ 01435 const char * msg; 01436 /*@observer@*/ 01437 const char * argv[4]; 01438 rpmTag ntag; 01439 rpmTag vtag; 01440 rpmTag ftag; 01441 int mask; 01442 int xor; 01443 }; 01444 01447 /*@-nullassign@*/ 01448 /*@unchecked@*/ 01449 static struct DepMsg_s depMsgs[] = { 01450 { "Provides", { "%{?__find_provides}", NULL, NULL, NULL }, 01451 RPMTAG_PROVIDENAME, RPMTAG_PROVIDEVERSION, RPMTAG_PROVIDEFLAGS, 01452 0, -1 }, 01453 { "Requires(interp)", { NULL, "interp", NULL, NULL }, 01454 RPMTAG_REQUIRENAME, RPMTAG_REQUIREVERSION, RPMTAG_REQUIREFLAGS, 01455 _notpre(RPMSENSE_INTERP), 0 }, 01456 { "Requires(rpmlib)", { NULL, "rpmlib", NULL, NULL }, 01457 -1, -1, RPMTAG_REQUIREFLAGS, 01458 _notpre(RPMSENSE_RPMLIB), 0 }, 01459 { "Requires(verify)", { NULL, "verify", NULL, NULL }, 01460 -1, -1, RPMTAG_REQUIREFLAGS, 01461 RPMSENSE_SCRIPT_VERIFY, 0 }, 01462 { "Requires(pre)", { NULL, "pre", NULL, NULL }, 01463 -1, -1, RPMTAG_REQUIREFLAGS, 01464 _notpre(RPMSENSE_SCRIPT_PRE), 0 }, 01465 { "Requires(post)", { NULL, "post", NULL, NULL }, 01466 -1, -1, RPMTAG_REQUIREFLAGS, 01467 _notpre(RPMSENSE_SCRIPT_POST), 0 }, 01468 { "Requires(preun)", { NULL, "preun", NULL, NULL }, 01469 -1, -1, RPMTAG_REQUIREFLAGS, 01470 _notpre(RPMSENSE_SCRIPT_PREUN), 0 }, 01471 { "Requires(postun)", { NULL, "postun", NULL, NULL }, 01472 -1, -1, RPMTAG_REQUIREFLAGS, 01473 _notpre(RPMSENSE_SCRIPT_POSTUN), 0 }, 01474 { "Requires", { "%{?__find_requires}", NULL, NULL, NULL }, 01475 -1, -1, RPMTAG_REQUIREFLAGS, /* XXX inherit name/version arrays */ 01476 RPMSENSE_FIND_REQUIRES|RPMSENSE_TRIGGERIN|RPMSENSE_TRIGGERUN|RPMSENSE_TRIGGERPOSTUN|RPMSENSE_TRIGGERPREIN, 0 }, 01477 { "Conflicts", { "%{?__find_conflicts}", NULL, NULL, NULL }, 01478 RPMTAG_CONFLICTNAME, RPMTAG_CONFLICTVERSION, RPMTAG_CONFLICTFLAGS, 01479 0, -1 }, 01480 { "Obsoletes", { "%{?__find_obsoletes}", NULL, NULL, NULL }, 01481 RPMTAG_OBSOLETENAME, RPMTAG_OBSOLETEVERSION, RPMTAG_OBSOLETEFLAGS, 01482 0, -1 }, 01483 { NULL, { NULL, NULL, NULL, NULL }, 0, 0, 0, 0, 0 } 01484 }; 01485 /*@=nullassign@*/ 01486 01487 /*@unchecked@*/ 01488 static DepMsg_t DepMsgs = depMsgs; 01489 01494 static void printDeps(Header h) 01495 /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/ 01496 /*@modifies h, rpmGlobalMacroContext, fileSystem, internalState @*/ 01497 { 01498 DepMsg_t dm; 01499 rpmds ds = NULL; 01500 int flags = 0x2; /* XXX no filtering, !scareMem */ 01501 const char * DNEVR; 01502 evrFlags Flags; 01503 int bingo = 0; 01504 01505 for (dm = DepMsgs; dm->msg != NULL; dm++) { 01506 if ((int)dm->ntag != -1) { 01507 (void)rpmdsFree(ds); 01508 ds = NULL; 01509 ds = rpmdsNew(h, dm->ntag, flags); 01510 } 01511 if (dm->ftag == 0) 01512 continue; 01513 01514 ds = rpmdsInit(ds); 01515 if (ds == NULL) 01516 continue; /* XXX can't happen */ 01517 01518 bingo = 0; 01519 while (rpmdsNext(ds) >= 0) { 01520 01521 Flags = rpmdsFlags(ds); 01522 01523 if (!((Flags & dm->mask) ^ dm->xor)) 01524 /*@innercontinue@*/ continue; 01525 if (bingo == 0) { 01526 rpmlog(RPMLOG_NOTICE, "%s:", (dm->msg ? dm->msg : "")); 01527 bingo = 1; 01528 } 01529 if ((DNEVR = rpmdsDNEVR(ds)) == NULL) 01530 /*@innercontinue@*/ continue; /* XXX can't happen */ 01531 rpmlog(RPMLOG_NOTICE, " %s", DNEVR+2); 01532 } 01533 if (bingo) 01534 rpmlog(RPMLOG_NOTICE, "\n"); 01535 } 01536 (void)rpmdsFree(ds); 01537 ds = NULL; 01538 } 01539 01542 static rpmRC rpmfcGenerateDependsHelper(const Spec spec, Package pkg, rpmfi fi) 01543 /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/ 01544 /*@modifies fi, rpmGlobalMacroContext, fileSystem, internalState @*/ 01545 { 01546 rpmiob iob_stdin; 01547 rpmiob iob_stdout; 01548 DepMsg_t dm; 01549 int failnonzero = 0; 01550 rpmRC rc = RPMRC_OK; 01551 01552 /* 01553 * Create file manifest buffer to deliver to dependency finder. 01554 */ 01555 iob_stdin = rpmiobNew(0); 01556 fi = rpmfiInit(fi, 0); 01557 if (fi != NULL) 01558 while (rpmfiNext(fi) >= 0) 01559 iob_stdin = rpmiobAppend(iob_stdin, rpmfiFN(fi), 1); 01560 01561 for (dm = DepMsgs; dm->msg != NULL; dm++) { 01562 rpmTag tag; 01563 rpmsenseFlags tagflags; 01564 char * s; 01565 int xx; 01566 01567 tag = (dm->ftag > 0) ? dm->ftag : dm->ntag; 01568 tagflags = 0; 01569 s = NULL; 01570 01571 switch(tag) { 01572 case RPMTAG_PROVIDEFLAGS: 01573 if (!pkg->autoProv) 01574 continue; 01575 failnonzero = 1; 01576 tagflags = RPMSENSE_FIND_PROVIDES; 01577 /*@switchbreak@*/ break; 01578 case RPMTAG_REQUIREFLAGS: 01579 if (!pkg->autoReq) 01580 continue; 01581 failnonzero = 0; 01582 tagflags = RPMSENSE_FIND_REQUIRES; 01583 /*@switchbreak@*/ break; 01584 default: 01585 continue; 01586 /*@notreached@*/ /*@switchbreak@*/ break; 01587 } 01588 01589 xx = rpmfcExec(dm->argv, iob_stdin, &iob_stdout, failnonzero); 01590 if (xx == -1) 01591 continue; 01592 01593 s = rpmExpand(dm->argv[0], NULL); 01594 rpmlog(RPMLOG_NOTICE, _("Finding %s: %s\n"), dm->msg, 01595 (s ? s : "")); 01596 s = _free(s); 01597 01598 if (iob_stdout == NULL) { 01599 rpmlog(RPMLOG_ERR, _("Failed to find %s:\n"), dm->msg); 01600 rc = RPMRC_FAIL; 01601 break; 01602 } 01603 01604 /* Parse dependencies into header */ 01605 if (spec->_parseRCPOT) 01606 rc = spec->_parseRCPOT(spec, pkg, rpmiobStr(iob_stdout), tag, 01607 0, tagflags); 01608 iob_stdout = rpmiobFree(iob_stdout); 01609 01610 if (rc) { 01611 rpmlog(RPMLOG_ERR, _("Failed to find %s:\n"), dm->msg); 01612 break; 01613 } 01614 } 01615 01616 iob_stdin = rpmiobFree(iob_stdin); 01617 01618 return rc; 01619 } 01620 01623 /*@-nullassign@*/ 01624 /*@unchecked@*/ 01625 static struct DepMsg_s scriptMsgs[] = { 01626 { "Requires(pre)", { "%{?__scriptlet_requires}", NULL, NULL, NULL }, 01627 RPMTAG_PREINPROG, RPMTAG_PREIN, RPMTAG_REQUIREFLAGS, 01628 RPMSENSE_SCRIPT_PRE, 0 }, 01629 { "Requires(post)", { "%{?__scriptlet_requires}", NULL, NULL, NULL }, 01630 RPMTAG_POSTINPROG, RPMTAG_POSTIN, RPMTAG_REQUIREFLAGS, 01631 RPMSENSE_SCRIPT_POST, 0 }, 01632 { "Requires(preun)", { "%{?__scriptlet_requires}", NULL, NULL, NULL }, 01633 RPMTAG_PREUNPROG, RPMTAG_PREUN, RPMTAG_REQUIREFLAGS, 01634 RPMSENSE_SCRIPT_PREUN, 0 }, 01635 { "Requires(postun)", { "%{?__scriptlet_requires}", NULL, NULL, NULL }, 01636 RPMTAG_POSTUNPROG, RPMTAG_POSTUN, RPMTAG_REQUIREFLAGS, 01637 RPMSENSE_SCRIPT_POSTUN, 0 }, 01638 { NULL, { NULL, NULL, NULL, NULL }, 0, 0, 0, 0, 0 } 01639 }; 01640 /*@=nullassign@*/ 01641 01642 /*@unchecked@*/ 01643 static DepMsg_t ScriptMsgs = scriptMsgs; 01644 01647 static int rpmfcGenerateScriptletDeps(const Spec spec, Package pkg) 01648 /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/ 01649 /*@modifies rpmGlobalMacroContext, fileSystem, internalState @*/ 01650 { 01651 HE_t he = memset(alloca(sizeof(*he)), 0, sizeof(*he)); 01652 rpmiob iob_stdin = rpmiobNew(0); 01653 rpmiob iob_stdout = NULL; 01654 DepMsg_t dm; 01655 int failnonzero = 0; 01656 int rc = 0; 01657 int xx; 01658 01659 for (dm = ScriptMsgs; dm->msg != NULL; dm++) { 01660 int tag, tagflags; 01661 char * s; 01662 01663 tag = dm->ftag; 01664 tagflags = RPMSENSE_FIND_REQUIRES | dm->mask; 01665 01666 /* Retrieve scriptlet interpreter. */ 01667 he->tag = dm->ntag; 01668 xx = headerGet(pkg->header, he, 0); 01669 if (!xx || he->p.str == NULL) 01670 continue; 01671 xx = strcmp(he->p.str, "/bin/sh") && strcmp(he->p.str, "/bin/bash"); 01672 he->p.ptr = _free(he->p.ptr); 01673 if (xx) 01674 continue; 01675 01676 /* Retrieve scriptlet body. */ 01677 he->tag = dm->vtag; 01678 xx = headerGet(pkg->header, he, 0); 01679 if (!xx || he->p.str == NULL) 01680 continue; 01681 iob_stdin = rpmiobEmpty(iob_stdin); 01682 iob_stdin = rpmiobAppend(iob_stdin, he->p.str, 1); 01683 iob_stdin = rpmiobRTrim(iob_stdin); 01684 he->p.ptr = _free(he->p.ptr); 01685 01686 xx = rpmfcExec(dm->argv, iob_stdin, &iob_stdout, failnonzero); 01687 if (xx == -1) 01688 continue; 01689 01690 /* Parse dependencies into header */ 01691 s = rpmiobStr(iob_stdout); 01692 if (s != NULL && *s != '\0') { 01693 char * se = s; 01694 /* XXX Convert "executable(/path/to/file)" to "/path/to/file". */ 01695 while ((se = strstr(se, "executable(/")) != NULL) { 01696 /*@-modobserver@*/ /* FIX: rpmiobStr should not be observer */ 01697 se = stpcpy(se, " "); 01698 *se = '/'; /* XXX stpcpy truncates the '/' */ 01699 /*@=modobserver@*/ 01700 se = strchr(se, ')'); 01701 if (se == NULL) 01702 /*@innerbreak@*/ break; 01703 *se++ = ' '; 01704 } 01705 if (spec->_parseRCPOT) 01706 rc = spec->_parseRCPOT(spec, pkg, s, tag, 0, tagflags); 01707 } 01708 iob_stdout = rpmiobFree(iob_stdout); 01709 01710 } 01711 01712 iob_stdin = rpmiobFree(iob_stdin); 01713 01714 return rc; 01715 } 01716 01717 rpmRC rpmfcGenerateDepends(void * specp, void * pkgp) 01718 { 01719 HE_t he = memset(alloca(sizeof(*he)), 0, sizeof(*he)); 01720 const Spec spec = specp; 01721 Package pkg = pkgp; 01722 rpmfi fi = pkg->fi; 01723 rpmfc fc = NULL; 01724 rpmds ds; 01725 int flags = 0x2; /* XXX no filtering, !scareMem */ 01726 ARGV_t av; 01727 rpmuint16_t * fmode; 01728 int ac = rpmfiFC(fi); 01729 char buf[BUFSIZ]; 01730 const char * N; 01731 const char * EVR; 01732 int genConfigDeps, internaldeps; 01733 rpmRC rc = RPMRC_OK; 01734 int i; 01735 int xx; 01736 01737 /* Skip packages with no files. */ 01738 if (ac <= 0) 01739 return RPMRC_OK; 01740 01741 /* Skip packages that have dependency generation disabled. */ 01742 if (! (pkg->autoReq || pkg->autoProv)) 01743 return RPMRC_OK; 01744 01745 /* If new-fangled dependency generation is disabled ... */ 01746 internaldeps = rpmExpandNumeric("%{?_use_internal_dependency_generator}"); 01747 if (internaldeps == 0) { 01748 /* ... then generate dependencies using %{__find_requires} et al. */ 01749 rc = rpmfcGenerateDependsHelper(spec, pkg, fi); 01750 printDeps(pkg->header); 01751 return rc; 01752 } 01753 01754 /* Generate scriptlet Dependencies. */ 01755 if (internaldeps > 1) 01756 xx = rpmfcGenerateScriptletDeps(spec, pkg); 01757 01758 /* Extract absolute file paths in argv format. */ 01759 /* XXX TODO: should use argvFoo ... */ 01760 av = xcalloc(ac+1, sizeof(*av)); 01761 fmode = xcalloc(ac+1, sizeof(*fmode)); 01762 01763 genConfigDeps = 0; 01764 fi = rpmfiInit(fi, 0); 01765 if (fi != NULL) 01766 while ((i = rpmfiNext(fi)) >= 0) { 01767 rpmfileAttrs fileAttrs; 01768 01769 /* Does package have any %config files? */ 01770 fileAttrs = rpmfiFFlags(fi); 01771 genConfigDeps |= (fileAttrs & RPMFILE_CONFIG); 01772 01773 av[i] = xstrdup(rpmfiFN(fi)); 01774 fmode[i] = rpmfiFMode(fi); 01775 } 01776 av[ac] = NULL; 01777 01778 fc = rpmfcNew(); 01779 fc->skipProv = !pkg->autoProv; 01780 fc->skipReq = !pkg->autoReq; 01781 fc->tracked = 0; 01782 01783 { const char * buildRootURL; 01784 const char * buildRoot; 01785 buildRootURL = rpmGenPath(spec->rootURL, "%{?buildroot}", NULL); 01786 (void) urlPath(buildRootURL, &buildRoot); 01787 if (buildRoot && !strcmp(buildRoot, "/")) buildRoot = NULL; 01788 fc->brlen = (buildRoot ? strlen(buildRoot) : 0); 01789 buildRootURL = _free(buildRootURL); 01790 } 01791 01792 /* Copy (and delete) manually generated dependencies to dictionary. */ 01793 if (!fc->skipProv) { 01794 ds = rpmdsNew(pkg->header, RPMTAG_PROVIDENAME, flags); 01795 xx = rpmdsMerge(&fc->provides, ds); 01796 (void)rpmdsFree(ds); 01797 ds = NULL; 01798 he->tag = RPMTAG_PROVIDENAME; 01799 xx = headerDel(pkg->header, he, 0); 01800 he->tag = RPMTAG_PROVIDEVERSION; 01801 xx = headerDel(pkg->header, he, 0); 01802 he->tag = RPMTAG_PROVIDEFLAGS; 01803 xx = headerDel(pkg->header, he, 0); 01804 01805 /* Add config dependency, Provides: config(N) = EVR */ 01806 if (genConfigDeps) { 01807 N = rpmdsN(pkg->ds); 01808 assert(N != NULL); 01809 EVR = rpmdsEVR(pkg->ds); 01810 assert(EVR != NULL); 01811 sprintf(buf, "config(%s)", N); 01812 ds = rpmdsSingle(RPMTAG_PROVIDENAME, buf, EVR, 01813 (RPMSENSE_EQUAL|RPMSENSE_CONFIG)); 01814 xx = rpmdsMerge(&fc->provides, ds); 01815 (void)rpmdsFree(ds); 01816 ds = NULL; 01817 } 01818 } 01819 01820 if (!fc->skipReq) { 01821 ds = rpmdsNew(pkg->header, RPMTAG_REQUIRENAME, flags); 01822 xx = rpmdsMerge(&fc->requires, ds); 01823 (void)rpmdsFree(ds); 01824 ds = NULL; 01825 he->tag = RPMTAG_REQUIRENAME; 01826 xx = headerDel(pkg->header, he, 0); 01827 he->tag = RPMTAG_REQUIREVERSION; 01828 xx = headerDel(pkg->header, he, 0); 01829 he->tag = RPMTAG_REQUIREFLAGS; 01830 xx = headerDel(pkg->header, he, 0); 01831 01832 /* Add config dependency, Requires: config(N) = EVR */ 01833 if (genConfigDeps) { 01834 N = rpmdsN(pkg->ds); 01835 assert(N != NULL); 01836 EVR = rpmdsEVR(pkg->ds); 01837 assert(EVR != NULL); 01838 sprintf(buf, "config(%s)", N); 01839 ds = rpmdsSingle(RPMTAG_REQUIRENAME, buf, EVR, 01840 (RPMSENSE_EQUAL|RPMSENSE_CONFIG)); 01841 xx = rpmdsMerge(&fc->requires, ds); 01842 (void)rpmdsFree(ds); 01843 ds = NULL; 01844 } 01845 } 01846 01847 /* Build file class dictionary. */ 01848 xx = rpmfcClassify(fc, av, fmode); 01849 01850 /* Build file/package dependency dictionary. */ 01851 xx = rpmfcApply(fc); 01852 01853 /* Add per-file colors(#files) */ 01854 he->tag = RPMTAG_FILECOLORS; 01855 he->t = RPM_UINT32_TYPE; 01856 he->p.ui32p = argiData(fc->fcolor); 01857 he->c = argiCount(fc->fcolor); 01858 assert(ac == (int)he->c); 01859 if (he->p.ptr != NULL && he->c > 0) { 01860 rpmuint32_t * fcolors = he->p.ui32p; 01861 01862 /* XXX Make sure only primary (i.e. Elf32/Elf64) colors are added. */ 01863 for (i = 0; i < (int)he->c; i++) 01864 fcolors[i] &= 0x0f; 01865 01866 xx = headerPut(pkg->header, he, 0); 01867 } 01868 01869 /* Add classes(#classes) */ 01870 he->tag = RPMTAG_CLASSDICT; 01871 he->t = RPM_STRING_ARRAY_TYPE; 01872 he->p.argv = argvData(fc->cdict); 01873 he->c = argvCount(fc->cdict); 01874 if (he->p.ptr != NULL && he->c > 0) { 01875 xx = headerPut(pkg->header, he, 0); 01876 } 01877 01878 /* Add per-file classes(#files) */ 01879 he->tag = RPMTAG_FILECLASS; 01880 he->t = RPM_UINT32_TYPE; 01881 he->p.ui32p = argiData(fc->fcdictx); 01882 he->c = argiCount(fc->fcdictx); 01883 assert(ac == (int)he->c); 01884 if (he->p.ptr != NULL && he->c > 0) { 01885 xx = headerPut(pkg->header, he, 0); 01886 } 01887 01888 /* Add Provides: */ 01889 if (fc->provides != NULL && (he->c = rpmdsCount(fc->provides)) > 0 01890 && !fc->skipProv) 01891 { 01892 he->tag = RPMTAG_PROVIDENAME; 01893 he->t = RPM_STRING_ARRAY_TYPE; 01894 he->p.argv = fc->provides->N; 01895 xx = headerPut(pkg->header, he, 0); 01896 01897 /* XXX rpm prior to 3.0.2 did not always supply EVR and Flags. */ 01898 /*@-nullpass@*/ 01899 he->tag = RPMTAG_PROVIDEVERSION; 01900 he->t = RPM_STRING_ARRAY_TYPE; 01901 he->p.argv = fc->provides->EVR; 01902 assert(he->p.ptr != NULL); 01903 xx = headerPut(pkg->header, he, 0); 01904 01905 he->tag = RPMTAG_PROVIDEFLAGS; 01906 he->t = RPM_UINT32_TYPE; 01907 he->p.ui32p = (rpmuint32_t *) fc->provides->Flags; 01908 assert(he->p.ptr != NULL); 01909 xx = headerPut(pkg->header, he, 0); 01910 /*@=nullpass@*/ 01911 } 01912 01913 /* Add Requires: */ 01914 if (fc->requires != NULL && (he->c = rpmdsCount(fc->requires)) > 0 01915 && !fc->skipReq) 01916 { 01917 he->tag = RPMTAG_REQUIRENAME; 01918 he->t = RPM_STRING_ARRAY_TYPE; 01919 he->p.argv = fc->requires->N; 01920 assert(he->p.ptr != NULL); 01921 xx = headerPut(pkg->header, he, 0); 01922 01923 /* XXX rpm prior to 3.0.2 did not always supply EVR and Flags. */ 01924 /*@-nullpass@*/ 01925 he->tag = RPMTAG_REQUIREVERSION; 01926 he->t = RPM_STRING_ARRAY_TYPE; 01927 he->p.argv = fc->requires->EVR; 01928 assert(he->p.ptr != NULL); 01929 xx = headerPut(pkg->header, he, 0); 01930 01931 he->tag = RPMTAG_REQUIREFLAGS; 01932 he->t = RPM_UINT32_TYPE; 01933 he->p.ui32p = (rpmuint32_t *) fc->requires->Flags; 01934 assert(he->p.ptr != NULL); 01935 xx = headerPut(pkg->header, he, 0); 01936 /*@=nullpass@*/ 01937 } 01938 01939 /* Add dependency dictionary(#dependencies) */ 01940 he->tag = RPMTAG_DEPENDSDICT; 01941 he->t = RPM_UINT32_TYPE; 01942 he->p.ui32p = argiData(fc->ddictx); 01943 he->c = argiCount(fc->ddictx); 01944 if (he->p.ptr != NULL) { 01945 xx = headerPut(pkg->header, he, 0); 01946 } 01947 01948 /* Add per-file dependency (start,number) pairs (#files) */ 01949 he->tag = RPMTAG_FILEDEPENDSX; 01950 he->t = RPM_UINT32_TYPE; 01951 he->p.ui32p = argiData(fc->fddictx); 01952 he->c = argiCount(fc->fddictx); 01953 assert(ac == (int)he->c); 01954 if (he->p.ptr != NULL) { 01955 xx = headerPut(pkg->header, he, 0); 01956 } 01957 01958 he->tag = RPMTAG_FILEDEPENDSN; 01959 he->t = RPM_UINT32_TYPE; 01960 he->p.ui32p = argiData(fc->fddictn); 01961 he->c = argiCount(fc->fddictn); 01962 assert(ac == (int)he->c); 01963 if (he->p.ptr != NULL) { 01964 xx = headerPut(pkg->header, he, 0); 01965 } 01966 01967 printDeps(pkg->header); 01968 01969 if (fc != NULL && _rpmfc_debug) { 01970 char msg[BUFSIZ]; 01971 sprintf(msg, "final: files %u cdict[%d] %u%% ddictx[%d]", (unsigned int)fc->nfiles, argvCount(fc->cdict), (unsigned int)((100 * fc->fknown)/fc->nfiles), argiCount(fc->ddictx)); 01972 rpmfcPrint(msg, fc, NULL); 01973 } 01974 01975 /* Clean up. */ 01976 fmode = _free(fmode); 01977 fc = rpmfcFree(fc); 01978 av = argvFree(av); 01979 01980 return rc; 01981 } 01982 01983 /*@-mustmod@*/ 01984 static void rpmfcFini(void * _fc) 01985 /*@modifies _fc @*/ 01986 { 01987 rpmfc fc = _fc; 01988 01989 fc->fn = argvFree(fc->fn); 01990 fc->fcolor = argiFree(fc->fcolor); 01991 fc->fcdictx = argiFree(fc->fcdictx); 01992 fc->fddictx = argiFree(fc->fddictx); 01993 fc->fddictn = argiFree(fc->fddictn); 01994 fc->cdict = argvFree(fc->cdict); 01995 fc->ddict = argvFree(fc->ddict); 01996 fc->ddictx = argiFree(fc->ddictx); 01997 01998 (void)rpmdsFree(fc->provides); 01999 fc->provides = NULL; 02000 (void)rpmdsFree(fc->requires); 02001 fc->requires = NULL; 02002 02003 fc->iob_java = rpmiobFree(fc->iob_java); 02004 fc->iob_perl = rpmiobFree(fc->iob_perl); 02005 fc->iob_python = rpmiobFree(fc->iob_python); 02006 fc->iob_php = rpmiobFree(fc->iob_php); 02007 } 02008 /*@=mustmod@*/ 02009 02010 /*@unchecked@*/ /*@only@*/ /*@null@*/ 02011 rpmioPool _rpmfcPool = NULL; 02012 02013 static rpmfc rpmfcGetPool(/*@null@*/ rpmioPool pool) 02014 /*@globals _rpmfcPool, fileSystem, internalState @*/ 02015 /*@modifies pool, _rpmfcPool, fileSystem, internalState @*/ 02016 { 02017 rpmfc fc; 02018 02019 if (_rpmfcPool == NULL) { 02020 _rpmfcPool = rpmioNewPool("fc", sizeof(*fc), -1, _rpmfc_debug, 02021 NULL, NULL, rpmfcFini); 02022 pool = _rpmfcPool; 02023 } 02024 fc = (rpmfc) rpmioGetPool(pool, sizeof(*fc)); 02025 memset(((char *)fc)+sizeof(fc->_item), 0, sizeof(*fc)-sizeof(fc->_item)); 02026 return fc; 02027 } 02028 02029 rpmfc rpmfcNew(void) 02030 { 02031 rpmfc fc = rpmfcGetPool(_rpmfcPool); 02032 fc->fn = xcalloc(1, sizeof(*fc->fn)); 02033 return rpmfcLink(fc); 02034 } 02035