/** \ingroup header * \file lib/formats.c */ #include "system.h" #include #include /* XXX for %_i18ndomains */ #include "misc.h" #include "debug.h" /** * Return ls-like formatted mode string. * @param mode file mode * @return formatted mode string (malloc'ed) */ static /*@only@*/ char * permsString(int mode) /*@*/ { char * perms = xmalloc(11); strcpy(perms, "-----------"); if (mode & S_ISVTX) perms[10] = 't'; /*@-unrecog@*/ if (mode & S_IRUSR) perms[1] = 'r'; if (mode & S_IWUSR) perms[2] = 'w'; if (mode & S_IXUSR) perms[3] = 'x'; if (mode & S_IRGRP) perms[4] = 'r'; if (mode & S_IWGRP) perms[5] = 'w'; if (mode & S_IXGRP) perms[6] = 'x'; if (mode & S_IROTH) perms[7] = 'r'; if (mode & S_IWOTH) perms[8] = 'w'; if (mode & S_IXOTH) perms[9] = 'x'; /*@=unrecog@*/ if (mode & S_ISUID) { if (mode & S_IXUSR) perms[3] = 's'; else perms[3] = 'S'; } if (mode & S_ISGID) { if (mode & S_IXGRP) perms[6] = 's'; else perms[6] = 'S'; } if (S_ISDIR(mode)) perms[0] = 'd'; else if (S_ISLNK(mode)) { perms[0] = 'l'; } else if (S_ISFIFO(mode)) perms[0] = 'p'; else if (S_ISSOCK(mode)) perms[0] = 'l'; else if (S_ISCHR(mode)) { perms[0] = 'c'; } else if (S_ISBLK(mode)) { perms[0] = 'b'; } return perms; } /** * @param type tag type * @param data tag value * @param formatPrefix (unused) * @param padding (unused) * @param element (unused) * @return formatted string */ static /*@only@*/ char * triggertypeFormat(int_32 type, const void * data, /*@unused@*/ char * formatPrefix, /*@unused@*/ int padding, /*@unused@*/ int element) /*@*/ { const int_32 * item = data; char * val; if (type != RPM_INT32_TYPE) { val = xstrdup(_("(not a number)")); } else if (*item & RPMSENSE_TRIGGERIN) { val = xstrdup("in"); } else { val = xstrdup("un"); } return val; } /** * @param type tag type * @param data tag value * @param formatPrefix * @param padding * @param element (unused) * @return formatted string */ static /*@only@*/ char * permsFormat(int_32 type, const void * data, char * formatPrefix, int padding, /*@unused@*/ int element) /*@modifies formatPrefix @*/ { char * val; char * buf; if (type != RPM_INT32_TYPE) { val = xstrdup(_("(not a number)")); } else { val = xmalloc(15 + padding); strcat(formatPrefix, "s"); buf = permsString(*((int_32 *) data)); sprintf(val, formatPrefix, buf); free(buf); } return val; } /** * @param type tag type * @param data tag value * @param formatPrefix * @param padding * @param element (unused) * @return formatted string */ static /*@only@*/ char * fflagsFormat(int_32 type, const void * data, char * formatPrefix, int padding, /*@unused@*/ int element) /*@modifies formatPrefix @*/ { char * val; char buf[15]; int anint = *((int_32 *) data); if (type != RPM_INT32_TYPE) { val = xstrdup(_("(not a number)")); } else { buf[0] = '\0'; if (anint & RPMFILE_DOC) strcat(buf, "d"); if (anint & RPMFILE_CONFIG) strcat(buf, "c"); if (anint & RPMFILE_SPECFILE) strcat(buf, "s"); if (anint & RPMFILE_MISSINGOK) strcat(buf, "m"); if (anint & RPMFILE_NOREPLACE) strcat(buf, "n"); if (anint & RPMFILE_GHOST) strcat(buf, "g"); val = xmalloc(5 + padding); strcat(formatPrefix, "s"); sprintf(val, formatPrefix, buf); } return val; } /** * @param type tag type * @param data tag value * @param formatPrefix * @param padding * @param element (unused) * @return formatted string */ static /*@only@*/ char * depflagsFormat(int_32 type, const void * data, char * formatPrefix, int padding, /*@unused@*/ int element) /*@modifies formatPrefix @*/ { char * val; char buf[10]; int anint = *((int_32 *) data); if (type != RPM_INT32_TYPE) { val = xstrdup(_("(not a number)")); } else { buf[0] = '\0'; if (anint & RPMSENSE_LESS) strcat(buf, "<"); if (anint & RPMSENSE_GREATER) strcat(buf, ">"); if (anint & RPMSENSE_EQUAL) strcat(buf, "="); val = xmalloc(5 + padding); strcat(formatPrefix, "s"); sprintf(val, formatPrefix, buf); } return val; } /** * @param h header * @retval type address of tag type * @retval data address of tag value pointer * @retval count address of no. of data items * @retval freedata address of data-was-malloc'ed indicator * @return 0 on success */ static int fsnamesTag( /*@unused@*/ Header h, /*@out@*/ int_32 * type, /*@out@*/ void ** data, /*@out@*/ int_32 * count, /*@out@*/ int * freeData) /*@modifies *type, *data, *count, *freeData @*/ { const char ** list; if (rpmGetFilesystemList(&list, count)) { return 1; } *type = RPM_STRING_ARRAY_TYPE; *((const char ***) data) = list; *freeData = 0; return 0; } /** * @param h header * @retval type address of tag type * @retval data address of tag value pointer * @retval count address of no. of data items * @retval freedata address of data-was-malloc'ed indicator * @return 0 on success */ static int instprefixTag(Header h, /*@out@*/ int_32 * type, /*@out@*/ const void ** data, /*@out@*/ int_32 * count, /*@out@*/ int * freeData) /*@modifies h, *type, *data, *count, *freeData @*/ { char ** array; if (headerGetEntry(h, RPMTAG_INSTALLPREFIX, type, (void **)data, count)) { *freeData = 0; return 0; } else if (headerGetEntry(h, RPMTAG_INSTPREFIXES, NULL, (void **) &array, count)) { *data = xstrdup(array[0]); *freeData = 1; *type = RPM_STRING_TYPE; free(array); return 0; } return 1; } /** * @param h header * @retval type address of tag type * @retval data address of tag value pointer * @retval count address of no. of data items * @retval freedata address of data-was-malloc'ed indicator * @return 0 on success */ static int fssizesTag(Header h, /*@out@*/ int_32 * type, /*@out@*/ const void ** data, /*@out@*/ int_32 * count, /*@out@*/ int * freeData) /*@modifies h, *type, *data, *count, *freeData @*/ { const char ** filenames; int_32 * filesizes; uint_32 * usages; int numFiles; if (!headerGetEntry(h, RPMTAG_FILESIZES, NULL, (void **) &filesizes, &numFiles)) { filesizes = NULL; numFiles = 0; filenames = NULL; } else { rpmBuildFileList(h, &filenames, &numFiles); } if (rpmGetFilesystemList(NULL, count)) { return 1; } *type = RPM_INT32_TYPE; *freeData = 1; if (filenames == NULL) { usages = xcalloc((*count), sizeof(usages)); *data = usages; return 0; } if (rpmGetFilesystemUsage(filenames, filesizes, numFiles, &usages, 0)) return 1; *data = usages; if (filenames) free(filenames); return 0; } /** * @param h header * @retval type address of tag type * @retval data address of tag value pointer * @retval count address of no. of data items * @retval freedata address of data-was-malloc'ed indicator * @return 0 on success */ static int triggercondsTag(Header h, /*@out@*/ int_32 * type, /*@out@*/ const void ** data, /*@out@*/ int_32 * count, /*@out@*/ int * freeData) /*@modifies h, *type, *data, *count, *freeData @*/ { int_32 * indices, * flags; char ** names, ** versions; int numNames, numScripts; char ** conds, ** s; char * item, * flagsStr; char * chptr; int i, j; char buf[5]; if (!headerGetEntry(h, RPMTAG_TRIGGERNAME, NULL, (void **) &names, &numNames)) { *freeData = 0; return 0; } headerGetEntry(h, RPMTAG_TRIGGERINDEX, NULL, (void **) &indices, NULL); headerGetEntry(h, RPMTAG_TRIGGERFLAGS, NULL, (void **) &flags, NULL); headerGetEntry(h, RPMTAG_TRIGGERVERSION, NULL, (void **) &versions, NULL); headerGetEntry(h, RPMTAG_TRIGGERSCRIPTS, NULL, (void **) &s, &numScripts); free(s); *freeData = 1; *data = conds = xmalloc(sizeof(char * ) * numScripts); *count = numScripts; *type = RPM_STRING_ARRAY_TYPE; for (i = 0; i < numScripts; i++) { chptr = xstrdup(""); for (j = 0; j < numNames; j++) { if (indices[j] != i) continue; item = xmalloc(strlen(names[j]) + strlen(versions[j]) + 20); if (flags[j] & RPMSENSE_SENSEMASK) { buf[0] = '%', buf[1] = '\0'; flagsStr = depflagsFormat(RPM_INT32_TYPE, flags, buf, 0, j); sprintf(item, "%s %s %s", names[j], flagsStr, versions[j]); free(flagsStr); } else { strcpy(item, names[j]); } chptr = xrealloc(chptr, strlen(chptr) + strlen(item) + 5); if (*chptr) strcat(chptr, ", "); strcat(chptr, item); free(item); } conds[i] = chptr; } free(names); free(versions); return 0; } /** * @param h header * @retval type address of tag type * @retval data address of tag value pointer * @retval count address of no. of data items * @retval freedata address of data-was-malloc'ed indicator * @return 0 on success */ static int triggertypeTag(Header h, /*@out@*/ int_32 * type, /*@out@*/ const void ** data, /*@out@*/ int_32 * count, /*@out@*/ int * freeData) /*@modifies h, *type, *data, *count, *freeData @*/ { int_32 * indices, * flags; char ** conds, ** s; int i, j; int numScripts, numNames; if (!headerGetEntry(h, RPMTAG_TRIGGERINDEX, NULL, (void **) &indices, &numNames)) { *freeData = 0; return 1; } headerGetEntry(h, RPMTAG_TRIGGERFLAGS, NULL, (void **) &flags, NULL); headerGetEntry(h, RPMTAG_TRIGGERSCRIPTS, NULL, (void **) &s, &numScripts); free(s); *freeData = 1; *data = conds = xmalloc(sizeof(char * ) * numScripts); *count = numScripts; *type = RPM_STRING_ARRAY_TYPE; for (i = 0; i < numScripts; i++) { for (j = 0; j < numNames; j++) { if (indices[j] != i) continue; if (flags[j] & RPMSENSE_TRIGGERIN) conds[i] = xstrdup("in"); else if (flags[j] & RPMSENSE_TRIGGERUN) conds[i] = xstrdup("un"); else conds[i] = xstrdup("postun"); break; } } return 0; } /** * @param h header * @retval type address of tag type * @retval data address of tag value pointer * @retval count address of no. of data items * @retval freedata address of data-was-malloc'ed indicator * @return 0 on success */ static int filenamesTag(Header h, /*@out@*/ int_32 * type, /*@out@*/ const void ** data, /*@out@*/ int_32 * count, /*@out@*/ int * freeData) /*@modifies *type, *data, *count, *freeData @*/ { *type = RPM_STRING_ARRAY_TYPE; rpmBuildFileList(h, (const char ***) data, count); *freeData = 1; *freeData = 0; /* XXX WTFO? */ return 0; } /* I18N look aside diversions */ int _nl_msg_cat_cntr; /* XXX GNU gettext voodoo */ static const char * language = "LANGUAGE"; static char * _macro_i18ndomains = "%{?_i18ndomains:%{_i18ndomains}}"; /** * @param h header * @param tag tag * @retval type address of tag type * @retval data address of tag value pointer * @retval count address of no. of data items * @retval freedata address of data-was-malloc'ed indicator * @return 0 on success */ static int i18nTag(Header h, int_32 tag, /*@out@*/ int_32 * type, /*@out@*/ const void ** data, /*@out@*/ int_32 * count, /*@out@*/ int * freeData) /*@modifies h, *type, *data, *count, *freeData @*/ { char * dstring = rpmExpand(_macro_i18ndomains, NULL); int rc; *type = RPM_STRING_TYPE; *data = NULL; *count = 0; *freeData = 0; if (dstring && *dstring) { char *domain, *de; const char * langval; const char * msgkey; const char * msgid; { const char * tn = tagName(tag); const char * n; char * mk; headerNVR(h, &n, NULL, NULL); mk = alloca(strlen(n) + strlen(tn) + sizeof("()")); sprintf(mk, "%s(%s)", n, tn); msgkey = mk; } /* change to en_US for msgkey -> msgid resolution */ langval = getenv(language); setenv(language, "en_US", 1); ++_nl_msg_cat_cntr; msgid = NULL; for (domain = dstring; domain != NULL; domain = de) { de = strchr(domain, ':'); if (de) *de++ = '\0'; msgid = /*@-unrecog@*/ dgettext(domain, msgkey) /*@=unrecog@*/; if (msgid != msgkey) break; } /* restore previous environment for msgid -> msgstr resolution */ if (langval) setenv(language, langval, 1); else unsetenv(language); ++_nl_msg_cat_cntr; if (domain && msgid) { *data = /*@-unrecog@*/ dgettext(domain, msgid) /*@=unrecog@*/; *data = xstrdup(*data); /* XXX xstrdup has side effects. */ *count = 1; *freeData = 1; } free(dstring); dstring = NULL; if (*data) { return 0; } } if (dstring) free(dstring); rc = headerGetEntry(h, tag, type, (void **)data, count); if (rc) { *data = xstrdup(*data); *freeData = 1; return 0; } *freeData = 0; *data = NULL; *count = 0; return 1; } /** * @param h header * @retval type address of tag type * @retval data address of tag value pointer * @retval count address of no. of data items * @retval freedata address of data-was-malloc'ed indicator * @return 0 on success */ static int summaryTag(Header h, /*@out@*/ int_32 * type, /*@out@*/ const void ** data, /*@out@*/ int_32 * count, /*@out@*/ int * freeData) /*@modifies h, *type, *data, *count, *freeData @*/ { return i18nTag(h, RPMTAG_SUMMARY, type, data, count, freeData); } /** * @param h header * @retval type address of tag type * @retval data address of tag value pointer * @retval count address of no. of data items * @retval freedata address of data-was-malloc'ed indicator * @return 0 on success */ static int descriptionTag(Header h, /*@out@*/ int_32 * type, /*@out@*/ const void ** data, /*@out@*/ int_32 * count, /*@out@*/ int * freeData) /*@modifies h, *type, *data, *count, *freeData @*/ { return i18nTag(h, RPMTAG_DESCRIPTION, type, data, count, freeData); } /** * @param h header * @retval type address of tag type * @retval data address of tag value pointer * @retval count address of no. of data items * @retval freedata address of data-was-malloc'ed indicator * @return 0 on success */ static int groupTag(Header h, /*@out@*/ int_32 * type, /*@out@*/ const void ** data, /*@out@*/ int_32 * count, /*@out@*/ int * freeData) /*@modifies h, *type, *data, *count, *freeData @*/ { return i18nTag(h, RPMTAG_GROUP, type, data, count, freeData); } const struct headerSprintfExtension rpmHeaderFormats[] = { { HEADER_EXT_TAG, "RPMTAG_GROUP", { groupTag } }, { HEADER_EXT_TAG, "RPMTAG_DESCRIPTION", { descriptionTag } }, { HEADER_EXT_TAG, "RPMTAG_SUMMARY", { summaryTag } }, { HEADER_EXT_TAG, "RPMTAG_FILENAMES", { filenamesTag } }, { HEADER_EXT_TAG, "RPMTAG_FSSIZES", { fssizesTag } }, { HEADER_EXT_TAG, "RPMTAG_FSNAMES", { fsnamesTag } }, { HEADER_EXT_TAG, "RPMTAG_INSTALLPREFIX", { instprefixTag } }, { HEADER_EXT_TAG, "RPMTAG_TRIGGERCONDS", { triggercondsTag } }, { HEADER_EXT_TAG, "RPMTAG_TRIGGERTYPE", { triggertypeTag } }, { HEADER_EXT_FORMAT, "depflags", { depflagsFormat } }, { HEADER_EXT_FORMAT, "fflags", { fflagsFormat } }, { HEADER_EXT_FORMAT, "perms", { permsFormat } }, { HEADER_EXT_FORMAT, "permissions", { permsFormat } }, { HEADER_EXT_FORMAT, "triggertype", { triggertypeFormat } }, { HEADER_EXT_MORE, NULL, { (void *) headerDefaultFormats } } } ;