609 lines
15 KiB
C
609 lines
15 KiB
C
#include "system.h"
|
|
|
|
/** \ingroup header
|
|
* \file lib/formats.c
|
|
*/
|
|
|
|
#include <rpmlib.h>
|
|
#include <rpmmacro.h> /* XXX for %_i18ndomains */
|
|
#include "misc.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 } }
|
|
} ;
|