diff options
author | Kim Kibum <kb0929.kim@samsung.com> | 2012-05-21 17:49:08 +0900 |
---|---|---|
committer | Kim Kibum <kb0929.kim@samsung.com> | 2012-05-21 17:49:08 +0900 |
commit | dec48cfa66e17ba4a7e50c92cb24b913289feb12 (patch) | |
tree | e1f48cd5cabb40a1d604b36949ff072d01267cb5 /lib/query.c | |
parent | b7a3bffb8e0341b7e4ef69def268bca3a7f279ff (diff) | |
download | rpm-dec48cfa66e17ba4a7e50c92cb24b913289feb12.tar.gz rpm-dec48cfa66e17ba4a7e50c92cb24b913289feb12.tar.bz2 rpm-dec48cfa66e17ba4a7e50c92cb24b913289feb12.zip |
Upload Tizen:Base source
Diffstat (limited to 'lib/query.c')
-rw-r--r-- | lib/query.c | 575 |
1 files changed, 575 insertions, 0 deletions
diff --git a/lib/query.c b/lib/query.c new file mode 100644 index 0000000..308fe65 --- /dev/null +++ b/lib/query.c @@ -0,0 +1,575 @@ +/** \ingroup rpmcli + * \file lib/query.c + * Display tag values from package metadata. + */ + +#include "system.h" + +#include <errno.h> +#include <inttypes.h> +#include <ctype.h> + +#include <rpm/rpmcli.h> +#include <rpm/header.h> +#include <rpm/rpmdb.h> +#include <rpm/rpmfi.h> +#include <rpm/rpmts.h> +#include <rpm/rpmlog.h> +#include <rpm/rpmfileutil.h> /* rpmCleanPath */ + +#include "lib/rpmgi.h" +#include "lib/manifest.h" + +#include "debug.h" + + +/** + */ +static void printFileInfo(const char * name, + rpm_loff_t size, unsigned short mode, + unsigned int mtime, + unsigned short rdev, unsigned int nlink, + const char * owner, const char * group, + const char * linkto) +{ + char sizefield[21]; + char ownerfield[8+1], groupfield[8+1]; + char timefield[100]; + time_t when = mtime; /* important if sizeof(int32_t) ! sizeof(time_t) */ + struct tm * tm; + static time_t now; + static struct tm nowtm; + char * perms = rpmPermsString(mode); + char *link = NULL; + + /* On first call, grab snapshot of now */ + if (now == 0) { + now = time(NULL); + tm = localtime(&now); + if (tm) nowtm = *tm; /* structure assignment */ + } + + rstrlcpy(ownerfield, owner, sizeof(ownerfield)); + rstrlcpy(groupfield, group, sizeof(groupfield)); + + /* this is normally right */ + snprintf(sizefield, sizeof(sizefield), "%20" PRIu64, size); + + /* this knows too much about dev_t */ + + if (S_ISLNK(mode)) { + rasprintf(&link, "%s -> %s", name, linkto); + } else if (S_ISCHR(mode)) { + perms[0] = 'c'; + snprintf(sizefield, sizeof(sizefield), "%3u, %3u", ((unsigned)(rdev >> 8) & 0xff), + ((unsigned)rdev & 0xff)); + } else if (S_ISBLK(mode)) { + perms[0] = 'b'; + snprintf(sizefield, sizeof(sizefield), "%3u, %3u", ((unsigned)(rdev >> 8) & 0xff), + ((unsigned)rdev & 0xff)); + } + + /* Convert file mtime to display format */ + tm = localtime(&when); + timefield[0] = '\0'; + if (tm != NULL) + { const char *fmt; + if (now > when + 6L * 30L * 24L * 60L * 60L || /* Old. */ + now < when - 60L * 60L) /* In the future. */ + { + /* The file is fairly old or in the future. + * POSIX says the cutoff is 6 months old; + * approximate this by 6*30 days. + * Allow a 1 hour slop factor for what is considered "the future", + * to allow for NFS server/client clock disagreement. + * Show the year instead of the time of day. + */ + fmt = "%b %e %Y"; + } else { + fmt = "%b %e %H:%M"; + } + (void)strftime(timefield, sizeof(timefield) - 1, fmt, tm); + } + + rpmlog(RPMLOG_NOTICE, "%s %4d %-8s%-8s %10s %s %s\n", perms, + (int)nlink, ownerfield, groupfield, sizefield, timefield, + link ? link : name); + free(perms); + free(link); +} + +int showQueryPackage(QVA_t qva, rpmts ts, Header h) +{ + rpmfi fi = NULL; + rpmfiFlags fiflags = (RPMFI_NOHEADER | RPMFI_FLAGS_QUERY); + int rc = 0; /* XXX FIXME: need real return code */ + + if (qva->qva_queryFormat != NULL) { + const char *errstr; + char *str = headerFormat(h, qva->qva_queryFormat, &errstr); + + if ( str != NULL ) { + rpmlog(RPMLOG_NOTICE, "%s", str); + free(str); + } else { + rpmlog(RPMLOG_ERR, _("incorrect format: %s\n"), errstr); + } + } + + if (!(qva->qva_flags & QUERY_FOR_LIST)) + goto exit; + + if (!(qva->qva_flags & QUERY_FOR_DUMPFILES)) + fiflags |= RPMFI_NOFILEDIGESTS; + + fi = rpmfiNew(ts, h, RPMTAG_BASENAMES, fiflags); + if (rpmfiFC(fi) <= 0) { + rpmlog(RPMLOG_NOTICE, _("(contains no files)\n")); + goto exit; + } + + fi = rpmfiInit(fi, 0); + while (rpmfiNext(fi) >= 0) { + rpmfileAttrs fflags = rpmfiFFlags(fi); + rpm_mode_t fmode = rpmfiFMode(fi); + rpm_rdev_t frdev = rpmfiFRdev(fi); + rpm_time_t fmtime = rpmfiFMtime(fi); + rpmfileState fstate = rpmfiFState(fi); + rpm_loff_t fsize = rpmfiFSize(fi); + const char *fn = rpmfiFN(fi); + const char *fuser = rpmfiFUser(fi); + const char *fgroup = rpmfiFGroup(fi); + const char *flink = rpmfiFLink(fi); + char *buf = NULL; + + /* If querying only docs, skip non-doc files. */ + if ((qva->qva_flags & QUERY_FOR_DOCS) && !(fflags & RPMFILE_DOC)) + continue; + + /* If querying only configs, skip non-config files. */ + if ((qva->qva_flags & QUERY_FOR_CONFIG) && !(fflags & RPMFILE_CONFIG)) + continue; + + /* If not querying %ghost, skip ghost files. */ + if ((qva->qva_fflags & RPMFILE_GHOST) && (fflags & RPMFILE_GHOST)) + continue; + + if (qva->qva_flags & QUERY_FOR_STATE) { + switch (fstate) { + case RPMFILE_STATE_NORMAL: + rstrcat(&buf, _("normal ")); + break; + case RPMFILE_STATE_REPLACED: + rstrcat(&buf, _("replaced ")); + break; + case RPMFILE_STATE_NOTINSTALLED: + rstrcat(&buf, _("not installed ")); + break; + case RPMFILE_STATE_NETSHARED: + rstrcat(&buf, _("net shared ")); + break; + case RPMFILE_STATE_WRONGCOLOR: + rstrcat(&buf, _("wrong color ")); + break; + case RPMFILE_STATE_MISSING: + rstrcat(&buf, _("(no state) ")); + break; + default: + rasprintf(&buf, _("(unknown %3d) "), fstate); + break; + } + } + + if (qva->qva_flags & QUERY_FOR_DUMPFILES) { + char *add, *fdigest; + fdigest = rpmfiFDigestHex(fi, NULL); + rasprintf(&add, "%s %" PRIu64 " %d %s 0%o ", + fn, fsize, fmtime, fdigest ? fdigest : "", fmode); + rstrcat(&buf, add); + free(add); + free(fdigest); + + if (fuser && fgroup) { + rasprintf(&add, "%s %s", fuser, fgroup); + rstrcat(&buf, add); + free(add); + } else { + rpmlog(RPMLOG_ERR, + _("package has not file owner/group lists\n")); + } + + rasprintf(&add, " %s %s %u %s", + fflags & RPMFILE_CONFIG ? "1" : "0", + fflags & RPMFILE_DOC ? "1" : "0", + frdev, + (flink && *flink ? flink : "X")); + rpmlog(RPMLOG_NOTICE, "%s%s\n", buf, add); + free(add); + } else + if (!rpmIsVerbose()) { + rpmlog(RPMLOG_NOTICE, "%s%s\n", buf ? buf : "", fn); + } + else { + uint32_t fnlink = rpmfiFNlink(fi); + + /* XXX Adjust directory link count and size for display output. */ + if (S_ISDIR(fmode)) { + fnlink++; + fsize = 0; + } + + if (fuser && fgroup) { + if (buf) { + rpmlog(RPMLOG_NOTICE, "%s", buf); + } + printFileInfo(fn, fsize, fmode, fmtime, frdev, fnlink, + fuser, fgroup, flink); + } else { + rpmlog(RPMLOG_ERR, + _("package has neither file owner or id lists\n")); + } + } + free(buf); + } + + rc = 0; + +exit: + fi = rpmfiFree(fi); + return rc; +} + +void rpmDisplayQueryTags(FILE * fp) +{ + static const char * const tagTypeNames[] = { + "", "char", "int8", "int16", "int32", "int64", + "string", "blob", "argv", "i18nstring" + }; + const char *tname, *sname; + rpmtd names = rpmtdNew(); + (void) rpmTagGetNames(names, 1); + + while ((tname = rpmtdNextString(names))) { + sname = tname + strlen("RPMTAG_"); + if (rpmIsVerbose()) { + rpmTagVal tag = rpmTagGetValue(sname); + rpmTagType type = rpmTagGetTagType(tag); + fprintf(fp, "%-20s %6d", sname, tag); + if (type > RPM_NULL_TYPE && type <= RPM_MAX_TYPE) + fprintf(fp, " %s", tagTypeNames[type]); + } else { + fprintf(fp, "%s", sname); + } + fprintf(fp, "\n"); + } + rpmtdFreeData(names); + rpmtdFree(names); +} + +static int rpmgiShowMatches(QVA_t qva, rpmts ts, rpmgi gi) +{ + int ec = 0; + Header h; + + while ((h = rpmgiNext(gi)) != NULL) { + int rc; + + rpmdbCheckSignals(); + if ((rc = qva->qva_showPackage(qva, ts, h)) != 0) + ec = rc; + headerFree(h); + } + return ec + rpmgiNumErrors(gi); +} + +static int rpmcliShowMatches(QVA_t qva, rpmts ts, rpmdbMatchIterator mi) +{ + Header h; + int ec = 0; + + if (mi == NULL) + return 1; + + while ((h = rpmdbNextIterator(mi)) != NULL) { + int rc; + rpmdbCheckSignals(); + if ((rc = qva->qva_showPackage(qva, ts, h)) != 0) + ec = rc; + } + return ec; +} + +static rpmdbMatchIterator initQueryIterator(QVA_t qva, rpmts ts, const char * arg) +{ + const char * s; + int i; + int provides_checked = 0; + rpmdbMatchIterator mi = NULL; + + (void) rpmdbCheckSignals(); + + if (qva->qva_showPackage == NULL) + goto exit; + + switch (qva->qva_source) { + case RPMQV_GROUP: + mi = rpmtsInitIterator(ts, RPMDBI_GROUP, arg, 0); + if (mi == NULL) { + rpmlog(RPMLOG_NOTICE, + _("group %s does not contain any packages\n"), arg); + } + break; + + case RPMQV_TRIGGEREDBY: + mi = rpmtsInitIterator(ts, RPMDBI_TRIGGERNAME, arg, 0); + if (mi == NULL) { + rpmlog(RPMLOG_NOTICE, _("no package triggers %s\n"), arg); + } + break; + + case RPMQV_PKGID: + { unsigned char MD5[16]; + unsigned char * t; + + for (i = 0, s = arg; *s && isxdigit(*s); s++, i++) + {}; + if (i != 32) { + rpmlog(RPMLOG_ERR, _("malformed %s: %s\n"), "pkgid", arg); + goto exit; + } + + MD5[0] = '\0'; + for (i = 0, t = MD5, s = arg; i < 16; i++, t++, s += 2) + *t = (rnibble(s[0]) << 4) | rnibble(s[1]); + + mi = rpmtsInitIterator(ts, RPMDBI_SIGMD5, MD5, sizeof(MD5)); + if (mi == NULL) { + rpmlog(RPMLOG_NOTICE, _("no package matches %s: %s\n"), + "pkgid", arg); + } + } break; + + case RPMQV_HDRID: + for (i = 0, s = arg; *s && isxdigit(*s); s++, i++) + {}; + if (i != 40) { + rpmlog(RPMLOG_ERR, _("malformed %s: %s\n"), "hdrid", arg); + goto exit; + } + + mi = rpmtsInitIterator(ts, RPMDBI_SHA1HEADER, arg, 0); + if (mi == NULL) { + rpmlog(RPMLOG_NOTICE, _("no package matches %s: %s\n"), + "hdrid", arg); + } + break; + + case RPMQV_TID: + { char * end = NULL; + rpm_tid_t iid = strtoul(arg, &end, 0); + + if ((*end) || (end == arg) || (iid == UINT_MAX)) { + rpmlog(RPMLOG_ERR, _("malformed %s: %s\n"), "tid", arg); + goto exit; + } + mi = rpmtsInitIterator(ts, RPMDBI_INSTALLTID, &iid, sizeof(iid)); + if (mi == NULL) { + rpmlog(RPMLOG_NOTICE, _("no package matches %s: %s\n"), + "tid", arg); + } + } break; + + case RPMQV_WHATREQUIRES: + mi = rpmtsInitIterator(ts, RPMDBI_REQUIRENAME, arg, 0); + if (mi == NULL) { + rpmlog(RPMLOG_NOTICE, _("no package requires %s\n"), arg); + } + break; + + case RPMQV_WHATPROVIDES: + if (arg[0] != '/') { + provides_checked = 1; + mi = rpmtsInitIterator(ts, RPMDBI_PROVIDENAME, arg, 0); + if (mi == NULL) { + rpmlog(RPMLOG_NOTICE, _("no package provides %s\n"), arg); + } + break; + } + case RPMQV_PATH: + { char * fn; + + for (s = arg; *s != '\0'; s++) + if (!(*s == '.' || *s == '/')) + break; + + if (*s == '\0') { + char fnbuf[PATH_MAX]; + fn = realpath(arg, fnbuf); + fn = xstrdup( (fn != NULL ? fn : arg) ); + } else if (*arg != '/') { + char *curDir = rpmGetCwd(); + fn = (char *) rpmGetPath(curDir, "/", arg, NULL); + curDir = _free(curDir); + } else + fn = xstrdup(arg); + (void) rpmCleanPath(fn); + + mi = rpmtsInitIterator(ts, RPMDBI_BASENAMES, fn, 0); + if (mi == NULL && !provides_checked) + mi = rpmtsInitIterator(ts, RPMDBI_PROVIDENAME, fn, 0); + + if (mi == NULL) { + struct stat sb; + if (lstat(fn, &sb) != 0) + rpmlog(RPMLOG_ERR, _("file %s: %s\n"), fn, strerror(errno)); + else + rpmlog(RPMLOG_NOTICE, + _("file %s is not owned by any package\n"), fn); + } + + fn = _free(fn); + } break; + + case RPMQV_DBOFFSET: + { char * end = NULL; + unsigned int recOffset = strtoul(arg, &end, 0); + + if ((*end) || (end == arg) || (recOffset == UINT_MAX)) { + rpmlog(RPMLOG_ERR, _("invalid package number: %s\n"), arg); + goto exit; + } + rpmlog(RPMLOG_DEBUG, "package record number: %u\n", recOffset); + /* RPMDBI_PACKAGES */ + mi = rpmtsInitIterator(ts, RPMDBI_PACKAGES, &recOffset, sizeof(recOffset)); + if (mi == NULL) { + rpmlog(RPMLOG_ERR, _("record %u could not be read\n"), recOffset); + } + } break; + + case RPMQV_PACKAGE: + { + int matches = 0; + mi = rpmtsInitIterator(ts, RPMDBI_LABEL, arg, 0); + while (rpmdbNextIterator(mi) != NULL) { + matches++; + } + mi = rpmdbFreeIterator(mi); + if (! matches) { + rpmlog(RPMLOG_NOTICE, _("package %s is not installed\n"), arg); + } else { + mi = rpmtsInitIterator(ts, RPMDBI_LABEL, arg, 0); + } + break; + } + default: + break; + } + +exit: + return mi; +} + +/* + * Initialize db iterator with optional filters. By default patterns + * applied to package name, others can be specified with <tagname>=<pattern> + */ +static rpmdbMatchIterator initFilterIterator(rpmts ts, ARGV_const_t argv) +{ + rpmdbMatchIterator mi = rpmtsInitIterator(ts, RPMDBI_PACKAGES, NULL, 0); + + for (ARGV_const_t arg = argv; arg && *arg != NULL; arg++) { + rpmTagVal tag = RPMTAG_NAME; + char a[strlen(*arg)+1], *ae; + const char *pat = a; + + strcpy(a, *arg); + + /* Parse for "tag=pattern" args. */ + if ((ae = strchr(a, '=')) != NULL) { + *ae++ = '\0'; + tag = rpmTagGetValue(a); + if (tag == RPMTAG_NOT_FOUND) { + rpmlog(RPMLOG_ERR, _("unknown tag: \"%s\"\n"), a); + mi = rpmdbFreeIterator(mi); + break; + } + pat = ae; + } + + rpmdbSetIteratorRE(mi, tag, RPMMIRE_DEFAULT, pat); + } + + return mi; +} + +int rpmcliArgIter(rpmts ts, QVA_t qva, ARGV_const_t argv) +{ + int ec = 0; + + switch (qva->qva_source) { + case RPMQV_ALL: { + rpmdbMatchIterator mi = initFilterIterator(ts, argv); + ec = rpmcliShowMatches(qva, ts, mi); + mi = rpmdbFreeIterator(mi); + break; + } + case RPMQV_RPM: { + rpmgi gi = rpmgiNew(ts, giFlags, argv); + ec = rpmgiShowMatches(qva, ts, gi); + gi = rpmgiFree(gi); + break; + } + case RPMQV_SPECRPMS: + case RPMQV_SPECSRPM: + for (ARGV_const_t arg = argv; arg && *arg; arg++) { + ec += ((qva->qva_specQuery != NULL) + ? qva->qva_specQuery(ts, qva, *arg) : 1); + } + break; + default: + for (ARGV_const_t arg = argv; arg && *arg; arg++) { + rpmdbMatchIterator mi = initQueryIterator(qva, ts, *arg); + ec += rpmcliShowMatches(qva, ts, mi); + rpmdbFreeIterator(mi); + } + break; + } + + return ec; +} + +int rpmcliQuery(rpmts ts, QVA_t qva, char * const * argv) +{ + rpmVSFlags vsflags, ovsflags; + int ec = 0; + + if (qva->qva_showPackage == NULL) + qva->qva_showPackage = showQueryPackage; + + /* If --queryformat unspecified, then set default now. */ + if (!(qva->qva_flags & _QUERY_FOR_BITS) && qva->qva_queryFormat == NULL) { + char * fmt = rpmExpand("%{?_query_all_fmt}\n", NULL); + if (fmt == NULL || strlen(fmt) <= 1) { + fmt = _free(fmt); + fmt = xstrdup("%{nvra}\n"); + } + qva->qva_queryFormat = fmt; + } + + vsflags = rpmExpandNumeric("%{?_vsflags_query}"); + if (rpmcliQueryFlags & VERIFY_DIGEST) + vsflags |= _RPMVSF_NODIGESTS; + if (rpmcliQueryFlags & VERIFY_SIGNATURE) + vsflags |= _RPMVSF_NOSIGNATURES; + if (rpmcliQueryFlags & VERIFY_HDRCHK) + vsflags |= RPMVSF_NOHDRCHK; + + ovsflags = rpmtsSetVSFlags(ts, vsflags); + ec = rpmcliArgIter(ts, qva, argv); + vsflags = rpmtsSetVSFlags(ts, ovsflags); + + if (qva->qva_showPackage == showQueryPackage) + qva->qva_showPackage = NULL; + + return ec; +} |