7 #include <rpm/rpmtypes.h>
8 #include <rpm/rpmlib.h> /* rpmGetFilesystem*() */
9 #include <rpm/rpmmacro.h> /* XXX for %_i18ndomains */
10 #include <rpm/rpmfi.h>
11 #include <rpm/rpmstring.h>
15 struct headerTagFunc_s {
16 rpmTag tag; /*!< Tag of extension. */
17 void *func; /*!< Pointer to formatter function. */
20 /* forward declarations */
21 static const struct headerTagFunc_s rpmHeaderTagExtensions[];
23 void *rpmHeaderTagFunc(rpmTag tag);
26 * Retrieve file names from header.
28 * The representation of file names in package headers changed in rpm-4.0.
29 * Originally, file names were stored as an array of absolute paths.
30 * In rpm-4.0, file names are stored as separate arrays of dirname's and
31 * basename's, * with a dirname index to associate the correct dirname
34 * This function is used to retrieve file names independent of how the
35 * file names are represented in the package header.
38 * @param tagN RPMTAG_BASENAMES | PMTAG_ORIGBASENAMES
39 * @retval *fnp array of file names
40 * @retval *fcp number of files
42 static void rpmfiBuildFNames(Header h, rpmTag tagN,
43 const char *** fnp, rpm_count_t * fcp)
45 const char **baseNames, **dirNames, **fileNames;
49 rpmTag dirNameTag = 0;
50 rpmTag dirIndexesTag = 0;
53 struct rpmtd_s bnames, dnames, dixs;
55 if (tagN == RPMTAG_BASENAMES) {
56 dirNameTag = RPMTAG_DIRNAMES;
57 dirIndexesTag = RPMTAG_DIRINDEXES;
58 } else if (tagN == RPMTAG_ORIGBASENAMES) {
59 dirNameTag = RPMTAG_ORIGDIRNAMES;
60 dirIndexesTag = RPMTAG_ORIGDIRINDEXES;
63 if (!headerGet(h, tagN, &bnames, HEADERGET_MINMEM)) {
66 return; /* no file list */
68 (void) headerGet(h, dirNameTag, &dnames, HEADERGET_MINMEM);
69 (void) headerGet(h, dirIndexesTag, &dixs, HEADERGET_MINMEM);
71 count = rpmtdCount(&bnames);
72 baseNames = bnames.data;
73 dirNames = dnames.data;
74 dirIndexes = dixs.data;
77 * fsm, psm and rpmfi assume the data is stored in a single allocation
78 * block, until those assumptions are removed we need to jump through
79 * a few hoops here and precalculate sizes etc
81 size = sizeof(*fileNames) * count;
82 for (i = 0; i < count; i++)
83 size += strlen(baseNames[i]) + strlen(dirNames[dirIndexes[i]]) + 1;
85 fileNames = xmalloc(size);
86 t = ((char *) fileNames) + (sizeof(*fileNames) * count);
87 for (i = 0; i < count; i++) {
89 t = stpcpy( stpcpy(t, dirNames[dirIndexes[i]]), baseNames[i]);
92 rpmtdFreeData(&bnames);
93 rpmtdFreeData(&dnames);
100 static int filedepTag(Header h, rpmTag tagN, rpmtd td, headerGetFlags hgflags)
102 rpmfi fi = rpmfiNew(NULL, h, RPMTAG_BASENAMES, RPMFI_NOHEADER);
110 numfiles = rpmfiFC(fi);
115 if (tagN == RPMTAG_PROVIDENAME)
117 else if (tagN == RPMTAG_REQUIRENAME)
120 ds = rpmdsNew(h, tagN, 0);
121 fdeps = xmalloc(numfiles * sizeof(*fdeps));
123 while ((fileix = rpmfiNext(fi)) >= 0) {
125 const uint32_t * ddict = NULL;
126 int ndx = rpmfiFDepends(fi, &ddict);
130 unsigned dix = *ddict++;
131 char mydt = ((dix >> 24) & 0xff);
135 (void) rpmdsSetIx(ds, dix-1);
136 if (rpmdsNext(ds) < 0)
138 DNEVR = rpmdsDNEVR(ds);
140 argvAdd(&deps, DNEVR);
144 fdeps[fileix] = deps ? argvJoin(deps, " ") : xstrdup("");
148 td->count = numfiles;
149 td->flags = RPMTD_ALLOCED | RPMTD_PTR_ALLOCED;
150 td->type = RPM_STRING_ARRAY_TYPE;
160 * Retrieve mounted file system paths.
162 * @retval td tag data container
163 * @return 1 on success
165 static int fsnamesTag(Header h, rpmtd td, headerGetFlags hgflags)
169 if (rpmGetFilesystemList(&list, &(td->count)))
172 td->type = RPM_STRING_ARRAY_TYPE;
179 * Retrieve install prefixes.
181 * @retval td tag data container
182 * @return 1 on success
184 static int instprefixTag(Header h, rpmtd td, headerGetFlags hgflags)
186 struct rpmtd_s prefixes;
187 int flags = HEADERGET_MINMEM;
189 if (headerGet(h, RPMTAG_INSTALLPREFIX, td, flags)) {
191 } else if (headerGet(h, RPMTAG_INSTPREFIXES, &prefixes, flags)) {
192 /* only return the first prefix of the array */
193 td->type = RPM_STRING_TYPE;
194 td->data = xstrdup(rpmtdGetString(&prefixes));
195 td->flags = RPMTD_ALLOCED;
196 rpmtdFreeData(&prefixes);
204 * Retrieve mounted file system space.
206 * @retval td tag data container
207 * @return 1 on success
209 static int fssizesTag(Header h, rpmtd td, headerGetFlags hgflags)
211 struct rpmtd_s fsizes, fnames;
212 const char ** filenames = NULL;
213 rpm_loff_t * filesizes = NULL;
214 rpm_loff_t * usages = NULL;
215 rpm_count_t numFiles = 0;
217 if (headerGet(h, RPMTAG_LONGFILESIZES, &fsizes, HEADERGET_EXT)) {
218 filesizes = fsizes.data;
219 headerGet(h, RPMTAG_FILENAMES, &fnames, HEADERGET_EXT);
220 filenames = fnames.data;
221 numFiles = rpmtdCount(&fnames);
224 if (rpmGetFilesystemList(NULL, &(td->count)))
227 td->type = RPM_INT64_TYPE;
228 td->flags = RPMTD_ALLOCED;
230 if (filenames == NULL) {
231 usages = xcalloc((td->count), sizeof(usages));
237 if (rpmGetFilesystemUsage(filenames, filesizes, numFiles, &usages, 0))
242 rpmtdFreeData(&fnames);
243 rpmtdFreeData(&fsizes);
249 * Retrieve trigger info.
251 * @retval td tag data container
252 * @return 1 on success
254 static int triggercondsTag(Header h, rpmtd td, headerGetFlags hgflags)
259 struct rpmtd_s nametd, indextd, flagtd, versiontd, scripttd;
260 int hgeflags = HEADERGET_MINMEM;
262 if (!headerGet(h, RPMTAG_TRIGGERNAME, &nametd, hgeflags)) {
266 headerGet(h, RPMTAG_TRIGGERINDEX, &indextd, hgeflags);
267 headerGet(h, RPMTAG_TRIGGERFLAGS, &flagtd, hgeflags);
268 headerGet(h, RPMTAG_TRIGGERVERSION, &versiontd, hgeflags);
269 headerGet(h, RPMTAG_TRIGGERSCRIPTS, &scripttd, hgeflags);
271 td->type = RPM_STRING_ARRAY_TYPE;
272 td->flags = RPMTD_ALLOCED | RPMTD_PTR_ALLOCED;
273 td->data = conds = xmalloc(sizeof(*conds) * rpmtdCount(&scripttd));
274 td->count = rpmtdCount(&scripttd);
276 indices = indextd.data;
278 while ((i = rpmtdNext(&scripttd)) >= 0) {
280 char *flagStr, *item;
283 rpmtdInit(&nametd); rpmtdInit(&flagtd); rpmtdInit(&versiontd);
284 while ((j = rpmtdNext(&nametd)) >= 0) {
285 /* flag and version arrays match name array size always */
286 rpmtdNext(&flagtd); rpmtdNext(&versiontd);
291 flag = rpmtdGetUint32(&flagtd);
292 if (flag && *flag & RPMSENSE_SENSEMASK) {
293 flagStr = rpmtdFormat(&flagtd, RPMTD_FORMAT_DEPFLAGS, NULL);
294 rasprintf(&item, "%s %s %s", rpmtdGetString(&nametd),
296 rpmtdGetString(&versiontd));
299 item = xstrdup(rpmtdGetString(&nametd));
302 argvAdd(&items, item);
306 conds[i] = argvJoin(items, ", ");
310 rpmtdFreeData(&nametd);
311 rpmtdFreeData(&versiontd);
312 rpmtdFreeData(&flagtd);
313 rpmtdFreeData(&indextd);
314 rpmtdFreeData(&scripttd);
319 * Retrieve trigger type info.
321 * @retval td tag data container
322 * @return 1 on success
324 static int triggertypeTag(Header h, rpmtd td, headerGetFlags hgflags)
328 struct rpmtd_s indices, flags, scripts;
330 if (!headerGet(h, RPMTAG_TRIGGERINDEX, &indices, HEADERGET_MINMEM)) {
334 headerGet(h, RPMTAG_TRIGGERFLAGS, &flags, HEADERGET_MINMEM);
335 headerGet(h, RPMTAG_TRIGGERSCRIPTS, &scripts, HEADERGET_MINMEM);
337 td->flags = RPMTD_ALLOCED | RPMTD_PTR_ALLOCED;
338 td->count = rpmtdCount(&scripts);
339 td->data = conds = xmalloc(sizeof(*conds) * td->count);
340 td->type = RPM_STRING_ARRAY_TYPE;
342 while ((i = rpmtdNext(&scripts)) >= 0) {
344 rpmtdInit(&indices); rpmtdInit(&flags);
346 while (rpmtdNext(&indices) >= 0 && rpmtdNext(&flags) >= 0) {
347 if (*rpmtdGetUint32(&indices) != i)
350 flag = rpmtdGetUint32(&flags);
351 if (*flag & RPMSENSE_TRIGGERPREIN)
352 conds[i] = xstrdup("prein");
353 else if (*flag & RPMSENSE_TRIGGERIN)
354 conds[i] = xstrdup("in");
355 else if (*flag & RPMSENSE_TRIGGERUN)
356 conds[i] = xstrdup("un");
357 else if (*flag & RPMSENSE_TRIGGERPOSTUN)
358 conds[i] = xstrdup("postun");
360 conds[i] = xstrdup("");
364 rpmtdFreeData(&indices);
365 rpmtdFreeData(&flags);
366 rpmtdFreeData(&scripts);
372 * Retrieve file paths.
374 * @retval td tag data container
375 * @return 1 on success
377 static int filenamesTag(Header h, rpmtd td, headerGetFlags hgflags)
379 rpmfiBuildFNames(h, RPMTAG_BASENAMES,
380 (const char ***) &(td->data), &(td->count));
382 td->type = RPM_STRING_ARRAY_TYPE;
383 td->flags = RPMTD_ALLOCED;
385 return (td->data != NULL);
389 * Retrieve original file paths (wrt relocation).
391 * @retval td tag data container
392 * @return 1 on success
394 static int origfilenamesTag(Header h, rpmtd td, headerGetFlags hgflags)
396 rpmfiBuildFNames(h, RPMTAG_ORIGBASENAMES,
397 (const char ***) &(td->data), &(td->count));
399 td->type = RPM_STRING_ARRAY_TYPE;
400 td->flags = RPMTD_ALLOCED;
402 return (td->data != NULL);
405 * Retrieve file classes.
407 * @retval td tag data container
408 * @return 1 on success
410 static int fileclassTag(Header h, rpmtd td, headerGetFlags hgflags)
412 rpmfi fi = rpmfiNew(NULL, h, RPMTAG_BASENAMES, RPMFI_NOHEADER);
417 numfiles = rpmfiFC(fi);
422 fclasses = xmalloc(numfiles * sizeof(*fclasses));
424 while ((ix = rpmfiNext(fi)) >= 0) {
425 const char *fclass = rpmfiFClass(fi);
426 fclasses[ix] = xstrdup(fclass ? fclass : "");
430 td->count = numfiles;
431 td->flags = RPMTD_ALLOCED | RPMTD_PTR_ALLOCED;
432 td->type = RPM_STRING_ARRAY_TYPE;
441 * Retrieve file provides.
443 * @retval td tag data container
444 * @return 1 on success
446 static int fileprovideTag(Header h, rpmtd td, headerGetFlags hgflags)
448 return filedepTag(h, RPMTAG_PROVIDENAME, td, hgflags);
452 * Retrieve file requires.
454 * @retval td tag data container
455 * @return 1 on success
457 static int filerequireTag(Header h, rpmtd td, headerGetFlags hgflags)
459 return filedepTag(h, RPMTAG_REQUIRENAME, td, hgflags);
462 /* I18N look aside diversions */
464 #if defined(ENABLE_NLS)
465 extern int _nl_msg_cat_cntr; /* XXX GNU gettext voodoo */
467 static const char * const language = "LANGUAGE";
469 static const char * const _macro_i18ndomains = "%{?_i18ndomains}";
472 * Retrieve i18n text.
475 * @retval td tag data container
476 * @return 1 on success
478 static int i18nTag(Header h, rpmTag tag, rpmtd td, headerGetFlags hgflags)
480 char * dstring = rpmExpand(_macro_i18ndomains, NULL);
483 td->type = RPM_STRING_TYPE;
487 if (dstring && *dstring) {
489 const char * langval;
493 rasprintf(&msgkey, "%s(%s)", headerGetString(h, RPMTAG_NAME),
496 /* change to en_US for msgkey -> msgid resolution */
497 langval = getenv(language);
498 (void) setenv(language, "en_US", 1);
499 #if defined(ENABLE_NLS)
504 for (domain = dstring; domain != NULL; domain = de) {
505 de = strchr(domain, ':');
506 if (de) *de++ = '\0';
507 msgid = dgettext(domain, msgkey);
508 if (msgid != msgkey) break;
511 /* restore previous environment for msgid -> msgstr resolution */
513 (void) setenv(language, langval, 1);
516 #if defined(ENABLE_NLS)
520 if (domain && msgid) {
521 td->data = dgettext(domain, msgid);
522 td->data = xstrdup(td->data); /* XXX xstrdup has side effects. */
524 td->flags = RPMTD_ALLOCED;
526 dstring = _free(dstring);
532 dstring = _free(dstring);
534 rc = headerGet(h, tag, td, HEADERGET_DEFAULT);
539 * Retrieve summary text.
541 * @retval td tag data container
542 * @return 1 on success
544 static int summaryTag(Header h, rpmtd td, headerGetFlags hgflags)
546 return i18nTag(h, RPMTAG_SUMMARY, td, hgflags);
550 * Retrieve description text.
552 * @retval td tag data container
553 * @return 1 on success
555 static int descriptionTag(Header h, rpmtd td, headerGetFlags hgflags)
557 return i18nTag(h, RPMTAG_DESCRIPTION, td, hgflags);
561 * Retrieve group text.
563 * @retval td tag data container
564 * @return 1 on success
566 static int groupTag(Header h, rpmtd td, headerGetFlags hgflags)
568 return i18nTag(h, RPMTAG_GROUP, td, hgflags);
572 * Helper to convert 32bit tag to 64bit version.
573 * If header has new 64bit tag then just return the data,
574 * otherwise convert 32bit old tag data to 64bit values.
575 * For consistency, always return malloced data.
577 static int get64(Header h, rpmtd td, rpmTag newtag, rpmTag oldtag)
581 if (headerIsEntry(h, newtag)) {
582 rc = headerGet(h, newtag, td, HEADERGET_ALLOC);
584 struct rpmtd_s olddata;
585 uint32_t *d32 = NULL;
586 uint64_t *d64 = NULL;
588 headerGet(h, oldtag, &olddata, HEADERGET_MINMEM);
589 if (rpmtdType(&olddata) == RPM_INT32_TYPE) {
590 td->type = RPM_INT64_TYPE;
591 td->count = olddata.count;
592 td->flags = RPMTD_ALLOCED;
593 td->data = xmalloc(sizeof(*d64) * td->count);
595 while ((d32 = rpmtdNextUint32(&olddata))) {
599 rpmtdFreeData(&olddata);
607 * Retrieve file sizes as 64bit regardless of how they're stored.
609 * @retval td tag data container
610 * @return 1 on success
612 static int longfilesizesTag(Header h, rpmtd td, headerGetFlags hgflags)
614 return get64(h, td, RPMTAG_LONGFILESIZES, RPMTAG_FILESIZES);
617 static int longarchivesizeTag(Header h, rpmtd td, headerGetFlags hgflags)
619 return get64(h, td, RPMTAG_LONGARCHIVESIZE, RPMTAG_ARCHIVESIZE);
622 static int longsizeTag(Header h, rpmtd td, headerGetFlags hgflags)
624 return get64(h, td, RPMTAG_LONGSIZE, RPMTAG_SIZE);
627 static int longsigsizeTag(Header h, rpmtd td, headerGetFlags hgflags)
629 return get64(h, td, RPMTAG_LONGSIGSIZE, RPMTAG_SIGSIZE);
632 static int dbinstanceTag(Header h, rpmtd td, headerGetFlags hgflags)
634 uint32_t *recno = xmalloc(sizeof(*recno));
636 recno[0] = headerGetInstance(h);
637 td->type = RPM_INT32_TYPE;
640 td->flags = RPMTD_ALLOCED;
641 return 1; /* this cannot fail */
644 typedef enum nevraFlags_e {
645 NEVRA_NAME = (1 << 0),
646 NEVRA_EPOCH = (1 << 1),
647 NEVRA_VERSION = (1 << 2),
648 NEVRA_RELEASE = (1 << 3),
649 NEVRA_ARCH = (1 << 4)
652 static int getNEVRA(Header h, rpmtd td, nevraFlags flags)
654 const char *val = NULL;
657 if ((flags & NEVRA_NAME)) {
658 val = headerGetString(h, RPMTAG_NAME);
659 if (val) rstrscat(&res, val, "-", NULL);
661 if ((flags & NEVRA_EPOCH)) {
662 char *e = headerGetAsString(h, RPMTAG_EPOCH);
663 if (e) rstrscat(&res, e, ":", NULL);
666 if ((flags & NEVRA_VERSION)) {
667 val = headerGetString(h, RPMTAG_VERSION);
668 if (val) rstrscat(&res, val, "-", NULL);
670 if ((flags & NEVRA_RELEASE)) {
671 val = headerGetString(h, RPMTAG_RELEASE);
672 if (val) rstrscat(&res, val, NULL);
674 if ((flags & NEVRA_ARCH)) {
675 val = headerGetString(h, RPMTAG_ARCH);
676 if (headerIsSource(h) && val == NULL) val = "src";
677 if (val) rstrscat(&res, ".", val, NULL);
680 td->type = RPM_STRING_TYPE;
683 td->flags = RPMTD_ALLOCED;
688 static int evrTag(Header h, rpmtd td, headerGetFlags hgflags)
690 return getNEVRA(h, td, NEVRA_EPOCH|NEVRA_VERSION|NEVRA_RELEASE);
693 static int nvrTag(Header h, rpmtd td, headerGetFlags hgflags)
695 return getNEVRA(h, td, NEVRA_NAME|NEVRA_VERSION|NEVRA_RELEASE);
698 static int nvraTag(Header h, rpmtd td, headerGetFlags hgflags)
700 return getNEVRA(h, td, NEVRA_NAME|NEVRA_VERSION|NEVRA_RELEASE|NEVRA_ARCH);
703 static int nevrTag(Header h, rpmtd td, headerGetFlags hgflags)
705 return getNEVRA(h, td, NEVRA_NAME|NEVRA_EPOCH|NEVRA_VERSION|NEVRA_RELEASE);
708 static int nevraTag(Header h, rpmtd td, headerGetFlags hgflags)
710 return getNEVRA(h, td, NEVRA_NAME|NEVRA_EPOCH|NEVRA_VERSION|NEVRA_RELEASE|NEVRA_ARCH);
713 void *rpmHeaderTagFunc(rpmTag tag)
715 const struct headerTagFunc_s * ext;
718 for (ext = rpmHeaderTagExtensions; ext->func != NULL; ext++) {
719 if (ext->tag == tag) {
727 static const struct headerTagFunc_s rpmHeaderTagExtensions[] = {
728 { RPMTAG_GROUP, groupTag },
729 { RPMTAG_DESCRIPTION, descriptionTag },
730 { RPMTAG_SUMMARY, summaryTag },
731 { RPMTAG_FILECLASS, fileclassTag },
732 { RPMTAG_FILENAMES, filenamesTag },
733 { RPMTAG_ORIGFILENAMES, origfilenamesTag },
734 { RPMTAG_FILEPROVIDE, fileprovideTag },
735 { RPMTAG_FILEREQUIRE, filerequireTag },
736 { RPMTAG_FSNAMES, fsnamesTag },
737 { RPMTAG_FSSIZES, fssizesTag },
738 { RPMTAG_INSTALLPREFIX, instprefixTag },
739 { RPMTAG_TRIGGERCONDS, triggercondsTag },
740 { RPMTAG_TRIGGERTYPE, triggertypeTag },
741 { RPMTAG_LONGFILESIZES, longfilesizesTag },
742 { RPMTAG_LONGARCHIVESIZE, longarchivesizeTag },
743 { RPMTAG_LONGSIZE, longsizeTag },
744 { RPMTAG_LONGSIGSIZE, longsigsizeTag },
745 { RPMTAG_DBINSTANCE, dbinstanceTag },
746 { RPMTAG_EVR, evrTag },
747 { RPMTAG_NVR, nvrTag },
748 { RPMTAG_NEVR, nevrTag },
749 { RPMTAG_NVRA, nvraTag },
750 { RPMTAG_NEVRA, nevraTag },