Annotation of rpm2html/rpmopen.c, revision 1.27

1.1       veillard    1: /*
                      2:  * rpmopen.c : open an extract informations from RPM files.
                      3:  *
1.11      veillard    4:  * Copyright (c) 1997 Daniel Veillard <veillard@apocalypse.org>
1.9       veillard    5:  * See COPYING for the status of this software.
1.1       veillard    6:  *
1.27    ! veillard    7:  * $Id: rpmopen.c,v 1.26 1998/02/16 23:13:22 veillard Exp $
1.1       veillard    8:  */
                      9: 
1.9       veillard   10: #include <config.h>
1.1       veillard   11: #include <sys/types.h>
                     12: #include <sys/stat.h>
1.9       veillard   13: #ifdef HAVE_FCNTL_H
1.1       veillard   14: #include <fcntl.h>
1.9       veillard   15: #endif
1.1       veillard   16: #include <stdio.h>
                     17: #include <stdlib.h>
                     18: #include <string.h>
1.9       veillard   19: #ifdef HAVE_UNISTD_H
1.1       veillard   20: #include <unistd.h>
1.9       veillard   21: #endif
1.6       veillard   22: #include <dirent.h>
1.13      veillard   23: #include <errno.h>
1.1       veillard   24: 
                     25: #include <rpm/rpmlib.h>
                     26: 
                     27: #include "rpmdata.h"
