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