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