1.7       veillard   28: #include "html.h"
1.8       veillard   29: #include "rpm2html.h"
1.12      veillard   30: #include "language.h"
1.1       veillard   31: 
                     32: /*
                     33:  * Get the internal number associated to an RPM tag.
                     34:  */
                     35: static int getTagNumber(char *tag) {
                     36:     int i;
                     37:     const struct headerTagTableEntry * t;
                     38: 
                     39:     for (i = 0, t = rpmTagTable; i < rpmTagTableSize; i++, t++) {
                     40:        if (!strcasecmp(tag, t->name)) return(t->val);
                     41:     }
                     42:     fprintf(stderr, "getTagNumber(%s) : unknown tag !\n", tag);
                     43:     return(-1);
                     44: }
                     45: 
                     46: /*
1.11      veillard   47:  * rpmAnalyze : analyze an RPM record, read and parse the header and 
                     48:  *              fill the informations in the database.
1.1       veillard   49:  */
1.24      veillard   50: int rpmAnalyze(char *nameRpm, Header h, rpmDirPtr dir, const char *subdir,
                     51:                time_t stamp) {
1.11      veillard   52:     int installed = dir->installbase;
1.2       veillard   53:     char * name = NULL, * version = NULL, * release = NULL;
1.1       veillard   54:     int_32 count, type;
1.2       veillard   55:     void * p = NULL;
1.10      veillard   56:     int val, i, j;
1.1       veillard   57:     rpmDataPtr rpm = NULL;
1.5       veillard   58:     static char buffer[500000];
1.11      veillard   59:     static char nameBuffer[500];
1.1       veillard   60: 
                     61:     /* extract informations from the header */
                     62:     headerGetEntry(h, RPMTAG_NAME, &type, (void **) &name, &count);
                     63:     headerGetEntry(h, RPMTAG_VERSION, &type, (void **) &version, &count);
                     64:     headerGetEntry(h, RPMTAG_RELEASE, &type, (void **) &release, &count);
                     65:         
                     66:     /* allocate a new rpmData block, fill it */
                     67:     rpm = (rpmDataPtr) malloc(sizeof(rpmData));
1.15      veillard   68:     memset(rpm, 0, sizeof(rpmData));
1.1       veillard   69:     if (rpm == NULL) {
                     70:          fprintf(stderr, "cannot allocate %d bytes: %s\n", sizeof(rpmData),
                     71:                 strerror(errno));
1.11      veillard   72:          return(-1);
1.1       veillard   73:     }
1.6       veillard   74:     rpm->dir = dir;
1.24      veillard   75:     rpm->subdir = strdup(subdir);
1.20      veillard   76:     rpm->stamp = stamp;
1.1       veillard   77:     rpm->name = strdup(name);
                     78:     rpm->version = strdup(version);
                     79:     rpm->release = strdup(release);
                     80: 
1.26      veillard   81:     /* get all the resources provided by this RPM */
1.2       veillard   82:     if (!headerGetEntry(h, RPMTAG_SUMMARY, &type, &p, &count) || !p) {
1.27    ! veillard   83:         rpm->summary = strdup(localizedStrings[LANG_NO_SUMMARY]);
1.2       veillard   84:     } else {
1.19      veillard   85:        rpm->summary = strdupHTML((char *) p);
1.2       veillard   86:     }
                     87:     if (!headerGetEntry(h, RPMTAG_DESCRIPTION, &type, &p, &count) || !p) {
1.27    ! veillard   88:         rpm->description = strdup(localizedStrings[LANG_NO_DESCRIPTION]);
1.2       veillard   89:     } else {
1.19      veillard   90:        rpm->description = strdupHTML((char *) p);
1.2       veillard   91:     }
                     92:     if (!headerGetEntry(h, RPMTAG_DISTRIBUTION, &type, &p, &count) || !p) {
1.27    ! veillard   93:         rpm->distribution = strdup(localizedStrings[LANG_UNKNOWN]);
1.2       veillard   94:     } else {
                     95:        rpm->distribution = strdup((char *) p);
                     96:     }
                     97:     if (!headerGetEntry(h, RPMTAG_ARCH, &type, &p, &count) || !p) {
1.27    ! veillard   98:         rpm->arch = strdup(localizedStrings[LANG_NONE]);
1.11      veillard   99:        if (nameRpm == NULL) {
1.12      veillard  100:            sprintf(nameBuffer, "%s-%s-%s.rpm", name, version, release);
1.11      veillard  101:            nameRpm = nameBuffer;
                    102:        }
1.2       veillard  103:     } else {
                    104:        rpm->arch = strdup((char *) p);
1.11      veillard  105:        if (nameRpm == NULL) {
1.12      veillard  106:            sprintf(nameBuffer, "%s-%s-%s.%s.rpm",
                    107:                    name, version, release, (char *)p);
1.11      veillard  108:            nameRpm = nameBuffer;
                    109:        }
1.2       veillard  110:     }
1.7       veillard  111:     if (!headerGetEntry(h, RPMTAG_OS, &type, &p, &count) || !p) {
                    112:         rpm->os = "";
                    113:     } else {
                    114:        rpm->os = strdup((char *) p);
                    115:     }
1.2       veillard  116:     if (!headerGetEntry(h, RPMTAG_VENDOR, &type, &p, &count) || !p) {
1.7       veillard  117:         rpm->vendor = NULL;
1.2       veillard  118:     } else {
                    119:        rpm->vendor = strdup((char *) p);
                    120:     }
                    121:     if (!headerGetEntry(h, RPMTAG_GROUP, &type, &p, &count) || !p) {
1.27    ! veillard  122:         rpm->group = strdup(localizedStrings[LANG_NO_GROUP]);
1.2       veillard  123:     } else {
                    124:        rpm->group = strdup((char *) p);
                    125:     }
                    126:     if (!headerGetEntry(h, RPMTAG_BUILDHOST, &type, &p, &count) || !p) {
1.27    ! veillard  127:         rpm->host = strdup(localizedStrings[LANG_NO_HOST]);
1.2       veillard  128:     } else {
                    129:        rpm->host = strdup((char *) p);
                    130:     }
                    131:     if (!headerGetEntry(h, RPMTAG_SIZE, &type, &p, &count) || !p) {
                    132:         rpm->size = 0;
                    133:     } else {
                    134:        rpm->size = *((int *) p);
                    135:     }
1.11      veillard  136:     if (installed) {
                    137:        if (!headerGetEntry(h, RPMTAG_INSTALLTIME, &type, &p, &count) || !p) {
                    138:            rpm->date = 0;
                    139:        } else {
                    140:            rpm->date = *((int_32 *) p);
                    141:        }
1.2       veillard  142:     } else {
1.11      veillard  143:        if (!headerGetEntry(h, RPMTAG_BUILDTIME, &type, &p, &count) || !p) {
                    144:            rpm->date = 0;
                    145:        } else {
                    146:            rpm->date = *((int_32 *) p);
                    147:        }
1.2       veillard  148:     }
                    149:     if (!headerGetEntry(h, RPMTAG_SOURCERPM, &type, &p, &count) || !p) {
1.27    ! veillard  150:         rpm->srcrpm = strdup("");
1.2       veillard  151:     } else {
                    152:        rpm->srcrpm = strdup((char *) p);
                    153:     }
1.7       veillard  154:     if (!headerGetEntry(h, RPMTAG_URL, &type, &p, &count) || !p) {
                    155:         rpm->url = NULL;
                    156:     } else {
                    157:        rpm->url = strdup((char *) p);
                    158:     }
                    159:     if (!headerGetEntry(h, RPMTAG_PACKAGER, &type, &p, &count) || !p) {
                    160:         rpm->packager = NULL;
                    161:     } else {
                    162:        rpm->packager = strdup((char *) p);
                    163:     }
                    164:     if (!headerGetEntry(h, RPMTAG_COPYRIGHT, &type, &p, &count) || !p) {
                    165:         rpm->copyright = NULL;
                    166:     } else {
                    167:        rpm->copyright = strdup((char *) p);
                    168:     }
                    169:     if (rpm->vendor == NULL) {
1.15      veillard  170:         if (rpm->packager != NULL) rpm->vendor = strdup(rpm->packager);
                    171:        else rpm->vendor = strdup(localizedStrings[LANG_UNKNOWN]);
1.7       veillard  172:     }
1.2       veillard  173: 
1.11      veillard  174:     rpm->filename = strdup(nameRpm);
                    175: 
1.26      veillard  176:     /* package-xxx.rpm provides the resource "package" */
                    177:     rpm->nb_resources = 1;
                    178:     rpm->resources[0] = rpmRessAdd(name, rpm, installed);
1.10      veillard  179: 
1.1       veillard  180:     val = getTagNumber("RPMTAG_PROVIDES");
                    181:     if (!headerGetEntry(h, val, &type, &p, &count) || !p) {
1.26      veillard  182:         rpm->nb_resources = 1;
1.1       veillard  183:     } else {
1.26      veillard  184:        if (count >= MAX_RES) {
                    185:            fprintf(stderr, "MAX_RES %d overflow, increase the limit!\n",
                    186:                    MAX_RES);
                    187:            count = MAX_RES;
1.1       veillard  188:        }
                    189: 
1.26      veillard  190:         for (i = 0, j = rpm->nb_resources; i < count;j++, i++) {
                    191:            rpm->resources[j] = rpmRessAdd(((char **) p)[i], rpm, installed);
1.4       veillard  192:        }
1.26      veillard  193:        rpm->nb_resources += count;
1.4       veillard  194:     }
                    195: 
                    196:     val = getTagNumber("RPMTAG_REQUIRENAME");
                    197:     if (!headerGetEntry(h, val, &type, &p, &count) || !p) {
                    198:         rpm->nb_requires = 0;
                    199:     } else {
                    200:        if (count >= MAX_REQU) {
                    201:            fprintf(stderr, "MAX_REQU %d overflow, increase the limit!\n",
                    202:                    MAX_REQU);
                    203:            count = MAX_REQU;
                    204:        }
                    205: 
                    206:        rpm->nb_requires = count;
                    207:         for (i = 0; i < count;i++) {
1.11      veillard  208:            rpm->requires[i] = rpmRequAdd(((char **) p)[i], rpm, installed);
1.1       veillard  209:        }
1.5       veillard  210:     }
                    211:     val = getTagNumber("RPMTAG_FILENAMES");
                    212:     if (!headerGetEntry(h, val, &type, &p, &count) || !p) {
1.7       veillard  213:         rpm->filelist = NULL; /* No filelist in the package ! */
1.5       veillard  214:     } else {
                    215:         char *ptr = buffer;
                    216:        for (i = 0; i < count;i++) {
                    217:            ptr += sprintf(ptr, "%s\n", ((char **) p)[i]);
                    218:        }
                    219:        rpm->filelist = strdup(buffer);
1.1       veillard  220:     }
                    221: 
                    222:     /* insert the package informations in the database */
1.11      veillard  223:     if (installed) {
                    224:        rpm->next = rpmInstalledList;
                    225:        rpmInstalledList = rpm;
                    226:     } else {
                    227:        rpm->next = rpmList;
                    228:        rpmList = rpm;
                    229:     }
1.17      veillard  230: 
                    231:     /* Register this package */
                    232:     rpmAddSoftware(rpm);
1.7       veillard  233: 
                    234:     /* dump the HTML related to this package */
                    235:     dumpRpmHtml(rpm);
                    236: 
                    237:     /* free large amount of data not used later */
                    238:     if (rpm->filelist) free(rpm->filelist);
1.15      veillard  239:     rpm->filelist = NULL;
1.7       veillard  240:     if (rpm->copyright) free(rpm->copyright);
1.15      veillard  241:     rpm->copyright = NULL;
                    242:     if (rpm->description) free(rpm->description);
                    243:     rpm->description = NULL;
1.8       veillard  244: 
                    245:     /* increment the counters */
1.11      veillard  246:     if (installed) {
                    247:        rpm2html_install_files++;
1.21      veillard  248:        rpm2html_install_size += rpm->size / 1024;
1.11      veillard  249:     } else {
                    250:        rpm2html_files++;
1.21      veillard  251:        rpm2html_size += rpm->size / 1024;
1.11      veillard  252:     }
1.7       veillard  253: 
1.1       veillard  254:     return(0);
1.11      veillard  255: }
                    256: 
                    257: /*
                    258:  * rpmOpen : open an RPM file, read and parse the header and 
                    259:  *           fill the informations in the database.
                    260:  */
