/* * rpmopen.c : open an extract informations from RPM files. * * Copyright (c) 1997 Daniel Veillard * See COPYING for the status of this software. * * $Id: rpmopen.c,v 1.34 1998/03/13 07:30:13 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 "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, const char *subdir, 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[500000]; static char nameBuffer[500]; /* extract informations from the header */ headerGetEntry(h, RPMTAG_NAME, &type, (void **) &name, &count); headerGetEntry(h, RPMTAG_VERSION, &type, (void **) &version, &count); headerGetEntry(h, RPMTAG_RELEASE, &type, (void **) &release, &count); /* allocate a new rpmData block, fill it */ rpm = (rpmDataPtr) malloc(sizeof(rpmData)); memset(rpm, 0, sizeof(rpmData)); if (rpm == NULL) { fprintf(stderr, "cannot allocate %d bytes: %s\n", sizeof(rpmData), strerror(errno)); return(NULL); } rpm->dir = dir; rpm->subdir = strdup(subdir); 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 = strdupHTML((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 = strdupHTML((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++) { 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 the resource "package" */ rpm->nb_resources = 1; rpm->resources[0] = rpmRessAdd(name, rpm, installed); val = getTagNumber("RPMTAG_PROVIDES"); if (!headerGetEntry(h, val, &type, &p, &count) || !p) { rpm->nb_resources = 1; } else { if (count >= MAX_RES) { fprintf(stderr, "MAX_RES %d overflow, increase the limit!\n", MAX_RES); count = MAX_RES; } 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; } else { if (count >= MAX_REQU) { fprintf(stderr, "MAX_REQU %d overflow, increase the limit!\n", MAX_REQU); count = MAX_REQU; } 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++) { ptr += sprintf(ptr, "%s\n", ((char **) p)[i]); } rpm->filelist = strdup(buffer); } /* insert the package informations in the database if (installed) { rpm->next = rpmInstalledList; rpmInstalledList = rpm; } else { rpm->next = rpmList; rpmList = rpm; } */ /* Register this package */ rpmAddSoftware(rpm); /* dump the HTML related to this package */ dumpRpmHtml(rpm); /* 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, const char *subdir) { rpmDataPtr cur; int fd; int rc; Header h = NULL; int isSource; char buffer[500]; struct stat buf; /* open the file for reading */ if (subdir[0] != '\0') sprintf(buffer, "%s/%s/%s", dir->rpmdir, subdir, 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, subdir, 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, char *subdir) { rpmDataPtr ret = NULL, cur; struct dirent **namelist; char *filename; static char path[2000]; struct stat buf; int len; int i, n; /* * Create the directory for the HTML pages */ if ((dir->subdir != NULL) && (dir->subdir[0] != '\0')) { if (*subdir != '\0') sprintf(path, "%s/%s/%s", dir->dir, dir->subdir, subdir); else sprintf(path, "%s/%s", dir->dir, dir->subdir); } else { if (*subdir != '\0') sprintf(path, "%s/%s", dir->dir, subdir); else sprintf(path, "%s", dir->dir); } createDirectory(path); /* * Scan the repository. */ if (*subdir != '\0') sprintf(path, "%s/%s", dir->rpmdir, subdir); else sprintf(path, "%s", dir->rpmdir); if (verbose) fprintf(stderr, "Scanning directory %s\n", path); n = scandir(path, &namelist, 0, alphasort); if (n < 0) { fprintf(stderr, "Listing of %s failed: %s\n", path, strerror(errno)); return(NULL); } else { for (i = 0;i < n;i++) { cur = NULL; filename = namelist[i]->d_name; len = strlen(filename); /* * Compute the full path */ if (*subdir != '\0') sprintf(path, "%s/%s/%s", dir->rpmdir, subdir, 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 (verbose) 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, subdir); } /* * Else if this is a directory, recurse ! */ else if (S_ISDIR(buf.st_mode)) { if (filename[0] != '.') { if (*subdir == '\0') cur = rpmOneDirScan(dir, filename); else { char *newdir; sprintf(path, "%s/%s", subdir, filename); newdir = strdup(path); cur = rpmOneDirScan(dir, newdir); free(newdir); } } } if (cur != NULL) ret = rpmAddList(ret, cur); } } /* * Dump the pages related to this directory. */ if (ret != NULL) ret = dumpDirIndex(dir, subdir, ret); free(namelist); return(ret); } /* * Scan a directory for RPM files. */ static rpmDataPtr rpmDirScan(rpmDirPtr dir) { return(rpmOneDirScan(dir, "")); } /* * Scan the local RPM database for RPM files. */ static rpmDataPtr rpmBaseScan(rpmDirPtr dir) { rpmDataPtr ret = NULL, cur; rpmdb db; Header h = NULL; int offset; char *prefix = "/"; 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, "", 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; /* * first reverse the list .... */ dir = dirList; dirList = NULL; while (dir != NULL) { next = dir->next; dir->next = dirList; dirList = dir; dir = next; } dir = dirList; 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 (verbose) fprintf(stderr, "Scanning directory %s for RPMs\n",dir->rpmdir); cur = rpmDirScan(dir); } if (cur != NULL) ret = rpmAddList(ret, cur); dir = dir->next; } return(ret); }