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