1.24      veillard  261: int rpmOpen(char *nameRpm, rpmDirPtr dir, const char *subdir) {
1.11      veillard  262:     int fd;
                    263:     int rc;
                    264:     int n;
                    265:     Header h = NULL;
                    266:     int isSource;
                    267:     char buffer[500];
1.20      veillard  268:     struct stat buf;
1.11      veillard  269: 
                    270:     /* open the file for reading */
1.24      veillard  271:     if (subdir[0] != '\0')
                    272:        sprintf(buffer, "%s/%s/%s", dir->rpmdir, subdir, nameRpm);
                    273:     else
                    274:        sprintf(buffer, "%s/%s", dir->rpmdir, nameRpm);
1.11      veillard  275:     if ((fd = open(buffer, O_RDONLY)) < 0) {
                    276:          fprintf(stderr, "open of %s failed: %s\n", buffer,
                    277:                 strerror(errno));
                    278:         return(-1);
                    279:     }
                    280: 
1.20      veillard  281:     stat(buffer, &buf);
                    282: 
1.11      veillard  283:     /* read the RPM header */
                    284:     rc = rpmReadPackageHeader(fd, &h, &isSource, NULL, NULL);
                    285:     switch (rc) {
                    286:        case 0:
                    287:            if (!h) {
                    288:                fprintf(stderr,
                    289:                        "old format source packages cannot be queried\n");
                    290:                return(-1);
                    291:            }
                    292:            break;
                    293:        case 1:
                    294:            fprintf(stderr, "%s does not appear to be a RPM package\n",
                    295:                    nameRpm);
                    296:            return(-1);
                    297:        case 2:
                    298:            fprintf(stderr, "query of %s failed\n", nameRpm);
                    299:            return(-1);
                    300:        default:
                    301:            fprintf(stderr, "rpmReadPackageHeader(%s): unknown error %d\n",
                    302:                    nameRpm, rc);
                    303:            return(-1);
                    304:     }
                    305: 
1.24      veillard  306:     n = rpmAnalyze(nameRpm, h, dir, subdir, buf.st_mtime);
1.11      veillard  307: 
                    308:     /* free the header and close the descriptor */
                    309:     headerFree(h);
                    310:     close(fd);
1.1       veillard  311: 
1.11      veillard  312:     return(n);
1.6       veillard  313: }
                    314: 
                    315: /*
1.22      veillard  316:  * Scan one directory for RPM files this is where the recursive handling
                    317:  * is done.
1.6       veillard  318:  */
1.24      veillard  319: static int rpmOneDirScan(rpmDirPtr dir, char *subdir) {
1.6       veillard  320:     struct dirent **namelist;
1.7       veillard  321:     char *filename;
1.22      veillard  322:     static char path[2000];
1.23      veillard  323:     struct stat buf;
1.7       veillard  324:     int len;
1.6       veillard  325:     int n, i;
                    326: 
1.24      veillard  327: 
                    328:     /*
                    329:      * Create the directory for the HTML pages
                    330:      */
                    331:     if (*subdir != '\0')
                    332:        sprintf(path, "%s/%s", dir->dir, subdir);
                    333:     else
                    334:        sprintf(path, "%s", dir->dir);
                    335:     createDirectory(path);
                    336: 
                    337:     /*
                    338:      * Scan the repository.
                    339:      */
                    340:     if (*subdir != '\0')
                    341:        sprintf(path, "%s/%s", dir->rpmdir, subdir);
                    342:     else
                    343:        sprintf(path, "%s", dir->rpmdir);
                    344:     if (verbose)
                    345:         fprintf(stderr, "Scanning directory %s\n", path);
                    346: 
                    347:     n = scandir(path, &namelist, 0, alphasort);
                    348: 
1.6       veillard  349:     if (n < 0) {
1.24      veillard  350:         fprintf(stderr, "Listing of %s failed: %s\n", path,
1.6       veillard  351:                strerror(errno));
                    352:        return(-1);
                    353:     } else {
1.7       veillard  354:         for (i = 0;i < n;i++) {
                    355:            filename = namelist[i]->d_name;
                    356:            len = strlen(filename);
1.24      veillard  357: 
                    358:            /*
                    359:             * Compute the full path
                    360:             */
                    361:            if (*subdir != '\0')
                    362:                sprintf(path, "%s/%s/%s", dir->rpmdir, subdir, filename);
1.22      veillard  363:            else
1.24      veillard  364:                sprintf(path, "%s/%s", dir->rpmdir, filename);
1.22      veillard  365: 
                    366:            /*
1.25      veillard  367:             * Stat() the file to detect directory and symlimks
                    368:             */
                    369:            if (stat(path, &buf) != 0) {
                    370:                fprintf(stderr, "Couldn't stat(%s)\n", path);
                    371:                continue;
                    372:            }
                    373:            /*
                    374:             * Don't follow of analyze symlinks,
                    375:             */
                    376:             if (S_ISLNK(buf.st_mode)) {
                    377:                if (verbose)
                    378:                    fprintf(stderr, "Dropping symlink %s\n", path);
                    379:                continue;
                    380:            }
                    381:            /*
1.23      veillard  382:             * Check for RPM files by looking at the suffix
1.22      veillard  383:             */
1.25      veillard  384:            else if ((len >= 5) && (!strcasecmp(&filename[len - 4], ".rpm"))) {
1.24      veillard  385:                rpmOpen(filename, dir, subdir);
1.22      veillard  386:            }
                    387:            /*
1.23      veillard  388:             * Else if this is a directory, recurse !
1.22      veillard  389:             */
1.25      veillard  390:            else if (S_ISDIR(buf.st_mode)) {
                    391:                if (filename[0] != '.') {
                    392:                    if (*subdir == '\0')
                    393:                        rpmOneDirScan(dir, filename);
                    394:                    else {
                    395:                        char *newdir;
                    396:                        sprintf(path, "%s/%s", subdir, filename);
                    397:                        newdir = strdup(path);
                    398:                        rpmOneDirScan(dir, newdir);
                    399:                        free(newdir);
1.23      veillard  400:                    }
1.25      veillard  401:                }
1.22      veillard  402:            }
1.7       veillard  403:        }
1.6       veillard  404:     }
                    405:     free(namelist);
                    406:     return(n);
1.22      veillard  407: }
                    408: 
                    409: /*
                    410:  * Scan a directory for RPM files.
                    411:  */
                    412: static int rpmDirScan(rpmDirPtr dir) {
1.23      veillard  413:     return(rpmOneDirScan(dir, ""));
1.6       veillard  414: }
                    415: 
                    416: /*
1.11      veillard  417:  * Scan the local RPM database for RPM files.
                    418:  */
                    419: static int rpmBaseScan(rpmDirPtr dir) {
                    420:     rpmdb db;
                    421:     Header h = NULL;
                    422:     int offset, n = 0;
                    423:     char *prefix = "/";
                    424: 
                    425:     if (rpmdbOpen(prefix, &db, O_RDONLY, 0644)) {
                    426:         return(n);
                    427:     }
                    428:     offset = rpmdbFirstRecNum(db);
                    429:     while (offset) {
                    430:         h = rpmdbGetRecord(db, offset);
                    431:        if (!h) {
                    432:            fprintf(stderr, "could not read database record!\n");
                    433:            return(n);
                    434:        }
1.24      veillard  435:        rpmAnalyze(NULL, h, dir, "", 0);
1.11      veillard  436:        headerFree(h);
                    437:        offset = rpmdbNextRecNum(db, offset);
                    438:     }
                    439:     rpmdbClose(db);
                    440: 
                    441:     return(n);
                    442: }
                    443: 
                    444: /*
1.6       veillard  445:  * Scan all registered directories.
                    446:  * One fist check for completeness of the informations in
                    447:  * the rpmDir structure.
                    448:  */
                    449: 
                    450: int rpmDirScanAll(void) {
1.7       veillard  451:     int n = 0, i;
                    452: 
1.18      veillard  453:     rpmDirPtr dir, next;
                    454: 
                    455:     /*
                    456:      * first reverse the list ....
                    457:      */
                    458:     dir = dirList;
                    459:     dirList = NULL;
                    460:     while (dir != NULL) {
                    461:         next = dir->next;
                    462:        dir->next = dirList;
                    463:        dirList = dir;
                    464:        dir = next;
                    465:     }
                    466: 
                    467:     dir = dirList;
1.6       veillard  468: 
                    469:     while (dir != NULL) {
1.14      veillard  470:        /*
                    471:         * Override default setting.
                    472:         */
1.15      veillard  473:        if ((dir->maint == NULL) && (rpm2html_maint != NULL))
                    474:            dir->maint = strdup(rpm2html_maint);
                    475:        if ((dir->mail == NULL) && (rpm2html_mail != NULL))
                    476:            dir->mail = strdup(rpm2html_mail);
                    477:        if ((dir->ftp == NULL) && (rpm2html_ftp != NULL))
                    478:            dir->ftp = strdup(rpm2html_ftp);
                    479:        if ((dir->ftpsrc == NULL) && (rpm2html_ftpsrc != NULL))
                    480:            dir->ftpsrc = strdup(rpm2html_ftpsrc);
                    481:        if ((dir->dir == NULL) && (rpm2html_dir != NULL))
                    482:            dir->dir = strdup(rpm2html_dir);
                    483:        if ((dir->host == NULL) && (rpm2html_host != NULL))
                    484:            dir->host = strdup(rpm2html_host);
                    485:        if ((dir->name == NULL) && (rpm2html_name != NULL))
                    486:            dir->name = strdup(rpm2html_name);
                    487:        if ((dir->url == NULL) && (rpm2html_url != NULL))
                    488:            dir->url = strdup(rpm2html_url);
1.14      veillard  489: 
                    490:         if (dir->rpmdir == NULL) {
1.6       veillard  491:            fprintf(stderr, "?!? rpmDir without directory ?!? disabled !\n");
1.14      veillard  492:        } else if (!strcmp(dir->rpmdir, "localbase")) {
1.11      veillard  493:            /* Scan the local RPM database instead of a directory */
                    494:             i = rpmBaseScan(dir);
                    495:            if (i > 0) n += i;
1.7       veillard  496:        } else if (dir->ftp == NULL) {
                    497:            fprintf(stderr, "Directory %s disabled : no ftp field\n",
1.14      veillard  498:                    dir->rpmdir);
1.6       veillard  499:        } else {
1.16      veillard  500:            if (verbose)
                    501:                fprintf(stderr, "Scanning directory %s for RPMs\n",dir->rpmdir);
1.7       veillard  502:            i = rpmDirScan(dir);
                    503:            if (i > 0) n += i;
1.6       veillard  504:        }
                    505: 
                    506:         dir = dir->next;
                    507:     }
1.7       veillard  508:     return(n);
1.1       veillard  509: }
                    510: 

Webmaster