/* * rpmopen.c : open an extract informations from RPM files. * * See Copyright for the status of this software. * * $Id: rpmopen.c,v 1.51 1998/05/26 01:42:35 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 "rpmdata.h" #include "html.h" #include "rdf.h" #include "rpm2html.h" #include "language.h" /* * Get the internal number associated to 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); } /* * rpmAnalyze : analyze an RPM record, read and parse the header and * fill the informations in the database. */ rpmDataPtr rpmAnalyze(char *nameRpm, Header h, rpmDirPtr dir, rpmSubdirPtr tree, time_t stamp) { 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 *buffer = NULL; static int buffer_size = 50 * 1024 * sizeof(char); static char nameBuffer[500]; if (buffer == NULL) { buffer = (char *) malloc(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); 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); 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); return(NULL); } /* allocate a new rpmData block, fill it */ rpm = (rpmDataPtr) malloc(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->dir = dir; if (tree) { if ((tree->rpmpath != NULL) && (tree->rpmpath[0] != '\0')) rpm->subdir = strdup(tree->rpmpath); else rpm->subdir = NULL; } else rpm->subdir = NULL; rpm->stamp = stamp; rpm->name = strdup(name); rpm->version = strdup(version); rpm->release = strdup(release); /* get all the resources provided by this RPM */ if (!headerGetEntry(h, RPMTAG_SUMMARY, &type, &p, &count) || !p) { rpm->summary = strdup(localizedStrings[LANG_NO_SUMMARY]); } else { rpm->summary = strdup((char *) p); } if (!headerGetEntry(h, RPMTAG_DESCRIPTION, &type, &p, &count) || !p || (type != RPM_STRING_TYPE)) { rpm->description = strdup(localizedStrings[LANG_NO_DESCRIPTION]); } else { rpm->description = strdup((char *) p); } if (!headerGetEntry(h, RPMTAG_DISTRIBUTION, &type, &p, &count) || !p || (type != RPM_STRING_TYPE)) { rpm->distribution = strdup(localizedStrings[LANG_UNKNOWN]); } else { rpm->distribution = strdup((char *) p); } 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 = strdup("i386"); break; default: rpm->arch = strdup("i386"); break; } } else rpm->arch = strdup(localizedStrings[LANG_NONE]); if (nameRpm == NULL) { sprintf(nameBuffer, "%s-%s-%s.rpm", name, version, release); nameRpm = nameBuffer; } } else { rpm->arch = strdup((char *) p); if (nameRpm == NULL) { sprintf(nameBuffer, "%s-%s-%s.%s.rpm", name, version, release, (char *)p); nameRpm = nameBuffer; } } 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 = strdup("linux"); break; default: rpm->os = strdup("linux"); break; } } else rpm->os = strdup(""); } else { rpm->os = strdup((char *) p); } if (!headerGetEntry(h, RPMTAG_VENDOR, &type, &p, &count) || !p || (type != RPM_STRING_TYPE)) { rpm->vendor = NULL; } else { rpm->vendor = strdup((char *) p); } if (!headerGetEntry(h, RPMTAG_GROUP, &type, &p, &count) || !p || (type != RPM_STRING_TYPE)) { rpm->group = strdup(localizedStrings[LANG_NO_GROUP]); } else { rpm->group = strdup((char *) p); } if (!headerGetEntry(h, RPMTAG_BUILDHOST, &type, &p, &count) || !p || (type != RPM_STRING_TYPE)) { rpm->host = strdup(localizedStrings[LANG_NO_HOST]); } else { rpm->host = strdup((char *) p); } if (!headerGetEntry(h, RPMTAG_SIZE, &type, &p, &count) || !p) { rpm->size = 0; } else { rpm->size = *((int *) p); } if (installed) { if (!headerGetEntry(h, RPMTAG_INSTALLTIME, &type, &p, &count) || !p) { rpm->date = 0; } else { rpm->date = *((int_32 *) p); } } else { if (!headerGetEntry(h, RPMTAG_BUILDTIME, &type, &p, &count) || !p) { rpm->date = 0; } else { rpm->date = *((int_32 *) p); } } if (!headerGetEntry(h, RPMTAG_SOURCERPM, &type, &p, &count) || !p || (type != RPM_STRING_TYPE)) { rpm->srcrpm = strdup(""); } else { rpm->srcrpm = strdup((char *) p); } if (!headerGetEntry(h, RPMTAG_URL, &type, &p, &count) || !p || (type != RPM_STRING_TYPE)) { rpm->url = NULL; } else { rpm->url = strdup((char *) p); } if (!headerGetEntry(h, RPMTAG_PACKAGER, &type, &p, &count) || !p || (type != RPM_STRING_TYPE)) { rpm->packager = NULL; } else { rpm->packager = strdup((char *) p); } if (!headerGetEntry(h, RPMTAG_COPYRIGHT, &type, &p, &count) || !p || (type != RPM_STRING_TYPE)) { rpm->copyright = NULL; } else { rpm->copyright = strdup((char *) p); } /* Pick up changelog entries */ if (!headerGetEntry(h, RPMTAG_CHANGELOGTEXT, &type, &p, &count) || !p) { rpm->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 *) realloc(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 = sprintf(res, "* %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->changelog = strdup(buffer); } if (rpm->vendor == NULL) { if (rpm->packager != NULL) rpm->vendor = strdup(rpm->packager); else rpm->vendor = strdup(localizedStrings[LANG_UNKNOWN]); } rpm->filename = strdup(nameRpm); /* package-xxx.rpm provides at least the resource "package" */ val = getTagNumber("RPMTAG_PROVIDES"); if (!headerGetEntry(h, val, &type, &p, &count) || !p) { rpm->nb_resources = 1; rpm->max_resources = 1; rpm->resources = (rpmRessPtr *) malloc(sizeof(rpmRessPtr) * rpm->max_resources); if (rpm->resources == NULL) { fprintf(stderr, ": ran out of memory\n"); exit(1); } rpm->resources[0] = rpmRessAdd(name, rpm, installed); } else { rpm->max_resources = count + 1; rpm->resources = (rpmRessPtr *) malloc(sizeof(rpmRessPtr) * rpm->max_resources); if (rpm->resources == NULL) { fprintf(stderr, ": ran out of memory\n"); exit(1); } rpm->resources[0] = rpmRessAdd(name, rpm, installed); rpm->nb_resources = 1; for (i = 0, j = rpm->nb_resources; i < count;j++, i++) { rpm->resources[j] = rpmRessAdd(((char **) p)[i], rpm, installed); } rpm->nb_resources += count; } val = getTagNumber("RPMTAG_REQUIRENAME"); if (!headerGetEntry(h, val, &type, &p, &count) || !p) { rpm->nb_requires = 0; rpm->requires = NULL; } else { rpm->max_requires = count; rpm->requires = (rpmRessPtr *) malloc(sizeof(rpmRessPtr) * rpm->max_requires); if (rpm->requires == NULL) { fprintf(stderr, ": ran out of memory\n"); exit(1); } rpm->nb_requires = count; for (i = 0; i < count;i++) { rpm->requires[i] = rpmRequAdd(((char **) p)[i], rpm, installed); } } val = getTagNumber("RPMTAG_FILENAMES"); if (!headerGetEntry(h, val, &type, &p, &count) || !p) { rpm->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 *) realloc(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 += sprintf(ptr, "%s\n", ((char **) p)[i]); } rpm->filelist = strdup(buffer); } /* Add the package files to the real filesystem tree if asked for */ if ((dir->build_tree != 0) && (rpm->filelist != NULL)) { char *cur, *filename; cur = rpm->filelist; while ((*cur != '\0') && (*cur != '/')) cur++; filename = cur; while (*cur != '\0') { if ((*cur == '\n') || (*cur == '\r')) { if (cur != filename) rpmAddRealFile(dir->root, filename, rpm); 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) dumpRpmHtml(rpm, tree); if (rpm2html_dump_rdf) dumpRpmRdf(rpm, tree); /* free large amount of data not used later */ if (rpm->filelist) free(rpm->filelist); rpm->filelist = NULL; if (rpm->copyright) free(rpm->copyright); rpm->copyright = NULL; if (rpm->changelog) free(rpm->changelog); rpm->changelog = NULL; if (rpm->description) free(rpm->description); rpm->description = NULL; /* 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; int fd; int rc; Header h = NULL; int isSource; char buffer[500]; struct stat buf; /* open the file for reading */ if (tree->htmlpath[0] != '\0') sprintf(buffer, "%s/%s/%s", dir->rpmdir, tree->rpmpath, nameRpm); else sprintf(buffer, "%s/%s", dir->rpmdir, nameRpm); if ((fd = open(buffer, O_RDONLY)) < 0) { fprintf(stderr, "open of %s failed: %s\n", buffer, strerror(errno)); return(NULL); } 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"); return(NULL); } break; case 1: fprintf(stderr, "%s does not appear to be a RPM package\n", nameRpm); return(NULL); case 2: fprintf(stderr, "query of %s failed\n", nameRpm); return(NULL); default: fprintf(stderr, "rpmReadPackageHeader(%s): unknown error %d\n", nameRpm, rc); return(NULL); } cur = rpmAnalyze(nameRpm, h, dir, tree, buf.st_mtime); /* free the header and close the descriptor */ headerFree(h); close(fd); 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) { if (tree->htmlpath[0] != '\0') sprintf(path, "%s/%s", dir->dir, tree->htmlpath); else sprintf(path, "%s", dir->dir); createDirectory(path); } /* * Create the directory for the RDF pages if (rpm2html_rdf_dir != NULL) { if (tree->htmlpath[0] != '\0') sprintf(path, "%s/%s", rpm2html_rdf_dir, tree->htmlpath); else sprintf(path, "%s", rpm2html_rdf_dir); createDirectory(path); } */ /* * Scan the repository. */ if (tree->rpmpath[0] != '\0') sprintf(path, "%s/%s", dir->rpmdir, tree->rpmpath); else sprintf(path, "%s", dir->rpmdir); if (rpm2htmlVerbose > 1) fprintf(stderr, "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') sprintf(path, "%s/%s/%s", dir->rpmdir, tree->rpmpath, filename); else sprintf(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; } /* * Don't follow of analyze symlinks, */ if (S_ISLNK(buf.st_mode)) { if (rpm2htmlVerbose) fprintf(stderr, "Dropping symlink %s\n", path); continue; } /* * Check for RPM files by looking at the suffix */ else if ((len >= 5) && (!strcasecmp(&filename[len - 4], ".rpm"))) { cur = rpmOpen(filename, dir, tree); } /* * 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); 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->build_tree != 0)) { dir->root = rpmCreateRealRoot(); } cur = rpmNewSubdir(tree, dir->name, dir->subdir == NULL ? "" : dir->subdir, "", dir->color); 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; int offset; char *prefix = "/"; /* * Create the directory for the HTML pages */ if (rpm2html_dump_html) { if (dir->subdir) sprintf(path, "%s/%s", dir->dir, dir->subdir); else sprintf(path, "%s", dir->dir); createDirectory(path); } /* * Create the directory for the RDF pages */ if (rpm2html_rdf_dir != NULL) { if (dir->subdir) sprintf(path, "%s/%s", rpm2html_rdf_dir, dir->subdir); else sprintf(path, "%s", rpm2html_rdf_dir); createDirectory(path); } if (rpmdbOpen(prefix, &db, O_RDONLY, 0644)) { return(NULL); } offset = rpmdbFirstRecNum(db); while (offset) { h = rpmdbGetRecord(db, offset); if (!h) { fprintf(stderr, "could not read database record!\n"); return(ret); } cur = rpmAnalyze(NULL, h, dir, NULL, 0); if (cur != NULL) ret = rpmAddList(ret, cur); headerFree(h); offset = rpmdbNextRecNum(db, offset); } rpmdbClose(db); return(ret); } /* * 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; } /* * Allocate a directory tree. */ dirTree = rpmNewSubdir(NULL, "", "", "", NULL); dir = dirList; rpmLists = (rpmDataPtr *) malloc(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 = strdup(rpm2html_maint); if ((dir->mail == NULL) && (rpm2html_mail != NULL)) dir->mail = strdup(rpm2html_mail); if ((dir->ftp == NULL) && (rpm2html_ftp != NULL)) dir->ftp = strdup(rpm2html_ftp); if ((dir->ftpsrc == NULL) && (rpm2html_ftpsrc != NULL)) dir->ftpsrc = strdup(rpm2html_ftpsrc); if ((dir->dir == NULL) && (rpm2html_dir != NULL)) dir->dir = strdup(rpm2html_dir); if ((dir->host == NULL) && (rpm2html_host != NULL)) dir->host = strdup(rpm2html_host); if ((dir->name == NULL) && (rpm2html_name != NULL)) dir->name = strdup(rpm2html_name); if ((dir->url == NULL) && (rpm2html_url != NULL)) dir->url = strdup(rpm2html_url); if (dir->rpmdir == NULL) { fprintf(stderr, "?!? rpmDir without directory ?!? disabled !\n"); } else if (!strcmp(dir->rpmdir, "localbase")) { /* 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 { if (rpm2htmlVerbose) fprintf(stderr, "Scanning directory %s for RPMs\n",dir->rpmdir); cur = rpmDirScan(dir, dirTree); } if (cur != NULL) { if (nbLists >= maxLists) { maxLists *= 2; rpmLists = (rpmDataPtr *) realloc(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]); free(rpmLists); return(ret); }