/* * rpmopen.c : open an extract informations from RPM files. * * See Copyright for the status of this software. * * $Id: rpmopen.c,v 1.86 2000/11/06 10:51:40 veillard Exp $ */ #include #include #include #ifdef HAVE_FCNTL_H #include #endif #include #include #include #ifdef HAVE_UNISTD_H #include #endif #include #include #include #include #include /* Added by A. Gibert */ //#include - not included in rpm-devel package // XXX hack - I hope that readLead IS in librpm.o even when .h is missing int readLead(FD_t fd, /*@out@*/struct rpmlead *lead); //#include - not included in rpm-devel package // XXX hack - I hope that int rpmReadSignature IS in librpm.o even when .h is missing int rpmReadSignature(FD_t fd, /*@out@*/ Header *header, short sig_type); #if defined(WITH_GPG) #include #endif #include "rpm2html.h" #include "rpmdata.h" #include "html.h" #include "rdf.h" #include "language.h" #ifdef WITH_SQL #include "sql.h" #endif #ifndef HAVE_SNPRINTF #error You really need snprintf ... #endif /* * Get the internal number associated with an RPM tag. */ static int getTagNumber(char *tag) { int i; const struct headerTagTableEntry * t; for (i = 0, t = rpmTagTable; i < rpmTagTableSize; i++, t++) { if (!strcasecmp(tag, t->name)) return(t->val); } fprintf(stderr, "getTagNumber(%s) : unknown tag !\n", tag); return(-1); } /* * Free up the extra data not needed for the last stage processing. */ void rpmFreeExtraData(rpmDataPtr rpm) { rpmExtraDataPtr extra; int n1; if ((rpm == NULL) || (rpm->extra == NULL)) return; extra = rpm->extra; if (extra->packager != NULL) debugFree(extra->packager); if (extra->description != NULL) debugFree(extra->description); if (extra->copyright != NULL) debugFree(extra->copyright); if (extra->changelog != NULL) debugFree(extra->changelog); if (extra->srcrpm != NULL) debugFree(extra->srcrpm); if (extra->host != NULL) debugFree(extra->host); if (extra->resources != NULL) debugFree(extra->resources); if (extra->requires != NULL) debugFree(extra->requires); if (extra->filelist != NULL) debugFree(extra->filelist); if (extra->sigs != NULL) { for (n1 = 0; n1 < extra->nb_sigs; n1++) if (extra->sigs[n1] != NULL) { if (extra->sigs[n1]->sig != NULL) debugFree(extra->sigs[n1]->sig); #if defined(WITH_GPG) if (extra->sigs[n1]->resolve != NULL) debugFree(extra->sigs[n1]->resolve); #endif debugFree(extra->sigs[n1]); } debugFree(extra->sigs); } debugFree(extra); } /* * check a dependancy name to get rid of bad deps due to bad scripts * or spec files. */ int checkResourceName(const char *res) { int isname = 0; const char *base = res; if (*res == 0) return(0); /* * we only accept absolute pathnames. */ if (*res == '/') isname = 1; while (*res != 0) { if (((*res >= 'A') && (*res <= 'Z')) || ((*res >= 'a') && (*res <= 'z')) || ((*res >= '0') && (*res <= '9')) || (*res == '-') || (*res == '.') || (*res == '@') || (*res == '_') || (*res == '+') || ((*res == '/') && (isname == 1))) res++; else return(0); if ((res - base) > 100) return(0); } return(1); } /* * check a release name */ int checkReleaseName(const char *res) { const char *base = res; if (*res == 0) return(0); while (*res != 0) { if (((*res >= 'A') && (*res <= 'Z')) || ((*res >= 'a') && (*res <= 'z')) || ((*res >= '0') && (*res <= '9')) || (*res == '-') || (*res == '.') || (*res == '@') || (*res == '_') || (*res == '+')) res++; else return(0); if ((res - base) > 20) return(0); } return(1); } /* * check a group name */ int checkGroupName(const char *res) { const char *base = res; /* Grrr !!! Suse packages have an empty Group name if (*res == 0) return(0); */ while (*res != 0) { if (((*res >= 'A') && (*res <= 'Z')) || ((*res >= 'a') && (*res <= 'z')) || ((*res >= '0') && (*res <= '9')) || (*res == ' ') || (*res == '.') || (*res == '+') || (*res == '/') || (*res == '-')) res++; else return(0); if ((res - base) > 60) return(0); } return(1); } /* * check a version name */ int checkVersionName(const char *res) { const char *base = res; if (*res == 0) return(0); while (*res != 0) { if (((*res >= 'A') && (*res <= 'Z')) || ((*res >= 'a') && (*res <= 'z')) || ((*res >= '0') && (*res <= '9')) || (*res == '-') || (*res == '.') || (*res == '@') || (*res == '_') || (*res == '+')) res++; else return(0); if ((res - base) > 20) return(0); } return(1); } #if defined(WITH_GPG) /* * rpmResolveGPGPSignatures : resolve GPG and PGP signatures found in package * code based on rpm-4.0-0.45 */ void rpmResolveGPGPSignature(const char *nameRpm, const char *sigtarget, const char *sigfile, rpmDataPtr rpm, int sign) { int pid, status, outpipe[2]; FILE *file; int rsize = 128, crsize; unsigned char buf[8192]; /* Now run GPG */ outpipe[0] = outpipe[1] = 0; pipe(outpipe); if (!(pid = fork())) { close(outpipe[0]); /* gpg version 0.9 sends its output to stderr. */ dup2(outpipe[1], STDERR_FILENO); execlp(GPG_PROG, GPG_PROG, "--batch", "--no-verbose", "--verify", sigfile, sigtarget, NULL); fprintf(stderr, "%s exec failed!\n", GPG_PROG); exit(1); } close(outpipe[1]); file = fdopen(outpipe[0], "r"); rpm->extra->sigs[sign]->resolve = debugMalloc(sizeof(char) * rsize); rpm->extra->sigs[sign]->resolve[0] = '\0'; while (fgets(buf, 1024, file)) { crsize = strlen(buf) + strlen(rpm->extra->sigs[sign]->resolve); if (crsize >= rsize) { rsize = crsize * 2; rpm->extra->sigs[sign]->resolve = debugRealloc(rpm->extra->sigs[sign]->resolve, sizeof(char) * rsize); if (rpm->extra->sigs[sign]->resolve == NULL) { fprintf(stderr, "cannot re-allocate %d bytes: %s\n", rsize, strerror(errno)); exit (1); } } strcat(rpm->extra->sigs[sign]->resolve, buf); } fclose(file); (void)waitpid(pid, &status, 0); } /* * rpmResolveMD5Signatures : resolve MD5 signatures found in package * code based on rpm-4.0-0.45 * for now, we are not checking whether MD5 sums are OK */ /*void rpmResolveMD5Signature(const char *nameRpm, const char *sigtarget, const char *sigfile, rpmDataPtr rpm, int sign) { }*/ /* * rpmResolveSignatures : resolve signatures found in package * code based on rpm-4.0-0.45 */ void rpmResolveSignatures(const char *path, const char *nameRpm, const char *sigtarget, rpmDataPtr rpm) { int sign = 0; if (rpm == NULL || rpm->extra->nb_sigs == 0 || sigtarget == NULL) return; for (sign = 0; sign < rpm->extra->nb_sigs; sign++) { FD_t sfd; char *sigfile = NULL; if (rpm->extra->sigs[sign]->tag != RPMSIGTAG_PGP && rpm->extra->sigs[sign]->tag != RPMSIGTAG_GPG) continue; /* Write out the signature */ sigfile = debugMalloc(30); strcpy(sigfile, "/tmp/rpm2html.sig.XXXXXX"); sigfile = mktemp(sigfile); sfd = Fopen(sigfile, "w.fdio"); (void)Fwrite(rpm->extra->sigs[sign]->sig, sizeof(char), rpm->extra->sigs[sign]->size, sfd); Fclose(sfd); switch(rpm->extra->sigs[sign]->tag) { case RPMSIGTAG_PGP: case RPMSIGTAG_GPG: rpmResolveGPGPSignature(nameRpm, sigtarget, sigfile, rpm, sign); break; /*case RPMSIGTAG_MD5: rpmResolveMD5Signature(nameRpm, sigtarget, sigfile, rpm, sign); break;*/ default: break; } if (sigfile != NULL) { unlink(sigfile); debugFree(sigfile); } } } #endif /* * rpmAnalyze : analyze an RPM record, read and parse the header and * fill the informations in the database. */ #define ENTRY_CLEANUP(p) \ if ((type == RPM_STRING_ARRAY_TYPE || type == RPM_I18NSTRING_TYPE)&&\ (p != NULL)) { free((p)); p = NULL; } static char *buffer = NULL; static int buffer_size = 50 * 1024 * sizeof(char); rpmDataPtr rpmAnalyze(char *path, char *nameRpm, const char *sigtarget, Header h, Header s, rpmDirPtr dir, rpmSubdirPtr tree, time_t stamp, int isSource) { int installed = dir->installbase; char * name = NULL, * version = NULL, * release = NULL; int_32 count, type; void * p = NULL; int val, i, j; rpmDataPtr rpm = NULL; static char nameBuffer[500]; #ifdef WITH_SQL int id; #endif HeaderIterator sIter; if (buffer == NULL) { buffer = (char *) debugMalloc(buffer_size); if (buffer == NULL) { fprintf(stderr, "cannot allocate %d bytes: %s\n", buffer_size, strerror(errno)); exit(1); } } /* extract informations from the header */ headerGetEntry(h, RPMTAG_NAME, &type, (void **) &name, &count); if (name == NULL) { fprintf(stderr, "Invalid package %s : no name\n", nameRpm); return(NULL); } if (!(((name[0] >= 'a') && (name[0] <= 'z')) || ((name[0] >= 'A') && (name[0] <= 'Z')) || ((name[0] >= '0') && (name[0] <= '9')))) { fprintf(stderr, "Invalid package %s : garbled name\n", nameRpm); ENTRY_CLEANUP(name) return(NULL); } if (!checkResourceName(name)) { fprintf(stderr, "Invalid package %s : garbled name\n", nameRpm); ENTRY_CLEANUP(name) return(NULL); } headerGetEntry(h, RPMTAG_VERSION, &type, (void **) &version, &count); if ((version == NULL) || (version[0] == 0)) { fprintf(stderr, "Invalid package %s : version invalid\n", nameRpm); ENTRY_CLEANUP(name) ENTRY_CLEANUP(version) return(NULL); } if (!checkVersionName(version)) { fprintf(stderr, "Invalid package %s : garbled version\n", nameRpm); ENTRY_CLEANUP(name) ENTRY_CLEANUP(version) return(NULL); } headerGetEntry(h, RPMTAG_RELEASE, &type, (void **) &release, &count); if ((release == NULL) || (release[0] == 0)) { fprintf(stderr, "Invalid package %s : release invalid\n", nameRpm); ENTRY_CLEANUP(name) ENTRY_CLEANUP(version) ENTRY_CLEANUP(release) return(NULL); } if (!checkReleaseName(release)) { fprintf(stderr, "Invalid package %s : garbled release\n", nameRpm); ENTRY_CLEANUP(name) ENTRY_CLEANUP(version) ENTRY_CLEANUP(release) return(NULL); } /* allocate a new rpmData block, and an rpmExtraData block fill them */ rpm = (rpmDataPtr) debugMalloc(sizeof(rpmData)); if (rpm == NULL) { fprintf(stderr, "cannot allocate %d bytes: %s\n", sizeof(rpmData), strerror(errno)); return(NULL); } memset(rpm, 0, sizeof(rpmData)); rpm->extra = (rpmExtraDataPtr) debugMalloc(sizeof(rpmExtraData)); if (rpm == NULL) { fprintf(stderr, "cannot allocate %d bytes: %s\n", sizeof(rpmExtraData), strerror(errno)); return(NULL); } memset(rpm->extra, 0, sizeof(rpmExtraData)); rpm->dir = dir; if (tree) { if ((tree->rpmpath != NULL) && (tree->rpmpath[0] != '\0')) rpm->subdir = stringAdd(tree->rpmpath); else rpm->subdir = NULL; } else rpm->subdir = NULL; rpm->extra->stamp = stamp; rpm->name = stringAdd(name); ENTRY_CLEANUP(name) rpm->version = stringAdd(version); ENTRY_CLEANUP(version) rpm->release = stringAdd(release); ENTRY_CLEANUP(release) /* get all the resources provided by this RPM */ if (!headerGetEntry(h, RPMTAG_SUMMARY, &type, &p, &count) || !p) { rpm->summary = debugStrdup(localizedStrings[LANG_NO_SUMMARY]); } else { rpm->summary = debugStrdup((char *) p); } ENTRY_CLEANUP(p); if (!headerGetEntry(h, RPMTAG_DESCRIPTION, &type, &p, &count) || !p || (type != RPM_STRING_TYPE)) { rpm->extra->description = debugStrdup(localizedStrings[LANG_NO_DESCRIPTION]); } else { rpm->extra->description = debugStrdup((char *) p); } ENTRY_CLEANUP(p); if (!headerGetEntry(h, RPMTAG_DISTRIBUTION, &type, &p, &count) || !p || (type != RPM_STRING_TYPE)) { rpm->distribution = stringAdd(localizedStrings[LANG_UNKNOWN]); } else { rpm->distribution = stringAdd((char *) p); } ENTRY_CLEANUP(p); if (isSource) { rpm->arch = stringAdd("src"); if (nameRpm == NULL) { snprintf(nameBuffer, sizeof(nameBuffer), "%s-%s-%s.src.rpm", name, version, release); nameRpm = nameBuffer; } } else { if (!headerGetEntry(h, RPMTAG_ARCH, &type, &p, &count) || !p || (type != RPM_STRING_TYPE)) { if (type == RPM_INT8_TYPE) { /* * Old packages. */ switch (*((char *) p)) { case 1: rpm->arch = stringAdd("i386"); break; default: rpm->arch = stringAdd("src"); break; } } else rpm->arch = stringAdd(localizedStrings[LANG_NONE]); if (nameRpm == NULL) { snprintf(nameBuffer, sizeof(nameBuffer), "%s-%s-%s.rpm", name, version, release); nameRpm = nameBuffer; } } else { rpm->arch = stringAdd((char *) p); if (nameRpm == NULL) { snprintf(nameBuffer, sizeof(nameBuffer), "%s-%s-%s.%s.rpm", name, version, release, (char *)p); nameRpm = nameBuffer; } } ENTRY_CLEANUP(p); } if (!headerGetEntry(h, RPMTAG_OS, &type, &p, &count) || !p || (type != RPM_STRING_TYPE)) { if (type == RPM_INT8_TYPE) { /* * Old packages. */ switch (*((char *) p)) { case 1: rpm->os = stringAdd("linux"); break; default: rpm->os = stringAdd("linux"); break; } } else rpm->os = stringAdd(""); } else { rpm->os = stringAdd((char *) p); } ENTRY_CLEANUP(p); if (!headerGetEntry(h, RPMTAG_VENDOR, &type, &p, &count) || !p || (type != RPM_STRING_TYPE)) { rpm->vendor = NULL; } else { rpm->vendor = stringAdd((char *) p); } ENTRY_CLEANUP(p); if (!headerGetEntry(h, RPMTAG_GROUP, &type, &p, &count) || !p || (type != RPM_STRING_TYPE)) { rpm->group = stringAdd(localizedStrings[LANG_NO_GROUP]); } else { rpm->group = stringAdd((char *) p); } ENTRY_CLEANUP(p); if (!checkGroupName(rpm->group)) { fprintf(stderr, "Invalid package %s : garbled group\n", nameRpm); if (rpm->name) stringFree(rpm->name); if (rpm->version) stringFree(rpm->version); if (rpm->release) stringFree(rpm->release); if (rpm->summary) debugFree(rpm->summary); if (rpm->distribution) stringFree(rpm->distribution); if (rpm->arch) stringFree(rpm->arch); if (rpm->os) stringFree(rpm->os); if (rpm->vendor != NULL) stringFree(rpm->vendor); if (rpm->group != NULL) stringFree(rpm->group); debugFree(rpm); return(NULL); } if (!headerGetEntry(h, RPMTAG_BUILDHOST, &type, &p, &count) || !p || (type != RPM_STRING_TYPE)) { rpm->extra->host = debugStrdup(localizedStrings[LANG_NO_HOST]); } else { rpm->extra->host = debugStrdup((char *) p); } ENTRY_CLEANUP(p); if (!headerGetEntry(h, RPMTAG_SIZE, &type, &p, &count) || !p) { rpm->size = 0; } else { rpm->size = *((int *) p); } ENTRY_CLEANUP(p); if (installed) { if (!headerGetEntry(h, RPMTAG_INSTALLTIME, &type, &p, &count) || !p) { rpm->date = 0; } else { rpm->date = *((int_32 *) p); } ENTRY_CLEANUP(p); } else { if (!headerGetEntry(h, RPMTAG_BUILDTIME, &type, &p, &count) || !p) { rpm->date = 0; } else { rpm->date = *((int_32 *) p); } ENTRY_CLEANUP(p); } if (!headerGetEntry(h, RPMTAG_SOURCERPM, &type, &p, &count) || !p || (type != RPM_STRING_TYPE)) { rpm->extra->srcrpm = debugStrdup(""); } else { rpm->extra->srcrpm = debugStrdup((char *) p); } ENTRY_CLEANUP(p); if (!headerGetEntry(h, RPMTAG_URL, &type, &p, &count) || !p || (type != RPM_STRING_TYPE)) { rpm->url = NULL; } else { rpm->url = debugStrdup((char *) p); } ENTRY_CLEANUP(p); if (!headerGetEntry(h, RPMTAG_PACKAGER, &type, &p, &count) || !p || (type != RPM_STRING_TYPE)) { rpm->extra->packager = NULL; } else { rpm->extra->packager = debugStrdup((char *) p); } ENTRY_CLEANUP(p); if (!headerGetEntry(h, RPMTAG_COPYRIGHT, &type, &p, &count) || !p || (type != RPM_STRING_TYPE)) { rpm->extra->copyright = NULL; } else { rpm->extra->copyright = debugStrdup((char *) p); } ENTRY_CLEANUP(p); /* Pick up changelog entries */ if (!headerGetEntry(h, RPMTAG_CHANGELOGTEXT, &type, &p, &count) || !p) { rpm->extra->changelog = NULL; } else { time_t *dates; char **names; char **holdp = (char **)p; char *cp; struct tm *tm_buf; int i, len, pos; char date_string[50]; char *res = buffer; *res = '\0'; headerGetEntry(h, RPMTAG_CHANGELOGTIME, &type, (void *)&dates, &count); headerGetEntry(h, RPMTAG_CHANGELOGNAME, &type, (void *)&names, &count); for (i = 0; i < count; i++) { if ((res - buffer) > (buffer_size - 1024)) { int delta = res - buffer; buffer_size *= 2; buffer = (char *) debugRealloc(buffer, buffer_size); if (buffer == NULL) { fprintf(stderr, "cannot re-allocate %d bytes: %s\n", buffer_size, strerror(errno)); exit(1); } res = &buffer[delta]; } tm_buf = localtime(&dates[i]); strftime(date_string, sizeof(date_string) - 1, "%a %b %d %Y", tm_buf); len = snprintf(res, buffer_size, "* %s %s\n", date_string, names[i]); res += len; cp = holdp[i]; pos = 0; while (*cp) { if (pos++ == 0) { *res++ = ' '; *res++ = ' '; } *res++ = *cp; if (*cp++ == '\n') pos = 0; } *res++ = '\n'; } *res = '\0'; rpm->extra->changelog = debugStrdup(buffer); } ENTRY_CLEANUP(p); if (rpm->vendor == NULL) { if (rpm->extra->packager != NULL) rpm->vendor = debugStrdup(rpm->extra->packager); else rpm->vendor = debugStrdup(localizedStrings[LANG_UNKNOWN]); } if (s == NULL) rpm->extra->sigs = NULL; else { int tag, type; rpm->extra->max_sigs = 1; rpm->extra->sigs = (rpmSigPtr *) debugMalloc(sizeof(rpmSigPtr) * rpm->extra->max_sigs); rpm->extra->sigs[0] = NULL; rpm->extra->nb_sigs = 0; for (sIter = headerInitIterator(s); headerNextIterator(sIter, &tag, &type, &p, &count); ) { if ((tag != RPMSIGTAG_MD5) && (tag != RPMSIGTAG_PGP) && (tag != RPMSIGTAG_GPG)) continue; if (rpm->extra->nb_sigs >= rpm->extra->max_sigs) { rpm->extra->max_sigs *= 2; rpm->extra->sigs = (rpmSigPtr *) debugRealloc(rpm->extra->sigs, sizeof(rpmSigPtr) * rpm->extra->max_sigs); if (rpm->extra->sigs == NULL) { fprintf(stderr, "cannot re-allocate %d bytes: %s\n", rpm->extra->max_sigs, strerror(errno)); exit(1); } } rpm->extra->sigs[rpm->extra->nb_sigs] = (rpmSigPtr) debugMalloc(sizeof(rpmSig)); rpm->extra->sigs[rpm->extra->nb_sigs]->tag = tag; rpm->extra->sigs[rpm->extra->nb_sigs]->type = type; rpm->extra->sigs[rpm->extra->nb_sigs]->size = count; rpm->extra->sigs[rpm->extra->nb_sigs]->sig = debugMalloc(count); memcpy(rpm->extra->sigs[rpm->extra->nb_sigs]->sig, p, count); #if defined(WITH_GPG) rpm->extra->sigs[rpm->extra->nb_sigs]->resolve = NULL; #endif rpm->extra->nb_sigs++; ENTRY_CLEANUP(p); } } rpm->filename = debugStrdup(nameRpm); /* package-xxx.rpm provides at least the resource "package" */ val = getTagNumber("RPMTAG_PROVIDES"); if (!headerGetEntry(h, val, &type, &p, &count) || !p) { rpm->extra->nb_resources = 1; rpm->extra->max_resources = 1; rpm->extra->resources = (rpmRessPtr *) debugMalloc(sizeof(rpmRessPtr) * rpm->extra->max_resources); if (rpm->extra->resources == NULL) { fprintf(stderr, ": ran out of memory\n"); exit(1); } rpm->extra->resources[0] = rpmRessAdd(name, rpm, installed); } else { rpm->extra->max_resources = count + 1; rpm->extra->resources = (rpmRessPtr *) debugMalloc(sizeof(rpmRessPtr) * rpm->extra->max_resources); if (rpm->extra->resources == NULL) { fprintf(stderr, ": ran out of memory\n"); exit(1); } rpm->extra->resources[0] = rpmRessAdd(name, rpm, installed); rpm->extra->nb_resources = 1; for (i = 0, j = rpm->extra->nb_resources; i < count;i++) { if (!checkResourceName(((char **) p)[i])) continue; rpm->extra->resources[j++] = rpmRessAdd(((char **) p)[i], rpm, installed); } rpm->extra->nb_resources = j; } ENTRY_CLEANUP(p); val = getTagNumber("RPMTAG_REQUIRENAME"); if (!headerGetEntry(h, val, &type, &p, &count) || !p) { rpm->extra->nb_requires = 0; rpm->extra->requires = NULL; } else { int_32 count2, count3, type2, type3; void * q = NULL; void * r = NULL; int valv, valf; rpm->extra->max_requires = count; rpm->extra->requires = (rpmRessPtr *) debugMalloc(sizeof(rpmRessPtr) * rpm->extra->max_requires); if (rpm->extra->requires == NULL) { fprintf(stderr, ": ran out of memory\n"); exit(1); } valv = getTagNumber("RPMTAG_REQUIREVERSION"); valf = getTagNumber("RPMTAG_REQUIREFLAGS"); headerGetEntry(h, valv, &type2, &q, &count2); headerGetEntry(h, valf, &type3, &r, &count3); rpm->extra->nb_requires = 0; for (i = 0, j = 0; (i < count2) && (i < count3);i++) { long anint = *(((long *)r)+i); rpm_dep_flag flag = RPM2HTML_REQ_NONE; if ((anint & RPMSENSE_LESS) && (anint & RPMSENSE_EQUAL)) flag = RPM2HTML_REQ_LEQ; else if (anint & RPMSENSE_LESS) flag = RPM2HTML_REQ_LT; if ((anint & RPMSENSE_GREATER) && (anint & RPMSENSE_EQUAL)) flag = RPM2HTML_REQ_GEQ; else if (anint & RPMSENSE_GREATER) flag = RPM2HTML_REQ_GT; else if (anint & RPMSENSE_EQUAL) flag = RPM2HTML_REQ_EQU; if (!checkResourceName(((char **) p)[i])) continue; rpm->extra->requires[j++] = rpmRequAdd(((char **) p)[i],((char **) q)[i], flag , rpm, installed); } rpm->extra->nb_requires = j; if ((type2 == RPM_STRING_ARRAY_TYPE || type2 == RPM_I18NSTRING_TYPE)&& (q != NULL)) { free((q)); q = NULL; } if ((type3 == RPM_STRING_ARRAY_TYPE || type3 == RPM_I18NSTRING_TYPE)&& (r != NULL)) { free((r)); r = NULL; } for (;i < count;i++) rpmRequAdd(((char **) p)[i], NULL, RPM2HTML_REQ_NONE, rpm, installed); } ENTRY_CLEANUP(p); #if defined(RPMTAG_FILENAMES) val = getTagNumber("RPMTAG_FILENAMES"); headerGetEntry(h, val, &type, &p, &count); #else rpmBuildFileList(h, (const char ***) &p, &count); #endif if (count == 0) { rpm->extra->filelist = NULL; /* No filelist in the package ! */ } else { char *ptr = buffer; for (i = 0; i < count;i++) { if ((ptr - buffer) > (buffer_size - 1024)) { int delta = ptr - buffer; buffer_size *= 2; buffer = (char *) debugRealloc(buffer, buffer_size); if (buffer == NULL) { fprintf(stderr, "cannot re-allocate %d bytes: %s\n", buffer_size, strerror(errno)); exit(1); } ptr = &buffer[delta]; } ptr += snprintf(ptr, buffer_size, "%s\n", ((char **) p)[i]); } rpm->extra->filelist = debugStrdup(buffer); } ENTRY_CLEANUP(p); #ifdef WITH_GPG rpmResolveSignatures(path, nameRpm, sigtarget, rpm); #endif WITH_GPG #ifdef WITH_SQL id = sql_add_package(path, rpm->name, rpm->version, rpm->release, rpm->arch, dir->no, rpm->url, rpm->extra->srcrpm, dir->vendor, rpm->extra->packager, rpm->group, rpm->summary, rpm->extra->description, rpm->extra->copyright, rpm->date); if (id > 0) { for (i = 0;i < rpm->extra->nb_resources;i++) sql_add_provides(id, rpm->extra->resources[i]->name); for (i = 0;i < rpm->extra->nb_requires;i++) sql_add_requires(id, rpm->extra->requires[i]->name, rpm->extra->requires[i]->flag, rpm->extra->requires[i]->version); } #endif /* Add the package files to the real filesystem tree if asked for */ #ifdef WITH_SQL if ((rpm->extra->filelist != NULL) && ((dir->build_tree != 0) || (id > 0))) { #else if ((dir->build_tree != 0) && (rpm->extra->filelist != NULL)) { #endif char *cur, *filename; cur = rpm->extra->filelist; while ((*cur != '\0') && (*cur != '/')) cur++; filename = cur; while (*cur != '\0') { if ((*cur == '\n') || (*cur == '\r')) { if (cur != filename) { #ifdef WITH_SQL if (dir->build_tree != 0) rpmAddRealFile(dir->root, filename, rpm); if (id > 0) { *cur = 0; sql_add_file(filename,id); *cur = '\n'; } #else rpmAddRealFile(dir->root, filename, rpm); #endif } while ((*cur != '\0') && (*cur != '/')) cur++; filename = cur; } else cur++; } if (cur != filename) rpmAddRealFile(dir->root, filename, rpm); } /* Register this package */ rpmAddSoftware(rpm); /* dump the HTML related to this package */ if ((rpm2html_dump_html) && (dir->html)) dumpRpmHtml(rpm, tree); if (rpm2html_dump_rdf) dumpRpmRdf(rpm, tree); /* free the extra data */ rpmFreeExtraData(rpm); /* increment the counters */ if (installed) { rpm2html_install_files++; rpm2html_install_size += rpm->size / 1024; } else { rpm2html_files++; rpm2html_size += rpm->size / 1024; } return(rpm); } /* * rpmOpen : open an RPM file, read and parse the header and * fill the informations in the database. */ rpmDataPtr rpmOpen(char *nameRpm, rpmDirPtr dir, rpmSubdirPtr tree) { rpmDataPtr cur; #if defined(HAVE_RPM_RPMIO_H) FD_t fd; #else int fd; #define fdOpen(_a, _b, _c) open((_a), (_b)) #define fdClose(_a) close(_a) #endif int rc; Header h = NULL; Header s = NULL; struct rpmlead lead; int isSource; char buffer[500]; struct stat buf; #if defined(WITH_GPG) FD_t ofd = NULL; char *sigtarget = NULL; ssize_t count; unsigned char stbuffer[8192]; #endif /* open the file for reading */ if (tree->htmlpath[0] != '\0') snprintf(buffer, sizeof(buffer), "%s/%s/%s", dir->rpmdir, tree->rpmpath, nameRpm); else snprintf(buffer, sizeof(buffer), "%s/%s", dir->rpmdir, nameRpm); if (access(buffer, R_OK) < 0) { fprintf(stderr, "open of %s failed: %s\n", buffer, strerror(errno)); return(NULL); } #if defined(USE_RPMIO) fd = Fopen(buffer, "r.fdio"); if (fd == NULL || Ferror(fd)) { fprintf(stderr, "Fopen of %s failed: %s\n", buffer, Fstrerror(fd)); return(NULL); } #else if ((fd = fdOpen(buffer, O_RDONLY, 0)) < 0) { fprintf(stderr, "open of %s failed: %s\n", buffer, strerror(errno)); return(NULL); } #endif stat(buffer, &buf); /* read the RPM header */ rc = rpmReadPackageHeader(fd, &h, &isSource, NULL, NULL); switch (rc) { case 0: if (!h) { fprintf(stderr, "old format source packages cannot be queried\n"); fdClose(fd); return(NULL); } break; case 1: fprintf(stderr, "%s does not appear to be a RPM package\n", nameRpm); fdClose(fd); return(NULL); case 2: fprintf(stderr, "query of %s failed\n", nameRpm); fdClose(fd); return(NULL); default: fprintf(stderr, "rpmReadPackageHeader(%s): unknown error %d\n", nameRpm, rc); fdClose(fd); return(NULL); } /* close the descriptor */ #if defined(USE_RPMIO) Fclose(fd); #else fdClose(fd); #endif /* XXX I do not know whether it is necessary to open the file twice */ /* open the file for reading */ #if defined(USE_RPMIO) fd = Fopen(buffer, "r.fdio"); if (fd == NULL || Ferror(fd)) { fprintf(stderr, "Fopen of %s failed: %s\n", buffer, Fstrerror(fd)); return(NULL); } #else if ((fd = fdOpen(buffer, O_RDONLY, 0)) < 0) { fprintf(stderr, "open of %s failed: %s\n", buffer, strerror(errno)); return(NULL); } #endif /* read the RPM signature */ if (readLead(fd, &lead)) { fprintf(stderr, "readLead failed\n"); fdClose(fd); return(NULL); } switch (lead.major) { case 1: fprintf(stderr, "no signature available (v1.0 RPM) in %s\n", nameRpm); break; default: if (rpmReadSignature(fd, &s, lead.signature_type)) { fprintf(stderr, "rpmReadSignature failed\n"); fdClose(fd); return(NULL); } if (!s) { fprintf(stderr, "no signature available in %s\n", nameRpm); fdClose(fd); return(NULL); } #if defined(WITH_GPG) /* open temp file for writing */ sigtarget = debugMalloc(30); strcpy(sigtarget, "/tmp/rpm2html.date.XXXXXX"); sigtarget = mktemp(sigtarget); ofd = Fopen(sigtarget, "w.ufdio"); if (ofd == NULL || Ferror(ofd)) { fprintf(stderr, "Fopen of %s failed: %s\n", sigtarget, Fstrerror(ofd)); debugFree(sigtarget); sigtarget = NULL; } /* write the header and archive to a temp file */ while ((count = Fread(stbuffer, sizeof(stbuffer[0]), sizeof(stbuffer), fd)) > 0) { if (Fwrite(stbuffer, sizeof(stbuffer[0]), count, ofd) < 0) { fprintf(stderr, "%s: Fwrite failed: %s\n", sigtarget, Fstrerror(ofd)); debugFree(sigtarget); sigtarget = NULL; } } if (count < 0) { fprintf(stderr, "%s: Fread failed: %s\n", buffer, Fstrerror(fd)); debugFree(sigtarget); sigtarget = NULL; } Fclose(ofd); #endif break; } /* close the descriptor */ #if defined(USE_RPMIO) Fclose(fd); #else fdClose(fd); #endif #if defined(WITH_GPG) cur = rpmAnalyze(buffer, nameRpm, sigtarget, h, s, dir, tree, buf.st_mtime, isSource); #else cur = rpmAnalyze(buffer, nameRpm, NULL, h, s, dir, tree, buf.st_mtime, isSource); #endif /* free the header */ headerFree(h); headerFree(s); #if defined(WITH_GPG) if (sigtarget) { unlink(sigtarget); debugFree(sigtarget); } #endif return(cur); } /* * Scan one directory for RPM files this is where the recursive handling * is done. */ static rpmDataPtr rpmOneDirScan(rpmDirPtr dir, rpmSubdirPtr tree) { rpmSubdirPtr subtree; rpmDataPtr ret = NULL, cur; char *filename; static char path[2000]; struct stat buf; int len; DIR *d; struct dirent *file; /* * Create the directory for the HTML pages */ if ((rpm2html_dump_html) && (dir->html)) { if (tree->htmlpath[0] != '\0') snprintf(path, sizeof(path), "%s/%s", dir->dir, tree->htmlpath); else snprintf(path, sizeof(path), "%s", dir->dir); createDirectory(path); } /* * Create the directory for the RDF pages if (rpm2html_rdf_dir != NULL) { if (tree->htmlpath[0] != '\0') snprintf(path, sizeof(path), "%s/%s", rpm2html_rdf_dir, tree->htmlpath); else snprintf(path, sizeof(path), "%s", rpm2html_rdf_dir); createDirectory(path); } */ /* * Scan the repository. */ if (tree->rpmpath[0] != '\0') snprintf(path, sizeof(path), "%s/%s", dir->rpmdir, tree->rpmpath); else snprintf(path, sizeof(path), "%s", dir->rpmdir); if (rpm2htmlVerbose > 1) printf("Scanning directory %s\n", path); d = opendir(path); if (d == NULL) { fprintf(stderr, "Listing of %s failed: %s\n", path, strerror(errno)); rpmRemoveSubdir(tree); rpmFreeSubdir(tree); return(NULL); } else { while ((file = readdir(d)) != NULL) { cur = NULL; filename = file->d_name; len = strlen(filename); /* * Compute the full path */ if (tree->rpmpath[0] != '\0') snprintf(path, sizeof(path), "%s/%s/%s", dir->rpmdir, tree->rpmpath, filename); else snprintf(path, sizeof(path), "%s/%s", dir->rpmdir, filename); /* * Stat() the file to detect directory and symlimks */ if (lstat(path, &buf) != 0) { fprintf(stderr, "Couldn't stat(%s)\n", path); continue; } /* * Check for RPM files by looking at the suffix * Note that SuSE source RPMs have a ".spm" suffix * We may or may not follow symlinks to RPM files */ if (((len >= 5) && (!strcasecmp(&filename[len - 4], ".rpm"))) || ((len >= 5) && (!strcasecmp(&filename[len - 4], ".spm")))) { if ((S_ISLNK(buf.st_mode)) && (dir->rpm_symlinks == 0)) { if (rpm2htmlVerbose > 1) fprintf(stderr, "Dropping symlink %s\n", path); continue; } cur = rpmOpen(filename, dir, tree); } /* * Don't follow of analyze symlinks, */ else if ((S_ISLNK(buf.st_mode)) && (dir->follow_symlinks == 0)) { if (rpm2htmlVerbose > 1) fprintf(stderr, "Dropping symlink %s\n", path); continue; } /* * Check for RDF files by looking at the suffix */ else if ((len >= 5) && (!strcasecmp(&filename[len - 4], ".rdf"))) { cur = rpmOpenRdf(filename, dir, tree); } /* * Else if this is a directory, recurse ! */ else if (S_ISDIR(buf.st_mode)) { if (filename[0] != '.') { subtree = rpmNewSubdir(tree, filename, NULL, NULL, NULL, 0); cur = rpmOneDirScan(dir, subtree); } } if (cur != NULL) ret = rpmAddList(ret, cur); } } closedir(d); /* * Dump the pages related to this directory. */ if (ret != NULL) ret = dumpDirIndex(dir, tree, ret); else { rpmRemoveSubdir(tree); rpmFreeSubdir(tree); } return(ret); } /* * Scan a directory for RPM files. */ static rpmDataPtr rpmDirScan(rpmDirPtr dir, rpmSubdirPtr tree) { rpmSubdirPtr cur; rpmDataPtr ret; if ((rpm2html_dump_html) && (dir->html) && (dir->build_tree != 0)) { dir->root = rpmCreateRealRoot(); } cur = rpmNewSubdir(tree, dir->name, dir->subdir == NULL ? "" : dir->subdir, "", dir->color, dir->html); ret = rpmOneDirScan(dir, cur); rpmDumpHtmlRealRoot(dir); return(ret); } /* * Scan the local RPM database for RPM files. */ static rpmDataPtr rpmBaseScan(rpmDirPtr dir) { static char path[2000]; rpmDataPtr ret = NULL, cur; rpmdb db; Header h = NULL; #ifndef USE_RPMIO int offset; #endif char *prefix = "/"; /* * Create the directory for the HTML pages */ if ((rpm2html_dump_html) && (dir->html)) { if (dir->subdir) snprintf(path, sizeof(path), "%s/%s", dir->dir, dir->subdir); else snprintf(path, sizeof(path), "%s", dir->dir); createDirectory(path); } /* * Create the directory for the RDF pages */ if (rpm2html_rdf_dir != NULL) { if (dir->subdir) snprintf(path, sizeof(path), "%s/%s", rpm2html_rdf_dir, dir->subdir); else snprintf(path, sizeof(path), "%s", rpm2html_rdf_dir); createDirectory(path); } if (rpm2htmlVerbose) printf("Scanning the database of installed RPMs\n"); if (dir->dbpath != NULL) addMacro(NULL, "_dbpath", NULL, dir->dbpath, -7); /* Added by A.Gibert */ if (rpmdbOpen(prefix, &db, O_RDONLY, 0644)) { return(NULL); } #ifdef USE_RPMIO { rpmdbMatchIterator mi; mi = rpmdbInitIterator(db, RPMDBI_PACKAGES, NULL, 0); while ((h = rpmdbNextIterator(mi)) != NULL) { cur = rpmAnalyze(NULL, NULL, NULL, h, NULL, dir, NULL, 0, 0); if (cur != NULL) ret = rpmAddList(ret, cur); } rpmdbFreeIterator(mi); } #else /* USE_RPMIO */ offset = rpmdbFirstRecNum(db); while (offset) { h = rpmdbGetRecord(db, offset); if (!h) { fprintf(stderr, "could not read database record!\n"); return(ret); } cur = rpmAnalyze(NULL, NULL, NULL, h, NULL, dir, NULL, 0, 0); if (cur != NULL) ret = rpmAddList(ret, cur); headerFree(h); offset = rpmdbNextRecNum(db, offset); } #endif /* USE_RPMIO */ rpmdbClose(db); return(ret); } /* * Scan one distribution only */ void rpmDirScanOneDist(const char *dist) { rpmDirPtr dir; rpmDataPtr cur; /* * first try to find the distrib */ dir = dirList; while (dir != NULL) { if (!strcasecmp(dir->name, dist)) break; if (!strcasecmp(dir->subdir, dist)) break; if (!strcasecmp(dir->rpmdir, dist)) break; dir = dir->next; } if (dir == NULL) { dir = dirList; while (dir != NULL) { if (!strstr(dir->name, dist)) break; if (!strstr(dir->subdir, dist)) break; if (!strstr(dir->rpmdir, dist)) break; dir = dir->next; } } if (dir == NULL) { fprintf(stderr, "rpmDirScanOneDist(%s): distribution not found\n", dist); return; } if (rpm2htmlVerbose) printf("indexing %s\n", dir->name); /* * Allocate a directory tree. */ dirTree = rpmNewSubdir(NULL, "", "", "", NULL, 1); cur = NULL; /* * Override default setting. */ if ((dir->maint == NULL) && (rpm2html_maint != NULL)) dir->maint = debugStrdup(rpm2html_maint); if ((dir->mail == NULL) && (rpm2html_mail != NULL)) dir->mail = debugStrdup(rpm2html_mail); if ((dir->ftp == NULL) && (rpm2html_ftp != NULL)) dir->ftp = debugStrdup(rpm2html_ftp); if ((dir->ftpsrc == NULL) && (rpm2html_ftpsrc != NULL)) dir->ftpsrc = debugStrdup(rpm2html_ftpsrc); if ((dir->dir == NULL) && (rpm2html_dir != NULL)) dir->dir = debugStrdup(rpm2html_dir); if ((dir->host == NULL) && (rpm2html_host != NULL)) dir->host = debugStrdup(rpm2html_host); if ((dir->name == NULL) && (rpm2html_name != NULL)) dir->name = debugStrdup(rpm2html_name); if ((dir->url == NULL) && (rpm2html_url != NULL)) dir->url = debugStrdup(rpm2html_url); if (dir->rpmdir == NULL) { fprintf(stderr, "?!? rpmDir without directory ?!? disabled !\n"); } else if (!strncmp(dir->rpmdir, "localbase", 9)) { /* Scan the local RPM database instead of a directory */ cur = rpmBaseScan(dir); } else if (dir->ftp == NULL) { fprintf(stderr, "Directory %s disabled : no ftp field\n", dir->rpmdir); } else { #ifdef WITH_SQL dir->no = sql_get_distrib_by_directory(dir->rpmdir); #endif if (rpm2htmlVerbose) printf("Scanning directory %s for RPMs\n",dir->rpmdir); cur = rpmDirScan(dir, dirTree); } if (dir->root != NULL) { rpmDestroyRealRoot(dir->root); dir->root = NULL; } } /* * Scan all registered directories. * One fist check for completeness of the informations in * the rpmDir structure. */ rpmDataPtr rpmDirScanAll(void) { rpmDirPtr dir, next; rpmDataPtr ret = NULL, cur; int maxLists = 50; rpmDataPtr *rpmLists; int nbLists = 0; int i; /* * first reverse the list .... */ dir = dirList; dirList = NULL; while (dir != NULL) { next = dir->next; dir->next = dirList; dirList = dir; dir = next; } dir = dirList; /* * Allocate a directory tree. */ dirTree = rpmNewSubdir(NULL, "", "", "", NULL, 1); rpmLists = (rpmDataPtr *) debugMalloc(maxLists * sizeof(rpmDataPtr)); if (rpmLists == NULL) { fprintf(stderr, "rpmDirScanAll : running out of memory !\n"); exit(1); } while (dir != NULL) { cur = NULL; /* * Override default setting. */ if ((dir->maint == NULL) && (rpm2html_maint != NULL)) dir->maint = debugStrdup(rpm2html_maint); if ((dir->mail == NULL) && (rpm2html_mail != NULL)) dir->mail = debugStrdup(rpm2html_mail); if ((dir->ftp == NULL) && (rpm2html_ftp != NULL)) dir->ftp = debugStrdup(rpm2html_ftp); if ((dir->ftpsrc == NULL) && (rpm2html_ftpsrc != NULL)) dir->ftpsrc = debugStrdup(rpm2html_ftpsrc); if ((dir->dir == NULL) && (rpm2html_dir != NULL)) dir->dir = debugStrdup(rpm2html_dir); if ((dir->host == NULL) && (rpm2html_host != NULL)) dir->host = debugStrdup(rpm2html_host); if ((dir->name == NULL) && (rpm2html_name != NULL)) dir->name = debugStrdup(rpm2html_name); if ((dir->url == NULL) && (rpm2html_url != NULL)) dir->url = debugStrdup(rpm2html_url); if (dir->rpmdir == NULL) { fprintf(stderr, "?!? rpmDir without directory ?!? disabled !\n"); } else if (!strncmp(dir->rpmdir, "localbase", 9)) { /* Added by A. Gibert */ /* Scan the local RPM database instead of a directory */ cur = rpmBaseScan(dir); } else if (dir->ftp == NULL) { fprintf(stderr, "Directory %s disabled : no ftp field\n", dir->rpmdir); } else { #ifdef WITH_SQL dir->no = sql_get_distrib_by_directory(dir->rpmdir); #endif if (rpm2htmlVerbose) printf("Scanning directory %s for RPMs\n",dir->rpmdir); cur = rpmDirScan(dir, dirTree); } if (cur != NULL) { if (nbLists >= maxLists) { maxLists *= 2; rpmLists = (rpmDataPtr *) debugRealloc(rpmLists, maxLists * sizeof(rpmDataPtr)); if (rpmLists == NULL) { fprintf(stderr, "rpmDirScanAll : running out of memory!\n"); exit(1); } } rpmLists[nbLists] = cur; nbLists++; } if (dir->root != NULL) { /************************************************ if (rpm2html_build_tree) treeRoot = rpmMergeRealRoots(treeRoot, dir->root); else ************************************************/ rpmDestroyRealRoot(dir->root); dir->root = NULL; } dir = dir->next; } for (i = 0;i < nbLists;i++) ret = rpmAddList(ret, rpmLists[i]); debugFree(rpmLists); return(ret); } /* * Cleanup the global variables from this module */ void rpmopenCleanup(void) { if (buffer != NULL) debugFree(buffer); buffer = NULL; buffer_size = 50 * 1024 * sizeof(char); }