/* reqprov.c -- require/provide handling */ #include #include #include #include #include #include #include #include #include #include #include #include #include "specP.h" #include "reqprov.h" #include "messages.h" #include "rpmlib.h" #include "misc.h" static StringBuf getOutputFrom(char *dir, char *argv[], char *writePtr, int writeBytesLeft, int failNonZero); /*************************************************************/ /* */ /* Adding entries to the package reqprov list */ /* Handle duplicate entries */ /* */ /*************************************************************/ int addReqProv(struct PackageRec *p, int flags, char *name, char *version) { struct ReqProv *rd; int same; /* Frist see if the same entry is already there */ rd = p->reqprov; while (rd) { if (rd->flags == flags) { if (rd->version == version) { same = 1; } else if (!rd->version || !version) { same = 0; } else if (!strcmp(rd->version, version)) { same = 1; } else { same = 0; } if (same && !strcmp(rd->name, name)) { /* They are exacty the same */ break; } } rd = rd->next; } if (rd) { /* already there */ rpmMessage(RPMMESS_DEBUG, "Already Got: %s\n", name); return 0; } rd = (struct ReqProv *)malloc(sizeof(*rd)); rd->flags = flags; rd->name = strdup(name); rd->version = version ? strdup(version) : NULL; rd->next = p->reqprov; p->reqprov = rd; if (flags & RPMSENSE_PROVIDES) { rpmMessage(RPMMESS_DEBUG, "Adding provide: %s\n", name); p->numProv++; } else if (flags & RPMSENSE_CONFLICTS) { rpmMessage(RPMMESS_DEBUG, "Adding conflict: %s\n", name); p->numConflict++; } else if (flags & RPMSENSE_PREREQ) { rpmMessage(RPMMESS_DEBUG, "Adding prereq: %s\n", name); p->numPreReq++; } else if (flags & RPMSENSE_OBSOLETES) { rpmMessage(RPMMESS_DEBUG, "Adding obsoletes: %s\n", name); p->numObsoletes++; } else { rpmMessage(RPMMESS_DEBUG, "Adding require: %s\n", name); p->numReq++; } return 0; } /*************************************************************/ /* */ /* Add require/provides for the files in the header */ /* (adds to the package structure) */ /* */ /*************************************************************/ static StringBuf getOutputFrom(char *dir, char *argv[], char *writePtr, int writeBytesLeft, int failNonZero) { int progPID; int progDead; int toProg[2]; int fromProg[2]; int status; void *oldhandler; int bytesWritten; StringBuf readBuff; int bytes; unsigned char buf[8193]; oldhandler = signal(SIGPIPE, SIG_IGN); pipe(toProg); pipe(fromProg); if (!(progPID = fork())) { close(toProg[1]); close(fromProg[0]); dup2(toProg[0], 0); /* Make stdin the in pipe */ dup2(fromProg[1], 1); /* Make stdout the out pipe */ close(toProg[0]); close(fromProg[1]); chdir(dir); execvp(argv[0], argv); rpmError(RPMERR_EXEC, "Couldn't exec %s", argv[0]); _exit(RPMERR_EXEC); } if (progPID < 0) { rpmError(RPMERR_FORK, "Couldn't fork %s", argv[0]); return NULL; } close(toProg[0]); close(fromProg[1]); /* Do not block reading or writing from/to prog. */ fcntl(fromProg[0], F_SETFL, O_NONBLOCK); fcntl(toProg[1], F_SETFL, O_NONBLOCK); readBuff = newStringBuf(); progDead = 0; do { if (waitpid(progPID, &status, WNOHANG)) { progDead = 1; } /* Write some stuff to the process if possible */ if (writeBytesLeft) { if ((bytesWritten = write(toProg[1], writePtr, (1024 0) { buf[bytes] = '\0'; appendStringBuf(readBuff, buf); bytes = read(fromProg[0], buf, sizeof(buf)-1); } /* terminate when prog dies */ } while (!progDead); close(toProg[1]); close(fromProg[0]); signal(SIGPIPE, oldhandler); if (writeBytesLeft) { rpmError(RPMERR_EXEC, "failed to write all data to %s", argv[0]); return NULL; } waitpid(progPID, &status, 0); if (failNonZero && (!WIFEXITED(status) || WEXITSTATUS(status))) { rpmError(RPMERR_EXEC, "%s failed", argv[0]); return NULL; } return readBuff; } int generateAutoReqProv(Header header, struct PackageRec *p) { char **f, **fsave, *s; int count; int_16 *modes; StringBuf writeBuff; StringBuf readBuff; char *writePtr; int writeBytes; char dir[1024]; char *argv[8]; rpmMessage(RPMMESS_VERBOSE, "Finding dependencies...\n"); /*** Get root directory ***/ if (rpmGetVar(RPMVAR_ROOT)) { strcpy(dir, rpmGetVar(RPMVAR_ROOT)); } else { strcpy(dir, "/"); } /*** Generate File List ***/ if (!headerGetEntry(header, RPMTAG_FILENAMES, NULL, (void **) &f, &count)) { return 0; } if (!count) { return 0; } fsave = f; headerGetEntry(header, RPMTAG_FILEMODES, NULL, (void **) &modes, NULL); writeBuff = newStringBuf(); writeBytes = 0; while (count--) { s = *f++; /* We skip the leading "/" (already normalized) */ writeBytes += strlen(s); appendLineStringBuf(writeBuff, s + 1); } if (fsave) { free(fsave); } writePtr = getStringBuf(writeBuff); /*** Do Provides ***/ argv[0] = "find-provides"; argv[1] = NULL; readBuff = getOutputFrom(dir, argv, writePtr, writeBytes, 1); if (!readBuff) { rpmError(RPMERR_EXEC, "Failed to find provides"); exit(1); } s = getStringBuf(readBuff); f = fsave = splitString(s, strlen(s), '\n'); freeStringBuf(readBuff); while (*f) { if (**f) { addReqProv(p, RPMSENSE_PROVIDES, *f, NULL); } f++; } free(fsave); /*** Do Requires ***/ argv[0] = "find-requires"; argv[1] = NULL; readBuff = getOutputFrom(dir, argv, writePtr, writeBytes, 0); if (!readBuff) { rpmError(RPMERR_EXEC, "Failed to find requires"); exit(1); } s = getStringBuf(readBuff); f = fsave = splitString(s, strlen(s), '\n'); freeStringBuf(readBuff); while (*f) { if (**f) { addReqProv(p, RPMSENSE_ANY, *f, NULL); } f++; } free(fsave); /*** Clean Up ***/ freeStringBuf(writeBuff); return 0; } /*************************************************************/ /* */ /* Generate and add header entry from package record */ /* */ /*************************************************************/ int processReqProv(Header h, struct PackageRec *p) { struct ReqProv *rd; char **nameArray, **namePtr; char **versionArray, **versionPtr; int_32 *flagArray, *flagPtr; int x; if (p->numProv) { rd = p->reqprov; nameArray = namePtr = malloc(p->numProv * sizeof(*nameArray)); rpmMessage(RPMMESS_VERBOSE, "Provides (%d):", p->numProv); while (rd) { if (rd->flags & RPMSENSE_PROVIDES) { rpmMessage(RPMMESS_VERBOSE, " %s", rd->name); *namePtr++ = rd->name; } rd = rd->next; } rpmMessage(RPMMESS_VERBOSE, "\n"); headerAddEntry(h, RPMTAG_PROVIDES, RPM_STRING_ARRAY_TYPE, nameArray, p->numProv); free(nameArray); } if (p->numObsoletes) { rd = p->reqprov; nameArray = namePtr = malloc(p->numProv * sizeof(*nameArray)); rpmMessage(RPMMESS_VERBOSE, "Obsoletes (%d):", p->numObsoletes); while (rd) { if (rd->flags & RPMSENSE_OBSOLETES) { rpmMessage(RPMMESS_VERBOSE, " %s", rd->name); *namePtr++ = rd->name; } rd = rd->next; } rpmMessage(RPMMESS_VERBOSE, "\n"); headerAddEntry(h, RPMTAG_OBSOLETES, RPM_STRING_ARRAY_TYPE, nameArray, p->numObsoletes); free(nameArray); } if (p->numConflict) { rd = p->reqprov; nameArray = namePtr = malloc(p->numConflict * sizeof(*nameArray)); versionArray = versionPtr = malloc(p->numConflict * sizeof(*versionArray)); flagArray = flagPtr = malloc(p->numConflict * sizeof(*flagArray)); rpmMessage(RPMMESS_VERBOSE, "Conflicts (%d):", p->numConflict); while (rd) { if (rd->flags & RPMSENSE_CONFLICTS) { rpmMessage(RPMMESS_VERBOSE, " %s", rd->name); *namePtr++ = rd->name; *versionPtr++ = rd->version ? rd->version : ""; *flagPtr++ = rd->flags & RPMSENSE_SENSEMASK; } rd = rd->next; } rpmMessage(RPMMESS_VERBOSE, "\n"); headerAddEntry(h, RPMTAG_CONFLICTNAME, RPM_STRING_ARRAY_TYPE, nameArray, p->numConflict); headerAddEntry(h, RPMTAG_CONFLICTVERSION, RPM_STRING_ARRAY_TYPE, versionArray, p->numConflict); headerAddEntry(h, RPMTAG_CONFLICTFLAGS, RPM_INT32_TYPE, flagArray, p->numConflict); free(nameArray); free(versionArray); free(flagArray); } x = p->numReq + p->numPreReq; if (x) { rd = p->reqprov; nameArray = namePtr = malloc(x * sizeof(*nameArray)); versionArray = versionPtr = malloc(x * sizeof(*versionArray)); flagArray = flagPtr = malloc(x * sizeof(*flagArray)); rpmMessage(RPMMESS_VERBOSE, "[Pre]Requires (%d):", x); while (rd) { if (! ((rd->flags & RPMSENSE_PROVIDES) || (rd->flags & RPMSENSE_OBSOLETES) || (rd->flags & RPMSENSE_CONFLICTS))) { if (rd->flags & RPMSENSE_PREREQ) { rpmMessage(RPMMESS_VERBOSE, " [%s]", rd->name); } else { rpmMessage(RPMMESS_VERBOSE, " %s", rd->name); } *namePtr++ = rd->name; *versionPtr++ = rd->version ? rd->version : ""; *flagPtr++ = (rd->flags & RPMSENSE_SENSEMASK) | (rd->flags & RPMSENSE_PREREQ); } rd = rd->next; } rpmMessage(RPMMESS_VERBOSE, "\n"); headerAddEntry(h, RPMTAG_REQUIRENAME, RPM_STRING_ARRAY_TYPE, nameArray, x); headerAddEntry(h, RPMTAG_REQUIREVERSION, RPM_STRING_ARRAY_TYPE, versionArray, x); headerAddEntry(h, RPMTAG_REQUIREFLAGS, RPM_INT32_TYPE, flagArray, x); free(nameArray); free(versionArray); free(flagArray); } return 0; }