/*
* rpmopen.c : open an extract informations from RPM files.
*
* See Copyright for the status of this software.
*
* $Id: rpmopen.c,v 1.71 2000/06/15 16:37:36 daniel 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 <rpm/rpmmacro.h> /* Added by A. Gibert */
#include "rpmdata.h"
#include "html.h"
#include "rdf.h"
#include "rpm2html.h"
#include "language.h"
#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;
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);
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);
}
/*
* 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 *nameRpm, Header h, 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;
void * q = NULL; /* Added by A.Gibert */
void * r = NULL; /* Added by A.Gibert */
int val, i, j;
int valv, valf; /* Added by A.Gibert */
rpmDataPtr rpm = NULL;
static char nameBuffer[500];
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);
stringFree(rpm->name);
stringFree(rpm->version);
stringFree(rpm->release);
debugFree(rpm->summary);
stringFree(rpm->distribution);
stringFree(rpm->arch);
stringFree(rpm->os);
stringFree(rpm->vendor);
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]);
}
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");
valv = getTagNumber("RPMTAG_REQUIREVERSION"); /* Added by A.Gibert */
valf = getTagNumber("RPMTAG_REQUIREFLAGS"); /* Added by A.Gibert */
if (!headerGetEntry(h, val, &type, &p, &count) || !p) {
rpm->extra->nb_requires = 0;
rpm->extra->requires = NULL;
} else {
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);
}
}
if (!headerGetEntry(h, valv, &type, &q, &count) || !q) { /* Beginning of a part added by A.Gibert */
rpm->extra->nb_requires = 0;
rpm->extra->requires = NULL;
} else {
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);
}
}
if (!headerGetEntry(h, valf, &type, &r, &count) || !r) {
rpm->extra->nb_requires = 0;
rpm->extra->requires = NULL;
} else {
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);
}
rpm->extra->nb_requires = 0;
for (i = 0, j = 0; i < count;i++) {
char buf[10];
long anint = *(((long *)r)+i);
buf[0]='\0';
if (anint & RPMSENSE_LESS)
strcat(buf, "<");
if (anint & RPMSENSE_GREATER)
strcat(buf, ">");
if (anint & RPMSENSE_EQUAL)
strcat(buf, "="); /* End of a part added by A.Gibert */
if (!checkResourceName(((char **) p)[i])) continue;
rpm->extra->requires[j++] =
rpmRequAdd(((char **) p)[i],((char **) q)[i],
((char *) buf) , rpm, installed);
}
rpm->extra->nb_requires = j;
}
ENTRY_CLEANUP(p);
ENTRY_CLEANUP(q); /* Added by A.Gibert */
ENTRY_CLEANUP(r); /* Added by A.Gibert */
#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);
/* Add the package files to the real filesystem tree if asked for */
if ((dir->build_tree != 0) && (rpm->extra->filelist != NULL)) {
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)
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) && (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;
int isSource;
char buffer[500];
struct stat buf;
/* 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 ((fd = fdOpen(buffer, O_RDONLY, 0)) < 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");
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);
}
cur = rpmAnalyze(nameRpm, h, dir, tree, buf.st_mtime, isSource);
/* free the header and close the descriptor */
headerFree(h);
fdClose(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) && (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_RPM310
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_RPM310
{ rpmdbMatchIterator mi;
mi = rpmdbInitIterator(db, RPMDBI_PACKAGES, NULL, 0);
while ((h = rpmdbNextIterator(mi)) != NULL) {
cur = rpmAnalyze(NULL, h, dir, NULL, 0, 0);
if (cur != NULL) ret = rpmAddList(ret, cur);
}
rpmdbFreeIterator(mi);
}
#else /* USE_RPM310 */
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, 0);
if (cur != NULL) ret = rpmAddList(ret, cur);
headerFree(h);
offset = rpmdbNextRecNum(db, offset);
}
#endif /* USE_RPM310 */
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;
}
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 {
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);
}
Webmaster