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