rpm 5.2.1
|
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) { 00344 xx = poptParseArgvString(s, &ac, (const char ***)&av); 00345 s = _free(s); 00346 } 00347 if (ac == 0 || av == NULL || *av == NULL) 00348 goto exit; 00349 00350 for (i = 0; i < ac; i++) { 00351 xx = mireAppend(RPMMIRE_REGEX, 0, av[i], NULL, &mire, &nmire); 00352 /* XXX add REG_NOSUB? better error msg? */ 00353 if (xx) { 00354 rpmlog(RPMLOG_NOTICE, 00355 _("Compilation of pattern '%s'" 00356 " (expanded from '%s') failed. Skipping ...\n"), 00357 av[i], str); 00358 nmire--; /* XXX does this actually skip?!? */ 00359 } 00360 } 00361 if (nmire == 0) 00362 mire = mireFree(mire); 00363 00364 exit: 00365 av = _free(av); 00366 if (nmirep) 00367 *nmirep = nmire; 00368 return mire; 00369 } 00370 00371 static int rpmfcMatchRegexps(void * mires, int nmire, 00372 const char * str, char deptype) 00373 /*@modifies mires @*/ 00374 { 00375 miRE mire = mires; 00376 int xx; 00377 int i; 00378 00379 for (i = 0; i < nmire; i++) { 00380 rpmlog(RPMLOG_DEBUG, D_("Checking %c: '%s'\n"), deptype, str); 00381 if ((xx = mireRegexec(mire + i, str, 0)) < 0) 00382 continue; 00383 rpmlog(RPMLOG_NOTICE, _("Skipping %c: '%s'\n"), deptype, str); 00384 return 1; 00385 } 00386 return 0; 00387 } 00388 00389 /*@null@*/ 00390 static void * rpmfcFreeRegexps(/*@only@*/ void * mires, int nmire) 00391 /*@modifies mires @*/ 00392 { 00393 miRE mire = mires; 00394 /*@-refcounttrans@*/ 00395 return mireFreeAll(mire, nmire); 00396 /*@=refcounttrans@*/ 00397 } 00398 00406 static int rpmfcHelper(rpmfc fc, unsigned char deptype, const char * nsdep) 00407 /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/ 00408 /*@modifies fc, rpmGlobalMacroContext, fileSystem, internalState @*/ 00409 { 00410 miRE mire = NULL; 00411 int nmire = 0; 00412 const char * fn = fc->fn[fc->ix]; 00413 char buf[BUFSIZ]; 00414 rpmiob iob_stdout = NULL; 00415 rpmiob iob_stdin; 00416 const char *av[2]; 00417 rpmds * depsp, ds; 00418 const char * N; 00419 const char * EVR; 00420 rpmTag tagN; 00421 evrFlags Flags; 00422 evrFlags dsContext; 00423 ARGV_t pav; 00424 const char * s; 00425 int pac; 00426 int xx; 00427 int i; 00428 00429 switch (deptype) { 00430 default: 00431 return -1; 00432 /*@notreached@*/ break; 00433 case 'P': 00434 if (fc->skipProv) 00435 return 0; 00436 xx = snprintf(buf, sizeof(buf), "%%{?__%s_provides}", nsdep); 00437 depsp = &fc->provides; 00438 dsContext = RPMSENSE_FIND_PROVIDES; 00439 tagN = RPMTAG_PROVIDENAME; 00440 mire = fc->Pmires; 00441 nmire = fc->Pnmire; 00442 break; 00443 case 'R': 00444 if (fc->skipReq) 00445 return 0; 00446 xx = snprintf(buf, sizeof(buf), "%%{?__%s_requires}", nsdep); 00447 depsp = &fc->requires; 00448 dsContext = RPMSENSE_FIND_REQUIRES; 00449 tagN = RPMTAG_REQUIRENAME; 00450 mire = fc->Rmires; 00451 nmire = fc->Rnmire; 00452 break; 00453 } 00454 buf[sizeof(buf)-1] = '\0'; 00455 av[0] = buf; 00456 av[1] = NULL; 00457 00458 iob_stdin = rpmiobNew(0); 00459 iob_stdin = rpmiobAppend(iob_stdin, fn, 1); 00460 iob_stdout = NULL; 00461 xx = rpmfcExec(av, iob_stdin, &iob_stdout, 0); 00462 iob_stdin = rpmiobFree(iob_stdin); 00463 00464 if (xx == 0 && iob_stdout != NULL) { 00465 pav = NULL; 00466 xx = argvSplit(&pav, rpmiobStr(iob_stdout), " \t\n\r"); 00467 pac = argvCount(pav); 00468 if (pav) 00469 for (i = 0; i < pac; i++) { 00470 N = pav[i]; 00471 EVR = ""; 00472 Flags = dsContext; 00473 if (pav[i+1] && strchr("=<>", *pav[i+1])) { 00474 i++; 00475 for (s = pav[i]; *s; s++) { 00476 switch(*s) { 00477 default: 00478 assert(*s != '\0'); 00479 /*@switchbreak@*/ break; 00480 case '=': 00481 Flags |= RPMSENSE_EQUAL; 00482 /*@switchbreak@*/ break; 00483 case '<': 00484 Flags |= RPMSENSE_LESS; 00485 /*@switchbreak@*/ break; 00486 case '>': 00487 Flags |= RPMSENSE_GREATER; 00488 /*@switchbreak@*/ break; 00489 } 00490 } 00491 i++; 00492 EVR = pav[i]; 00493 assert(EVR != NULL); 00494 } 00495 00496 if (_filter_values && rpmfcMatchRegexps(mire, nmire, N, deptype)) 00497 continue; 00498 00499 /* Add tracking dependency for versioned Provides: */ 00500 if (!fc->tracked && deptype == 'P' && *EVR != '\0') { 00501 ds = rpmdsSingle(RPMTAG_REQUIRENAME, 00502 "rpmlib(VersionedDependencies)", "3.0.3-1", 00503 RPMSENSE_RPMLIB|(RPMSENSE_LESS|RPMSENSE_EQUAL)); 00504 xx = rpmdsMerge(&fc->requires, ds); 00505 (void)rpmdsFree(ds); 00506 ds = NULL; 00507 fc->tracked = 1; 00508 } 00509 00510 ds = rpmdsSingle(tagN, N, EVR, Flags); 00511 00512 /* Add to package dependencies. */ 00513 xx = rpmdsMerge(depsp, ds); 00514 00515 /* Add to file dependencies. */ 00516 xx = rpmfcSaveArg(&fc->ddict, rpmfcFileDep(buf, fc->ix, ds)); 00517 00518 (void)rpmdsFree(ds); 00519 ds = NULL; 00520 } 00521 00522 pav = argvFree(pav); 00523 } 00524 iob_stdout = rpmiobFree(iob_stdout); 00525 00526 return 0; 00527 } 00528 00531 /*@-nullassign@*/ 00532 /*@unchecked@*/ /*@observer@*/ 00533 static struct rpmfcTokens_s rpmfcTokens[] = { 00534 { "directory", RPMFC_DIRECTORY|RPMFC_INCLUDE }, 00535 00536 { " shared object", RPMFC_LIBRARY }, 00537 { " executable", RPMFC_EXECUTABLE }, 00538 { " statically linked", RPMFC_STATIC }, 00539 { " not stripped", RPMFC_NOTSTRIPPED }, 00540 { " archive", RPMFC_ARCHIVE }, 00541 00542 { "MIPS, N32 MIPS32", RPMFC_ELFMIPSN32|RPMFC_INCLUDE }, 00543 { "ELF 32-bit", RPMFC_ELF32|RPMFC_INCLUDE }, 00544 { "ELF 64-bit", RPMFC_ELF64|RPMFC_INCLUDE }, 00545 00546 { " script", RPMFC_SCRIPT }, 00547 { " text", RPMFC_TEXT }, 00548 { " document", RPMFC_DOCUMENT }, 00549 00550 { " compressed", RPMFC_COMPRESSED }, 00551 00552 { "troff or preprocessor input", RPMFC_MANPAGE|RPMFC_INCLUDE }, 00553 { "GNU Info", RPMFC_MANPAGE|RPMFC_INCLUDE }, 00554 00555 { "perl script text", RPMFC_PERL|RPMFC_INCLUDE }, 00556 { "Perl5 module source text", RPMFC_PERL|RPMFC_MODULE|RPMFC_INCLUDE }, 00557 00558 { "PHP script text", RPMFC_PHP|RPMFC_INCLUDE }, 00559 00560 /* XXX "a /usr/bin/python -t script text executable" */ 00561 /* XXX "python 2.3 byte-compiled" */ 00562 { " /usr/bin/python", RPMFC_PYTHON|RPMFC_INCLUDE }, 00563 { "python ", RPMFC_PYTHON|RPMFC_INCLUDE }, 00564 00565 { "libtool library ", RPMFC_LIBTOOL|RPMFC_INCLUDE }, 00566 { "pkgconfig ", RPMFC_PKGCONFIG|RPMFC_INCLUDE }, 00567 00568 { "Bourne ", RPMFC_BOURNE|RPMFC_INCLUDE }, 00569 { "Bourne-Again ", RPMFC_BOURNE|RPMFC_INCLUDE }, 00570 00571 { "Java ", RPMFC_JAVA|RPMFC_INCLUDE }, 00572 00573 { "Mono/.Net assembly", RPMFC_MONO|RPMFC_INCLUDE }, 00574 00575 { "current ar archive", RPMFC_STATIC|RPMFC_LIBRARY|RPMFC_ARCHIVE|RPMFC_INCLUDE }, 00576 00577 { "Zip archive data", RPMFC_COMPRESSED|RPMFC_ARCHIVE|RPMFC_INCLUDE }, 00578 { "tar archive", RPMFC_ARCHIVE|RPMFC_INCLUDE }, 00579 { "cpio archive", RPMFC_ARCHIVE|RPMFC_INCLUDE }, 00580 { "RPM v3", RPMFC_ARCHIVE|RPMFC_INCLUDE }, 00581 { "RPM v4", RPMFC_ARCHIVE|RPMFC_INCLUDE }, 00582 00583 { " image", RPMFC_IMAGE|RPMFC_INCLUDE }, 00584 { " font", RPMFC_FONT|RPMFC_INCLUDE }, 00585 { " Font", RPMFC_FONT|RPMFC_INCLUDE }, 00586 00587 { " commands", RPMFC_SCRIPT|RPMFC_INCLUDE }, 00588 { " script", RPMFC_SCRIPT|RPMFC_INCLUDE }, 00589 00590 { "empty", RPMFC_WHITE|RPMFC_INCLUDE }, 00591 00592 { "HTML", RPMFC_WHITE|RPMFC_INCLUDE }, 00593 { "SGML", RPMFC_WHITE|RPMFC_INCLUDE }, 00594 { "XML", RPMFC_WHITE|RPMFC_INCLUDE }, 00595 00596 { " program text", RPMFC_WHITE|RPMFC_INCLUDE }, 00597 { " source", RPMFC_WHITE|RPMFC_INCLUDE }, 00598 { "GLS_BINARY_LSB_FIRST", RPMFC_WHITE|RPMFC_INCLUDE }, 00599 { " DB ", RPMFC_WHITE|RPMFC_INCLUDE }, 00600 00601 { "ASCII English text", RPMFC_WHITE|RPMFC_INCLUDE }, 00602 { "ASCII text", RPMFC_WHITE|RPMFC_INCLUDE }, 00603 { "ISO-8859 text", RPMFC_WHITE|RPMFC_INCLUDE }, 00604 00605 { "symbolic link to", RPMFC_SYMLINK }, 00606 { "socket", RPMFC_DEVICE }, 00607 { "special", RPMFC_DEVICE }, 00608 00609 { "ASCII", RPMFC_WHITE }, 00610 { "ISO-8859", RPMFC_WHITE }, 00611 00612 { "data", RPMFC_WHITE }, 00613 00614 { "application", RPMFC_WHITE }, 00615 { "boot", RPMFC_WHITE }, 00616 { "catalog", RPMFC_WHITE }, 00617 { "code", RPMFC_WHITE }, 00618 { "file", RPMFC_WHITE }, 00619 { "format", RPMFC_WHITE }, 00620 { "message", RPMFC_WHITE }, 00621 { "program", RPMFC_WHITE }, 00622 00623 { "broken symbolic link to ", RPMFC_WHITE|RPMFC_ERROR }, 00624 { "can't read", RPMFC_WHITE|RPMFC_ERROR }, 00625 { "can't stat", RPMFC_WHITE|RPMFC_ERROR }, 00626 { "executable, can't read", RPMFC_WHITE|RPMFC_ERROR }, 00627 { "core file", RPMFC_WHITE|RPMFC_ERROR }, 00628 00629 { NULL, RPMFC_BLACK } 00630 }; 00631 /*@=nullassign@*/ 00632 00633 int rpmfcColoring(const char * fmstr) 00634 { 00635 rpmfcToken fct; 00636 int fcolor = RPMFC_BLACK; 00637 00638 for (fct = rpmfcTokens; fct->token != NULL; fct++) { 00639 if (strstr(fmstr, fct->token) == NULL) 00640 continue; 00641 fcolor |= fct->colors; 00642 if (fcolor & RPMFC_INCLUDE) 00643 return fcolor; 00644 } 00645 return fcolor; 00646 } 00647 00648 void rpmfcPrint(const char * msg, rpmfc fc, FILE * fp) 00649 { 00650 int fcolor; 00651 int ndx; 00652 int cx; 00653 int dx; 00654 size_t fx; 00655 00656 unsigned nprovides; 00657 unsigned nrequires; 00658 00659 if (fp == NULL) fp = stderr; 00660 00661 if (msg) 00662 fprintf(fp, "===================================== %s\n", msg); 00663 00664 nprovides = rpmdsCount(fc->provides); 00665 nrequires = rpmdsCount(fc->requires); 00666 00667 if (fc) 00668 for (fx = 0; fx < fc->nfiles; fx++) { 00669 assert(fx < fc->fcdictx->nvals); 00670 cx = fc->fcdictx->vals[fx]; 00671 assert(fx < fc->fcolor->nvals); 00672 fcolor = fc->fcolor->vals[fx]; 00673 00674 fprintf(fp, "%3d %s", (int)fx, fc->fn[fx]); 00675 if (fcolor != RPMFC_BLACK) 00676 fprintf(fp, "\t0x%x", fc->fcolor->vals[fx]); 00677 else 00678 fprintf(fp, "\t%s", fc->cdict[cx]); 00679 fprintf(fp, "\n"); 00680 00681 if (fc->fddictx == NULL || fc->fddictn == NULL) 00682 continue; 00683 00684 assert(fx < fc->fddictx->nvals); 00685 dx = fc->fddictx->vals[fx]; 00686 assert(fx < fc->fddictn->nvals); 00687 ndx = fc->fddictn->vals[fx]; 00688 00689 while (ndx-- > 0) { 00690 const char * depval; 00691 unsigned char deptype; 00692 unsigned ix; 00693 00694 ix = fc->ddictx->vals[dx++]; 00695 deptype = ((ix >> 24) & 0xff); 00696 ix &= 0x00ffffff; 00697 depval = NULL; 00698 switch (deptype) { 00699 default: 00700 assert(depval != NULL); 00701 /*@switchbreak@*/ break; 00702 case 'P': 00703 if (nprovides > 0) { 00704 assert(ix < nprovides); 00705 (void) rpmdsSetIx(fc->provides, ix-1); 00706 if (rpmdsNext(fc->provides) >= 0) 00707 depval = rpmdsDNEVR(fc->provides); 00708 } 00709 /*@switchbreak@*/ break; 00710 case 'R': 00711 if (nrequires > 0) { 00712 assert(ix < nrequires); 00713 (void) rpmdsSetIx(fc->requires, ix-1); 00714 if (rpmdsNext(fc->requires) >= 0) 00715 depval = rpmdsDNEVR(fc->requires); 00716 } 00717 /*@switchbreak@*/ break; 00718 } 00719 if (depval) 00720 fprintf(fp, "\t%s\n", depval); 00721 } 00722 } 00723 } 00724 00730 static int rpmfcSCRIPT(rpmfc fc) 00731 /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/ 00732 /*@modifies fc, rpmGlobalMacroContext, fileSystem, internalState @*/ 00733 { 00734 const char * fn = fc->fn[fc->ix]; 00735 const char * bn; 00736 rpmds ds; 00737 char buf[BUFSIZ]; 00738 FILE * fp; 00739 char * s, * se; 00740 int i; 00741 int is_executable; 00742 int xx; 00743 00744 /* Extract dependencies only from files with executable bit set. */ 00745 { struct stat sb, * st = &sb; 00746 if (stat(fn, st) != 0) 00747 return -1; 00748 is_executable = (int)(st->st_mode & (S_IXUSR|S_IXGRP|S_IXOTH)); 00749 } 00750 00751 fp = fopen(fn, "r"); 00752 if (fp == NULL || ferror(fp)) { 00753 if (fp) (void) fclose(fp); 00754 return -1; 00755 } 00756 00757 /* Look for #! interpreter in first 10 lines. */ 00758 for (i = 0; i < 10; i++) { 00759 00760 s = fgets(buf, sizeof(buf) - 1, fp); 00761 if (s == NULL || ferror(fp) || feof(fp)) 00762 break; 00763 s[sizeof(buf)-1] = '\0'; 00764 if (!(s[0] == '#' && s[1] == '!')) 00765 continue; 00766 s += 2; 00767 00768 while (*s && strchr(" \t\n\r", *s) != NULL) 00769 s++; 00770 if (*s == '\0') 00771 continue; 00772 if (*s != '/') 00773 continue; 00774 00775 for (se = s+1; *se; se++) { 00776 if (strchr(" \t\n\r", *se) != NULL) 00777 /*@innerbreak@*/ break; 00778 } 00779 *se = '\0'; 00780 se++; 00781 00782 if (!_filter_values 00783 || (!fc->skipReq 00784 && !rpmfcMatchRegexps(fc->Rmires, fc->Rnmire, s, 'R'))) 00785 if (is_executable) { 00786 /* Add to package requires. */ 00787 ds = rpmdsSingle(RPMTAG_REQUIRENAME, s, "", RPMSENSE_FIND_REQUIRES); 00788 xx = rpmdsMerge(&fc->requires, ds); 00789 00790 /* Add to file requires. */ 00791 xx = rpmfcSaveArg(&fc->ddict, rpmfcFileDep(se, fc->ix, ds)); 00792 00793 (void)rpmdsFree(ds); 00794 ds = NULL; 00795 } 00796 00797 /* Set color based on interpreter name. */ 00798 /* XXX magic token should have already done this?!? */ 00799 /*@-moduncon@*/ 00800 bn = basename(s); 00801 /*@=moduncon@*/ 00802 if (!strcmp(bn, "perl")) 00803 fc->fcolor->vals[fc->ix] |= RPMFC_PERL; 00804 else if (!strncmp(bn, "python", sizeof("python")-1)) 00805 fc->fcolor->vals[fc->ix] |= RPMFC_PYTHON; 00806 else if (!strncmp(bn, "php", sizeof("php")-1)) 00807 fc->fcolor->vals[fc->ix] |= RPMFC_PHP; 00808 00809 break; 00810 } 00811 00812 (void) fclose(fp); 00813 00814 if (fc->fcolor->vals[fc->ix] & RPMFC_PERL) { 00815 if (strncmp(fn, "/usr/share/doc/", sizeof("/usr/share/doc/")-1)) { 00816 if (fc->fcolor->vals[fc->ix] & RPMFC_MODULE) 00817 xx = rpmfcHelper(fc, 'P', "perl"); 00818 if (is_executable || (fc->fcolor->vals[fc->ix] & RPMFC_MODULE)) 00819 xx = rpmfcHelper(fc, 'R', "perl"); 00820 } 00821 } else 00822 if (fc->fcolor->vals[fc->ix] & RPMFC_PYTHON) { 00823 xx = rpmfcHelper(fc, 'P', "python"); 00824 #ifdef NOTYET 00825 if (is_executable) 00826 #endif 00827 xx = rpmfcHelper(fc, 'R', "python"); 00828 } else 00829 if (fc->fcolor->vals[fc->ix] & RPMFC_LIBTOOL) { 00830 xx = rpmfcHelper(fc, 'P', "libtool"); 00831 #ifdef NOTYET 00832 if (is_executable) 00833 #endif 00834 xx = rpmfcHelper(fc, 'R', "libtool"); 00835 } else 00836 if (fc->fcolor->vals[fc->ix] & RPMFC_PKGCONFIG) { 00837 xx = rpmfcHelper(fc, 'P', "pkgconfig"); 00838 #ifdef NOTYET 00839 if (is_executable) 00840 #endif 00841 xx = rpmfcHelper(fc, 'R', "pkgconfig"); 00842 } else 00843 if (fc->fcolor->vals[fc->ix] & RPMFC_BOURNE) { 00844 #ifdef NOTYET 00845 xx = rpmfcHelper(fc, 'P', "executable"); 00846 #endif 00847 if (is_executable) 00848 xx = rpmfcHelper(fc, 'R', "executable"); 00849 } else 00850 if (fc->fcolor->vals[fc->ix] & RPMFC_PHP) { 00851 xx = rpmfcHelper(fc, 'P', "php"); 00852 if (is_executable) 00853 xx = rpmfcHelper(fc, 'R', "php"); 00854 } else 00855 if (fc->fcolor->vals[fc->ix] & RPMFC_MONO) { 00856 xx = rpmfcHelper(fc, 'P', "mono"); 00857 if (is_executable) 00858 xx = rpmfcHelper(fc, 'R', "mono"); 00859 } 00860 return 0; 00861 } 00862 00869 static int rpmfcMergePR(void * context, rpmds ds) 00870 /*@globals fileSystem, internalState @*/ 00871 /*@modifies ds, fileSystem, internalState @*/ 00872 { 00873 rpmfc fc = context; 00874 char buf[BUFSIZ]; 00875 int rc = 0; 00876 00877 if (_rpmfc_debug < 0) 00878 fprintf(stderr, "*** rpmfcMergePR(%p, %p) %s\n", context, ds, tagName(rpmdsTagN(ds))); 00879 switch(rpmdsTagN(ds)) { 00880 default: 00881 rc = -1; 00882 break; 00883 case RPMTAG_PROVIDENAME: 00884 if (!_filter_values 00885 || (!fc->skipProv 00886 && !rpmfcMatchRegexps(fc->Pmires, fc->Pnmire, ds->N[0], 'P'))) 00887 { 00888 /* Add to package provides. */ 00889 rc = rpmdsMerge(&fc->provides, ds); 00890 00891 /* Add to file dependencies. */ 00892 buf[0] = '\0'; 00893 rc = rpmfcSaveArg(&fc->ddict, rpmfcFileDep(buf, fc->ix, ds)); 00894 } 00895 break; 00896 case RPMTAG_REQUIRENAME: 00897 if (!_filter_values 00898 || (!fc->skipReq 00899 && !rpmfcMatchRegexps(fc->Rmires, fc->Rnmire, ds->N[0], 'R'))) 00900 { 00901 /* Add to package requires. */ 00902 rc = rpmdsMerge(&fc->requires, ds); 00903 00904 /* Add to file dependencies. */ 00905 buf[0] = '\0'; 00906 rc = rpmfcSaveArg(&fc->ddict, rpmfcFileDep(buf, fc->ix, ds)); 00907 } 00908 break; 00909 } 00910 return rc; 00911 } 00912 00918 static int rpmfcELF(rpmfc fc) 00919 /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/ 00920 /*@modifies rpmGlobalMacroContext, fileSystem, internalState @*/ 00921 { 00922 const char * fn = fc->fn[fc->ix]; 00923 int flags = 0; 00924 00925 if (fc->skipProv) 00926 flags |= RPMELF_FLAG_SKIPPROVIDES; 00927 if (fc->skipReq) 00928 flags |= RPMELF_FLAG_SKIPREQUIRES; 00929 00930 return rpmdsELF(fn, flags, rpmfcMergePR, fc); 00931 } 00932 00933 typedef struct rpmfcApplyTbl_s { 00934 int (*func) (rpmfc fc); 00935 int colormask; 00936 } * rpmfcApplyTbl; 00937 00941 /*@-nullassign@*/ 00942 /*@unchecked@*/ 00943 static struct rpmfcApplyTbl_s rpmfcApplyTable[] = { 00944 { rpmfcELF, RPMFC_ELF }, 00945 { rpmfcSCRIPT, (RPMFC_SCRIPT|RPMFC_PERL|RPMFC_PYTHON|RPMFC_LIBTOOL|RPMFC_PKGCONFIG|RPMFC_BOURNE|RPMFC_JAVA|RPMFC_PHP|RPMFC_MONO) }, 00946 { NULL, 0 } 00947 }; 00948 /*@=nullassign@*/ 00949 00950 rpmRC rpmfcApply(rpmfc fc) 00951 { 00952 rpmfcApplyTbl fcat; 00953 const char * s; 00954 char * se; 00955 rpmds ds; 00956 const char * fn; 00957 const char * N; 00958 const char * EVR; 00959 evrFlags Flags; 00960 unsigned char deptype; 00961 int nddict; 00962 int previx; 00963 unsigned int val; 00964 int dix; 00965 int ix; 00966 int i; 00967 int xx; 00968 int skipping; 00969 00970 miRE mire; 00971 int skipProv = fc->skipProv; 00972 int skipReq = fc->skipReq; 00973 int j; 00974 00975 if (_filter_execs) { 00976 fc->Pnmire = 0; 00977 fc->PFnmire = 0; 00978 fc->Rnmire = 0; 00979 fc->RFnmire = 0; 00980 00981 fc->PFmires = rpmfcExpandRegexps("%{__noautoprovfiles}", &fc->PFnmire); 00982 fc->RFmires = rpmfcExpandRegexps("%{__noautoreqfiles}", &fc->RFnmire); 00983 fc->Pmires = rpmfcExpandRegexps("%{__noautoprov}", &fc->Pnmire); 00984 fc->Rmires = rpmfcExpandRegexps("%{__noautoreq}", &fc->Rnmire); 00985 rpmlog(RPMLOG_DEBUG, D_("%i _noautoprov patterns.\n"), fc->Pnmire); 00986 rpmlog(RPMLOG_DEBUG, D_("%i _noautoreq patterns.\n"), fc->Rnmire); 00987 } 00988 00989 /* Make sure something didn't go wrong previously! */ 00990 assert(fc->fn != NULL); 00991 /* Generate package and per-file dependencies. */ 00992 for (fc->ix = 0; fc->fn[fc->ix] != NULL; fc->ix++) { 00993 00994 /* XXX Insure that /usr/lib{,64}/python files are marked RPMFC_PYTHON */ 00995 /* XXX HACK: classification by path is intrinsically stupid. */ 00996 { fn = strstr(fc->fn[fc->ix], "/usr/lib"); 00997 if (fn) { 00998 fn += sizeof("/usr/lib")-1; 00999 if ((fn[0] == '3' && fn[1] == '2') || 01000 (fn[0] == '6' && fn[1] == '4')) 01001 fn += 2; 01002 if (!strncmp(fn, "/python", sizeof("/python")-1)) 01003 fc->fcolor->vals[fc->ix] |= RPMFC_PYTHON; 01004 } 01005 } 01006 01007 if (fc->fcolor->vals[fc->ix]) 01008 for (fcat = rpmfcApplyTable; fcat->func != NULL; fcat++) { 01009 if (!(fc->fcolor->vals[fc->ix] & fcat->colormask)) 01010 /*@innercontinue@*/ continue; 01011 01012 if (_filter_execs) { 01013 fc->skipProv = skipProv; 01014 fc->skipReq = skipReq; 01015 if ((mire = fc->PFmires) != NULL) 01016 for (j = 0; j < fc->PFnmire; j++, mire++) { 01017 fn = fc->fn[fc->ix] + fc->brlen; 01018 if ((xx = mireRegexec(mire, fn, 0)) < 0) 01019 /*@innercontinue@*/ continue; 01020 rpmlog(RPMLOG_NOTICE, _("skipping %s provides detection\n"), 01021 fn); 01022 fc->skipProv = 1; 01023 /*@innerbreak@*/ break; 01024 } 01025 if ((mire = fc->RFmires) != NULL) 01026 for (j = 0; j < fc->RFnmire; j++, mire++) { 01027 fn = fc->fn[fc->ix] + fc->brlen; 01028 if ((xx = mireRegexec(mire, fn, 0)) < 0) 01029 /*@innercontinue@*/ continue; 01030 rpmlog(RPMLOG_NOTICE, _("skipping %s requires detection\n"), 01031 fn); 01032 fc->skipReq = 1; 01033 /*@innerbreak@*/ break; 01034 } 01035 } 01036 01037 xx = (*fcat->func) (fc); 01038 } 01039 } 01040 01041 if (_filter_execs) { 01042 fc->PFmires = rpmfcFreeRegexps(fc->PFmires, fc->PFnmire); 01043 fc->RFmires = rpmfcFreeRegexps(fc->RFmires, fc->RFnmire); 01044 fc->Pmires = rpmfcFreeRegexps(fc->Pmires, fc->Pnmire); 01045 fc->Rmires = rpmfcFreeRegexps(fc->Rmires, fc->Rnmire); 01046 } 01047 fc->skipProv = skipProv; 01048 fc->skipReq = skipReq; 01049 01050 /* Generate per-file indices into package dependencies. */ 01051 nddict = argvCount(fc->ddict); 01052 previx = -1; 01053 for (i = 0; i < nddict; i++) { 01054 s = fc->ddict[i]; 01055 01056 /* Parse out (file#,deptype,N,EVR,Flags) */ 01057 ix = strtol(s, &se, 10); 01058 assert(se != NULL); 01059 deptype = *se++; 01060 se++; 01061 N = se; 01062 while (*se && *se != ' ') 01063 se++; 01064 *se++ = '\0'; 01065 EVR = se; 01066 while (*se && *se != ' ') 01067 se++; 01068 *se++ = '\0'; 01069 Flags = strtol(se, NULL, 16); 01070 01071 dix = -1; 01072 skipping = 0; 01073 switch (deptype) { 01074 default: 01075 /*@switchbreak@*/ break; 01076 case 'P': 01077 skipping = fc->skipProv; 01078 ds = rpmdsSingle(RPMTAG_PROVIDENAME, N, EVR, Flags); 01079 dix = rpmdsFind(fc->provides, ds); 01080 (void)rpmdsFree(ds); 01081 ds = NULL; 01082 /*@switchbreak@*/ break; 01083 case 'R': 01084 skipping = fc->skipReq; 01085 ds = rpmdsSingle(RPMTAG_REQUIRENAME, N, EVR, Flags); 01086 dix = rpmdsFind(fc->requires, ds); 01087 (void)rpmdsFree(ds); 01088 ds = NULL; 01089 /*@switchbreak@*/ break; 01090 } 01091 01092 /* XXX assertion incorrect while generating -debuginfo deps. */ 01093 #if 0 01094 assert(dix >= 0); 01095 #else 01096 if (dix < 0) 01097 continue; 01098 #endif 01099 01100 val = (deptype << 24) | (dix & 0x00ffffff); 01101 xx = argiAdd(&fc->ddictx, -1, val); 01102 01103 if (previx != ix) { 01104 previx = ix; 01105 xx = argiAdd(&fc->fddictx, ix, argiCount(fc->ddictx)-1); 01106 } 01107 if (fc->fddictn && fc->fddictn->vals && !skipping) 01108 fc->fddictn->vals[ix]++; 01109 } 01110 01111 return RPMRC_OK; 01112 } 01113 01114 rpmRC rpmfcClassify(rpmfc fc, ARGV_t argv, rpmuint16_t * fmode) 01115 { 01116 ARGV_t fcav = NULL; 01117 ARGV_t dav; 01118 rpmmg mg = NULL; 01119 const char * s, * se; 01120 size_t slen; 01121 int fcolor; 01122 int xx; 01123 const char * magicfile = NULL; 01124 01125 if (fc == NULL || argv == NULL) 01126 return RPMRC_OK; 01127 01128 magicfile = rpmExpand("%{?_rpmfc_magic_path}", NULL); 01129 if (magicfile == NULL || *magicfile == '\0') 01130 magicfile = _free(magicfile); 01131 mg = rpmmgNew(magicfile, 0); 01132 assert(mg != NULL); /* XXX figger a proper return path. */ 01133 01134 fc->nfiles = argvCount(argv); 01135 01136 /* Initialize the per-file dictionary indices. */ 01137 xx = argiAdd(&fc->fddictx, fc->nfiles-1, 0); 01138 xx = argiAdd(&fc->fddictn, fc->nfiles-1, 0); 01139 01140 /* Build (sorted) file class dictionary. */ 01141 xx = argvAdd(&fc->cdict, ""); 01142 xx = argvAdd(&fc->cdict, "directory"); 01143 01144 for (fc->ix = 0; fc->ix < fc->nfiles; fc->ix++) { 01145 const char * ftype; 01146 int freeftype; 01147 rpmuint16_t mode = (fmode ? fmode[fc->ix] : 0); 01148 int urltype; 01149 01150 ftype = ""; freeftype = 0; 01151 urltype = urlPath(argv[fc->ix], &s); 01152 assert(s != NULL && *s == '/'); 01153 slen = strlen(s); 01154 01155 switch (mode & S_IFMT) { 01156 case S_IFCHR: ftype = "character special"; /*@switchbreak@*/ break; 01157 case S_IFBLK: ftype = "block special"; /*@switchbreak@*/ break; 01158 #if defined(S_IFIFO) 01159 case S_IFIFO: ftype = "fifo (named pipe)"; /*@switchbreak@*/ break; 01160 #endif 01161 #if defined(S_IFSOCK) 01162 /*@-unrecog@*/ 01163 case S_IFSOCK: ftype = "socket"; /*@switchbreak@*/ break; 01164 /*@=unrecog@*/ 01165 #endif 01166 case S_IFDIR: 01167 case S_IFLNK: 01168 case S_IFREG: 01169 default: 01170 01171 #define _suffix(_s, _x) \ 01172 (slen >= sizeof(_x) && !strcmp((_s)+slen-(sizeof(_x)-1), (_x))) 01173 01174 /* XXX all files with extension ".pm" are perl modules for now. */ 01175 if (_suffix(s, ".pm")) 01176 ftype = "Perl5 module source text"; 01177 01178 /* XXX all files with extension ".jar" are java archives for now. */ 01179 else if (_suffix(s, ".jar")) 01180 ftype = "Java archive file"; 01181 01182 /* XXX all files with extension ".class" are java class files for now. */ 01183 else if (_suffix(s, ".class")) 01184 ftype = "Java class file"; 01185 01186 /* XXX all files with extension ".la" are libtool for now. */ 01187 else if (_suffix(s, ".la")) 01188 ftype = "libtool library file"; 01189 01190 /* XXX all files with extension ".pc" are pkgconfig for now. */ 01191 else if (_suffix(s, ".pc")) 01192 ftype = "pkgconfig file"; 01193 01194 /* XXX all files with extension ".php" are PHP for now. */ 01195 else if (_suffix(s, ".php")) 01196 ftype = "PHP script text"; 01197 01198 /* XXX skip all files in /dev/ which are (or should be) %dev dummies. */ 01199 else if (slen >= fc->brlen+sizeof("/dev/") && !strncmp(s+fc->brlen, "/dev/", sizeof("/dev/")-1)) 01200 ftype = ""; 01201 else if (magicfile) { 01202 ftype = rpmmgFile(mg, s); 01203 assert(ftype != NULL); /* XXX never happens, rpmmgFile() returns "" */ 01204 freeftype = 1; 01205 } 01206 /*@switchbreak@*/ break; 01207 } 01208 01209 se = ftype; 01210 01211 if (_rpmfc_debug) /* XXX noisy */ 01212 rpmlog(RPMLOG_DEBUG, "%s: %s\n", s, se); 01213 01214 /* Save the path. */ 01215 xx = argvAdd(&fc->fn, s); 01216 01217 /* Save the file type string. */ 01218 xx = argvAdd(&fcav, se); 01219 01220 /* Add (filtered) entry to sorted class dictionary. */ 01221 fcolor = rpmfcColoring(se); 01222 xx = argiAdd(&fc->fcolor, (int)fc->ix, fcolor); 01223 01224 if (fcolor != RPMFC_WHITE && (fcolor & RPMFC_INCLUDE)) 01225 xx = rpmfcSaveArg(&fc->cdict, se); 01226 01227 /*@-modobserver -observertrans @*/ /* XXX mixed types in variable */ 01228 if (freeftype) 01229 ftype = _free(ftype); 01230 /*@=modobserver =observertrans @*/ 01231 } 01232 01233 /* Build per-file class index array. */ 01234 fc->fknown = 0; 01235 for (fc->ix = 0; fc->ix < fc->nfiles; fc->ix++) { 01236 se = fcav[fc->ix]; 01237 assert(se != NULL); 01238 01239 dav = argvSearch(fc->cdict, se, NULL); 01240 if (dav) { 01241 xx = argiAdd(&fc->fcdictx, (int)fc->ix, (dav - fc->cdict)); 01242 fc->fknown++; 01243 } else { 01244 xx = argiAdd(&fc->fcdictx, (int)fc->ix, 0); 01245 fc->fwhite++; 01246 } 01247 } 01248 01249 fcav = argvFree(fcav); 01250 01251 mg = rpmmgFree(mg); 01252 rpmlog(RPMLOG_DEBUG, 01253 D_("categorized %d files into %d classes (using %s).\n"), 01254 fc->nfiles, argvCount(fc->cdict), magicfile); 01255 magicfile = _free(magicfile); 01256 01257 return RPMRC_OK; 01258 } 01259 01262 typedef struct DepMsg_s * DepMsg_t; 01263 01266 struct DepMsg_s { 01267 /*@observer@*/ /*@null@*/ 01268 const char * msg; 01269 /*@observer@*/ 01270 const char * argv[4]; 01271 rpmTag ntag; 01272 rpmTag vtag; 01273 rpmTag ftag; 01274 int mask; 01275 int xor; 01276 }; 01277 01280 /*@-nullassign@*/ 01281 /*@unchecked@*/ 01282 static struct DepMsg_s depMsgs[] = { 01283 { "Provides", { "%{?__find_provides}", NULL, NULL, NULL }, 01284 RPMTAG_PROVIDENAME, RPMTAG_PROVIDEVERSION, RPMTAG_PROVIDEFLAGS, 01285 0, -1 }, 01286 { "Requires(interp)", { NULL, "interp", NULL, NULL }, 01287 RPMTAG_REQUIRENAME, RPMTAG_REQUIREVERSION, RPMTAG_REQUIREFLAGS, 01288 _notpre(RPMSENSE_INTERP), 0 }, 01289 { "Requires(rpmlib)", { NULL, "rpmlib", NULL, NULL }, 01290 -1, -1, RPMTAG_REQUIREFLAGS, 01291 _notpre(RPMSENSE_RPMLIB), 0 }, 01292 { "Requires(verify)", { NULL, "verify", NULL, NULL }, 01293 -1, -1, RPMTAG_REQUIREFLAGS, 01294 RPMSENSE_SCRIPT_VERIFY, 0 }, 01295 { "Requires(pre)", { NULL, "pre", NULL, NULL }, 01296 -1, -1, RPMTAG_REQUIREFLAGS, 01297 _notpre(RPMSENSE_SCRIPT_PRE), 0 }, 01298 { "Requires(post)", { NULL, "post", NULL, NULL }, 01299 -1, -1, RPMTAG_REQUIREFLAGS, 01300 _notpre(RPMSENSE_SCRIPT_POST), 0 }, 01301 { "Requires(preun)", { NULL, "preun", NULL, NULL }, 01302 -1, -1, RPMTAG_REQUIREFLAGS, 01303 _notpre(RPMSENSE_SCRIPT_PREUN), 0 }, 01304 { "Requires(postun)", { NULL, "postun", NULL, NULL }, 01305 -1, -1, RPMTAG_REQUIREFLAGS, 01306 _notpre(RPMSENSE_SCRIPT_POSTUN), 0 }, 01307 { "Requires", { "%{?__find_requires}", NULL, NULL, NULL }, 01308 -1, -1, RPMTAG_REQUIREFLAGS, /* XXX inherit name/version arrays */ 01309 RPMSENSE_FIND_REQUIRES|RPMSENSE_TRIGGERIN|RPMSENSE_TRIGGERUN|RPMSENSE_TRIGGERPOSTUN|RPMSENSE_TRIGGERPREIN, 0 }, 01310 { "Conflicts", { "%{?__find_conflicts}", NULL, NULL, NULL }, 01311 RPMTAG_CONFLICTNAME, RPMTAG_CONFLICTVERSION, RPMTAG_CONFLICTFLAGS, 01312 0, -1 }, 01313 { "Obsoletes", { "%{?__find_obsoletes}", NULL, NULL, NULL }, 01314 RPMTAG_OBSOLETENAME, RPMTAG_OBSOLETEVERSION, RPMTAG_OBSOLETEFLAGS, 01315 0, -1 }, 01316 { NULL, { NULL, NULL, NULL, NULL }, 0, 0, 0, 0, 0 } 01317 }; 01318 /*@=nullassign@*/ 01319 01320 /*@unchecked@*/ 01321 static DepMsg_t DepMsgs = depMsgs; 01322 01327 static void printDeps(Header h) 01328 /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/ 01329 /*@modifies h, rpmGlobalMacroContext, fileSystem, internalState @*/ 01330 { 01331 DepMsg_t dm; 01332 rpmds ds = NULL; 01333 int flags = 0x2; /* XXX no filtering, !scareMem */ 01334 const char * DNEVR; 01335 evrFlags Flags; 01336 int bingo = 0; 01337 01338 for (dm = DepMsgs; dm->msg != NULL; dm++) { 01339 if ((int)dm->ntag != -1) { 01340 (void)rpmdsFree(ds); 01341 ds = NULL; 01342 ds = rpmdsNew(h, dm->ntag, flags); 01343 } 01344 if (dm->ftag == 0) 01345 continue; 01346 01347 ds = rpmdsInit(ds); 01348 if (ds == NULL) 01349 continue; /* XXX can't happen */ 01350 01351 bingo = 0; 01352 while (rpmdsNext(ds) >= 0) { 01353 01354 Flags = rpmdsFlags(ds); 01355 01356 if (!((Flags & dm->mask) ^ dm->xor)) 01357 /*@innercontinue@*/ continue; 01358 if (bingo == 0) { 01359 rpmlog(RPMLOG_NOTICE, "%s:", (dm->msg ? dm->msg : "")); 01360 bingo = 1; 01361 } 01362 if ((DNEVR = rpmdsDNEVR(ds)) == NULL) 01363 /*@innercontinue@*/ continue; /* XXX can't happen */ 01364 rpmlog(RPMLOG_NOTICE, " %s", DNEVR+2); 01365 } 01366 if (bingo) 01367 rpmlog(RPMLOG_NOTICE, "\n"); 01368 } 01369 (void)rpmdsFree(ds); 01370 ds = NULL; 01371 } 01372 01375 static rpmRC rpmfcGenerateDependsHelper(const Spec spec, Package pkg, rpmfi fi) 01376 /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/ 01377 /*@modifies fi, rpmGlobalMacroContext, fileSystem, internalState @*/ 01378 { 01379 rpmiob iob_stdin; 01380 rpmiob iob_stdout; 01381 DepMsg_t dm; 01382 int failnonzero = 0; 01383 rpmRC rc = RPMRC_OK; 01384 01385 /* 01386 * Create file manifest buffer to deliver to dependency finder. 01387 */ 01388 iob_stdin = rpmiobNew(0); 01389 fi = rpmfiInit(fi, 0); 01390 if (fi != NULL) 01391 while (rpmfiNext(fi) >= 0) 01392 iob_stdin = rpmiobAppend(iob_stdin, rpmfiFN(fi), 1); 01393 01394 for (dm = DepMsgs; dm->msg != NULL; dm++) { 01395 rpmTag tag; 01396 rpmsenseFlags tagflags; 01397 char * s; 01398 int xx; 01399 01400 tag = (dm->ftag > 0) ? dm->ftag : dm->ntag; 01401 tagflags = 0; 01402 s = NULL; 01403 01404 switch(tag) { 01405 case RPMTAG_PROVIDEFLAGS: 01406 if (!pkg->autoProv) 01407 continue; 01408 failnonzero = 1; 01409 tagflags = RPMSENSE_FIND_PROVIDES; 01410 /*@switchbreak@*/ break; 01411 case RPMTAG_REQUIREFLAGS: 01412 if (!pkg->autoReq) 01413 continue; 01414 failnonzero = 0; 01415 tagflags = RPMSENSE_FIND_REQUIRES; 01416 /*@switchbreak@*/ break; 01417 default: 01418 continue; 01419 /*@notreached@*/ /*@switchbreak@*/ break; 01420 } 01421 01422 xx = rpmfcExec(dm->argv, iob_stdin, &iob_stdout, failnonzero); 01423 if (xx == -1) 01424 continue; 01425 01426 s = rpmExpand(dm->argv[0], NULL); 01427 rpmlog(RPMLOG_NOTICE, _("Finding %s: %s\n"), dm->msg, 01428 (s ? s : "")); 01429 s = _free(s); 01430 01431 if (iob_stdout == NULL) { 01432 rpmlog(RPMLOG_ERR, _("Failed to find %s:\n"), dm->msg); 01433 rc = RPMRC_FAIL; 01434 break; 01435 } 01436 01437 /* Parse dependencies into header */ 01438 if (spec->_parseRCPOT) 01439 rc = spec->_parseRCPOT(spec, pkg, rpmiobStr(iob_stdout), tag, 01440 0, tagflags); 01441 iob_stdout = rpmiobFree(iob_stdout); 01442 01443 if (rc) { 01444 rpmlog(RPMLOG_ERR, _("Failed to find %s:\n"), dm->msg); 01445 break; 01446 } 01447 } 01448 01449 iob_stdin = rpmiobFree(iob_stdin); 01450 01451 return rc; 01452 } 01453 01456 /*@-nullassign@*/ 01457 /*@unchecked@*/ 01458 static struct DepMsg_s scriptMsgs[] = { 01459 { "Requires(pre)", { "%{?__scriptlet_requires}", NULL, NULL, NULL }, 01460 RPMTAG_PREINPROG, RPMTAG_PREIN, RPMTAG_REQUIREFLAGS, 01461 RPMSENSE_SCRIPT_PRE, 0 }, 01462 { "Requires(post)", { "%{?__scriptlet_requires}", NULL, NULL, NULL }, 01463 RPMTAG_POSTINPROG, RPMTAG_POSTIN, RPMTAG_REQUIREFLAGS, 01464 RPMSENSE_SCRIPT_POST, 0 }, 01465 { "Requires(preun)", { "%{?__scriptlet_requires}", NULL, NULL, NULL }, 01466 RPMTAG_PREUNPROG, RPMTAG_PREUN, RPMTAG_REQUIREFLAGS, 01467 RPMSENSE_SCRIPT_PREUN, 0 }, 01468 { "Requires(postun)", { "%{?__scriptlet_requires}", NULL, NULL, NULL }, 01469 RPMTAG_POSTUNPROG, RPMTAG_POSTUN, RPMTAG_REQUIREFLAGS, 01470 RPMSENSE_SCRIPT_POSTUN, 0 }, 01471 { NULL, { NULL, NULL, NULL, NULL }, 0, 0, 0, 0, 0 } 01472 }; 01473 /*@=nullassign@*/ 01474 01475 /*@unchecked@*/ 01476 static DepMsg_t ScriptMsgs = scriptMsgs; 01477 01480 static int rpmfcGenerateScriptletDeps(const Spec spec, Package pkg) 01481 /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/ 01482 /*@modifies rpmGlobalMacroContext, fileSystem, internalState @*/ 01483 { 01484 HE_t he = memset(alloca(sizeof(*he)), 0, sizeof(*he)); 01485 rpmiob iob_stdin = rpmiobNew(0); 01486 rpmiob iob_stdout = NULL; 01487 DepMsg_t dm; 01488 int failnonzero = 0; 01489 int rc = 0; 01490 int xx; 01491 01492 for (dm = ScriptMsgs; dm->msg != NULL; dm++) { 01493 int tag, tagflags; 01494 char * s; 01495 01496 tag = dm->ftag; 01497 tagflags = RPMSENSE_FIND_REQUIRES | dm->mask; 01498 01499 /* Retrieve scriptlet interpreter. */ 01500 he->tag = dm->ntag; 01501 xx = headerGet(pkg->header, he, 0); 01502 if (!xx || he->p.str == NULL) 01503 continue; 01504 xx = strcmp(he->p.str, "/bin/sh") && strcmp(he->p.str, "/bin/bash"); 01505 he->p.ptr = _free(he->p.ptr); 01506 if (xx) 01507 continue; 01508 01509 /* Retrieve scriptlet body. */ 01510 he->tag = dm->vtag; 01511 xx = headerGet(pkg->header, he, 0); 01512 if (!xx || he->p.str == NULL) 01513 continue; 01514 iob_stdin = rpmiobEmpty(iob_stdin); 01515 iob_stdin = rpmiobAppend(iob_stdin, he->p.str, 1); 01516 iob_stdin = rpmiobRTrim(iob_stdin); 01517 he->p.ptr = _free(he->p.ptr); 01518 01519 xx = rpmfcExec(dm->argv, iob_stdin, &iob_stdout, failnonzero); 01520 if (xx == -1) 01521 continue; 01522 01523 /* Parse dependencies into header */ 01524 s = rpmiobStr(iob_stdout); 01525 if (s != NULL && *s != '\0') { 01526 char * se = s; 01527 /* XXX Convert "executable(/path/to/file)" to "/path/to/file". */ 01528 while ((se = strstr(se, "executable(/")) != NULL) { 01529 /*@-modobserver@*/ /* FIX: rpmiobStr should not be observer */ 01530 se = stpcpy(se, " "); 01531 *se = '/'; /* XXX stpcpy truncates the '/' */ 01532 /*@=modobserver@*/ 01533 se = strchr(se, ')'); 01534 if (se == NULL) 01535 /*@innerbreak@*/ break; 01536 *se++ = ' '; 01537 } 01538 if (spec->_parseRCPOT) 01539 rc = spec->_parseRCPOT(spec, pkg, s, tag, 0, tagflags); 01540 } 01541 iob_stdout = rpmiobFree(iob_stdout); 01542 01543 } 01544 01545 iob_stdin = rpmiobFree(iob_stdin); 01546 01547 return rc; 01548 } 01549 01550 rpmRC rpmfcGenerateDepends(void * specp, void * pkgp) 01551 { 01552 HE_t he = memset(alloca(sizeof(*he)), 0, sizeof(*he)); 01553 const Spec spec = specp; 01554 Package pkg = pkgp; 01555 rpmfi fi = pkg->cpioList; 01556 rpmfc fc = NULL; 01557 rpmds ds; 01558 int flags = 0x2; /* XXX no filtering, !scareMem */ 01559 ARGV_t av; 01560 rpmuint16_t * fmode; 01561 int ac = rpmfiFC(fi); 01562 char buf[BUFSIZ]; 01563 const char * N; 01564 const char * EVR; 01565 int genConfigDeps, internaldeps; 01566 rpmRC rc = RPMRC_OK; 01567 int i; 01568 int xx; 01569 01570 /* Skip packages with no files. */ 01571 if (ac <= 0) 01572 return RPMRC_OK; 01573 01574 /* Skip packages that have dependency generation disabled. */ 01575 if (! (pkg->autoReq || pkg->autoProv)) 01576 return RPMRC_OK; 01577 01578 /* If new-fangled dependency generation is disabled ... */ 01579 internaldeps = rpmExpandNumeric("%{?_use_internal_dependency_generator}"); 01580 if (internaldeps == 0) { 01581 /* ... then generate dependencies using %{__find_requires} et al. */ 01582 rc = rpmfcGenerateDependsHelper(spec, pkg, fi); 01583 printDeps(pkg->header); 01584 return rc; 01585 } 01586 01587 /* Generate scriptlet Dependencies. */ 01588 if (internaldeps > 1) 01589 xx = rpmfcGenerateScriptletDeps(spec, pkg); 01590 01591 /* Extract absolute file paths in argv format. */ 01592 /* XXX TODO: should use argvFoo ... */ 01593 av = xcalloc(ac+1, sizeof(*av)); 01594 fmode = xcalloc(ac+1, sizeof(*fmode)); 01595 01596 genConfigDeps = 0; 01597 fi = rpmfiInit(fi, 0); 01598 if (fi != NULL) 01599 while ((i = rpmfiNext(fi)) >= 0) { 01600 rpmfileAttrs fileAttrs; 01601 01602 /* Does package have any %config files? */ 01603 fileAttrs = rpmfiFFlags(fi); 01604 genConfigDeps |= (fileAttrs & RPMFILE_CONFIG); 01605 01606 av[i] = xstrdup(rpmfiFN(fi)); 01607 fmode[i] = rpmfiFMode(fi); 01608 } 01609 av[ac] = NULL; 01610 01611 fc = rpmfcNew(); 01612 fc->skipProv = !pkg->autoProv; 01613 fc->skipReq = !pkg->autoReq; 01614 fc->tracked = 0; 01615 01616 { const char * buildRootURL; 01617 const char * buildRoot; 01618 buildRootURL = rpmGenPath(spec->rootURL, "%{?buildroot}", NULL); 01619 (void) urlPath(buildRootURL, &buildRoot); 01620 if (buildRoot && !strcmp(buildRoot, "/")) buildRoot = NULL; 01621 fc->brlen = (buildRoot ? strlen(buildRoot) : 0); 01622 buildRootURL = _free(buildRootURL); 01623 } 01624 01625 /* Copy (and delete) manually generated dependencies to dictionary. */ 01626 if (!fc->skipProv) { 01627 ds = rpmdsNew(pkg->header, RPMTAG_PROVIDENAME, flags); 01628 xx = rpmdsMerge(&fc->provides, ds); 01629 (void)rpmdsFree(ds); 01630 ds = NULL; 01631 he->tag = RPMTAG_PROVIDENAME; 01632 xx = headerDel(pkg->header, he, 0); 01633 he->tag = RPMTAG_PROVIDEVERSION; 01634 xx = headerDel(pkg->header, he, 0); 01635 he->tag = RPMTAG_PROVIDEFLAGS; 01636 xx = headerDel(pkg->header, he, 0); 01637 01638 /* Add config dependency, Provides: config(N) = EVR */ 01639 if (genConfigDeps) { 01640 N = rpmdsN(pkg->ds); 01641 assert(N != NULL); 01642 EVR = rpmdsEVR(pkg->ds); 01643 assert(EVR != NULL); 01644 sprintf(buf, "config(%s)", N); 01645 ds = rpmdsSingle(RPMTAG_PROVIDENAME, buf, EVR, 01646 (RPMSENSE_EQUAL|RPMSENSE_CONFIG)); 01647 xx = rpmdsMerge(&fc->provides, ds); 01648 (void)rpmdsFree(ds); 01649 ds = NULL; 01650 } 01651 } 01652 01653 if (!fc->skipReq) { 01654 ds = rpmdsNew(pkg->header, RPMTAG_REQUIRENAME, flags); 01655 xx = rpmdsMerge(&fc->requires, ds); 01656 (void)rpmdsFree(ds); 01657 ds = NULL; 01658 he->tag = RPMTAG_REQUIRENAME; 01659 xx = headerDel(pkg->header, he, 0); 01660 he->tag = RPMTAG_REQUIREVERSION; 01661 xx = headerDel(pkg->header, he, 0); 01662 he->tag = RPMTAG_REQUIREFLAGS; 01663 xx = headerDel(pkg->header, he, 0); 01664 01665 /* Add config dependency, Requires: config(N) = EVR */ 01666 if (genConfigDeps) { 01667 N = rpmdsN(pkg->ds); 01668 assert(N != NULL); 01669 EVR = rpmdsEVR(pkg->ds); 01670 assert(EVR != NULL); 01671 sprintf(buf, "config(%s)", N); 01672 ds = rpmdsSingle(RPMTAG_REQUIRENAME, buf, EVR, 01673 (RPMSENSE_EQUAL|RPMSENSE_CONFIG)); 01674 xx = rpmdsMerge(&fc->requires, ds); 01675 (void)rpmdsFree(ds); 01676 ds = NULL; 01677 } 01678 } 01679 01680 /* Build file class dictionary. */ 01681 xx = rpmfcClassify(fc, av, fmode); 01682 01683 /* Build file/package dependency dictionary. */ 01684 xx = rpmfcApply(fc); 01685 01686 /* Add per-file colors(#files) */ 01687 he->tag = RPMTAG_FILECOLORS; 01688 he->t = RPM_UINT32_TYPE; 01689 he->p.ui32p = argiData(fc->fcolor); 01690 he->c = argiCount(fc->fcolor); 01691 assert(ac == (int)he->c); 01692 if (he->p.ptr != NULL && he->c > 0) { 01693 rpmuint32_t * fcolors = he->p.ui32p; 01694 01695 /* XXX Make sure only primary (i.e. Elf32/Elf64) colors are added. */ 01696 for (i = 0; i < (int)he->c; i++) 01697 fcolors[i] &= 0x0f; 01698 01699 xx = headerPut(pkg->header, he, 0); 01700 } 01701 01702 /* Add classes(#classes) */ 01703 he->tag = RPMTAG_CLASSDICT; 01704 he->t = RPM_STRING_ARRAY_TYPE; 01705 he->p.argv = argvData(fc->cdict); 01706 he->c = argvCount(fc->cdict); 01707 if (he->p.ptr != NULL && he->c > 0) { 01708 xx = headerPut(pkg->header, he, 0); 01709 } 01710 01711 /* Add per-file classes(#files) */ 01712 he->tag = RPMTAG_FILECLASS; 01713 he->t = RPM_UINT32_TYPE; 01714 he->p.ui32p = argiData(fc->fcdictx); 01715 he->c = argiCount(fc->fcdictx); 01716 assert(ac == (int)he->c); 01717 if (he->p.ptr != NULL && he->c > 0) { 01718 xx = headerPut(pkg->header, he, 0); 01719 } 01720 01721 /* Add Provides: */ 01722 if (fc->provides != NULL && (he->c = rpmdsCount(fc->provides)) > 0 01723 && !fc->skipProv) 01724 { 01725 he->tag = RPMTAG_PROVIDENAME; 01726 he->t = RPM_STRING_ARRAY_TYPE; 01727 he->p.argv = fc->provides->N; 01728 xx = headerPut(pkg->header, he, 0); 01729 01730 /* XXX rpm prior to 3.0.2 did not always supply EVR and Flags. */ 01731 /*@-nullpass@*/ 01732 he->tag = RPMTAG_PROVIDEVERSION; 01733 he->t = RPM_STRING_ARRAY_TYPE; 01734 he->p.argv = fc->provides->EVR; 01735 assert(he->p.ptr != NULL); 01736 xx = headerPut(pkg->header, he, 0); 01737 01738 he->tag = RPMTAG_PROVIDEFLAGS; 01739 he->t = RPM_UINT32_TYPE; 01740 he->p.ui32p = (rpmuint32_t *) fc->provides->Flags; 01741 assert(he->p.ptr != NULL); 01742 xx = headerPut(pkg->header, he, 0); 01743 /*@=nullpass@*/ 01744 } 01745 01746 /* Add Requires: */ 01747 if (fc->requires != NULL && (he->c = rpmdsCount(fc->requires)) > 0 01748 && !fc->skipReq) 01749 { 01750 he->tag = RPMTAG_REQUIRENAME; 01751 he->t = RPM_STRING_ARRAY_TYPE; 01752 he->p.argv = fc->requires->N; 01753 assert(he->p.ptr != NULL); 01754 xx = headerPut(pkg->header, he, 0); 01755 01756 /* XXX rpm prior to 3.0.2 did not always supply EVR and Flags. */ 01757 /*@-nullpass@*/ 01758 he->tag = RPMTAG_REQUIREVERSION; 01759 he->t = RPM_STRING_ARRAY_TYPE; 01760 he->p.argv = fc->requires->EVR; 01761 assert(he->p.ptr != NULL); 01762 xx = headerPut(pkg->header, he, 0); 01763 01764 he->tag = RPMTAG_REQUIREFLAGS; 01765 he->t = RPM_UINT32_TYPE; 01766 he->p.ui32p = (rpmuint32_t *) fc->requires->Flags; 01767 assert(he->p.ptr != NULL); 01768 xx = headerPut(pkg->header, he, 0); 01769 /*@=nullpass@*/ 01770 } 01771 01772 /* Add dependency dictionary(#dependencies) */ 01773 he->tag = RPMTAG_DEPENDSDICT; 01774 he->t = RPM_UINT32_TYPE; 01775 he->p.ui32p = argiData(fc->ddictx); 01776 he->c = argiCount(fc->ddictx); 01777 if (he->p.ptr != NULL) { 01778 xx = headerPut(pkg->header, he, 0); 01779 } 01780 01781 /* Add per-file dependency (start,number) pairs (#files) */ 01782 he->tag = RPMTAG_FILEDEPENDSX; 01783 he->t = RPM_UINT32_TYPE; 01784 he->p.ui32p = argiData(fc->fddictx); 01785 he->c = argiCount(fc->fddictx); 01786 assert(ac == (int)he->c); 01787 if (he->p.ptr != NULL) { 01788 xx = headerPut(pkg->header, he, 0); 01789 } 01790 01791 he->tag = RPMTAG_FILEDEPENDSN; 01792 he->t = RPM_UINT32_TYPE; 01793 he->p.ui32p = argiData(fc->fddictn); 01794 he->c = argiCount(fc->fddictn); 01795 assert(ac == (int)he->c); 01796 if (he->p.ptr != NULL) { 01797 xx = headerPut(pkg->header, he, 0); 01798 } 01799 01800 printDeps(pkg->header); 01801 01802 if (fc != NULL && _rpmfc_debug) { 01803 char msg[BUFSIZ]; 01804 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)); 01805 rpmfcPrint(msg, fc, NULL); 01806 } 01807 01808 /* Clean up. */ 01809 fmode = _free(fmode); 01810 fc = rpmfcFree(fc); 01811 av = argvFree(av); 01812 01813 return rc; 01814 } 01815 01816 /*@-mustmod@*/ 01817 static void rpmfcFini(void * _fc) 01818 /*@modifies _fc @*/ 01819 { 01820 rpmfc fc = _fc; 01821 01822 fc->fn = argvFree(fc->fn); 01823 fc->fcolor = argiFree(fc->fcolor); 01824 fc->fcdictx = argiFree(fc->fcdictx); 01825 fc->fddictx = argiFree(fc->fddictx); 01826 fc->fddictn = argiFree(fc->fddictn); 01827 fc->cdict = argvFree(fc->cdict); 01828 fc->ddict = argvFree(fc->ddict); 01829 fc->ddictx = argiFree(fc->ddictx); 01830 01831 (void)rpmdsFree(fc->provides); 01832 fc->provides = NULL; 01833 (void)rpmdsFree(fc->requires); 01834 fc->requires = NULL; 01835 01836 fc->iob_java = rpmiobFree(fc->iob_java); 01837 fc->iob_perl = rpmiobFree(fc->iob_perl); 01838 fc->iob_python = rpmiobFree(fc->iob_python); 01839 fc->iob_php = rpmiobFree(fc->iob_php); 01840 } 01841 /*@=mustmod@*/ 01842 01843 /*@unchecked@*/ /*@only@*/ /*@null@*/ 01844 rpmioPool _rpmfcPool = NULL; 01845 01846 static rpmfc rpmfcGetPool(/*@null@*/ rpmioPool pool) 01847 /*@globals _rpmfcPool, fileSystem, internalState @*/ 01848 /*@modifies pool, _rpmfcPool, fileSystem, internalState @*/ 01849 { 01850 rpmfc fc; 01851 01852 if (_rpmfcPool == NULL) { 01853 _rpmfcPool = rpmioNewPool("fc", sizeof(*fc), -1, _rpmfc_debug, 01854 NULL, NULL, rpmfcFini); 01855 pool = _rpmfcPool; 01856 } 01857 return (rpmfc) rpmioGetPool(pool, sizeof(*fc)); 01858 } 01859 01860 rpmfc rpmfcNew(void) 01861 { 01862 rpmfc fc = rpmfcGetPool(_rpmfcPool); 01863 return rpmfcLink(fc); 01864 } 01865