rpm 5.3.12
|
00001 00005 #include "system.h" 00006 00007 /* XXX todo: these should likely be in "system.h" */ 00008 #if defined(HAVE_ICONV) 00009 #include <iconv.h> 00010 #if defined(__LCLINT__) 00011 /*@-declundef -exportheader -incondefs @*/ 00012 extern /*@only@*/ iconv_t iconv_open(const char *__tocode, const char *__fromcode) 00013 /*@*/; 00014 00015 extern size_t iconv(iconv_t __cd, /*@null@*/ char ** __inbuf, 00016 /*@out@*/ size_t * __inbytesleft, 00017 /*@out@*/ char ** __outbuf, 00018 /*@out@*/ size_t * __outbytesleft) 00019 /*@modifies __cd, 00020 *__inbuf, *__inbytesleft, *__outbuf, *__outbytesleft @*/; 00021 00022 extern int iconv_close(/*@only@*/ iconv_t __cd) 00023 /*@modifies __cd @*/; 00024 /*@=declundef =exportheader =incondefs @*/ 00025 #endif 00026 #endif 00027 00028 #if defined(HAVE_LANGINFO_H) 00029 #include <langinfo.h> 00030 #if defined(__LCLINT__) 00031 /*@-declundef -exportheader -incondefs @*/ 00032 extern char *nl_langinfo (nl_item __item) 00033 /*@*/; 00034 /*@=declundef =exportheader =incondefs @*/ 00035 #endif 00036 #endif 00037 00038 #define _MIRE_INTERNAL 00039 #include "rpmio_internal.h" 00040 #include <rpmbc.h> /* XXX beecrypt base64 */ 00041 #include <rpmcb.h> /* XXX rpmIsVerbose */ 00042 #include <rpmmacro.h> /* XXX for %_i18ndomains */ 00043 #include <rpmuuid.h> 00044 #include <argv.h> 00045 #include <ugid.h> 00046 00047 #define _RPMTAG_INTERNAL 00048 #include <rpmtag.h> 00049 #define _RPMEVR_INTERNAL 00050 #include <rpmevr.h> /* XXX RPMSENSE_FOO */ 00051 #include <rpmns.h> 00052 #include <rpmdb.h> 00053 00054 #include <rpmtypes.h> /* XXX rpmfi */ 00055 #include "misc.h" /* XXX rpmMkdirPath */ 00056 #include <rpmfi.h> /* XXX RPMFILE_FOO */ 00057 00058 #include "legacy.h" 00059 #include "misc.h" 00060 00061 #include "debug.h" 00062 00063 /*@unchecked@*/ 00064 int _hdrqf_debug; 00065 00066 /*@access pgpDig @*/ 00067 /*@access pgpDigParams @*/ 00068 /*@access headerSprintfExtension @*/ 00069 /*@access headerTagTableEntry @*/ 00070 /*@access Header @*/ /* XXX debugging msgs */ 00071 /*@access EVR_t @*/ 00072 /*@access rpmdb @*/ /* XXX for casts */ 00073 /*@access miRE @*/ 00074 00082 static char * intFormat(HE_t he, /*@unused@*/ /*@null@*/ const char ** av, 00083 /*@null@*/ const char *fmt) 00084 /*@*/ 00085 { 00086 rpmuint32_t ix = (he->ix > 0 ? he->ix : 0); 00087 rpmuint64_t ival = 0; 00088 const char * istr = NULL; 00089 char * b; 00090 size_t nb = 0; 00091 int xx; 00092 00093 if (fmt == NULL || *fmt == '\0') 00094 fmt = "d"; 00095 00096 switch (he->t) { 00097 default: 00098 return xstrdup(_("(not a number)")); 00099 /*@notreached@*/ break; 00100 case RPM_UINT8_TYPE: 00101 ival = (rpmuint64_t) he->p.ui8p[ix]; 00102 break; 00103 case RPM_UINT16_TYPE: 00104 ival = (rpmuint64_t) he->p.ui16p[ix]; 00105 break; 00106 case RPM_UINT32_TYPE: 00107 ival = (rpmuint64_t) he->p.ui32p[ix]; 00108 break; 00109 case RPM_UINT64_TYPE: 00110 ival = he->p.ui64p[ix]; 00111 break; 00112 case RPM_STRING_TYPE: 00113 istr = he->p.str; 00114 break; 00115 case RPM_STRING_ARRAY_TYPE: 00116 istr = he->p.argv[ix]; 00117 break; 00118 case RPM_BIN_TYPE: 00119 { static char hex[] = "0123456789abcdef"; 00120 const char * s = he->p.str; 00121 rpmTagCount c = he->c; 00122 char * t; 00123 00124 nb = 2 * c + 1; 00125 t = b = alloca(nb+1); 00126 while (c-- > 0) { 00127 unsigned i; 00128 i = (unsigned) *s++; 00129 *t++ = hex[ (i >> 4) & 0xf ]; 00130 *t++ = hex[ (i ) & 0xf ]; 00131 } 00132 *t = '\0'; 00133 } break; 00134 } 00135 00136 if (istr) { /* string */ 00137 b = (char *)istr; /* NOCAST */ 00138 } else 00139 if (nb == 0) { /* number */ 00140 char myfmt[] = "%llX"; 00141 myfmt[3] = ((fmt != NULL && *fmt != '\0') ? *fmt : 'd'); 00142 nb = 64; 00143 b = alloca(nb); 00144 /*@-formatconst@*/ 00145 xx = snprintf(b, nb, myfmt, ival); 00146 /*@=formatconst@*/ 00147 b[nb-1] = '\0'; 00148 } else 00149 b = ""; 00150 00151 return xstrdup(b); 00152 } 00153 00160 static char * octFormat(HE_t he, /*@null@*/ const char ** av) 00161 /*@*/ 00162 { 00163 return intFormat(he, av, "o"); 00164 } 00165 00172 static char * hexFormat(HE_t he, /*@null@*/ const char ** av) 00173 /*@*/ 00174 { 00175 return intFormat(he, av, "x"); 00176 } 00177 00184 static char * decFormat(HE_t he, /*@null@*/ const char ** av) 00185 /*@*/ 00186 { 00187 return intFormat(he, av, "d"); 00188 } 00189 00197 static char * realDateFormat(HE_t he, /*@unused@*/ /*@null@*/ const char ** av, 00198 const char * strftimeFormat) 00199 /*@*/ 00200 { 00201 char * val; 00202 00203 if (he->t != RPM_UINT64_TYPE) { 00204 val = xstrdup(_("(not a number)")); 00205 } else { 00206 struct tm * tstruct; 00207 char buf[50]; 00208 00209 /* this is important if sizeof(rpmuint64_t) ! sizeof(time_t) */ 00210 { time_t dateint = he->p.ui64p[0]; 00211 tstruct = localtime(&dateint); 00212 } 00213 buf[0] = '\0'; 00214 if (tstruct) 00215 (void) strftime(buf, sizeof(buf) - 1, strftimeFormat, tstruct); 00216 buf[sizeof(buf) - 1] = '\0'; 00217 val = xstrdup(buf); 00218 } 00219 00220 return val; 00221 } 00222 00229 static char * dateFormat(HE_t he, /*@null@*/ const char ** av) 00230 /*@*/ 00231 { 00232 return realDateFormat(he, av, _("%c")); 00233 } 00234 00241 static char * dayFormat(HE_t he, /*@null@*/ const char ** av) 00242 /*@*/ 00243 { 00244 return realDateFormat(he, av, _("%a %b %d %Y")); 00245 } 00246 00253 static char * shescapeFormat(HE_t he, /*@unused@*/ /*@null@*/ const char ** av) 00254 /*@*/ 00255 { 00256 char * val; 00257 size_t nb; 00258 int xx; 00259 00260 /* XXX one of these integer types is unnecessary. */ 00261 if (he->t == RPM_UINT32_TYPE) { 00262 nb = 20; 00263 val = xmalloc(nb); 00264 xx = snprintf(val, nb, "%u", (unsigned) he->p.ui32p[0]); 00265 val[nb-1] = '\0'; 00266 } else if (he->t == RPM_UINT64_TYPE) { 00267 nb = 40; 00268 val = xmalloc(40); 00269 /*@-duplicatequals@*/ 00270 xx = snprintf(val, nb, "%llu", (unsigned long long)he->p.ui64p[0]); 00271 /*@=duplicatequals@*/ 00272 val[nb-1] = '\0'; 00273 } else if (he->t == RPM_STRING_TYPE) { 00274 const char * s = he->p.str; 00275 char * t; 00276 int c; 00277 00278 nb = 0; 00279 for (s = he->p.str; (c = (int)*s) != 0; s++) { 00280 nb++; 00281 if (c == (int)'\'') 00282 nb += 3; 00283 } 00284 nb += 3; 00285 t = val = xmalloc(nb); 00286 *t++ = '\''; 00287 for (s = he->p.str; (c = (int)*s) != 0; s++) { 00288 if (c == (int)'\'') { 00289 *t++ = '\''; 00290 *t++ = '\\'; 00291 *t++ = '\''; 00292 } 00293 *t++ = (char) c; 00294 } 00295 *t++ = '\''; 00296 *t = '\0'; 00297 } else 00298 val = xstrdup(_("invalid type")); 00299 00300 return val; 00301 } 00302 00303 static struct headerSprintfExtension_s _headerDefaultFormats[] = { 00304 { HEADER_EXT_FORMAT, "octal", 00305 { .fmtFunction = octFormat } }, 00306 { HEADER_EXT_FORMAT, "oct", 00307 { .fmtFunction = octFormat } }, 00308 { HEADER_EXT_FORMAT, "hex", 00309 { .fmtFunction = hexFormat } }, 00310 { HEADER_EXT_FORMAT, "decimal", 00311 { .fmtFunction = decFormat } }, 00312 { HEADER_EXT_FORMAT, "dec", 00313 { .fmtFunction = decFormat } }, 00314 { HEADER_EXT_FORMAT, "date", 00315 { .fmtFunction = dateFormat } }, 00316 { HEADER_EXT_FORMAT, "day", 00317 { .fmtFunction = dayFormat } }, 00318 { HEADER_EXT_FORMAT, "shescape", 00319 { .fmtFunction = shescapeFormat } }, 00320 { HEADER_EXT_LAST, NULL, { NULL } } 00321 }; 00322 00323 headerSprintfExtension headerDefaultFormats = &_headerDefaultFormats[0]; 00324 00325 /*====================================================================*/ 00326 typedef const struct spew_s * spew_t; 00327 struct spew_s { 00328 /*@observer@*/ 00329 const char * spew_name; 00330 const char * spew_init; 00331 const char * spew_fini; 00332 size_t (*spew_strlen) (const char * s, int lvl) 00333 /*@*/; 00334 char * (*spew_strcpy) (/*@returned@*/ char * t, const char * s, int lvl) 00335 /*@modifies t @*/; 00336 }; 00337 00338 /*====================================================================*/ 00345 static size_t xmlstrlen(const char * s, /*@unused@*/ int lvl) 00346 /*@*/ 00347 { 00348 size_t len = 0; 00349 int c; 00350 00351 while ((c = (int) *s++) != (int) '\0') { 00352 switch (c) { 00353 case '<': 00354 case '>': len += sizeof("<") - 1; /*@switchbreak@*/ break; 00355 case '&': len += sizeof("&") - 1; /*@switchbreak@*/ break; 00356 default: len += 1; /*@switchbreak@*/ break; 00357 } 00358 } 00359 return len; 00360 } 00361 00369 static char * xmlstrcpy(/*@returned@*/ char * t, const char * s, 00370 /*@unused@*/ int lvl) 00371 /*@modifies t @*/ 00372 { 00373 char * te = t; 00374 int c; 00375 00376 while ((c = (int) *s++) != (int) '\0') { 00377 switch (c) { 00378 case '<': te = stpcpy(te, "<"); /*@switchbreak@*/ break; 00379 case '>': te = stpcpy(te, ">"); /*@switchbreak@*/ break; 00380 case '&': te = stpcpy(te, "&"); /*@switchbreak@*/ break; 00381 default: *te++ = (char) c; /*@switchbreak@*/ break; 00382 } 00383 } 00384 *te = '\0'; 00385 return t; 00386 } 00387 00388 /*@unchecked@*/ /*@observer@*/ 00389 static const struct spew_s _xml_spew = { 00390 .spew_name = "xml", 00391 .spew_init = "<rpmHeader>\n", 00392 .spew_fini = "</rpmHeader>\n", 00393 .spew_strlen = xmlstrlen, 00394 .spew_strcpy = xmlstrcpy 00395 }; 00396 00397 /*====================================================================*/ 00398 00405 static size_t yamlstrlen(const char * s, int lvl) 00406 /*@*/ 00407 { 00408 size_t len = 0; 00409 int indent = (lvl > 0); 00410 int c; 00411 00412 while ((c = (int) *s++) != (int) '\0') 00413 { 00414 if (indent) { 00415 len += 2 * lvl; 00416 indent = 0; 00417 } 00418 if (c == (int) '\n') 00419 indent = (lvl > 0); 00420 len++; 00421 } 00422 return len; 00423 } 00424 00432 static char * yamlstrcpy(/*@out@*/ /*@returned@*/ char * t, const char * s, 00433 int lvl) 00434 /*@modifies t @*/ 00435 { 00436 char * te = t; 00437 int indent = (lvl > 0); 00438 int c; 00439 00440 while ((c = (int) *s++) != (int) '\0') { 00441 if (indent) { 00442 int i; 00443 for (i = 0; i < lvl; i++) { 00444 *te++ = ' '; 00445 *te++ = ' '; 00446 } 00447 indent = 0; 00448 } 00449 if (c == (int) '\n') 00450 indent = (lvl > 0); 00451 *te++ = (char) c; 00452 } 00453 *te = '\0'; 00454 return t; 00455 } 00456 00457 /*@unchecked@*/ /*@observer@*/ 00458 static const struct spew_s _yaml_spew = { 00459 .spew_name = "yaml", 00460 .spew_init = "- !!omap\n", 00461 .spew_fini = "\n", 00462 .spew_strlen = yamlstrlen, 00463 .spew_strcpy = yamlstrcpy 00464 }; 00465 00466 /*====================================================================*/ 00467 00474 static size_t jsonstrlen(const char * s, /*@unused@*/ int lvl) 00475 /*@*/ 00476 { 00477 size_t len = 0; 00478 int c; 00479 00480 while ((c = (int) *s++) != (int) '\0') { 00481 switch (c) { 00482 case '\b': 00483 case '\t': 00484 case '\n': 00485 case '\v': 00486 case '\f': 00487 case '\r': 00488 case '\"': 00489 case '\'': len += 1; /*@fallthrough@*/ 00490 default: len += 1; /*@switchbreak@*/ break; 00491 } 00492 } 00493 return len; 00494 } 00495 00503 static char * jsonstrcpy(/*@returned@*/ char * t, const char * s, 00504 /*@unused@*/ int lvl) 00505 /*@modifies t @*/ 00506 { 00507 char * te = t; 00508 int c; 00509 00510 while ((c = (int) *s++) != (int) '\0') { 00511 switch (c) { 00512 case '\b': *te++ = '\\'; *te++ = 'b'; /*@switchbreak@*/ break; 00513 case '\t': *te++ = '\\'; *te++ = 't'; /*@switchbreak@*/ break; 00514 case '\n': *te++ = '\\'; *te++ = 'n'; /*@switchbreak@*/ break; 00515 case '\v': *te++ = '\\'; *te++ = 'v'; /*@switchbreak@*/ break; 00516 case '\f': *te++ = '\\'; *te++ = 'f'; /*@switchbreak@*/ break; 00517 case '\r': *te++ = '\\'; *te++ = 'r'; /*@switchbreak@*/ break; 00518 case '\"': *te++ = '\\'; *te++ = '"'; /*@switchbreak@*/ break; 00519 case '\'': *te++ = '\\'; *te++ = '\''; /*@switchbreak@*/ break; 00520 default: *te++ = (char) c; /*@switchbreak@*/ break; 00521 } 00522 } 00523 *te = '\0'; 00524 return t; 00525 } 00526 00527 /*@unchecked@*/ /*@observer@*/ 00528 static const struct spew_s _json_spew = { 00529 .spew_name = "json", 00530 .spew_init = "db.Packages.save({\n", 00531 .spew_fini = "});\n", 00532 .spew_strlen = jsonstrlen, 00533 .spew_strcpy = jsonstrcpy 00534 }; 00535 00536 /*====================================================================*/ 00537 00544 static size_t sqlstrlen(const char * s, /*@unused@*/ int lvl) 00545 /*@*/ 00546 { 00547 size_t len = 0; 00548 int c; 00549 00550 while ((c = (int) *s++) != (int) '\0') { 00551 switch (c) { 00552 case '\'': len += 1; /*@fallthrough@*/ 00553 default: len += 1; /*@switchbreak@*/ break; 00554 } 00555 } 00556 return len; 00557 } 00558 00566 static char * sqlstrcpy(/*@returned@*/ char * t, const char * s, 00567 /*@unused@*/ int lvl) 00568 /*@modifies t @*/ 00569 { 00570 char * te = t; 00571 int c; 00572 00573 while ((c = (int) *s++) != (int) '\0') { 00574 switch (c) { 00575 case '\'': *te++ = (char) c; /*@fallthrough@*/ 00576 default: *te++ = (char) c; /*@switchbreak@*/ break; 00577 } 00578 } 00579 *te = '\0'; 00580 return t; 00581 } 00582 00583 /*@unchecked@*/ /*@observer@*/ 00584 static const struct spew_s _sql_spew = { 00585 .spew_name = "sql", 00586 .spew_init = "", 00587 .spew_fini = "", 00588 .spew_strlen = sqlstrlen, 00589 .spew_strcpy = sqlstrcpy 00590 }; 00591 00592 /*====================================================================*/ 00593 00594 /* XXX FIXME: static for now, refactor from manifest.c later. */ 00595 static char * rpmPermsString(int mode) 00596 /*@*/ 00597 { 00598 char *perms = xstrdup("----------"); 00599 00600 if (S_ISREG(mode)) 00601 perms[0] = '-'; 00602 else if (S_ISDIR(mode)) 00603 perms[0] = 'd'; 00604 else if (S_ISLNK(mode)) 00605 perms[0] = 'l'; 00606 else if (S_ISFIFO(mode)) 00607 perms[0] = 'p'; 00608 /*@-unrecog@*/ 00609 else if (S_ISSOCK(mode)) 00610 perms[0] = 's'; 00611 /*@=unrecog@*/ 00612 else if (S_ISCHR(mode)) 00613 perms[0] = 'c'; 00614 else if (S_ISBLK(mode)) 00615 perms[0] = 'b'; 00616 else 00617 perms[0] = '?'; 00618 00619 if (mode & S_IRUSR) perms[1] = 'r'; 00620 if (mode & S_IWUSR) perms[2] = 'w'; 00621 if (mode & S_IXUSR) perms[3] = 'x'; 00622 00623 if (mode & S_IRGRP) perms[4] = 'r'; 00624 if (mode & S_IWGRP) perms[5] = 'w'; 00625 if (mode & S_IXGRP) perms[6] = 'x'; 00626 00627 if (mode & S_IROTH) perms[7] = 'r'; 00628 if (mode & S_IWOTH) perms[8] = 'w'; 00629 if (mode & S_IXOTH) perms[9] = 'x'; 00630 00631 if (mode & S_ISUID) 00632 perms[3] = ((mode & S_IXUSR) ? 's' : 'S'); 00633 00634 if (mode & S_ISGID) 00635 perms[6] = ((mode & S_IXGRP) ? 's' : 'S'); 00636 00637 if (mode & S_ISVTX) 00638 perms[9] = ((mode & S_IXOTH) ? 't' : 'T'); 00639 00640 return perms; 00641 } 00642 00649 static /*@only@*/ char * triggertypeFormat(HE_t he, /*@unused@*/ /*@null@*/ const char ** av) 00650 /*@*/ 00651 { 00652 int ix = (he->ix > 0 ? he->ix : 0); 00653 char * val; 00654 00655 assert(ix == 0); 00656 if (he->t != RPM_UINT64_TYPE) 00657 val = xstrdup(_("(invalid type)")); 00658 else { 00659 rpmuint64_t anint = he->p.ui64p[ix]; 00660 if (anint & RPMSENSE_TRIGGERPREIN) 00661 val = xstrdup("prein"); 00662 else if (anint & RPMSENSE_TRIGGERIN) 00663 val = xstrdup("in"); 00664 else if (anint & RPMSENSE_TRIGGERUN) 00665 val = xstrdup("un"); 00666 else if (anint & RPMSENSE_TRIGGERPOSTUN) 00667 val = xstrdup("postun"); 00668 else 00669 val = xstrdup(""); 00670 } 00671 return val; 00672 } 00673 00680 static /*@only@*/ char * permsFormat(HE_t he, /*@unused@*/ /*@null@*/ const char ** av) 00681 /*@*/ 00682 { 00683 int ix = (he->ix > 0 ? he->ix : 0); 00684 char * val; 00685 00686 assert(ix == 0); 00687 if (he->t != RPM_UINT64_TYPE) { 00688 val = xstrdup(_("(invalid type)")); 00689 } else { 00690 rpmuint64_t anint = he->p.ui64p[0]; 00691 val = rpmPermsString((int)anint); 00692 } 00693 00694 return val; 00695 } 00696 00703 static /*@only@*/ char * fflagsFormat(HE_t he, /*@unused@*/ /*@null@*/ const char ** av) 00704 /*@*/ 00705 { 00706 int ix = (he->ix >= 0 ? he->ix : 0); 00707 char * val; 00708 00709 assert(ix == 0); 00710 if (he->t != RPM_UINT64_TYPE) { 00711 val = xstrdup(_("(invalid type)")); 00712 } else { 00713 char buf[15]; 00714 rpmuint64_t anint = he->p.ui64p[ix]; 00715 buf[0] = '\0'; 00716 if (anint & RPMFILE_DOC) 00717 strcat(buf, "d"); 00718 if (anint & RPMFILE_CONFIG) 00719 strcat(buf, "c"); 00720 if (anint & RPMFILE_SPECFILE) 00721 strcat(buf, "s"); 00722 if (anint & RPMFILE_MISSINGOK) 00723 strcat(buf, "m"); 00724 if (anint & RPMFILE_NOREPLACE) 00725 strcat(buf, "n"); 00726 if (anint & RPMFILE_GHOST) 00727 strcat(buf, "g"); 00728 if (anint & RPMFILE_LICENSE) 00729 strcat(buf, "l"); 00730 if (anint & RPMFILE_README) 00731 strcat(buf, "r"); 00732 val = xstrdup(buf); 00733 } 00734 00735 return val; 00736 } 00737 00745 static /*@only@*/ char * armorFormat(HE_t he, /*@unused@*/ /*@null@*/ const char ** av) 00746 /*@*/ 00747 { 00748 int ix = (he->ix > 0 ? he->ix : 0); 00749 const char * enc; 00750 const unsigned char * s; 00751 size_t ns; 00752 rpmuint8_t atype; 00753 char * val; 00754 00755 assert(ix == 0); 00756 switch (he->t) { 00757 case RPM_BIN_TYPE: 00758 s = (unsigned char *) he->p.ui8p; 00759 ns = he->c; 00760 atype = (rpmuint8_t)PGPARMOR_SIGNATURE; /* XXX check pkt for signature */ 00761 break; 00762 case RPM_STRING_TYPE: 00763 case RPM_STRING_ARRAY_TYPE: 00764 enc = he->p.str; 00765 s = NULL; 00766 ns = 0; 00767 /*@-moduncon@*/ 00768 if (b64decode(enc, (void *)&s, &ns)) 00769 return xstrdup(_("(not base64)")); 00770 /*@=moduncon@*/ 00771 atype = (rpmuint8_t)PGPARMOR_PUBKEY; /* XXX check pkt for pubkey */ 00772 break; 00773 case RPM_UINT8_TYPE: 00774 case RPM_UINT16_TYPE: 00775 case RPM_UINT32_TYPE: 00776 case RPM_UINT64_TYPE: 00777 case RPM_I18NSTRING_TYPE: 00778 default: 00779 return xstrdup(_("(invalid type)")); 00780 /*@notreached@*/ break; 00781 } 00782 00783 val = pgpArmorWrap(atype, s, ns); 00784 if (atype == (rpmuint8_t)PGPARMOR_PUBKEY) 00785 s = _free(s); 00786 return val; 00787 } 00788 00796 static /*@only@*/ char * base64Format(HE_t he, /*@unused@*/ /*@null@*/ const char ** av) 00797 /*@*/ 00798 { 00799 int ix = (he->ix > 0 ? he->ix : 0); 00800 char * val; 00801 const char * enc; 00802 char * t; 00803 int lc; 00804 size_t ns; 00805 size_t nt; 00806 00807 assert(ix == 0); 00808 switch(he->t) { 00809 default: 00810 val = xstrdup(_("(invalid type :base64)")); 00811 goto exit; 00812 /*@notreached@*/ break; 00813 case RPM_UINT64_TYPE: 00814 ns = sizeof(he->p.ui64p[0]); 00815 break; 00816 case RPM_STRING_TYPE: 00817 ns = strlen(he->p.str); 00818 break; 00819 case RPM_BIN_TYPE: 00820 ns = he->c; 00821 break; 00822 } 00823 00824 nt = ((ns + 2) / 3) * 4; 00825 00826 /*@-globs@*/ 00827 /* Add additional bytes necessary for eol string(s). */ 00828 if (b64encode_chars_per_line > 0 && b64encode_eolstr != NULL) { 00829 lc = (nt + b64encode_chars_per_line - 1) / b64encode_chars_per_line; 00830 if (((nt + b64encode_chars_per_line - 1) % b64encode_chars_per_line) != 0) 00831 ++lc; 00832 nt += lc * strlen(b64encode_eolstr); 00833 } 00834 /*@=globs@*/ 00835 00836 val = t = xcalloc(1, nt + 1); 00837 *t = '\0'; 00838 00839 /* XXX b64encode accesses uninitialized memory. */ 00840 { unsigned char * _data = xcalloc(1, ns+1); 00841 assert(he->p.ptr != NULL); 00842 memcpy(_data, he->p.ptr, ns); 00843 /*@-moduncon@*/ 00844 if ((enc = b64encode(_data, ns)) != NULL) { 00845 t = stpcpy(t, enc); 00846 enc = _free(enc); 00847 } 00848 /*@=moduncon@*/ 00849 _data = _free(_data); 00850 } 00851 00852 exit: 00853 /*@-globstate@*/ /* b64encode_eolstr annotation */ 00854 return val; 00855 /*@=globstate@*/ 00856 } 00857 00858 /*====================================================================*/ 00859 00860 static /*@only@*/ /*@null@*/ char * 00861 strdup_locale_convert (/*@null@*/ const char * buffer, 00862 /*@null@*/ const char * tocode) 00863 /*@*/ 00864 { 00865 char *dest_str; 00866 #if defined(HAVE_ICONV) 00867 char *fromcode = NULL; 00868 iconv_t fd; 00869 00870 if (buffer == NULL) 00871 return NULL; 00872 00873 if (tocode == NULL) 00874 tocode = "UTF-8"; 00875 00876 #ifdef HAVE_LANGINFO_H 00877 fromcode = nl_langinfo (CODESET); 00878 #endif 00879 00880 if (fromcode != NULL && strcmp(tocode, fromcode) != 0 00881 && (fd = iconv_open(tocode, fromcode)) != (iconv_t)-1) 00882 { 00883 const char *pin = buffer; 00884 char *pout = NULL; 00885 size_t ib, ob, dest_size; 00886 int done; 00887 int is_error; 00888 size_t err; 00889 const char *shift_pin = NULL; 00890 int xx; 00891 00892 err = iconv(fd, NULL, &ib, &pout, &ob); 00893 dest_size = ob = ib = strlen(buffer); 00894 dest_str = pout = malloc((dest_size + 1) * sizeof(*dest_str)); 00895 if (dest_str) 00896 *dest_str = '\0'; 00897 done = is_error = 0; 00898 if (pout != NULL) 00899 while (done == 0 && is_error == 0) { 00900 err = iconv(fd, (char **)&pin, &ib, &pout, &ob); 00901 00902 if (err == (size_t)-1) { 00903 switch (errno) { 00904 case EINVAL: 00905 done = 1; 00906 /*@switchbreak@*/ break; 00907 case E2BIG: 00908 { size_t used = (size_t)(pout - dest_str); 00909 dest_size *= 2; 00910 dest_str = realloc(dest_str, (dest_size + 1) * sizeof(*dest_str)); 00911 if (dest_str == NULL) { 00912 is_error = 1; 00913 continue; 00914 } 00915 pout = dest_str + used; 00916 ob = dest_size - used; 00917 } /*@switchbreak@*/ break; 00918 case EILSEQ: 00919 is_error = 1; 00920 /*@switchbreak@*/ break; 00921 default: 00922 is_error = 1; 00923 /*@switchbreak@*/ break; 00924 } 00925 } else { 00926 if (shift_pin == NULL) { 00927 shift_pin = pin; 00928 pin = NULL; 00929 ib = 0; 00930 } else { 00931 done = 1; 00932 } 00933 } 00934 } 00935 xx = iconv_close(fd); 00936 if (pout) 00937 *pout = '\0'; 00938 if (dest_str != NULL) 00939 dest_str = xstrdup(dest_str); 00940 } else 00941 #endif 00942 { 00943 dest_str = xstrdup((buffer ? buffer : "")); 00944 } 00945 00946 return dest_str; 00947 } 00948 00955 static /*@only@*/ char * cdataFormat(HE_t he, /*@null@*/ const char ** av) 00956 /*@*/ 00957 { 00958 int ix = (he->ix > 0 ? he->ix : 0); 00959 char * val; 00960 int lvl = 0; 00961 spew_t spew = &_xml_spew; 00962 00963 assert(ix == 0); 00964 if (he->t != RPM_STRING_TYPE) { 00965 val = xstrdup(_("(not a string)")); 00966 } else { 00967 const char * s = strdup_locale_convert(he->p.str, (av ? av[0] : NULL)); 00968 size_t nb; 00969 char * t; 00970 00971 if (s == NULL) { 00972 /* XXX better error msg? */ 00973 val = xstrdup(_("(not a string)")); 00974 goto exit; 00975 } 00976 nb = spew->spew_strlen(s, lvl); 00977 val = t = xcalloc(1, nb + 1); 00978 t = spew->spew_strcpy(t, s, lvl); t += strlen(t); 00979 *t = '\0'; 00980 s = _free(s); 00981 } 00982 00983 exit: 00984 return val; 00985 } 00986 00993 static /*@only@*/ char * iconvFormat(HE_t he, /*@unused@*/ /*@null@*/ const char ** av) 00994 /*@*/ 00995 { 00996 int ix = (he->ix > 0 ? he->ix : 0); 00997 char * val = NULL; 00998 00999 assert(ix == 0); 01000 if (he->t == RPM_STRING_TYPE) 01001 val = strdup_locale_convert(he->p.str, (av ? av[0] : NULL)); 01002 if (val == NULL) 01003 val = xstrdup(_("(not a string)")); 01004 01005 return val; 01006 } 01007 01014 static /*@only@*/ char * xmlFormat(HE_t he, /*@unused@*/ /*@null@*/ const char ** av) 01015 /*@*/ 01016 { 01017 int ix = (he->ix > 0 ? he->ix : 0); 01018 const char * xtag = NULL; 01019 size_t nb; 01020 char * val; 01021 const char * s = NULL; 01022 char * t, * te; 01023 rpmuint64_t anint = 0; 01024 int freeit = 0; 01025 int xx; 01026 int lvl = 0; 01027 spew_t spew = &_xml_spew; 01028 01029 assert(ix == 0); 01030 assert(he->t == RPM_STRING_TYPE || he->t == RPM_UINT64_TYPE || he->t == RPM_BIN_TYPE); 01031 switch (he->t) { 01032 case RPM_STRING_ARRAY_TYPE: /* XXX currently never happens */ 01033 s = he->p.argv[ix]; 01034 xtag = "string"; 01035 /* XXX Force utf8 strings. */ 01036 s = xstrdup(s); 01037 s = xstrtolocale(s); 01038 freeit = 1; 01039 break; 01040 case RPM_I18NSTRING_TYPE: /* XXX currently never happens */ 01041 case RPM_STRING_TYPE: 01042 s = he->p.str; 01043 xtag = "string"; 01044 /* XXX Force utf8 strings. */ 01045 s = xstrdup(s); 01046 s = xstrtolocale(s); 01047 freeit = 1; 01048 break; 01049 case RPM_BIN_TYPE: 01050 /*@-globs -mods@*/ /* Don't bother annotating beecrypt global mods */ 01051 { int cpl = b64encode_chars_per_line; 01052 b64encode_chars_per_line = 0; 01053 /*@-formatconst@*/ 01054 s = base64Format(he, NULL); 01055 /*@=formatconst@*/ 01056 b64encode_chars_per_line = cpl; 01057 xtag = "base64"; 01058 freeit = 1; 01059 } break; 01060 /*@=globs =mods@*/ 01061 case RPM_UINT8_TYPE: 01062 anint = (rpmuint64_t)he->p.ui8p[ix]; 01063 break; 01064 case RPM_UINT16_TYPE: 01065 anint = (rpmuint64_t)he->p.ui16p[ix]; 01066 break; 01067 case RPM_UINT32_TYPE: 01068 anint = (rpmuint64_t)he->p.ui32p[ix]; 01069 break; 01070 case RPM_UINT64_TYPE: 01071 anint = he->p.ui64p[ix]; 01072 break; 01073 default: 01074 return xstrdup(_("(invalid xml type)")); 01075 /*@notreached@*/ break; 01076 } 01077 01078 if (s == NULL) { 01079 int tlen = 64; 01080 t = memset(alloca(tlen+1), 0, tlen+1); 01081 /*@-duplicatequals@*/ 01082 if (anint != 0) 01083 xx = snprintf(t, tlen, "%llu", (unsigned long long)anint); 01084 /*@=duplicatequals@*/ 01085 s = t; 01086 xtag = "integer"; 01087 } 01088 01089 nb = spew->spew_strlen(s, lvl); 01090 if (nb == 0) { 01091 nb += strlen(xtag) + sizeof("\t</>"); 01092 te = t = alloca(nb); 01093 te = stpcpy( stpcpy( stpcpy(te, "\t<"), xtag), "/>"); 01094 } else { 01095 nb += 2 * strlen(xtag) + sizeof("\t<></>"); 01096 te = t = alloca(nb); 01097 te = stpcpy( stpcpy( stpcpy(te, "\t<"), xtag), ">"); 01098 te = spew->spew_strcpy(te, s, lvl); 01099 te += strlen(te); 01100 te = stpcpy( stpcpy( stpcpy(te, "</"), xtag), ">"); 01101 } 01102 01103 if (freeit) 01104 s = _free(s); 01105 01106 val = xstrdup(t); 01107 01108 return val; 01109 } 01110 01117 static /*@only@*/ char * yamlFormat(HE_t he, /*@unused@*/ /*@null@*/ const char ** av) 01118 /*@*/ 01119 { 01120 int element = he->ix; 01121 int ix = (he->ix > 0 ? he->ix : 0); 01122 const char * xtag = NULL; 01123 int freetag = 0; 01124 size_t nb; 01125 char * val; 01126 const char * s = NULL; 01127 char * t, * te; 01128 rpmuint64_t anint = 0; 01129 int freeit = 0; 01130 int xx; 01131 int ls; 01132 int c; 01133 int lvl = 0; 01134 spew_t spew = &_yaml_spew; 01135 01136 assert(ix == 0); 01137 assert(he->t == RPM_STRING_TYPE || he->t == RPM_UINT64_TYPE || he->t == RPM_BIN_TYPE); 01138 xx = 0; 01139 ls = 0; 01140 switch (he->t) { 01141 case RPM_STRING_ARRAY_TYPE: /* XXX currently never happens */ 01142 case RPM_I18NSTRING_TYPE: /* XXX currently never happens */ 01143 case RPM_STRING_TYPE: 01144 s = (he->t == RPM_STRING_ARRAY_TYPE ? he->p.argv[ix] : he->p.str); 01145 if (strchr("[", s[0])) /* leading [ */ 01146 xx = 1; 01147 if (xx == 0) 01148 while ((c = (int) *s++) != (int) '\0') { 01149 switch (c) { 01150 default: 01151 continue; 01152 case '\n': /* multiline */ 01153 xx = 1; 01154 if (s[0] == ' ' || s[0] == '\t') /* leading space */ 01155 ls = 1; 01156 continue; 01157 case '-': /* leading "- \"" */ 01158 case ':': /* embedded ": " or ":" at EOL */ 01159 if (s[0] != ' ' && s[0] != '\0' && s[1] != '"') 01160 continue; 01161 xx = 1; 01162 /*@switchbreak@*/ break; 01163 } 01164 /*@loopbreak@*/ break; 01165 } 01166 if (xx) { 01167 if (ls) { /* leading spaces means we need to specify the indent */ 01168 xtag = xmalloc(strlen("- |##-\n") + 1); 01169 freetag = 1; 01170 if (element >= 0) { 01171 lvl = 3; 01172 sprintf((char *)xtag, "- |%d-\n", lvl); 01173 } else { 01174 lvl = 2; 01175 if (he->ix < 0) lvl++; /* XXX extra indent for array[1] */ 01176 sprintf((char *)xtag, "|%d-\n", lvl); 01177 } 01178 } else { 01179 if (element >= 0) { 01180 xtag = "- |-\n"; 01181 lvl = 3; 01182 } else { 01183 xtag = "|-\n"; 01184 lvl = 2; 01185 if (he->ix < 0) lvl++; /* XXX extra indent for array[1] */ 01186 } 01187 } 01188 } else { 01189 xtag = (element >= 0 ? "- " : NULL); 01190 } 01191 01192 /* XXX Force utf8 strings. */ 01193 s = xstrdup(he->p.str); 01194 s = xstrtolocale(s); 01195 freeit = 1; 01196 break; 01197 case RPM_BIN_TYPE: 01198 /*@-globs -mods@*/ /* Don't bother annotating beecrypt global mods */ 01199 { int cpl = b64encode_chars_per_line; 01200 b64encode_chars_per_line = 0; 01201 /*@-formatconst@*/ 01202 s = base64Format(he, NULL); 01203 element = -element; /* XXX skip " " indent. */ 01204 /*@=formatconst@*/ 01205 b64encode_chars_per_line = cpl; 01206 xtag = "!!binary "; 01207 freeit = 1; 01208 } break; 01209 /*@=globs =mods@*/ 01210 case RPM_UINT8_TYPE: 01211 anint = (rpmuint64_t)he->p.ui8p[ix]; 01212 break; 01213 case RPM_UINT16_TYPE: 01214 anint = (rpmuint64_t)he->p.ui16p[ix]; 01215 break; 01216 case RPM_UINT32_TYPE: 01217 anint = (rpmuint64_t)he->p.ui32p[ix]; 01218 break; 01219 case RPM_UINT64_TYPE: 01220 anint = he->p.ui64p[ix]; 01221 break; 01222 default: 01223 return xstrdup(_("(invalid yaml type)")); 01224 /*@notreached@*/ break; 01225 } 01226 01227 if (s == NULL) { 01228 int tlen = 64; 01229 t = memset(alloca(tlen+1), 0, tlen+1); 01230 /*@-duplicatequals@*/ 01231 xx = snprintf(t, tlen, "%llu", (unsigned long long)anint); 01232 /*@=duplicatequals@*/ 01233 s = t; 01234 xtag = (element >= 0 ? "- " : NULL); 01235 } 01236 01237 nb = spew->spew_strlen(s, lvl); 01238 if (nb == 0) { 01239 if (element >= 0) 01240 nb += sizeof(" ") - 1; 01241 nb += sizeof("- ~") - 1; 01242 nb++; 01243 te = t = alloca(nb); 01244 if (element >= 0) 01245 te = stpcpy(te, " "); 01246 te = stpcpy(te, "- ~"); 01247 } else { 01248 if (element >= 0) 01249 nb += sizeof(" ") - 1; 01250 if (xtag) 01251 nb += strlen(xtag); 01252 nb++; 01253 te = t = alloca(nb); 01254 if (element >= 0) 01255 te = stpcpy(te, " "); 01256 if (xtag) 01257 te = stpcpy(te, xtag); 01258 /*@-modobserver -observertrans -statictrans @*/ /* XXX LCL: can't see freetag flow */ 01259 if (freetag) 01260 xtag = _free(xtag); 01261 /*@=modobserver =observertrans =statictrans @*/ 01262 te = spew->spew_strcpy(te, s, lvl); 01263 te += strlen(te); 01264 } 01265 01266 /* XXX s was malloc'd */ 01267 if (freeit) 01268 s = _free(s); 01269 01270 val = xstrdup(t); 01271 01272 return val; 01273 } 01274 01281 static /*@only@*/ char * jsonFormat(HE_t he, /*@unused@*/ /*@null@*/ const char ** av) 01282 /*@*/ 01283 { 01284 int element = he->ix; 01285 int ix = (he->ix > 0 ? he->ix : 0); 01286 size_t nb; 01287 char * val; 01288 const char * s = NULL; 01289 char * t, * te; 01290 rpmuint64_t anint = 0; 01291 int freeit = 0; 01292 int xx = 0; 01293 int c; 01294 int lvl = 0; 01295 spew_t spew = &_json_spew; 01296 01297 assert(ix == 0); 01298 assert(he->t == RPM_STRING_TYPE || he->t == RPM_UINT64_TYPE || he->t == RPM_BIN_TYPE); 01299 xx = 0; 01300 switch (he->t) { 01301 case RPM_STRING_ARRAY_TYPE: /* XXX currently never happens */ 01302 case RPM_I18NSTRING_TYPE: /* XXX currently never happens */ 01303 case RPM_STRING_TYPE: 01304 s = (he->t == RPM_STRING_ARRAY_TYPE ? he->p.argv[ix] : he->p.str); 01305 /* XXX Force utf8 strings. */ 01306 s = xstrdup(he->p.str); 01307 s = xstrtolocale(s); 01308 freeit = 1; 01309 break; 01310 case RPM_BIN_TYPE: 01311 /*@-globs -mods@*/ /* Don't bother annotating beecrypt global mods */ 01312 { int cpl = b64encode_chars_per_line; 01313 b64encode_chars_per_line = 0; 01314 /*@-formatconst@*/ 01315 s = base64Format(he, NULL); 01316 element = -element; /* XXX skip " " indent. */ 01317 /*@=formatconst@*/ 01318 b64encode_chars_per_line = cpl; 01319 freeit = 1; 01320 } break; 01321 /*@=globs =mods@*/ 01322 case RPM_UINT8_TYPE: 01323 anint = (rpmuint64_t)he->p.ui8p[ix]; 01324 break; 01325 case RPM_UINT16_TYPE: 01326 anint = (rpmuint64_t)he->p.ui16p[ix]; 01327 break; 01328 case RPM_UINT32_TYPE: 01329 anint = (rpmuint64_t)he->p.ui32p[ix]; 01330 break; 01331 case RPM_UINT64_TYPE: 01332 anint = he->p.ui64p[ix]; 01333 break; 01334 default: 01335 return xstrdup(_("(invalid json type)")); 01336 /*@notreached@*/ break; 01337 } 01338 01339 if (s == NULL) { 01340 int tlen = 64; 01341 t = memset(alloca(tlen+1), 0, tlen+1); 01342 /*@-duplicatequals@*/ 01343 xx = snprintf(t, tlen, "%llu", (unsigned long long)anint); 01344 /*@=duplicatequals@*/ 01345 s = t; 01346 c = '\0'; 01347 } else 01348 c = '\''; 01349 01350 nb = spew->spew_strlen(s, lvl); 01351 if (c != '\0') 01352 nb += 2; 01353 nb += sizeof("\t,") - 1; 01354 te = t = alloca(nb); 01355 *te++ = '\t'; 01356 if (c != '\0') *te++ = c; 01357 if (nb) { 01358 te = spew->spew_strcpy(te, s, lvl); 01359 te += strlen(te); 01360 } 01361 if (c != '\0') *te++ = c; 01362 *te++ = ','; 01363 *te = '\0'; 01364 01365 /* XXX s was malloc'd */ 01366 if (freeit) 01367 s = _free(s); 01368 01369 val = xstrdup(t); 01370 01371 return val; 01372 } 01373 01374 /*====================================================================*/ 01375 01382 static /*@only@*/ char * pgpsigFormat(HE_t he, /*@unused@*/ /*@null@*/ const char ** av) 01383 /*@globals fileSystem, internalState @*/ 01384 /*@modifies fileSystem, internalState @*/ 01385 { 01386 int ix = (he->ix > 0 ? he->ix : 0); 01387 char * val, * t; 01388 01389 assert(ix == 0); 01390 if (!(he->t == RPM_BIN_TYPE)) { 01391 val = xstrdup(_("(not a blob)")); 01392 } else { 01393 rpmuint8_t * pkt = he->p.ui8p; 01394 unsigned int pktlen = 0; 01395 unsigned int v = (unsigned int) *pkt; 01396 pgpTag tag = 0; 01397 unsigned int plen; 01398 unsigned int hlen = 0; 01399 01400 if (v & 0x80) { 01401 if (v & 0x40) { 01402 tag = (v & 0x3f); 01403 plen = pgpLen(pkt+1, &hlen); 01404 } else { 01405 tag = (v >> 2) & 0xf; 01406 plen = (1 << (v & 0x3)); 01407 hlen = pgpGrab(pkt+1, plen); 01408 } 01409 01410 pktlen = 1 + plen + hlen; 01411 } 01412 01413 if (pktlen == 0 || tag != PGPTAG_SIGNATURE) { 01414 val = xstrdup(_("(not an OpenPGP signature)")); 01415 } else { 01416 pgpDig dig = pgpDigNew(RPMVSF_DEFAULT, 0); 01417 pgpDigParams sigp = pgpGetSignature(dig); 01418 size_t nb = 0; 01419 const char *tempstr; 01420 01421 (void) pgpPrtPkts(pkt, pktlen, dig, 0); 01422 01423 val = NULL; 01424 again: 01425 nb += 100; 01426 val = t = xrealloc(val, nb + 1); 01427 01428 switch (sigp->pubkey_algo) { 01429 case PGPPUBKEYALGO_DSA: 01430 t = stpcpy(t, "DSA"); 01431 break; 01432 case PGPPUBKEYALGO_RSA: 01433 t = stpcpy(t, "RSA"); 01434 break; 01435 default: 01436 (void) snprintf(t, nb - (t - val), "%u", (unsigned)sigp->pubkey_algo); 01437 t += strlen(t); 01438 break; 01439 } 01440 if (t + 5 >= val + nb) 01441 goto again; 01442 *t++ = '/'; 01443 switch (sigp->hash_algo) { 01444 case PGPHASHALGO_MD5: 01445 t = stpcpy(t, "MD5"); 01446 break; 01447 case PGPHASHALGO_SHA1: 01448 t = stpcpy(t, "SHA1"); 01449 break; 01450 default: 01451 (void) snprintf(t, nb - (t - val), "%u", (unsigned)sigp->hash_algo); 01452 t += strlen(t); 01453 break; 01454 } 01455 if (t + strlen (", ") + 1 >= val + nb) 01456 goto again; 01457 01458 t = stpcpy(t, ", "); 01459 01460 /* this is important if sizeof(rpmuint32_t) ! sizeof(time_t) */ 01461 { time_t dateint = pgpGrab(sigp->time, sizeof(sigp->time)); 01462 struct tm * tstruct = localtime(&dateint); 01463 if (tstruct) 01464 (void) strftime(t, (nb - (t - val)), "%c", tstruct); 01465 } 01466 t += strlen(t); 01467 if (t + strlen (", Key ID ") + 1 >= val + nb) 01468 goto again; 01469 t = stpcpy(t, ", Key ID "); 01470 tempstr = pgpHexStr(sigp->signid, sizeof(sigp->signid)); 01471 if (t + strlen (tempstr) > val + nb) 01472 goto again; 01473 t = stpcpy(t, tempstr); 01474 01475 dig = pgpDigFree(dig); 01476 } 01477 } 01478 01479 return val; 01480 } 01481 01488 static /*@only@*/ 01489 char * depflagsFormat(HE_t he, /*@unused@*/ /*@null@*/ const char ** av) 01490 /*@*/ 01491 { 01492 int ix = (he->ix > 0 ? he->ix : 0); 01493 char * val; 01494 01495 assert(ix == 0); 01496 if (he->t != RPM_UINT64_TYPE) { 01497 val = xstrdup(_("(invalid type)")); 01498 } else { 01499 rpmuint64_t anint = he->p.ui64p[ix]; 01500 char *t, *buf; 01501 01502 t = buf = alloca(32); 01503 *t = '\0'; 01504 01505 #ifdef NOTYET /* XXX appending markers breaks :depflags format. */ 01506 if (anint & RPMSENSE_SCRIPT_PRE) 01507 t = stpcpy(t, "(pre)"); 01508 else if (anint & RPMSENSE_SCRIPT_POST) 01509 t = stpcpy(t, "(post)"); 01510 else if (anint & RPMSENSE_SCRIPT_PREUN) 01511 t = stpcpy(t, "(preun)"); 01512 else if (anint & RPMSENSE_SCRIPT_POSTUN) 01513 t = stpcpy(t, "(postun)"); 01514 #endif 01515 if (anint & RPMSENSE_SENSEMASK) 01516 *t++ = ' '; 01517 if (anint & RPMSENSE_LESS) 01518 *t++ = '<'; 01519 if (anint & RPMSENSE_GREATER) 01520 *t++ = '>'; 01521 if (anint & RPMSENSE_EQUAL) 01522 *t++ = '='; 01523 if (anint & RPMSENSE_SENSEMASK) 01524 *t++ = ' '; 01525 *t = '\0'; 01526 01527 val = xstrdup(buf); 01528 } 01529 01530 return val; 01531 } 01532 01540 static /*@only@*/ 01541 char * deptypeFormat(HE_t he, /*@unused@*/ /*@null@*/ const char ** av) 01542 /*@*/ 01543 { 01544 int ix = (he->ix > 0 ? he->ix : 0); 01545 char * val; 01546 01547 assert(ix == 0); 01548 if (he->t != RPM_UINT64_TYPE) { 01549 val = xstrdup(_("(invalid type)")); 01550 } else { 01551 rpmuint64_t anint = he->p.ui64p[ix]; 01552 char *t, *buf; 01553 01554 t = buf = alloca(32); 01555 *t = '\0'; 01556 01557 if (anint & RPMSENSE_SCRIPT_PRE) 01558 t = stpcpy(t, "pre"); 01559 else if (anint & RPMSENSE_SCRIPT_POST) 01560 t = stpcpy(t, "post"); 01561 else if (anint & RPMSENSE_SCRIPT_PREUN) 01562 t = stpcpy(t, "preun"); 01563 else if (anint & RPMSENSE_SCRIPT_POSTUN) 01564 t = stpcpy(t, "postun"); 01565 else if (anint & RPMSENSE_SCRIPT_VERIFY) 01566 t = stpcpy(t, "verify"); 01567 else if (anint & RPMSENSE_RPMLIB) 01568 t = stpcpy(t, "rpmlib"); 01569 else if (anint & RPMSENSE_INTERP) 01570 t = stpcpy(t, "interp"); 01571 else if (anint & (RPMSENSE_FIND_PROVIDES | RPMSENSE_FIND_REQUIRES)) 01572 t = stpcpy(t, "auto"); 01573 else 01574 t = stpcpy(t, "manual"); 01575 *t = '\0'; 01576 01577 val = xstrdup(buf); 01578 } 01579 01580 return val; 01581 } 01582 01589 static int instprefixTag(Header h, HE_t he) 01590 /*@globals internalState @*/ 01591 /*@modifies he, internalState @*/ 01592 { 01593 he->tag = RPMTAG_INSTALLPREFIX; 01594 if (headerGet(h, he, 0)) 01595 return 0; 01596 01597 he->tag = RPMTAG_INSTPREFIXES; 01598 if (headerGet(h, he, 0)) { 01599 rpmTagData array = { .argv = he->p.argv }; 01600 he->t = RPM_STRING_TYPE; 01601 he->c = 1; 01602 he->p.str = xstrdup(array.argv[0]); 01603 he->freeData = 1; 01604 array.ptr = _free(array.ptr); 01605 return 0; 01606 } 01607 return 1; 01608 } 01609 01617 static int tv2uuidv1(/*@unused@*/ Header h, HE_t he, struct timeval *tv) 01618 /*@modifies he @*/ 01619 { 01620 rpmuint64_t uuid_time = ((rpmuint64_t)tv->tv_sec * 10000000) + 01621 (tv->tv_usec * 10) + 0x01B21DD213814000ULL; 01622 01623 he->t = RPM_BIN_TYPE; 01624 he->c = 128/8; 01625 he->p.ptr = xcalloc(1, he->c); 01626 he->freeData = 1; 01627 if (rpmuuidMake(1, NULL, NULL, NULL, (unsigned char *)he->p.ui8p)) { 01628 he->p.ptr = _free(he->p.ptr); 01629 he->freeData = 0; 01630 return 1; 01631 } 01632 01633 he->p.ui8p[6] &= 0xf0; /* preserve version, clear time_hi nibble */ 01634 he->p.ui8p[8] &= 0xc0; /* preserve variant, clear clock */ 01635 he->p.ui8p[9] &= 0x00; 01636 01637 he->p.ui8p[3] = (rpmuint8_t)(uuid_time >> 0); 01638 he->p.ui8p[2] = (rpmuint8_t)(uuid_time >> 8); 01639 he->p.ui8p[1] = (rpmuint8_t)(uuid_time >> 16); 01640 he->p.ui8p[0] = (rpmuint8_t)(uuid_time >> 24); 01641 he->p.ui8p[5] = (rpmuint8_t)(uuid_time >> 32); 01642 he->p.ui8p[4] = (rpmuint8_t)(uuid_time >> 40); 01643 he->p.ui8p[6] |= (rpmuint8_t)(uuid_time >> 56) & 0x0f; 01644 01645 #ifdef NOTYET 01646 /* XXX Jigger up a non-zero (but constant) clock value. Is this needed? */ 01647 he->p.ui8p[8] |= (he->p.ui8p[2] & 0x3f); 01648 he->p.ui8p[9] |= he->p.ui8p[3] 01649 #endif 01650 01651 return 0; 01652 } 01653 01660 static int tag2uuidv1(Header h, HE_t he) 01661 /*@globals internalState @*/ 01662 /*@modifies he, internalState @*/ 01663 { 01664 struct timeval tv; 01665 01666 if (!headerGet(h, he, 0)) 01667 return 1; 01668 tv.tv_sec = (long) he->p.ui32p[0]; 01669 tv.tv_usec = (long) (he->c > 1 ? he->p.ui32p[1] : 0); 01670 he->p.ptr = _free(he->p.ptr); 01671 return tv2uuidv1(h, he, &tv); 01672 } 01673 01680 static int installtime_uuidTag(Header h, HE_t he) 01681 /*@globals internalState @*/ 01682 /*@modifies he, internalState @*/ 01683 { 01684 he->tag = RPMTAG_INSTALLTIME; 01685 return tag2uuidv1(h, he); 01686 } 01687 01694 static int buildtime_uuidTag(Header h, HE_t he) 01695 /*@globals internalState @*/ 01696 /*@modifies he, internalState @*/ 01697 { 01698 he->tag = RPMTAG_BUILDTIME; 01699 return tag2uuidv1(h, he); 01700 } 01701 01708 static int origintime_uuidTag(Header h, HE_t he) 01709 /*@globals internalState @*/ 01710 /*@modifies he, internalState @*/ 01711 { 01712 he->tag = RPMTAG_ORIGINTIME; 01713 return tag2uuidv1(h, he); 01714 } 01715 01722 static int installtid_uuidTag(Header h, HE_t he) 01723 /*@globals internalState @*/ 01724 /*@modifies he, internalState @*/ 01725 { 01726 he->tag = RPMTAG_INSTALLTID; 01727 return tag2uuidv1(h, he); 01728 } 01729 01736 static int removetid_uuidTag(Header h, HE_t he) 01737 /*@globals internalState @*/ 01738 /*@modifies he, internalState @*/ 01739 { 01740 he->tag = RPMTAG_REMOVETID; 01741 return tag2uuidv1(h, he); 01742 } 01743 01750 static int origintid_uuidTag(Header h, HE_t he) 01751 /*@globals internalState @*/ 01752 /*@modifies he, internalState @*/ 01753 { 01754 he->tag = RPMTAG_ORIGINTID; 01755 return tag2uuidv1(h, he); 01756 } 01757 01758 /*@unchecked@*/ /*@observer@*/ 01759 static const char uuid_ns[] = "ns:URL"; 01760 /*@unchecked@*/ /*@observer@*/ 01761 static const char uuid_auth[] = "%{?_uuid_auth}%{!?_uuid_auth:http://rpm5.org}"; 01762 /*@unchecked@*/ /*@observer@*/ 01763 static const char uuid_path[] = "%{?_uuid_path}%{!?_uuid_path:/package}"; 01764 /*@unchecked@*/ 01765 static rpmuint32_t uuid_version = 5; 01766 01775 static int str2uuid(HE_t he, /*@unused@*/ /*@null@*/ const char ** av, 01776 rpmuint32_t version, char * val) 01777 /*@globals rpmGlobalMacroContext, h_errno, internalState @*/ 01778 /*@modifies he, rpmGlobalMacroContext, internalState @*/ 01779 { 01780 const char * ns = NULL; 01781 const char * tagn = tagName(he->tag); 01782 const char * s = NULL; 01783 char * t = (val ? val : alloca(40)); 01784 int rc; 01785 01786 /* XXX Substitute Pkgid & Hdrid strings for aliases. */ 01787 if (!strcmp("Sigmd5", tagn)) 01788 tagn = "Pkgid"; 01789 else if (!strcmp("Sha1header", tagn)) 01790 tagn = "Hdrid"; 01791 01792 switch (version) { 01793 default: 01794 version = uuid_version; 01795 /*@fallthrough@*/ 01796 case 3: 01797 case 5: 01798 assert(he->t == RPM_STRING_TYPE); 01799 ns = uuid_ns; 01800 s = rpmGetPath(uuid_auth, "/", uuid_path, "/", tagn, "/", 01801 he->p.str, NULL); 01802 /*@fallthrough@*/ 01803 case 4: 01804 break; 01805 } 01806 he->p.ptr = _free(he->p.ptr); 01807 he->t = RPM_BIN_TYPE; 01808 he->c = 128/8; 01809 he->p.ptr = xcalloc(1, he->c); 01810 he->freeData = 1; 01811 rc = rpmuuidMake((int)version, ns, s, t, (unsigned char *)he->p.ui8p); 01812 if (rc) { 01813 he->p.ptr = _free(he->p.ptr); 01814 he->freeData = 0; 01815 } 01816 s = _free(s); 01817 01818 return rc; 01819 } 01820 01827 static int tag2uuidv5(Header h, HE_t he) 01828 /*@globals rpmGlobalMacroContext, h_errno, internalState @*/ 01829 /*@modifies he, rpmGlobalMacroContext, internalState @*/ 01830 { 01831 if (!headerGet(h, he, 0)) 01832 return 1; 01833 switch (he->t) { 01834 default: 01835 assert(0); 01836 /*@notreached@*/ break; 01837 case RPM_BIN_TYPE: { /* Convert RPMTAG_PKGID from binary => hex. */ 01838 static const char hex[] = "0123456789abcdef"; 01839 char * t; 01840 char * te; 01841 rpmuint32_t i; 01842 01843 t = te = xmalloc (2*he->c + 1); 01844 for (i = 0; i < he->c; i++) { 01845 *te++ = hex[ (int)((he->p.ui8p[i] >> 4) & 0x0f) ]; 01846 *te++ = hex[ (int)((he->p.ui8p[i] ) & 0x0f) ]; 01847 } 01848 *te = '\0'; 01849 he->p.ptr = _free(he->p.ptr); 01850 he->t = RPM_STRING_TYPE; 01851 he->p.ptr = t; 01852 he->c = 1; 01853 he->freeData = 1; 01854 } break; 01855 case RPM_STRING_TYPE: 01856 break; 01857 } 01858 return str2uuid(he, NULL, 0, NULL); 01859 } 01860 01867 static int pkguuidTag(Header h, HE_t he) 01868 /*@globals rpmGlobalMacroContext, h_errno, internalState @*/ 01869 /*@modifies he, rpmGlobalMacroContext, internalState @*/ 01870 { 01871 he->tag = RPMTAG_PKGID; 01872 return tag2uuidv5(h, he); 01873 } 01874 01881 static int sourcepkguuidTag(Header h, HE_t he) 01882 /*@globals rpmGlobalMacroContext, h_errno, internalState @*/ 01883 /*@modifies he, rpmGlobalMacroContext, internalState @*/ 01884 { 01885 he->tag = RPMTAG_SOURCEPKGID; 01886 return tag2uuidv5(h, he); 01887 } 01888 01895 static int hdruuidTag(Header h, HE_t he) 01896 /*@globals rpmGlobalMacroContext, h_errno, internalState @*/ 01897 /*@modifies he, rpmGlobalMacroContext, internalState @*/ 01898 { 01899 he->tag = RPMTAG_HDRID; 01900 return tag2uuidv5(h, he); 01901 } 01902 01909 static int triggercondsTag(Header h, HE_t he) 01910 /*@globals internalState @*/ 01911 /*@modifies he, internalState @*/ 01912 { 01913 HE_t _he = memset(alloca(sizeof(*_he)), 0, sizeof(*_he)); 01914 HE_t Fhe = memset(alloca(sizeof(*Fhe)), 0, sizeof(*Fhe)); 01915 HE_t Ihe = memset(alloca(sizeof(*Ihe)), 0, sizeof(*Ihe)); 01916 HE_t Nhe = memset(alloca(sizeof(*Nhe)), 0, sizeof(*Nhe)); 01917 HE_t Vhe = memset(alloca(sizeof(*Vhe)), 0, sizeof(*Vhe)); 01918 HE_t She = memset(alloca(sizeof(*She)), 0, sizeof(*She)); 01919 rpmuint64_t anint; 01920 unsigned i, j; 01921 int rc = 1; /* assume failure */ 01922 int xx; 01923 01924 he->freeData = 0; 01925 01926 Nhe->tag = RPMTAG_TRIGGERNAME; 01927 xx = headerGet(h, Nhe, 0); 01928 if (!xx) { /* no triggers, succeed anyways */ 01929 rc = 0; 01930 goto exit; 01931 } 01932 01933 Ihe->tag = RPMTAG_TRIGGERINDEX; 01934 xx = headerGet(h, Ihe, 0); 01935 if (!xx) goto exit; 01936 01937 Fhe->tag = RPMTAG_TRIGGERFLAGS; 01938 xx = headerGet(h, Fhe, 0); 01939 if (!xx) goto exit; 01940 01941 Vhe->tag = RPMTAG_TRIGGERVERSION; 01942 xx = headerGet(h, Vhe, 0); 01943 if (!xx) goto exit; 01944 01945 She->tag = RPMTAG_TRIGGERSCRIPTS; 01946 xx = headerGet(h, She, 0); 01947 if (!xx) goto exit; 01948 01949 _he->tag = he->tag; 01950 _he->t = RPM_UINT64_TYPE; 01951 _he->p.ui64p = &anint; 01952 _he->c = 1; 01953 _he->freeData = 0; 01954 01955 he->t = RPM_STRING_ARRAY_TYPE; 01956 he->c = She->c; 01957 01958 he->freeData = 1; 01959 he->p.argv = xmalloc(sizeof(*he->p.argv) * he->c); 01960 for (i = 0; i < (unsigned) he->c; i++) { 01961 char * item, * flagsStr; 01962 char * chptr; 01963 01964 chptr = xstrdup(""); 01965 01966 for (j = 0; j < Nhe->c; j++) { 01967 if (Ihe->p.ui32p[j] != i) 01968 /*@innercontinue@*/ continue; 01969 01970 item = xmalloc(strlen(Nhe->p.argv[j]) + strlen(Vhe->p.argv[j]) + 20); 01971 /*@-compmempass@*/ /* use separate HE_t, not rpmTagData, containers. */ 01972 if (Fhe->p.ui32p[j] & RPMSENSE_SENSEMASK) { 01973 anint = Fhe->p.ui32p[j]; 01974 flagsStr = depflagsFormat(_he, NULL); 01975 sprintf(item, "%s%s%s", Nhe->p.argv[j], flagsStr, Vhe->p.argv[j]); 01976 flagsStr = _free(flagsStr); 01977 } else 01978 strcpy(item, Nhe->p.argv[j]); 01979 /*@=compmempass@*/ 01980 01981 chptr = xrealloc(chptr, strlen(chptr) + strlen(item) + 5); 01982 if (*chptr != '\0') strcat(chptr, ", "); 01983 strcat(chptr, item); 01984 item = _free(item); 01985 } 01986 01987 he->p.argv[i] = chptr; 01988 } 01989 rc = 0; 01990 01991 exit: 01992 Ihe->p.ptr = _free(Ihe->p.ptr); 01993 Fhe->p.ptr = _free(Fhe->p.ptr); 01994 Nhe->p.ptr = _free(Nhe->p.ptr); 01995 Vhe->p.ptr = _free(Vhe->p.ptr); 01996 She->p.ptr = _free(She->p.ptr); 01997 01998 return rc; 01999 } 02000 02007 static int triggertypeTag(Header h, HE_t he) 02008 /*@globals internalState @*/ 02009 /*@modifies he, internalState @*/ 02010 { 02011 HE_t _he = memset(alloca(sizeof(*_he)), 0, sizeof(*_he)); 02012 rpmTagData indices = { .ptr = NULL }; 02013 rpmTagData flags = { .ptr = NULL }; 02014 rpmTagData s = { .ptr = NULL }; 02015 rpmTagCount numNames; 02016 rpmTagCount numScripts; 02017 unsigned i, j; 02018 int rc = 1; /* assume failure */ 02019 int xx; 02020 02021 he->freeData = 0; 02022 02023 /*@-compmempass@*/ /* use separate HE_t, not rpmTagData, containers. */ 02024 _he->tag = RPMTAG_TRIGGERINDEX; 02025 xx = headerGet(h, _he, 0); 02026 if (!xx) goto exit; 02027 indices.ui32p = _he->p.ui32p; 02028 numNames = _he->c; 02029 02030 _he->tag = RPMTAG_TRIGGERFLAGS; 02031 xx = headerGet(h, _he, 0); 02032 if (!xx) goto exit; 02033 flags.ui32p = _he->p.ui32p; 02034 02035 _he->tag = RPMTAG_TRIGGERSCRIPTS; 02036 xx = headerGet(h, _he, 0); 02037 if (!xx) goto exit; 02038 s.argv = _he->p.argv; 02039 numScripts = _he->c; 02040 /*@=compmempass@*/ 02041 02042 he->t = RPM_STRING_ARRAY_TYPE; 02043 he->c = numScripts; 02044 02045 he->freeData = 1; 02046 he->p.argv = xmalloc(sizeof(*he->p.argv) * he->c); 02047 for (i = 0; i < (unsigned) he->c; i++) { 02048 for (j = 0; j < (unsigned) numNames; j++) { 02049 if (indices.ui32p[j] != i) 02050 /*@innercontinue@*/ continue; 02051 02052 /* XXX FIXME: there's memory leaks here. */ 02053 if (flags.ui32p[j] & RPMSENSE_TRIGGERPREIN) 02054 he->p.argv[i] = xstrdup("prein"); 02055 else if (flags.ui32p[j] & RPMSENSE_TRIGGERIN) 02056 he->p.argv[i] = xstrdup("in"); 02057 else if (flags.ui32p[j] & RPMSENSE_TRIGGERUN) 02058 he->p.argv[i] = xstrdup("un"); 02059 else if (flags.ui32p[j] & RPMSENSE_TRIGGERPOSTUN) 02060 he->p.argv[i] = xstrdup("postun"); 02061 else 02062 he->p.argv[i] = xstrdup(""); 02063 /*@innerbreak@*/ break; 02064 } 02065 } 02066 rc = 0; 02067 02068 exit: 02069 indices.ptr = _free(indices.ptr); 02070 flags.ptr = _free(flags.ptr); 02071 s.ptr = _free(s.ptr); 02072 return 0; 02073 } 02074 02075 /* I18N look aside diversions */ 02076 02077 #if defined(ENABLE_NLS) 02078 /*@-exportlocal -exportheadervar@*/ 02079 /*@unchecked@*/ 02080 extern int _nl_msg_cat_cntr; /* XXX GNU gettext voodoo */ 02081 /*@=exportlocal =exportheadervar@*/ 02082 #endif 02083 /*@observer@*/ /*@unchecked@*/ 02084 static const char * language = "LANGUAGE"; 02085 02086 /*@observer@*/ /*@unchecked@*/ 02087 static const char * _macro_i18ndomains = "%{?_i18ndomains}"; 02088 02095 static int i18nTag(Header h, HE_t he) 02096 /*@globals rpmGlobalMacroContext, h_errno, internalState @*/ 02097 /*@modifies he, rpmGlobalMacroContext, internalState @*/ 02098 { 02099 char * dstring = rpmExpand(_macro_i18ndomains, NULL); 02100 int rc = 1; /* assume failure */ 02101 02102 he->t = RPM_STRING_TYPE; 02103 he->p.str = NULL; 02104 he->c = 0; 02105 he->freeData = 0; 02106 02107 if (dstring && *dstring) { 02108 char *domain, *de; 02109 const char * langval; 02110 const char * msgkey; 02111 const char * msgid; 02112 02113 { HE_t nhe = memset(alloca(sizeof(*nhe)), 0, sizeof(*nhe)); 02114 const char * tn; 02115 char * mk; 02116 size_t nb = sizeof("()"); 02117 int xx; 02118 02119 nhe->tag = RPMTAG_NAME; 02120 xx = headerGet(h, nhe, 0); 02121 /* 02122 * XXX Ick, tagName() is called by headerGet(), and the tagName() 02123 * buffer is valid only until next tagName() call. 02124 * For now, do the tagName() lookup after headerGet(). 02125 */ 02126 tn = tagName(he->tag); 02127 if (tn) nb += strlen(tn); 02128 if (nhe->p.str) nb += strlen(nhe->p.str); 02129 mk = alloca(nb); 02130 (void) snprintf(mk, nb, "%s(%s)", 02131 (nhe->p.str ? nhe->p.str : ""), (tn ? tn : "")); 02132 mk[nb-1] = '\0'; 02133 nhe->p.ptr = _free(nhe->p.ptr); 02134 msgkey = mk; 02135 } 02136 02137 /* change to en_US for msgkey -> msgid resolution */ 02138 langval = getenv(language); 02139 (void) setenv(language, "en_US", 1); 02140 #if defined(ENABLE_NLS) 02141 /*@i@*/ ++_nl_msg_cat_cntr; 02142 #endif 02143 02144 msgid = NULL; 02145 for (domain = dstring; domain != NULL; domain = de) { 02146 de = strchr(domain, ':'); 02147 if (de) *de++ = '\0'; 02148 /*@-unrecog@*/ 02149 msgid = dgettext(domain, msgkey); 02150 /*@=unrecog@*/ 02151 if (msgid != msgkey) break; 02152 } 02153 02154 /* restore previous environment for msgid -> msgstr resolution */ 02155 if (langval) 02156 (void) setenv(language, langval, 1); 02157 else 02158 unsetenv(language); 02159 #if defined(ENABLE_NLS) 02160 /*@i@*/ ++_nl_msg_cat_cntr; 02161 #endif 02162 02163 if (domain && msgid) { 02164 /*@-unrecog@*/ 02165 const char * s = dgettext(domain, msgid); 02166 /*@=unrecog@*/ 02167 if (s) { 02168 rc = 0; 02169 he->p.str = xstrdup(s); 02170 he->c = 1; 02171 he->freeData = 1; 02172 } 02173 } 02174 } 02175 02176 /*@-dependenttrans@*/ 02177 dstring = _free(dstring); 02178 /*@=dependenttrans@*/ 02179 if (!rc) 02180 return rc; 02181 02182 rc = headerGet(h, he, HEADERGET_NOEXTENSION); 02183 if (rc) { 02184 rc = 0; 02185 he->p.str = xstrtolocale(he->p.str); 02186 he->freeData = 1; 02187 return rc; 02188 } 02189 02190 he->t = RPM_STRING_TYPE; 02191 he->p.str = NULL; 02192 he->c = 0; 02193 he->freeData = 0; 02194 02195 return 1; 02196 } 02197 02201 static int localeTag(Header h, HE_t he) 02202 /*@globals internalState @*/ 02203 /*@modifies he, internalState @*/ 02204 { 02205 int rc; 02206 02207 rc = headerGet(h, he, HEADERGET_NOEXTENSION); 02208 if (!rc || he->p.str == NULL || he->c == 0) { 02209 he->t = RPM_STRING_TYPE; 02210 he->freeData = 0; 02211 return 1; 02212 } 02213 02214 switch (he->t) { 02215 default: 02216 he->freeData = 0; 02217 break; 02218 case RPM_STRING_TYPE: 02219 he->p.str = xstrtolocale(he->p.str); 02220 he->freeData = 1; 02221 break; 02222 case RPM_STRING_ARRAY_TYPE: 02223 { const char ** argv; 02224 char * te; 02225 size_t l = 0; 02226 unsigned i; 02227 for (i = 0; i < (unsigned) he->c; i++) { 02228 he->p.argv[i] = xstrdup(he->p.argv[i]); 02229 he->p.argv[i] = xstrtolocale(he->p.argv[i]); 02230 assert(he->p.argv[i] != NULL); 02231 l += strlen(he->p.argv[i]) + 1; 02232 } 02233 argv = xmalloc(he->c * sizeof(*argv) + l); 02234 te = (char *)&argv[he->c]; 02235 for (i = 0; i < (unsigned) he->c; i++) { 02236 argv[i] = te; 02237 te = stpcpy(te, he->p.argv[i]); 02238 te++; 02239 he->p.argv[i] = _free(he->p.argv[i]); 02240 } 02241 he->p.ptr = _free(he->p.ptr); 02242 he->p.argv = argv; 02243 he->freeData = 1; 02244 } break; 02245 } 02246 02247 return 0; 02248 } 02249 02256 static int summaryTag(Header h, HE_t he) 02257 /*@globals rpmGlobalMacroContext, h_errno, internalState @*/ 02258 /*@modifies he, rpmGlobalMacroContext, internalState @*/ 02259 { 02260 he->tag = RPMTAG_SUMMARY; 02261 return i18nTag(h, he); 02262 } 02263 02270 static int descriptionTag(Header h, HE_t he) 02271 /*@globals rpmGlobalMacroContext, h_errno, internalState @*/ 02272 /*@modifies he, rpmGlobalMacroContext, internalState @*/ 02273 { 02274 he->tag = RPMTAG_DESCRIPTION; 02275 return i18nTag(h, he); 02276 } 02277 02278 static int changelognameTag(Header h, HE_t he) 02279 /*@globals internalState @*/ 02280 /*@modifies he, internalState @*/ 02281 { 02282 he->tag = RPMTAG_CHANGELOGNAME; 02283 return localeTag(h, he); 02284 } 02285 02286 static int changelogtextTag(Header h, HE_t he) 02287 /*@globals internalState @*/ 02288 /*@modifies he, internalState @*/ 02289 { 02290 he->tag = RPMTAG_CHANGELOGTEXT; 02291 return localeTag(h, he); 02292 } 02293 02300 static int groupTag(Header h, HE_t he) 02301 /*@globals rpmGlobalMacroContext, h_errno, internalState @*/ 02302 /*@modifies he, rpmGlobalMacroContext, internalState @*/ 02303 { 02304 he->tag = RPMTAG_GROUP; 02305 return i18nTag(h, he); 02306 } 02307 02314 static int dbinstanceTag(Header h, HE_t he) 02315 /*@modifies he @*/ 02316 { 02317 he->tag = RPMTAG_DBINSTANCE; 02318 he->t = RPM_UINT32_TYPE; 02319 he->p.ui32p = xmalloc(sizeof(*he->p.ui32p)); 02320 he->p.ui32p[0] = headerGetInstance(h); 02321 he->freeData = 1; 02322 he->c = 1; 02323 return 0; 02324 } 02325 02332 static int headerstartoffTag(Header h, HE_t he) 02333 /*@modifies he @*/ 02334 { 02335 he->tag = RPMTAG_HEADERSTARTOFF; 02336 he->t = RPM_UINT64_TYPE; 02337 he->p.ui64p = xmalloc(sizeof(*he->p.ui64p)); 02338 he->p.ui64p[0] = headerGetStartOff(h); 02339 he->freeData = 1; 02340 he->c = 1; 02341 return 0; 02342 } 02343 02350 static int headerendoffTag(Header h, HE_t he) 02351 /*@modifies he @*/ 02352 { 02353 he->tag = RPMTAG_HEADERENDOFF; 02354 he->t = RPM_UINT64_TYPE; 02355 he->p.ui64p = xmalloc(sizeof(*he->p.ui64p)); 02356 he->p.ui64p[0] = headerGetEndOff(h); 02357 he->freeData = 1; 02358 he->c = 1; 02359 return 0; 02360 } 02361 02368 static int pkgoriginTag(Header h, HE_t he) 02369 /*@globals internalState @*/ 02370 /*@modifies he, internalState @*/ 02371 { 02372 const char * origin; 02373 int rc = 1; 02374 02375 he->tag = RPMTAG_PACKAGEORIGIN; 02376 if (!headerGet(h, he, HEADERGET_NOEXTENSION) 02377 && (origin = headerGetOrigin(h)) != NULL) 02378 { 02379 he->t = RPM_STRING_TYPE; 02380 he->p.str = xstrdup(origin); 02381 he->c = 1; 02382 he->freeData = 1; 02383 rc = 0; 02384 } 02385 return rc; 02386 } 02387 02394 static int pkgbaseurlTag(Header h, HE_t he) 02395 /*@globals internalState @*/ 02396 /*@modifies he, internalState @*/ 02397 { 02398 const char * baseurl; 02399 int rc = 1; 02400 02401 he->tag = RPMTAG_PACKAGEBASEURL; 02402 if (!headerGet(h, he, HEADERGET_NOEXTENSION) 02403 && (baseurl = headerGetBaseURL(h)) != NULL) 02404 { 02405 he->t = RPM_STRING_TYPE; 02406 he->p.str = xstrdup(baseurl); 02407 he->c = 1; 02408 he->freeData = 1; 02409 rc = 0; 02410 } 02411 return rc; 02412 } 02413 02420 static int pkgdigestTag(Header h, HE_t he) 02421 /*@modifies he @*/ 02422 { 02423 const char * digest; 02424 int rc = 1; 02425 02426 he->tag = RPMTAG_PACKAGEDIGEST; 02427 if ((digest = headerGetDigest(h)) != NULL) 02428 { 02429 he->t = RPM_STRING_TYPE; 02430 he->p.str = xstrdup(digest); 02431 he->c = 1; 02432 he->freeData = 1; 02433 rc = 0; 02434 } 02435 return rc; 02436 } 02437 02444 static int pkgmtimeTag(Header h, HE_t he) 02445 /*@modifies he @*/ 02446 { 02447 struct stat * st = headerGetStatbuf(h); 02448 he->tag = RPMTAG_PACKAGETIME; 02449 he->t = RPM_UINT64_TYPE; 02450 he->p.ui64p = xmalloc(sizeof(*he->p.ui64p)); 02451 /*@-type@*/ 02452 he->p.ui64p[0] = (rpmuint64_t)st->st_mtime; 02453 /*@=type@*/ 02454 he->freeData = 1; 02455 he->c = 1; 02456 return 0; 02457 } 02458 02465 static int pkgsizeTag(Header h, HE_t he) 02466 /*@modifies he @*/ 02467 { 02468 struct stat * st = headerGetStatbuf(h); 02469 he->tag = RPMTAG_PACKAGESIZE; 02470 he->t = RPM_UINT64_TYPE; 02471 he->p.ui64p = xmalloc(sizeof(*he->p.ui64p)); 02472 he->p.ui64p[0] = (rpmuint64_t)st->st_size; 02473 he->freeData = 1; 02474 he->c = 1; 02475 return 0; 02476 } 02477 02483 /*@only@*/ 02484 static char * hGetNVRA(Header h) 02485 /*@globals internalState @*/ 02486 /*@modifies h, internalState @*/ 02487 { 02488 const char * N = NULL; 02489 const char * V = NULL; 02490 const char * R = NULL; 02491 const char * A = NULL; 02492 size_t nb = 0; 02493 char * NVRA, * t; 02494 02495 (void) headerNEVRA(h, &N, NULL, &V, &R, &A); 02496 if (N) nb += strlen(N); 02497 if (V) nb += strlen(V) + 1; 02498 if (R) nb += strlen(R) + 1; 02499 #if defined(RPM_VENDOR_OPENPKG) /* no-architecture-expose */ 02500 /* do not expose the architecture as this is too less 02501 information, as in OpenPKG the "platform" is described by the 02502 architecture+operating-system combination. But as the whole 02503 "platform" information is actually overkill, just revert to the 02504 RPM 4 behaviour and do not expose any such information at all. */ 02505 #else 02506 if (A) nb += strlen(A) + 1; 02507 #endif 02508 nb++; 02509 NVRA = t = xmalloc(nb); 02510 *t = '\0'; 02511 if (N) t = stpcpy(t, N); 02512 if (V) t = stpcpy( stpcpy(t, "-"), V); 02513 if (R) t = stpcpy( stpcpy(t, "-"), R); 02514 #if defined(RPM_VENDOR_OPENPKG) /* no-architecture-expose */ 02515 /* do not expose the architecture as this is too less 02516 information, as in OpenPKG the "platform" is described by the 02517 architecture+operating-system combination. But as the whole 02518 "platform" information is actually overkill, just revert to the 02519 RPM 4 behaviour and do not expose any such information at all. */ 02520 #else 02521 if (A) t = stpcpy( stpcpy(t, "."), A); 02522 #endif 02523 N = _free(N); 02524 V = _free(V); 02525 R = _free(R); 02526 A = _free(A); 02527 return NVRA; 02528 } 02529 02536 static int nvraTag(Header h, HE_t he) 02537 /*@globals internalState @*/ 02538 /*@modifies h, he, internalState @*/ 02539 { 02540 he->t = RPM_STRING_TYPE; 02541 he->p.str = hGetNVRA(h); 02542 he->c = 1; 02543 he->freeData = 1; 02544 return 0; 02545 } 02546 02564 static void rpmfiBuildFNames(Header h, rpmTag tagN, 02565 /*@null@*/ /*@out@*/ const char *** fnp, 02566 /*@null@*/ /*@out@*/ rpmTagCount * fcp) 02567 /*@globals internalState @*/ 02568 /*@modifies *fnp, *fcp, internalState @*/ 02569 { 02570 HE_t he = memset(alloca(sizeof(*he)), 0, sizeof(*he)); 02571 rpmTag dirNameTag = 0; 02572 rpmTag dirIndexesTag = 0; 02573 rpmTagData baseNames = { .ptr = NULL }; 02574 rpmTagData dirNames = { .ptr = NULL }; 02575 rpmTagData dirIndexes = { .ptr = NULL }; 02576 rpmTagData fileNames; 02577 rpmTagCount count; 02578 size_t size; 02579 int isSource = 02580 (headerIsEntry(h, RPMTAG_SOURCERPM) == 0 && 02581 headerIsEntry(h, RPMTAG_ARCH) != 0); 02582 char * t; 02583 unsigned i; 02584 int xx; 02585 02586 if (tagN == RPMTAG_BASENAMES) { 02587 dirNameTag = RPMTAG_DIRNAMES; 02588 dirIndexesTag = RPMTAG_DIRINDEXES; 02589 } else if (tagN == RPMTAG_ORIGBASENAMES) { 02590 dirNameTag = RPMTAG_ORIGDIRNAMES; 02591 dirIndexesTag = RPMTAG_ORIGDIRINDEXES; 02592 } else { 02593 if (fnp) *fnp = NULL; 02594 if (fcp) *fcp = 0; 02595 return; /* programmer error */ 02596 } 02597 02598 /*@-compmempass@*/ /* use separate HE_t, not rpmTagData, containers. */ 02599 he->tag = tagN; 02600 xx = headerGet(h, he, 0); 02601 /* XXX 3.0.x SRPM's can be used, relative fn's at RPMTAG_OLDFILENAMES. */ 02602 if (xx == 0 && isSource) { 02603 he->tag = RPMTAG_OLDFILENAMES; 02604 xx = headerGet(h, he, 0); 02605 if (xx) { 02606 dirNames.argv = xcalloc(3, sizeof(*dirNames.argv)); 02607 dirNames.argv[0] = (const char *)&dirNames.argv[2]; 02608 dirIndexes.ui32p = xcalloc(he->c, sizeof(*dirIndexes.ui32p)); 02609 } 02610 } 02611 baseNames.argv = he->p.argv; 02612 count = he->c; 02613 02614 if (!xx) { 02615 if (fnp) *fnp = NULL; 02616 if (fcp) *fcp = 0; 02617 return; /* no file list */ 02618 } 02619 02620 he->tag = dirNameTag; 02621 if ((xx = headerGet(h, he, 0)) != 0) 02622 dirNames.argv = he->p.argv; 02623 02624 he->tag = dirIndexesTag; 02625 if ((xx = headerGet(h, he, 0)) != 0) 02626 dirIndexes.ui32p = he->p.ui32p; 02627 /*@=compmempass@*/ 02628 02629 size = sizeof(*fileNames.argv) * count; 02630 for (i = 0; i < (unsigned)count; i++) { 02631 const char * dn = NULL; 02632 (void) urlPath(dirNames.argv[dirIndexes.ui32p[i]], &dn); 02633 size += strlen(baseNames.argv[i]) + strlen(dn) + 1; 02634 } 02635 02636 fileNames.argv = xmalloc(size); 02637 t = (char *)&fileNames.argv[count]; 02638 for (i = 0; i < (unsigned)count; i++) { 02639 const char * dn = NULL; 02640 (void) urlPath(dirNames.argv[dirIndexes.ui32p[i]], &dn); 02641 fileNames.argv[i] = t; 02642 t = stpcpy( stpcpy(t, dn), baseNames.argv[i]); 02643 *t++ = '\0'; 02644 } 02645 baseNames.ptr = _free(baseNames.ptr); 02646 dirNames.ptr = _free(dirNames.ptr); 02647 dirIndexes.ptr = _free(dirIndexes.ptr); 02648 02649 /*@-onlytrans@*/ 02650 if (fnp) 02651 *fnp = fileNames.argv; 02652 else 02653 fileNames.ptr = _free(fileNames.ptr); 02654 /*@=onlytrans@*/ 02655 if (fcp) *fcp = count; 02656 } 02657 02665 static int _fnTag(Header h, HE_t he, rpmTag tag) 02666 /*@globals internalState @*/ 02667 /*@modifies he, internalState @*/ 02668 { 02669 he->t = RPM_STRING_ARRAY_TYPE; 02670 rpmfiBuildFNames(h, tag, &he->p.argv, &he->c); 02671 he->freeData = 1; 02672 /* XXX headerGet() rc on RPMTAG_FILEPATHS w empty list. */ 02673 if (he->p.argv && he->p.argv[0] && he->c > 0) 02674 return 0; 02675 he->p.ptr = _free(he->p.ptr); 02676 he->c = 0; 02677 return 1; 02678 } 02679 02680 static int filenamesTag(Header h, HE_t he) 02681 /*@globals internalState @*/ 02682 /*@modifies he, internalState @*/ 02683 { 02684 he->tag = tagValue("Filenames"); 02685 return _fnTag(h, he, RPMTAG_BASENAMES); 02686 } 02687 02688 static int filepathsTag(Header h, HE_t he) 02689 /*@globals internalState @*/ 02690 /*@modifies he, internalState @*/ 02691 { 02692 he->tag = RPMTAG_FILEPATHS; 02693 return _fnTag(h, he, RPMTAG_BASENAMES); 02694 } 02695 02696 static int origpathsTag(Header h, HE_t he) 02697 /*@globals internalState @*/ 02698 /*@modifies he, internalState @*/ 02699 { 02700 he->tag = RPMTAG_ORIGPATHS; 02701 return _fnTag(h, he, RPMTAG_ORIGBASENAMES); 02702 } 02703 02713 static int debevrfmtTag(/*@unused@*/ Header h, HE_t he, 02714 HE_t Nhe, HE_t EVRhe, HE_t Fhe) 02715 /*@globals rpmGlobalMacroContext, h_errno, internalState @*/ 02716 /*@modifies he, Nhe, rpmGlobalMacroContext, internalState @*/ 02717 { 02718 char * t, * te; 02719 size_t nb = 0; 02720 int rc = 1; 02721 02722 he->t = RPM_STRING_ARRAY_TYPE; 02723 he->c = 0; 02724 he->freeData = 1; 02725 for (Nhe->ix = 0; Nhe->ix < (int)Nhe->c; Nhe->ix++) { 02726 nb += sizeof(*he->p.argv); 02727 nb += strlen(Nhe->p.argv[Nhe->ix]) + 1; 02728 if (*EVRhe->p.argv[Nhe->ix] != '\0') 02729 nb += strlen(EVRhe->p.argv[Nhe->ix]) + (sizeof(" (== )")-1); 02730 he->c++; 02731 } 02732 nb += sizeof(*he->p.argv); 02733 02734 he->p.argv = xmalloc(nb); 02735 te = (char *) &he->p.argv[he->c+1]; 02736 02737 he->c = 0; 02738 for (Nhe->ix = 0; Nhe->ix < (int)Nhe->c; Nhe->ix++) { 02739 he->p.argv[he->c++] = te; 02740 if (*EVRhe->p.argv[Nhe->ix] != '\0') { 02741 char opstr[4], * op = opstr; 02742 if (Fhe->p.ui32p[Nhe->ix] & RPMSENSE_LESS) 02743 *op++ = '<'; 02744 if (Fhe->p.ui32p[Nhe->ix] & RPMSENSE_GREATER) 02745 *op++ = '>'; 02746 if (Fhe->p.ui32p[Nhe->ix] & RPMSENSE_EQUAL) 02747 *op++ = '='; 02748 *op = '\0'; 02749 t = rpmExpand(Nhe->p.argv[Nhe->ix], 02750 " (", opstr, " ", EVRhe->p.argv[Nhe->ix], ")", NULL); 02751 } else 02752 t = rpmExpand(Nhe->p.argv[Nhe->ix], NULL); 02753 te = stpcpy(te, t); 02754 te++; 02755 t = _free(t); 02756 } 02757 he->p.argv[he->c] = NULL; 02758 rc = 0; 02759 02760 return rc; 02761 } 02762 02772 static int debevrTag(Header h, HE_t he, rpmTag tagN, rpmTag tagEVR, rpmTag tagF) 02773 /*@globals rpmGlobalMacroContext, h_errno, internalState @*/ 02774 /*@modifies he, rpmGlobalMacroContext, internalState @*/ 02775 { 02776 HE_t Nhe = memset(alloca(sizeof(*Nhe)), 0, sizeof(*Nhe)); 02777 HE_t EVRhe = memset(alloca(sizeof(*EVRhe)), 0, sizeof(*EVRhe)); 02778 HE_t Fhe = memset(alloca(sizeof(*Fhe)), 0, sizeof(*Fhe)); 02779 int rc = 1; 02780 int xx; 02781 02782 Nhe->tag = tagN; 02783 if (!(xx = headerGet(h, Nhe, 0))) 02784 goto exit; 02785 EVRhe->tag = tagEVR; 02786 if (!(xx = headerGet(h, EVRhe, 0))) 02787 goto exit; 02788 assert(EVRhe->c == Nhe->c); 02789 Fhe->tag = tagF; 02790 if (!(xx = headerGet(h, Fhe, 0))) 02791 goto exit; 02792 assert(Fhe->c == Nhe->c); 02793 02794 rc = debevrfmtTag(h, he, Nhe, EVRhe, Fhe); 02795 02796 exit: 02797 Nhe->p.ptr = _free(Nhe->p.ptr); 02798 EVRhe->p.ptr = _free(EVRhe->p.ptr); 02799 Fhe->p.ptr = _free(Fhe->p.ptr); 02800 return rc; 02801 } 02802 02809 static int debconflictsTag(Header h, HE_t he) 02810 /*@globals rpmGlobalMacroContext, h_errno, internalState @*/ 02811 /*@modifies he, rpmGlobalMacroContext, internalState @*/ 02812 { 02813 he->tag = tagValue("Debconflicts"); 02814 return debevrTag(h, he, 02815 RPMTAG_CONFLICTNAME, RPMTAG_CONFLICTVERSION, RPMTAG_CONFLICTFLAGS); 02816 } 02817 02818 static int debdependsTag(Header h, HE_t he) 02819 /*@globals rpmGlobalMacroContext, h_errno, internalState @*/ 02820 /*@modifies he, rpmGlobalMacroContext, internalState @*/ 02821 { 02822 he->tag = tagValue("Debdepends"); 02823 return debevrTag(h, he, 02824 RPMTAG_REQUIRENAME, RPMTAG_REQUIREVERSION, RPMTAG_REQUIREFLAGS); 02825 } 02826 02827 static int debobsoletesTag(Header h, HE_t he) 02828 /*@globals rpmGlobalMacroContext, h_errno, internalState @*/ 02829 /*@modifies he, rpmGlobalMacroContext, internalState @*/ 02830 { 02831 he->tag = tagValue("Debobsoletes"); 02832 return debevrTag(h, he, 02833 RPMTAG_OBSOLETENAME, RPMTAG_OBSOLETEVERSION, RPMTAG_OBSOLETEFLAGS); 02834 } 02835 02836 static int debprovidesTag(Header h, HE_t he) 02837 /*@globals rpmGlobalMacroContext, h_errno, internalState @*/ 02838 /*@modifies he, rpmGlobalMacroContext, internalState @*/ 02839 { 02840 he->tag = tagValue("Debprovides"); 02841 return debevrTag(h, he, 02842 RPMTAG_PROVIDENAME, RPMTAG_PROVIDEVERSION, RPMTAG_PROVIDEFLAGS); 02843 } 02844 02851 static int debmd5sumsTag(Header h, HE_t he) 02852 /*@globals rpmGlobalMacroContext, h_errno, internalState @*/ 02853 /*@modifies he, rpmGlobalMacroContext, internalState @*/ 02854 { 02855 HE_t Nhe = memset(alloca(sizeof(*Nhe)), 0, sizeof(*Nhe)); 02856 HE_t Dhe = memset(alloca(sizeof(*Dhe)), 0, sizeof(*Dhe)); 02857 char * t, * te; 02858 size_t nb = 0; 02859 int rc = 1; 02860 int xx; 02861 02862 Nhe->tag = RPMTAG_FILEPATHS; 02863 if (!(xx = headerGet(h, Nhe, 0))) 02864 goto exit; 02865 Dhe->tag = RPMTAG_FILEDIGESTS; 02866 if (!(xx = headerGet(h, Dhe, 0))) 02867 goto exit; 02868 assert(Dhe->c == Nhe->c); 02869 02870 he->tag = tagValue("Debmd5sums"); 02871 he->t = RPM_STRING_ARRAY_TYPE; 02872 he->c = 0; 02873 he->freeData = 1; 02874 for (Dhe->ix = 0; Dhe->ix < (int)Dhe->c; Dhe->ix++) { 02875 if (!(Dhe->p.argv[Dhe->ix] && *Dhe->p.argv[Dhe->ix])) 02876 continue; 02877 nb += sizeof(*he->p.argv); 02878 nb += strlen(Dhe->p.argv[Dhe->ix]) + sizeof(" ") + strlen(Nhe->p.argv[Dhe->ix]) - 1; 02879 he->c++; 02880 } 02881 nb += sizeof(*he->p.argv); 02882 02883 he->p.argv = xmalloc(nb); 02884 te = (char *) &he->p.argv[he->c+1]; 02885 02886 he->c = 0; 02887 for (Dhe->ix = 0; Dhe->ix < (int)Dhe->c; Dhe->ix++) { 02888 if (!(Dhe->p.argv[Dhe->ix] && *Dhe->p.argv[Dhe->ix])) 02889 continue; 02890 he->p.argv[he->c++] = te; 02891 t = rpmExpand(Dhe->p.argv[Dhe->ix], " ", Nhe->p.argv[Dhe->ix]+1, NULL); 02892 te = stpcpy(te, t); 02893 te++; 02894 t = _free(t); 02895 } 02896 he->p.argv[he->c] = NULL; 02897 rc = 0; 02898 02899 exit: 02900 Nhe->p.ptr = _free(Nhe->p.ptr); 02901 Dhe->p.ptr = _free(Dhe->p.ptr); 02902 return rc; 02903 } 02904 02905 static int filestatTag(Header h, HE_t he) 02906 /*@globals internalState @*/ 02907 /*@modifies he, internalState @*/ 02908 { 02909 rpmTagData paths = { .ptr = NULL }; 02910 /* _dev */ 02911 rpmTagData _ino = { .ptr = NULL }; 02912 rpmTagData _mode = { .ptr = NULL }; 02913 /* _nlink */ 02914 /* _uid */ 02915 /* _gid */ 02916 rpmTagData _rdev = { .ptr = NULL }; 02917 rpmTagData _size = { .ptr = NULL }; 02918 /* _blksize */ 02919 /* _blocks */ 02920 /* _atime */ 02921 rpmTagData _mtime = { .ptr = NULL }; 02922 /* st_ctime */ 02923 int rc; 02924 02925 he->tag = RPMTAG_FILEPATHS; 02926 if ((rc = _fnTag(h, he, RPMTAG_BASENAMES)) != 0 || he->c == 0) 02927 goto exit; 02928 02929 exit: 02930 paths.ptr = _free(paths.ptr); 02931 _ino.ptr = _free(_ino.ptr); 02932 _mode.ptr = _free(_mode.ptr); 02933 _rdev.ptr = _free(_rdev.ptr); 02934 _size.ptr = _free(_size.ptr); 02935 _mtime.ptr = _free(_mtime.ptr); 02936 return rc; 02937 } 02938 02939 static int wnlookupTag(Header h, rpmTag tagNVRA, ARGV_t *avp, ARGI_t *hitp, 02940 HE_t PNhe, /*@null@*/ HE_t PEVRhe, /*@null@*/ HE_t PFhe) 02941 /*@globals rpmGlobalMacroContext, h_errno, 02942 fileSystem, internalState @*/ 02943 /*@modifies *avp, *hitp, rpmGlobalMacroContext, 02944 fileSystem, internalState @*/ 02945 { 02946 HE_t NVRAhe = memset(alloca(sizeof(*NVRAhe)), 0, sizeof(*NVRAhe)); 02947 HE_t RNhe = memset(alloca(sizeof(*RNhe)), 0, sizeof(*RNhe)); 02948 HE_t REVRhe = memset(alloca(sizeof(*REVRhe)), 0, sizeof(*REVRhe)); 02949 HE_t RFhe = memset(alloca(sizeof(*RFhe)), 0, sizeof(*RFhe)); 02950 rpmdb _rpmdb = (rpmdb) headerGetRpmdb(h); 02951 const char * key = PNhe->p.argv[PNhe->ix]; 02952 size_t keylen = 0; 02953 rpmmi mi; 02954 rpmTag tagN = RPMTAG_REQUIRENAME; 02955 rpmTag tagEVR = RPMTAG_REQUIREVERSION; 02956 rpmTag tagF = RPMTAG_REQUIREFLAGS; 02957 rpmuint32_t PFlags; 02958 rpmuint32_t RFlags; 02959 EVR_t Pevr; 02960 Header oh; 02961 int rc = 0; 02962 int xx; 02963 02964 if (tagNVRA == 0) 02965 tagNVRA = RPMTAG_NVRA; 02966 02967 PFlags = (PFhe != NULL ? (PFhe->p.ui32p[PNhe->ix] & RPMSENSE_SENSEMASK) : 0); 02968 Pevr = rpmEVRnew(PFlags, 1); 02969 02970 if (PEVRhe != NULL) 02971 xx = rpmEVRparse(xstrdup(PEVRhe->p.argv[PNhe->ix]), Pevr); 02972 02973 RNhe->tag = tagN; 02974 REVRhe->tag = tagEVR; 02975 RFhe->tag = tagF; 02976 02977 mi = rpmmiInit(_rpmdb, tagN, key, keylen); 02978 if (hitp && *hitp) 02979 xx = rpmmiPrune(mi, (uint32_t *)argiData(*hitp), argiCount(*hitp), 0); 02980 while ((oh = rpmmiNext(mi)) != NULL) { 02981 if (!headerGet(oh, RNhe, 0)) 02982 goto bottom; 02983 if (PEVRhe != NULL) { 02984 if (!headerGet(oh, REVRhe, 0)) 02985 goto bottom; 02986 assert(REVRhe->c == RNhe->c); 02987 if (!headerGet(oh, RFhe, 0)) 02988 goto bottom; 02989 assert(RFhe->c == RNhe->c); 02990 } 02991 02992 for (RNhe->ix = 0; RNhe->ix < (int)RNhe->c; RNhe->ix++) { 02993 if (strcmp(PNhe->p.argv[PNhe->ix], RNhe->p.argv[RNhe->ix])) 02994 /*@innercontinue@*/ continue; 02995 if (PEVRhe == NULL) 02996 goto bingo; 02997 RFlags = RFhe->p.ui32p[RNhe->ix] & RPMSENSE_SENSEMASK; 02998 { EVR_t Revr = rpmEVRnew(RFlags, 1); 02999 if (!(PFlags && RFlags)) 03000 xx = 1; 03001 else { 03002 xx = rpmEVRparse(REVRhe->p.argv[RNhe->ix], Revr); 03003 xx = rpmEVRoverlap(Pevr, Revr); 03004 } 03005 Revr = rpmEVRfree(Revr); 03006 } 03007 if (xx) 03008 goto bingo; 03009 } 03010 goto bottom; 03011 03012 bingo: 03013 NVRAhe->tag = tagNVRA; 03014 xx = headerGet(oh, NVRAhe, 0); 03015 if (!(*avp != NULL && argvSearch(*avp, NVRAhe->p.str, NULL) != NULL)) { 03016 xx = argvAdd(avp, NVRAhe->p.str); 03017 xx = argvSort(*avp, NULL); 03018 if (hitp != NULL) 03019 xx = argiAdd(hitp, -1, rpmmiInstance(mi)); 03020 rc++; 03021 } 03022 03023 bottom: 03024 RNhe->p.ptr = _free(RNhe->p.ptr); 03025 REVRhe->p.ptr = _free(REVRhe->p.ptr); 03026 RFhe->p.ptr = _free(RFhe->p.ptr); 03027 NVRAhe->p.ptr = _free(NVRAhe->p.ptr); 03028 } 03029 mi = rpmmiFree(mi); 03030 03031 Pevr = rpmEVRfree(Pevr); 03032 03033 return rc; 03034 } 03035 03036 static int whatneedsTag(Header h, HE_t he) 03037 /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/ 03038 /*@modifies he, rpmGlobalMacroContext, fileSystem, internalState @*/ 03039 { 03040 HE_t NVRAhe = memset(alloca(sizeof(*NVRAhe)), 0, sizeof(*NVRAhe)); 03041 HE_t PNhe = memset(alloca(sizeof(*PNhe)), 0, sizeof(*PNhe)); 03042 HE_t PEVRhe = memset(alloca(sizeof(*PEVRhe)), 0, sizeof(*PEVRhe)); 03043 HE_t PFhe = memset(alloca(sizeof(*PFhe)), 0, sizeof(*PFhe)); 03044 HE_t FNhe = memset(alloca(sizeof(*FNhe)), 0, sizeof(*FNhe)); 03045 rpmTag tagNVRA = RPMTAG_NVRA; 03046 ARGV_t pkgs = NULL; 03047 ARGI_t hits = NULL; 03048 int rc = 1; 03049 03050 PNhe->tag = RPMTAG_PROVIDENAME; 03051 if (!headerGet(h, PNhe, 0)) 03052 goto exit; 03053 PEVRhe->tag = RPMTAG_PROVIDEVERSION; 03054 if (!headerGet(h, PEVRhe, 0)) 03055 goto exit; 03056 assert(PEVRhe->c == PNhe->c); 03057 PFhe->tag = RPMTAG_PROVIDEFLAGS; 03058 if (!headerGet(h, PFhe, 0)) 03059 goto exit; 03060 assert(PFhe->c == PNhe->c); 03061 03062 FNhe->tag = RPMTAG_FILEPATHS; 03063 if (!headerGet(h, FNhe, 0)) 03064 goto exit; 03065 03066 NVRAhe->tag = tagNVRA;; 03067 if (!headerGet(h, NVRAhe, 0)) 03068 goto exit; 03069 03070 (void) argvAdd(&pkgs, NVRAhe->p.str); 03071 03072 for (PNhe->ix = 0; PNhe->ix < (int)PNhe->c; PNhe->ix++) 03073 (void) wnlookupTag(h, tagNVRA, &pkgs, &hits, PNhe, PEVRhe, PFhe); 03074 for (FNhe->ix = 0; FNhe->ix < (int)FNhe->c; FNhe->ix++) 03075 (void) wnlookupTag(h, tagNVRA, &pkgs, &hits, FNhe, NULL, NULL); 03076 03077 /* Convert package NVRA array to Header string array. */ 03078 { size_t nb = 0; 03079 char * te; 03080 rpmuint32_t i; 03081 03082 he->t = RPM_STRING_ARRAY_TYPE; 03083 he->c = argvCount(pkgs); 03084 nb = 0; 03085 for (i = 0; i < he->c; i++) { 03086 nb += sizeof(*he->p.argv); 03087 nb += strlen(pkgs[i]) + 1; 03088 } 03089 nb += sizeof(*he->p.argv); 03090 03091 he->p.argv = xmalloc(nb); 03092 te = (char *) &he->p.argv[he->c+1]; 03093 03094 for (i = 0; i < he->c; i++) { 03095 he->p.argv[i] = te; 03096 te = stpcpy(te, pkgs[i]); 03097 te++; 03098 } 03099 he->p.argv[he->c] = NULL; 03100 } 03101 03102 hits = argiFree(hits); 03103 pkgs = argvFree(pkgs); 03104 rc = 0; 03105 03106 exit: 03107 NVRAhe->p.ptr = _free(NVRAhe->p.ptr); 03108 PNhe->p.ptr = _free(PNhe->p.ptr); 03109 PEVRhe->p.ptr = _free(PEVRhe->p.ptr); 03110 PFhe->p.ptr = _free(PFhe->p.ptr); 03111 FNhe->p.ptr = _free(FNhe->p.ptr); 03112 return rc; 03113 } 03114 03115 static int nwlookupTag(Header h, rpmTag tagNVRA, ARGV_t *avp, ARGI_t *hitp, 03116 HE_t RNhe, /*@null@*/ HE_t REVRhe, /*@null@*/ HE_t RFhe) 03117 /*@globals rpmGlobalMacroContext, h_errno, 03118 fileSystem, internalState @*/ 03119 /*@modifies *avp, *hitp, REVRhe, rpmGlobalMacroContext, 03120 fileSystem, internalState @*/ 03121 { 03122 HE_t NVRAhe = memset(alloca(sizeof(*NVRAhe)), 0, sizeof(*NVRAhe)); 03123 HE_t PNhe = memset(alloca(sizeof(*PNhe)), 0, sizeof(*PNhe)); 03124 HE_t PEVRhe = memset(alloca(sizeof(*PEVRhe)), 0, sizeof(*PEVRhe)); 03125 HE_t PFhe = memset(alloca(sizeof(*PFhe)), 0, sizeof(*PFhe)); 03126 rpmdb _rpmdb = (rpmdb) headerGetRpmdb(h); 03127 const char * key = RNhe->p.argv[RNhe->ix]; 03128 size_t keylen = 0; 03129 rpmmi mi; 03130 rpmTag tagN = tagN = (*RNhe->p.argv[RNhe->ix] == '/') 03131 ? RPMTAG_BASENAMES : RPMTAG_PROVIDENAME; 03132 rpmTag tagEVR = RPMTAG_PROVIDEVERSION; 03133 rpmTag tagF = RPMTAG_PROVIDEFLAGS; 03134 rpmuint32_t PFlags; 03135 rpmuint32_t RFlags; 03136 EVR_t Revr; 03137 Header oh; 03138 int rc = 0; 03139 int xx; 03140 03141 if (tagNVRA == 0) 03142 tagNVRA = RPMTAG_NVRA; 03143 03144 RFlags = (RFhe != NULL ? (RFhe->p.ui32p[RNhe->ix] & RPMSENSE_SENSEMASK) : 0); 03145 Revr = rpmEVRnew(RFlags, 1); 03146 03147 if (REVRhe != NULL) 03148 xx = rpmEVRparse(REVRhe->p.argv[RNhe->ix], Revr); 03149 03150 PNhe->tag = tagN; 03151 PEVRhe->tag = tagEVR; 03152 PFhe->tag = tagF; 03153 03154 mi = rpmmiInit(_rpmdb, tagN, key, keylen); 03155 if (hitp && *hitp) 03156 xx = rpmmiPrune(mi, (uint32_t *)argiData(*hitp), argiCount(*hitp), 0); 03157 while ((oh = rpmmiNext(mi)) != NULL) { 03158 if (!headerGet(oh, PNhe, 0)) 03159 goto bottom; 03160 if (REVRhe != NULL) { 03161 if (!headerGet(oh, PEVRhe, 0)) 03162 goto bottom; 03163 assert(PEVRhe->c == PNhe->c); 03164 if (!headerGet(oh, PFhe, 0)) 03165 goto bottom; 03166 assert(PFhe->c == PNhe->c); 03167 } 03168 03169 for (PNhe->ix = 0; PNhe->ix < (int)PNhe->c; PNhe->ix++) { 03170 if (strcmp(RNhe->p.argv[RNhe->ix], PNhe->p.argv[PNhe->ix])) 03171 /*@innercontinue@*/ continue; 03172 if (REVRhe == NULL) 03173 goto bingo; 03174 PFlags = PFhe->p.ui32p[PNhe->ix] & RPMSENSE_SENSEMASK; 03175 { EVR_t Pevr = rpmEVRnew(PFlags, 1); 03176 if (!(PFlags && RFlags)) 03177 xx = 1; 03178 else { 03179 xx = rpmEVRparse(PEVRhe->p.argv[PNhe->ix], Pevr); 03180 xx = rpmEVRoverlap(Revr, Pevr); 03181 } 03182 Pevr = rpmEVRfree(Pevr); 03183 } 03184 if (xx) 03185 goto bingo; 03186 } 03187 goto bottom; 03188 03189 bingo: 03190 NVRAhe->tag = tagNVRA; 03191 xx = headerGet(oh, NVRAhe, 0); 03192 if (!(*avp != NULL && argvSearch(*avp, NVRAhe->p.str, NULL) != NULL)) { 03193 xx = argvAdd(avp, NVRAhe->p.str); 03194 xx = argvSort(*avp, NULL); 03195 if (hitp != NULL) 03196 xx = argiAdd(hitp, -1, rpmmiInstance(mi)); 03197 rc++; 03198 } 03199 03200 bottom: 03201 PNhe->p.ptr = _free(PNhe->p.ptr); 03202 PEVRhe->p.ptr = _free(PEVRhe->p.ptr); 03203 PFhe->p.ptr = _free(PFhe->p.ptr); 03204 NVRAhe->p.ptr = _free(NVRAhe->p.ptr); 03205 } 03206 mi = rpmmiFree(mi); 03207 03208 Revr = rpmEVRfree(Revr); 03209 03210 return rc; 03211 } 03212 03213 static int needswhatTag(Header h, HE_t he) 03214 /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/ 03215 /*@modifies he, rpmGlobalMacroContext, fileSystem, internalState @*/ 03216 { 03217 HE_t NVRAhe = memset(alloca(sizeof(*NVRAhe)), 0, sizeof(*NVRAhe)); 03218 HE_t RNhe = memset(alloca(sizeof(*RNhe)), 0, sizeof(*RNhe)); 03219 HE_t REVRhe = memset(alloca(sizeof(*REVRhe)), 0, sizeof(*REVRhe)); 03220 HE_t RFhe = memset(alloca(sizeof(*RFhe)), 0, sizeof(*RFhe)); 03221 rpmTag tagNVRA = RPMTAG_NVRA; 03222 ARGV_t pkgs = NULL; 03223 ARGI_t hits = NULL; 03224 int rc = 1; 03225 03226 RNhe->tag = RPMTAG_REQUIRENAME; 03227 if (!headerGet(h, RNhe, 0)) 03228 goto exit; 03229 REVRhe->tag = RPMTAG_REQUIREVERSION; 03230 if (!headerGet(h, REVRhe, 0)) 03231 goto exit; 03232 assert(REVRhe->c == RNhe->c); 03233 RFhe->tag = RPMTAG_REQUIREFLAGS; 03234 if (!headerGet(h, RFhe, 0)) 03235 goto exit; 03236 assert(RFhe->c == RNhe->c); 03237 03238 NVRAhe->tag = tagNVRA;; 03239 if (!headerGet(h, NVRAhe, 0)) 03240 goto exit; 03241 03242 (void) argvAdd(&pkgs, NVRAhe->p.str); 03243 03244 for (RNhe->ix = 0; RNhe->ix < (int)RNhe->c; RNhe->ix++) { 03245 if (*RNhe->p.argv[RNhe->ix] == '/' || *REVRhe->p.argv[RNhe->ix] == '\0') 03246 (void) nwlookupTag(h, tagNVRA, &pkgs, &hits, RNhe, NULL, NULL); 03247 else 03248 (void) nwlookupTag(h, tagNVRA, &pkgs, &hits, RNhe, REVRhe, RFhe); 03249 } 03250 03251 /* Convert package NVRA array to Header string array. */ 03252 { size_t nb = 0; 03253 char * te; 03254 rpmuint32_t i; 03255 03256 he->t = RPM_STRING_ARRAY_TYPE; 03257 he->c = argvCount(pkgs); 03258 nb = 0; 03259 for (i = 0; i < he->c; i++) { 03260 nb += sizeof(*he->p.argv); 03261 nb += strlen(pkgs[i]) + 1; 03262 } 03263 nb += sizeof(*he->p.argv); 03264 03265 he->p.argv = xmalloc(nb); 03266 te = (char *) &he->p.argv[he->c+1]; 03267 03268 for (i = 0; i < he->c; i++) { 03269 he->p.argv[i] = te; 03270 te = stpcpy(te, pkgs[i]); 03271 te++; 03272 } 03273 he->p.argv[he->c] = NULL; 03274 } 03275 03276 hits = argiFree(hits); 03277 pkgs = argvFree(pkgs); 03278 rc = 0; 03279 03280 exit: 03281 NVRAhe->p.ptr = _free(NVRAhe->p.ptr); 03282 RNhe->p.ptr = _free(RNhe->p.ptr); 03283 REVRhe->p.ptr = _free(REVRhe->p.ptr); 03284 RFhe->p.ptr = _free(RFhe->p.ptr); 03285 return rc; 03286 } 03287 03288 static int PRCOSkip(rpmTag tag, rpmTagData N, rpmTagData EVR, rpmTagData F, 03289 rpmuint32_t i) 03290 /*@*/ 03291 { 03292 int a = -2, b = -2; 03293 03294 if (N.argv[i] == NULL || *N.argv[i] == '\0') 03295 return 1; 03296 if (tag == RPMTAG_REQUIRENAME && i > 0 03297 && !(a=strcmp(N.argv[i], N.argv[i-1])) 03298 && !(b=strcmp(EVR.argv[i], EVR.argv[i-1])) 03299 && (F.ui32p[i] & 0x4e) == ((F.ui32p[i-1] & 0x4e))) 03300 return 1; 03301 return 0; 03302 } 03303 03304 static int PRCOxmlTag(Header h, HE_t he, rpmTag EVRtag, rpmTag Ftag) 03305 /*@globals internalState @*/ 03306 /*@modifies he, internalState @*/ 03307 { 03308 rpmTag tag = he->tag; 03309 rpmTagData N = { .ptr = NULL }; 03310 rpmTagData EVR = { .ptr = NULL }; 03311 rpmTagData F = { .ptr = NULL }; 03312 size_t nb; 03313 rpmuint32_t ac; 03314 rpmuint32_t c; 03315 rpmuint32_t i; 03316 char *t; 03317 int rc = 1; /* assume failure */ 03318 int xx; 03319 int lvl = 0; 03320 spew_t spew = &_xml_spew; 03321 03322 /*@-compmempass@*/ /* use separate HE_t, not rpmTagData, containers. */ 03323 xx = headerGet(h, he, 0); 03324 if (xx == 0) goto exit; 03325 N.argv = he->p.argv; 03326 c = he->c; 03327 03328 he->tag = EVRtag; 03329 xx = headerGet(h, he, 0); 03330 if (xx == 0) goto exit; 03331 EVR.argv = he->p.argv; 03332 03333 he->tag = Ftag; 03334 xx = headerGet(h, he, 0); 03335 if (xx == 0) goto exit; 03336 F.ui32p = he->p.ui32p; 03337 03338 nb = sizeof(*he->p.argv); 03339 ac = 0; 03340 for (i = 0; i < c; i++) { 03341 /*@-nullstate@*/ /* EVR.argv might be NULL */ 03342 if (PRCOSkip(tag, N, EVR, F, i)) 03343 continue; 03344 /*@=nullstate@*/ 03345 ac++; 03346 nb += sizeof(*he->p.argv); 03347 nb += sizeof("<rpm:entry name=\"\"/>"); 03348 if (*N.argv[i] == '/') 03349 nb += spew->spew_strlen(N.argv[i], lvl); 03350 else 03351 nb += strlen(N.argv[i]); 03352 if (EVR.argv != NULL && EVR.argv[i] != NULL && *EVR.argv[i] != '\0') { 03353 nb += sizeof(" flags=\"EQ\" epoch=\"0\" ver=\"\"") - 1; 03354 nb += strlen(EVR.argv[i]); 03355 if (strchr(EVR.argv[i], ':') != NULL) 03356 nb -= 2; 03357 if (strchr(EVR.argv[i], '-') != NULL) 03358 nb += sizeof(" rel=\"\"") - 2; 03359 } 03360 #ifdef NOTNOW 03361 if (tag == RPMTAG_REQUIRENAME && (F.ui32p[i] & 0x40)) 03362 nb += sizeof(" pre=\"1\"") - 1; 03363 #endif 03364 } 03365 03366 he->t = RPM_STRING_ARRAY_TYPE; 03367 he->c = ac; 03368 he->freeData = 1; 03369 he->p.argv = xmalloc(nb + BUFSIZ); /* XXX hack: leave slop */ 03370 t = (char *) &he->p.argv[he->c + 1]; 03371 ac = 0; 03372 for (i = 0; i < c; i++) { 03373 /*@-nullstate@*/ /* EVR.argv might be NULL */ 03374 if (PRCOSkip(tag, N, EVR, F, i)) 03375 continue; 03376 /*@=nullstate@*/ 03377 he->p.argv[ac++] = t; 03378 t = stpcpy(t, "<rpm:entry"); 03379 t = stpcpy(t, " name=\""); 03380 if (*N.argv[i] == '/') { 03381 t = spew->spew_strcpy(t, N.argv[i], lvl); t += strlen(t); 03382 } else 03383 t = stpcpy(t, N.argv[i]); 03384 t = stpcpy(t, "\""); 03385 /*@-readonlytrans@*/ 03386 if (EVR.argv != NULL && EVR.argv[i] != NULL && *EVR.argv[i] != '\0') { 03387 static char *Fstr[] = { "?0","LT","GT","?3","EQ","LE","GE","?7" }; 03388 rpmuint32_t Fx = ((F.ui32p[i] >> 1) & 0x7); 03389 const char *E, *V, *R; 03390 char *f, *fe; 03391 t = stpcpy( stpcpy( stpcpy(t, " flags=\""), Fstr[Fx]), "\""); 03392 f = (char *) EVR.argv[i]; 03393 for (fe = f; *fe != '\0' && *fe >= '0' && *fe <= '9'; fe++) 03394 {}; 03395 if (*fe == ':') { *fe++ = '\0'; E = f; f = fe; } else E = NULL; 03396 V = f; 03397 for (fe = f; *fe != '\0' && *fe != '-'; fe++) 03398 {}; 03399 if (*fe == '-') { *fe++ = '\0'; R = fe; } else R = NULL; 03400 t = stpcpy( stpcpy( stpcpy(t, " epoch=\""), (E && *E ? E : "0")), "\""); 03401 t = stpcpy( stpcpy( stpcpy(t, " ver=\""), V), "\""); 03402 if (R != NULL) 03403 t = stpcpy( stpcpy( stpcpy(t, " rel=\""), R), "\""); 03404 } 03405 /*@=readonlytrans@*/ 03406 #ifdef NOTNOW 03407 if (tag == RPMTAG_REQUIRENAME && (F.ui32p[i] & 0x40)) 03408 t = stpcpy(t, " pre=\"1\""); 03409 #endif 03410 t = stpcpy(t, "/>"); 03411 *t++ = '\0'; 03412 } 03413 he->p.argv[he->c] = NULL; 03414 /*@=compmempass@*/ 03415 rc = 0; 03416 03417 exit: 03418 /*@-kepttrans@*/ /* N.argv may be kept. */ 03419 N.argv = _free(N.argv); 03420 /*@=kepttrans@*/ 03421 /*@-usereleased@*/ /* EVR.argv may be dead. */ 03422 EVR.argv = _free(EVR.argv); 03423 /*@=usereleased@*/ 03424 F.ui32p = _free(F.ui32p); 03425 return rc; 03426 } 03427 03428 static int PxmlTag(Header h, HE_t he) 03429 /*@globals internalState @*/ 03430 /*@modifies he, internalState @*/ 03431 { 03432 he->tag = RPMTAG_PROVIDENAME; 03433 return PRCOxmlTag(h, he, RPMTAG_PROVIDEVERSION, RPMTAG_PROVIDEFLAGS); 03434 } 03435 03436 static int RxmlTag(Header h, HE_t he) 03437 /*@globals internalState @*/ 03438 /*@modifies he, internalState @*/ 03439 { 03440 he->tag = RPMTAG_REQUIRENAME; 03441 return PRCOxmlTag(h, he, RPMTAG_REQUIREVERSION, RPMTAG_REQUIREFLAGS); 03442 } 03443 03444 static int CxmlTag(Header h, HE_t he) 03445 /*@globals internalState @*/ 03446 /*@modifies he, internalState @*/ 03447 { 03448 he->tag = RPMTAG_CONFLICTNAME; 03449 return PRCOxmlTag(h, he, RPMTAG_CONFLICTVERSION, RPMTAG_CONFLICTFLAGS); 03450 } 03451 03452 static int OxmlTag(Header h, HE_t he) 03453 /*@globals internalState @*/ 03454 /*@modifies he, internalState @*/ 03455 { 03456 he->tag = RPMTAG_OBSOLETENAME; 03457 return PRCOxmlTag(h, he, RPMTAG_OBSOLETEVERSION, RPMTAG_OBSOLETEFLAGS); 03458 } 03459 03468 static /*@only@*/ char * spewescapeFormat(HE_t he, /*@null@*/ const char ** av, 03469 spew_t spew, int lvl) 03470 /*@*/ 03471 { 03472 int ix = (he->ix > 0 ? he->ix : 0); 03473 char * val; 03474 03475 assert(ix == 0); 03476 if (he->t != RPM_STRING_TYPE) { 03477 val = xstrdup(_("(not a string)")); 03478 } else { 03479 const char * s = strdup_locale_convert(he->p.str, (av ? av[0] : NULL)); 03480 size_t nb; 03481 char * t; 03482 03483 if (s == NULL) { 03484 /* XXX better error msg? */ 03485 val = xstrdup(_("(not a string)")); 03486 goto exit; 03487 } 03488 03489 nb = spew->spew_strlen(s, lvl); 03490 val = t = xcalloc(1, nb + 1); 03491 t = spew->spew_strcpy(t, s, lvl); t += strlen(t); 03492 *t = '\0'; 03493 s = _free(s); 03494 } 03495 03496 exit: 03497 return val; 03498 } 03499 03500 #ifndef DYING /* XXX is :json gud enuf? there are side effects ... */ 03501 static /*@only@*/ char * jsonescapeFormat(HE_t he, /*@null@*/ const char ** av) 03502 /*@*/ 03503 { 03504 return spewescapeFormat(he, av, &_json_spew, 0); 03505 } 03506 #endif 03507 03508 static /*@only@*/ char * sqlescapeFormat(HE_t he, /*@null@*/ const char ** av) 03509 /*@*/ 03510 { 03511 return spewescapeFormat(he, av, &_sql_spew, 0); 03512 } 03513 03514 /*@-compmempass -kepttrans -nullstate -usereleased @*/ 03515 static int PRCOsqlTag(Header h, HE_t he, rpmTag EVRtag, rpmTag Ftag) 03516 /*@globals internalState @*/ 03517 /*@modifies he, internalState @*/ 03518 { 03519 rpmTag tag = he->tag; 03520 rpmTagData N = { .ptr = NULL }; 03521 rpmTagData EVR = { .ptr = NULL }; 03522 rpmTagData F = { .ptr = NULL }; 03523 char instance[64]; 03524 size_t nb; 03525 rpmuint32_t ac; 03526 rpmuint32_t c; 03527 rpmuint32_t i; 03528 char *t; 03529 int rc = 1; /* assume failure */ 03530 int xx; 03531 03532 /*@-compmempass@*/ /* use separate HE_t, not rpmTagData, containers. */ 03533 xx = headerGet(h, he, 0); 03534 if (xx == 0) goto exit; 03535 N.argv = he->p.argv; 03536 c = he->c; 03537 03538 he->tag = EVRtag; 03539 xx = headerGet(h, he, 0); 03540 if (xx == 0) goto exit; 03541 EVR.argv = he->p.argv; 03542 03543 he->tag = Ftag; 03544 xx = headerGet(h, he, 0); 03545 if (xx == 0) goto exit; 03546 F.ui32p = he->p.ui32p; 03547 03548 xx = snprintf(instance, sizeof(instance), "'%u'", (unsigned)headerGetInstance(h)); 03549 nb = sizeof(*he->p.argv); 03550 ac = 0; 03551 for (i = 0; i < c; i++) { 03552 /*@-nullstate@*/ /* EVR.argv might be NULL */ 03553 if (PRCOSkip(tag, N, EVR, F, i)) 03554 continue; 03555 /*@=nullstate@*/ 03556 ac++; 03557 nb += sizeof(*he->p.argv); 03558 nb += strlen(instance) + sizeof(", '', '', '', '', ''"); 03559 if (tag == RPMTAG_REQUIRENAME) 03560 nb += sizeof(", ''") - 1; 03561 nb += strlen(N.argv[i]); 03562 if (EVR.argv != NULL && EVR.argv[i] != NULL && *EVR.argv[i] != '\0') { 03563 nb += strlen(EVR.argv[i]); 03564 nb += sizeof("EQ0") - 1; 03565 } 03566 #ifdef NOTNOW 03567 if (tag == RPMTAG_REQUIRENAME && (F.ui32p[i] & 0x40)) 03568 nb += sizeof("1") - 1; 03569 #endif 03570 } 03571 03572 he->t = RPM_STRING_ARRAY_TYPE; 03573 he->c = ac; 03574 he->freeData = 1; 03575 he->p.argv = xmalloc(nb + BUFSIZ); /* XXX hack: leave slop */ 03576 t = (char *) &he->p.argv[he->c + 1]; 03577 ac = 0; 03578 for (i = 0; i < c; i++) { 03579 /*@-nullstate@*/ /* EVR.argv might be NULL */ 03580 if (PRCOSkip(tag, N, EVR, F, i)) 03581 continue; 03582 /*@=nullstate@*/ 03583 he->p.argv[ac++] = t; 03584 t = stpcpy(t, instance); 03585 t = stpcpy( stpcpy( stpcpy(t, ", '"), N.argv[i]), "'"); 03586 /*@-readonlytrans@*/ 03587 if (EVR.argv != NULL && EVR.argv[i] != NULL && *EVR.argv[i] != '\0') { 03588 static char *Fstr[] = { "?0","LT","GT","?3","EQ","LE","GE","?7" }; 03589 rpmuint32_t Fx = ((F.ui32p[i] >> 1) & 0x7); 03590 const char *E, *V, *R; 03591 char *f, *fe; 03592 t = stpcpy( stpcpy( stpcpy(t, ", '"), Fstr[Fx]), "'"); 03593 f = (char *) EVR.argv[i]; 03594 for (fe = f; *fe != '\0' && *fe >= '0' && *fe <= '9'; fe++) 03595 {}; 03596 if (*fe == ':') { *fe++ = '\0'; E = f; f = fe; } else E = NULL; 03597 V = f; 03598 for (fe = f; *fe != '\0' && *fe != '-'; fe++) 03599 {}; 03600 if (*fe == '-') { *fe++ = '\0'; R = fe; } else R = NULL; 03601 t = stpcpy( stpcpy( stpcpy(t, ", '"), (E && *E ? E : "0")), "'"); 03602 t = stpcpy( stpcpy( stpcpy(t, ", '"), V), "'"); 03603 t = stpcpy( stpcpy( stpcpy(t, ", '"), (R ? R : "")), "'"); 03604 } else 03605 t = stpcpy(t, ", '', '', '', ''"); 03606 /*@=readonlytrans@*/ 03607 #ifdef NOTNOW 03608 if (tag == RPMTAG_REQUIRENAME) 03609 t = stpcpy(stpcpy(stpcpy(t, ", '"),(F.ui32p[i] & 0x40) ? "1" : "0"), "'"); 03610 #endif 03611 *t++ = '\0'; 03612 } 03613 he->p.argv[he->c] = NULL; 03614 /*@=compmempass@*/ 03615 rc = 0; 03616 03617 exit: 03618 /*@-kepttrans@*/ /* N.argv may be kept. */ 03619 N.argv = _free(N.argv); 03620 /*@=kepttrans@*/ 03621 /*@-usereleased@*/ /* EVR.argv may be dead. */ 03622 EVR.argv = _free(EVR.argv); 03623 /*@=usereleased@*/ 03624 F.ui32p = _free(F.ui32p); 03625 return rc; 03626 } 03627 03628 static int PsqlTag(Header h, HE_t he) 03629 /*@globals internalState @*/ 03630 /*@modifies he, internalState @*/ 03631 { 03632 he->tag = RPMTAG_PROVIDENAME; 03633 return PRCOsqlTag(h, he, RPMTAG_PROVIDEVERSION, RPMTAG_PROVIDEFLAGS); 03634 } 03635 03636 static int RsqlTag(Header h, HE_t he) 03637 /*@globals internalState @*/ 03638 /*@modifies he, internalState @*/ 03639 { 03640 he->tag = RPMTAG_REQUIRENAME; 03641 return PRCOsqlTag(h, he, RPMTAG_REQUIREVERSION, RPMTAG_REQUIREFLAGS); 03642 } 03643 03644 static int CsqlTag(Header h, HE_t he) 03645 /*@globals internalState @*/ 03646 /*@modifies he, internalState @*/ 03647 { 03648 he->tag = RPMTAG_CONFLICTNAME; 03649 return PRCOsqlTag(h, he, RPMTAG_CONFLICTVERSION, RPMTAG_CONFLICTFLAGS); 03650 } 03651 03652 static int OsqlTag(Header h, HE_t he) 03653 /*@globals internalState @*/ 03654 /*@modifies he, internalState @*/ 03655 { 03656 he->tag = RPMTAG_OBSOLETENAME; 03657 return PRCOsqlTag(h, he, RPMTAG_OBSOLETEVERSION, RPMTAG_OBSOLETEFLAGS); 03658 } 03659 03660 static int PRCOyamlTag(Header h, HE_t he, rpmTag EVRtag, rpmTag Ftag) 03661 /*@globals internalState @*/ 03662 /*@modifies he, internalState @*/ 03663 { 03664 rpmTag tag = he->tag; 03665 rpmTagData N = { .ptr = NULL }; 03666 rpmTagData EVR = { .ptr = NULL }; 03667 rpmTagData F = { .ptr = NULL }; 03668 size_t nb; 03669 rpmuint32_t ac; 03670 rpmuint32_t c; 03671 rpmuint32_t i; 03672 char *t; 03673 int rc = 1; /* assume failure */ 03674 int xx; 03675 int indent = 0; 03676 spew_t spew = &_yaml_spew; 03677 03678 /*@-compmempass@*/ /* use separate HE_t, not rpmTagData, containers. */ 03679 xx = headerGet(h, he, 0); 03680 if (xx == 0) goto exit; 03681 N.argv = he->p.argv; 03682 c = he->c; 03683 03684 he->tag = EVRtag; 03685 xx = headerGet(h, he, 0); 03686 if (xx == 0) goto exit; 03687 EVR.argv = he->p.argv; 03688 03689 he->tag = Ftag; 03690 xx = headerGet(h, he, 0); 03691 if (xx == 0) goto exit; 03692 F.ui32p = he->p.ui32p; 03693 03694 nb = sizeof(*he->p.argv); 03695 ac = 0; 03696 for (i = 0; i < c; i++) { 03697 /*@-nullstate@*/ /* EVR.argv might be NULL */ 03698 if (PRCOSkip(tag, N, EVR, F, i)) 03699 continue; 03700 /*@=nullstate@*/ 03701 ac++; 03702 nb += sizeof(*he->p.argv); 03703 nb += sizeof("- "); 03704 if (*N.argv[i] == '/') 03705 nb += spew->spew_strlen(N.argv[i], indent); 03706 else 03707 nb += strlen(N.argv[i]); 03708 if (EVR.argv != NULL && EVR.argv[i] != NULL && *EVR.argv[i] != '\0') { 03709 nb += sizeof(" >= ") - 1; 03710 nb += strlen(EVR.argv[i]); 03711 } 03712 } 03713 03714 he->t = RPM_STRING_ARRAY_TYPE; 03715 he->c = ac; 03716 he->freeData = 1; 03717 he->p.argv = xmalloc(nb + BUFSIZ); /* XXX hack: leave slop */ 03718 t = (char *) &he->p.argv[he->c + 1]; 03719 ac = 0; 03720 for (i = 0; i < c; i++) { 03721 /*@-nullstate@*/ /* EVR.argv might be NULL */ 03722 if (PRCOSkip(tag, N, EVR, F, i)) 03723 continue; 03724 /*@=nullstate@*/ 03725 he->p.argv[ac++] = t; 03726 t = stpcpy(t, "- "); 03727 if (*N.argv[i] == '/') { 03728 t = spew->spew_strcpy(t, N.argv[i], indent); t += strlen(t); 03729 } else 03730 t = stpcpy(t, N.argv[i]); 03731 /*@-readonlytrans@*/ 03732 if (EVR.argv != NULL && EVR.argv[i] != NULL && *EVR.argv[i] != '\0') { 03733 static char *Fstr[] = { "?0","<",">","?3","=","<=",">=","?7" }; 03734 rpmuint32_t Fx = ((F.ui32p[i] >> 1) & 0x7); 03735 t = stpcpy( stpcpy( stpcpy(t, " "), Fstr[Fx]), " "); 03736 t = stpcpy(t, EVR.argv[i]); 03737 } 03738 /*@=readonlytrans@*/ 03739 *t++ = '\0'; 03740 } 03741 he->p.argv[he->c] = NULL; 03742 /*@=compmempass@*/ 03743 rc = 0; 03744 03745 exit: 03746 /*@-kepttrans@*/ /* N.argv may be kept. */ 03747 N.argv = _free(N.argv); 03748 /*@=kepttrans@*/ 03749 /*@-usereleased@*/ /* EVR.argv may be dead. */ 03750 EVR.argv = _free(EVR.argv); 03751 /*@=usereleased@*/ 03752 F.ui32p = _free(F.ui32p); 03753 return rc; 03754 } 03755 03756 static int PyamlTag(Header h, HE_t he) 03757 /*@globals internalState @*/ 03758 /*@modifies he, internalState @*/ 03759 { 03760 int rc; 03761 he->tag = RPMTAG_PROVIDENAME; 03762 rc = PRCOyamlTag(h, he, RPMTAG_PROVIDEVERSION, RPMTAG_PROVIDEFLAGS); 03763 he->tag = RPMTAG_PROVIDEYAMLENTRY; 03764 return rc; 03765 } 03766 03767 static int RyamlTag(Header h, HE_t he) 03768 /*@globals internalState @*/ 03769 /*@modifies he, internalState @*/ 03770 { 03771 int rc; 03772 he->tag = RPMTAG_REQUIRENAME; 03773 rc = PRCOyamlTag(h, he, RPMTAG_REQUIREVERSION, RPMTAG_REQUIREFLAGS); 03774 he->tag = RPMTAG_REQUIREYAMLENTRY; 03775 return rc; 03776 } 03777 03778 static int CyamlTag(Header h, HE_t he) 03779 /*@globals internalState @*/ 03780 /*@modifies he, internalState @*/ 03781 { 03782 int rc; 03783 he->tag = RPMTAG_CONFLICTNAME; 03784 rc = PRCOyamlTag(h, he, RPMTAG_CONFLICTVERSION, RPMTAG_CONFLICTFLAGS); 03785 he->tag = RPMTAG_CONFLICTYAMLENTRY; 03786 return rc; 03787 } 03788 03789 static int OyamlTag(Header h, HE_t he) 03790 /*@globals internalState @*/ 03791 /*@modifies he, internalState @*/ 03792 { 03793 int rc; 03794 he->tag = RPMTAG_OBSOLETENAME; 03795 rc = PRCOyamlTag(h, he, RPMTAG_OBSOLETEVERSION, RPMTAG_OBSOLETEFLAGS); 03796 he->tag = RPMTAG_OBSOLETEYAMLENTRY; 03797 return rc; 03798 } 03799 03800 static int FDGSkip(rpmTagData DN, rpmTagData BN, rpmTagData DI, rpmuint32_t i) 03801 /*@*/ 03802 { 03803 const char * dn = DN.argv[DI.ui32p[i]]; 03804 size_t dnlen = strlen(dn); 03805 03806 assert(dn != NULL); 03807 if (strstr(dn, "bin/") != NULL) 03808 return 1; 03809 if (dnlen >= sizeof("/etc/")-1 && !strncmp(dn, "/etc/", dnlen)) 03810 return 1; 03811 if (!strcmp(dn, "/usr/lib/") && !strcmp(BN.argv[i], "sendmail")) 03812 return 1; 03813 return 2; 03814 } 03815 03816 static int FDGxmlTag(Header h, HE_t he, int lvl) 03817 /*@globals internalState @*/ 03818 /*@modifies he, internalState @*/ 03819 { 03820 rpmTagData BN = { .ptr = NULL }; 03821 rpmTagData DN = { .ptr = NULL }; 03822 rpmTagData DI = { .ptr = NULL }; 03823 rpmTagData FMODES = { .ptr = NULL }; 03824 rpmTagData FFLAGS = { .ptr = NULL }; 03825 size_t nb; 03826 rpmuint32_t ac; 03827 rpmuint32_t c; 03828 rpmuint32_t i; 03829 char *t; 03830 int rc = 1; /* assume failure */ 03831 int xx; 03832 spew_t spew = &_xml_spew; 03833 03834 /*@-compmempass@*/ /* use separate HE_t, not rpmTagData, containers. */ 03835 he->tag = RPMTAG_BASENAMES; 03836 xx = headerGet(h, he, 0); 03837 if (xx == 0) goto exit; 03838 BN.argv = he->p.argv; 03839 c = he->c; 03840 03841 he->tag = RPMTAG_DIRNAMES; 03842 xx = headerGet(h, he, 0); 03843 if (xx == 0) goto exit; 03844 DN.argv = he->p.argv; 03845 03846 he->tag = RPMTAG_DIRINDEXES; 03847 xx = headerGet(h, he, 0); 03848 if (xx == 0) goto exit; 03849 DI.ui32p = he->p.ui32p; 03850 03851 he->tag = RPMTAG_FILEMODES; 03852 xx = headerGet(h, he, 0); 03853 if (xx == 0) goto exit; 03854 FMODES.ui16p = he->p.ui16p; 03855 03856 he->tag = RPMTAG_FILEFLAGS; 03857 xx = headerGet(h, he, 0); 03858 if (xx == 0) goto exit; 03859 FFLAGS.ui32p = he->p.ui32p; 03860 03861 nb = sizeof(*he->p.argv); 03862 ac = 0; 03863 for (i = 0; i < c; i++) { 03864 if (lvl > 0 && FDGSkip(DN, BN, DI, i) != lvl) 03865 continue; 03866 ac++; 03867 nb += sizeof(*he->p.argv); 03868 nb += sizeof("<file></file>"); 03869 nb += spew->spew_strlen(DN.argv[DI.ui32p[i]], lvl); 03870 nb += spew->spew_strlen(BN.argv[i], lvl); 03871 if (FFLAGS.ui32p[i] & 0x40) /* XXX RPMFILE_GHOST */ 03872 nb += sizeof(" type=\"ghost\"") - 1; 03873 else if (S_ISDIR(FMODES.ui16p[i])) { 03874 nb += sizeof(" type=\"dir\"") - 1; 03875 #ifdef NOTYET 03876 nb += sizeof("/") - 1; 03877 #endif 03878 } 03879 } 03880 03881 he->t = RPM_STRING_ARRAY_TYPE; 03882 he->c = ac; 03883 he->freeData = 1; 03884 he->p.argv = xmalloc(nb); 03885 t = (char *) &he->p.argv[he->c + 1]; 03886 ac = 0; 03887 /* FIXME: Files, then dirs, finally ghosts breaks sort order. */ 03888 for (i = 0; i < c; i++) { 03889 if (lvl > 0 && FDGSkip(DN, BN, DI, i) != lvl) 03890 continue; 03891 if (FFLAGS.ui32p[i] & 0x40) /* XXX RPMFILE_GHOST */ 03892 continue; 03893 if (S_ISDIR(FMODES.ui16p[i])) 03894 continue; 03895 he->p.argv[ac++] = t; 03896 t = stpcpy(t, "<file>"); 03897 t = spew->spew_strcpy(t, DN.argv[DI.ui32p[i]], lvl); t += strlen(t); 03898 t = spew->spew_strcpy(t, BN.argv[i], lvl); t += strlen(t); 03899 t = stpcpy(t, "</file>"); 03900 *t++ = '\0'; 03901 } 03902 for (i = 0; i < c; i++) { 03903 if (lvl > 0 && FDGSkip(DN, BN, DI, i) != lvl) 03904 continue; 03905 if (FFLAGS.ui32p[i] & 0x40) /* XXX RPMFILE_GHOST */ 03906 continue; 03907 if (!S_ISDIR(FMODES.ui16p[i])) 03908 continue; 03909 he->p.argv[ac++] = t; 03910 t = stpcpy(t, "<file type=\"dir\">"); 03911 t = spew->spew_strcpy(t, DN.argv[DI.ui32p[i]], lvl); t += strlen(t); 03912 t = spew->spew_strcpy(t, BN.argv[i], lvl); t += strlen(t); 03913 #ifdef NOTYET 03914 /* Append the pesky trailing / to directories. */ 03915 if (t[-1] != '/') 03916 t = stpcpy(t, "/"); 03917 #endif 03918 t = stpcpy(t, "</file>"); 03919 *t++ = '\0'; 03920 } 03921 for (i = 0; i < c; i++) { 03922 if (lvl > 0 && FDGSkip(DN, BN, DI, i) != lvl) 03923 continue; 03924 if (!(FFLAGS.ui32p[i] & 0x40)) /* XXX RPMFILE_GHOST */ 03925 continue; 03926 he->p.argv[ac++] = t; 03927 t = stpcpy(t, "<file type=\"ghost\">"); 03928 t = spew->spew_strcpy(t, DN.argv[DI.ui32p[i]], lvl); t += strlen(t); 03929 t = spew->spew_strcpy(t, BN.argv[i], lvl); t += strlen(t); 03930 t = stpcpy(t, "</file>"); 03931 *t++ = '\0'; 03932 } 03933 03934 he->p.argv[he->c] = NULL; 03935 /*@=compmempass@*/ 03936 rc = 0; 03937 03938 exit: 03939 /*@-kepttrans@*/ /* {BN,DN,DI}.argv may be kept. */ 03940 BN.argv = _free(BN.argv); 03941 /*@-usereleased@*/ /* DN.argv may be dead. */ 03942 DN.argv = _free(DN.argv); 03943 /*@=usereleased@*/ 03944 DI.ui32p = _free(DI.ui32p); 03945 /*@=kepttrans@*/ 03946 FMODES.ui16p = _free(FMODES.ui16p); 03947 /*@-usereleased@*/ /* FFLAGS.argv may be dead. */ 03948 FFLAGS.ui32p = _free(FFLAGS.ui32p); 03949 /*@=usereleased@*/ 03950 return rc; 03951 } 03952 03953 static int F1xmlTag(Header h, HE_t he) 03954 /*@globals internalState @*/ 03955 /*@modifies he, internalState @*/ 03956 { 03957 he->tag = RPMTAG_BASENAMES; 03958 return FDGxmlTag(h, he, 1); 03959 } 03960 03961 static int F2xmlTag(Header h, HE_t he) 03962 /*@globals internalState @*/ 03963 /*@modifies he, internalState @*/ 03964 { 03965 he->tag = RPMTAG_BASENAMES; 03966 return FDGxmlTag(h, he, 2); 03967 } 03968 03969 static int FDGsqlTag(Header h, HE_t he, int lvl) 03970 /*@globals internalState @*/ 03971 /*@modifies he, internalState @*/ 03972 { 03973 rpmTagData BN = { .ptr = NULL }; 03974 rpmTagData DN = { .ptr = NULL }; 03975 rpmTagData DI = { .ptr = NULL }; 03976 rpmTagData FMODES = { .ptr = NULL }; 03977 rpmTagData FFLAGS = { .ptr = NULL }; 03978 char instance[64]; 03979 size_t nb; 03980 rpmuint32_t ac; 03981 rpmuint32_t c; 03982 rpmuint32_t i; 03983 char *t; 03984 int rc = 1; /* assume failure */ 03985 int xx; 03986 03987 /*@-compmempass@*/ /* use separate HE_t, not rpmTagData, containers. */ 03988 he->tag = RPMTAG_BASENAMES; 03989 xx = headerGet(h, he, 0); 03990 if (xx == 0) goto exit; 03991 BN.argv = he->p.argv; 03992 c = he->c; 03993 03994 he->tag = RPMTAG_DIRNAMES; 03995 xx = headerGet(h, he, 0); 03996 if (xx == 0) goto exit; 03997 DN.argv = he->p.argv; 03998 03999 he->tag = RPMTAG_DIRINDEXES; 04000 xx = headerGet(h, he, 0); 04001 if (xx == 0) goto exit; 04002 DI.ui32p = he->p.ui32p; 04003 04004 he->tag = RPMTAG_FILEMODES; 04005 xx = headerGet(h, he, 0); 04006 if (xx == 0) goto exit; 04007 FMODES.ui16p = he->p.ui16p; 04008 04009 he->tag = RPMTAG_FILEFLAGS; 04010 xx = headerGet(h, he, 0); 04011 if (xx == 0) goto exit; 04012 FFLAGS.ui32p = he->p.ui32p; 04013 04014 xx = snprintf(instance, sizeof(instance), "'%u'", (unsigned)headerGetInstance(h)); 04015 nb = sizeof(*he->p.argv); 04016 ac = 0; 04017 for (i = 0; i < c; i++) { 04018 if (lvl > 0 && FDGSkip(DN, BN, DI, i) != lvl) 04019 continue; 04020 ac++; 04021 nb += sizeof(*he->p.argv); 04022 nb += strlen(instance) + sizeof(", '', ''"); 04023 nb += strlen(DN.argv[DI.ui32p[i]]); 04024 nb += strlen(BN.argv[i]); 04025 if (FFLAGS.ui32p[i] & 0x40) /* XXX RPMFILE_GHOST */ 04026 nb += sizeof("ghost") - 1; 04027 else if (S_ISDIR(FMODES.ui16p[i])) { 04028 nb += sizeof("dir") - 1; 04029 #ifdef NOTYET 04030 nb += sizeof("/") - 1; 04031 #endif 04032 } else 04033 nb += sizeof("file") - 1; 04034 } 04035 04036 he->t = RPM_STRING_ARRAY_TYPE; 04037 he->c = ac; 04038 he->freeData = 1; 04039 he->p.argv = xmalloc(nb); 04040 t = (char *) &he->p.argv[he->c + 1]; 04041 ac = 0; 04042 /* FIXME: Files, then dirs, finally ghosts breaks sort order. */ 04043 for (i = 0; i < c; i++) { 04044 if (lvl > 0 && FDGSkip(DN, BN, DI, i) != lvl) 04045 continue; 04046 if (FFLAGS.ui32p[i] & 0x40) /* XXX RPMFILE_GHOST */ 04047 continue; 04048 if (S_ISDIR(FMODES.ui16p[i])) 04049 continue; 04050 he->p.argv[ac++] = t; 04051 t = stpcpy( stpcpy(t, instance), ", '"); 04052 t = strcpy(t, DN.argv[DI.ui32p[i]]); t += strlen(t); 04053 t = strcpy(t, BN.argv[i]); t += strlen(t); 04054 t = stpcpy(t, "', 'file'"); 04055 *t++ = '\0'; 04056 } 04057 for (i = 0; i < c; i++) { 04058 if (lvl > 0 && FDGSkip(DN, BN, DI, i) != lvl) 04059 continue; 04060 if (FFLAGS.ui32p[i] & 0x40) /* XXX RPMFILE_GHOST */ 04061 continue; 04062 if (!S_ISDIR(FMODES.ui16p[i])) 04063 continue; 04064 he->p.argv[ac++] = t; 04065 t = stpcpy( stpcpy(t, instance), ", '"); 04066 t = strcpy(t, DN.argv[DI.ui32p[i]]); t += strlen(t); 04067 t = strcpy(t, BN.argv[i]); t += strlen(t); 04068 #ifdef NOTYET 04069 /* Append the pesky trailing / to directories. */ 04070 if (t[-1] != '/') 04071 t = stpcpy(t, "/"); 04072 #endif 04073 t = stpcpy(t, "', 'dir'"); 04074 *t++ = '\0'; 04075 } 04076 for (i = 0; i < c; i++) { 04077 if (lvl > 0 && FDGSkip(DN, BN, DI, i) != lvl) 04078 continue; 04079 if (!(FFLAGS.ui32p[i] & 0x40)) /* XXX RPMFILE_GHOST */ 04080 continue; 04081 he->p.argv[ac++] = t; 04082 t = stpcpy( stpcpy(t, instance), ", '"); 04083 t = strcpy(t, DN.argv[DI.ui32p[i]]); t += strlen(t); 04084 t = strcpy(t, BN.argv[i]); t += strlen(t); 04085 t = stpcpy(t, "', 'ghost'"); 04086 *t++ = '\0'; 04087 } 04088 04089 he->p.argv[he->c] = NULL; 04090 /*@=compmempass@*/ 04091 rc = 0; 04092 04093 exit: 04094 /*@-kepttrans@*/ /* {BN,DN,DI}.argv may be kept. */ 04095 BN.argv = _free(BN.argv); 04096 /*@-usereleased@*/ /* DN.argv may be dead. */ 04097 DN.argv = _free(DN.argv); 04098 /*@=usereleased@*/ 04099 DI.ui32p = _free(DI.ui32p); 04100 /*@=kepttrans@*/ 04101 FMODES.ui16p = _free(FMODES.ui16p); 04102 /*@-usereleased@*/ /* FFLAGS.argv may be dead. */ 04103 FFLAGS.ui32p = _free(FFLAGS.ui32p); 04104 /*@=usereleased@*/ 04105 return rc; 04106 } 04107 04108 static int F1sqlTag(Header h, HE_t he) 04109 /*@globals internalState @*/ 04110 /*@modifies he, internalState @*/ 04111 { 04112 he->tag = RPMTAG_BASENAMES; 04113 return FDGsqlTag(h, he, 1); 04114 } 04115 04116 static int F2sqlTag(Header h, HE_t he) 04117 /*@globals internalState @*/ 04118 /*@modifies he, internalState @*/ 04119 { 04120 he->tag = RPMTAG_BASENAMES; 04121 return FDGsqlTag(h, he, 2); 04122 } 04123 04124 static int FDGyamlTag(Header h, HE_t he, int lvl) 04125 /*@globals internalState @*/ 04126 /*@modifies he, internalState @*/ 04127 { 04128 rpmTagData BN = { .ptr = NULL }; 04129 rpmTagData DN = { .ptr = NULL }; 04130 rpmTagData DI = { .ptr = NULL }; 04131 rpmTagData FMODES = { .ptr = NULL }; 04132 rpmTagData FFLAGS = { .ptr = NULL }; 04133 size_t nb; 04134 rpmuint32_t ac; 04135 rpmuint32_t c; 04136 rpmuint32_t i; 04137 char *t; 04138 int rc = 1; /* assume failure */ 04139 int xx; 04140 int indent = 0; 04141 spew_t spew = &_yaml_spew; 04142 04143 /*@-compmempass@*/ /* use separate HE_t, not rpmTagData, containers. */ 04144 he->tag = RPMTAG_BASENAMES; 04145 xx = headerGet(h, he, 0); 04146 if (xx == 0) goto exit; 04147 BN.argv = he->p.argv; 04148 c = he->c; 04149 04150 he->tag = RPMTAG_DIRNAMES; 04151 xx = headerGet(h, he, 0); 04152 if (xx == 0) goto exit; 04153 DN.argv = he->p.argv; 04154 04155 he->tag = RPMTAG_DIRINDEXES; 04156 xx = headerGet(h, he, 0); 04157 if (xx == 0) goto exit; 04158 DI.ui32p = he->p.ui32p; 04159 04160 he->tag = RPMTAG_FILEMODES; 04161 xx = headerGet(h, he, 0); 04162 if (xx == 0) goto exit; 04163 FMODES.ui16p = he->p.ui16p; 04164 04165 he->tag = RPMTAG_FILEFLAGS; 04166 xx = headerGet(h, he, 0); 04167 if (xx == 0) goto exit; 04168 FFLAGS.ui32p = he->p.ui32p; 04169 04170 nb = sizeof(*he->p.argv); 04171 ac = 0; 04172 for (i = 0; i < c; i++) { 04173 if (lvl > 0 && FDGSkip(DN, BN, DI, i) != lvl) 04174 continue; 04175 ac++; 04176 nb += sizeof(*he->p.argv); 04177 nb += sizeof("- "); 04178 nb += spew->spew_strlen(DN.argv[DI.ui32p[i]], indent); 04179 nb += spew->spew_strlen(BN.argv[i], indent); 04180 if (FFLAGS.ui32p[i] & 0x40) /* XXX RPMFILE_GHOST */ 04181 nb += sizeof("") - 1; 04182 else if (S_ISDIR(FMODES.ui16p[i])) 04183 nb += sizeof("/") - 1; 04184 } 04185 04186 he->t = RPM_STRING_ARRAY_TYPE; 04187 he->c = ac; 04188 he->freeData = 1; 04189 he->p.argv = xmalloc(nb); 04190 t = (char *) &he->p.argv[he->c + 1]; 04191 ac = 0; 04192 /* FIXME: Files, then dirs, finally ghosts breaks sort order. */ 04193 for (i = 0; i < c; i++) { 04194 if (lvl > 0 && FDGSkip(DN, BN, DI, i) != lvl) 04195 continue; 04196 if (FFLAGS.ui32p[i] & 0x40) /* XXX RPMFILE_GHOST */ 04197 continue; 04198 if (S_ISDIR(FMODES.ui16p[i])) 04199 continue; 04200 he->p.argv[ac++] = t; 04201 t = stpcpy(t, "- "); 04202 t = spew->spew_strcpy(t, DN.argv[DI.ui32p[i]], indent); t += strlen(t); 04203 t = spew->spew_strcpy(t, BN.argv[i], indent); t += strlen(t); 04204 t = stpcpy(t, ""); 04205 *t++ = '\0'; 04206 } 04207 for (i = 0; i < c; i++) { 04208 if (lvl > 0 && FDGSkip(DN, BN, DI, i) != lvl) 04209 continue; 04210 if (FFLAGS.ui32p[i] & 0x40) /* XXX RPMFILE_GHOST */ 04211 continue; 04212 if (!S_ISDIR(FMODES.ui16p[i])) 04213 continue; 04214 he->p.argv[ac++] = t; 04215 t = stpcpy(t, "- "); 04216 t = spew->spew_strcpy(t, DN.argv[DI.ui32p[i]], indent); t += strlen(t); 04217 t = spew->spew_strcpy(t, BN.argv[i], indent); t += strlen(t); 04218 /* Append the pesky trailing / to directories. */ 04219 if (t[-1] != '/') 04220 t = stpcpy(t, "/"); 04221 *t++ = '\0'; 04222 } 04223 for (i = 0; i < c; i++) { 04224 if (lvl > 0 && FDGSkip(DN, BN, DI, i) != lvl) 04225 continue; 04226 if (!(FFLAGS.ui32p[i] & 0x40)) /* XXX RPMFILE_GHOST */ 04227 continue; 04228 he->p.argv[ac++] = t; 04229 t = stpcpy(t, "- "); 04230 t = spew->spew_strcpy(t, DN.argv[DI.ui32p[i]], indent); t += strlen(t); 04231 t = spew->spew_strcpy(t, BN.argv[i], indent); t += strlen(t); 04232 *t++ = '\0'; 04233 } 04234 04235 he->p.argv[he->c] = NULL; 04236 /*@=compmempass@*/ 04237 rc = 0; 04238 04239 exit: 04240 /*@-kepttrans@*/ /* {BN,DN,DI}.argv may be kept. */ 04241 BN.argv = _free(BN.argv); 04242 /*@-usereleased@*/ /* DN.argv may be dead. */ 04243 DN.argv = _free(DN.argv); 04244 /*@=usereleased@*/ 04245 DI.ui32p = _free(DI.ui32p); 04246 /*@=kepttrans@*/ 04247 FMODES.ui16p = _free(FMODES.ui16p); 04248 /*@-usereleased@*/ /* FFLAGS.argv may be dead. */ 04249 FFLAGS.ui32p = _free(FFLAGS.ui32p); 04250 /*@=usereleased@*/ 04251 return rc; 04252 } 04253 04254 static int F1yamlTag(Header h, HE_t he) 04255 /*@globals internalState @*/ 04256 /*@modifies he, internalState @*/ 04257 { 04258 he->tag = RPMTAG_BASENAMES; 04259 return FDGyamlTag(h, he, 1); 04260 } 04261 04262 static int F2yamlTag(Header h, HE_t he) 04263 /*@globals internalState @*/ 04264 /*@modifies he, internalState @*/ 04265 { 04266 he->tag = RPMTAG_BASENAMES; 04267 return FDGyamlTag(h, he, 2); 04268 } 04269 04276 static /*@only@*/ char * bncdataFormat(HE_t he, /*@null@*/ const char ** av) 04277 /*@*/ 04278 { 04279 char * val; 04280 04281 if (he->t != RPM_STRING_TYPE) { 04282 val = xstrdup(_("(not a string)")); 04283 } else { 04284 const char * bn; 04285 const char * s; 04286 size_t nb; 04287 char * t; 04288 int lvl = 0; 04289 spew_t spew = &_xml_spew; 04290 04291 assert(he->p.str != NULL); 04292 /* Get rightmost '/' in string (i.e. basename(3) behavior). */ 04293 if ((bn = strrchr(he->p.str, '/')) != NULL) 04294 bn++; 04295 else 04296 bn = he->p.str; 04297 04298 /* Convert to utf8, escape for XML CDATA. */ 04299 s = strdup_locale_convert(bn, (av ? av[0] : NULL)); 04300 if (s == NULL) { 04301 /* XXX better error msg? */ 04302 val = xstrdup(_("(not a string)")); 04303 goto exit; 04304 } 04305 04306 nb = spew->spew_strlen(s, lvl); 04307 val = t = xcalloc(1, nb + 1); 04308 t = spew->spew_strcpy(t, s, lvl); t += strlen(t); 04309 *t = '\0'; 04310 s = _free(s); 04311 } 04312 04313 exit: 04314 return val; 04315 } 04316 04317 typedef struct key_s { 04318 /*@observer@*/ 04319 const char *name; /* key name */ 04320 rpmuint32_t value; 04321 } KEY; 04322 04323 /*@unchecked@*/ /*@observer@*/ 04324 static KEY keyDigests[] = { 04325 { "adler32", PGPHASHALGO_ADLER32 }, 04326 { "crc32", PGPHASHALGO_CRC32 }, 04327 { "crc64", PGPHASHALGO_CRC64 }, 04328 { "haval160", PGPHASHALGO_HAVAL_5_160 }, 04329 { "jlu32", PGPHASHALGO_JLU32 }, 04330 { "md2", PGPHASHALGO_MD2 }, 04331 { "md4", PGPHASHALGO_MD4 }, 04332 { "md5", PGPHASHALGO_MD5 }, 04333 { "rmd128", PGPHASHALGO_RIPEMD128 }, 04334 { "rmd160", PGPHASHALGO_RIPEMD160 }, 04335 { "rmd256", PGPHASHALGO_RIPEMD256 }, 04336 { "rmd320", PGPHASHALGO_RIPEMD320 }, 04337 { "salsa10", PGPHASHALGO_SALSA10 }, 04338 { "salsa20", PGPHASHALGO_SALSA20 }, 04339 { "sha1", PGPHASHALGO_SHA1 }, 04340 { "sha224", PGPHASHALGO_SHA224 }, 04341 { "sha256", PGPHASHALGO_SHA256 }, 04342 { "sha384", PGPHASHALGO_SHA384 }, 04343 { "sha512", PGPHASHALGO_SHA512 }, 04344 { "tiger192", PGPHASHALGO_TIGER192 }, 04345 }; 04346 /*@unchecked@*/ 04347 static size_t nkeyDigests = sizeof(keyDigests) / sizeof(keyDigests[0]); 04348 04352 enum keyStat_e { 04353 STAT_KEYS_NONE = 0, 04354 STAT_KEYS_DEV = (1U << 0), 04355 STAT_KEYS_INO = (1U << 1), 04356 STAT_KEYS_MODE = (1U << 2), 04357 STAT_KEYS_NLINK = (1U << 3), 04358 STAT_KEYS_UID = (1U << 4), 04359 STAT_KEYS_GID = (1U << 5), 04360 STAT_KEYS_RDEV = (1U << 6), 04361 STAT_KEYS_SIZE = (1U << 7), 04362 STAT_KEYS_BLKSIZE = (1U << 8), 04363 STAT_KEYS_BLOCKS = (1U << 9), 04364 STAT_KEYS_ATIME = (1U << 10), 04365 STAT_KEYS_CTIME = (1U << 11), 04366 STAT_KEYS_MTIME = (1U << 12), 04367 #ifdef NOTYET 04368 STAT_KEYS_FLAGS = (1U << 13), 04369 #endif 04370 STAT_KEYS_SLINK = (1U << 14), 04371 STAT_KEYS_DIGEST = (1U << 15), 04372 #ifdef NOTYET 04373 STAT_KEYS_FCONTEXT = (1U << 16), 04374 #endif 04375 STAT_KEYS_UNAME = (1U << 17), 04376 STAT_KEYS_GNAME = (1U << 18), 04377 }; 04378 04379 /*@unchecked@*/ /*@observer@*/ 04380 static KEY keyStat[] = { 04381 { "adler32", STAT_KEYS_DIGEST }, 04382 { "atime", STAT_KEYS_ATIME }, 04383 { "ctime", STAT_KEYS_CTIME }, 04384 { "blksize", STAT_KEYS_BLKSIZE }, 04385 { "blocks", STAT_KEYS_BLOCKS }, 04386 { "crc32", STAT_KEYS_DIGEST }, 04387 { "crc64", STAT_KEYS_DIGEST }, 04388 { "dev", STAT_KEYS_DEV }, 04389 #ifdef NOTYET 04390 { "digest", STAT_KEYS_DIGEST }, 04391 { "fcontext", STAT_KEYS_FCONTEXT }, 04392 { "flags", STAT_KEYS_FLAGS }, 04393 #endif 04394 { "gid", STAT_KEYS_GID }, 04395 { "gname", STAT_KEYS_GNAME }, 04396 { "haval160", STAT_KEYS_DIGEST }, 04397 { "ino", STAT_KEYS_INO }, 04398 { "jlu32", STAT_KEYS_DIGEST }, 04399 { "link", STAT_KEYS_SLINK }, 04400 { "md2", STAT_KEYS_DIGEST }, 04401 { "md4", STAT_KEYS_DIGEST }, 04402 { "md5", STAT_KEYS_DIGEST }, 04403 { "mode", STAT_KEYS_MODE }, 04404 { "mtime", STAT_KEYS_MTIME }, 04405 { "nlink", STAT_KEYS_NLINK }, 04406 { "rdev", STAT_KEYS_RDEV }, 04407 { "rmd128", STAT_KEYS_DIGEST }, 04408 { "rmd160", STAT_KEYS_DIGEST }, 04409 { "rmd256", STAT_KEYS_DIGEST }, 04410 { "rmd320", STAT_KEYS_DIGEST }, 04411 { "salsa10", STAT_KEYS_DIGEST }, 04412 { "salsa20", STAT_KEYS_DIGEST }, 04413 { "sha1", STAT_KEYS_DIGEST }, 04414 { "sha224", STAT_KEYS_DIGEST }, 04415 { "sha256", STAT_KEYS_DIGEST }, 04416 { "sha384", STAT_KEYS_DIGEST }, 04417 { "sha512", STAT_KEYS_DIGEST }, 04418 { "size", STAT_KEYS_SIZE }, 04419 { "tiger192", STAT_KEYS_DIGEST }, 04420 { "uid", STAT_KEYS_UID }, 04421 { "uname", STAT_KEYS_UNAME }, 04422 }; 04423 /*@unchecked@*/ 04424 static size_t nkeyStat = sizeof(keyStat) / sizeof(keyStat[0]); 04425 04429 enum keyUuids_e { 04430 UUID_KEYS_NONE = (0U << 0), 04431 UUID_KEYS_V1 = (1U << 0), 04432 UUID_KEYS_V3 = (3U << 0), 04433 UUID_KEYS_V4 = (4U << 0), 04434 UUID_KEYS_V5 = (5U << 0), 04435 #ifdef NOTYET 04436 UUID_KEYS_STRING = (0U << 4), 04437 UUID_KEYS_SIV = (1U << 4), 04438 UUID_KEYS_BINARY = (2U << 4), 04439 UUID_KEYS_TEXT = (3U << 4), 04440 #endif 04441 }; 04442 04443 /*@unchecked@*/ /*@observer@*/ 04444 static KEY keyUuids[] = { 04445 #ifdef NOTYET 04446 { "binary", UUID_KEYS_BINARY }, 04447 { "siv", UUID_KEYS_SIV }, 04448 { "string", UUID_KEYS_STRING }, 04449 { "text", UUID_KEYS_TEXT }, 04450 #endif 04451 { "v1", UUID_KEYS_V1 }, 04452 { "v3", UUID_KEYS_V3 }, 04453 { "v4", UUID_KEYS_V4 }, 04454 { "v5", UUID_KEYS_V5 }, 04455 }; 04456 /*@unchecked@*/ 04457 static size_t nkeyUuids = sizeof(keyUuids) / sizeof(keyUuids[0]); 04458 04461 static int 04462 keyCmp(const void * a, const void * b) 04463 /*@*/ 04464 { 04465 return strcmp(((KEY *)a)->name, ((KEY *)b)->name); 04466 } 04467 04470 static rpmuint32_t 04471 keyValue(KEY * keys, size_t nkeys, /*@null@*/ const char *name) 04472 /*@*/ 04473 { 04474 rpmuint32_t keyval = 0; 04475 04476 if (name && * name) { 04477 KEY needle = { .name = name, .value = 0 }; 04478 KEY *k = (KEY *)bsearch(&needle, keys, nkeys, sizeof(*keys), keyCmp); 04479 if (k) 04480 keyval = k->value; 04481 } 04482 return keyval; 04483 } 04484 04491 static /*@only@*/ char * digestFormat(HE_t he, /*@null@*/ const char ** av) 04492 /*@*/ 04493 { 04494 int ix = (he->ix > 0 ? he->ix : 0); 04495 char * val = NULL; 04496 size_t ns; 04497 04498 assert(ix == 0); 04499 switch(he->t) { 04500 default: 04501 val = xstrdup(_("(invalid type :digest)")); 04502 goto exit; 04503 /*@notreached@*/ break; 04504 case RPM_UINT64_TYPE: 04505 ns = sizeof(he->p.ui64p[0]); 04506 break; 04507 case RPM_STRING_TYPE: 04508 ns = strlen(he->p.str); 04509 break; 04510 case RPM_BIN_TYPE: 04511 ns = he->c; 04512 break; 04513 } 04514 04515 assert(he->p.ptr != NULL); 04516 { rpmuint32_t keyval = keyValue(keyDigests, nkeyDigests, (av ? av[0] : NULL)); 04517 rpmuint32_t algo = (keyval ? keyval : PGPHASHALGO_SHA1); 04518 DIGEST_CTX ctx = rpmDigestInit(algo, 0); 04519 int xx = rpmDigestUpdate(ctx, he->p.ptr, ns); 04520 xx = rpmDigestFinal(ctx, &val, NULL, 1); 04521 } 04522 04523 exit: 04524 return val; 04525 } 04526 04533 static /*@only@*/ char * statFormat(HE_t he, /*@null@*/ const char ** av) 04534 /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/ 04535 /*@modifies rpmGlobalMacroContext, fileSystem, internalState @*/ 04536 { 04537 /*@-nullassign@*/ 04538 /*@unchecked@*/ /*@observer@*/ 04539 static const char *avdefault[] = { "mode", NULL }; 04540 /*@=nullassign@*/ 04541 const char * fn = NULL; 04542 struct stat sb, *st = &sb; 04543 int ix = (he->ix > 0 ? he->ix : 0); 04544 char * val = NULL; 04545 int xx; 04546 int i; 04547 04548 memset(st, 0, sizeof(*st)); 04549 assert(ix == 0); 04550 switch(he->t) { 04551 case RPM_BIN_TYPE: 04552 /* XXX limit to RPMTAG_PACKAGESTAT ... */ 04553 if (he->tag == RPMTAG_PACKAGESTAT) 04554 if ((size_t)he->c == sizeof(*st)) { 04555 st = (struct stat *)he->p.ptr; 04556 break; 04557 } 04558 /*@fallthrough @*/ 04559 default: 04560 val = xstrdup(_("(invalid type :stat)")); 04561 goto exit; 04562 /*@notreached@*/ break; 04563 case RPM_STRING_TYPE: 04564 fn = he->p.str; 04565 if (Lstat(fn, st) == 0) 04566 break; 04567 /*@-ownedtrans@*/ 04568 val = rpmExpand("(Lstat:", fn, ":", strerror(errno), ")", NULL); 04569 /*@=ownedtrans@*/ 04570 goto exit; 04571 /*@notreached@*/ break; 04572 } 04573 04574 if (!(av && av[0] && *av[0])) 04575 av = avdefault; 04576 for (i = 0; av[i] != NULL; i++) { 04577 char b[BUFSIZ]; 04578 size_t nb = sizeof(b); 04579 char * nval; 04580 rpmuint32_t keyval = keyValue(keyStat, nkeyStat, av[i]); 04581 04582 nval = NULL; 04583 b[0] = '\0'; 04584 switch (keyval) { 04585 default: 04586 /*@switchbreak@*/ break; 04587 case STAT_KEYS_NONE: 04588 /*@switchbreak@*/ break; 04589 case STAT_KEYS_DEV: 04590 xx = snprintf(b, nb, "0x%lx", (unsigned long)st->st_dev); 04591 /*@switchbreak@*/ break; 04592 case STAT_KEYS_INO: 04593 xx = snprintf(b, nb, "0x%lx", (unsigned long)st->st_ino); 04594 /*@switchbreak@*/ break; 04595 case STAT_KEYS_MODE: 04596 xx = snprintf(b, nb, "%06o", (unsigned)st->st_mode); 04597 /*@switchbreak@*/ break; 04598 case STAT_KEYS_NLINK: 04599 xx = snprintf(b, nb, "0x%ld", (unsigned long)st->st_nlink); 04600 /*@switchbreak@*/ break; 04601 case STAT_KEYS_UID: 04602 xx = snprintf(b, nb, "%ld", (unsigned long)st->st_uid); 04603 /*@switchbreak@*/ break; 04604 case STAT_KEYS_GID: 04605 xx = snprintf(b, nb, "%ld", (unsigned long)st->st_gid); 04606 /*@switchbreak@*/ break; 04607 case STAT_KEYS_RDEV: 04608 xx = snprintf(b, nb, "0x%lx", (unsigned long)st->st_rdev); 04609 /*@switchbreak@*/ break; 04610 case STAT_KEYS_SIZE: 04611 xx = snprintf(b, nb, "%ld", (unsigned long)st->st_size); 04612 /*@switchbreak@*/ break; 04613 case STAT_KEYS_BLKSIZE: 04614 xx = snprintf(b, nb, "%ld", (unsigned long)st->st_blksize); 04615 /*@switchbreak@*/ break; 04616 case STAT_KEYS_BLOCKS: 04617 xx = snprintf(b, nb, "%ld", (unsigned long)st->st_blocks); 04618 /*@switchbreak@*/ break; 04619 case STAT_KEYS_ATIME: 04620 /*@i@*/ (void) stpcpy(b, ctime((time_t *)&st->st_atime)); 04621 /*@switchbreak@*/ break; 04622 case STAT_KEYS_CTIME: 04623 /*@i@*/ (void) stpcpy(b, ctime((time_t *)&st->st_ctime)); 04624 /*@switchbreak@*/ break; 04625 case STAT_KEYS_MTIME: 04626 /*@i@*/ (void) stpcpy(b, ctime((time_t *)&st->st_mtime)); 04627 /*@switchbreak@*/ break; 04628 #ifdef NOTYET 04629 case STAT_KEYS_FLAGS: 04630 /*@switchbreak@*/ break; 04631 #endif 04632 case STAT_KEYS_SLINK: 04633 if (fn != NULL && S_ISLNK(st->st_mode)) { 04634 ssize_t size = Readlink(fn, b, nb); 04635 if (size == -1) { 04636 nval = rpmExpand("(Readlink:", fn, ":", strerror(errno), ")", NULL); 04637 (void) stpcpy(b, nval); 04638 nval = _free(nval); 04639 } else 04640 b[size] = '\0'; 04641 } 04642 /*@switchbreak@*/ break; 04643 case STAT_KEYS_DIGEST: 04644 if (fn != NULL && S_ISREG(st->st_mode)) { 04645 rpmuint32_t digval = keyValue(keyDigests, nkeyDigests, av[i]); 04646 rpmuint32_t algo = (digval ? digval : PGPHASHALGO_SHA1); 04647 FD_t fd = Fopen(fn, "r%{?_rpmgio}"); 04648 if (fd == NULL || Ferror(fd)) { 04649 nval = rpmExpand("(Fopen:", fn, ":", Fstrerror(fd), ")", NULL); 04650 } else { 04651 static int asAscii = 1; 04652 char buffer[16 * 1024]; 04653 fdInitDigest(fd, algo, 0); 04654 while (Fread(buffer, sizeof(buffer[0]), sizeof(buffer), fd) > 0) 04655 {}; 04656 if (Ferror(fd)) 04657 nval = rpmExpand("(Fread:", fn, ":", Fstrerror(fd), ")", NULL); 04658 else 04659 fdFiniDigest(fd, algo, &nval, NULL, asAscii); 04660 } 04661 if (nval) { 04662 (void) stpcpy(b, nval); 04663 nval = _free(nval); 04664 } 04665 if (fd != NULL) 04666 xx = Fclose(fd); 04667 } 04668 /*@switchbreak@*/ break; 04669 case STAT_KEYS_UNAME: 04670 { const char * uname = uidToUname(st->st_uid); 04671 if (uname != NULL) 04672 (void) stpcpy(b, uname); 04673 else 04674 xx = snprintf(b, nb, "%u", (unsigned)st->st_uid); 04675 } /*@switchbreak@*/ break; 04676 case STAT_KEYS_GNAME: 04677 { const char * gname = gidToGname(st->st_gid); 04678 if (gname != NULL) 04679 (void) stpcpy(b, gname); 04680 else 04681 xx = snprintf(b, nb, "%u", (unsigned)st->st_gid); 04682 } /*@switchbreak@*/ break; 04683 } 04684 if (b[0] == '\0') 04685 continue; 04686 b[nb-1] = '\0'; 04687 04688 if (val == NULL) 04689 val = xstrdup(b); 04690 else { 04691 nval = rpmExpand(val, " | ", b, NULL); 04692 val = _free(val); 04693 val = nval; 04694 } 04695 } 04696 04697 exit: 04698 return val; 04699 } 04700 04707 static /*@only@*/ char * uuidFormat(HE_t he, /*@null@*/ const char ** av) 04708 /*@globals rpmGlobalMacroContext, h_errno, internalState @*/ 04709 /*@modifies rpmGlobalMacroContext, internalState @*/ 04710 { 04711 static const char hex[] = "0123456789abcdef"; 04712 /* XXX use private tag container to avoid memory issues for now. */ 04713 HE_t nhe = memset(alloca(sizeof(*nhe)), 0, sizeof(*nhe)); 04714 /*@-nullassign@*/ 04715 /*@unchecked@*/ /*@observer@*/ 04716 static const char *avdefault[] = { "v5", NULL }; 04717 /*@=nullassign@*/ 04718 int ix = (he->ix > 0 ? he->ix : 0); 04719 char * val = NULL; 04720 struct timeval tv; 04721 char * t; 04722 char * te; 04723 uint32_t i; 04724 04725 assert(ix == 0); 04726 val = xmalloc((128/4 + 4) + 1); 04727 *val = '\0'; 04728 04729 nhe->tag = he->tag; 04730 nhe->t = he->t; 04731 switch(he->t) { 04732 default: 04733 val = _free(val); 04734 val = xstrdup(_("(invalid type :uuid)")); 04735 goto exit; 04736 /*@notreached@*/ break; 04737 case RPM_UINT64_TYPE: 04738 /* XXX Limit to tag time stamps with UUIDv1 direct conversion. */ 04739 switch (he->tag) { 04740 default: 04741 val = _free(val); 04742 val = xstrdup(_("(invalid tag :uuid)")); 04743 goto exit; 04744 break; 04745 case RPMTAG_INSTALLTIME: 04746 case RPMTAG_BUILDTIME: 04747 case RPMTAG_ORIGINTIME: 04748 case RPMTAG_INSTALLTID: 04749 case RPMTAG_REMOVETID: 04750 case RPMTAG_ORIGINTID: 04751 04752 /* Convert tag time stamp to UUIDv1. */ 04753 tv.tv_sec = (long) he->p.ui64p[0]; 04754 tv.tv_usec = (long) (he->c > 1 ? he->p.ui64p[1] : 0); 04755 ix = tv2uuidv1(NULL, nhe, &tv); 04756 04757 /* Convert UUIDv1 to display string. */ 04758 te = val; 04759 for (i = 0; i < nhe->c; i++) { 04760 *te++ = hex[ (int)((nhe->p.ui8p[i] >> 4) & 0x0f) ]; 04761 *te++ = hex[ (int)((nhe->p.ui8p[i] ) & 0x0f) ]; 04762 if (i == 3 || i == 5 || i == 7 || i == 9) 04763 *te++ = '-'; 04764 } 04765 *te = '\0'; 04766 goto exit; /* XXX immediate exit for UUIDv1 */ 04767 break; 04768 } 04769 break; 04770 case RPM_BIN_TYPE: 04771 /* XXX Limit to tag binary digests with djb formatting in UUIDv5. */ 04772 switch (he->tag) { 04773 default: 04774 val = _free(val); 04775 val = xstrdup(_("(invalid tag :uuid)")); 04776 goto exit; 04777 break; 04778 case RPMTAG_PKGID: 04779 case RPMTAG_SOURCEPKGID: 04780 /* Convert RPMTAG_*PKGID from binary => hex. */ 04781 t = te = xmalloc(2*he->c + 1); 04782 for (i = 0; i < he->c; i++) { 04783 *te++ = hex[ (int)((he->p.ui8p[i] >> 4) & 0x0f) ]; 04784 *te++ = hex[ (int)((he->p.ui8p[i] ) & 0x0f) ]; 04785 } 04786 *te = '\0'; 04787 nhe->t = RPM_STRING_TYPE; 04788 nhe->p.ptr = t; 04789 nhe->c = 1; 04790 break; 04791 } 04792 break; 04793 case RPM_STRING_TYPE: 04794 nhe->c = 1; 04795 nhe->p.ptr = xstrdup(he->p.str); 04796 break; 04797 } 04798 04799 if (!(av && av[0] && *av[0])) 04800 av = avdefault; 04801 04802 for (i = 0; av[i] != NULL; i++) { 04803 uint32_t keyval = keyValue(keyUuids, nkeyUuids, av[i]); 04804 04805 switch (keyval) { 04806 default: 04807 /*@switchbreak@*/ break; 04808 case UUID_KEYS_V1: 04809 case UUID_KEYS_V3: 04810 case UUID_KEYS_V4: 04811 case UUID_KEYS_V5: 04812 ix = str2uuid(nhe, NULL, keyval, val); 04813 goto exit; /* XXX exit after first found. */ 04814 break; 04815 } 04816 } 04817 04818 exit: 04819 nhe->p.ptr = _free(nhe->p.ptr); 04820 return val; 04821 } 04822 04829 static /*@only@*/ char * rpnFormat(HE_t he, /*@null@*/ const char ** av) 04830 /*@*/ 04831 { 04832 int ac = argvCount(av) + 1; 04833 int64_t * stack = memset(alloca(ac*sizeof(*stack)), 0, (ac*sizeof(*stack))); 04834 char * end; 04835 char * val = NULL; 04836 int ix = 0; 04837 int i; 04838 04839 switch(he->t) { 04840 default: 04841 val = xstrdup(_("(invalid type :rpn)")); 04842 goto exit; 04843 /*@notreached@*/ break; 04844 case RPM_UINT64_TYPE: 04845 stack[ix] = he->p.ui64p[0]; 04846 break; 04847 case RPM_STRING_TYPE: 04848 end = NULL; 04849 /*@-unrecog@*/ /* Add annotated prototype. */ 04850 stack[ix] = strtoll(he->p.str, &end, 0); 04851 /*@=unrecog@*/ 04852 if (end && *end != '\0') { 04853 val = xstrdup(_("(invalid string :rpn)")); 04854 goto exit; 04855 } 04856 break; 04857 } 04858 04859 if (av != NULL) 04860 for (i = 0; av[i] != NULL; i++) { 04861 const char * arg = av[i]; 04862 size_t len = strlen(arg); 04863 int c = (int) *arg; 04864 04865 if (len == 0) { 04866 /* do nothing */ 04867 } else if (len > 1) { 04868 if (!(xisdigit(c) || (c == (int)'-' && xisdigit((int) arg[1])))) { 04869 val = xstrdup(_("(expected number :rpn)")); 04870 goto exit; 04871 } 04872 if (++ix == ac) { 04873 val = xstrdup(_("(stack overflow :rpn)")); 04874 goto exit; 04875 } 04876 end = NULL; 04877 stack[ix] = strtoll(arg, &end, 0); 04878 if (end && *end != '\0') { 04879 val = xstrdup(_("(invalid number :rpn)")); 04880 goto exit; 04881 } 04882 } else { 04883 if (ix-- < 1) { 04884 val = xstrdup(_("(stack underflow :rpn)")); 04885 goto exit; 04886 } 04887 switch (c) { 04888 case '&': stack[ix] &= stack[ix+1]; /*@switchbreak@*/ break; 04889 case '|': stack[ix] |= stack[ix+1]; /*@switchbreak@*/ break; 04890 case '^': stack[ix] ^= stack[ix+1]; /*@switchbreak@*/ break; 04891 case '+': stack[ix] += stack[ix+1]; /*@switchbreak@*/ break; 04892 case '-': stack[ix] -= stack[ix+1]; /*@switchbreak@*/ break; 04893 case '*': stack[ix] *= stack[ix+1]; /*@switchbreak@*/ break; 04894 case '%': 04895 case '/': 04896 if (stack[ix+1] == 0) { 04897 val = xstrdup(_("(divide by zero :rpn)")); 04898 goto exit; 04899 } 04900 if (c == (int)'%') 04901 stack[ix] %= stack[ix+1]; 04902 else 04903 stack[ix] /= stack[ix+1]; 04904 /*@switchbreak@*/ break; 04905 } 04906 } 04907 } 04908 04909 { HE_t nhe = memset(alloca(sizeof(*nhe)), 0, sizeof(*nhe)); 04910 nhe->tag = he->tag; 04911 nhe->t = RPM_UINT64_TYPE; 04912 nhe->p.ui64p = (rpmuint64_t *)&stack[ix]; 04913 nhe->c = 1; 04914 val = intFormat(nhe, NULL, NULL); 04915 } 04916 04917 exit: 04918 return val; 04919 } 04920 04927 static /*@only@*/ char * strsubFormat(HE_t he, /*@null@*/ const char ** av) 04928 /*@globals rpmGlobalMacroContext, h_errno, internalState @*/ 04929 /*@modifies rpmGlobalMacroContext, internalState @*/ 04930 { 04931 char * val = NULL; 04932 int ac = argvCount(av); 04933 miRE mires = NULL; 04934 int nmires = 0; 04935 int xx; 04936 int i; 04937 04938 switch(he->t) { 04939 default: 04940 val = xstrdup(_("(invalid type :strsub)")); 04941 goto exit; 04942 /*@notreached@*/ break; 04943 case RPM_STRING_TYPE: 04944 if (ac < 2 || (ac % 2) != 0) { 04945 val = xstrdup(_("(invalid args :strsub)")); 04946 goto exit; 04947 } 04948 break; 04949 } 04950 if (av == NULL) 04951 goto noop; 04952 04953 /* Create the mire pattern array. */ 04954 for (i = 0; av[i] != NULL; i += 2) 04955 xx = mireAppend(RPMMIRE_REGEX, 0, av[i], NULL, &mires, &nmires); 04956 04957 /* Find-and-replace first pattern that matches. */ 04958 if (mires != NULL) { 04959 int noffsets = 3; 04960 int offsets[3]; 04961 const char * s, * se; 04962 char * t, * te; 04963 char * nval; 04964 size_t slen; 04965 size_t nb; 04966 04967 for (i = 0; i < nmires; i++) { 04968 miRE mire = mires + i; 04969 04970 s = he->p.str; 04971 slen = strlen(s); 04972 if ((xx = mireRegexec(mire, s, slen)) < 0) 04973 continue; 04974 xx = mireSetEOptions(mire, offsets, noffsets); 04975 04976 /* Replace the string(s). This is just s/find/replace/g */ 04977 val = xstrdup(""); 04978 while (*s != '\0') { 04979 nb = strlen(s); 04980 if ((se = strchr(s, '\n')) == NULL) 04981 se = s + nb; 04982 else 04983 se++; 04984 04985 offsets[0] = offsets[1] = -1; 04986 xx = mireRegexec(mire, s, nb); 04987 04988 nb = 1; 04989 /* On match, copy lead-in and match string. */ 04990 if (xx == 0) 04991 nb += offsets[0] + strlen(av[2*i+1]); 04992 /* Copy up to EOL on nomatch or insertion. */ 04993 if (xx != 0 || offsets[1] == offsets[0]) 04994 nb += (se - (s + offsets[1])); 04995 04996 te = t = xmalloc(nb); 04997 04998 /* On match, copy lead-in and match string. */ 04999 if (xx == 0) { 05000 te = stpcpy( stpncpy(te, s, offsets[0]), av[2*i+1]); 05001 s += offsets[1]; 05002 } 05003 /* Copy up to EOL on nomatch or insertion. */ 05004 if (xx != 0 || offsets[1] == offsets[0]) { 05005 s += offsets[1]; 05006 te = stpncpy(te, s, (se - s)); 05007 s = se; 05008 } 05009 *te = '\0'; 05010 05011 nval = rpmExpand(val, t, NULL); 05012 val = _free(val); 05013 val = nval; 05014 t = _free(t); 05015 } 05016 } 05017 mires = mireFreeAll(mires, nmires); 05018 } 05019 05020 noop: 05021 if (val == NULL) 05022 val = xstrdup(he->p.str); 05023 exit: 05024 return val; 05025 } 05026 05027 static struct headerSprintfExtension_s _headerCompoundFormats[] = { 05028 { HEADER_EXT_TAG, "RPMTAG_BUILDTIMEUUID", 05029 { .tagFunction = buildtime_uuidTag } }, 05030 { HEADER_EXT_TAG, "RPMTAG_CHANGELOGNAME", 05031 { .tagFunction = changelognameTag } }, 05032 { HEADER_EXT_TAG, "RPMTAG_CHANGELOGTEXT", 05033 { .tagFunction = changelogtextTag } }, 05034 { HEADER_EXT_TAG, "RPMTAG_DESCRIPTION", 05035 { .tagFunction = descriptionTag } }, 05036 { HEADER_EXT_TAG, "RPMTAG_GROUP", 05037 { .tagFunction = groupTag } }, 05038 { HEADER_EXT_TAG, "RPMTAG_HDRUUID", 05039 { .tagFunction = hdruuidTag } }, 05040 { HEADER_EXT_TAG, "RPMTAG_INSTALLPREFIX", 05041 { .tagFunction = instprefixTag } }, 05042 { HEADER_EXT_TAG, "RPMTAG_INSTALLTIDUUID", 05043 { .tagFunction = installtid_uuidTag } }, 05044 { HEADER_EXT_TAG, "RPMTAG_INSTALLTIMEUUID", 05045 { .tagFunction = installtime_uuidTag } }, 05046 { HEADER_EXT_TAG, "RPMTAG_ORIGINTIDUUID", 05047 { .tagFunction = origintid_uuidTag } }, 05048 { HEADER_EXT_TAG, "RPMTAG_ORIGINTIMEUUID", 05049 { .tagFunction = origintime_uuidTag } }, 05050 { HEADER_EXT_TAG, "RPMTAG_PKGUUID", 05051 { .tagFunction = pkguuidTag } }, 05052 { HEADER_EXT_TAG, "RPMTAG_REMOVETIDUUID", 05053 { .tagFunction = removetid_uuidTag } }, 05054 { HEADER_EXT_TAG, "RPMTAG_SOURCEPKGUUID", 05055 { .tagFunction = sourcepkguuidTag } }, 05056 { HEADER_EXT_TAG, "RPMTAG_SUMMARY", 05057 { .tagFunction = summaryTag } }, 05058 { HEADER_EXT_TAG, "RPMTAG_TRIGGERCONDS", 05059 { .tagFunction = triggercondsTag } }, 05060 { HEADER_EXT_TAG, "RPMTAG_TRIGGERTYPE", 05061 { .tagFunction = triggertypeTag } }, 05062 { HEADER_EXT_TAG, "RPMTAG_DBINSTANCE", 05063 { .tagFunction = dbinstanceTag } }, 05064 { HEADER_EXT_TAG, "RPMTAG_HEADERSTARTOFF", 05065 { .tagFunction = headerstartoffTag } }, 05066 { HEADER_EXT_TAG, "RPMTAG_HEADERENDOFF", 05067 { .tagFunction = headerendoffTag } }, 05068 { HEADER_EXT_TAG, "RPMTAG_PACKAGEBASEURL", 05069 { .tagFunction = pkgbaseurlTag } }, 05070 { HEADER_EXT_TAG, "RPMTAG_PACKAGEDIGEST", 05071 { .tagFunction = pkgdigestTag } }, 05072 { HEADER_EXT_TAG, "RPMTAG_PACKAGEORIGIN", 05073 { .tagFunction = pkgoriginTag } }, 05074 { HEADER_EXT_TAG, "RPMTAG_PACKAGESIZE", 05075 { .tagFunction = pkgsizeTag } }, 05076 { HEADER_EXT_TAG, "RPMTAG_PACKAGETIME", 05077 { .tagFunction = pkgmtimeTag } }, 05078 { HEADER_EXT_TAG, "RPMTAG_NVRA", 05079 { .tagFunction = nvraTag } }, 05080 { HEADER_EXT_TAG, "RPMTAG_FILENAMES", 05081 { .tagFunction = filenamesTag } }, 05082 { HEADER_EXT_TAG, "RPMTAG_FILEPATHS", 05083 { .tagFunction = filepathsTag } }, 05084 { HEADER_EXT_TAG, "RPMTAG_ORIGPATHS", 05085 { .tagFunction = origpathsTag } }, 05086 { HEADER_EXT_TAG, "RPMTAG_FILESTAT", 05087 { .tagFunction = filestatTag } }, 05088 { HEADER_EXT_TAG, "RPMTAG_PROVIDEXMLENTRY", 05089 { .tagFunction = PxmlTag } }, 05090 { HEADER_EXT_TAG, "RPMTAG_REQUIREXMLENTRY", 05091 { .tagFunction = RxmlTag } }, 05092 { HEADER_EXT_TAG, "RPMTAG_CONFLICTXMLENTRY", 05093 { .tagFunction = CxmlTag } }, 05094 { HEADER_EXT_TAG, "RPMTAG_OBSOLETEXMLENTRY", 05095 { .tagFunction = OxmlTag } }, 05096 { HEADER_EXT_TAG, "RPMTAG_FILESXMLENTRY1", 05097 { .tagFunction = F1xmlTag } }, 05098 { HEADER_EXT_TAG, "RPMTAG_FILESXMLENTRY2", 05099 { .tagFunction = F2xmlTag } }, 05100 { HEADER_EXT_TAG, "RPMTAG_PROVIDEYAMLENTRY", 05101 { .tagFunction = PyamlTag } }, 05102 { HEADER_EXT_TAG, "RPMTAG_REQUIREYAMLENTRY", 05103 { .tagFunction = RyamlTag } }, 05104 { HEADER_EXT_TAG, "RPMTAG_CONFLICTYAMLENTRY", 05105 { .tagFunction = CyamlTag } }, 05106 { HEADER_EXT_TAG, "RPMTAG_OBSOLETEYAMLENTRY", 05107 { .tagFunction = OyamlTag } }, 05108 { HEADER_EXT_TAG, "RPMTAG_FILESYAMLENTRY1", 05109 { .tagFunction = F1yamlTag } }, 05110 { HEADER_EXT_TAG, "RPMTAG_FILESYAMLENTRY2", 05111 { .tagFunction = F2yamlTag } }, 05112 { HEADER_EXT_TAG, "RPMTAG_PROVIDESQLENTRY", 05113 { .tagFunction = PsqlTag } }, 05114 { HEADER_EXT_TAG, "RPMTAG_REQUIRESQLENTRY", 05115 { .tagFunction = RsqlTag } }, 05116 { HEADER_EXT_TAG, "RPMTAG_CONFLICTSQLENTRY", 05117 { .tagFunction = CsqlTag } }, 05118 { HEADER_EXT_TAG, "RPMTAG_OBSOLETESQLENTRY", 05119 { .tagFunction = OsqlTag } }, 05120 { HEADER_EXT_TAG, "RPMTAG_FILESSQLENTRY1", 05121 { .tagFunction = F1sqlTag } }, 05122 { HEADER_EXT_TAG, "RPMTAG_FILESSQLENTRY2", 05123 { .tagFunction = F2sqlTag } }, 05124 { HEADER_EXT_TAG, "RPMTAG_DEBCONFLICTS", 05125 { .tagFunction = debconflictsTag } }, 05126 { HEADER_EXT_TAG, "RPMTAG_DEBDEPENDS", 05127 { .tagFunction = debdependsTag } }, 05128 { HEADER_EXT_TAG, "RPMTAG_DEBMD5SUMS", 05129 { .tagFunction = debmd5sumsTag } }, 05130 { HEADER_EXT_TAG, "RPMTAG_DEBOBSOLETES", 05131 { .tagFunction = debobsoletesTag } }, 05132 { HEADER_EXT_TAG, "RPMTAG_DEBPROVIDES", 05133 { .tagFunction = debprovidesTag } }, 05134 { HEADER_EXT_TAG, "RPMTAG_NEEDSWHAT", 05135 { .tagFunction = needswhatTag } }, 05136 { HEADER_EXT_TAG, "RPMTAG_WHATNEEDS", 05137 { .tagFunction = whatneedsTag } }, 05138 { HEADER_EXT_FORMAT, "armor", 05139 { .fmtFunction = armorFormat } }, 05140 { HEADER_EXT_FORMAT, "base64", 05141 { .fmtFunction = base64Format } }, 05142 { HEADER_EXT_FORMAT, "bncdata", 05143 { .fmtFunction = bncdataFormat } }, 05144 { HEADER_EXT_FORMAT, "cdata", 05145 { .fmtFunction = cdataFormat } }, 05146 { HEADER_EXT_FORMAT, "depflags", 05147 { .fmtFunction = depflagsFormat } }, 05148 { HEADER_EXT_FORMAT, "deptype", 05149 { .fmtFunction = deptypeFormat } }, 05150 { HEADER_EXT_FORMAT, "digest", 05151 { .fmtFunction = digestFormat } }, 05152 { HEADER_EXT_FORMAT, "fflags", 05153 { .fmtFunction = fflagsFormat } }, 05154 { HEADER_EXT_FORMAT, "iconv", 05155 { .fmtFunction = iconvFormat } }, 05156 { HEADER_EXT_FORMAT, "json", 05157 { .fmtFunction = jsonFormat } }, 05158 #ifndef DYING /* XXX is :json gud enuf? there are side effects ... */ 05159 { HEADER_EXT_FORMAT, "jsonescape", 05160 { .fmtFunction = jsonescapeFormat } }, 05161 #endif 05162 { HEADER_EXT_FORMAT, "perms", 05163 { .fmtFunction = permsFormat } }, 05164 { HEADER_EXT_FORMAT, "permissions", 05165 { .fmtFunction = permsFormat } }, 05166 { HEADER_EXT_FORMAT, "pgpsig", 05167 { .fmtFunction = pgpsigFormat } }, 05168 { HEADER_EXT_FORMAT, "rpn", 05169 { .fmtFunction = rpnFormat } }, 05170 { HEADER_EXT_FORMAT, "sqlescape", 05171 { .fmtFunction = sqlescapeFormat } }, 05172 { HEADER_EXT_FORMAT, "stat", 05173 { .fmtFunction = statFormat } }, 05174 { HEADER_EXT_FORMAT, "strsub", 05175 { .fmtFunction = strsubFormat } }, 05176 { HEADER_EXT_FORMAT, "triggertype", 05177 { .fmtFunction = triggertypeFormat } }, 05178 { HEADER_EXT_FORMAT, "utf8", 05179 { .fmtFunction = iconvFormat } }, 05180 { HEADER_EXT_FORMAT, "uuid", 05181 { .fmtFunction = uuidFormat } }, 05182 { HEADER_EXT_FORMAT, "xml", 05183 { .fmtFunction = xmlFormat } }, 05184 { HEADER_EXT_FORMAT, "yaml", 05185 { .fmtFunction = yamlFormat } }, 05186 { HEADER_EXT_MORE, NULL, { (void *) &headerDefaultFormats } } 05187 } ; 05188 05189 headerSprintfExtension headerCompoundFormats = &_headerCompoundFormats[0]; 05190 05191 /*====================================================================*/ 05192 05193 void rpmDisplayQueryTags(FILE * fp, headerTagTableEntry _rpmTagTable, headerSprintfExtension _rpmHeaderFormats) 05194 { 05195 const struct headerTagTableEntry_s * t; 05196 headerSprintfExtension exts; 05197 headerSprintfExtension ext; 05198 int extNum; 05199 05200 if (fp == NULL) 05201 fp = stdout; 05202 if (_rpmTagTable == NULL) 05203 _rpmTagTable = rpmTagTable; 05204 05205 /* XXX this should use rpmHeaderFormats, but there are linkage problems. */ 05206 if (_rpmHeaderFormats == NULL) 05207 _rpmHeaderFormats = headerCompoundFormats; 05208 05209 for (t = _rpmTagTable; t && t->name; t++) { 05210 /*@observer@*/ 05211 static const char * tagtypes[] = { 05212 "", "char", "uint8", "uint16", "uint32", "uint64", 05213 "string", "octets", "argv", "i18nstring", 05214 }; 05215 rpmuint32_t ttype; 05216 05217 if (rpmIsVerbose()) { 05218 fprintf(fp, "%-20s %6d", t->name + 7, t->val); 05219 ttype = t->type & RPM_MASK_TYPE; 05220 if (ttype < RPM_MIN_TYPE || ttype > RPM_MAX_TYPE) 05221 continue; 05222 if (t->type & RPM_OPENPGP_RETURN_TYPE) 05223 fprintf(fp, " openpgp"); 05224 if (t->type & RPM_X509_RETURN_TYPE) 05225 fprintf(fp, " x509"); 05226 if (t->type & RPM_ASN1_RETURN_TYPE) 05227 fprintf(fp, " asn1"); 05228 if (t->type & RPM_OPAQUE_RETURN_TYPE) 05229 fprintf(fp, " opaque"); 05230 fprintf(fp, " %s", tagtypes[ttype]); 05231 if (t->type & RPM_ARRAY_RETURN_TYPE) 05232 fprintf(fp, " array"); 05233 if (t->type & RPM_MAPPING_RETURN_TYPE) 05234 fprintf(fp, " mapping"); 05235 if (t->type & RPM_PROBE_RETURN_TYPE) 05236 fprintf(fp, " probe"); 05237 if (t->type & RPM_TREE_RETURN_TYPE) 05238 fprintf(fp, " tree"); 05239 } else 05240 fprintf(fp, "%s", t->name + 7); 05241 fprintf(fp, "\n"); 05242 } 05243 05244 exts = _rpmHeaderFormats; 05245 for (ext = exts, extNum = 0; ext != NULL && ext->type != HEADER_EXT_LAST; 05246 ext = (ext->type == HEADER_EXT_MORE ? *ext->u.more : ext+1), extNum++) 05247 { 05248 if (ext->name == NULL || ext->type != HEADER_EXT_TAG) 05249 continue; 05250 05251 /* XXX don't print header tags twice. */ 05252 if (tagValue(ext->name) > 0) 05253 continue; 05254 fprintf(fp, "%s\n", ext->name + 7); 05255 } 05256 } 05257 05258 /*====================================================================*/ 05259 05260 #define PARSER_BEGIN 0 05261 #define PARSER_IN_ARRAY 1 05262 #define PARSER_IN_EXPR 2 05263 05266 typedef /*@abstract@*/ struct sprintfTag_s * sprintfTag; 05267 05270 struct sprintfTag_s { 05271 HE_s he; 05272 /*@null@*/ 05273 headerTagFormatFunction * fmtfuncs; 05274 /*@null@*/ 05275 headerTagTagFunction ext; 05276 int extNum; 05277 /*@only@*/ /*@relnull@*/ 05278 rpmTag * tagno; 05279 int justOne; 05280 int arrayCount; 05281 /*@kept@*/ 05282 char * format; 05283 /*@only@*/ /*@relnull@*/ 05284 ARGV_t av; 05285 /*@only@*/ /*@relnull@*/ 05286 ARGV_t params; 05287 unsigned pad; 05288 }; 05289 05292 typedef /*@abstract@*/ struct sprintfToken_s * sprintfToken; 05293 05296 struct sprintfToken_s { 05297 enum { 05298 PTOK_NONE = 0, 05299 PTOK_TAG = 1, 05300 PTOK_ARRAY = 2, 05301 PTOK_STRING = 3, 05302 PTOK_COND = 4 05303 } type; 05304 union { 05305 struct sprintfTag_s tag; 05306 struct { 05307 /*@only@*/ 05308 sprintfToken format; 05309 size_t numTokens; 05310 } array; 05311 struct { 05312 /*@dependent@*/ 05313 char * string; 05314 size_t len; 05315 } string; 05316 struct { 05317 /*@only@*/ /*@null@*/ 05318 sprintfToken ifFormat; 05319 size_t numIfTokens; 05320 /*@only@*/ /*@null@*/ 05321 sprintfToken elseFormat; 05322 size_t numElseTokens; 05323 struct sprintfTag_s tag; 05324 } cond; 05325 } u; 05326 }; 05327 05330 typedef /*@abstract@*/ struct headerSprintfArgs_s * headerSprintfArgs; 05331 05334 struct headerSprintfArgs_s { 05335 Header h; 05336 char * fmt; 05337 /*@observer@*/ /*@temp@*/ 05338 headerTagTableEntry tags; 05339 /*@observer@*/ /*@temp@*/ 05340 headerSprintfExtension exts; 05341 /*@observer@*/ /*@null@*/ 05342 const char * errmsg; 05343 HE_t ec; 05344 int nec; 05345 sprintfToken format; 05346 /*@relnull@*/ 05347 HeaderIterator hi; 05348 /*@owned@*/ 05349 char * val; 05350 size_t vallen; 05351 size_t alloced; 05352 size_t numTokens; 05353 size_t i; 05354 }; 05355 05356 /*@access sprintfTag @*/ 05357 /*@access sprintfToken @*/ 05358 /*@access headerSprintfArgs @*/ 05359 05362 static char escapedChar(const char ch) 05363 /*@*/ 05364 { 05365 /*@-modfilesys@*/ 05366 if (_hdrqf_debug) 05367 fprintf(stderr, "\t\t\\%c\n", ch); 05368 /*@=modfilesys@*/ 05369 switch (ch) { 05370 case 'a': return '\a'; 05371 case 'b': return '\b'; 05372 case 'f': return '\f'; 05373 case 'n': return '\n'; 05374 case 'r': return '\r'; 05375 case 't': return '\t'; 05376 case 'v': return '\v'; 05377 default: return ch; 05378 } 05379 } 05380 05385 /*@relnull@*/ 05386 static HE_t rpmheClean(/*@returned@*/ /*@null@*/ HE_t he) 05387 /*@modifies he @*/ 05388 { 05389 if (he) { 05390 if (he->freeData && he->p.ptr != NULL) 05391 he->p.ptr = _free(he->p.ptr); 05392 memset(he, 0, sizeof(*he)); 05393 } 05394 return he; 05395 } 05396 05403 static /*@null@*/ sprintfToken 05404 freeFormat( /*@only@*/ /*@null@*/ sprintfToken format, size_t num) 05405 /*@modifies *format @*/ 05406 { 05407 unsigned i; 05408 05409 if (format == NULL) return NULL; 05410 05411 for (i = 0; i < (unsigned) num; i++) { 05412 switch (format[i].type) { 05413 case PTOK_TAG: 05414 (void) rpmheClean(&format[i].u.tag.he); 05415 format[i].u.tag.tagno = _free(format[i].u.tag.tagno); 05416 format[i].u.tag.av = argvFree(format[i].u.tag.av); 05417 format[i].u.tag.params = argvFree(format[i].u.tag.params); 05418 /*@-type@*/ 05419 format[i].u.tag.fmtfuncs = _free(format[i].u.tag.fmtfuncs); 05420 /*@=type@*/ 05421 /*@switchbreak@*/ break; 05422 case PTOK_ARRAY: 05423 format[i].u.array.format = 05424 freeFormat(format[i].u.array.format, 05425 format[i].u.array.numTokens); 05426 /*@switchbreak@*/ break; 05427 case PTOK_COND: 05428 format[i].u.cond.ifFormat = 05429 freeFormat(format[i].u.cond.ifFormat, 05430 format[i].u.cond.numIfTokens); 05431 format[i].u.cond.elseFormat = 05432 freeFormat(format[i].u.cond.elseFormat, 05433 format[i].u.cond.numElseTokens); 05434 (void) rpmheClean(&format[i].u.cond.tag.he); 05435 format[i].u.cond.tag.tagno = _free(format[i].u.cond.tag.tagno); 05436 format[i].u.cond.tag.av = argvFree(format[i].u.cond.tag.av); 05437 format[i].u.cond.tag.params = argvFree(format[i].u.cond.tag.params); 05438 /*@-type@*/ 05439 format[i].u.cond.tag.fmtfuncs = _free(format[i].u.cond.tag.fmtfuncs); 05440 /*@=type@*/ 05441 /*@switchbreak@*/ break; 05442 case PTOK_NONE: 05443 case PTOK_STRING: 05444 default: 05445 /*@switchbreak@*/ break; 05446 } 05447 } 05448 format = _free(format); 05449 return NULL; 05450 } 05451 05457 static headerSprintfArgs hsaInit(/*@returned@*/ headerSprintfArgs hsa) 05458 /*@globals fileSystem @*/ 05459 /*@modifies hsa, fileSystem @*/ 05460 { 05461 sprintfTag tag = 05462 (hsa->format->type == PTOK_TAG 05463 ? &hsa->format->u.tag : 05464 (hsa->format->type == PTOK_ARRAY 05465 ? &hsa->format->u.array.format->u.tag : 05466 NULL)); 05467 05468 if (hsa != NULL) { 05469 hsa->i = 0; 05470 if (tag != NULL && tag->tagno != NULL && tag->tagno[0] == (rpmTag)-2) 05471 hsa->hi = headerInit(hsa->h); 05472 } 05473 /*@-nullret@*/ 05474 return hsa; 05475 /*@=nullret@*/ 05476 } 05477 05483 /*@null@*/ 05484 static sprintfToken hsaNext(/*@returned@*/ headerSprintfArgs hsa) 05485 /*@globals internalState @*/ 05486 /*@modifies hsa, internalState @*/ 05487 { 05488 sprintfToken fmt = NULL; 05489 sprintfTag tag = 05490 (hsa->format->type == PTOK_TAG 05491 ? &hsa->format->u.tag : 05492 (hsa->format->type == PTOK_ARRAY 05493 ? &hsa->format->u.array.format->u.tag : 05494 NULL)); 05495 05496 if (hsa != NULL && hsa->i < hsa->numTokens) { 05497 fmt = hsa->format + hsa->i; 05498 if (hsa->hi == NULL) { 05499 hsa->i++; 05500 } else { 05501 HE_t he = rpmheClean(&tag->he); 05502 if (!headerNext(hsa->hi, he, 0)) 05503 { 05504 tag->tagno[0] = 0; 05505 return NULL; 05506 } 05507 he->avail = 1; 05508 tag->tagno[0] = he->tag; 05509 } 05510 } 05511 05512 /*@-dependenttrans -onlytrans@*/ 05513 return fmt; 05514 /*@=dependenttrans =onlytrans@*/ 05515 } 05516 05522 static headerSprintfArgs hsaFini(/*@returned@*/ headerSprintfArgs hsa) 05523 /*@globals fileSystem @*/ 05524 /*@modifies hsa, fileSystem @*/ 05525 { 05526 if (hsa != NULL) { 05527 hsa->hi = headerFini(hsa->hi); 05528 hsa->i = 0; 05529 } 05530 /*@-nullret@*/ 05531 return hsa; 05532 /*@=nullret@*/ 05533 } 05534 05541 /*@dependent@*/ /*@exposed@*/ 05542 static char * hsaReserve(headerSprintfArgs hsa, size_t need) 05543 /*@modifies hsa */ 05544 { 05545 if ((hsa->vallen + need) >= hsa->alloced) { 05546 if (hsa->alloced <= need) 05547 hsa->alloced += need; 05548 hsa->alloced <<= 1; 05549 hsa->val = xrealloc(hsa->val, hsa->alloced+1); 05550 } 05551 return hsa->val + hsa->vallen; 05552 } 05553 05561 /*@observer@*/ /*@null@*/ 05562 static const char * myTagName(headerTagTableEntry tbl, rpmuint32_t val, 05563 /*@null@*/ rpmuint32_t *typep) 05564 /*@modifies *typep @*/ 05565 { 05566 static char name[128]; /* XXX Ick. */ 05567 const char * s; 05568 char *t; 05569 05570 /* XXX Use bsearch on the "normal" rpmTagTable lookup. */ 05571 if (tbl == NULL || tbl == rpmTagTable) { 05572 s = tagName(val); 05573 if (s != NULL && typep != NULL) 05574 *typep = tagType(val); 05575 return s; 05576 } 05577 05578 for (; tbl->name != NULL; tbl++) { 05579 if (tbl->val == val) 05580 break; 05581 } 05582 if ((s = tbl->name) == NULL) 05583 return NULL; 05584 s += sizeof("RPMTAG_") - 1; 05585 t = name; 05586 *t++ = *s++; 05587 while (*s != '\0') 05588 *t++ = (char)xtolower((int)*s++); 05589 *t = '\0'; 05590 if (typep) 05591 *typep = tbl->type; 05592 return name; 05593 } 05594 05601 static rpmuint32_t myTagValue(headerTagTableEntry tbl, const char * name) 05602 /*@*/ 05603 { 05604 rpmuint32_t val = 0; 05605 05606 /* XXX Use bsearch on the "normal" rpmTagTable lookup. */ 05607 if (tbl == NULL || tbl == rpmTagTable) 05608 val = tagValue(name); 05609 else 05610 for (; tbl->name != NULL; tbl++) { 05611 if (xstrcasecmp(tbl->name, name)) 05612 continue; 05613 val = tbl->val; 05614 break; 05615 } 05616 return val; 05617 } 05618 05626 static int findTag(headerSprintfArgs hsa, sprintfToken token, const char * name) 05627 /*@modifies token @*/ 05628 { 05629 headerSprintfExtension exts = hsa->exts; 05630 headerSprintfExtension ext; 05631 sprintfTag stag = (token->type == PTOK_COND 05632 ? &token->u.cond.tag : &token->u.tag); 05633 int extNum; 05634 rpmTag tagno = (rpmTag)-1; 05635 05636 stag->fmtfuncs = NULL; 05637 stag->ext = NULL; 05638 stag->extNum = 0; 05639 05640 if (!strcmp(name, "*")) { 05641 tagno = (rpmTag)-2; 05642 goto bingo; 05643 } 05644 05645 if (strncmp("RPMTAG_", name, sizeof("RPMTAG_")-1)) { 05646 char * t = alloca(strlen(name) + sizeof("RPMTAG_")); 05647 (void) stpcpy( stpcpy(t, "RPMTAG_"), name); 05648 name = t; 05649 } 05650 05651 /* Search extensions for specific tag override. */ 05652 for (ext = exts, extNum = 0; ext != NULL && ext->type != HEADER_EXT_LAST; 05653 ext = (ext->type == HEADER_EXT_MORE ? *ext->u.more : ext+1), extNum++) 05654 { 05655 if (ext->name == NULL || ext->type != HEADER_EXT_TAG) 05656 continue; 05657 if (!xstrcasecmp(ext->name, name)) { 05658 stag->ext = ext->u.tagFunction; 05659 stag->extNum = extNum; 05660 tagno = tagValue(name); 05661 goto bingo; 05662 } 05663 } 05664 05665 /* Search tag names. */ 05666 tagno = myTagValue(hsa->tags, name); 05667 if (tagno != 0) 05668 goto bingo; 05669 05670 return 1; 05671 05672 bingo: 05673 stag->tagno = xcalloc(1, sizeof(*stag->tagno)); 05674 stag->tagno[0] = tagno; 05675 /* Search extensions for specific format(s). */ 05676 if (stag->av != NULL) { 05677 int i; 05678 /*@-type@*/ 05679 stag->fmtfuncs = xcalloc(argvCount(stag->av) + 1, sizeof(*stag->fmtfuncs)); 05680 /*@=type@*/ 05681 for (i = 0; stag->av[i] != NULL; i++) { 05682 for (ext = exts; ext != NULL && ext->type != HEADER_EXT_LAST; 05683 ext = (ext->type == HEADER_EXT_MORE ? *ext->u.more : ext+1)) 05684 { 05685 if (ext->name == NULL || ext->type != HEADER_EXT_FORMAT) 05686 /*@innercontinue@*/ continue; 05687 if (strcmp(ext->name, stag->av[i]+1)) 05688 /*@innercontinue@*/ continue; 05689 stag->fmtfuncs[i] = ext->u.fmtFunction; 05690 /*@innerbreak@*/ break; 05691 } 05692 } 05693 } 05694 return 0; 05695 } 05696 05697 /* forward ref */ 05706 static int parseExpression(headerSprintfArgs hsa, sprintfToken token, 05707 char * str, /*@out@*/char ** endPtr) 05708 /*@modifies hsa, str, token, *endPtr @*/ 05709 /*@requires maxSet(endPtr) >= 0 @*/; 05710 05721 static int parseFormat(headerSprintfArgs hsa, char * str, 05722 /*@out@*/ sprintfToken * formatPtr, 05723 /*@out@*/ size_t * numTokensPtr, 05724 /*@null@*/ /*@out@*/ char ** endPtr, int state) 05725 /*@modifies hsa, str, *formatPtr, *numTokensPtr, *endPtr @*/ 05726 /*@requires maxSet(formatPtr) >= 0 /\ maxSet(numTokensPtr) >= 0 05727 /\ maxSet(endPtr) >= 0 @*/ 05728 { 05729 /*@observer@*/ 05730 static const char *pstates[] = { 05731 "NORMAL", "ARRAY", "EXPR", "WTF?" 05732 }; 05733 char * chptr, * start, * next, * dst; 05734 sprintfToken format; 05735 sprintfToken token; 05736 size_t numTokens; 05737 unsigned i; 05738 int done = 0; 05739 int xx; 05740 05741 /*@-modfilesys@*/ 05742 if (_hdrqf_debug) 05743 fprintf(stderr, "--> parseFormat(%p, \"%.20s...\", %p, %p, %p, %s)\n", hsa, str, formatPtr, numTokensPtr, endPtr, pstates[(state & 0x3)]); 05744 /*@=modfilesys@*/ 05745 05746 /* upper limit on number of individual formats */ 05747 numTokens = 0; 05748 if (str != NULL) 05749 for (chptr = str; *chptr != '\0'; chptr++) 05750 if (*chptr == '%' || *chptr == '[') numTokens++; 05751 numTokens = numTokens * 2 + 1; 05752 05753 format = xcalloc(numTokens, sizeof(*format)); 05754 if (endPtr) *endPtr = NULL; 05755 05756 /*@-infloops@*/ /* LCL: can't detect (start, *start) termination */ 05757 dst = start = str; 05758 numTokens = 0; 05759 token = NULL; 05760 if (start != NULL) 05761 while (*start != '\0') { 05762 switch (*start) { 05763 case '%': 05764 /* handle %% */ 05765 if (*(start + 1) == '%') { 05766 if (token == NULL || token->type != PTOK_STRING) { 05767 token = format + numTokens++; 05768 token->type = PTOK_STRING; 05769 /*@-temptrans -assignexpose@*/ 05770 dst = token->u.string.string = start; 05771 /*@=temptrans =assignexpose@*/ 05772 } 05773 start++; 05774 *dst++ = *start++; 05775 /*@switchbreak@*/ break; 05776 } 05777 05778 token = format + numTokens++; 05779 *dst++ = '\0'; 05780 start++; 05781 05782 if (*start == '|') { 05783 char * newEnd; 05784 05785 start++; 05786 if (parseExpression(hsa, token, start, &newEnd)) 05787 { 05788 format = freeFormat(format, numTokens); 05789 return 1; 05790 } 05791 start = newEnd; 05792 /*@switchbreak@*/ break; 05793 } 05794 05795 /*@-assignexpose@*/ 05796 token->u.tag.format = start; 05797 /*@=assignexpose@*/ 05798 token->u.tag.pad = 0; 05799 token->u.tag.justOne = 0; 05800 token->u.tag.arrayCount = 0; 05801 05802 chptr = start; 05803 while (*chptr && *chptr != '{' && *chptr != '%') chptr++; 05804 if (!*chptr || *chptr == '%') { 05805 hsa->errmsg = _("missing { after %"); 05806 format = freeFormat(format, numTokens); 05807 return 1; 05808 } 05809 05810 /*@-modfilesys@*/ 05811 if (_hdrqf_debug) 05812 fprintf(stderr, "\tchptr *%p = NUL\n", chptr); 05813 /*@=modfilesys@*/ 05814 *chptr++ = '\0'; 05815 05816 while (start < chptr) { 05817 if (xisdigit((int)*start)) { 05818 i = strtoul(start, &start, 10); 05819 token->u.tag.pad += i; 05820 start = chptr; 05821 /*@innerbreak@*/ break; 05822 } else { 05823 start++; 05824 } 05825 } 05826 05827 if (*start == '=') { 05828 token->u.tag.justOne = 1; 05829 start++; 05830 } else if (*start == '#') { 05831 token->u.tag.justOne = 1; 05832 token->u.tag.arrayCount = 1; 05833 start++; 05834 } 05835 05836 next = start; 05837 while (*next && *next != '}') next++; 05838 if (!*next) { 05839 hsa->errmsg = _("missing } after %{"); 05840 format = freeFormat(format, numTokens); 05841 return 1; 05842 } 05843 /*@-modfilesys@*/ 05844 if (_hdrqf_debug) 05845 fprintf(stderr, "\tnext *%p = NUL\n", next); 05846 /*@=modfilesys@*/ 05847 *next++ = '\0'; 05848 05849 #define isSEP(_c) ((_c) == ':' || (_c) == '|') 05850 chptr = start; 05851 while (!(*chptr == '\0' || isSEP(*chptr))) chptr++; 05852 /* Split ":bing|bang:boom" --qf pipeline formatters (if any) */ 05853 while (isSEP(*chptr)) { 05854 if (chptr[1] == '\0' || isSEP(chptr[1])) { 05855 hsa->errmsg = _("empty tag format"); 05856 format = freeFormat(format, numTokens); 05857 return 1; 05858 } 05859 /* Parse the formatter parameter list. */ 05860 { char * te = chptr + 1; 05861 char * t = strchr(te, '('); 05862 char c; 05863 05864 while (!(*te == '\0' || isSEP(*te))) { 05865 #ifdef NOTYET /* XXX some means of escaping is needed */ 05866 if (te[0] == '\\' && te[1] != '\0') te++; 05867 #endif 05868 te++; 05869 } 05870 c = *te; *te = '\0'; 05871 /* Parse (a,b,c) parameter list. */ 05872 if (t != NULL) { 05873 *t++ = '\0'; 05874 if (te <= t || te[-1] != ')') { 05875 hsa->errmsg = _("malformed parameter list"); 05876 format = freeFormat(format, numTokens); 05877 return 1; 05878 } 05879 te[-1] = '\0'; 05880 xx = argvAdd(&token->u.tag.params, t); 05881 } else 05882 xx = argvAdd(&token->u.tag.params, ""); 05883 /*@-modfilesys@*/ 05884 if (_hdrqf_debug) 05885 fprintf(stderr, "\tformat \"%s\" params \"%s\"\n", chptr, (t ? t : "")); 05886 /*@=modfilesys@*/ 05887 xx = argvAdd(&token->u.tag.av, chptr); 05888 *te = c; 05889 *chptr = '\0'; 05890 chptr = te; 05891 } 05892 } 05893 #undef isSEP 05894 05895 if (*start == '\0') { 05896 hsa->errmsg = _("empty tag name"); 05897 format = freeFormat(format, numTokens); 05898 return 1; 05899 } 05900 05901 i = 0; 05902 token->type = PTOK_TAG; 05903 05904 if (findTag(hsa, token, start)) { 05905 hsa->errmsg = _("unknown tag"); 05906 format = freeFormat(format, numTokens); 05907 return 1; 05908 } 05909 05910 dst = start = next; 05911 /*@-modfilesys@*/ 05912 if (_hdrqf_debug) 05913 fprintf(stderr, "\tdst = start = next %p\n", dst); 05914 /*@=modfilesys@*/ 05915 /*@switchbreak@*/ break; 05916 05917 case '[': 05918 /*@-modfilesys@*/ 05919 if (_hdrqf_debug) 05920 fprintf(stderr, "\t%s => %s *%p = NUL\n", pstates[(state & 0x3)], pstates[PARSER_IN_ARRAY], start); 05921 /*@=modfilesys@*/ 05922 *start++ = '\0'; 05923 token = format + numTokens++; 05924 05925 if (parseFormat(hsa, start, 05926 &token->u.array.format, 05927 &token->u.array.numTokens, 05928 &start, PARSER_IN_ARRAY)) 05929 { 05930 format = freeFormat(format, numTokens); 05931 return 1; 05932 } 05933 05934 if (!start) { 05935 hsa->errmsg = _("] expected at end of array"); 05936 format = freeFormat(format, numTokens); 05937 return 1; 05938 } 05939 05940 dst = start; 05941 /*@-modfilesys@*/ 05942 if (_hdrqf_debug) 05943 fprintf(stderr, "\tdst = start %p\n", dst); 05944 /*@=modfilesys@*/ 05945 05946 token->type = PTOK_ARRAY; 05947 05948 /*@switchbreak@*/ break; 05949 05950 case ']': 05951 if (state != PARSER_IN_ARRAY) { 05952 hsa->errmsg = _("unexpected ]"); 05953 format = freeFormat(format, numTokens); 05954 return 1; 05955 } 05956 *start++ = '\0'; 05957 /*@-modfilesys@*/ 05958 if (_hdrqf_debug) 05959 fprintf(stderr, "\t<= %s %p[-1] = NUL\n", pstates[(state & 0x3)], start); 05960 /*@=modfilesys@*/ 05961 if (endPtr) *endPtr = start; 05962 done = 1; 05963 /*@switchbreak@*/ break; 05964 05965 case '}': 05966 if (state != PARSER_IN_EXPR) { 05967 hsa->errmsg = _("unexpected }"); 05968 format = freeFormat(format, numTokens); 05969 return 1; 05970 } 05971 *start++ = '\0'; 05972 /*@-modfilesys@*/ 05973 if (_hdrqf_debug) 05974 fprintf(stderr, "\t<= %s %p[-1] = NUL\n", pstates[(state & 0x3)], start); 05975 /*@=modfilesys@*/ 05976 if (endPtr) *endPtr = start; 05977 done = 1; 05978 /*@switchbreak@*/ break; 05979 05980 default: 05981 if (token == NULL || token->type != PTOK_STRING) { 05982 token = format + numTokens++; 05983 token->type = PTOK_STRING; 05984 /*@-temptrans -assignexpose@*/ 05985 dst = token->u.string.string = start; 05986 /*@=temptrans =assignexpose@*/ 05987 } 05988 05989 /*@-modfilesys@*/ 05990 if (_hdrqf_debug) 05991 fprintf(stderr, "\t*%p = *%p \"%.30s\"\n", dst, start, start); 05992 /*@=modfilesys@*/ 05993 if (start[0] == '\\' && start[1] != '\0') { 05994 start++; 05995 *dst++ = escapedChar(*start); 05996 *start++ = '\0'; 05997 } else { 05998 *dst++ = *start++; 05999 } 06000 /*@switchbreak@*/ break; 06001 } 06002 if (dst < start) *dst = '\0'; 06003 if (done) 06004 break; 06005 } 06006 /*@=infloops@*/ 06007 06008 if (dst != NULL) 06009 *dst = '\0'; 06010 06011 for (i = 0; i < (unsigned) numTokens; i++) { 06012 token = format + i; 06013 switch(token->type) { 06014 default: 06015 /*@switchbreak@*/ break; 06016 case PTOK_STRING: 06017 token->u.string.len = strlen(token->u.string.string); 06018 /*@switchbreak@*/ break; 06019 } 06020 } 06021 06022 if (numTokensPtr != NULL) 06023 *numTokensPtr = numTokens; 06024 if (formatPtr != NULL) 06025 *formatPtr = format; 06026 06027 return 0; 06028 } 06029 06030 static int parseExpression(headerSprintfArgs hsa, sprintfToken token, 06031 char * str, /*@out@*/ char ** endPtr) 06032 { 06033 char * chptr; 06034 char * end; 06035 06036 /*@-modfilesys@*/ 06037 if (_hdrqf_debug) 06038 fprintf(stderr, "--> parseExpression(%p, %p, \"%.20s...\", %p)\n", hsa, token, str, endPtr); 06039 /*@=modfilesys@*/ 06040 06041 hsa->errmsg = NULL; 06042 chptr = str; 06043 while (*chptr && *chptr != '?') chptr++; 06044 06045 if (*chptr != '?') { 06046 hsa->errmsg = _("? expected in expression"); 06047 return 1; 06048 } 06049 06050 *chptr++ = '\0'; 06051 06052 if (*chptr != '{') { 06053 hsa->errmsg = _("{ expected after ? in expression"); 06054 return 1; 06055 } 06056 06057 chptr++; 06058 06059 if (parseFormat(hsa, chptr, &token->u.cond.ifFormat, 06060 &token->u.cond.numIfTokens, &end, PARSER_IN_EXPR)) 06061 return 1; 06062 06063 /* XXX fix segfault on "rpm -q rpm --qf='%|NAME?{%}:{NAME}|\n'"*/ 06064 if (!(end && *end)) { 06065 hsa->errmsg = _("} expected in expression"); 06066 token->u.cond.ifFormat = 06067 freeFormat(token->u.cond.ifFormat, token->u.cond.numIfTokens); 06068 return 1; 06069 } 06070 06071 chptr = end; 06072 if (*chptr != ':' && *chptr != '|') { 06073 hsa->errmsg = _(": expected following ? subexpression"); 06074 token->u.cond.ifFormat = 06075 freeFormat(token->u.cond.ifFormat, token->u.cond.numIfTokens); 06076 return 1; 06077 } 06078 06079 if (*chptr == '|') { 06080 if (parseFormat(hsa, NULL, &token->u.cond.elseFormat, 06081 &token->u.cond.numElseTokens, &end, PARSER_IN_EXPR)) 06082 { 06083 token->u.cond.ifFormat = 06084 freeFormat(token->u.cond.ifFormat, token->u.cond.numIfTokens); 06085 return 1; 06086 } 06087 } else { 06088 chptr++; 06089 06090 if (*chptr != '{') { 06091 hsa->errmsg = _("{ expected after : in expression"); 06092 token->u.cond.ifFormat = 06093 freeFormat(token->u.cond.ifFormat, token->u.cond.numIfTokens); 06094 return 1; 06095 } 06096 06097 chptr++; 06098 06099 if (parseFormat(hsa, chptr, &token->u.cond.elseFormat, 06100 &token->u.cond.numElseTokens, &end, PARSER_IN_EXPR)) 06101 return 1; 06102 06103 /* XXX fix segfault on "rpm -q rpm --qf='%|NAME?{a}:{%}|{NAME}\n'" */ 06104 if (!(end && *end)) { 06105 hsa->errmsg = _("} expected in expression"); 06106 token->u.cond.ifFormat = 06107 freeFormat(token->u.cond.ifFormat, token->u.cond.numIfTokens); 06108 return 1; 06109 } 06110 06111 chptr = end; 06112 if (*chptr != '|') { 06113 hsa->errmsg = _("| expected at end of expression"); 06114 token->u.cond.ifFormat = 06115 freeFormat(token->u.cond.ifFormat, token->u.cond.numIfTokens); 06116 token->u.cond.elseFormat = 06117 freeFormat(token->u.cond.elseFormat, token->u.cond.numElseTokens); 06118 return 1; 06119 } 06120 } 06121 06122 chptr++; 06123 06124 *endPtr = chptr; 06125 06126 token->type = PTOK_COND; 06127 06128 (void) findTag(hsa, token, str); 06129 06130 return 0; 06131 } 06132 06141 static int getExtension(headerSprintfArgs hsa, headerTagTagFunction fn, 06142 HE_t he, HE_t ec) 06143 /*@modifies he, ec @*/ 06144 { 06145 int rc = 0; 06146 if (!ec->avail) { 06147 he = rpmheClean(he); 06148 rc = fn(hsa->h, he); 06149 *ec = *he; /* structure copy. */ 06150 if (!rc) 06151 ec->avail = 1; 06152 } else 06153 *he = *ec; /* structure copy. */ 06154 he->freeData = 0; 06155 rc = (rc == 0); /* XXX invert getExtension return. */ 06156 return rc; 06157 } 06158 06166 /*@observer@*/ /*@null@*/ 06167 static char * formatValue(headerSprintfArgs hsa, sprintfTag tag, 06168 size_t element) 06169 /*@globals rpmGlobalMacroContext, h_errno, internalState @*/ 06170 /*@modifies hsa, tag, rpmGlobalMacroContext, internalState @*/ 06171 { 06172 HE_t vhe = memset(alloca(sizeof(*vhe)), 0, sizeof(*vhe)); 06173 HE_t he = &tag->he; 06174 char * val = NULL; 06175 size_t need = 0; 06176 char * t, * te; 06177 rpmuint64_t ival = 0; 06178 rpmTagCount countBuf; 06179 int xx; 06180 06181 if (!he->avail) { 06182 if (tag->ext) 06183 xx = getExtension(hsa, tag->ext, he, hsa->ec + tag->extNum); 06184 else { 06185 he->tag = tag->tagno[0]; /* XXX necessary? */ 06186 xx = headerGet(hsa->h, he, 0); 06187 } 06188 if (!xx) { 06189 (void) rpmheClean(he); 06190 he->t = RPM_STRING_TYPE; 06191 he->p.str = xstrdup("(none)"); 06192 he->c = 1; 06193 he->freeData = 1; 06194 } 06195 he->avail = 1; 06196 } 06197 06198 if (tag->arrayCount) { 06199 countBuf = he->c; 06200 he = rpmheClean(he); 06201 he->t = RPM_UINT32_TYPE; 06202 he->p.ui32p = &countBuf; 06203 he->c = 1; 06204 he->freeData = 0; 06205 } 06206 06207 vhe->tag = he->tag; 06208 06209 if (he->p.ptr) 06210 switch (he->t) { 06211 default: 06212 val = xstrdup("(unknown type)"); 06213 need = strlen(val) + 1; 06214 goto exit; 06215 /*@notreached@*/ break; 06216 case RPM_I18NSTRING_TYPE: 06217 case RPM_STRING_ARRAY_TYPE: 06218 vhe->t = RPM_STRING_TYPE; 06219 vhe->p.str = he->p.argv[element]; 06220 vhe->c = he->c; 06221 vhe->ix = (he->t == RPM_STRING_ARRAY_TYPE || he->c > 1 ? 0 : -1); 06222 break; 06223 case RPM_STRING_TYPE: 06224 vhe->p.str = he->p.str; 06225 vhe->t = RPM_STRING_TYPE; 06226 vhe->c = 0; 06227 vhe->ix = -1; 06228 break; 06229 case RPM_UINT8_TYPE: 06230 case RPM_UINT16_TYPE: 06231 case RPM_UINT32_TYPE: 06232 case RPM_UINT64_TYPE: 06233 switch (he->t) { 06234 default: 06235 assert(0); /* XXX keep gcc quiet. */ 06236 /*@innerbreak@*/ break; 06237 case RPM_UINT8_TYPE: 06238 ival = (rpmuint64_t)he->p.ui8p[element]; 06239 /*@innerbreak@*/ break; 06240 case RPM_UINT16_TYPE: 06241 ival = (rpmuint64_t)he->p.ui16p[element]; 06242 /*@innerbreak@*/ break; 06243 case RPM_UINT32_TYPE: 06244 ival = (rpmuint64_t)he->p.ui32p[element]; 06245 /*@innerbreak@*/ break; 06246 case RPM_UINT64_TYPE: 06247 ival = he->p.ui64p[element]; 06248 /*@innerbreak@*/ break; 06249 } 06250 vhe->t = RPM_UINT64_TYPE; 06251 vhe->p.ui64p = &ival; 06252 vhe->c = he->c; 06253 vhe->ix = (he->c > 1 ? 0 : -1); 06254 if ((tagType(he->tag) & RPM_MASK_RETURN_TYPE) == RPM_ARRAY_RETURN_TYPE) 06255 vhe->ix = 0; 06256 break; 06257 06258 case RPM_BIN_TYPE: 06259 vhe->t = RPM_BIN_TYPE; 06260 vhe->p.ptr = he->p.ptr; 06261 vhe->c = he->c; 06262 vhe->ix = -1; 06263 break; 06264 } 06265 06266 /*@-compmempass@*/ /* vhe->p.ui64p is stack, not owned */ 06267 if (tag->fmtfuncs) { 06268 char * nval; 06269 int i; 06270 for (i = 0; tag->av[i] != NULL; i++) { 06271 headerTagFormatFunction fmt; 06272 ARGV_t av; 06273 if ((fmt = tag->fmtfuncs[i]) == NULL) 06274 continue; 06275 /* If !1st formatter, and transformer, not extractor, save val. */ 06276 if (val != NULL && *tag->av[i] == '|') { 06277 int ix = vhe->ix; 06278 vhe = rpmheClean(vhe); 06279 vhe->tag = he->tag; 06280 vhe->t = RPM_STRING_TYPE; 06281 vhe->p.str = xstrdup(val); 06282 vhe->c = he->c; 06283 vhe->ix = ix; 06284 vhe->freeData = 1; 06285 } 06286 av = NULL; 06287 if (tag->params && tag->params[i] && *tag->params[i] != '\0') 06288 xx = argvSplit(&av, tag->params[i], ","); 06289 06290 nval = fmt(vhe, av); 06291 06292 /*@-castfcnptr -modfilesys@*/ 06293 if (_hdrqf_debug) 06294 fprintf(stderr, "\t%s(%s) %p(%p,%p) ret \"%s\"\n", tag->av[i], (tag->params ? tag->params[i] : NULL), (void *)fmt, (void *)vhe, (void *)(av ? av : NULL), (val ? val : "(null)")); 06295 /*@=castfcnptr =modfilesys@*/ 06296 06297 /* Accumulate (by appending) next formmatter's return string. */ 06298 if (val == NULL) 06299 val = xstrdup((nval ? nval : "")); 06300 else { 06301 char * oval = val; 06302 /* XXX using ... | ... as separator is feeble. */ 06303 val = rpmExpand(val, (*val != '\0' ? " | " : ""), nval, NULL); 06304 oval = _free(oval); 06305 } 06306 nval = _free(nval); 06307 av = argvFree(av); 06308 } 06309 } 06310 if (val == NULL) 06311 val = intFormat(vhe, NULL, NULL); 06312 /*@=compmempass@*/ 06313 assert(val != NULL); 06314 if (val) 06315 need = strlen(val) + 1; 06316 06317 exit: 06318 if (val && need > 0) { 06319 if (tag->format && *tag->format && tag->pad > 0) { 06320 size_t nb; 06321 nb = strlen(tag->format) + sizeof("%s"); 06322 t = alloca(nb); 06323 (void) stpcpy( stpcpy( stpcpy(t, "%"), tag->format), "s"); 06324 nb = tag->pad + strlen(val) + 1; 06325 te = xmalloc(nb); 06326 /*@-formatconst@*/ 06327 (void) snprintf(te, nb, t, val); 06328 /*@=formatconst@*/ 06329 te[nb-1] = '\0'; 06330 val = _free(val); 06331 val = te; 06332 need += tag->pad; 06333 } 06334 t = hsaReserve(hsa, need); 06335 te = stpcpy(t, val); 06336 hsa->vallen += (te - t); 06337 val = _free(val); 06338 } 06339 06340 return (hsa->val + hsa->vallen); 06341 } 06342 06350 /*@observer@*/ /*@null@*/ 06351 static char * singleSprintf(headerSprintfArgs hsa, sprintfToken token, 06352 size_t element) 06353 /*@globals rpmGlobalMacroContext, h_errno, internalState @*/ 06354 /*@modifies hsa, token, rpmGlobalMacroContext, internalState @*/ 06355 { 06356 char * t, * te; 06357 size_t i, j; 06358 size_t numElements; 06359 sprintfToken spft; 06360 sprintfTag tag = NULL; 06361 HE_t he = NULL; 06362 size_t condNumFormats; 06363 size_t need; 06364 int xx; 06365 06366 /* we assume the token and header have been validated already! */ 06367 06368 switch (token->type) { 06369 case PTOK_NONE: 06370 break; 06371 06372 case PTOK_STRING: 06373 need = token->u.string.len; 06374 if (need == 0) break; 06375 t = hsaReserve(hsa, need); 06376 te = stpcpy(t, token->u.string.string); 06377 hsa->vallen += (te - t); 06378 break; 06379 06380 case PTOK_TAG: 06381 t = hsa->val + hsa->vallen; 06382 /*@-modobserver@*/ /* headerCompoundFormats not modified. */ 06383 te = formatValue(hsa, &token->u.tag, 06384 (token->u.tag.justOne ? 0 : element)); 06385 /*@=modobserver@*/ 06386 if (te == NULL) 06387 return NULL; 06388 break; 06389 06390 case PTOK_COND: 06391 if (token->u.cond.tag.ext 06392 || headerIsEntry(hsa->h, token->u.cond.tag.tagno[0])) 06393 { 06394 spft = token->u.cond.ifFormat; 06395 condNumFormats = token->u.cond.numIfTokens; 06396 } else { 06397 spft = token->u.cond.elseFormat; 06398 condNumFormats = token->u.cond.numElseTokens; 06399 } 06400 06401 need = condNumFormats * 20; 06402 if (spft == NULL || need == 0) break; 06403 06404 t = hsaReserve(hsa, need); 06405 for (i = 0; i < condNumFormats; i++, spft++) { 06406 /*@-modobserver@*/ /* headerCompoundFormats not modified. */ 06407 te = singleSprintf(hsa, spft, element); 06408 /*@=modobserver@*/ 06409 if (te == NULL) 06410 return NULL; 06411 } 06412 break; 06413 06414 case PTOK_ARRAY: 06415 numElements = 0; 06416 spft = token->u.array.format; 06417 for (i = 0; i < token->u.array.numTokens; i++, spft++) 06418 { 06419 tag = &spft->u.tag; 06420 if (spft->type != PTOK_TAG || tag->arrayCount || tag->justOne) 06421 continue; 06422 he = &tag->he; 06423 if (!he->avail) { 06424 he->tag = tag->tagno[0]; 06425 if (tag->ext) 06426 xx = getExtension(hsa, tag->ext, he, hsa->ec + tag->extNum); 06427 else 06428 xx = headerGet(hsa->h, he, 0); 06429 if (!xx) { 06430 (void) rpmheClean(he); 06431 continue; 06432 } 06433 he->avail = 1; 06434 } 06435 06436 /* Check iteration arrays are same dimension (or scalar). */ 06437 switch (he->t) { 06438 default: 06439 if (numElements == 0) { 06440 numElements = he->c; 06441 /*@switchbreak@*/ break; 06442 } 06443 if ((size_t)he->c == numElements) 06444 /*@switchbreak@*/ break; 06445 hsa->errmsg = 06446 _("array iterator used with different sized arrays"); 06447 he = rpmheClean(he); 06448 return NULL; 06449 /*@notreached@*/ /*@switchbreak@*/ break; 06450 case RPM_BIN_TYPE: 06451 case RPM_STRING_TYPE: 06452 if (numElements == 0) 06453 numElements = 1; 06454 /*@switchbreak@*/ break; 06455 } 06456 } 06457 spft = token->u.array.format; 06458 06459 if (numElements == 0) { 06460 #ifdef DYING /* XXX lots of pugly "(none)" lines with --conflicts. */ 06461 need = sizeof("(none)\n") - 1; 06462 t = hsaReserve(hsa, need); 06463 te = stpcpy(t, "(none)\n"); 06464 hsa->vallen += (te - t); 06465 #endif 06466 } else { 06467 rpmTagReturnType tagT = 0; 06468 const char * tagN = NULL; 06469 spew_t spew = NULL; 06470 06471 need = numElements * token->u.array.numTokens; 06472 if (need == 0) break; 06473 06474 tag = &spft->u.tag; 06475 06476 spew = NULL; 06477 /* XXX Ick: +1 needed to handle :extractor |transformer marking. */ 06478 if (spft->type == PTOK_TAG && tag->av != NULL 06479 && tag->av[0] != NULL && !strcmp(tag->av[0]+1, "xml")) 06480 spew = &_xml_spew; 06481 if (spft->type == PTOK_TAG && tag->av != NULL 06482 && tag->av[0] != NULL && !strcmp(tag->av[0]+1, "yaml")) 06483 spew = &_yaml_spew; 06484 if (spft->type == PTOK_TAG && tag->av != NULL 06485 && tag->av[0] != NULL && !strcmp(tag->av[0]+1, "json")) 06486 spew = &_json_spew; 06487 06488 if (spew == &_xml_spew) { 06489 assert(tag->tagno != NULL); 06490 /* XXX display "Tag_0x01234567" for arbitrary tags. */ 06491 if (tag->tagno[0] & 0x40000000) { 06492 tagN = myTagName(hsa->tags, tag->tagno[0], NULL); 06493 } else 06494 tagN = myTagName(hsa->tags, tag->tagno[0], NULL); 06495 need = sizeof(" <rpmTag name=\"\">\n") + strlen(tagN); 06496 te = t = hsaReserve(hsa, need); 06497 te = stpcpy( stpcpy( stpcpy(te, " <rpmTag name=\""), tagN), "\">\n"); 06498 hsa->vallen += (te - t); 06499 } 06500 if (spew == &_yaml_spew) { 06501 assert(tag->tagno != NULL); 06502 /* XXX display "Tag_0x01234567" for arbitrary tags. */ 06503 if (tag->tagno[0] & 0x40000000) { 06504 tagN = myTagName(hsa->tags, tag->tagno[0], NULL); 06505 tagT = numElements > 1 06506 ? RPM_ARRAY_RETURN_TYPE : RPM_SCALAR_RETURN_TYPE; 06507 } else 06508 tagN = myTagName(hsa->tags, tag->tagno[0], &tagT); 06509 need = sizeof(" : - ") + strlen(tagN); 06510 te = t = hsaReserve(hsa, need); 06511 *te++ = ' '; 06512 *te++ = ' '; 06513 te = stpcpy(te, tagN); 06514 *te++ = ':'; 06515 *te++ = (((tagT & RPM_MASK_RETURN_TYPE) == RPM_ARRAY_RETURN_TYPE) 06516 ? '\n' : ' '); 06517 *te = '\0'; 06518 hsa->vallen += (te - t); 06519 } 06520 if (spew == &_json_spew) { 06521 assert(tag->tagno != NULL); 06522 /* XXX display "Tag_0x01234567" for arbitrary tags. */ 06523 if (tag->tagno[0] & 0x40000000) { 06524 tagN = myTagName(hsa->tags, tag->tagno[0], NULL); 06525 tagT = numElements > 1 06526 ? RPM_ARRAY_RETURN_TYPE : RPM_SCALAR_RETURN_TYPE; 06527 } else 06528 if (tag->tagno[0] == RPMTAG_HDRID) { /* RPMTAG_SHA1HEADER */ 06529 tagN = "_id"; /* XXX mongo primary key name */ 06530 } else 06531 tagN = myTagName(hsa->tags, tag->tagno[0], &tagT); 06532 need = sizeof(" : [\n") + strlen(tagN); 06533 te = t = hsaReserve(hsa, need); 06534 te = stpcpy( stpcpy( stpcpy(te, " "), tagN), ":"); 06535 if ((tagT & RPM_MASK_RETURN_TYPE) == RPM_ARRAY_RETURN_TYPE) 06536 te = stpcpy(te, " [\n"); 06537 hsa->vallen += (te - t); 06538 } 06539 06540 need = numElements * token->u.array.numTokens * 10; 06541 t = hsaReserve(hsa, need); 06542 for (j = 0; j < numElements; j++) { 06543 spft = token->u.array.format; 06544 for (i = 0; i < token->u.array.numTokens; i++, spft++) { 06545 /*@-modobserver@*/ /* headerCompoundFormats not modified. */ 06546 te = singleSprintf(hsa, spft, j); 06547 /*@=modobserver@*/ 06548 if (te == NULL) 06549 return NULL; 06550 } 06551 } 06552 06553 if (spew == &_xml_spew) { 06554 need = sizeof(" </rpmTag>\n") - 1; 06555 te = t = hsaReserve(hsa, need); 06556 te = stpcpy(te, " </rpmTag>\n"); 06557 hsa->vallen += (te - t); 06558 } 06559 if (spew == &_json_spew) { 06560 if ((tagT & RPM_MASK_RETURN_TYPE) == RPM_ARRAY_RETURN_TYPE) { 06561 need = sizeof(" ],\n") - 1; 06562 te = t = hsaReserve(hsa, need); 06563 te = stpcpy(te, " ],\n"); 06564 hsa->vallen += (te - t); 06565 } 06566 } 06567 06568 } 06569 break; 06570 } 06571 06572 return (hsa->val + hsa->vallen); 06573 } 06574 06581 static /*@only@*/ HE_t 06582 rpmecNew(const headerSprintfExtension exts, /*@null@*/ int * necp) 06583 /*@modifies *necp @*/ 06584 { 06585 headerSprintfExtension ext; 06586 HE_t ec; 06587 int extNum = 0; 06588 06589 if (exts != NULL) 06590 for (ext = exts, extNum = 0; ext != NULL && ext->type != HEADER_EXT_LAST; 06591 ext = (ext->type == HEADER_EXT_MORE ? *ext->u.more : ext+1), extNum++) 06592 { 06593 ; 06594 } 06595 if (necp) 06596 *necp = extNum; 06597 ec = xcalloc(extNum+1, sizeof(*ec)); /* XXX +1 unnecessary */ 06598 return ec; 06599 } 06600 06607 static /*@null@*/ HE_t 06608 rpmecFree(const headerSprintfExtension exts, /*@only@*/ HE_t ec) 06609 /*@modifies ec @*/ 06610 { 06611 headerSprintfExtension ext; 06612 int extNum; 06613 06614 for (ext = exts, extNum = 0; ext != NULL && ext->type != HEADER_EXT_LAST; 06615 ext = (ext->type == HEADER_EXT_MORE ? *ext->u.more : ext+1), extNum++) 06616 { 06617 (void) rpmheClean(&ec[extNum]); 06618 } 06619 06620 ec = _free(ec); 06621 return NULL; 06622 } 06623 06624 char * headerSprintf(Header h, const char * fmt, 06625 headerTagTableEntry tags, 06626 headerSprintfExtension exts, 06627 errmsg_t * errmsg) 06628 { 06629 headerSprintfArgs hsa = memset(alloca(sizeof(*hsa)), 0, sizeof(*hsa)); 06630 sprintfToken nextfmt; 06631 sprintfTag tag; 06632 char * t, * te; 06633 int need; 06634 spew_t spew = NULL; 06635 06636 /*@-modfilesys@*/ 06637 if (_hdrqf_debug) 06638 fprintf(stderr, "==> headerSprintf(%p, \"%s\", %p, %p, %p)\n", h, fmt, tags, exts, errmsg); 06639 /*@=modfilesys@*/ 06640 06641 /* Set some reasonable defaults */ 06642 if (tags == NULL) 06643 tags = rpmTagTable; 06644 /* XXX this loses the extensions in lib/formats.c. */ 06645 if (exts == NULL) 06646 exts = headerCompoundFormats; 06647 06648 /*@-assignexpose -castexpose @*/ 06649 hsa->h = headerLink(h); 06650 /*@=assignexpose =castexpose @*/ 06651 hsa->fmt = xstrdup(fmt); 06652 /*@-assignexpose -dependenttrans@*/ 06653 hsa->exts = exts; 06654 hsa->tags = tags; 06655 /*@=assignexpose =dependenttrans@*/ 06656 hsa->errmsg = NULL; 06657 06658 if (parseFormat(hsa, hsa->fmt, &hsa->format, &hsa->numTokens, NULL, PARSER_BEGIN)) 06659 goto exit; 06660 06661 hsa->nec = 0; 06662 hsa->ec = rpmecNew(hsa->exts, &hsa->nec); 06663 hsa->val = xstrdup(""); 06664 06665 tag = 06666 (hsa->format->type == PTOK_TAG 06667 ? &hsa->format->u.tag : 06668 (hsa->format->type == PTOK_ARRAY 06669 ? &hsa->format->u.array.format->u.tag : 06670 NULL)); 06671 06672 spew = NULL; 06673 /* XXX Ick: +1 needed to handle :extractor |transformer marking. */ 06674 if (tag != NULL && tag->tagno != NULL && tag->tagno[0] == (rpmTag)-2 06675 && tag->av != NULL && tag->av[0] != NULL && !strcmp(tag->av[0]+1, "xml")) 06676 spew = &_xml_spew; 06677 if (tag != NULL && tag->tagno != NULL && tag->tagno[0] == (rpmTag)-2 06678 && tag->av != NULL && tag->av[0] != NULL && !strcmp(tag->av[0]+1, "yaml")) 06679 spew = &_yaml_spew; 06680 if (tag != NULL && tag->tagno != NULL && tag->tagno[0] == (rpmTag)-2 06681 && tag->av != NULL && tag->av[0] != NULL && !strcmp(tag->av[0]+1, "json")) 06682 spew = &_json_spew; 06683 06684 if (spew && spew->spew_init && spew->spew_init[0]) { 06685 need = strlen(spew->spew_init); 06686 t = hsaReserve(hsa, need); 06687 te = stpcpy(t, spew->spew_init); 06688 hsa->vallen += (te - t); 06689 } 06690 06691 hsa = hsaInit(hsa); 06692 while ((nextfmt = hsaNext(hsa)) != NULL) { 06693 /*@-globs -mods@*/ /* XXX rpmGlobalMacroContext @*/ 06694 te = singleSprintf(hsa, nextfmt, 0); 06695 /*@=globs =mods @*/ 06696 if (te == NULL) { 06697 hsa->val = _free(hsa->val); 06698 break; 06699 } 06700 } 06701 hsa = hsaFini(hsa); 06702 06703 if (spew && spew->spew_fini && spew->spew_fini[0]) { 06704 need = strlen(spew->spew_fini); 06705 t = hsaReserve(hsa, need); 06706 te = stpcpy(t, spew->spew_fini); 06707 hsa->vallen += (te - t); 06708 } 06709 06710 if (hsa->val != NULL && hsa->vallen < hsa->alloced) 06711 hsa->val = xrealloc(hsa->val, hsa->vallen+1); 06712 06713 hsa->ec = rpmecFree(hsa->exts, hsa->ec); 06714 hsa->nec = 0; 06715 hsa->format = freeFormat(hsa->format, hsa->numTokens); 06716 06717 exit: 06718 /*@-dependenttrans -observertrans @*/ 06719 if (errmsg) 06720 *errmsg = hsa->errmsg; 06721 /*@=dependenttrans =observertrans @*/ 06722 (void)headerFree(hsa->h); 06723 hsa->h = NULL; 06724 hsa->fmt = _free(hsa->fmt); 06725 /*@-retexpose@*/ 06726 return hsa->val; 06727 /*@=retexpose@*/ 06728 }