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