rpm 5.3.7
|
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] &= 0x3f; /* preserve reserved, 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 int rc; 01784 01785 /* XXX Substitute Pkgid & Hdrid strings for aliases. */ 01786 if (!strcmp("Sigmd5", tagn)) 01787 tagn = "Pkgid"; 01788 else if (!strcmp("Sha1header", tagn)) 01789 tagn = "Hdrid"; 01790 01791 switch (version) { 01792 default: 01793 version = uuid_version; 01794 /*@fallthrough@*/ 01795 case 3: 01796 case 5: 01797 assert(he->t == RPM_STRING_TYPE); 01798 ns = uuid_ns; 01799 s = rpmGetPath(uuid_auth, "/", uuid_path, "/", tagn, "/", 01800 he->p.str, NULL); 01801 /*@fallthrough@*/ 01802 case 4: 01803 break; 01804 } 01805 he->p.ptr = _free(he->p.ptr); 01806 he->t = RPM_BIN_TYPE; 01807 he->c = 128/8; 01808 he->p.ptr = xcalloc(1, he->c); 01809 he->freeData = 1; 01810 rc = rpmuuidMake((int)version, ns, s, val, (unsigned char *)he->p.ui8p); 01811 if (rc) { 01812 he->p.ptr = _free(he->p.ptr); 01813 he->freeData = 0; 01814 } 01815 s = _free(s); 01816 return rc; 01817 } 01818 01825 static int tag2uuidv5(Header h, HE_t he) 01826 /*@globals rpmGlobalMacroContext, h_errno, internalState @*/ 01827 /*@modifies he, rpmGlobalMacroContext, internalState @*/ 01828 { 01829 if (!headerGet(h, he, 0)) 01830 return 1; 01831 switch (he->t) { 01832 default: 01833 assert(0); 01834 /*@notreached@*/ break; 01835 case RPM_BIN_TYPE: { /* Convert RPMTAG_PKGID from binary => hex. */ 01836 static const char hex[] = "0123456789abcdef"; 01837 char * t; 01838 char * te; 01839 rpmuint32_t i; 01840 01841 t = te = xmalloc (2*he->c + 1); 01842 for (i = 0; i < he->c; i++) { 01843 *te++ = hex[ (int)((he->p.ui8p[i] >> 4) & 0x0f) ]; 01844 *te++ = hex[ (int)((he->p.ui8p[i] ) & 0x0f) ]; 01845 } 01846 *te = '\0'; 01847 he->p.ptr = _free(he->p.ptr); 01848 he->t = RPM_STRING_TYPE; 01849 he->p.ptr = t; 01850 he->c = 1; 01851 he->freeData = 1; 01852 } break; 01853 case RPM_STRING_TYPE: 01854 break; 01855 } 01856 return str2uuid(he, NULL, 0, NULL); 01857 } 01858 01865 static int pkguuidTag(Header h, HE_t he) 01866 /*@globals rpmGlobalMacroContext, h_errno, internalState @*/ 01867 /*@modifies he, rpmGlobalMacroContext, internalState @*/ 01868 { 01869 he->tag = RPMTAG_PKGID; 01870 return tag2uuidv5(h, he); 01871 } 01872 01879 static int sourcepkguuidTag(Header h, HE_t he) 01880 /*@globals rpmGlobalMacroContext, h_errno, internalState @*/ 01881 /*@modifies he, rpmGlobalMacroContext, internalState @*/ 01882 { 01883 he->tag = RPMTAG_SOURCEPKGID; 01884 return tag2uuidv5(h, he); 01885 } 01886 01893 static int hdruuidTag(Header h, HE_t he) 01894 /*@globals rpmGlobalMacroContext, h_errno, internalState @*/ 01895 /*@modifies he, rpmGlobalMacroContext, internalState @*/ 01896 { 01897 he->tag = RPMTAG_HDRID; 01898 return tag2uuidv5(h, he); 01899 } 01900 01907 static int triggercondsTag(Header h, HE_t he) 01908 /*@globals internalState @*/ 01909 /*@modifies he, internalState @*/ 01910 { 01911 HE_t _he = memset(alloca(sizeof(*_he)), 0, sizeof(*_he)); 01912 HE_t Fhe = memset(alloca(sizeof(*Fhe)), 0, sizeof(*Fhe)); 01913 HE_t Ihe = memset(alloca(sizeof(*Ihe)), 0, sizeof(*Ihe)); 01914 HE_t Nhe = memset(alloca(sizeof(*Nhe)), 0, sizeof(*Nhe)); 01915 HE_t Vhe = memset(alloca(sizeof(*Vhe)), 0, sizeof(*Vhe)); 01916 HE_t She = memset(alloca(sizeof(*She)), 0, sizeof(*She)); 01917 rpmuint64_t anint; 01918 unsigned i, j; 01919 int rc = 1; /* assume failure */ 01920 int xx; 01921 01922 he->freeData = 0; 01923 01924 Nhe->tag = RPMTAG_TRIGGERNAME; 01925 xx = headerGet(h, Nhe, 0); 01926 if (!xx) { /* no triggers, succeed anyways */ 01927 rc = 0; 01928 goto exit; 01929 } 01930 01931 Ihe->tag = RPMTAG_TRIGGERINDEX; 01932 xx = headerGet(h, Ihe, 0); 01933 if (!xx) goto exit; 01934 01935 Fhe->tag = RPMTAG_TRIGGERFLAGS; 01936 xx = headerGet(h, Fhe, 0); 01937 if (!xx) goto exit; 01938 01939 Vhe->tag = RPMTAG_TRIGGERVERSION; 01940 xx = headerGet(h, Vhe, 0); 01941 if (!xx) goto exit; 01942 01943 She->tag = RPMTAG_TRIGGERSCRIPTS; 01944 xx = headerGet(h, She, 0); 01945 if (!xx) goto exit; 01946 01947 _he->tag = he->tag; 01948 _he->t = RPM_UINT64_TYPE; 01949 _he->p.ui64p = &anint; 01950 _he->c = 1; 01951 _he->freeData = 0; 01952 01953 he->t = RPM_STRING_ARRAY_TYPE; 01954 he->c = She->c; 01955 01956 he->freeData = 1; 01957 he->p.argv = xmalloc(sizeof(*he->p.argv) * he->c); 01958 for (i = 0; i < (unsigned) he->c; i++) { 01959 char * item, * flagsStr; 01960 char * chptr; 01961 01962 chptr = xstrdup(""); 01963 01964 for (j = 0; j < Nhe->c; j++) { 01965 if (Ihe->p.ui32p[j] != i) 01966 /*@innercontinue@*/ continue; 01967 01968 item = xmalloc(strlen(Nhe->p.argv[j]) + strlen(Vhe->p.argv[j]) + 20); 01969 /*@-compmempass@*/ /* use separate HE_t, not rpmTagData, containers. */ 01970 if (Fhe->p.ui32p[j] & RPMSENSE_SENSEMASK) { 01971 anint = Fhe->p.ui32p[j]; 01972 flagsStr = depflagsFormat(_he, NULL); 01973 sprintf(item, "%s%s%s", Nhe->p.argv[j], flagsStr, Vhe->p.argv[j]); 01974 flagsStr = _free(flagsStr); 01975 } else 01976 strcpy(item, Nhe->p.argv[j]); 01977 /*@=compmempass@*/ 01978 01979 chptr = xrealloc(chptr, strlen(chptr) + strlen(item) + 5); 01980 if (*chptr != '\0') strcat(chptr, ", "); 01981 strcat(chptr, item); 01982 item = _free(item); 01983 } 01984 01985 he->p.argv[i] = chptr; 01986 } 01987 rc = 0; 01988 01989 exit: 01990 Ihe->p.ptr = _free(Ihe->p.ptr); 01991 Fhe->p.ptr = _free(Fhe->p.ptr); 01992 Nhe->p.ptr = _free(Nhe->p.ptr); 01993 Vhe->p.ptr = _free(Vhe->p.ptr); 01994 She->p.ptr = _free(She->p.ptr); 01995 01996 return rc; 01997 } 01998 02005 static int triggertypeTag(Header h, HE_t he) 02006 /*@globals internalState @*/ 02007 /*@modifies he, internalState @*/ 02008 { 02009 HE_t _he = memset(alloca(sizeof(*_he)), 0, sizeof(*_he)); 02010 rpmTagData indices = { .ptr = NULL }; 02011 rpmTagData flags = { .ptr = NULL }; 02012 rpmTagData s = { .ptr = NULL }; 02013 rpmTagCount numNames; 02014 rpmTagCount numScripts; 02015 unsigned i, j; 02016 int rc = 1; /* assume failure */ 02017 int xx; 02018 02019 he->freeData = 0; 02020 02021 /*@-compmempass@*/ /* use separate HE_t, not rpmTagData, containers. */ 02022 _he->tag = RPMTAG_TRIGGERINDEX; 02023 xx = headerGet(h, _he, 0); 02024 if (!xx) goto exit; 02025 indices.ui32p = _he->p.ui32p; 02026 numNames = _he->c; 02027 02028 _he->tag = RPMTAG_TRIGGERFLAGS; 02029 xx = headerGet(h, _he, 0); 02030 if (!xx) goto exit; 02031 flags.ui32p = _he->p.ui32p; 02032 02033 _he->tag = RPMTAG_TRIGGERSCRIPTS; 02034 xx = headerGet(h, _he, 0); 02035 if (!xx) goto exit; 02036 s.argv = _he->p.argv; 02037 numScripts = _he->c; 02038 /*@=compmempass@*/ 02039 02040 he->t = RPM_STRING_ARRAY_TYPE; 02041 he->c = numScripts; 02042 02043 he->freeData = 1; 02044 he->p.argv = xmalloc(sizeof(*he->p.argv) * he->c); 02045 for (i = 0; i < (unsigned) he->c; i++) { 02046 for (j = 0; j < (unsigned) numNames; j++) { 02047 if (indices.ui32p[j] != i) 02048 /*@innercontinue@*/ continue; 02049 02050 /* XXX FIXME: there's memory leaks here. */ 02051 if (flags.ui32p[j] & RPMSENSE_TRIGGERPREIN) 02052 he->p.argv[i] = xstrdup("prein"); 02053 else if (flags.ui32p[j] & RPMSENSE_TRIGGERIN) 02054 he->p.argv[i] = xstrdup("in"); 02055 else if (flags.ui32p[j] & RPMSENSE_TRIGGERUN) 02056 he->p.argv[i] = xstrdup("un"); 02057 else if (flags.ui32p[j] & RPMSENSE_TRIGGERPOSTUN) 02058 he->p.argv[i] = xstrdup("postun"); 02059 else 02060 he->p.argv[i] = xstrdup(""); 02061 /*@innerbreak@*/ break; 02062 } 02063 } 02064 rc = 0; 02065 02066 exit: 02067 indices.ptr = _free(indices.ptr); 02068 flags.ptr = _free(flags.ptr); 02069 s.ptr = _free(s.ptr); 02070 return 0; 02071 } 02072 02073 /* I18N look aside diversions */ 02074 02075 #if defined(ENABLE_NLS) 02076 /*@-exportlocal -exportheadervar@*/ 02077 /*@unchecked@*/ 02078 extern int _nl_msg_cat_cntr; /* XXX GNU gettext voodoo */ 02079 /*@=exportlocal =exportheadervar@*/ 02080 #endif 02081 /*@observer@*/ /*@unchecked@*/ 02082 static const char * language = "LANGUAGE"; 02083 02084 /*@observer@*/ /*@unchecked@*/ 02085 static const char * _macro_i18ndomains = "%{?_i18ndomains}"; 02086 02093 static int i18nTag(Header h, HE_t he) 02094 /*@globals rpmGlobalMacroContext, h_errno, internalState @*/ 02095 /*@modifies he, rpmGlobalMacroContext, internalState @*/ 02096 { 02097 char * dstring = rpmExpand(_macro_i18ndomains, NULL); 02098 int rc = 1; /* assume failure */ 02099 02100 he->t = RPM_STRING_TYPE; 02101 he->p.str = NULL; 02102 he->c = 0; 02103 he->freeData = 0; 02104 02105 if (dstring && *dstring) { 02106 char *domain, *de; 02107 const char * langval; 02108 const char * msgkey; 02109 const char * msgid; 02110 02111 { HE_t nhe = memset(alloca(sizeof(*nhe)), 0, sizeof(*nhe)); 02112 const char * tn; 02113 char * mk; 02114 size_t nb = sizeof("()"); 02115 int xx; 02116 02117 nhe->tag = RPMTAG_NAME; 02118 xx = headerGet(h, nhe, 0); 02119 /* 02120 * XXX Ick, tagName() is called by headerGet(), and the tagName() 02121 * buffer is valid only until next tagName() call. 02122 * For now, do the tagName() lookup after headerGet(). 02123 */ 02124 tn = tagName(he->tag); 02125 if (tn) nb += strlen(tn); 02126 if (nhe->p.str) nb += strlen(nhe->p.str); 02127 mk = alloca(nb); 02128 (void) snprintf(mk, nb, "%s(%s)", 02129 (nhe->p.str ? nhe->p.str : ""), (tn ? tn : "")); 02130 mk[nb-1] = '\0'; 02131 nhe->p.ptr = _free(nhe->p.ptr); 02132 msgkey = mk; 02133 } 02134 02135 /* change to en_US for msgkey -> msgid resolution */ 02136 langval = getenv(language); 02137 (void) setenv(language, "en_US", 1); 02138 #if defined(ENABLE_NLS) 02139 /*@i@*/ ++_nl_msg_cat_cntr; 02140 #endif 02141 02142 msgid = NULL; 02143 for (domain = dstring; domain != NULL; domain = de) { 02144 de = strchr(domain, ':'); 02145 if (de) *de++ = '\0'; 02146 /*@-unrecog@*/ 02147 msgid = dgettext(domain, msgkey); 02148 /*@=unrecog@*/ 02149 if (msgid != msgkey) break; 02150 } 02151 02152 /* restore previous environment for msgid -> msgstr resolution */ 02153 if (langval) 02154 (void) setenv(language, langval, 1); 02155 else 02156 unsetenv(language); 02157 #if defined(ENABLE_NLS) 02158 /*@i@*/ ++_nl_msg_cat_cntr; 02159 #endif 02160 02161 if (domain && msgid) { 02162 /*@-unrecog@*/ 02163 const char * s = dgettext(domain, msgid); 02164 /*@=unrecog@*/ 02165 if (s) { 02166 rc = 0; 02167 he->p.str = xstrdup(s); 02168 he->c = 1; 02169 he->freeData = 1; 02170 } 02171 } 02172 } 02173 02174 /*@-dependenttrans@*/ 02175 dstring = _free(dstring); 02176 /*@=dependenttrans@*/ 02177 if (!rc) 02178 return rc; 02179 02180 rc = headerGet(h, he, HEADERGET_NOEXTENSION); 02181 if (rc) { 02182 rc = 0; 02183 he->p.str = xstrtolocale(he->p.str); 02184 he->freeData = 1; 02185 return rc; 02186 } 02187 02188 he->t = RPM_STRING_TYPE; 02189 he->p.str = NULL; 02190 he->c = 0; 02191 he->freeData = 0; 02192 02193 return 1; 02194 } 02195 02199 static int localeTag(Header h, HE_t he) 02200 /*@globals internalState @*/ 02201 /*@modifies he, internalState @*/ 02202 { 02203 int rc; 02204 02205 rc = headerGet(h, he, HEADERGET_NOEXTENSION); 02206 if (!rc || he->p.str == NULL || he->c == 0) { 02207 he->t = RPM_STRING_TYPE; 02208 he->freeData = 0; 02209 return 1; 02210 } 02211 02212 switch (he->t) { 02213 default: 02214 he->freeData = 0; 02215 break; 02216 case RPM_STRING_TYPE: 02217 he->p.str = xstrtolocale(he->p.str); 02218 he->freeData = 1; 02219 break; 02220 case RPM_STRING_ARRAY_TYPE: 02221 { const char ** argv; 02222 char * te; 02223 size_t l = 0; 02224 unsigned i; 02225 for (i = 0; i < (unsigned) he->c; i++) { 02226 he->p.argv[i] = xstrdup(he->p.argv[i]); 02227 he->p.argv[i] = xstrtolocale(he->p.argv[i]); 02228 assert(he->p.argv[i] != NULL); 02229 l += strlen(he->p.argv[i]) + 1; 02230 } 02231 argv = xmalloc(he->c * sizeof(*argv) + l); 02232 te = (char *)&argv[he->c]; 02233 for (i = 0; i < (unsigned) he->c; i++) { 02234 argv[i] = te; 02235 te = stpcpy(te, he->p.argv[i]); 02236 te++; 02237 he->p.argv[i] = _free(he->p.argv[i]); 02238 } 02239 he->p.ptr = _free(he->p.ptr); 02240 he->p.argv = argv; 02241 he->freeData = 1; 02242 } break; 02243 } 02244 02245 return 0; 02246 } 02247 02254 static int summaryTag(Header h, HE_t he) 02255 /*@globals rpmGlobalMacroContext, h_errno, internalState @*/ 02256 /*@modifies he, rpmGlobalMacroContext, internalState @*/ 02257 { 02258 he->tag = RPMTAG_SUMMARY; 02259 return i18nTag(h, he); 02260 } 02261 02268 static int descriptionTag(Header h, HE_t he) 02269 /*@globals rpmGlobalMacroContext, h_errno, internalState @*/ 02270 /*@modifies he, rpmGlobalMacroContext, internalState @*/ 02271 { 02272 he->tag = RPMTAG_DESCRIPTION; 02273 return i18nTag(h, he); 02274 } 02275 02276 static int changelognameTag(Header h, HE_t he) 02277 /*@globals internalState @*/ 02278 /*@modifies he, internalState @*/ 02279 { 02280 he->tag = RPMTAG_CHANGELOGNAME; 02281 return localeTag(h, he); 02282 } 02283 02284 static int changelogtextTag(Header h, HE_t he) 02285 /*@globals internalState @*/ 02286 /*@modifies he, internalState @*/ 02287 { 02288 he->tag = RPMTAG_CHANGELOGTEXT; 02289 return localeTag(h, he); 02290 } 02291 02298 static int groupTag(Header h, HE_t he) 02299 /*@globals rpmGlobalMacroContext, h_errno, internalState @*/ 02300 /*@modifies he, rpmGlobalMacroContext, internalState @*/ 02301 { 02302 he->tag = RPMTAG_GROUP; 02303 return i18nTag(h, he); 02304 } 02305 02312 static int dbinstanceTag(Header h, HE_t he) 02313 /*@modifies he @*/ 02314 { 02315 he->tag = RPMTAG_DBINSTANCE; 02316 he->t = RPM_UINT32_TYPE; 02317 he->p.ui32p = xmalloc(sizeof(*he->p.ui32p)); 02318 he->p.ui32p[0] = headerGetInstance(h); 02319 he->freeData = 1; 02320 he->c = 1; 02321 return 0; 02322 } 02323 02330 static int headerstartoffTag(Header h, HE_t he) 02331 /*@modifies he @*/ 02332 { 02333 he->tag = RPMTAG_HEADERSTARTOFF; 02334 he->t = RPM_UINT64_TYPE; 02335 he->p.ui64p = xmalloc(sizeof(*he->p.ui64p)); 02336 he->p.ui64p[0] = headerGetStartOff(h); 02337 he->freeData = 1; 02338 he->c = 1; 02339 return 0; 02340 } 02341 02348 static int headerendoffTag(Header h, HE_t he) 02349 /*@modifies he @*/ 02350 { 02351 he->tag = RPMTAG_HEADERENDOFF; 02352 he->t = RPM_UINT64_TYPE; 02353 he->p.ui64p = xmalloc(sizeof(*he->p.ui64p)); 02354 he->p.ui64p[0] = headerGetEndOff(h); 02355 he->freeData = 1; 02356 he->c = 1; 02357 return 0; 02358 } 02359 02366 static int pkgoriginTag(Header h, HE_t he) 02367 /*@globals internalState @*/ 02368 /*@modifies he, internalState @*/ 02369 { 02370 const char * origin; 02371 int rc = 1; 02372 02373 he->tag = RPMTAG_PACKAGEORIGIN; 02374 if (!headerGet(h, he, HEADERGET_NOEXTENSION) 02375 && (origin = headerGetOrigin(h)) != NULL) 02376 { 02377 he->t = RPM_STRING_TYPE; 02378 he->p.str = xstrdup(origin); 02379 he->c = 1; 02380 he->freeData = 1; 02381 rc = 0; 02382 } 02383 return rc; 02384 } 02385 02392 static int pkgbaseurlTag(Header h, HE_t he) 02393 /*@globals internalState @*/ 02394 /*@modifies he, internalState @*/ 02395 { 02396 const char * baseurl; 02397 int rc = 1; 02398 02399 he->tag = RPMTAG_PACKAGEBASEURL; 02400 if (!headerGet(h, he, HEADERGET_NOEXTENSION) 02401 && (baseurl = headerGetBaseURL(h)) != NULL) 02402 { 02403 he->t = RPM_STRING_TYPE; 02404 he->p.str = xstrdup(baseurl); 02405 he->c = 1; 02406 he->freeData = 1; 02407 rc = 0; 02408 } 02409 return rc; 02410 } 02411 02418 static int pkgdigestTag(Header h, HE_t he) 02419 /*@modifies he @*/ 02420 { 02421 const char * digest; 02422 int rc = 1; 02423 02424 he->tag = RPMTAG_PACKAGEDIGEST; 02425 if ((digest = headerGetDigest(h)) != NULL) 02426 { 02427 he->t = RPM_STRING_TYPE; 02428 he->p.str = xstrdup(digest); 02429 he->c = 1; 02430 he->freeData = 1; 02431 rc = 0; 02432 } 02433 return rc; 02434 } 02435 02442 static int pkgmtimeTag(Header h, HE_t he) 02443 /*@modifies he @*/ 02444 { 02445 struct stat * st = headerGetStatbuf(h); 02446 he->tag = RPMTAG_PACKAGETIME; 02447 he->t = RPM_UINT64_TYPE; 02448 he->p.ui64p = xmalloc(sizeof(*he->p.ui64p)); 02449 /*@-type@*/ 02450 he->p.ui64p[0] = (rpmuint64_t)st->st_mtime; 02451 /*@=type@*/ 02452 he->freeData = 1; 02453 he->c = 1; 02454 return 0; 02455 } 02456 02463 static int pkgsizeTag(Header h, HE_t he) 02464 /*@modifies he @*/ 02465 { 02466 struct stat * st = headerGetStatbuf(h); 02467 he->tag = RPMTAG_PACKAGESIZE; 02468 he->t = RPM_UINT64_TYPE; 02469 he->p.ui64p = xmalloc(sizeof(*he->p.ui64p)); 02470 he->p.ui64p[0] = (rpmuint64_t)st->st_size; 02471 he->freeData = 1; 02472 he->c = 1; 02473 return 0; 02474 } 02475 02481 /*@only@*/ 02482 static char * hGetNVRA(Header h) 02483 /*@globals internalState @*/ 02484 /*@modifies h, internalState @*/ 02485 { 02486 const char * N = NULL; 02487 const char * V = NULL; 02488 const char * R = NULL; 02489 const char * A = NULL; 02490 size_t nb = 0; 02491 char * NVRA, * t; 02492 02493 (void) headerNEVRA(h, &N, NULL, &V, &R, &A); 02494 if (N) nb += strlen(N); 02495 if (V) nb += strlen(V) + 1; 02496 if (R) nb += strlen(R) + 1; 02497 #if defined(RPM_VENDOR_OPENPKG) /* no-architecture-expose */ 02498 /* do not expose the architecture as this is too less 02499 information, as in OpenPKG the "platform" is described by the 02500 architecture+operating-system combination. But as the whole 02501 "platform" information is actually overkill, just revert to the 02502 RPM 4 behaviour and do not expose any such information at all. */ 02503 #else 02504 if (A) nb += strlen(A) + 1; 02505 #endif 02506 nb++; 02507 NVRA = t = xmalloc(nb); 02508 *t = '\0'; 02509 if (N) t = stpcpy(t, N); 02510 if (V) t = stpcpy( stpcpy(t, "-"), V); 02511 if (R) t = stpcpy( stpcpy(t, "-"), R); 02512 #if defined(RPM_VENDOR_OPENPKG) /* no-architecture-expose */ 02513 /* do not expose the architecture as this is too less 02514 information, as in OpenPKG the "platform" is described by the 02515 architecture+operating-system combination. But as the whole 02516 "platform" information is actually overkill, just revert to the 02517 RPM 4 behaviour and do not expose any such information at all. */ 02518 #else 02519 if (A) t = stpcpy( stpcpy(t, "."), A); 02520 #endif 02521 N = _free(N); 02522 V = _free(V); 02523 R = _free(R); 02524 A = _free(A); 02525 return NVRA; 02526 } 02527 02534 static int nvraTag(Header h, HE_t he) 02535 /*@globals internalState @*/ 02536 /*@modifies h, he, internalState @*/ 02537 { 02538 he->t = RPM_STRING_TYPE; 02539 he->p.str = hGetNVRA(h); 02540 he->c = 1; 02541 he->freeData = 1; 02542 return 0; 02543 } 02544 02562 static void rpmfiBuildFNames(Header h, rpmTag tagN, 02563 /*@null@*/ /*@out@*/ const char *** fnp, 02564 /*@null@*/ /*@out@*/ rpmTagCount * fcp) 02565 /*@globals internalState @*/ 02566 /*@modifies *fnp, *fcp, internalState @*/ 02567 { 02568 HE_t he = memset(alloca(sizeof(*he)), 0, sizeof(*he)); 02569 rpmTag dirNameTag = 0; 02570 rpmTag dirIndexesTag = 0; 02571 rpmTagData baseNames = { .ptr = NULL }; 02572 rpmTagData dirNames = { .ptr = NULL }; 02573 rpmTagData dirIndexes = { .ptr = NULL }; 02574 rpmTagData fileNames; 02575 rpmTagCount count; 02576 size_t size; 02577 int isSource = 02578 (headerIsEntry(h, RPMTAG_SOURCERPM) == 0 && 02579 headerIsEntry(h, RPMTAG_ARCH) != 0); 02580 char * t; 02581 unsigned i; 02582 int xx; 02583 02584 if (tagN == RPMTAG_BASENAMES) { 02585 dirNameTag = RPMTAG_DIRNAMES; 02586 dirIndexesTag = RPMTAG_DIRINDEXES; 02587 } else if (tagN == RPMTAG_ORIGBASENAMES) { 02588 dirNameTag = RPMTAG_ORIGDIRNAMES; 02589 dirIndexesTag = RPMTAG_ORIGDIRINDEXES; 02590 } else { 02591 if (fnp) *fnp = NULL; 02592 if (fcp) *fcp = 0; 02593 return; /* programmer error */ 02594 } 02595 02596 /*@-compmempass@*/ /* use separate HE_t, not rpmTagData, containers. */ 02597 he->tag = tagN; 02598 xx = headerGet(h, he, 0); 02599 /* XXX 3.0.x SRPM's can be used, relative fn's at RPMTAG_OLDFILENAMES. */ 02600 if (xx == 0 && isSource) { 02601 he->tag = RPMTAG_OLDFILENAMES; 02602 xx = headerGet(h, he, 0); 02603 if (xx) { 02604 dirNames.argv = xcalloc(3, sizeof(*dirNames.argv)); 02605 dirNames.argv[0] = (const char *)&dirNames.argv[2]; 02606 dirIndexes.ui32p = xcalloc(he->c, sizeof(*dirIndexes.ui32p)); 02607 } 02608 } 02609 baseNames.argv = he->p.argv; 02610 count = he->c; 02611 02612 if (!xx) { 02613 if (fnp) *fnp = NULL; 02614 if (fcp) *fcp = 0; 02615 return; /* no file list */ 02616 } 02617 02618 he->tag = dirNameTag; 02619 if ((xx = headerGet(h, he, 0)) != 0) 02620 dirNames.argv = he->p.argv; 02621 02622 he->tag = dirIndexesTag; 02623 if ((xx = headerGet(h, he, 0)) != 0) 02624 dirIndexes.ui32p = he->p.ui32p; 02625 /*@=compmempass@*/ 02626 02627 size = sizeof(*fileNames.argv) * count; 02628 for (i = 0; i < (unsigned)count; i++) { 02629 const char * dn = NULL; 02630 (void) urlPath(dirNames.argv[dirIndexes.ui32p[i]], &dn); 02631 size += strlen(baseNames.argv[i]) + strlen(dn) + 1; 02632 } 02633 02634 fileNames.argv = xmalloc(size); 02635 t = (char *)&fileNames.argv[count]; 02636 for (i = 0; i < (unsigned)count; i++) { 02637 const char * dn = NULL; 02638 (void) urlPath(dirNames.argv[dirIndexes.ui32p[i]], &dn); 02639 fileNames.argv[i] = t; 02640 t = stpcpy( stpcpy(t, dn), baseNames.argv[i]); 02641 *t++ = '\0'; 02642 } 02643 baseNames.ptr = _free(baseNames.ptr); 02644 dirNames.ptr = _free(dirNames.ptr); 02645 dirIndexes.ptr = _free(dirIndexes.ptr); 02646 02647 /*@-onlytrans@*/ 02648 if (fnp) 02649 *fnp = fileNames.argv; 02650 else 02651 fileNames.ptr = _free(fileNames.ptr); 02652 /*@=onlytrans@*/ 02653 if (fcp) *fcp = count; 02654 } 02655 02663 static int _fnTag(Header h, HE_t he, rpmTag tag) 02664 /*@globals internalState @*/ 02665 /*@modifies he, internalState @*/ 02666 { 02667 he->t = RPM_STRING_ARRAY_TYPE; 02668 rpmfiBuildFNames(h, tag, &he->p.argv, &he->c); 02669 he->freeData = 1; 02670 /* XXX headerGet() rc on RPMTAG_FILEPATHS w empty list. */ 02671 if (he->p.argv && he->p.argv[0] && he->c > 0) 02672 return 0; 02673 he->p.ptr = _free(he->p.ptr); 02674 he->c = 0; 02675 return 1; 02676 } 02677 02678 static int filenamesTag(Header h, HE_t he) 02679 /*@globals internalState @*/ 02680 /*@modifies he, internalState @*/ 02681 { 02682 he->tag = tagValue("Filenames"); 02683 return _fnTag(h, he, RPMTAG_BASENAMES); 02684 } 02685 02686 static int filepathsTag(Header h, HE_t he) 02687 /*@globals internalState @*/ 02688 /*@modifies he, internalState @*/ 02689 { 02690 he->tag = RPMTAG_FILEPATHS; 02691 return _fnTag(h, he, RPMTAG_BASENAMES); 02692 } 02693 02694 static int origpathsTag(Header h, HE_t he) 02695 /*@globals internalState @*/ 02696 /*@modifies he, internalState @*/ 02697 { 02698 he->tag = RPMTAG_ORIGPATHS; 02699 return _fnTag(h, he, RPMTAG_ORIGBASENAMES); 02700 } 02701 02711 static int debevrfmtTag(/*@unused@*/ Header h, HE_t he, 02712 HE_t Nhe, HE_t EVRhe, HE_t Fhe) 02713 /*@globals rpmGlobalMacroContext, h_errno, internalState @*/ 02714 /*@modifies he, Nhe, rpmGlobalMacroContext, internalState @*/ 02715 { 02716 char * t, * te; 02717 size_t nb = 0; 02718 int rc = 1; 02719 02720 he->t = RPM_STRING_ARRAY_TYPE; 02721 he->c = 0; 02722 he->freeData = 1; 02723 for (Nhe->ix = 0; Nhe->ix < (int)Nhe->c; Nhe->ix++) { 02724 nb += sizeof(*he->p.argv); 02725 nb += strlen(Nhe->p.argv[Nhe->ix]) + 1; 02726 if (*EVRhe->p.argv[Nhe->ix] != '\0') 02727 nb += strlen(EVRhe->p.argv[Nhe->ix]) + (sizeof(" (== )")-1); 02728 he->c++; 02729 } 02730 nb += sizeof(*he->p.argv); 02731 02732 he->p.argv = xmalloc(nb); 02733 te = (char *) &he->p.argv[he->c+1]; 02734 02735 he->c = 0; 02736 for (Nhe->ix = 0; Nhe->ix < (int)Nhe->c; Nhe->ix++) { 02737 he->p.argv[he->c++] = te; 02738 if (*EVRhe->p.argv[Nhe->ix] != '\0') { 02739 char opstr[4], * op = opstr; 02740 if (Fhe->p.ui32p[Nhe->ix] & RPMSENSE_LESS) 02741 *op++ = '<'; 02742 if (Fhe->p.ui32p[Nhe->ix] & RPMSENSE_GREATER) 02743 *op++ = '>'; 02744 if (Fhe->p.ui32p[Nhe->ix] & RPMSENSE_EQUAL) 02745 *op++ = '='; 02746 *op = '\0'; 02747 t = rpmExpand(Nhe->p.argv[Nhe->ix], 02748 " (", opstr, " ", EVRhe->p.argv[Nhe->ix], ")", NULL); 02749 } else 02750 t = rpmExpand(Nhe->p.argv[Nhe->ix], NULL); 02751 te = stpcpy(te, t); 02752 te++; 02753 t = _free(t); 02754 } 02755 he->p.argv[he->c] = NULL; 02756 rc = 0; 02757 02758 return rc; 02759 } 02760 02770 static int debevrTag(Header h, HE_t he, rpmTag tagN, rpmTag tagEVR, rpmTag tagF) 02771 /*@globals rpmGlobalMacroContext, h_errno, internalState @*/ 02772 /*@modifies he, rpmGlobalMacroContext, internalState @*/ 02773 { 02774 HE_t Nhe = memset(alloca(sizeof(*Nhe)), 0, sizeof(*Nhe)); 02775 HE_t EVRhe = memset(alloca(sizeof(*EVRhe)), 0, sizeof(*EVRhe)); 02776 HE_t Fhe = memset(alloca(sizeof(*Fhe)), 0, sizeof(*Fhe)); 02777 int rc = 1; 02778 int xx; 02779 02780 Nhe->tag = tagN; 02781 if (!(xx = headerGet(h, Nhe, 0))) 02782 goto exit; 02783 EVRhe->tag = tagEVR; 02784 if (!(xx = headerGet(h, EVRhe, 0))) 02785 goto exit; 02786 assert(EVRhe->c == Nhe->c); 02787 Fhe->tag = tagF; 02788 if (!(xx = headerGet(h, Fhe, 0))) 02789 goto exit; 02790 assert(Fhe->c == Nhe->c); 02791 02792 rc = debevrfmtTag(h, he, Nhe, EVRhe, Fhe); 02793 02794 exit: 02795 Nhe->p.ptr = _free(Nhe->p.ptr); 02796 EVRhe->p.ptr = _free(EVRhe->p.ptr); 02797 Fhe->p.ptr = _free(Fhe->p.ptr); 02798 return rc; 02799 } 02800 02807 static int debconflictsTag(Header h, HE_t he) 02808 /*@globals rpmGlobalMacroContext, h_errno, internalState @*/ 02809 /*@modifies he, rpmGlobalMacroContext, internalState @*/ 02810 { 02811 he->tag = tagValue("Debconflicts"); 02812 return debevrTag(h, he, 02813 RPMTAG_CONFLICTNAME, RPMTAG_CONFLICTVERSION, RPMTAG_CONFLICTFLAGS); 02814 } 02815 02816 static int debdependsTag(Header h, HE_t he) 02817 /*@globals rpmGlobalMacroContext, h_errno, internalState @*/ 02818 /*@modifies he, rpmGlobalMacroContext, internalState @*/ 02819 { 02820 he->tag = tagValue("Debdepends"); 02821 return debevrTag(h, he, 02822 RPMTAG_REQUIRENAME, RPMTAG_REQUIREVERSION, RPMTAG_REQUIREFLAGS); 02823 } 02824 02825 static int debobsoletesTag(Header h, HE_t he) 02826 /*@globals rpmGlobalMacroContext, h_errno, internalState @*/ 02827 /*@modifies he, rpmGlobalMacroContext, internalState @*/ 02828 { 02829 he->tag = tagValue("Debobsoletes"); 02830 return debevrTag(h, he, 02831 RPMTAG_OBSOLETENAME, RPMTAG_OBSOLETEVERSION, RPMTAG_OBSOLETEFLAGS); 02832 } 02833 02834 static int debprovidesTag(Header h, HE_t he) 02835 /*@globals rpmGlobalMacroContext, h_errno, internalState @*/ 02836 /*@modifies he, rpmGlobalMacroContext, internalState @*/ 02837 { 02838 he->tag = tagValue("Debprovides"); 02839 return debevrTag(h, he, 02840 RPMTAG_PROVIDENAME, RPMTAG_PROVIDEVERSION, RPMTAG_PROVIDEFLAGS); 02841 } 02842 02849 static int debmd5sumsTag(Header h, HE_t he) 02850 /*@globals rpmGlobalMacroContext, h_errno, internalState @*/ 02851 /*@modifies he, rpmGlobalMacroContext, internalState @*/ 02852 { 02853 HE_t Nhe = memset(alloca(sizeof(*Nhe)), 0, sizeof(*Nhe)); 02854 HE_t Dhe = memset(alloca(sizeof(*Dhe)), 0, sizeof(*Dhe)); 02855 char * t, * te; 02856 size_t nb = 0; 02857 int rc = 1; 02858 int xx; 02859 02860 Nhe->tag = RPMTAG_FILEPATHS; 02861 if (!(xx = headerGet(h, Nhe, 0))) 02862 goto exit; 02863 Dhe->tag = RPMTAG_FILEDIGESTS; 02864 if (!(xx = headerGet(h, Dhe, 0))) 02865 goto exit; 02866 assert(Dhe->c == Nhe->c); 02867 02868 he->tag = tagValue("Debmd5sums"); 02869 he->t = RPM_STRING_ARRAY_TYPE; 02870 he->c = 0; 02871 he->freeData = 1; 02872 for (Dhe->ix = 0; Dhe->ix < (int)Dhe->c; Dhe->ix++) { 02873 if (!(Dhe->p.argv[Dhe->ix] && *Dhe->p.argv[Dhe->ix])) 02874 continue; 02875 nb += sizeof(*he->p.argv); 02876 nb += strlen(Dhe->p.argv[Dhe->ix]) + sizeof(" ") + strlen(Nhe->p.argv[Dhe->ix]) - 1; 02877 he->c++; 02878 } 02879 nb += sizeof(*he->p.argv); 02880 02881 he->p.argv = xmalloc(nb); 02882 te = (char *) &he->p.argv[he->c+1]; 02883 02884 he->c = 0; 02885 for (Dhe->ix = 0; Dhe->ix < (int)Dhe->c; Dhe->ix++) { 02886 if (!(Dhe->p.argv[Dhe->ix] && *Dhe->p.argv[Dhe->ix])) 02887 continue; 02888 he->p.argv[he->c++] = te; 02889 t = rpmExpand(Dhe->p.argv[Dhe->ix], " ", Nhe->p.argv[Dhe->ix]+1, NULL); 02890 te = stpcpy(te, t); 02891 te++; 02892 t = _free(t); 02893 } 02894 he->p.argv[he->c] = NULL; 02895 rc = 0; 02896 02897 exit: 02898 Nhe->p.ptr = _free(Nhe->p.ptr); 02899 Dhe->p.ptr = _free(Dhe->p.ptr); 02900 return rc; 02901 } 02902 02903 static int filestatTag(Header h, HE_t he) 02904 /*@globals internalState @*/ 02905 /*@modifies he, internalState @*/ 02906 { 02907 rpmTagData paths = { .ptr = NULL }; 02908 /* _dev */ 02909 rpmTagData _ino = { .ptr = NULL }; 02910 rpmTagData _mode = { .ptr = NULL }; 02911 /* _nlink */ 02912 /* _uid */ 02913 /* _gid */ 02914 rpmTagData _rdev = { .ptr = NULL }; 02915 rpmTagData _size = { .ptr = NULL }; 02916 /* _blksize */ 02917 /* _blocks */ 02918 /* _atime */ 02919 rpmTagData _mtime = { .ptr = NULL }; 02920 /* st_ctime */ 02921 int rc; 02922 02923 he->tag = RPMTAG_FILEPATHS; 02924 if ((rc = _fnTag(h, he, RPMTAG_BASENAMES)) != 0 || he->c == 0) 02925 goto exit; 02926 02927 exit: 02928 paths.ptr = _free(paths.ptr); 02929 _ino.ptr = _free(_ino.ptr); 02930 _mode.ptr = _free(_mode.ptr); 02931 _rdev.ptr = _free(_rdev.ptr); 02932 _size.ptr = _free(_size.ptr); 02933 _mtime.ptr = _free(_mtime.ptr); 02934 return rc; 02935 } 02936 02937 static int wnlookupTag(Header h, rpmTag tagNVRA, ARGV_t *avp, ARGI_t *hitp, 02938 HE_t PNhe, /*@null@*/ HE_t PEVRhe, /*@null@*/ HE_t PFhe) 02939 /*@globals rpmGlobalMacroContext, h_errno, 02940 fileSystem, internalState @*/ 02941 /*@modifies *avp, *hitp, rpmGlobalMacroContext, 02942 fileSystem, internalState @*/ 02943 { 02944 HE_t NVRAhe = memset(alloca(sizeof(*NVRAhe)), 0, sizeof(*NVRAhe)); 02945 HE_t RNhe = memset(alloca(sizeof(*RNhe)), 0, sizeof(*RNhe)); 02946 HE_t REVRhe = memset(alloca(sizeof(*REVRhe)), 0, sizeof(*REVRhe)); 02947 HE_t RFhe = memset(alloca(sizeof(*RFhe)), 0, sizeof(*RFhe)); 02948 rpmdb _rpmdb = (rpmdb) headerGetRpmdb(h); 02949 const char * key = PNhe->p.argv[PNhe->ix]; 02950 size_t keylen = 0; 02951 rpmmi mi; 02952 rpmTag tagN = RPMTAG_REQUIRENAME; 02953 rpmTag tagEVR = RPMTAG_REQUIREVERSION; 02954 rpmTag tagF = RPMTAG_REQUIREFLAGS; 02955 rpmuint32_t PFlags; 02956 rpmuint32_t RFlags; 02957 EVR_t Pevr; 02958 Header oh; 02959 int rc = 0; 02960 int xx; 02961 02962 if (tagNVRA == 0) 02963 tagNVRA = RPMTAG_NVRA; 02964 02965 PFlags = (PFhe != NULL ? (PFhe->p.ui32p[PNhe->ix] & RPMSENSE_SENSEMASK) : 0); 02966 Pevr = rpmEVRnew(PFlags, 1); 02967 02968 if (PEVRhe != NULL) 02969 xx = rpmEVRparse(xstrdup(PEVRhe->p.argv[PNhe->ix]), Pevr); 02970 02971 RNhe->tag = tagN; 02972 REVRhe->tag = tagEVR; 02973 RFhe->tag = tagF; 02974 02975 mi = rpmmiInit(_rpmdb, tagN, key, keylen); 02976 if (hitp && *hitp) 02977 xx = rpmmiPrune(mi, (uint32_t *)argiData(*hitp), argiCount(*hitp), 0); 02978 while ((oh = rpmmiNext(mi)) != NULL) { 02979 if (!headerGet(oh, RNhe, 0)) 02980 goto bottom; 02981 if (PEVRhe != NULL) { 02982 if (!headerGet(oh, REVRhe, 0)) 02983 goto bottom; 02984 assert(REVRhe->c == RNhe->c); 02985 if (!headerGet(oh, RFhe, 0)) 02986 goto bottom; 02987 assert(RFhe->c == RNhe->c); 02988 } 02989 02990 for (RNhe->ix = 0; RNhe->ix < (int)RNhe->c; RNhe->ix++) { 02991 if (strcmp(PNhe->p.argv[PNhe->ix], RNhe->p.argv[RNhe->ix])) 02992 /*@innercontinue@*/ continue; 02993 if (PEVRhe == NULL) 02994 goto bingo; 02995 RFlags = RFhe->p.ui32p[RNhe->ix] & RPMSENSE_SENSEMASK; 02996 { EVR_t Revr = rpmEVRnew(RFlags, 1); 02997 if (!(PFlags && RFlags)) 02998 xx = 1; 02999 else { 03000 xx = rpmEVRparse(REVRhe->p.argv[RNhe->ix], Revr); 03001 xx = rpmEVRoverlap(Pevr, Revr); 03002 } 03003 Revr = rpmEVRfree(Revr); 03004 } 03005 if (xx) 03006 goto bingo; 03007 } 03008 goto bottom; 03009 03010 bingo: 03011 NVRAhe->tag = tagNVRA; 03012 xx = headerGet(oh, NVRAhe, 0); 03013 if (!(*avp != NULL && argvSearch(*avp, NVRAhe->p.str, NULL) != NULL)) { 03014 xx = argvAdd(avp, NVRAhe->p.str); 03015 xx = argvSort(*avp, NULL); 03016 if (hitp != NULL) 03017 xx = argiAdd(hitp, -1, rpmmiInstance(mi)); 03018 rc++; 03019 } 03020 03021 bottom: 03022 RNhe->p.ptr = _free(RNhe->p.ptr); 03023 REVRhe->p.ptr = _free(REVRhe->p.ptr); 03024 RFhe->p.ptr = _free(RFhe->p.ptr); 03025 NVRAhe->p.ptr = _free(NVRAhe->p.ptr); 03026 } 03027 mi = rpmmiFree(mi); 03028 03029 Pevr = rpmEVRfree(Pevr); 03030 03031 return rc; 03032 } 03033 03034 static int whatneedsTag(Header h, HE_t he) 03035 /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/ 03036 /*@modifies he, rpmGlobalMacroContext, fileSystem, internalState @*/ 03037 { 03038 HE_t NVRAhe = memset(alloca(sizeof(*NVRAhe)), 0, sizeof(*NVRAhe)); 03039 HE_t PNhe = memset(alloca(sizeof(*PNhe)), 0, sizeof(*PNhe)); 03040 HE_t PEVRhe = memset(alloca(sizeof(*PEVRhe)), 0, sizeof(*PEVRhe)); 03041 HE_t PFhe = memset(alloca(sizeof(*PFhe)), 0, sizeof(*PFhe)); 03042 HE_t FNhe = memset(alloca(sizeof(*FNhe)), 0, sizeof(*FNhe)); 03043 rpmTag tagNVRA = RPMTAG_NVRA; 03044 ARGV_t pkgs = NULL; 03045 ARGI_t hits = NULL; 03046 int rc = 1; 03047 03048 PNhe->tag = RPMTAG_PROVIDENAME; 03049 if (!headerGet(h, PNhe, 0)) 03050 goto exit; 03051 PEVRhe->tag = RPMTAG_PROVIDEVERSION; 03052 if (!headerGet(h, PEVRhe, 0)) 03053 goto exit; 03054 assert(PEVRhe->c == PNhe->c); 03055 PFhe->tag = RPMTAG_PROVIDEFLAGS; 03056 if (!headerGet(h, PFhe, 0)) 03057 goto exit; 03058 assert(PFhe->c == PNhe->c); 03059 03060 FNhe->tag = RPMTAG_FILEPATHS; 03061 if (!headerGet(h, FNhe, 0)) 03062 goto exit; 03063 03064 NVRAhe->tag = tagNVRA;; 03065 if (!headerGet(h, NVRAhe, 0)) 03066 goto exit; 03067 03068 (void) argvAdd(&pkgs, NVRAhe->p.str); 03069 03070 for (PNhe->ix = 0; PNhe->ix < (int)PNhe->c; PNhe->ix++) 03071 (void) wnlookupTag(h, tagNVRA, &pkgs, &hits, PNhe, PEVRhe, PFhe); 03072 for (FNhe->ix = 0; FNhe->ix < (int)FNhe->c; FNhe->ix++) 03073 (void) wnlookupTag(h, tagNVRA, &pkgs, &hits, FNhe, NULL, NULL); 03074 03075 /* Convert package NVRA array to Header string array. */ 03076 { size_t nb = 0; 03077 char * te; 03078 rpmuint32_t i; 03079 03080 he->t = RPM_STRING_ARRAY_TYPE; 03081 he->c = argvCount(pkgs); 03082 nb = 0; 03083 for (i = 0; i < he->c; i++) { 03084 nb += sizeof(*he->p.argv); 03085 nb += strlen(pkgs[i]) + 1; 03086 } 03087 nb += sizeof(*he->p.argv); 03088 03089 he->p.argv = xmalloc(nb); 03090 te = (char *) &he->p.argv[he->c+1]; 03091 03092 for (i = 0; i < he->c; i++) { 03093 he->p.argv[i] = te; 03094 te = stpcpy(te, pkgs[i]); 03095 te++; 03096 } 03097 he->p.argv[he->c] = NULL; 03098 } 03099 03100 hits = argiFree(hits); 03101 pkgs = argvFree(pkgs); 03102 rc = 0; 03103 03104 exit: 03105 NVRAhe->p.ptr = _free(NVRAhe->p.ptr); 03106 PNhe->p.ptr = _free(PNhe->p.ptr); 03107 PEVRhe->p.ptr = _free(PEVRhe->p.ptr); 03108 PFhe->p.ptr = _free(PFhe->p.ptr); 03109 FNhe->p.ptr = _free(FNhe->p.ptr); 03110 return rc; 03111 } 03112 03113 static int nwlookupTag(Header h, rpmTag tagNVRA, ARGV_t *avp, ARGI_t *hitp, 03114 HE_t RNhe, /*@null@*/ HE_t REVRhe, /*@null@*/ HE_t RFhe) 03115 /*@globals rpmGlobalMacroContext, h_errno, 03116 fileSystem, internalState @*/ 03117 /*@modifies *avp, *hitp, REVRhe, rpmGlobalMacroContext, 03118 fileSystem, internalState @*/ 03119 { 03120 HE_t NVRAhe = memset(alloca(sizeof(*NVRAhe)), 0, sizeof(*NVRAhe)); 03121 HE_t PNhe = memset(alloca(sizeof(*PNhe)), 0, sizeof(*PNhe)); 03122 HE_t PEVRhe = memset(alloca(sizeof(*PEVRhe)), 0, sizeof(*PEVRhe)); 03123 HE_t PFhe = memset(alloca(sizeof(*PFhe)), 0, sizeof(*PFhe)); 03124 rpmdb _rpmdb = (rpmdb) headerGetRpmdb(h); 03125 const char * key = RNhe->p.argv[RNhe->ix]; 03126 size_t keylen = 0; 03127 rpmmi mi; 03128 rpmTag tagN = tagN = (*RNhe->p.argv[RNhe->ix] == '/') 03129 ? RPMTAG_BASENAMES : RPMTAG_PROVIDENAME; 03130 rpmTag tagEVR = RPMTAG_PROVIDEVERSION; 03131 rpmTag tagF = RPMTAG_PROVIDEFLAGS; 03132 rpmuint32_t PFlags; 03133 rpmuint32_t RFlags; 03134 EVR_t Revr; 03135 Header oh; 03136 int rc = 0; 03137 int xx; 03138 03139 if (tagNVRA == 0) 03140 tagNVRA = RPMTAG_NVRA; 03141 03142 RFlags = (RFhe != NULL ? (RFhe->p.ui32p[RNhe->ix] & RPMSENSE_SENSEMASK) : 0); 03143 Revr = rpmEVRnew(RFlags, 1); 03144 03145 if (REVRhe != NULL) 03146 xx = rpmEVRparse(REVRhe->p.argv[RNhe->ix], Revr); 03147 03148 PNhe->tag = tagN; 03149 PEVRhe->tag = tagEVR; 03150 PFhe->tag = tagF; 03151 03152 mi = rpmmiInit(_rpmdb, tagN, key, keylen); 03153 if (hitp && *hitp) 03154 xx = rpmmiPrune(mi, (uint32_t *)argiData(*hitp), argiCount(*hitp), 0); 03155 while ((oh = rpmmiNext(mi)) != NULL) { 03156 if (!headerGet(oh, PNhe, 0)) 03157 goto bottom; 03158 if (REVRhe != NULL) { 03159 if (!headerGet(oh, PEVRhe, 0)) 03160 goto bottom; 03161 assert(PEVRhe->c == PNhe->c); 03162 if (!headerGet(oh, PFhe, 0)) 03163 goto bottom; 03164 assert(PFhe->c == PNhe->c); 03165 } 03166 03167 for (PNhe->ix = 0; PNhe->ix < (int)PNhe->c; PNhe->ix++) { 03168 if (strcmp(RNhe->p.argv[RNhe->ix], PNhe->p.argv[PNhe->ix])) 03169 /*@innercontinue@*/ continue; 03170 if (REVRhe == NULL) 03171 goto bingo; 03172 PFlags = PFhe->p.ui32p[PNhe->ix] & RPMSENSE_SENSEMASK; 03173 { EVR_t Pevr = rpmEVRnew(PFlags, 1); 03174 if (!(PFlags && RFlags)) 03175 xx = 1; 03176 else { 03177 xx = rpmEVRparse(PEVRhe->p.argv[PNhe->ix], Pevr); 03178 xx = rpmEVRoverlap(Revr, Pevr); 03179 } 03180 Pevr = rpmEVRfree(Pevr); 03181 } 03182 if (xx) 03183 goto bingo; 03184 } 03185 goto bottom; 03186 03187 bingo: 03188 NVRAhe->tag = tagNVRA; 03189 xx = headerGet(oh, NVRAhe, 0); 03190 if (!(*avp != NULL && argvSearch(*avp, NVRAhe->p.str, NULL) != NULL)) { 03191 xx = argvAdd(avp, NVRAhe->p.str); 03192 xx = argvSort(*avp, NULL); 03193 if (hitp != NULL) 03194 xx = argiAdd(hitp, -1, rpmmiInstance(mi)); 03195 rc++; 03196 } 03197 03198 bottom: 03199 PNhe->p.ptr = _free(PNhe->p.ptr); 03200 PEVRhe->p.ptr = _free(PEVRhe->p.ptr); 03201 PFhe->p.ptr = _free(PFhe->p.ptr); 03202 NVRAhe->p.ptr = _free(NVRAhe->p.ptr); 03203 } 03204 mi = rpmmiFree(mi); 03205 03206 Revr = rpmEVRfree(Revr); 03207 03208 return rc; 03209 } 03210 03211 static int needswhatTag(Header h, HE_t he) 03212 /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/ 03213 /*@modifies he, rpmGlobalMacroContext, fileSystem, internalState @*/ 03214 { 03215 HE_t NVRAhe = memset(alloca(sizeof(*NVRAhe)), 0, sizeof(*NVRAhe)); 03216 HE_t RNhe = memset(alloca(sizeof(*RNhe)), 0, sizeof(*RNhe)); 03217 HE_t REVRhe = memset(alloca(sizeof(*REVRhe)), 0, sizeof(*REVRhe)); 03218 HE_t RFhe = memset(alloca(sizeof(*RFhe)), 0, sizeof(*RFhe)); 03219 rpmTag tagNVRA = RPMTAG_NVRA; 03220 ARGV_t pkgs = NULL; 03221 ARGI_t hits = NULL; 03222 int rc = 1; 03223 03224 RNhe->tag = RPMTAG_REQUIRENAME; 03225 if (!headerGet(h, RNhe, 0)) 03226 goto exit; 03227 REVRhe->tag = RPMTAG_REQUIREVERSION; 03228 if (!headerGet(h, REVRhe, 0)) 03229 goto exit; 03230 assert(REVRhe->c == RNhe->c); 03231 RFhe->tag = RPMTAG_REQUIREFLAGS; 03232 if (!headerGet(h, RFhe, 0)) 03233 goto exit; 03234 assert(RFhe->c == RNhe->c); 03235 03236 NVRAhe->tag = tagNVRA;; 03237 if (!headerGet(h, NVRAhe, 0)) 03238 goto exit; 03239 03240 (void) argvAdd(&pkgs, NVRAhe->p.str); 03241 03242 for (RNhe->ix = 0; RNhe->ix < (int)RNhe->c; RNhe->ix++) { 03243 if (*RNhe->p.argv[RNhe->ix] == '/' || *REVRhe->p.argv[RNhe->ix] == '\0') 03244 (void) nwlookupTag(h, tagNVRA, &pkgs, &hits, RNhe, NULL, NULL); 03245 else 03246 (void) nwlookupTag(h, tagNVRA, &pkgs, &hits, RNhe, REVRhe, RFhe); 03247 } 03248 03249 /* Convert package NVRA array to Header string array. */ 03250 { size_t nb = 0; 03251 char * te; 03252 rpmuint32_t i; 03253 03254 he->t = RPM_STRING_ARRAY_TYPE; 03255 he->c = argvCount(pkgs); 03256 nb = 0; 03257 for (i = 0; i < he->c; i++) { 03258 nb += sizeof(*he->p.argv); 03259 nb += strlen(pkgs[i]) + 1; 03260 } 03261 nb += sizeof(*he->p.argv); 03262 03263 he->p.argv = xmalloc(nb); 03264 te = (char *) &he->p.argv[he->c+1]; 03265 03266 for (i = 0; i < he->c; i++) { 03267 he->p.argv[i] = te; 03268 te = stpcpy(te, pkgs[i]); 03269 te++; 03270 } 03271 he->p.argv[he->c] = NULL; 03272 } 03273 03274 hits = argiFree(hits); 03275 pkgs = argvFree(pkgs); 03276 rc = 0; 03277 03278 exit: 03279 NVRAhe->p.ptr = _free(NVRAhe->p.ptr); 03280 RNhe->p.ptr = _free(RNhe->p.ptr); 03281 REVRhe->p.ptr = _free(REVRhe->p.ptr); 03282 RFhe->p.ptr = _free(RFhe->p.ptr); 03283 return rc; 03284 } 03285 03286 static int PRCOSkip(rpmTag tag, rpmTagData N, rpmTagData EVR, rpmTagData F, 03287 rpmuint32_t i) 03288 /*@*/ 03289 { 03290 int a = -2, b = -2; 03291 03292 if (N.argv[i] == NULL || *N.argv[i] == '\0') 03293 return 1; 03294 if (tag == RPMTAG_REQUIRENAME && i > 0 03295 && !(a=strcmp(N.argv[i], N.argv[i-1])) 03296 && !(b=strcmp(EVR.argv[i], EVR.argv[i-1])) 03297 && (F.ui32p[i] & 0x4e) == ((F.ui32p[i-1] & 0x4e))) 03298 return 1; 03299 return 0; 03300 } 03301 03302 static int PRCOxmlTag(Header h, HE_t he, rpmTag EVRtag, rpmTag Ftag) 03303 /*@globals internalState @*/ 03304 /*@modifies he, internalState @*/ 03305 { 03306 rpmTag tag = he->tag; 03307 rpmTagData N = { .ptr = NULL }; 03308 rpmTagData EVR = { .ptr = NULL }; 03309 rpmTagData F = { .ptr = NULL }; 03310 size_t nb; 03311 rpmuint32_t ac; 03312 rpmuint32_t c; 03313 rpmuint32_t i; 03314 char *t; 03315 int rc = 1; /* assume failure */ 03316 int xx; 03317 int lvl = 0; 03318 spew_t spew = &_xml_spew; 03319 03320 /*@-compmempass@*/ /* use separate HE_t, not rpmTagData, containers. */ 03321 xx = headerGet(h, he, 0); 03322 if (xx == 0) goto exit; 03323 N.argv = he->p.argv; 03324 c = he->c; 03325 03326 he->tag = EVRtag; 03327 xx = headerGet(h, he, 0); 03328 if (xx == 0) goto exit; 03329 EVR.argv = he->p.argv; 03330 03331 he->tag = Ftag; 03332 xx = headerGet(h, he, 0); 03333 if (xx == 0) goto exit; 03334 F.ui32p = he->p.ui32p; 03335 03336 nb = sizeof(*he->p.argv); 03337 ac = 0; 03338 for (i = 0; i < c; i++) { 03339 /*@-nullstate@*/ /* EVR.argv might be NULL */ 03340 if (PRCOSkip(tag, N, EVR, F, i)) 03341 continue; 03342 /*@=nullstate@*/ 03343 ac++; 03344 nb += sizeof(*he->p.argv); 03345 nb += sizeof("<rpm:entry name=\"\"/>"); 03346 if (*N.argv[i] == '/') 03347 nb += spew->spew_strlen(N.argv[i], lvl); 03348 else 03349 nb += strlen(N.argv[i]); 03350 if (EVR.argv != NULL && EVR.argv[i] != NULL && *EVR.argv[i] != '\0') { 03351 nb += sizeof(" flags=\"EQ\" epoch=\"0\" ver=\"\"") - 1; 03352 nb += strlen(EVR.argv[i]); 03353 if (strchr(EVR.argv[i], ':') != NULL) 03354 nb -= 2; 03355 if (strchr(EVR.argv[i], '-') != NULL) 03356 nb += sizeof(" rel=\"\"") - 2; 03357 } 03358 #ifdef NOTNOW 03359 if (tag == RPMTAG_REQUIRENAME && (F.ui32p[i] & 0x40)) 03360 nb += sizeof(" pre=\"1\"") - 1; 03361 #endif 03362 } 03363 03364 he->t = RPM_STRING_ARRAY_TYPE; 03365 he->c = ac; 03366 he->freeData = 1; 03367 he->p.argv = xmalloc(nb + BUFSIZ); /* XXX hack: leave slop */ 03368 t = (char *) &he->p.argv[he->c + 1]; 03369 ac = 0; 03370 for (i = 0; i < c; i++) { 03371 /*@-nullstate@*/ /* EVR.argv might be NULL */ 03372 if (PRCOSkip(tag, N, EVR, F, i)) 03373 continue; 03374 /*@=nullstate@*/ 03375 he->p.argv[ac++] = t; 03376 t = stpcpy(t, "<rpm:entry"); 03377 t = stpcpy(t, " name=\""); 03378 if (*N.argv[i] == '/') { 03379 t = spew->spew_strcpy(t, N.argv[i], lvl); t += strlen(t); 03380 } else 03381 t = stpcpy(t, N.argv[i]); 03382 t = stpcpy(t, "\""); 03383 /*@-readonlytrans@*/ 03384 if (EVR.argv != NULL && EVR.argv[i] != NULL && *EVR.argv[i] != '\0') { 03385 static char *Fstr[] = { "?0","LT","GT","?3","EQ","LE","GE","?7" }; 03386 rpmuint32_t Fx = ((F.ui32p[i] >> 1) & 0x7); 03387 const char *E, *V, *R; 03388 char *f, *fe; 03389 t = stpcpy( stpcpy( stpcpy(t, " flags=\""), Fstr[Fx]), "\""); 03390 f = (char *) EVR.argv[i]; 03391 for (fe = f; *fe != '\0' && *fe >= '0' && *fe <= '9'; fe++) 03392 {}; 03393 if (*fe == ':') { *fe++ = '\0'; E = f; f = fe; } else E = NULL; 03394 V = f; 03395 for (fe = f; *fe != '\0' && *fe != '-'; fe++) 03396 {}; 03397 if (*fe == '-') { *fe++ = '\0'; R = fe; } else R = NULL; 03398 t = stpcpy( stpcpy( stpcpy(t, " epoch=\""), (E && *E ? E : "0")), "\""); 03399 t = stpcpy( stpcpy( stpcpy(t, " ver=\""), V), "\""); 03400 if (R != NULL) 03401 t = stpcpy( stpcpy( stpcpy(t, " rel=\""), R), "\""); 03402 } 03403 /*@=readonlytrans@*/ 03404 #ifdef NOTNOW 03405 if (tag == RPMTAG_REQUIRENAME && (F.ui32p[i] & 0x40)) 03406 t = stpcpy(t, " pre=\"1\""); 03407 #endif 03408 t = stpcpy(t, "/>"); 03409 *t++ = '\0'; 03410 } 03411 he->p.argv[he->c] = NULL; 03412 /*@=compmempass@*/ 03413 rc = 0; 03414 03415 exit: 03416 /*@-kepttrans@*/ /* N.argv may be kept. */ 03417 N.argv = _free(N.argv); 03418 /*@=kepttrans@*/ 03419 /*@-usereleased@*/ /* EVR.argv may be dead. */ 03420 EVR.argv = _free(EVR.argv); 03421 /*@=usereleased@*/ 03422 F.ui32p = _free(F.ui32p); 03423 return rc; 03424 } 03425 03426 static int PxmlTag(Header h, HE_t he) 03427 /*@globals internalState @*/ 03428 /*@modifies he, internalState @*/ 03429 { 03430 he->tag = RPMTAG_PROVIDENAME; 03431 return PRCOxmlTag(h, he, RPMTAG_PROVIDEVERSION, RPMTAG_PROVIDEFLAGS); 03432 } 03433 03434 static int RxmlTag(Header h, HE_t he) 03435 /*@globals internalState @*/ 03436 /*@modifies he, internalState @*/ 03437 { 03438 he->tag = RPMTAG_REQUIRENAME; 03439 return PRCOxmlTag(h, he, RPMTAG_REQUIREVERSION, RPMTAG_REQUIREFLAGS); 03440 } 03441 03442 static int CxmlTag(Header h, HE_t he) 03443 /*@globals internalState @*/ 03444 /*@modifies he, internalState @*/ 03445 { 03446 he->tag = RPMTAG_CONFLICTNAME; 03447 return PRCOxmlTag(h, he, RPMTAG_CONFLICTVERSION, RPMTAG_CONFLICTFLAGS); 03448 } 03449 03450 static int OxmlTag(Header h, HE_t he) 03451 /*@globals internalState @*/ 03452 /*@modifies he, internalState @*/ 03453 { 03454 he->tag = RPMTAG_OBSOLETENAME; 03455 return PRCOxmlTag(h, he, RPMTAG_OBSOLETEVERSION, RPMTAG_OBSOLETEFLAGS); 03456 } 03457 03466 static /*@only@*/ char * spewescapeFormat(HE_t he, /*@null@*/ const char ** av, 03467 spew_t spew, int lvl) 03468 /*@*/ 03469 { 03470 int ix = (he->ix > 0 ? he->ix : 0); 03471 char * val; 03472 03473 assert(ix == 0); 03474 if (he->t != RPM_STRING_TYPE) { 03475 val = xstrdup(_("(not a string)")); 03476 } else { 03477 const char * s = strdup_locale_convert(he->p.str, (av ? av[0] : NULL)); 03478 size_t nb; 03479 char * t; 03480 03481 if (s == NULL) { 03482 /* XXX better error msg? */ 03483 val = xstrdup(_("(not a string)")); 03484 goto exit; 03485 } 03486 03487 nb = spew->spew_strlen(s, lvl); 03488 val = t = xcalloc(1, nb + 1); 03489 t = spew->spew_strcpy(t, s, lvl); t += strlen(t); 03490 *t = '\0'; 03491 s = _free(s); 03492 } 03493 03494 exit: 03495 return val; 03496 } 03497 03498 #ifndef DYING /* XXX is :json gud enuf? there are side effects ... */ 03499 static /*@only@*/ char * jsonescapeFormat(HE_t he, /*@null@*/ const char ** av) 03500 /*@*/ 03501 { 03502 return spewescapeFormat(he, av, &_json_spew, 0); 03503 } 03504 #endif 03505 03506 static /*@only@*/ char * sqlescapeFormat(HE_t he, /*@null@*/ const char ** av) 03507 /*@*/ 03508 { 03509 return spewescapeFormat(he, av, &_sql_spew, 0); 03510 } 03511 03512 /*@-compmempass -kepttrans -nullstate -usereleased @*/ 03513 static int PRCOsqlTag(Header h, HE_t he, rpmTag EVRtag, rpmTag Ftag) 03514 /*@globals internalState @*/ 03515 /*@modifies he, internalState @*/ 03516 { 03517 rpmTag tag = he->tag; 03518 rpmTagData N = { .ptr = NULL }; 03519 rpmTagData EVR = { .ptr = NULL }; 03520 rpmTagData F = { .ptr = NULL }; 03521 char instance[64]; 03522 size_t nb; 03523 rpmuint32_t ac; 03524 rpmuint32_t c; 03525 rpmuint32_t i; 03526 char *t; 03527 int rc = 1; /* assume failure */ 03528 int xx; 03529 03530 /*@-compmempass@*/ /* use separate HE_t, not rpmTagData, containers. */ 03531 xx = headerGet(h, he, 0); 03532 if (xx == 0) goto exit; 03533 N.argv = he->p.argv; 03534 c = he->c; 03535 03536 he->tag = EVRtag; 03537 xx = headerGet(h, he, 0); 03538 if (xx == 0) goto exit; 03539 EVR.argv = he->p.argv; 03540 03541 he->tag = Ftag; 03542 xx = headerGet(h, he, 0); 03543 if (xx == 0) goto exit; 03544 F.ui32p = he->p.ui32p; 03545 03546 xx = snprintf(instance, sizeof(instance), "'%u'", (unsigned)headerGetInstance(h)); 03547 nb = sizeof(*he->p.argv); 03548 ac = 0; 03549 for (i = 0; i < c; i++) { 03550 /*@-nullstate@*/ /* EVR.argv might be NULL */ 03551 if (PRCOSkip(tag, N, EVR, F, i)) 03552 continue; 03553 /*@=nullstate@*/ 03554 ac++; 03555 nb += sizeof(*he->p.argv); 03556 nb += strlen(instance) + sizeof(", '', '', '', '', ''"); 03557 if (tag == RPMTAG_REQUIRENAME) 03558 nb += sizeof(", ''") - 1; 03559 nb += strlen(N.argv[i]); 03560 if (EVR.argv != NULL && EVR.argv[i] != NULL && *EVR.argv[i] != '\0') { 03561 nb += strlen(EVR.argv[i]); 03562 nb += sizeof("EQ0") - 1; 03563 } 03564 #ifdef NOTNOW 03565 if (tag == RPMTAG_REQUIRENAME && (F.ui32p[i] & 0x40)) 03566 nb += sizeof("1") - 1; 03567 #endif 03568 } 03569 03570 he->t = RPM_STRING_ARRAY_TYPE; 03571 he->c = ac; 03572 he->freeData = 1; 03573 he->p.argv = xmalloc(nb + BUFSIZ); /* XXX hack: leave slop */ 03574 t = (char *) &he->p.argv[he->c + 1]; 03575 ac = 0; 03576 for (i = 0; i < c; i++) { 03577 /*@-nullstate@*/ /* EVR.argv might be NULL */ 03578 if (PRCOSkip(tag, N, EVR, F, i)) 03579 continue; 03580 /*@=nullstate@*/ 03581 he->p.argv[ac++] = t; 03582 t = stpcpy(t, instance); 03583 t = stpcpy( stpcpy( stpcpy(t, ", '"), N.argv[i]), "'"); 03584 /*@-readonlytrans@*/ 03585 if (EVR.argv != NULL && EVR.argv[i] != NULL && *EVR.argv[i] != '\0') { 03586 static char *Fstr[] = { "?0","LT","GT","?3","EQ","LE","GE","?7" }; 03587 rpmuint32_t Fx = ((F.ui32p[i] >> 1) & 0x7); 03588 const char *E, *V, *R; 03589 char *f, *fe; 03590 t = stpcpy( stpcpy( stpcpy(t, ", '"), Fstr[Fx]), "'"); 03591 f = (char *) EVR.argv[i]; 03592 for (fe = f; *fe != '\0' && *fe >= '0' && *fe <= '9'; fe++) 03593 {}; 03594 if (*fe == ':') { *fe++ = '\0'; E = f; f = fe; } else E = NULL; 03595 V = f; 03596 for (fe = f; *fe != '\0' && *fe != '-'; fe++) 03597 {}; 03598 if (*fe == '-') { *fe++ = '\0'; R = fe; } else R = NULL; 03599 t = stpcpy( stpcpy( stpcpy(t, ", '"), (E && *E ? E : "0")), "'"); 03600 t = stpcpy( stpcpy( stpcpy(t, ", '"), V), "'"); 03601 t = stpcpy( stpcpy( stpcpy(t, ", '"), (R ? R : "")), "'"); 03602 } else 03603 t = stpcpy(t, ", '', '', '', ''"); 03604 /*@=readonlytrans@*/ 03605 #ifdef NOTNOW 03606 if (tag == RPMTAG_REQUIRENAME) 03607 t = stpcpy(stpcpy(stpcpy(t, ", '"),(F.ui32p[i] & 0x40) ? "1" : "0"), "'"); 03608 #endif 03609 *t++ = '\0'; 03610 } 03611 he->p.argv[he->c] = NULL; 03612 /*@=compmempass@*/ 03613 rc = 0; 03614 03615 exit: 03616 /*@-kepttrans@*/ /* N.argv may be kept. */ 03617 N.argv = _free(N.argv); 03618 /*@=kepttrans@*/ 03619 /*@-usereleased@*/ /* EVR.argv may be dead. */ 03620 EVR.argv = _free(EVR.argv); 03621 /*@=usereleased@*/ 03622 F.ui32p = _free(F.ui32p); 03623 return rc; 03624 } 03625 03626 static int PsqlTag(Header h, HE_t he) 03627 /*@globals internalState @*/ 03628 /*@modifies he, internalState @*/ 03629 { 03630 he->tag = RPMTAG_PROVIDENAME; 03631 return PRCOsqlTag(h, he, RPMTAG_PROVIDEVERSION, RPMTAG_PROVIDEFLAGS); 03632 } 03633 03634 static int RsqlTag(Header h, HE_t he) 03635 /*@globals internalState @*/ 03636 /*@modifies he, internalState @*/ 03637 { 03638 he->tag = RPMTAG_REQUIRENAME; 03639 return PRCOsqlTag(h, he, RPMTAG_REQUIREVERSION, RPMTAG_REQUIREFLAGS); 03640 } 03641 03642 static int CsqlTag(Header h, HE_t he) 03643 /*@globals internalState @*/ 03644 /*@modifies he, internalState @*/ 03645 { 03646 he->tag = RPMTAG_CONFLICTNAME; 03647 return PRCOsqlTag(h, he, RPMTAG_CONFLICTVERSION, RPMTAG_CONFLICTFLAGS); 03648 } 03649 03650 static int OsqlTag(Header h, HE_t he) 03651 /*@globals internalState @*/ 03652 /*@modifies he, internalState @*/ 03653 { 03654 he->tag = RPMTAG_OBSOLETENAME; 03655 return PRCOsqlTag(h, he, RPMTAG_OBSOLETEVERSION, RPMTAG_OBSOLETEFLAGS); 03656 } 03657 03658 static int PRCOyamlTag(Header h, HE_t he, rpmTag EVRtag, rpmTag Ftag) 03659 /*@globals internalState @*/ 03660 /*@modifies he, internalState @*/ 03661 { 03662 rpmTag tag = he->tag; 03663 rpmTagData N = { .ptr = NULL }; 03664 rpmTagData EVR = { .ptr = NULL }; 03665 rpmTagData F = { .ptr = NULL }; 03666 size_t nb; 03667 rpmuint32_t ac; 03668 rpmuint32_t c; 03669 rpmuint32_t i; 03670 char *t; 03671 int rc = 1; /* assume failure */ 03672 int xx; 03673 int indent = 0; 03674 spew_t spew = &_yaml_spew; 03675 03676 /*@-compmempass@*/ /* use separate HE_t, not rpmTagData, containers. */ 03677 xx = headerGet(h, he, 0); 03678 if (xx == 0) goto exit; 03679 N.argv = he->p.argv; 03680 c = he->c; 03681 03682 he->tag = EVRtag; 03683 xx = headerGet(h, he, 0); 03684 if (xx == 0) goto exit; 03685 EVR.argv = he->p.argv; 03686 03687 he->tag = Ftag; 03688 xx = headerGet(h, he, 0); 03689 if (xx == 0) goto exit; 03690 F.ui32p = he->p.ui32p; 03691 03692 nb = sizeof(*he->p.argv); 03693 ac = 0; 03694 for (i = 0; i < c; i++) { 03695 /*@-nullstate@*/ /* EVR.argv might be NULL */ 03696 if (PRCOSkip(tag, N, EVR, F, i)) 03697 continue; 03698 /*@=nullstate@*/ 03699 ac++; 03700 nb += sizeof(*he->p.argv); 03701 nb += sizeof("- "); 03702 if (*N.argv[i] == '/') 03703 nb += spew->spew_strlen(N.argv[i], indent); 03704 else 03705 nb += strlen(N.argv[i]); 03706 if (EVR.argv != NULL && EVR.argv[i] != NULL && *EVR.argv[i] != '\0') { 03707 nb += sizeof(" >= ") - 1; 03708 nb += strlen(EVR.argv[i]); 03709 } 03710 } 03711 03712 he->t = RPM_STRING_ARRAY_TYPE; 03713 he->c = ac; 03714 he->freeData = 1; 03715 he->p.argv = xmalloc(nb + BUFSIZ); /* XXX hack: leave slop */ 03716 t = (char *) &he->p.argv[he->c + 1]; 03717 ac = 0; 03718 for (i = 0; i < c; i++) { 03719 /*@-nullstate@*/ /* EVR.argv might be NULL */ 03720 if (PRCOSkip(tag, N, EVR, F, i)) 03721 continue; 03722 /*@=nullstate@*/ 03723 he->p.argv[ac++] = t; 03724 t = stpcpy(t, "- "); 03725 if (*N.argv[i] == '/') { 03726 t = spew->spew_strcpy(t, N.argv[i], indent); t += strlen(t); 03727 } else 03728 t = stpcpy(t, N.argv[i]); 03729 /*@-readonlytrans@*/ 03730 if (EVR.argv != NULL && EVR.argv[i] != NULL && *EVR.argv[i] != '\0') { 03731 static char *Fstr[] = { "?0","<",">","?3","=","<=",">=","?7" }; 03732 rpmuint32_t Fx = ((F.ui32p[i] >> 1) & 0x7); 03733 t = stpcpy( stpcpy( stpcpy(t, " "), Fstr[Fx]), " "); 03734 t = stpcpy(t, EVR.argv[i]); 03735 } 03736 /*@=readonlytrans@*/ 03737 *t++ = '\0'; 03738 } 03739 he->p.argv[he->c] = NULL; 03740 /*@=compmempass@*/ 03741 rc = 0; 03742 03743 exit: 03744 /*@-kepttrans@*/ /* N.argv may be kept. */ 03745 N.argv = _free(N.argv); 03746 /*@=kepttrans@*/ 03747 /*@-usereleased@*/ /* EVR.argv may be dead. */ 03748 EVR.argv = _free(EVR.argv); 03749 /*@=usereleased@*/ 03750 F.ui32p = _free(F.ui32p); 03751 return rc; 03752 } 03753 03754 static int PyamlTag(Header h, HE_t he) 03755 /*@globals internalState @*/ 03756 /*@modifies he, internalState @*/ 03757 { 03758 int rc; 03759 he->tag = RPMTAG_PROVIDENAME; 03760 rc = PRCOyamlTag(h, he, RPMTAG_PROVIDEVERSION, RPMTAG_PROVIDEFLAGS); 03761 he->tag = RPMTAG_PROVIDEYAMLENTRY; 03762 return rc; 03763 } 03764 03765 static int RyamlTag(Header h, HE_t he) 03766 /*@globals internalState @*/ 03767 /*@modifies he, internalState @*/ 03768 { 03769 int rc; 03770 he->tag = RPMTAG_REQUIRENAME; 03771 rc = PRCOyamlTag(h, he, RPMTAG_REQUIREVERSION, RPMTAG_REQUIREFLAGS); 03772 he->tag = RPMTAG_REQUIREYAMLENTRY; 03773 return rc; 03774 } 03775 03776 static int CyamlTag(Header h, HE_t he) 03777 /*@globals internalState @*/ 03778 /*@modifies he, internalState @*/ 03779 { 03780 int rc; 03781 he->tag = RPMTAG_CONFLICTNAME; 03782 rc = PRCOyamlTag(h, he, RPMTAG_CONFLICTVERSION, RPMTAG_CONFLICTFLAGS); 03783 he->tag = RPMTAG_CONFLICTYAMLENTRY; 03784 return rc; 03785 } 03786 03787 static int OyamlTag(Header h, HE_t he) 03788 /*@globals internalState @*/ 03789 /*@modifies he, internalState @*/ 03790 { 03791 int rc; 03792 he->tag = RPMTAG_OBSOLETENAME; 03793 rc = PRCOyamlTag(h, he, RPMTAG_OBSOLETEVERSION, RPMTAG_OBSOLETEFLAGS); 03794 he->tag = RPMTAG_OBSOLETEYAMLENTRY; 03795 return rc; 03796 } 03797 03798 static int FDGSkip(rpmTagData DN, rpmTagData BN, rpmTagData DI, rpmuint32_t i) 03799 /*@*/ 03800 { 03801 const char * dn = DN.argv[DI.ui32p[i]]; 03802 size_t dnlen = strlen(dn); 03803 03804 assert(dn != NULL); 03805 if (strstr(dn, "bin/") != NULL) 03806 return 1; 03807 if (dnlen >= sizeof("/etc/")-1 && !strncmp(dn, "/etc/", dnlen)) 03808 return 1; 03809 if (!strcmp(dn, "/usr/lib/") && !strcmp(BN.argv[i], "sendmail")) 03810 return 1; 03811 return 2; 03812 } 03813 03814 static int FDGxmlTag(Header h, HE_t he, int lvl) 03815 /*@globals internalState @*/ 03816 /*@modifies he, internalState @*/ 03817 { 03818 rpmTagData BN = { .ptr = NULL }; 03819 rpmTagData DN = { .ptr = NULL }; 03820 rpmTagData DI = { .ptr = NULL }; 03821 rpmTagData FMODES = { .ptr = NULL }; 03822 rpmTagData FFLAGS = { .ptr = NULL }; 03823 size_t nb; 03824 rpmuint32_t ac; 03825 rpmuint32_t c; 03826 rpmuint32_t i; 03827 char *t; 03828 int rc = 1; /* assume failure */ 03829 int xx; 03830 spew_t spew = &_xml_spew; 03831 03832 /*@-compmempass@*/ /* use separate HE_t, not rpmTagData, containers. */ 03833 he->tag = RPMTAG_BASENAMES; 03834 xx = headerGet(h, he, 0); 03835 if (xx == 0) goto exit; 03836 BN.argv = he->p.argv; 03837 c = he->c; 03838 03839 he->tag = RPMTAG_DIRNAMES; 03840 xx = headerGet(h, he, 0); 03841 if (xx == 0) goto exit; 03842 DN.argv = he->p.argv; 03843 03844 he->tag = RPMTAG_DIRINDEXES; 03845 xx = headerGet(h, he, 0); 03846 if (xx == 0) goto exit; 03847 DI.ui32p = he->p.ui32p; 03848 03849 he->tag = RPMTAG_FILEMODES; 03850 xx = headerGet(h, he, 0); 03851 if (xx == 0) goto exit; 03852 FMODES.ui16p = he->p.ui16p; 03853 03854 he->tag = RPMTAG_FILEFLAGS; 03855 xx = headerGet(h, he, 0); 03856 if (xx == 0) goto exit; 03857 FFLAGS.ui32p = he->p.ui32p; 03858 03859 nb = sizeof(*he->p.argv); 03860 ac = 0; 03861 for (i = 0; i < c; i++) { 03862 if (lvl > 0 && FDGSkip(DN, BN, DI, i) != lvl) 03863 continue; 03864 ac++; 03865 nb += sizeof(*he->p.argv); 03866 nb += sizeof("<file></file>"); 03867 nb += spew->spew_strlen(DN.argv[DI.ui32p[i]], lvl); 03868 nb += spew->spew_strlen(BN.argv[i], lvl); 03869 if (FFLAGS.ui32p[i] & 0x40) /* XXX RPMFILE_GHOST */ 03870 nb += sizeof(" type=\"ghost\"") - 1; 03871 else if (S_ISDIR(FMODES.ui16p[i])) { 03872 nb += sizeof(" type=\"dir\"") - 1; 03873 #ifdef NOTYET 03874 nb += sizeof("/") - 1; 03875 #endif 03876 } 03877 } 03878 03879 he->t = RPM_STRING_ARRAY_TYPE; 03880 he->c = ac; 03881 he->freeData = 1; 03882 he->p.argv = xmalloc(nb); 03883 t = (char *) &he->p.argv[he->c + 1]; 03884 ac = 0; 03885 /* FIXME: Files, then dirs, finally ghosts breaks sort order. */ 03886 for (i = 0; i < c; i++) { 03887 if (lvl > 0 && FDGSkip(DN, BN, DI, i) != lvl) 03888 continue; 03889 if (FFLAGS.ui32p[i] & 0x40) /* XXX RPMFILE_GHOST */ 03890 continue; 03891 if (S_ISDIR(FMODES.ui16p[i])) 03892 continue; 03893 he->p.argv[ac++] = t; 03894 t = stpcpy(t, "<file>"); 03895 t = spew->spew_strcpy(t, DN.argv[DI.ui32p[i]], lvl); t += strlen(t); 03896 t = spew->spew_strcpy(t, BN.argv[i], lvl); t += strlen(t); 03897 t = stpcpy(t, "</file>"); 03898 *t++ = '\0'; 03899 } 03900 for (i = 0; i < c; i++) { 03901 if (lvl > 0 && FDGSkip(DN, BN, DI, i) != lvl) 03902 continue; 03903 if (FFLAGS.ui32p[i] & 0x40) /* XXX RPMFILE_GHOST */ 03904 continue; 03905 if (!S_ISDIR(FMODES.ui16p[i])) 03906 continue; 03907 he->p.argv[ac++] = t; 03908 t = stpcpy(t, "<file type=\"dir\">"); 03909 t = spew->spew_strcpy(t, DN.argv[DI.ui32p[i]], lvl); t += strlen(t); 03910 t = spew->spew_strcpy(t, BN.argv[i], lvl); t += strlen(t); 03911 #ifdef NOTYET 03912 /* Append the pesky trailing / to directories. */ 03913 if (t[-1] != '/') 03914 t = stpcpy(t, "/"); 03915 #endif 03916 t = stpcpy(t, "</file>"); 03917 *t++ = '\0'; 03918 } 03919 for (i = 0; i < c; i++) { 03920 if (lvl > 0 && FDGSkip(DN, BN, DI, i) != lvl) 03921 continue; 03922 if (!(FFLAGS.ui32p[i] & 0x40)) /* XXX RPMFILE_GHOST */ 03923 continue; 03924 he->p.argv[ac++] = t; 03925 t = stpcpy(t, "<file type=\"ghost\">"); 03926 t = spew->spew_strcpy(t, DN.argv[DI.ui32p[i]], lvl); t += strlen(t); 03927 t = spew->spew_strcpy(t, BN.argv[i], lvl); t += strlen(t); 03928 t = stpcpy(t, "</file>"); 03929 *t++ = '\0'; 03930 } 03931 03932 he->p.argv[he->c] = NULL; 03933 /*@=compmempass@*/ 03934 rc = 0; 03935 03936 exit: 03937 /*@-kepttrans@*/ /* {BN,DN,DI}.argv may be kept. */ 03938 BN.argv = _free(BN.argv); 03939 /*@-usereleased@*/ /* DN.argv may be dead. */ 03940 DN.argv = _free(DN.argv); 03941 /*@=usereleased@*/ 03942 DI.ui32p = _free(DI.ui32p); 03943 /*@=kepttrans@*/ 03944 FMODES.ui16p = _free(FMODES.ui16p); 03945 /*@-usereleased@*/ /* FFLAGS.argv may be dead. */ 03946 FFLAGS.ui32p = _free(FFLAGS.ui32p); 03947 /*@=usereleased@*/ 03948 return rc; 03949 } 03950 03951 static int F1xmlTag(Header h, HE_t he) 03952 /*@globals internalState @*/ 03953 /*@modifies he, internalState @*/ 03954 { 03955 he->tag = RPMTAG_BASENAMES; 03956 return FDGxmlTag(h, he, 1); 03957 } 03958 03959 static int F2xmlTag(Header h, HE_t he) 03960 /*@globals internalState @*/ 03961 /*@modifies he, internalState @*/ 03962 { 03963 he->tag = RPMTAG_BASENAMES; 03964 return FDGxmlTag(h, he, 2); 03965 } 03966 03967 static int FDGsqlTag(Header h, HE_t he, int lvl) 03968 /*@globals internalState @*/ 03969 /*@modifies he, internalState @*/ 03970 { 03971 rpmTagData BN = { .ptr = NULL }; 03972 rpmTagData DN = { .ptr = NULL }; 03973 rpmTagData DI = { .ptr = NULL }; 03974 rpmTagData FMODES = { .ptr = NULL }; 03975 rpmTagData FFLAGS = { .ptr = NULL }; 03976 char instance[64]; 03977 size_t nb; 03978 rpmuint32_t ac; 03979 rpmuint32_t c; 03980 rpmuint32_t i; 03981 char *t; 03982 int rc = 1; /* assume failure */ 03983 int xx; 03984 03985 /*@-compmempass@*/ /* use separate HE_t, not rpmTagData, containers. */ 03986 he->tag = RPMTAG_BASENAMES; 03987 xx = headerGet(h, he, 0); 03988 if (xx == 0) goto exit; 03989 BN.argv = he->p.argv; 03990 c = he->c; 03991 03992 he->tag = RPMTAG_DIRNAMES; 03993 xx = headerGet(h, he, 0); 03994 if (xx == 0) goto exit; 03995 DN.argv = he->p.argv; 03996 03997 he->tag = RPMTAG_DIRINDEXES; 03998 xx = headerGet(h, he, 0); 03999 if (xx == 0) goto exit; 04000 DI.ui32p = he->p.ui32p; 04001 04002 he->tag = RPMTAG_FILEMODES; 04003 xx = headerGet(h, he, 0); 04004 if (xx == 0) goto exit; 04005 FMODES.ui16p = he->p.ui16p; 04006 04007 he->tag = RPMTAG_FILEFLAGS; 04008 xx = headerGet(h, he, 0); 04009 if (xx == 0) goto exit; 04010 FFLAGS.ui32p = he->p.ui32p; 04011 04012 xx = snprintf(instance, sizeof(instance), "'%u'", (unsigned)headerGetInstance(h)); 04013 nb = sizeof(*he->p.argv); 04014 ac = 0; 04015 for (i = 0; i < c; i++) { 04016 if (lvl > 0 && FDGSkip(DN, BN, DI, i) != lvl) 04017 continue; 04018 ac++; 04019 nb += sizeof(*he->p.argv); 04020 nb += strlen(instance) + sizeof(", '', ''"); 04021 nb += strlen(DN.argv[DI.ui32p[i]]); 04022 nb += strlen(BN.argv[i]); 04023 if (FFLAGS.ui32p[i] & 0x40) /* XXX RPMFILE_GHOST */ 04024 nb += sizeof("ghost") - 1; 04025 else if (S_ISDIR(FMODES.ui16p[i])) { 04026 nb += sizeof("dir") - 1; 04027 #ifdef NOTYET 04028 nb += sizeof("/") - 1; 04029 #endif 04030 } else 04031 nb += sizeof("file") - 1; 04032 } 04033 04034 he->t = RPM_STRING_ARRAY_TYPE; 04035 he->c = ac; 04036 he->freeData = 1; 04037 he->p.argv = xmalloc(nb); 04038 t = (char *) &he->p.argv[he->c + 1]; 04039 ac = 0; 04040 /* FIXME: Files, then dirs, finally ghosts breaks sort order. */ 04041 for (i = 0; i < c; i++) { 04042 if (lvl > 0 && FDGSkip(DN, BN, DI, i) != lvl) 04043 continue; 04044 if (FFLAGS.ui32p[i] & 0x40) /* XXX RPMFILE_GHOST */ 04045 continue; 04046 if (S_ISDIR(FMODES.ui16p[i])) 04047 continue; 04048 he->p.argv[ac++] = t; 04049 t = stpcpy( stpcpy(t, instance), ", '"); 04050 t = strcpy(t, DN.argv[DI.ui32p[i]]); t += strlen(t); 04051 t = strcpy(t, BN.argv[i]); t += strlen(t); 04052 t = stpcpy(t, "', 'file'"); 04053 *t++ = '\0'; 04054 } 04055 for (i = 0; i < c; i++) { 04056 if (lvl > 0 && FDGSkip(DN, BN, DI, i) != lvl) 04057 continue; 04058 if (FFLAGS.ui32p[i] & 0x40) /* XXX RPMFILE_GHOST */ 04059 continue; 04060 if (!S_ISDIR(FMODES.ui16p[i])) 04061 continue; 04062 he->p.argv[ac++] = t; 04063 t = stpcpy( stpcpy(t, instance), ", '"); 04064 t = strcpy(t, DN.argv[DI.ui32p[i]]); t += strlen(t); 04065 t = strcpy(t, BN.argv[i]); t += strlen(t); 04066 #ifdef NOTYET 04067 /* Append the pesky trailing / to directories. */ 04068 if (t[-1] != '/') 04069 t = stpcpy(t, "/"); 04070 #endif 04071 t = stpcpy(t, "', 'dir'"); 04072 *t++ = '\0'; 04073 } 04074 for (i = 0; i < c; i++) { 04075 if (lvl > 0 && FDGSkip(DN, BN, DI, i) != lvl) 04076 continue; 04077 if (!(FFLAGS.ui32p[i] & 0x40)) /* XXX RPMFILE_GHOST */ 04078 continue; 04079 he->p.argv[ac++] = t; 04080 t = stpcpy( stpcpy(t, instance), ", '"); 04081 t = strcpy(t, DN.argv[DI.ui32p[i]]); t += strlen(t); 04082 t = strcpy(t, BN.argv[i]); t += strlen(t); 04083 t = stpcpy(t, "', 'ghost'"); 04084 *t++ = '\0'; 04085 } 04086 04087 he->p.argv[he->c] = NULL; 04088 /*@=compmempass@*/ 04089 rc = 0; 04090 04091 exit: 04092 /*@-kepttrans@*/ /* {BN,DN,DI}.argv may be kept. */ 04093 BN.argv = _free(BN.argv); 04094 /*@-usereleased@*/ /* DN.argv may be dead. */ 04095 DN.argv = _free(DN.argv); 04096 /*@=usereleased@*/ 04097 DI.ui32p = _free(DI.ui32p); 04098 /*@=kepttrans@*/ 04099 FMODES.ui16p = _free(FMODES.ui16p); 04100 /*@-usereleased@*/ /* FFLAGS.argv may be dead. */ 04101 FFLAGS.ui32p = _free(FFLAGS.ui32p); 04102 /*@=usereleased@*/ 04103 return rc; 04104 } 04105 04106 static int F1sqlTag(Header h, HE_t he) 04107 /*@globals internalState @*/ 04108 /*@modifies he, internalState @*/ 04109 { 04110 he->tag = RPMTAG_BASENAMES; 04111 return FDGsqlTag(h, he, 1); 04112 } 04113 04114 static int F2sqlTag(Header h, HE_t he) 04115 /*@globals internalState @*/ 04116 /*@modifies he, internalState @*/ 04117 { 04118 he->tag = RPMTAG_BASENAMES; 04119 return FDGsqlTag(h, he, 2); 04120 } 04121 04122 static int FDGyamlTag(Header h, HE_t he, int lvl) 04123 /*@globals internalState @*/ 04124 /*@modifies he, internalState @*/ 04125 { 04126 rpmTagData BN = { .ptr = NULL }; 04127 rpmTagData DN = { .ptr = NULL }; 04128 rpmTagData DI = { .ptr = NULL }; 04129 rpmTagData FMODES = { .ptr = NULL }; 04130 rpmTagData FFLAGS = { .ptr = NULL }; 04131 size_t nb; 04132 rpmuint32_t ac; 04133 rpmuint32_t c; 04134 rpmuint32_t i; 04135 char *t; 04136 int rc = 1; /* assume failure */ 04137 int xx; 04138 int indent = 0; 04139 spew_t spew = &_yaml_spew; 04140 04141 /*@-compmempass@*/ /* use separate HE_t, not rpmTagData, containers. */ 04142 he->tag = RPMTAG_BASENAMES; 04143 xx = headerGet(h, he, 0); 04144 if (xx == 0) goto exit; 04145 BN.argv = he->p.argv; 04146 c = he->c; 04147 04148 he->tag = RPMTAG_DIRNAMES; 04149 xx = headerGet(h, he, 0); 04150 if (xx == 0) goto exit; 04151 DN.argv = he->p.argv; 04152 04153 he->tag = RPMTAG_DIRINDEXES; 04154 xx = headerGet(h, he, 0); 04155 if (xx == 0) goto exit; 04156 DI.ui32p = he->p.ui32p; 04157 04158 he->tag = RPMTAG_FILEMODES; 04159 xx = headerGet(h, he, 0); 04160 if (xx == 0) goto exit; 04161 FMODES.ui16p = he->p.ui16p; 04162 04163 he->tag = RPMTAG_FILEFLAGS; 04164 xx = headerGet(h, he, 0); 04165 if (xx == 0) goto exit; 04166 FFLAGS.ui32p = he->p.ui32p; 04167 04168 nb = sizeof(*he->p.argv); 04169 ac = 0; 04170 for (i = 0; i < c; i++) { 04171 if (lvl > 0 && FDGSkip(DN, BN, DI, i) != lvl) 04172 continue; 04173 ac++; 04174 nb += sizeof(*he->p.argv); 04175 nb += sizeof("- "); 04176 nb += spew->spew_strlen(DN.argv[DI.ui32p[i]], indent); 04177 nb += spew->spew_strlen(BN.argv[i], indent); 04178 if (FFLAGS.ui32p[i] & 0x40) /* XXX RPMFILE_GHOST */ 04179 nb += sizeof("") - 1; 04180 else if (S_ISDIR(FMODES.ui16p[i])) 04181 nb += sizeof("/") - 1; 04182 } 04183 04184 he->t = RPM_STRING_ARRAY_TYPE; 04185 he->c = ac; 04186 he->freeData = 1; 04187 he->p.argv = xmalloc(nb); 04188 t = (char *) &he->p.argv[he->c + 1]; 04189 ac = 0; 04190 /* FIXME: Files, then dirs, finally ghosts breaks sort order. */ 04191 for (i = 0; i < c; i++) { 04192 if (lvl > 0 && FDGSkip(DN, BN, DI, i) != lvl) 04193 continue; 04194 if (FFLAGS.ui32p[i] & 0x40) /* XXX RPMFILE_GHOST */ 04195 continue; 04196 if (S_ISDIR(FMODES.ui16p[i])) 04197 continue; 04198 he->p.argv[ac++] = t; 04199 t = stpcpy(t, "- "); 04200 t = spew->spew_strcpy(t, DN.argv[DI.ui32p[i]], indent); t += strlen(t); 04201 t = spew->spew_strcpy(t, BN.argv[i], indent); t += strlen(t); 04202 t = stpcpy(t, ""); 04203 *t++ = '\0'; 04204 } 04205 for (i = 0; i < c; i++) { 04206 if (lvl > 0 && FDGSkip(DN, BN, DI, i) != lvl) 04207 continue; 04208 if (FFLAGS.ui32p[i] & 0x40) /* XXX RPMFILE_GHOST */ 04209 continue; 04210 if (!S_ISDIR(FMODES.ui16p[i])) 04211 continue; 04212 he->p.argv[ac++] = t; 04213 t = stpcpy(t, "- "); 04214 t = spew->spew_strcpy(t, DN.argv[DI.ui32p[i]], indent); t += strlen(t); 04215 t = spew->spew_strcpy(t, BN.argv[i], indent); t += strlen(t); 04216 /* Append the pesky trailing / to directories. */ 04217 if (t[-1] != '/') 04218 t = stpcpy(t, "/"); 04219 *t++ = '\0'; 04220 } 04221 for (i = 0; i < c; i++) { 04222 if (lvl > 0 && FDGSkip(DN, BN, DI, i) != lvl) 04223 continue; 04224 if (!(FFLAGS.ui32p[i] & 0x40)) /* XXX RPMFILE_GHOST */ 04225 continue; 04226 he->p.argv[ac++] = t; 04227 t = stpcpy(t, "- "); 04228 t = spew->spew_strcpy(t, DN.argv[DI.ui32p[i]], indent); t += strlen(t); 04229 t = spew->spew_strcpy(t, BN.argv[i], indent); t += strlen(t); 04230 *t++ = '\0'; 04231 } 04232 04233 he->p.argv[he->c] = NULL; 04234 /*@=compmempass@*/ 04235 rc = 0; 04236 04237 exit: 04238 /*@-kepttrans@*/ /* {BN,DN,DI}.argv may be kept. */ 04239 BN.argv = _free(BN.argv); 04240 /*@-usereleased@*/ /* DN.argv may be dead. */ 04241 DN.argv = _free(DN.argv); 04242 /*@=usereleased@*/ 04243 DI.ui32p = _free(DI.ui32p); 04244 /*@=kepttrans@*/ 04245 FMODES.ui16p = _free(FMODES.ui16p); 04246 /*@-usereleased@*/ /* FFLAGS.argv may be dead. */ 04247 FFLAGS.ui32p = _free(FFLAGS.ui32p); 04248 /*@=usereleased@*/ 04249 return rc; 04250 } 04251 04252 static int F1yamlTag(Header h, HE_t he) 04253 /*@globals internalState @*/ 04254 /*@modifies he, internalState @*/ 04255 { 04256 he->tag = RPMTAG_BASENAMES; 04257 return FDGyamlTag(h, he, 1); 04258 } 04259 04260 static int F2yamlTag(Header h, HE_t he) 04261 /*@globals internalState @*/ 04262 /*@modifies he, internalState @*/ 04263 { 04264 he->tag = RPMTAG_BASENAMES; 04265 return FDGyamlTag(h, he, 2); 04266 } 04267 04274 static /*@only@*/ char * bncdataFormat(HE_t he, /*@null@*/ const char ** av) 04275 /*@*/ 04276 { 04277 char * val; 04278 04279 if (he->t != RPM_STRING_TYPE) { 04280 val = xstrdup(_("(not a string)")); 04281 } else { 04282 const char * bn; 04283 const char * s; 04284 size_t nb; 04285 char * t; 04286 int lvl = 0; 04287 spew_t spew = &_xml_spew; 04288 04289 assert(he->p.str != NULL); 04290 /* Get rightmost '/' in string (i.e. basename(3) behavior). */ 04291 if ((bn = strrchr(he->p.str, '/')) != NULL) 04292 bn++; 04293 else 04294 bn = he->p.str; 04295 04296 /* Convert to utf8, escape for XML CDATA. */ 04297 s = strdup_locale_convert(bn, (av ? av[0] : NULL)); 04298 if (s == NULL) { 04299 /* XXX better error msg? */ 04300 val = xstrdup(_("(not a string)")); 04301 goto exit; 04302 } 04303 04304 nb = spew->spew_strlen(s, lvl); 04305 val = t = xcalloc(1, nb + 1); 04306 t = spew->spew_strcpy(t, s, lvl); t += strlen(t); 04307 *t = '\0'; 04308 s = _free(s); 04309 } 04310 04311 exit: 04312 return val; 04313 } 04314 04315 typedef struct key_s { 04316 /*@observer@*/ 04317 const char *name; /* key name */ 04318 rpmuint32_t value; 04319 } KEY; 04320 04321 /*@unchecked@*/ /*@observer@*/ 04322 static KEY keyDigests[] = { 04323 { "adler32", PGPHASHALGO_ADLER32 }, 04324 { "crc32", PGPHASHALGO_CRC32 }, 04325 { "crc64", PGPHASHALGO_CRC64 }, 04326 { "haval160", PGPHASHALGO_HAVAL_5_160 }, 04327 { "jlu32", PGPHASHALGO_JLU32 }, 04328 { "md2", PGPHASHALGO_MD2 }, 04329 { "md4", PGPHASHALGO_MD4 }, 04330 { "md5", PGPHASHALGO_MD5 }, 04331 { "rmd128", PGPHASHALGO_RIPEMD128 }, 04332 { "rmd160", PGPHASHALGO_RIPEMD160 }, 04333 { "rmd256", PGPHASHALGO_RIPEMD256 }, 04334 { "rmd320", PGPHASHALGO_RIPEMD320 }, 04335 { "salsa10", PGPHASHALGO_SALSA10 }, 04336 { "salsa20", PGPHASHALGO_SALSA20 }, 04337 { "sha1", PGPHASHALGO_SHA1 }, 04338 { "sha224", PGPHASHALGO_SHA224 }, 04339 { "sha256", PGPHASHALGO_SHA256 }, 04340 { "sha384", PGPHASHALGO_SHA384 }, 04341 { "sha512", PGPHASHALGO_SHA512 }, 04342 { "tiger192", PGPHASHALGO_TIGER192 }, 04343 }; 04344 /*@unchecked@*/ 04345 static size_t nkeyDigests = sizeof(keyDigests) / sizeof(keyDigests[0]); 04346 04350 enum keyStat_e { 04351 STAT_KEYS_NONE = 0, 04352 STAT_KEYS_DEV = (1U << 0), 04353 STAT_KEYS_INO = (1U << 1), 04354 STAT_KEYS_MODE = (1U << 2), 04355 STAT_KEYS_NLINK = (1U << 3), 04356 STAT_KEYS_UID = (1U << 4), 04357 STAT_KEYS_GID = (1U << 5), 04358 STAT_KEYS_RDEV = (1U << 6), 04359 STAT_KEYS_SIZE = (1U << 7), 04360 STAT_KEYS_BLKSIZE = (1U << 8), 04361 STAT_KEYS_BLOCKS = (1U << 9), 04362 STAT_KEYS_ATIME = (1U << 10), 04363 STAT_KEYS_CTIME = (1U << 11), 04364 STAT_KEYS_MTIME = (1U << 12), 04365 #ifdef NOTYET 04366 STAT_KEYS_FLAGS = (1U << 13), 04367 #endif 04368 STAT_KEYS_SLINK = (1U << 14), 04369 STAT_KEYS_DIGEST = (1U << 15), 04370 #ifdef NOTYET 04371 STAT_KEYS_FCONTEXT = (1U << 16), 04372 #endif 04373 STAT_KEYS_UNAME = (1U << 17), 04374 STAT_KEYS_GNAME = (1U << 18), 04375 }; 04376 04377 /*@unchecked@*/ /*@observer@*/ 04378 static KEY keyStat[] = { 04379 { "adler32", STAT_KEYS_DIGEST }, 04380 { "atime", STAT_KEYS_ATIME }, 04381 { "ctime", STAT_KEYS_CTIME }, 04382 { "blksize", STAT_KEYS_BLKSIZE }, 04383 { "blocks", STAT_KEYS_BLOCKS }, 04384 { "crc32", STAT_KEYS_DIGEST }, 04385 { "crc64", STAT_KEYS_DIGEST }, 04386 { "dev", STAT_KEYS_DEV }, 04387 #ifdef NOTYET 04388 { "digest", STAT_KEYS_DIGEST }, 04389 { "fcontext", STAT_KEYS_FCONTEXT }, 04390 { "flags", STAT_KEYS_FLAGS }, 04391 #endif 04392 { "gid", STAT_KEYS_GID }, 04393 { "gname", STAT_KEYS_GNAME }, 04394 { "haval160", STAT_KEYS_DIGEST }, 04395 { "ino", STAT_KEYS_INO }, 04396 { "jlu32", STAT_KEYS_DIGEST }, 04397 { "link", STAT_KEYS_SLINK }, 04398 { "md2", STAT_KEYS_DIGEST }, 04399 { "md4", STAT_KEYS_DIGEST }, 04400 { "md5", STAT_KEYS_DIGEST }, 04401 { "mode", STAT_KEYS_MODE }, 04402 { "mtime", STAT_KEYS_MTIME }, 04403 { "nlink", STAT_KEYS_NLINK }, 04404 { "rdev", STAT_KEYS_RDEV }, 04405 { "rmd128", STAT_KEYS_DIGEST }, 04406 { "rmd160", STAT_KEYS_DIGEST }, 04407 { "rmd256", STAT_KEYS_DIGEST }, 04408 { "rmd320", STAT_KEYS_DIGEST }, 04409 { "salsa10", STAT_KEYS_DIGEST }, 04410 { "salsa20", STAT_KEYS_DIGEST }, 04411 { "sha1", STAT_KEYS_DIGEST }, 04412 { "sha224", STAT_KEYS_DIGEST }, 04413 { "sha256", STAT_KEYS_DIGEST }, 04414 { "sha384", STAT_KEYS_DIGEST }, 04415 { "sha512", STAT_KEYS_DIGEST }, 04416 { "size", STAT_KEYS_SIZE }, 04417 { "tiger192", STAT_KEYS_DIGEST }, 04418 { "uid", STAT_KEYS_UID }, 04419 { "uname", STAT_KEYS_UNAME }, 04420 }; 04421 /*@unchecked@*/ 04422 static size_t nkeyStat = sizeof(keyStat) / sizeof(keyStat[0]); 04423 04427 enum keyUuids_e { 04428 UUID_KEYS_NONE = (0U << 0), 04429 UUID_KEYS_V1 = (1U << 0), 04430 UUID_KEYS_V3 = (3U << 0), 04431 UUID_KEYS_V4 = (4U << 0), 04432 UUID_KEYS_V5 = (5U << 0), 04433 #ifdef NOTYET 04434 UUID_KEYS_STRING = (0U << 4), 04435 UUID_KEYS_SIV = (1U << 4), 04436 UUID_KEYS_BINARY = (2U << 4), 04437 UUID_KEYS_TEXT = (3U << 4), 04438 #endif 04439 }; 04440 04441 /*@unchecked@*/ /*@observer@*/ 04442 static KEY keyUuids[] = { 04443 #ifdef NOTYET 04444 { "binary", UUID_KEYS_BINARY }, 04445 { "siv", UUID_KEYS_SIV }, 04446 { "string", UUID_KEYS_STRING }, 04447 { "text", UUID_KEYS_TEXT }, 04448 #endif 04449 { "v1", UUID_KEYS_V1 }, 04450 { "v3", UUID_KEYS_V3 }, 04451 { "v4", UUID_KEYS_V4 }, 04452 { "v5", UUID_KEYS_V5 }, 04453 }; 04454 /*@unchecked@*/ 04455 static size_t nkeyUuids = sizeof(keyUuids) / sizeof(keyUuids[0]); 04456 04459 static int 04460 keyCmp(const void * a, const void * b) 04461 /*@*/ 04462 { 04463 return strcmp(((KEY *)a)->name, ((KEY *)b)->name); 04464 } 04465 04468 static rpmuint32_t 04469 keyValue(KEY * keys, size_t nkeys, /*@null@*/ const char *name) 04470 /*@*/ 04471 { 04472 rpmuint32_t keyval = 0; 04473 04474 if (name && * name) { 04475 KEY needle = { .name = name, .value = 0 }; 04476 KEY *k = (KEY *)bsearch(&needle, keys, nkeys, sizeof(*keys), keyCmp); 04477 if (k) 04478 keyval = k->value; 04479 } 04480 return keyval; 04481 } 04482 04489 static /*@only@*/ char * digestFormat(HE_t he, /*@null@*/ const char ** av) 04490 /*@*/ 04491 { 04492 int ix = (he->ix > 0 ? he->ix : 0); 04493 char * val = NULL; 04494 size_t ns; 04495 04496 assert(ix == 0); 04497 switch(he->t) { 04498 default: 04499 val = xstrdup(_("(invalid type :digest)")); 04500 goto exit; 04501 /*@notreached@*/ break; 04502 case RPM_UINT64_TYPE: 04503 ns = sizeof(he->p.ui64p[0]); 04504 break; 04505 case RPM_STRING_TYPE: 04506 ns = strlen(he->p.str); 04507 break; 04508 case RPM_BIN_TYPE: 04509 ns = he->c; 04510 break; 04511 } 04512 04513 assert(he->p.ptr != NULL); 04514 { rpmuint32_t keyval = keyValue(keyDigests, nkeyDigests, (av ? av[0] : NULL)); 04515 rpmuint32_t algo = (keyval ? keyval : PGPHASHALGO_SHA1); 04516 DIGEST_CTX ctx = rpmDigestInit(algo, 0); 04517 int xx = rpmDigestUpdate(ctx, he->p.ptr, ns); 04518 xx = rpmDigestFinal(ctx, &val, NULL, 1); 04519 } 04520 04521 exit: 04522 return val; 04523 } 04524 04531 static /*@only@*/ char * statFormat(HE_t he, /*@null@*/ const char ** av) 04532 /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/ 04533 /*@modifies rpmGlobalMacroContext, fileSystem, internalState @*/ 04534 { 04535 /*@-nullassign@*/ 04536 /*@unchecked@*/ /*@observer@*/ 04537 static const char *avdefault[] = { "mode", NULL }; 04538 /*@=nullassign@*/ 04539 const char * fn = NULL; 04540 struct stat sb, *st = &sb; 04541 int ix = (he->ix > 0 ? he->ix : 0); 04542 char * val = NULL; 04543 int xx; 04544 int i; 04545 04546 memset(st, 0, sizeof(*st)); 04547 assert(ix == 0); 04548 switch(he->t) { 04549 case RPM_BIN_TYPE: 04550 /* XXX limit to RPMTAG_PACKAGESTAT ... */ 04551 if (he->tag == RPMTAG_PACKAGESTAT) 04552 if ((size_t)he->c == sizeof(*st)) { 04553 st = (struct stat *)he->p.ptr; 04554 break; 04555 } 04556 /*@fallthrough @*/ 04557 default: 04558 val = xstrdup(_("(invalid type :stat)")); 04559 goto exit; 04560 /*@notreached@*/ break; 04561 case RPM_STRING_TYPE: 04562 fn = he->p.str; 04563 if (Lstat(fn, st) == 0) 04564 break; 04565 /*@-ownedtrans@*/ 04566 val = rpmExpand("(Lstat:", fn, ":", strerror(errno), ")", NULL); 04567 /*@=ownedtrans@*/ 04568 goto exit; 04569 /*@notreached@*/ break; 04570 } 04571 04572 if (!(av && av[0] && *av[0])) 04573 av = avdefault; 04574 for (i = 0; av[i] != NULL; i++) { 04575 char b[BUFSIZ]; 04576 size_t nb = sizeof(b); 04577 char * nval; 04578 rpmuint32_t keyval = keyValue(keyStat, nkeyStat, av[i]); 04579 04580 nval = NULL; 04581 b[0] = '\0'; 04582 switch (keyval) { 04583 default: 04584 /*@switchbreak@*/ break; 04585 case STAT_KEYS_NONE: 04586 /*@switchbreak@*/ break; 04587 case STAT_KEYS_DEV: 04588 xx = snprintf(b, nb, "0x%lx", (unsigned long)st->st_dev); 04589 /*@switchbreak@*/ break; 04590 case STAT_KEYS_INO: 04591 xx = snprintf(b, nb, "0x%lx", (unsigned long)st->st_ino); 04592 /*@switchbreak@*/ break; 04593 case STAT_KEYS_MODE: 04594 xx = snprintf(b, nb, "%06o", (unsigned)st->st_mode); 04595 /*@switchbreak@*/ break; 04596 case STAT_KEYS_NLINK: 04597 xx = snprintf(b, nb, "0x%ld", (unsigned long)st->st_nlink); 04598 /*@switchbreak@*/ break; 04599 case STAT_KEYS_UID: 04600 xx = snprintf(b, nb, "%ld", (unsigned long)st->st_uid); 04601 /*@switchbreak@*/ break; 04602 case STAT_KEYS_GID: 04603 xx = snprintf(b, nb, "%ld", (unsigned long)st->st_gid); 04604 /*@switchbreak@*/ break; 04605 case STAT_KEYS_RDEV: 04606 xx = snprintf(b, nb, "0x%lx", (unsigned long)st->st_rdev); 04607 /*@switchbreak@*/ break; 04608 case STAT_KEYS_SIZE: 04609 xx = snprintf(b, nb, "%ld", (unsigned long)st->st_size); 04610 /*@switchbreak@*/ break; 04611 case STAT_KEYS_BLKSIZE: 04612 xx = snprintf(b, nb, "%ld", (unsigned long)st->st_blksize); 04613 /*@switchbreak@*/ break; 04614 case STAT_KEYS_BLOCKS: 04615 xx = snprintf(b, nb, "%ld", (unsigned long)st->st_blocks); 04616 /*@switchbreak@*/ break; 04617 case STAT_KEYS_ATIME: 04618 /*@i@*/ (void) stpcpy(b, ctime((time_t *)&st->st_atime)); 04619 /*@switchbreak@*/ break; 04620 case STAT_KEYS_CTIME: 04621 /*@i@*/ (void) stpcpy(b, ctime((time_t *)&st->st_ctime)); 04622 /*@switchbreak@*/ break; 04623 case STAT_KEYS_MTIME: 04624 /*@i@*/ (void) stpcpy(b, ctime((time_t *)&st->st_mtime)); 04625 /*@switchbreak@*/ break; 04626 #ifdef NOTYET 04627 case STAT_KEYS_FLAGS: 04628 /*@switchbreak@*/ break; 04629 #endif 04630 case STAT_KEYS_SLINK: 04631 if (fn != NULL && S_ISLNK(st->st_mode)) { 04632 ssize_t size = Readlink(fn, b, nb); 04633 if (size == -1) { 04634 nval = rpmExpand("(Readlink:", fn, ":", strerror(errno), ")", NULL); 04635 (void) stpcpy(b, nval); 04636 nval = _free(nval); 04637 } else 04638 b[size] = '\0'; 04639 } 04640 /*@switchbreak@*/ break; 04641 case STAT_KEYS_DIGEST: 04642 if (fn != NULL && S_ISREG(st->st_mode)) { 04643 rpmuint32_t digval = keyValue(keyDigests, nkeyDigests, av[i]); 04644 rpmuint32_t algo = (digval ? digval : PGPHASHALGO_SHA1); 04645 FD_t fd = Fopen(fn, "r%{?_rpmgio}"); 04646 if (fd == NULL || Ferror(fd)) { 04647 nval = rpmExpand("(Fopen:", fn, ":", Fstrerror(fd), ")", NULL); 04648 } else { 04649 static int asAscii = 1; 04650 char buffer[16 * 1024]; 04651 fdInitDigest(fd, algo, 0); 04652 while (Fread(buffer, sizeof(buffer[0]), sizeof(buffer), fd) > 0) 04653 {}; 04654 if (Ferror(fd)) 04655 nval = rpmExpand("(Fread:", fn, ":", Fstrerror(fd), ")", NULL); 04656 else 04657 fdFiniDigest(fd, algo, &nval, NULL, asAscii); 04658 } 04659 if (nval) { 04660 (void) stpcpy(b, nval); 04661 nval = _free(nval); 04662 } 04663 if (fd != NULL) 04664 xx = Fclose(fd); 04665 } 04666 /*@switchbreak@*/ break; 04667 case STAT_KEYS_UNAME: 04668 { const char * uname = uidToUname(st->st_uid); 04669 if (uname != NULL) 04670 (void) stpcpy(b, uname); 04671 else 04672 xx = snprintf(b, nb, "%u", (unsigned)st->st_uid); 04673 } /*@switchbreak@*/ break; 04674 case STAT_KEYS_GNAME: 04675 { const char * gname = gidToGname(st->st_gid); 04676 if (gname != NULL) 04677 (void) stpcpy(b, gname); 04678 else 04679 xx = snprintf(b, nb, "%u", (unsigned)st->st_gid); 04680 } /*@switchbreak@*/ break; 04681 } 04682 if (b[0] == '\0') 04683 continue; 04684 b[nb-1] = '\0'; 04685 04686 if (val == NULL) 04687 val = xstrdup(b); 04688 else { 04689 nval = rpmExpand(val, " | ", b, NULL); 04690 val = _free(val); 04691 val = nval; 04692 } 04693 } 04694 04695 exit: 04696 return val; 04697 } 04698 04705 static /*@only@*/ char * uuidFormat(HE_t he, /*@null@*/ const char ** av) 04706 /*@globals rpmGlobalMacroContext, h_errno, internalState @*/ 04707 /*@modifies rpmGlobalMacroContext, internalState @*/ 04708 { 04709 /*@-nullassign@*/ 04710 /*@unchecked@*/ /*@observer@*/ 04711 static const char *avdefault[] = { "v5", NULL }; 04712 /*@=nullassign@*/ 04713 rpmuint32_t version = 0; 04714 int ix = (he->ix > 0 ? he->ix : 0); 04715 char * val = NULL; 04716 int i; 04717 04718 assert(ix == 0); 04719 switch(he->t) { 04720 default: 04721 val = xstrdup(_("(invalid type :uuid)")); 04722 goto exit; 04723 /*@notreached@*/ break; 04724 case RPM_STRING_TYPE: 04725 break; 04726 } 04727 04728 if (!(av && av[0] && *av[0])) 04729 av = avdefault; 04730 04731 for (i = 0; av[i] != NULL; i++) { 04732 rpmuint32_t keyval = keyValue(keyUuids, nkeyUuids, av[i]); 04733 04734 switch (keyval) { 04735 default: 04736 /*@switchbreak@*/ break; 04737 case UUID_KEYS_V1: 04738 case UUID_KEYS_V3: 04739 case UUID_KEYS_V4: 04740 case UUID_KEYS_V5: 04741 version = keyval; 04742 /*@switchbreak@*/ break; 04743 } 04744 } 04745 04746 /* XXX use private tag container to avoid memory issues for now. */ 04747 { HE_t nhe = memset(alloca(sizeof(*nhe)), 0, sizeof(*nhe)); 04748 int xx; 04749 nhe->tag = he->tag; 04750 nhe->t = he->t; 04751 nhe->p.str = xstrdup(he->p.str); 04752 nhe->c = he->c; 04753 val = xmalloc((128/4 + 4) + 1); 04754 *val = '\0'; 04755 xx = str2uuid(nhe, NULL, version, val); 04756 nhe->p.ptr = _free(nhe->p.ptr); 04757 } 04758 04759 exit: 04760 return val; 04761 } 04762 04769 static /*@only@*/ char * rpnFormat(HE_t he, /*@null@*/ const char ** av) 04770 /*@*/ 04771 { 04772 int ac = argvCount(av) + 1; 04773 int64_t * stack = memset(alloca(ac*sizeof(*stack)), 0, (ac*sizeof(*stack))); 04774 char * end; 04775 char * val = NULL; 04776 int ix = 0; 04777 int i; 04778 04779 switch(he->t) { 04780 default: 04781 val = xstrdup(_("(invalid type :rpn)")); 04782 goto exit; 04783 /*@notreached@*/ break; 04784 case RPM_UINT64_TYPE: 04785 stack[ix] = he->p.ui64p[0]; 04786 break; 04787 case RPM_STRING_TYPE: 04788 end = NULL; 04789 /*@-unrecog@*/ /* Add annotated prototype. */ 04790 stack[ix] = strtoll(he->p.str, &end, 0); 04791 /*@=unrecog@*/ 04792 if (end && *end != '\0') { 04793 val = xstrdup(_("(invalid string :rpn)")); 04794 goto exit; 04795 } 04796 break; 04797 } 04798 04799 if (av != NULL) 04800 for (i = 0; av[i] != NULL; i++) { 04801 const char * arg = av[i]; 04802 size_t len = strlen(arg); 04803 int c = (int) *arg; 04804 04805 if (len == 0) { 04806 /* do nothing */ 04807 } else if (len > 1) { 04808 if (!(xisdigit(c) || (c == (int)'-' && xisdigit((int) arg[1])))) { 04809 val = xstrdup(_("(expected number :rpn)")); 04810 goto exit; 04811 } 04812 if (++ix == ac) { 04813 val = xstrdup(_("(stack overflow :rpn)")); 04814 goto exit; 04815 } 04816 end = NULL; 04817 stack[ix] = strtoll(arg, &end, 0); 04818 if (end && *end != '\0') { 04819 val = xstrdup(_("(invalid number :rpn)")); 04820 goto exit; 04821 } 04822 } else { 04823 if (ix-- < 1) { 04824 val = xstrdup(_("(stack underflow :rpn)")); 04825 goto exit; 04826 } 04827 switch (c) { 04828 case '&': stack[ix] &= stack[ix+1]; /*@switchbreak@*/ break; 04829 case '|': stack[ix] |= stack[ix+1]; /*@switchbreak@*/ break; 04830 case '^': stack[ix] ^= stack[ix+1]; /*@switchbreak@*/ break; 04831 case '+': stack[ix] += stack[ix+1]; /*@switchbreak@*/ break; 04832 case '-': stack[ix] -= stack[ix+1]; /*@switchbreak@*/ break; 04833 case '*': stack[ix] *= stack[ix+1]; /*@switchbreak@*/ break; 04834 case '%': 04835 case '/': 04836 if (stack[ix+1] == 0) { 04837 val = xstrdup(_("(divide by zero :rpn)")); 04838 goto exit; 04839 } 04840 if (c == (int)'%') 04841 stack[ix] %= stack[ix+1]; 04842 else 04843 stack[ix] /= stack[ix+1]; 04844 /*@switchbreak@*/ break; 04845 } 04846 } 04847 } 04848 04849 { HE_t nhe = memset(alloca(sizeof(*nhe)), 0, sizeof(*nhe)); 04850 nhe->tag = he->tag; 04851 nhe->t = RPM_UINT64_TYPE; 04852 nhe->p.ui64p = (rpmuint64_t *)&stack[ix]; 04853 nhe->c = 1; 04854 val = intFormat(nhe, NULL, NULL); 04855 } 04856 04857 exit: 04858 return val; 04859 } 04860 04867 static /*@only@*/ char * strsubFormat(HE_t he, /*@null@*/ const char ** av) 04868 /*@globals rpmGlobalMacroContext, h_errno, internalState @*/ 04869 /*@modifies rpmGlobalMacroContext, internalState @*/ 04870 { 04871 char * val = NULL; 04872 int ac = argvCount(av); 04873 miRE mires = NULL; 04874 int nmires = 0; 04875 int xx; 04876 int i; 04877 04878 switch(he->t) { 04879 default: 04880 val = xstrdup(_("(invalid type :strsub)")); 04881 goto exit; 04882 /*@notreached@*/ break; 04883 case RPM_STRING_TYPE: 04884 if (ac < 2 || (ac % 2) != 0) { 04885 val = xstrdup(_("(invalid args :strsub)")); 04886 goto exit; 04887 } 04888 break; 04889 } 04890 if (av == NULL) 04891 goto noop; 04892 04893 /* Create the mire pattern array. */ 04894 for (i = 0; av[i] != NULL; i += 2) 04895 xx = mireAppend(RPMMIRE_REGEX, 0, av[i], NULL, &mires, &nmires); 04896 04897 /* Find-and-replace first pattern that matches. */ 04898 if (mires != NULL) { 04899 int noffsets = 3; 04900 int offsets[3]; 04901 const char * s, * se; 04902 char * t, * te; 04903 char * nval; 04904 size_t slen; 04905 size_t nb; 04906 04907 for (i = 0; i < nmires; i++) { 04908 miRE mire = mires + i; 04909 04910 s = he->p.str; 04911 slen = strlen(s); 04912 if ((xx = mireRegexec(mire, s, slen)) < 0) 04913 continue; 04914 xx = mireSetEOptions(mire, offsets, noffsets); 04915 04916 /* Replace the string(s). This is just s/find/replace/g */ 04917 val = xstrdup(""); 04918 while (*s != '\0') { 04919 nb = strlen(s); 04920 if ((se = strchr(s, '\n')) == NULL) 04921 se = s + nb; 04922 else 04923 se++; 04924 04925 offsets[0] = offsets[1] = -1; 04926 xx = mireRegexec(mire, s, nb); 04927 04928 nb = 1; 04929 /* On match, copy lead-in and match string. */ 04930 if (xx == 0) 04931 nb += offsets[0] + strlen(av[2*i+1]); 04932 /* Copy up to EOL on nomatch or insertion. */ 04933 if (xx != 0 || offsets[1] == offsets[0]) 04934 nb += (se - (s + offsets[1])); 04935 04936 te = t = xmalloc(nb); 04937 04938 /* On match, copy lead-in and match string. */ 04939 if (xx == 0) { 04940 te = stpcpy( stpncpy(te, s, offsets[0]), av[2*i+1]); 04941 s += offsets[1]; 04942 } 04943 /* Copy up to EOL on nomatch or insertion. */ 04944 if (xx != 0 || offsets[1] == offsets[0]) { 04945 s += offsets[1]; 04946 te = stpncpy(te, s, (se - s)); 04947 s = se; 04948 } 04949 *te = '\0'; 04950 04951 nval = rpmExpand(val, t, NULL); 04952 val = _free(val); 04953 val = nval; 04954 t = _free(t); 04955 } 04956 } 04957 mires = mireFreeAll(mires, nmires); 04958 } 04959 04960 noop: 04961 if (val == NULL) 04962 val = xstrdup(he->p.str); 04963 exit: 04964 return val; 04965 } 04966 04967 static struct headerSprintfExtension_s _headerCompoundFormats[] = { 04968 { HEADER_EXT_TAG, "RPMTAG_BUILDTIMEUUID", 04969 { .tagFunction = buildtime_uuidTag } }, 04970 { HEADER_EXT_TAG, "RPMTAG_CHANGELOGNAME", 04971 { .tagFunction = changelognameTag } }, 04972 { HEADER_EXT_TAG, "RPMTAG_CHANGELOGTEXT", 04973 { .tagFunction = changelogtextTag } }, 04974 { HEADER_EXT_TAG, "RPMTAG_DESCRIPTION", 04975 { .tagFunction = descriptionTag } }, 04976 { HEADER_EXT_TAG, "RPMTAG_GROUP", 04977 { .tagFunction = groupTag } }, 04978 { HEADER_EXT_TAG, "RPMTAG_HDRUUID", 04979 { .tagFunction = hdruuidTag } }, 04980 { HEADER_EXT_TAG, "RPMTAG_INSTALLPREFIX", 04981 { .tagFunction = instprefixTag } }, 04982 { HEADER_EXT_TAG, "RPMTAG_INSTALLTIDUUID", 04983 { .tagFunction = installtid_uuidTag } }, 04984 { HEADER_EXT_TAG, "RPMTAG_INSTALLTIMEUUID", 04985 { .tagFunction = installtime_uuidTag } }, 04986 { HEADER_EXT_TAG, "RPMTAG_ORIGINTIDUUID", 04987 { .tagFunction = origintid_uuidTag } }, 04988 { HEADER_EXT_TAG, "RPMTAG_ORIGINTIMEUUID", 04989 { .tagFunction = origintime_uuidTag } }, 04990 { HEADER_EXT_TAG, "RPMTAG_PKGUUID", 04991 { .tagFunction = pkguuidTag } }, 04992 { HEADER_EXT_TAG, "RPMTAG_REMOVETIDUUID", 04993 { .tagFunction = removetid_uuidTag } }, 04994 { HEADER_EXT_TAG, "RPMTAG_SOURCEPKGUUID", 04995 { .tagFunction = sourcepkguuidTag } }, 04996 { HEADER_EXT_TAG, "RPMTAG_SUMMARY", 04997 { .tagFunction = summaryTag } }, 04998 { HEADER_EXT_TAG, "RPMTAG_TRIGGERCONDS", 04999 { .tagFunction = triggercondsTag } }, 05000 { HEADER_EXT_TAG, "RPMTAG_TRIGGERTYPE", 05001 { .tagFunction = triggertypeTag } }, 05002 { HEADER_EXT_TAG, "RPMTAG_DBINSTANCE", 05003 { .tagFunction = dbinstanceTag } }, 05004 { HEADER_EXT_TAG, "RPMTAG_HEADERSTARTOFF", 05005 { .tagFunction = headerstartoffTag } }, 05006 { HEADER_EXT_TAG, "RPMTAG_HEADERENDOFF", 05007 { .tagFunction = headerendoffTag } }, 05008 { HEADER_EXT_TAG, "RPMTAG_PACKAGEBASEURL", 05009 { .tagFunction = pkgbaseurlTag } }, 05010 { HEADER_EXT_TAG, "RPMTAG_PACKAGEDIGEST", 05011 { .tagFunction = pkgdigestTag } }, 05012 { HEADER_EXT_TAG, "RPMTAG_PACKAGEORIGIN", 05013 { .tagFunction = pkgoriginTag } }, 05014 { HEADER_EXT_TAG, "RPMTAG_PACKAGESIZE", 05015 { .tagFunction = pkgsizeTag } }, 05016 { HEADER_EXT_TAG, "RPMTAG_PACKAGETIME", 05017 { .tagFunction = pkgmtimeTag } }, 05018 { HEADER_EXT_TAG, "RPMTAG_NVRA", 05019 { .tagFunction = nvraTag } }, 05020 { HEADER_EXT_TAG, "RPMTAG_FILENAMES", 05021 { .tagFunction = filenamesTag } }, 05022 { HEADER_EXT_TAG, "RPMTAG_FILEPATHS", 05023 { .tagFunction = filepathsTag } }, 05024 { HEADER_EXT_TAG, "RPMTAG_ORIGPATHS", 05025 { .tagFunction = origpathsTag } }, 05026 { HEADER_EXT_TAG, "RPMTAG_FILESTAT", 05027 { .tagFunction = filestatTag } }, 05028 { HEADER_EXT_TAG, "RPMTAG_PROVIDEXMLENTRY", 05029 { .tagFunction = PxmlTag } }, 05030 { HEADER_EXT_TAG, "RPMTAG_REQUIREXMLENTRY", 05031 { .tagFunction = RxmlTag } }, 05032 { HEADER_EXT_TAG, "RPMTAG_CONFLICTXMLENTRY", 05033 { .tagFunction = CxmlTag } }, 05034 { HEADER_EXT_TAG, "RPMTAG_OBSOLETEXMLENTRY", 05035 { .tagFunction = OxmlTag } }, 05036 { HEADER_EXT_TAG, "RPMTAG_FILESXMLENTRY1", 05037 { .tagFunction = F1xmlTag } }, 05038 { HEADER_EXT_TAG, "RPMTAG_FILESXMLENTRY2", 05039 { .tagFunction = F2xmlTag } }, 05040 { HEADER_EXT_TAG, "RPMTAG_PROVIDEYAMLENTRY", 05041 { .tagFunction = PyamlTag } }, 05042 { HEADER_EXT_TAG, "RPMTAG_REQUIREYAMLENTRY", 05043 { .tagFunction = RyamlTag } }, 05044 { HEADER_EXT_TAG, "RPMTAG_CONFLICTYAMLENTRY", 05045 { .tagFunction = CyamlTag } }, 05046 { HEADER_EXT_TAG, "RPMTAG_OBSOLETEYAMLENTRY", 05047 { .tagFunction = OyamlTag } }, 05048 { HEADER_EXT_TAG, "RPMTAG_FILESYAMLENTRY1", 05049 { .tagFunction = F1yamlTag } }, 05050 { HEADER_EXT_TAG, "RPMTAG_FILESYAMLENTRY2", 05051 { .tagFunction = F2yamlTag } }, 05052 { HEADER_EXT_TAG, "RPMTAG_PROVIDESQLENTRY", 05053 { .tagFunction = PsqlTag } }, 05054 { HEADER_EXT_TAG, "RPMTAG_REQUIRESQLENTRY", 05055 { .tagFunction = RsqlTag } }, 05056 { HEADER_EXT_TAG, "RPMTAG_CONFLICTSQLENTRY", 05057 { .tagFunction = CsqlTag } }, 05058 { HEADER_EXT_TAG, "RPMTAG_OBSOLETESQLENTRY", 05059 { .tagFunction = OsqlTag } }, 05060 { HEADER_EXT_TAG, "RPMTAG_FILESSQLENTRY1", 05061 { .tagFunction = F1sqlTag } }, 05062 { HEADER_EXT_TAG, "RPMTAG_FILESSQLENTRY2", 05063 { .tagFunction = F2sqlTag } }, 05064 { HEADER_EXT_TAG, "RPMTAG_DEBCONFLICTS", 05065 { .tagFunction = debconflictsTag } }, 05066 { HEADER_EXT_TAG, "RPMTAG_DEBDEPENDS", 05067 { .tagFunction = debdependsTag } }, 05068 { HEADER_EXT_TAG, "RPMTAG_DEBMD5SUMS", 05069 { .tagFunction = debmd5sumsTag } }, 05070 { HEADER_EXT_TAG, "RPMTAG_DEBOBSOLETES", 05071 { .tagFunction = debobsoletesTag } }, 05072 { HEADER_EXT_TAG, "RPMTAG_DEBPROVIDES", 05073 { .tagFunction = debprovidesTag } }, 05074 { HEADER_EXT_TAG, "RPMTAG_NEEDSWHAT", 05075 { .tagFunction = needswhatTag } }, 05076 { HEADER_EXT_TAG, "RPMTAG_WHATNEEDS", 05077 { .tagFunction = whatneedsTag } }, 05078 { HEADER_EXT_FORMAT, "armor", 05079 { .fmtFunction = armorFormat } }, 05080 { HEADER_EXT_FORMAT, "base64", 05081 { .fmtFunction = base64Format } }, 05082 { HEADER_EXT_FORMAT, "bncdata", 05083 { .fmtFunction = bncdataFormat } }, 05084 { HEADER_EXT_FORMAT, "cdata", 05085 { .fmtFunction = cdataFormat } }, 05086 { HEADER_EXT_FORMAT, "depflags", 05087 { .fmtFunction = depflagsFormat } }, 05088 { HEADER_EXT_FORMAT, "deptype", 05089 { .fmtFunction = deptypeFormat } }, 05090 { HEADER_EXT_FORMAT, "digest", 05091 { .fmtFunction = digestFormat } }, 05092 { HEADER_EXT_FORMAT, "fflags", 05093 { .fmtFunction = fflagsFormat } }, 05094 { HEADER_EXT_FORMAT, "iconv", 05095 { .fmtFunction = iconvFormat } }, 05096 { HEADER_EXT_FORMAT, "json", 05097 { .fmtFunction = jsonFormat } }, 05098 #ifndef DYING /* XXX is :json gud enuf? there are side effects ... */ 05099 { HEADER_EXT_FORMAT, "jsonescape", 05100 { .fmtFunction = jsonescapeFormat } }, 05101 #endif 05102 { HEADER_EXT_FORMAT, "perms", 05103 { .fmtFunction = permsFormat } }, 05104 { HEADER_EXT_FORMAT, "permissions", 05105 { .fmtFunction = permsFormat } }, 05106 { HEADER_EXT_FORMAT, "pgpsig", 05107 { .fmtFunction = pgpsigFormat } }, 05108 { HEADER_EXT_FORMAT, "rpn", 05109 { .fmtFunction = rpnFormat } }, 05110 { HEADER_EXT_FORMAT, "sqlescape", 05111 { .fmtFunction = sqlescapeFormat } }, 05112 { HEADER_EXT_FORMAT, "stat", 05113 { .fmtFunction = statFormat } }, 05114 { HEADER_EXT_FORMAT, "strsub", 05115 { .fmtFunction = strsubFormat } }, 05116 { HEADER_EXT_FORMAT, "triggertype", 05117 { .fmtFunction = triggertypeFormat } }, 05118 { HEADER_EXT_FORMAT, "utf8", 05119 { .fmtFunction = iconvFormat } }, 05120 { HEADER_EXT_FORMAT, "uuid", 05121 { .fmtFunction = uuidFormat } }, 05122 { HEADER_EXT_FORMAT, "xml", 05123 { .fmtFunction = xmlFormat } }, 05124 { HEADER_EXT_FORMAT, "yaml", 05125 { .fmtFunction = yamlFormat } }, 05126 { HEADER_EXT_MORE, NULL, { (void *) &headerDefaultFormats } } 05127 } ; 05128 05129 headerSprintfExtension headerCompoundFormats = &_headerCompoundFormats[0]; 05130 05131 /*====================================================================*/ 05132 05133 void rpmDisplayQueryTags(FILE * fp, headerTagTableEntry _rpmTagTable, headerSprintfExtension _rpmHeaderFormats) 05134 { 05135 const struct headerTagTableEntry_s * t; 05136 headerSprintfExtension exts; 05137 headerSprintfExtension ext; 05138 int extNum; 05139 05140 if (fp == NULL) 05141 fp = stdout; 05142 if (_rpmTagTable == NULL) 05143 _rpmTagTable = rpmTagTable; 05144 05145 /* XXX this should use rpmHeaderFormats, but there are linkage problems. */ 05146 if (_rpmHeaderFormats == NULL) 05147 _rpmHeaderFormats = headerCompoundFormats; 05148 05149 for (t = _rpmTagTable; t && t->name; t++) { 05150 /*@observer@*/ 05151 static const char * tagtypes[] = { 05152 "", "char", "uint8", "uint16", "uint32", "uint64", 05153 "string", "octets", "argv", "i18nstring", 05154 }; 05155 rpmuint32_t ttype; 05156 05157 if (rpmIsVerbose()) { 05158 fprintf(fp, "%-20s %6d", t->name + 7, t->val); 05159 ttype = t->type & RPM_MASK_TYPE; 05160 if (ttype < RPM_MIN_TYPE || ttype > RPM_MAX_TYPE) 05161 continue; 05162 if (t->type & RPM_OPENPGP_RETURN_TYPE) 05163 fprintf(fp, " openpgp"); 05164 if (t->type & RPM_X509_RETURN_TYPE) 05165 fprintf(fp, " x509"); 05166 if (t->type & RPM_ASN1_RETURN_TYPE) 05167 fprintf(fp, " asn1"); 05168 if (t->type & RPM_OPAQUE_RETURN_TYPE) 05169 fprintf(fp, " opaque"); 05170 fprintf(fp, " %s", tagtypes[ttype]); 05171 if (t->type & RPM_ARRAY_RETURN_TYPE) 05172 fprintf(fp, " array"); 05173 if (t->type & RPM_MAPPING_RETURN_TYPE) 05174 fprintf(fp, " mapping"); 05175 if (t->type & RPM_PROBE_RETURN_TYPE) 05176 fprintf(fp, " probe"); 05177 if (t->type & RPM_TREE_RETURN_TYPE) 05178 fprintf(fp, " tree"); 05179 } else 05180 fprintf(fp, "%s", t->name + 7); 05181 fprintf(fp, "\n"); 05182 } 05183 05184 exts = _rpmHeaderFormats; 05185 for (ext = exts, extNum = 0; ext != NULL && ext->type != HEADER_EXT_LAST; 05186 ext = (ext->type == HEADER_EXT_MORE ? *ext->u.more : ext+1), extNum++) 05187 { 05188 if (ext->name == NULL || ext->type != HEADER_EXT_TAG) 05189 continue; 05190 05191 /* XXX don't print header tags twice. */ 05192 if (tagValue(ext->name) > 0) 05193 continue; 05194 fprintf(fp, "%s\n", ext->name + 7); 05195 } 05196 } 05197 05198 /*====================================================================*/ 05199 05200 #define PARSER_BEGIN 0 05201 #define PARSER_IN_ARRAY 1 05202 #define PARSER_IN_EXPR 2 05203 05206 typedef /*@abstract@*/ struct sprintfTag_s * sprintfTag; 05207 05210 struct sprintfTag_s { 05211 HE_s he; 05212 /*@null@*/ 05213 headerTagFormatFunction * fmtfuncs; 05214 /*@null@*/ 05215 headerTagTagFunction ext; 05216 int extNum; 05217 /*@only@*/ /*@relnull@*/ 05218 rpmTag * tagno; 05219 int justOne; 05220 int arrayCount; 05221 /*@kept@*/ 05222 char * format; 05223 /*@only@*/ /*@relnull@*/ 05224 ARGV_t av; 05225 /*@only@*/ /*@relnull@*/ 05226 ARGV_t params; 05227 unsigned pad; 05228 }; 05229 05232 typedef /*@abstract@*/ struct sprintfToken_s * sprintfToken; 05233 05236 struct sprintfToken_s { 05237 enum { 05238 PTOK_NONE = 0, 05239 PTOK_TAG = 1, 05240 PTOK_ARRAY = 2, 05241 PTOK_STRING = 3, 05242 PTOK_COND = 4 05243 } type; 05244 union { 05245 struct sprintfTag_s tag; 05246 struct { 05247 /*@only@*/ 05248 sprintfToken format; 05249 size_t numTokens; 05250 } array; 05251 struct { 05252 /*@dependent@*/ 05253 char * string; 05254 size_t len; 05255 } string; 05256 struct { 05257 /*@only@*/ /*@null@*/ 05258 sprintfToken ifFormat; 05259 size_t numIfTokens; 05260 /*@only@*/ /*@null@*/ 05261 sprintfToken elseFormat; 05262 size_t numElseTokens; 05263 struct sprintfTag_s tag; 05264 } cond; 05265 } u; 05266 }; 05267 05270 typedef /*@abstract@*/ struct headerSprintfArgs_s * headerSprintfArgs; 05271 05274 struct headerSprintfArgs_s { 05275 Header h; 05276 char * fmt; 05277 /*@observer@*/ /*@temp@*/ 05278 headerTagTableEntry tags; 05279 /*@observer@*/ /*@temp@*/ 05280 headerSprintfExtension exts; 05281 /*@observer@*/ /*@null@*/ 05282 const char * errmsg; 05283 HE_t ec; 05284 int nec; 05285 sprintfToken format; 05286 /*@relnull@*/ 05287 HeaderIterator hi; 05288 /*@owned@*/ 05289 char * val; 05290 size_t vallen; 05291 size_t alloced; 05292 size_t numTokens; 05293 size_t i; 05294 }; 05295 05296 /*@access sprintfTag @*/ 05297 /*@access sprintfToken @*/ 05298 /*@access headerSprintfArgs @*/ 05299 05302 static char escapedChar(const char ch) 05303 /*@*/ 05304 { 05305 /*@-modfilesys@*/ 05306 if (_hdrqf_debug) 05307 fprintf(stderr, "\t\t\\%c\n", ch); 05308 /*@=modfilesys@*/ 05309 switch (ch) { 05310 case 'a': return '\a'; 05311 case 'b': return '\b'; 05312 case 'f': return '\f'; 05313 case 'n': return '\n'; 05314 case 'r': return '\r'; 05315 case 't': return '\t'; 05316 case 'v': return '\v'; 05317 default: return ch; 05318 } 05319 } 05320 05325 /*@relnull@*/ 05326 static HE_t rpmheClean(/*@returned@*/ /*@null@*/ HE_t he) 05327 /*@modifies he @*/ 05328 { 05329 if (he) { 05330 if (he->freeData && he->p.ptr != NULL) 05331 he->p.ptr = _free(he->p.ptr); 05332 memset(he, 0, sizeof(*he)); 05333 } 05334 return he; 05335 } 05336 05343 static /*@null@*/ sprintfToken 05344 freeFormat( /*@only@*/ /*@null@*/ sprintfToken format, size_t num) 05345 /*@modifies *format @*/ 05346 { 05347 unsigned i; 05348 05349 if (format == NULL) return NULL; 05350 05351 for (i = 0; i < (unsigned) num; i++) { 05352 switch (format[i].type) { 05353 case PTOK_TAG: 05354 (void) rpmheClean(&format[i].u.tag.he); 05355 format[i].u.tag.tagno = _free(format[i].u.tag.tagno); 05356 format[i].u.tag.av = argvFree(format[i].u.tag.av); 05357 format[i].u.tag.params = argvFree(format[i].u.tag.params); 05358 /*@-type@*/ 05359 format[i].u.tag.fmtfuncs = _free(format[i].u.tag.fmtfuncs); 05360 /*@=type@*/ 05361 /*@switchbreak@*/ break; 05362 case PTOK_ARRAY: 05363 format[i].u.array.format = 05364 freeFormat(format[i].u.array.format, 05365 format[i].u.array.numTokens); 05366 /*@switchbreak@*/ break; 05367 case PTOK_COND: 05368 format[i].u.cond.ifFormat = 05369 freeFormat(format[i].u.cond.ifFormat, 05370 format[i].u.cond.numIfTokens); 05371 format[i].u.cond.elseFormat = 05372 freeFormat(format[i].u.cond.elseFormat, 05373 format[i].u.cond.numElseTokens); 05374 (void) rpmheClean(&format[i].u.cond.tag.he); 05375 format[i].u.cond.tag.tagno = _free(format[i].u.cond.tag.tagno); 05376 format[i].u.cond.tag.av = argvFree(format[i].u.cond.tag.av); 05377 format[i].u.cond.tag.params = argvFree(format[i].u.cond.tag.params); 05378 /*@-type@*/ 05379 format[i].u.cond.tag.fmtfuncs = _free(format[i].u.cond.tag.fmtfuncs); 05380 /*@=type@*/ 05381 /*@switchbreak@*/ break; 05382 case PTOK_NONE: 05383 case PTOK_STRING: 05384 default: 05385 /*@switchbreak@*/ break; 05386 } 05387 } 05388 format = _free(format); 05389 return NULL; 05390 } 05391 05397 static headerSprintfArgs hsaInit(/*@returned@*/ headerSprintfArgs hsa) 05398 /*@globals fileSystem @*/ 05399 /*@modifies hsa, fileSystem @*/ 05400 { 05401 sprintfTag tag = 05402 (hsa->format->type == PTOK_TAG 05403 ? &hsa->format->u.tag : 05404 (hsa->format->type == PTOK_ARRAY 05405 ? &hsa->format->u.array.format->u.tag : 05406 NULL)); 05407 05408 if (hsa != NULL) { 05409 hsa->i = 0; 05410 if (tag != NULL && tag->tagno != NULL && tag->tagno[0] == (rpmTag)-2) 05411 hsa->hi = headerInit(hsa->h); 05412 } 05413 /*@-nullret@*/ 05414 return hsa; 05415 /*@=nullret@*/ 05416 } 05417 05423 /*@null@*/ 05424 static sprintfToken hsaNext(/*@returned@*/ headerSprintfArgs hsa) 05425 /*@globals internalState @*/ 05426 /*@modifies hsa, internalState @*/ 05427 { 05428 sprintfToken fmt = NULL; 05429 sprintfTag tag = 05430 (hsa->format->type == PTOK_TAG 05431 ? &hsa->format->u.tag : 05432 (hsa->format->type == PTOK_ARRAY 05433 ? &hsa->format->u.array.format->u.tag : 05434 NULL)); 05435 05436 if (hsa != NULL && hsa->i < hsa->numTokens) { 05437 fmt = hsa->format + hsa->i; 05438 if (hsa->hi == NULL) { 05439 hsa->i++; 05440 } else { 05441 HE_t he = rpmheClean(&tag->he); 05442 if (!headerNext(hsa->hi, he, 0)) 05443 { 05444 tag->tagno[0] = 0; 05445 return NULL; 05446 } 05447 he->avail = 1; 05448 tag->tagno[0] = he->tag; 05449 } 05450 } 05451 05452 /*@-dependenttrans -onlytrans@*/ 05453 return fmt; 05454 /*@=dependenttrans =onlytrans@*/ 05455 } 05456 05462 static headerSprintfArgs hsaFini(/*@returned@*/ headerSprintfArgs hsa) 05463 /*@globals fileSystem @*/ 05464 /*@modifies hsa, fileSystem @*/ 05465 { 05466 if (hsa != NULL) { 05467 hsa->hi = headerFini(hsa->hi); 05468 hsa->i = 0; 05469 } 05470 /*@-nullret@*/ 05471 return hsa; 05472 /*@=nullret@*/ 05473 } 05474 05481 /*@dependent@*/ /*@exposed@*/ 05482 static char * hsaReserve(headerSprintfArgs hsa, size_t need) 05483 /*@modifies hsa */ 05484 { 05485 if ((hsa->vallen + need) >= hsa->alloced) { 05486 if (hsa->alloced <= need) 05487 hsa->alloced += need; 05488 hsa->alloced <<= 1; 05489 hsa->val = xrealloc(hsa->val, hsa->alloced+1); 05490 } 05491 return hsa->val + hsa->vallen; 05492 } 05493 05501 /*@observer@*/ /*@null@*/ 05502 static const char * myTagName(headerTagTableEntry tbl, rpmuint32_t val, 05503 /*@null@*/ rpmuint32_t *typep) 05504 /*@modifies *typep @*/ 05505 { 05506 static char name[128]; /* XXX Ick. */ 05507 const char * s; 05508 char *t; 05509 05510 /* XXX Use bsearch on the "normal" rpmTagTable lookup. */ 05511 if (tbl == NULL || tbl == rpmTagTable) { 05512 s = tagName(val); 05513 if (s != NULL && typep != NULL) 05514 *typep = tagType(val); 05515 return s; 05516 } 05517 05518 for (; tbl->name != NULL; tbl++) { 05519 if (tbl->val == val) 05520 break; 05521 } 05522 if ((s = tbl->name) == NULL) 05523 return NULL; 05524 s += sizeof("RPMTAG_") - 1; 05525 t = name; 05526 *t++ = *s++; 05527 while (*s != '\0') 05528 *t++ = (char)xtolower((int)*s++); 05529 *t = '\0'; 05530 if (typep) 05531 *typep = tbl->type; 05532 return name; 05533 } 05534 05541 static rpmuint32_t myTagValue(headerTagTableEntry tbl, const char * name) 05542 /*@*/ 05543 { 05544 rpmuint32_t val = 0; 05545 05546 /* XXX Use bsearch on the "normal" rpmTagTable lookup. */ 05547 if (tbl == NULL || tbl == rpmTagTable) 05548 val = tagValue(name); 05549 else 05550 for (; tbl->name != NULL; tbl++) { 05551 if (xstrcasecmp(tbl->name, name)) 05552 continue; 05553 val = tbl->val; 05554 break; 05555 } 05556 return val; 05557 } 05558 05566 static int findTag(headerSprintfArgs hsa, sprintfToken token, const char * name) 05567 /*@modifies token @*/ 05568 { 05569 headerSprintfExtension exts = hsa->exts; 05570 headerSprintfExtension ext; 05571 sprintfTag stag = (token->type == PTOK_COND 05572 ? &token->u.cond.tag : &token->u.tag); 05573 int extNum; 05574 rpmTag tagno = (rpmTag)-1; 05575 05576 stag->fmtfuncs = NULL; 05577 stag->ext = NULL; 05578 stag->extNum = 0; 05579 05580 if (!strcmp(name, "*")) { 05581 tagno = (rpmTag)-2; 05582 goto bingo; 05583 } 05584 05585 if (strncmp("RPMTAG_", name, sizeof("RPMTAG_")-1)) { 05586 char * t = alloca(strlen(name) + sizeof("RPMTAG_")); 05587 (void) stpcpy( stpcpy(t, "RPMTAG_"), name); 05588 name = t; 05589 } 05590 05591 /* Search extensions for specific tag override. */ 05592 for (ext = exts, extNum = 0; ext != NULL && ext->type != HEADER_EXT_LAST; 05593 ext = (ext->type == HEADER_EXT_MORE ? *ext->u.more : ext+1), extNum++) 05594 { 05595 if (ext->name == NULL || ext->type != HEADER_EXT_TAG) 05596 continue; 05597 if (!xstrcasecmp(ext->name, name)) { 05598 stag->ext = ext->u.tagFunction; 05599 stag->extNum = extNum; 05600 tagno = tagValue(name); 05601 goto bingo; 05602 } 05603 } 05604 05605 /* Search tag names. */ 05606 tagno = myTagValue(hsa->tags, name); 05607 if (tagno != 0) 05608 goto bingo; 05609 05610 return 1; 05611 05612 bingo: 05613 stag->tagno = xcalloc(1, sizeof(*stag->tagno)); 05614 stag->tagno[0] = tagno; 05615 /* Search extensions for specific format(s). */ 05616 if (stag->av != NULL) { 05617 int i; 05618 /*@-type@*/ 05619 stag->fmtfuncs = xcalloc(argvCount(stag->av) + 1, sizeof(*stag->fmtfuncs)); 05620 /*@=type@*/ 05621 for (i = 0; stag->av[i] != NULL; i++) { 05622 for (ext = exts; ext != NULL && ext->type != HEADER_EXT_LAST; 05623 ext = (ext->type == HEADER_EXT_MORE ? *ext->u.more : ext+1)) 05624 { 05625 if (ext->name == NULL || ext->type != HEADER_EXT_FORMAT) 05626 /*@innercontinue@*/ continue; 05627 if (strcmp(ext->name, stag->av[i]+1)) 05628 /*@innercontinue@*/ continue; 05629 stag->fmtfuncs[i] = ext->u.fmtFunction; 05630 /*@innerbreak@*/ break; 05631 } 05632 } 05633 } 05634 return 0; 05635 } 05636 05637 /* forward ref */ 05646 static int parseExpression(headerSprintfArgs hsa, sprintfToken token, 05647 char * str, /*@out@*/char ** endPtr) 05648 /*@modifies hsa, str, token, *endPtr @*/ 05649 /*@requires maxSet(endPtr) >= 0 @*/; 05650 05661 static int parseFormat(headerSprintfArgs hsa, char * str, 05662 /*@out@*/ sprintfToken * formatPtr, 05663 /*@out@*/ size_t * numTokensPtr, 05664 /*@null@*/ /*@out@*/ char ** endPtr, int state) 05665 /*@modifies hsa, str, *formatPtr, *numTokensPtr, *endPtr @*/ 05666 /*@requires maxSet(formatPtr) >= 0 /\ maxSet(numTokensPtr) >= 0 05667 /\ maxSet(endPtr) >= 0 @*/ 05668 { 05669 /*@observer@*/ 05670 static const char *pstates[] = { 05671 "NORMAL", "ARRAY", "EXPR", "WTF?" 05672 }; 05673 char * chptr, * start, * next, * dst; 05674 sprintfToken format; 05675 sprintfToken token; 05676 size_t numTokens; 05677 unsigned i; 05678 int done = 0; 05679 int xx; 05680 05681 /*@-modfilesys@*/ 05682 if (_hdrqf_debug) 05683 fprintf(stderr, "--> parseFormat(%p, \"%.20s...\", %p, %p, %p, %s)\n", hsa, str, formatPtr, numTokensPtr, endPtr, pstates[(state & 0x3)]); 05684 /*@=modfilesys@*/ 05685 05686 /* upper limit on number of individual formats */ 05687 numTokens = 0; 05688 if (str != NULL) 05689 for (chptr = str; *chptr != '\0'; chptr++) 05690 if (*chptr == '%' || *chptr == '[') numTokens++; 05691 numTokens = numTokens * 2 + 1; 05692 05693 format = xcalloc(numTokens, sizeof(*format)); 05694 if (endPtr) *endPtr = NULL; 05695 05696 /*@-infloops@*/ /* LCL: can't detect (start, *start) termination */ 05697 dst = start = str; 05698 numTokens = 0; 05699 token = NULL; 05700 if (start != NULL) 05701 while (*start != '\0') { 05702 switch (*start) { 05703 case '%': 05704 /* handle %% */ 05705 if (*(start + 1) == '%') { 05706 if (token == NULL || token->type != PTOK_STRING) { 05707 token = format + numTokens++; 05708 token->type = PTOK_STRING; 05709 /*@-temptrans -assignexpose@*/ 05710 dst = token->u.string.string = start; 05711 /*@=temptrans =assignexpose@*/ 05712 } 05713 start++; 05714 *dst++ = *start++; 05715 /*@switchbreak@*/ break; 05716 } 05717 05718 token = format + numTokens++; 05719 *dst++ = '\0'; 05720 start++; 05721 05722 if (*start == '|') { 05723 char * newEnd; 05724 05725 start++; 05726 if (parseExpression(hsa, token, start, &newEnd)) 05727 { 05728 format = freeFormat(format, numTokens); 05729 return 1; 05730 } 05731 start = newEnd; 05732 /*@switchbreak@*/ break; 05733 } 05734 05735 /*@-assignexpose@*/ 05736 token->u.tag.format = start; 05737 /*@=assignexpose@*/ 05738 token->u.tag.pad = 0; 05739 token->u.tag.justOne = 0; 05740 token->u.tag.arrayCount = 0; 05741 05742 chptr = start; 05743 while (*chptr && *chptr != '{' && *chptr != '%') chptr++; 05744 if (!*chptr || *chptr == '%') { 05745 hsa->errmsg = _("missing { after %"); 05746 format = freeFormat(format, numTokens); 05747 return 1; 05748 } 05749 05750 /*@-modfilesys@*/ 05751 if (_hdrqf_debug) 05752 fprintf(stderr, "\tchptr *%p = NUL\n", chptr); 05753 /*@=modfilesys@*/ 05754 *chptr++ = '\0'; 05755 05756 while (start < chptr) { 05757 if (xisdigit((int)*start)) { 05758 i = strtoul(start, &start, 10); 05759 token->u.tag.pad += i; 05760 start = chptr; 05761 /*@innerbreak@*/ break; 05762 } else { 05763 start++; 05764 } 05765 } 05766 05767 if (*start == '=') { 05768 token->u.tag.justOne = 1; 05769 start++; 05770 } else if (*start == '#') { 05771 token->u.tag.justOne = 1; 05772 token->u.tag.arrayCount = 1; 05773 start++; 05774 } 05775 05776 next = start; 05777 while (*next && *next != '}') next++; 05778 if (!*next) { 05779 hsa->errmsg = _("missing } after %{"); 05780 format = freeFormat(format, numTokens); 05781 return 1; 05782 } 05783 /*@-modfilesys@*/ 05784 if (_hdrqf_debug) 05785 fprintf(stderr, "\tnext *%p = NUL\n", next); 05786 /*@=modfilesys@*/ 05787 *next++ = '\0'; 05788 05789 #define isSEP(_c) ((_c) == ':' || (_c) == '|') 05790 chptr = start; 05791 while (!(*chptr == '\0' || isSEP(*chptr))) chptr++; 05792 /* Split ":bing|bang:boom" --qf pipeline formatters (if any) */ 05793 while (isSEP(*chptr)) { 05794 if (chptr[1] == '\0' || isSEP(chptr[1])) { 05795 hsa->errmsg = _("empty tag format"); 05796 format = freeFormat(format, numTokens); 05797 return 1; 05798 } 05799 /* Parse the formatter parameter list. */ 05800 { char * te = chptr + 1; 05801 char * t = strchr(te, '('); 05802 char c; 05803 05804 while (!(*te == '\0' || isSEP(*te))) { 05805 #ifdef NOTYET /* XXX some means of escaping is needed */ 05806 if (te[0] == '\\' && te[1] != '\0') te++; 05807 #endif 05808 te++; 05809 } 05810 c = *te; *te = '\0'; 05811 /* Parse (a,b,c) parameter list. */ 05812 if (t != NULL) { 05813 *t++ = '\0'; 05814 if (te <= t || te[-1] != ')') { 05815 hsa->errmsg = _("malformed parameter list"); 05816 format = freeFormat(format, numTokens); 05817 return 1; 05818 } 05819 te[-1] = '\0'; 05820 xx = argvAdd(&token->u.tag.params, t); 05821 } else 05822 xx = argvAdd(&token->u.tag.params, ""); 05823 /*@-modfilesys@*/ 05824 if (_hdrqf_debug) 05825 fprintf(stderr, "\tformat \"%s\" params \"%s\"\n", chptr, (t ? t : "")); 05826 /*@=modfilesys@*/ 05827 xx = argvAdd(&token->u.tag.av, chptr); 05828 *te = c; 05829 *chptr = '\0'; 05830 chptr = te; 05831 } 05832 } 05833 #undef isSEP 05834 05835 if (*start == '\0') { 05836 hsa->errmsg = _("empty tag name"); 05837 format = freeFormat(format, numTokens); 05838 return 1; 05839 } 05840 05841 i = 0; 05842 token->type = PTOK_TAG; 05843 05844 if (findTag(hsa, token, start)) { 05845 hsa->errmsg = _("unknown tag"); 05846 format = freeFormat(format, numTokens); 05847 return 1; 05848 } 05849 05850 dst = start = next; 05851 /*@-modfilesys@*/ 05852 if (_hdrqf_debug) 05853 fprintf(stderr, "\tdst = start = next %p\n", dst); 05854 /*@=modfilesys@*/ 05855 /*@switchbreak@*/ break; 05856 05857 case '[': 05858 /*@-modfilesys@*/ 05859 if (_hdrqf_debug) 05860 fprintf(stderr, "\t%s => %s *%p = NUL\n", pstates[(state & 0x3)], pstates[PARSER_IN_ARRAY], start); 05861 /*@=modfilesys@*/ 05862 *start++ = '\0'; 05863 token = format + numTokens++; 05864 05865 if (parseFormat(hsa, start, 05866 &token->u.array.format, 05867 &token->u.array.numTokens, 05868 &start, PARSER_IN_ARRAY)) 05869 { 05870 format = freeFormat(format, numTokens); 05871 return 1; 05872 } 05873 05874 if (!start) { 05875 hsa->errmsg = _("] expected at end of array"); 05876 format = freeFormat(format, numTokens); 05877 return 1; 05878 } 05879 05880 dst = start; 05881 /*@-modfilesys@*/ 05882 if (_hdrqf_debug) 05883 fprintf(stderr, "\tdst = start %p\n", dst); 05884 /*@=modfilesys@*/ 05885 05886 token->type = PTOK_ARRAY; 05887 05888 /*@switchbreak@*/ break; 05889 05890 case ']': 05891 if (state != PARSER_IN_ARRAY) { 05892 hsa->errmsg = _("unexpected ]"); 05893 format = freeFormat(format, numTokens); 05894 return 1; 05895 } 05896 *start++ = '\0'; 05897 /*@-modfilesys@*/ 05898 if (_hdrqf_debug) 05899 fprintf(stderr, "\t<= %s %p[-1] = NUL\n", pstates[(state & 0x3)], start); 05900 /*@=modfilesys@*/ 05901 if (endPtr) *endPtr = start; 05902 done = 1; 05903 /*@switchbreak@*/ break; 05904 05905 case '}': 05906 if (state != PARSER_IN_EXPR) { 05907 hsa->errmsg = _("unexpected }"); 05908 format = freeFormat(format, numTokens); 05909 return 1; 05910 } 05911 *start++ = '\0'; 05912 /*@-modfilesys@*/ 05913 if (_hdrqf_debug) 05914 fprintf(stderr, "\t<= %s %p[-1] = NUL\n", pstates[(state & 0x3)], start); 05915 /*@=modfilesys@*/ 05916 if (endPtr) *endPtr = start; 05917 done = 1; 05918 /*@switchbreak@*/ break; 05919 05920 default: 05921 if (token == NULL || token->type != PTOK_STRING) { 05922 token = format + numTokens++; 05923 token->type = PTOK_STRING; 05924 /*@-temptrans -assignexpose@*/ 05925 dst = token->u.string.string = start; 05926 /*@=temptrans =assignexpose@*/ 05927 } 05928 05929 /*@-modfilesys@*/ 05930 if (_hdrqf_debug) 05931 fprintf(stderr, "\t*%p = *%p \"%.30s\"\n", dst, start, start); 05932 /*@=modfilesys@*/ 05933 if (start[0] == '\\' && start[1] != '\0') { 05934 start++; 05935 *dst++ = escapedChar(*start); 05936 *start++ = '\0'; 05937 } else { 05938 *dst++ = *start++; 05939 } 05940 /*@switchbreak@*/ break; 05941 } 05942 if (dst < start) *dst = '\0'; 05943 if (done) 05944 break; 05945 } 05946 /*@=infloops@*/ 05947 05948 if (dst != NULL) 05949 *dst = '\0'; 05950 05951 for (i = 0; i < (unsigned) numTokens; i++) { 05952 token = format + i; 05953 switch(token->type) { 05954 default: 05955 /*@switchbreak@*/ break; 05956 case PTOK_STRING: 05957 token->u.string.len = strlen(token->u.string.string); 05958 /*@switchbreak@*/ break; 05959 } 05960 } 05961 05962 if (numTokensPtr != NULL) 05963 *numTokensPtr = numTokens; 05964 if (formatPtr != NULL) 05965 *formatPtr = format; 05966 05967 return 0; 05968 } 05969 05970 static int parseExpression(headerSprintfArgs hsa, sprintfToken token, 05971 char * str, /*@out@*/ char ** endPtr) 05972 { 05973 char * chptr; 05974 char * end; 05975 05976 /*@-modfilesys@*/ 05977 if (_hdrqf_debug) 05978 fprintf(stderr, "--> parseExpression(%p, %p, \"%.20s...\", %p)\n", hsa, token, str, endPtr); 05979 /*@=modfilesys@*/ 05980 05981 hsa->errmsg = NULL; 05982 chptr = str; 05983 while (*chptr && *chptr != '?') chptr++; 05984 05985 if (*chptr != '?') { 05986 hsa->errmsg = _("? expected in expression"); 05987 return 1; 05988 } 05989 05990 *chptr++ = '\0'; 05991 05992 if (*chptr != '{') { 05993 hsa->errmsg = _("{ expected after ? in expression"); 05994 return 1; 05995 } 05996 05997 chptr++; 05998 05999 if (parseFormat(hsa, chptr, &token->u.cond.ifFormat, 06000 &token->u.cond.numIfTokens, &end, PARSER_IN_EXPR)) 06001 return 1; 06002 06003 /* XXX fix segfault on "rpm -q rpm --qf='%|NAME?{%}:{NAME}|\n'"*/ 06004 if (!(end && *end)) { 06005 hsa->errmsg = _("} expected in expression"); 06006 token->u.cond.ifFormat = 06007 freeFormat(token->u.cond.ifFormat, token->u.cond.numIfTokens); 06008 return 1; 06009 } 06010 06011 chptr = end; 06012 if (*chptr != ':' && *chptr != '|') { 06013 hsa->errmsg = _(": expected following ? subexpression"); 06014 token->u.cond.ifFormat = 06015 freeFormat(token->u.cond.ifFormat, token->u.cond.numIfTokens); 06016 return 1; 06017 } 06018 06019 if (*chptr == '|') { 06020 if (parseFormat(hsa, NULL, &token->u.cond.elseFormat, 06021 &token->u.cond.numElseTokens, &end, PARSER_IN_EXPR)) 06022 { 06023 token->u.cond.ifFormat = 06024 freeFormat(token->u.cond.ifFormat, token->u.cond.numIfTokens); 06025 return 1; 06026 } 06027 } else { 06028 chptr++; 06029 06030 if (*chptr != '{') { 06031 hsa->errmsg = _("{ expected after : in expression"); 06032 token->u.cond.ifFormat = 06033 freeFormat(token->u.cond.ifFormat, token->u.cond.numIfTokens); 06034 return 1; 06035 } 06036 06037 chptr++; 06038 06039 if (parseFormat(hsa, chptr, &token->u.cond.elseFormat, 06040 &token->u.cond.numElseTokens, &end, PARSER_IN_EXPR)) 06041 return 1; 06042 06043 /* XXX fix segfault on "rpm -q rpm --qf='%|NAME?{a}:{%}|{NAME}\n'" */ 06044 if (!(end && *end)) { 06045 hsa->errmsg = _("} expected in expression"); 06046 token->u.cond.ifFormat = 06047 freeFormat(token->u.cond.ifFormat, token->u.cond.numIfTokens); 06048 return 1; 06049 } 06050 06051 chptr = end; 06052 if (*chptr != '|') { 06053 hsa->errmsg = _("| expected at end of expression"); 06054 token->u.cond.ifFormat = 06055 freeFormat(token->u.cond.ifFormat, token->u.cond.numIfTokens); 06056 token->u.cond.elseFormat = 06057 freeFormat(token->u.cond.elseFormat, token->u.cond.numElseTokens); 06058 return 1; 06059 } 06060 } 06061 06062 chptr++; 06063 06064 *endPtr = chptr; 06065 06066 token->type = PTOK_COND; 06067 06068 (void) findTag(hsa, token, str); 06069 06070 return 0; 06071 } 06072 06081 static int getExtension(headerSprintfArgs hsa, headerTagTagFunction fn, 06082 HE_t he, HE_t ec) 06083 /*@modifies he, ec @*/ 06084 { 06085 int rc = 0; 06086 if (!ec->avail) { 06087 he = rpmheClean(he); 06088 rc = fn(hsa->h, he); 06089 *ec = *he; /* structure copy. */ 06090 if (!rc) 06091 ec->avail = 1; 06092 } else 06093 *he = *ec; /* structure copy. */ 06094 he->freeData = 0; 06095 rc = (rc == 0); /* XXX invert getExtension return. */ 06096 return rc; 06097 } 06098 06106 /*@observer@*/ /*@null@*/ 06107 static char * formatValue(headerSprintfArgs hsa, sprintfTag tag, 06108 size_t element) 06109 /*@globals rpmGlobalMacroContext, h_errno, internalState @*/ 06110 /*@modifies hsa, tag, rpmGlobalMacroContext, internalState @*/ 06111 { 06112 HE_t vhe = memset(alloca(sizeof(*vhe)), 0, sizeof(*vhe)); 06113 HE_t he = &tag->he; 06114 char * val = NULL; 06115 size_t need = 0; 06116 char * t, * te; 06117 rpmuint64_t ival = 0; 06118 rpmTagCount countBuf; 06119 int xx; 06120 06121 if (!he->avail) { 06122 if (tag->ext) 06123 xx = getExtension(hsa, tag->ext, he, hsa->ec + tag->extNum); 06124 else { 06125 he->tag = tag->tagno[0]; /* XXX necessary? */ 06126 xx = headerGet(hsa->h, he, 0); 06127 } 06128 if (!xx) { 06129 (void) rpmheClean(he); 06130 he->t = RPM_STRING_TYPE; 06131 he->p.str = xstrdup("(none)"); 06132 he->c = 1; 06133 he->freeData = 1; 06134 } 06135 he->avail = 1; 06136 } 06137 06138 if (tag->arrayCount) { 06139 countBuf = he->c; 06140 he = rpmheClean(he); 06141 he->t = RPM_UINT32_TYPE; 06142 he->p.ui32p = &countBuf; 06143 he->c = 1; 06144 he->freeData = 0; 06145 } 06146 06147 vhe->tag = he->tag; 06148 06149 if (he->p.ptr) 06150 switch (he->t) { 06151 default: 06152 val = xstrdup("(unknown type)"); 06153 need = strlen(val) + 1; 06154 goto exit; 06155 /*@notreached@*/ break; 06156 case RPM_I18NSTRING_TYPE: 06157 case RPM_STRING_ARRAY_TYPE: 06158 vhe->t = RPM_STRING_TYPE; 06159 vhe->p.str = he->p.argv[element]; 06160 vhe->c = he->c; 06161 vhe->ix = (he->t == RPM_STRING_ARRAY_TYPE || he->c > 1 ? 0 : -1); 06162 break; 06163 case RPM_STRING_TYPE: 06164 vhe->p.str = he->p.str; 06165 vhe->t = RPM_STRING_TYPE; 06166 vhe->c = 0; 06167 vhe->ix = -1; 06168 break; 06169 case RPM_UINT8_TYPE: 06170 case RPM_UINT16_TYPE: 06171 case RPM_UINT32_TYPE: 06172 case RPM_UINT64_TYPE: 06173 switch (he->t) { 06174 default: 06175 assert(0); /* XXX keep gcc quiet. */ 06176 /*@innerbreak@*/ break; 06177 case RPM_UINT8_TYPE: 06178 ival = (rpmuint64_t)he->p.ui8p[element]; 06179 /*@innerbreak@*/ break; 06180 case RPM_UINT16_TYPE: 06181 ival = (rpmuint64_t)he->p.ui16p[element]; 06182 /*@innerbreak@*/ break; 06183 case RPM_UINT32_TYPE: 06184 ival = (rpmuint64_t)he->p.ui32p[element]; 06185 /*@innerbreak@*/ break; 06186 case RPM_UINT64_TYPE: 06187 ival = he->p.ui64p[element]; 06188 /*@innerbreak@*/ break; 06189 } 06190 vhe->t = RPM_UINT64_TYPE; 06191 vhe->p.ui64p = &ival; 06192 vhe->c = he->c; 06193 vhe->ix = (he->c > 1 ? 0 : -1); 06194 if ((tagType(he->tag) & RPM_MASK_RETURN_TYPE) == RPM_ARRAY_RETURN_TYPE) 06195 vhe->ix = 0; 06196 break; 06197 06198 case RPM_BIN_TYPE: 06199 vhe->t = RPM_BIN_TYPE; 06200 vhe->p.ptr = he->p.ptr; 06201 vhe->c = he->c; 06202 vhe->ix = -1; 06203 break; 06204 } 06205 06206 /*@-compmempass@*/ /* vhe->p.ui64p is stack, not owned */ 06207 if (tag->fmtfuncs) { 06208 char * nval; 06209 int i; 06210 for (i = 0; tag->av[i] != NULL; i++) { 06211 headerTagFormatFunction fmt; 06212 ARGV_t av; 06213 if ((fmt = tag->fmtfuncs[i]) == NULL) 06214 continue; 06215 /* If !1st formatter, and transformer, not extractor, save val. */ 06216 if (val != NULL && *tag->av[i] == '|') { 06217 int ix = vhe->ix; 06218 vhe = rpmheClean(vhe); 06219 vhe->tag = he->tag; 06220 vhe->t = RPM_STRING_TYPE; 06221 vhe->p.str = xstrdup(val); 06222 vhe->c = he->c; 06223 vhe->ix = ix; 06224 vhe->freeData = 1; 06225 } 06226 av = NULL; 06227 if (tag->params && tag->params[i] && *tag->params[i] != '\0') 06228 xx = argvSplit(&av, tag->params[i], ","); 06229 06230 nval = fmt(vhe, av); 06231 06232 /*@-castfcnptr -modfilesys@*/ 06233 if (_hdrqf_debug) 06234 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)")); 06235 /*@=castfcnptr =modfilesys@*/ 06236 06237 /* Accumulate (by appending) next formmatter's return string. */ 06238 if (val == NULL) 06239 val = xstrdup((nval ? nval : "")); 06240 else { 06241 char * oval = val; 06242 /* XXX using ... | ... as separator is feeble. */ 06243 val = rpmExpand(val, (*val != '\0' ? " | " : ""), nval, NULL); 06244 oval = _free(oval); 06245 } 06246 nval = _free(nval); 06247 av = argvFree(av); 06248 } 06249 } 06250 if (val == NULL) 06251 val = intFormat(vhe, NULL, NULL); 06252 /*@=compmempass@*/ 06253 assert(val != NULL); 06254 if (val) 06255 need = strlen(val) + 1; 06256 06257 exit: 06258 if (val && need > 0) { 06259 if (tag->format && *tag->format && tag->pad > 0) { 06260 size_t nb; 06261 nb = strlen(tag->format) + sizeof("%s"); 06262 t = alloca(nb); 06263 (void) stpcpy( stpcpy( stpcpy(t, "%"), tag->format), "s"); 06264 nb = tag->pad + strlen(val) + 1; 06265 te = xmalloc(nb); 06266 /*@-formatconst@*/ 06267 (void) snprintf(te, nb, t, val); 06268 /*@=formatconst@*/ 06269 te[nb-1] = '\0'; 06270 val = _free(val); 06271 val = te; 06272 need += tag->pad; 06273 } 06274 t = hsaReserve(hsa, need); 06275 te = stpcpy(t, val); 06276 hsa->vallen += (te - t); 06277 val = _free(val); 06278 } 06279 06280 return (hsa->val + hsa->vallen); 06281 } 06282 06290 /*@observer@*/ /*@null@*/ 06291 static char * singleSprintf(headerSprintfArgs hsa, sprintfToken token, 06292 size_t element) 06293 /*@globals rpmGlobalMacroContext, h_errno, internalState @*/ 06294 /*@modifies hsa, token, rpmGlobalMacroContext, internalState @*/ 06295 { 06296 char * t, * te; 06297 size_t i, j; 06298 size_t numElements; 06299 sprintfToken spft; 06300 sprintfTag tag = NULL; 06301 HE_t he = NULL; 06302 size_t condNumFormats; 06303 size_t need; 06304 int xx; 06305 06306 /* we assume the token and header have been validated already! */ 06307 06308 switch (token->type) { 06309 case PTOK_NONE: 06310 break; 06311 06312 case PTOK_STRING: 06313 need = token->u.string.len; 06314 if (need == 0) break; 06315 t = hsaReserve(hsa, need); 06316 te = stpcpy(t, token->u.string.string); 06317 hsa->vallen += (te - t); 06318 break; 06319 06320 case PTOK_TAG: 06321 t = hsa->val + hsa->vallen; 06322 /*@-modobserver@*/ /* headerCompoundFormats not modified. */ 06323 te = formatValue(hsa, &token->u.tag, 06324 (token->u.tag.justOne ? 0 : element)); 06325 /*@=modobserver@*/ 06326 if (te == NULL) 06327 return NULL; 06328 break; 06329 06330 case PTOK_COND: 06331 if (token->u.cond.tag.ext 06332 || headerIsEntry(hsa->h, token->u.cond.tag.tagno[0])) 06333 { 06334 spft = token->u.cond.ifFormat; 06335 condNumFormats = token->u.cond.numIfTokens; 06336 } else { 06337 spft = token->u.cond.elseFormat; 06338 condNumFormats = token->u.cond.numElseTokens; 06339 } 06340 06341 need = condNumFormats * 20; 06342 if (spft == NULL || need == 0) break; 06343 06344 t = hsaReserve(hsa, need); 06345 for (i = 0; i < condNumFormats; i++, spft++) { 06346 /*@-modobserver@*/ /* headerCompoundFormats not modified. */ 06347 te = singleSprintf(hsa, spft, element); 06348 /*@=modobserver@*/ 06349 if (te == NULL) 06350 return NULL; 06351 } 06352 break; 06353 06354 case PTOK_ARRAY: 06355 numElements = 0; 06356 spft = token->u.array.format; 06357 for (i = 0; i < token->u.array.numTokens; i++, spft++) 06358 { 06359 tag = &spft->u.tag; 06360 if (spft->type != PTOK_TAG || tag->arrayCount || tag->justOne) 06361 continue; 06362 he = &tag->he; 06363 if (!he->avail) { 06364 he->tag = tag->tagno[0]; 06365 if (tag->ext) 06366 xx = getExtension(hsa, tag->ext, he, hsa->ec + tag->extNum); 06367 else 06368 xx = headerGet(hsa->h, he, 0); 06369 if (!xx) { 06370 (void) rpmheClean(he); 06371 continue; 06372 } 06373 he->avail = 1; 06374 } 06375 06376 /* Check iteration arrays are same dimension (or scalar). */ 06377 switch (he->t) { 06378 default: 06379 if (numElements == 0) { 06380 numElements = he->c; 06381 /*@switchbreak@*/ break; 06382 } 06383 if ((size_t)he->c == numElements) 06384 /*@switchbreak@*/ break; 06385 hsa->errmsg = 06386 _("array iterator used with different sized arrays"); 06387 he = rpmheClean(he); 06388 return NULL; 06389 /*@notreached@*/ /*@switchbreak@*/ break; 06390 case RPM_BIN_TYPE: 06391 case RPM_STRING_TYPE: 06392 if (numElements == 0) 06393 numElements = 1; 06394 /*@switchbreak@*/ break; 06395 } 06396 } 06397 spft = token->u.array.format; 06398 06399 if (numElements == 0) { 06400 #ifdef DYING /* XXX lots of pugly "(none)" lines with --conflicts. */ 06401 need = sizeof("(none)\n") - 1; 06402 t = hsaReserve(hsa, need); 06403 te = stpcpy(t, "(none)\n"); 06404 hsa->vallen += (te - t); 06405 #endif 06406 } else { 06407 rpmTagReturnType tagT = 0; 06408 const char * tagN = NULL; 06409 spew_t spew = NULL; 06410 06411 need = numElements * token->u.array.numTokens; 06412 if (need == 0) break; 06413 06414 tag = &spft->u.tag; 06415 06416 spew = NULL; 06417 /* XXX Ick: +1 needed to handle :extractor |transformer marking. */ 06418 if (spft->type == PTOK_TAG && tag->av != NULL 06419 && tag->av[0] != NULL && !strcmp(tag->av[0]+1, "xml")) 06420 spew = &_xml_spew; 06421 if (spft->type == PTOK_TAG && tag->av != NULL 06422 && tag->av[0] != NULL && !strcmp(tag->av[0]+1, "yaml")) 06423 spew = &_yaml_spew; 06424 if (spft->type == PTOK_TAG && tag->av != NULL 06425 && tag->av[0] != NULL && !strcmp(tag->av[0]+1, "json")) 06426 spew = &_json_spew; 06427 06428 if (spew == &_xml_spew) { 06429 assert(tag->tagno != NULL); 06430 /* XXX display "Tag_0x01234567" for arbitrary tags. */ 06431 if (tag->tagno[0] & 0x40000000) { 06432 tagN = myTagName(hsa->tags, tag->tagno[0], NULL); 06433 } else 06434 tagN = myTagName(hsa->tags, tag->tagno[0], NULL); 06435 need = sizeof(" <rpmTag name=\"\">\n") + strlen(tagN); 06436 te = t = hsaReserve(hsa, need); 06437 te = stpcpy( stpcpy( stpcpy(te, " <rpmTag name=\""), tagN), "\">\n"); 06438 hsa->vallen += (te - t); 06439 } 06440 if (spew == &_yaml_spew) { 06441 assert(tag->tagno != NULL); 06442 /* XXX display "Tag_0x01234567" for arbitrary tags. */ 06443 if (tag->tagno[0] & 0x40000000) { 06444 tagN = myTagName(hsa->tags, tag->tagno[0], NULL); 06445 tagT = numElements > 1 06446 ? RPM_ARRAY_RETURN_TYPE : RPM_SCALAR_RETURN_TYPE; 06447 } else 06448 tagN = myTagName(hsa->tags, tag->tagno[0], &tagT); 06449 need = sizeof(" : - ") + strlen(tagN); 06450 te = t = hsaReserve(hsa, need); 06451 *te++ = ' '; 06452 *te++ = ' '; 06453 te = stpcpy(te, tagN); 06454 *te++ = ':'; 06455 *te++ = (((tagT & RPM_MASK_RETURN_TYPE) == RPM_ARRAY_RETURN_TYPE) 06456 ? '\n' : ' '); 06457 *te = '\0'; 06458 hsa->vallen += (te - t); 06459 } 06460 if (spew == &_json_spew) { 06461 assert(tag->tagno != NULL); 06462 /* XXX display "Tag_0x01234567" for arbitrary tags. */ 06463 if (tag->tagno[0] & 0x40000000) { 06464 tagN = myTagName(hsa->tags, tag->tagno[0], NULL); 06465 tagT = numElements > 1 06466 ? RPM_ARRAY_RETURN_TYPE : RPM_SCALAR_RETURN_TYPE; 06467 } else 06468 if (tag->tagno[0] == RPMTAG_HDRID) { /* RPMTAG_SHA1HEADER */ 06469 tagN = "_id"; /* XXX mongo primary key name */ 06470 } else 06471 tagN = myTagName(hsa->tags, tag->tagno[0], &tagT); 06472 need = sizeof(" : [\n") + strlen(tagN); 06473 te = t = hsaReserve(hsa, need); 06474 te = stpcpy( stpcpy( stpcpy(te, " "), tagN), ":"); 06475 if ((tagT & RPM_MASK_RETURN_TYPE) == RPM_ARRAY_RETURN_TYPE) 06476 te = stpcpy(te, " [\n"); 06477 hsa->vallen += (te - t); 06478 } 06479 06480 need = numElements * token->u.array.numTokens * 10; 06481 t = hsaReserve(hsa, need); 06482 for (j = 0; j < numElements; j++) { 06483 spft = token->u.array.format; 06484 for (i = 0; i < token->u.array.numTokens; i++, spft++) { 06485 /*@-modobserver@*/ /* headerCompoundFormats not modified. */ 06486 te = singleSprintf(hsa, spft, j); 06487 /*@=modobserver@*/ 06488 if (te == NULL) 06489 return NULL; 06490 } 06491 } 06492 06493 if (spew == &_xml_spew) { 06494 need = sizeof(" </rpmTag>\n") - 1; 06495 te = t = hsaReserve(hsa, need); 06496 te = stpcpy(te, " </rpmTag>\n"); 06497 hsa->vallen += (te - t); 06498 } 06499 if (spew == &_json_spew) { 06500 if ((tagT & RPM_MASK_RETURN_TYPE) == RPM_ARRAY_RETURN_TYPE) { 06501 need = sizeof(" ],\n") - 1; 06502 te = t = hsaReserve(hsa, need); 06503 te = stpcpy(te, " ],\n"); 06504 hsa->vallen += (te - t); 06505 } 06506 } 06507 06508 } 06509 break; 06510 } 06511 06512 return (hsa->val + hsa->vallen); 06513 } 06514 06521 static /*@only@*/ HE_t 06522 rpmecNew(const headerSprintfExtension exts, /*@null@*/ int * necp) 06523 /*@modifies *necp @*/ 06524 { 06525 headerSprintfExtension ext; 06526 HE_t ec; 06527 int extNum = 0; 06528 06529 if (exts != NULL) 06530 for (ext = exts, extNum = 0; ext != NULL && ext->type != HEADER_EXT_LAST; 06531 ext = (ext->type == HEADER_EXT_MORE ? *ext->u.more : ext+1), extNum++) 06532 { 06533 ; 06534 } 06535 if (necp) 06536 *necp = extNum; 06537 ec = xcalloc(extNum+1, sizeof(*ec)); /* XXX +1 unnecessary */ 06538 return ec; 06539 } 06540 06547 static /*@null@*/ HE_t 06548 rpmecFree(const headerSprintfExtension exts, /*@only@*/ HE_t ec) 06549 /*@modifies ec @*/ 06550 { 06551 headerSprintfExtension ext; 06552 int extNum; 06553 06554 for (ext = exts, extNum = 0; ext != NULL && ext->type != HEADER_EXT_LAST; 06555 ext = (ext->type == HEADER_EXT_MORE ? *ext->u.more : ext+1), extNum++) 06556 { 06557 (void) rpmheClean(&ec[extNum]); 06558 } 06559 06560 ec = _free(ec); 06561 return NULL; 06562 } 06563 06564 char * headerSprintf(Header h, const char * fmt, 06565 headerTagTableEntry tags, 06566 headerSprintfExtension exts, 06567 errmsg_t * errmsg) 06568 { 06569 headerSprintfArgs hsa = memset(alloca(sizeof(*hsa)), 0, sizeof(*hsa)); 06570 sprintfToken nextfmt; 06571 sprintfTag tag; 06572 char * t, * te; 06573 int need; 06574 spew_t spew = NULL; 06575 06576 /*@-modfilesys@*/ 06577 if (_hdrqf_debug) 06578 fprintf(stderr, "==> headerSprintf(%p, \"%s\", %p, %p, %p)\n", h, fmt, tags, exts, errmsg); 06579 /*@=modfilesys@*/ 06580 06581 /* Set some reasonable defaults */ 06582 if (tags == NULL) 06583 tags = rpmTagTable; 06584 /* XXX this loses the extensions in lib/formats.c. */ 06585 if (exts == NULL) 06586 exts = headerCompoundFormats; 06587 06588 /*@-assignexpose -castexpose @*/ 06589 hsa->h = headerLink(h); 06590 /*@=assignexpose =castexpose @*/ 06591 hsa->fmt = xstrdup(fmt); 06592 /*@-assignexpose -dependenttrans@*/ 06593 hsa->exts = exts; 06594 hsa->tags = tags; 06595 /*@=assignexpose =dependenttrans@*/ 06596 hsa->errmsg = NULL; 06597 06598 if (parseFormat(hsa, hsa->fmt, &hsa->format, &hsa->numTokens, NULL, PARSER_BEGIN)) 06599 goto exit; 06600 06601 hsa->nec = 0; 06602 hsa->ec = rpmecNew(hsa->exts, &hsa->nec); 06603 hsa->val = xstrdup(""); 06604 06605 tag = 06606 (hsa->format->type == PTOK_TAG 06607 ? &hsa->format->u.tag : 06608 (hsa->format->type == PTOK_ARRAY 06609 ? &hsa->format->u.array.format->u.tag : 06610 NULL)); 06611 06612 spew = NULL; 06613 /* XXX Ick: +1 needed to handle :extractor |transformer marking. */ 06614 if (tag != NULL && tag->tagno != NULL && tag->tagno[0] == (rpmTag)-2 06615 && tag->av != NULL && tag->av[0] != NULL && !strcmp(tag->av[0]+1, "xml")) 06616 spew = &_xml_spew; 06617 if (tag != NULL && tag->tagno != NULL && tag->tagno[0] == (rpmTag)-2 06618 && tag->av != NULL && tag->av[0] != NULL && !strcmp(tag->av[0]+1, "yaml")) 06619 spew = &_yaml_spew; 06620 if (tag != NULL && tag->tagno != NULL && tag->tagno[0] == (rpmTag)-2 06621 && tag->av != NULL && tag->av[0] != NULL && !strcmp(tag->av[0]+1, "json")) 06622 spew = &_json_spew; 06623 06624 if (spew && spew->spew_init && spew->spew_init[0]) { 06625 need = strlen(spew->spew_init); 06626 t = hsaReserve(hsa, need); 06627 te = stpcpy(t, spew->spew_init); 06628 hsa->vallen += (te - t); 06629 } 06630 06631 hsa = hsaInit(hsa); 06632 while ((nextfmt = hsaNext(hsa)) != NULL) { 06633 /*@-globs -mods@*/ /* XXX rpmGlobalMacroContext @*/ 06634 te = singleSprintf(hsa, nextfmt, 0); 06635 /*@=globs =mods @*/ 06636 if (te == NULL) { 06637 hsa->val = _free(hsa->val); 06638 break; 06639 } 06640 } 06641 hsa = hsaFini(hsa); 06642 06643 if (spew && spew->spew_fini && spew->spew_fini[0]) { 06644 need = strlen(spew->spew_fini); 06645 t = hsaReserve(hsa, need); 06646 te = stpcpy(t, spew->spew_fini); 06647 hsa->vallen += (te - t); 06648 } 06649 06650 if (hsa->val != NULL && hsa->vallen < hsa->alloced) 06651 hsa->val = xrealloc(hsa->val, hsa->vallen+1); 06652 06653 hsa->ec = rpmecFree(hsa->exts, hsa->ec); 06654 hsa->nec = 0; 06655 hsa->format = freeFormat(hsa->format, hsa->numTokens); 06656 06657 exit: 06658 /*@-dependenttrans -observertrans @*/ 06659 if (errmsg) 06660 *errmsg = hsa->errmsg; 06661 /*@=dependenttrans =observertrans @*/ 06662 (void)headerFree(hsa->h); 06663 hsa->h = NULL; 06664 hsa->fmt = _free(hsa->fmt); 06665 /*@-retexpose@*/ 06666 return hsa->val; 06667 /*@=retexpose@*/ 06668 }