File:  [Public] / rpm2html / rpmopen.c
Revision 1.24: download - view: text, annotated - select for diffs
Sun Feb 8 19:08:39 1998 UTC (26 years, 4 months ago) by veillard
Branches: MAIN
CVS tags: HEAD
Recursive support seems to work, corrected bugs in HTML output, Daniel.

/*
 * 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.24 1998/02/08 19:08:39 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 <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.
 */
int 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(-1);
    }
    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 ressources provided by this RPM */
    if (!headerGetEntry(h, RPMTAG_SUMMARY, &type, &p, &count) || !p) {
        rpm->summary = localizedStrings[LANG_NO_SUMMARY];
    } else {
	rpm->summary = strdupHTML((char *) p);
    }
    if (!headerGetEntry(h, RPMTAG_DESCRIPTION, &type, &p, &count) || !p) {
        rpm->description = localizedStrings[LANG_NO_DESCRIPTION];
    } else {
	rpm->description = strdupHTML((char *) p);
    }
    if (!headerGetEntry(h, RPMTAG_DISTRIBUTION, &type, &p, &count) || !p) {
        rpm->distribution = localizedStrings[LANG_UNKNOWN];
    } else {
	rpm->distribution = strdup((char *) p);
    }
    if (!headerGetEntry(h, RPMTAG_ARCH, &type, &p, &count) || !p) {
        rpm->arch = 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) {
        rpm->os = "";
    } else {
	rpm->os = strdup((char *) p);
    }
    if (!headerGetEntry(h, RPMTAG_VENDOR, &type, &p, &count) || !p) {
        rpm->vendor = NULL;
    } else {
	rpm->vendor = strdup((char *) p);
    }
    if (!headerGetEntry(h, RPMTAG_GROUP, &type, &p, &count) || !p) {
        rpm->group = localizedStrings[LANG_NO_GROUP];
    } else {
	rpm->group = strdup((char *) p);
    }
    if (!headerGetEntry(h, RPMTAG_BUILDHOST, &type, &p, &count) || !p) {
        rpm->host = 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) {
        rpm->srcrpm = "";
    } else {
	rpm->srcrpm = strdup((char *) p);
    }
    if (!headerGetEntry(h, RPMTAG_URL, &type, &p, &count) || !p) {
        rpm->url = NULL;
    } else {
	rpm->url = strdup((char *) p);
    }
    if (!headerGetEntry(h, RPMTAG_PACKAGER, &type, &p, &count) || !p) {
        rpm->packager = NULL;
    } else {
	rpm->packager = strdup((char *) p);
    }
    if (!headerGetEntry(h, RPMTAG_COPYRIGHT, &type, &p, &count) || !p) {
        rpm->copyright = NULL;
    } else {
	rpm->copyright = strdup((char *) p);
    }
    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 ressource "package" */
    rpm->nb_ressources = 1;
    rpm->ressources[0] = rpmRessAdd(name, rpm, installed);

    val = getTagNumber("RPMTAG_PROVIDES");
    if (!headerGetEntry(h, val, &type, &p, &count) || !p) {
        rpm->nb_ressources = 1;
    } else {
	if (count >= MAX_RESS) {
	    fprintf(stderr, "MAX_RESS %d overflow, increase the limit!\n",
		    MAX_RESS);
	    count = MAX_RESS;
	}

        for (i = 0, j = rpm->nb_ressources; i < count;j++, i++) {
	    rpm->ressources[j] = rpmRessAdd(((char **) p)[i], rpm, installed);
	}
	rpm->nb_ressources += 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->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(0);
}

/*
 * rpmOpen : open an RPM file, read and parse the header and 
 *           fill the informations in the database.
 */
int rpmOpen(char *nameRpm, rpmDirPtr dir, const char *subdir) {
    int fd;
    int rc;
    int n;
    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(-1);
    }

    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(-1);
	    }
	    break;
	case 1:
	    fprintf(stderr, "%s does not appear to be a RPM package\n",
		    nameRpm);
	    return(-1);
	case 2:
	    fprintf(stderr, "query of %s failed\n", nameRpm);
	    return(-1);
	default:
	    fprintf(stderr, "rpmReadPackageHeader(%s): unknown error %d\n",
		    nameRpm, rc);
	    return(-1);
    }

    n = rpmAnalyze(nameRpm, h, dir, subdir, buf.st_mtime);

    /* free the header and close the descriptor */
    headerFree(h);
    close(fd);

    return(n);
}

/*
 * Scan one directory for RPM files this is where the recursive handling
 * is done.
 */
static int rpmOneDirScan(rpmDirPtr dir, char *subdir) {
    struct dirent **namelist;
    char *filename;
    static char path[2000];
    struct stat buf;
    int len;
    int n, i;


    /*
     * Create the directory for the HTML pages
     */
    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(-1);
    } else {
        for (i = 0;i < n;i++) {
	    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);

	    /*
	     * Check for RPM files by looking at the suffix
	     */
	    if ((len >= 5) && (!strcasecmp(&filename[len - 4], ".rpm"))) {
	        rpmOpen(filename, dir, subdir);
	    }
	    /*
	     * Else if this is a directory, recurse !
	     */
	    else {
	        if ((stat(path, &buf) == 0) && (S_ISDIR(buf.st_mode))) {
		    if (filename[0] != '.') {
		        if (*subdir == '\0')
		            rpmOneDirScan(dir, filename);
			else {
			    char *newdir;
			    sprintf(path, "%s/%s", subdir, filename);
			    newdir = strdup(path);
			    rpmOneDirScan(dir, newdir);
			    free(newdir);
			}
		    }
	        }
	    }
	}
    }
    free(namelist);
    return(n);
}

/*
 * Scan a directory for RPM files.
 */
static int rpmDirScan(rpmDirPtr dir) {
    return(rpmOneDirScan(dir, ""));
}

/*
 * Scan the local RPM database for RPM files.
 */
static int rpmBaseScan(rpmDirPtr dir) {
    rpmdb db;
    Header h = NULL;
    int offset, n = 0;
    char *prefix = "/";

    if (rpmdbOpen(prefix, &db, O_RDONLY, 0644)) {
        return(n);
    }
    offset = rpmdbFirstRecNum(db);
    while (offset) {
        h = rpmdbGetRecord(db, offset);
	if (!h) {
	    fprintf(stderr, "could not read database record!\n");
	    return(n);
	}
	rpmAnalyze(NULL, h, dir, "", 0);
	headerFree(h);
	offset = rpmdbNextRecNum(db, offset);
    }
    rpmdbClose(db);

    return(n);
}

/*
 * Scan all registered directories.
 * One fist check for completeness of the informations in
 * the rpmDir structure.
 */

int rpmDirScanAll(void) {
    int n = 0, i;

    rpmDirPtr dir, next;

    /*
     * 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) {
	/*
	 * 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 */
            i = rpmBaseScan(dir);
	    if (i > 0) n += i;
	} 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);
	    i = rpmDirScan(dir);
	    if (i > 0) n += i;
	}

        dir = dir->next;
    }
    return(n);
}


Webmaster