/*
* rpmopen.c : open an extract informations from RPM files.
*
* Copyright (c) 1997 Daniel Veillard <veillard@apocalypse.org>
* See COPYING for the status of this software.
*
* $Id: rpmopen.c,v 1.38 1998/03/24 06:28:34 veillard Exp $
*/
#include <config.h>
#include <sys/types.h>
#include <sys/stat.h>
#ifdef HAVE_FCNTL_H
#include <fcntl.h>
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#include <dirent.h>
#include <errno.h>
#include <time.h>
#include <rpm/rpmlib.h>
#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,
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[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;
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 = 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);
}
/* 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 */
dumpRpmHtml(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;
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 (tree->htmlpath[0] != '\0')
sprintf(path, "%s/%s", dir->dir, tree->htmlpath);
else
sprintf(path, "%s", dir->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 (verbose > 1)
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));
rpmRemoveSubdir(tree);
rpmFreeSubdir(tree);
return(NULL);
} else {
for (i = 0;i < n;i++) {
cur = NULL;
filename = namelist[i]->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 (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, 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);
}
}
/*
* Dump the pages related to this directory.
*/
if (ret != NULL) ret = dumpDirIndex(dir, tree, ret);
else {
rpmRemoveSubdir(tree);
rpmFreeSubdir(tree);
}
/*
* cleanup of local variables.
*/
free(namelist);
return(ret);
}
/*
* Scan a directory for RPM files.
*/
static rpmDataPtr rpmDirScan(rpmDirPtr dir, rpmSubdirPtr tree) {
rpmSubdirPtr cur;
rpmDataPtr ret;
if (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 (dir->subdir)
sprintf(path, "%s/%s", dir->dir, dir->subdir);
else
sprintf(path, "%s", dir->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;
rpmDataPtr rpmLists[MAX_SUB_DIRECTORIES];
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);
/*
* If a real tree is to be generated, allocate the root
*/
treeRoot = rpmCreateRealRoot();
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, dirTree);
}
if (cur != NULL) {
if (nbLists < MAX_SUB_DIRECTORIES) {
rpmLists[nbLists] = cur;
nbLists++;
if (nbLists == MAX_SUB_DIRECTORIES) {
fprintf(stderr, "Increase MAX_SUB_DIRECTORIES : %d \n",
nbLists);
}
}
}
dir = dir->next;
}
for (i = 0;i < nbLists;i++)
ret = rpmAddList(ret, rpmLists[i]);
return(ret);
}
Webmaster