rpm 5.2.1

- Main Page
- Related Pages
- Modules
- Data Structures
- Files

- File List
- Globals

query.c
Go to the documentation of this file.
1
6 #include "system.h"
7
8 #ifndef PATH_MAX
9 /*@-incondefs@*/ /* FIX: long int? */
10 # define PATH_MAX 255
11 /*@=incondefs@*/
12 #endif
13
14 #include <rpmio.h>
15 #include <rpmiotypes.h>
16 #include <poptIO.h>
17
18 #include <rpmtag.h>
19 #include "rpmdb.h"
20
21 #include "rpmfi.h"
22 #define _RPMTS_INTERNAL /* XXX for ts->rdb */
23 #include "rpmts.h"
24 #include "rpmgi.h"
25
26 #include "manifest.h"
27 #include "misc.h" /* XXX for currentDirectory() */
28
29 #include <rpmcli.h>
30
31 #include "debug.h"
32
33 /*@access rpmts @*/ /* XXX cast */
34
37 static void printFileInfo(char * te, const char * name,
38 size_t size, unsigned short mode,
39 unsigned int mtime,
40 unsigned short rdev, unsigned int nlink,
41 const char * owner, const char * group,
42 const char * linkto)
43 /*@modifies *te @*/
44 {
45 char sizefield[15];
46 #if defined(RPM_VENDOR_OPENPKG) /* adjust-verbose-listing */
47 /* In verbose file listing output, give the owner and group fields
48 more width and at the same time reduce the nlink and size fields
49 more to typical sizes within OpenPKG. */
50 char ownerfield[13+1], groupfield[13+1];
51 #else
52 char ownerfield[8+1], groupfield[8+1];
53 #endif
54 char timefield[100];
55 time_t when = mtime; /* important if sizeof(rpmuint32_t) ! sizeof(time_t) */
56 struct tm * tm;
57 static time_t now;
58 static struct tm nowtm;
59 const char * namefield = name;
60 char * perms = rpmPermsString(mode);
61
62 /* On first call, grab snapshot of now */
63 if (now == 0) {
64 now = time(NULL);
65 tm = localtime(&now);
66 if (tm) nowtm = *tm; /* structure assignment */
67 }
68
69 strncpy(ownerfield, owner, sizeof(ownerfield));
70 ownerfield[sizeof(ownerfield)-1] = '\0';
71
72 strncpy(groupfield, group, sizeof(groupfield));
73 groupfield[sizeof(groupfield)-1] = '\0';
74
75 /* this is normally right */
76 #if defined(RPM_VENDOR_OPENPKG) /* adjust-verbose-listing */
77 /* In verbose file listing output, give the owner and group fields
78 more width and at the same time reduce the nlink and size fields
79 more to typical sizes within OpenPKG. */
80 sprintf(sizefield, "%8u", (unsigned)size);
81 #else
82 sprintf(sizefield, "%12u", (unsigned)size);
83 #endif
84
85 /* this knows too much about dev_t */
86
87 if (S_ISLNK(mode)) {
88 char *nf = alloca(strlen(name) + sizeof(" -> ") + strlen(linkto));
89 sprintf(nf, "%s -> %s", name, linkto);
90 namefield = nf;
91 } else if (S_ISCHR(mode)) {
92 perms[0] = 'c';
93 sprintf(sizefield, "%3u, %3u", ((unsigned)(rdev >> 8) & 0xff),
94 ((unsigned)rdev & 0xff));
95 } else if (S_ISBLK(mode)) {
96 perms[0] = 'b';
97 sprintf(sizefield, "%3u, %3u", ((unsigned)(rdev >> 8) & 0xff),
98 ((unsigned)rdev & 0xff));
99 }
100
101 /* Convert file mtime to display format */
102 tm = localtime(&when);
103 timefield[0] = '\0';
104 if (tm != NULL)
105 { const char *fmt;
106 if (now > when + 6L * 30L * 24L * 60L * 60L || /* Old. */
107 now < when - 60L * 60L) /* In the future. */
108 {
109 /* The file is fairly old or in the future.
110 * POSIX says the cutoff is 6 months old;
111 * approximate this by 6*30 days.
112 * Allow a 1 hour slop factor for what is considered "the future",
113 * to allow for NFS server/client clock disagreement.
114 * Show the year instead of the time of day.
115 */
116 fmt = "%b %e %Y";
117 } else {
118 fmt = "%b %e %H:%M";
119 }
120 (void)strftime(timefield, sizeof(timefield) - 1, fmt, tm);
121 }
122
123 #if defined(RPM_VENDOR_OPENPKG) /* adjust-verbose-listing */
124 /* In verbose file listing output, give the owner and group fields
125 more width and at the same time reduce the nlink and size fields
126 more to typical sizes within OpenPKG. */
127 sprintf(te, "%s %d %-13s %-13s %8s %s %s", perms,
128 (int)nlink, ownerfield, groupfield, sizefield, timefield, namefield);
129 #else
130 sprintf(te, "%s %4d %-7s %-8s %10s %s %s", perms,
131 (int)nlink, ownerfield, groupfield, sizefield, timefield, namefield);
132 #endif
133 perms = _free(perms);
134 }
135
138 static inline /*@null@*/ const char * queryHeader(Header h, const char * qfmt)
139 /*@globals internalState @*/
140 /*@modifies h, internalState @*/
141 {
142 const char * errstr = "(unkown error)";
143 const char * str;
144
145 /*@-modobserver@*/
146 str = headerSprintf(h, qfmt, NULL, rpmHeaderFormats, &errstr);
147 /*@=modobserver@*/
148 if (str == NULL)
149 rpmlog(RPMLOG_ERR, _("incorrect format: %s\n"), errstr);
150 return str;
151 }
152
155 static void flushBuffer(char ** tp, char ** tep, int nonewline)
156 /*@modifies *tp, **tp, *tep, **tep @*/
157 {
158 char *t, *te;
159
160 t = *tp;
161 te = *tep;
162 if (te > t) {
163 if (!nonewline) {
164 *te++ = '\n';
165 *te = '\0';
166 }
167 rpmlog(RPMLOG_NOTICE, "%s", t);
168 te = t;
169 *t = '\0';
170 }
171 *tp = t;
172 *tep = te;
173 }
174
175 int showQueryPackage(QVA_t qva, rpmts ts, Header h)
176 {
177 int scareMem = 0;
178 rpmfi fi = NULL;
179 size_t tb = 2 * BUFSIZ;
180 size_t sb;
181 char * t, * te;
182 char * prefix = NULL;
183 int rc = 0; /* XXX FIXME: need real return code */
184 int i;
185
186 te = t = xmalloc(tb);
187 *te = '\0';
188
189 if (qva->qva_queryFormat != NULL) {
190 const char * str;
191 /*@-type@*/ /* FIX rpmtsGetRDB()? */
192 (void) headerSetRpmdb(h, ts->rdb);
193 /*@=type@*/
194 str = queryHeader(h, qva->qva_queryFormat);
195 (void) headerSetRpmdb(h, NULL);
196 if (str) {
197 size_t tx = (te - t);
198
199 sb = strlen(str);
200 if (sb) {
201 tb += sb;
202 t = xrealloc(t, tb);
203 te = t + tx;
204 }
205 /*@-usereleased@*/
206 te = stpcpy(te, str);
207 /*@=usereleased@*/
208 str = _free(str);
209 flushBuffer(&t, &te, 1);
210 }
211 }
212
213 if (!(qva->qva_flags & QUERY_FOR_LIST))
214 goto exit;
215
216 fi = rpmfiNew(ts, h, RPMTAG_BASENAMES, scareMem);
217 if (rpmfiFC(fi) <= 0) {
218 te = stpcpy(te, _("(contains no files)"));
219 goto exit;
220 }
221
222 fi = rpmfiInit(fi, 0);
223 if (fi != NULL)
224 while ((i = rpmfiNext(fi)) >= 0) {
225 rpmfileAttrs fflags;
226 unsigned short fmode;
227 unsigned short frdev;
228 unsigned int fmtime;
229 rpmfileState fstate;
230 size_t fsize;
231 const char * fn;
232 const char * fdigest;
233 const char * fuser;
234 const char * fgroup;
235 const char * flink;
236 rpmuint32_t fnlink;
237
238 fflags = rpmfiFFlags(fi);
239 fmode = rpmfiFMode(fi);
240 frdev = rpmfiFRdev(fi);
241 fmtime = rpmfiFMtime(fi);
242 fstate = rpmfiFState(fi);
243 fsize = rpmfiFSize(fi);
244 fn = rpmfiFN(fi);
245 { static char hex[] = "0123456789abcdef";
246 int dalgo = 0;
247 size_t dlen = 0;
248 const unsigned char * digest = rpmfiDigest(fi, &dalgo, &dlen);
249 char * p;
250 size_t j;
251 fdigest = p = xcalloc(1, ((2 * dlen) + 1));
252 for (j = 0; j < dlen; j++) {
253 unsigned k = *digest++;
254 *p++ = hex[ (k >> 4) & 0xf ];
255 *p++ = hex[ (k ) & 0xf ];
256 }
257 *p = '\0';
258 }
259 fuser = rpmfiFUser(fi);
260 fgroup = rpmfiFGroup(fi);
261 flink = rpmfiFLink(fi);
262 fnlink = rpmfiFNlink(fi);
263 assert(fn != NULL);
264 assert(fdigest != NULL);
265
266 /* If querying only docs, skip non-doc files. */
267 if ((qva->qva_flags & QUERY_FOR_DOCS) && !(fflags & RPMFILE_DOC))
268 continue;
269
270 /* If querying only configs, skip non-config files. */
271 if ((qva->qva_flags & QUERY_FOR_CONFIG) && !(fflags & RPMFILE_CONFIG))
272 continue;
273
274 /* If not querying %config, skip config files. */
275 if ((qva->qva_fflags & RPMFILE_CONFIG) && (fflags & RPMFILE_CONFIG))
276 continue;
277
278 /* If not querying %doc, skip doc files. */
279 if ((qva->qva_fflags & RPMFILE_DOC) && (fflags & RPMFILE_DOC))
280 continue;
281
282 /* If not querying %ghost, skip ghost files. */
283 if ((qva->qva_fflags & RPMFILE_GHOST) && (fflags & RPMFILE_GHOST))
284 continue;
285
286 /* Insure space for header derived data */
287 sb = 0;
288 if (fn) sb += strlen(fn);
289 if (fdigest) sb += strlen(fdigest);
290 if (fuser) sb += strlen(fuser);
291 if (fgroup) sb += strlen(fgroup);
292 if (flink) sb += strlen(flink);
293 if ((sb + BUFSIZ) > tb) {
294 size_t tx = (te - t);
295 tb += sb + BUFSIZ;
296 t = xrealloc(t, tb);
297 te = t + tx;
298 }
299
300 if (!rpmIsVerbose() && prefix)
301 te = stpcpy(te, prefix);
302
303 if (qva->qva_flags & QUERY_FOR_STATE) {
304 switch (fstate) {
305 case RPMFILE_STATE_NORMAL:
306 te = stpcpy(te, _("normal "));
307 /*@switchbreak@*/ break;
308 case RPMFILE_STATE_REPLACED:
309 te = stpcpy(te, _("replaced "));
310 /*@switchbreak@*/ break;
311 case RPMFILE_STATE_NOTINSTALLED:
312 te = stpcpy(te, _("not installed "));
313 /*@switchbreak@*/ break;
314 case RPMFILE_STATE_NETSHARED:
315 te = stpcpy(te, _("net shared "));
316 /*@switchbreak@*/ break;
317 case RPMFILE_STATE_WRONGCOLOR:
318 te = stpcpy(te, _("wrong color "));
319 /*@switchbreak@*/ break;
320 case RPMFILE_STATE_MISSING:
321 te = stpcpy(te, _("(no state) "));
322 /*@switchbreak@*/ break;
323 default:
324 sprintf(te, _("(unknown %3d) "), fstate);
325 te += strlen(te);
326 /*@switchbreak@*/ break;
327 }
328 }
329
330 if (qva->qva_flags & QUERY_FOR_DUMPFILES) {
331 sprintf(te, "%s %d %d %s 0%o ",
332 fn, (int)fsize, fmtime, fdigest, fmode);
333 te += strlen(te);
334
335 if (fuser && fgroup) {
336 /*@-nullpass@*/
337 sprintf(te, "%s %s", fuser, fgroup);
338 /*@=nullpass@*/
339 te += strlen(te);
340 } else {
341 rpmlog(RPMLOG_CRIT, _("package without owner/group tags\n"));
342 }
343
344 sprintf(te, " %s %s %u ",
345 fflags & RPMFILE_CONFIG ? "1" : "0",
346 fflags & RPMFILE_DOC ? "1" : "0",
347 frdev);
348 te += strlen(te);
349
350 sprintf(te, "%s", (flink && *flink ? flink : "X"));
351 te += strlen(te);
352 } else
353 if (!rpmIsVerbose()) {
354 te = stpcpy(te, fn);
355 }
356 else {
357
358 /* XXX Adjust directory link count and size for display output. */
359 if (S_ISDIR(fmode)) {
360 fnlink++;
361 fsize = 0;
362 }
363
364 if (fuser && fgroup) {
365 /*@-nullpass@*/
366 printFileInfo(te, fn, fsize, fmode, fmtime, frdev, fnlink,
367 fuser, fgroup, flink);
368 /*@=nullpass@*/
369 te += strlen(te);
370 } else {
371 rpmlog(RPMLOG_CRIT, _("package without owner/group tags\n"));
372 }
373 }
374 flushBuffer(&t, &te, 0);
375 fdigest = _free(fdigest);
376 }
377
378 rc = 0;
379
380 exit:
381 flushBuffer(&t, &te, 0);
382 t = _free(t);
383
384 fi = rpmfiFree(fi);
385 return rc;
386 }
387
388 static int rpmgiShowMatches(QVA_t qva, rpmts ts)
389 /*@globals rpmGlobalMacroContext, h_errno, internalState @*/
390 /*@modifies qva, rpmGlobalMacroContext, h_errno, internalState @*/
391 {
392 rpmgi gi = qva->qva_gi;
393 rpmRC rpmrc = RPMRC_NOTFOUND;
394 int ec = 0;
395
396 while ((rpmrc = rpmgiNext(gi)) == RPMRC_OK) {
397 Header h;
398 int rc;
399
400 #ifdef NOTYET /* XXX exiting here will leave stale locks. */
401 (void) rpmdbCheckSignals();
402 #endif
403
404 h = rpmgiHeader(gi);
405 if (h == NULL) /* XXX perhaps stricter break instead? */
406 continue;
407 if ((rc = qva->qva_showPackage(qva, ts, h)) != 0)
408 ec = rc;
409 if (qva->qva_source == RPMQV_DBOFFSET)
410 break;
411 }
412 if (ec == 0 && rpmrc == RPMRC_FAIL)
413 ec++;
414 return ec;
415 }
416
417 int rpmcliShowMatches(QVA_t qva, rpmts ts)
418 {
419 Header h;
420 int ec = 1;
421
422 qva->qva_showFAIL = qva->qva_showOK = 0;
423 while ((h = rpmmiNext(qva->qva_mi)) != NULL) {
424 ec = qva->qva_showPackage(qva, ts, h);
425 if (ec)
426 qva->qva_showFAIL++;
427 else
428 qva->qva_showOK++;
429 if (qva->qva_source == RPMQV_DBOFFSET)
430 break;
431 }
432 qva->qva_mi = rpmmiFree(qva->qva_mi);
433 return ec;
434 }
435
441 static inline unsigned char nibble(char c)
442 /*@*/
443 {
444 if (c >= '0' && c <= '9')
445 return (c - '0');
446 if (c >= 'A' && c <= 'F')
447 return (c - 'A') + 10;
448 if (c >= 'a' && c <= 'f')
449 return (c - 'a') + 10;
450 return 0;
451 }
452
453 int rpmQueryVerify(QVA_t qva, rpmts ts, const char * arg)
454 {
455 int res = 0;
456 const char * s;
457 int i;
458 int provides_checked = 0;
459
460 (void) rpmdbCheckSignals();
461
462 if (qva->qva_showPackage == NULL)
463 return 1;
464
465 switch (qva->qva_source) {
466 #ifdef NOTYET
467 default:
468 #endif
469 case RPMQV_GROUP:
470 case RPMQV_TRIGGEREDBY:
471 case RPMQV_WHATCONFLICTS:
472 case RPMQV_WHATOBSOLETES:
473 qva->qva_mi = rpmtsInitIterator(ts, qva->qva_source, arg, 0);
474 if (qva->qva_mi == NULL) {
475 rpmlog(RPMLOG_NOTICE, _("key \"%s\" not found in %s table\n"),
476 arg, tagName((rpmTag)qva->qva_source));
477 res = 1;
478 } else
479 res = rpmcliShowMatches(qva, ts);
480 break;
481
482 case RPMQV_RPM:
483 res = rpmgiShowMatches(qva, ts);
484 break;
485
486 case RPMQV_ALL:
487 res = rpmgiShowMatches(qva, ts);
488 break;
489
490 case RPMQV_HDLIST:
491 res = rpmgiShowMatches(qva, ts);
492 break;
493
494 case RPMQV_FTSWALK:
495 res = rpmgiShowMatches(qva, ts);
496 break;
497
498 case RPMQV_SPECSRPM:
499 case RPMQV_SPECFILE:
500 res = ((qva->qva_specQuery != NULL)
501 ? qva->qva_specQuery(ts, qva, arg) : 1);
502 break;
503
504 #ifdef DYING
505 case RPMQV_GROUP:
506 qva->qva_mi = rpmtsInitIterator(ts, RPMTAG_GROUP, arg, 0);
507 if (qva->qva_mi == NULL) {
508 rpmlog(RPMLOG_ERR,
509 _("group %s does not contain any packages\n"), arg);
510 res = 1;
511 } else
512 res = rpmcliShowMatches(qva, ts);
513 break;
514
515 case RPMQV_TRIGGEREDBY:
516 qva->qva_mi = rpmtsInitIterator(ts, RPMTAG_TRIGGERNAME, arg, 0);
517 if (qva->qva_mi == NULL) {
518 rpmlog(RPMLOG_NOTICE, _("no package triggers %s\n"), arg);
519 res = 1;
520 } else
521 res = rpmcliShowMatches(qva, ts);
522 break;
523 #endif
524
525 case RPMQV_SOURCEPKGID:
526 case RPMQV_PKGID:
527 { unsigned char MD5[16];
528 unsigned char * t;
529 rpmuint32_t tag;
530
531 for (i = 0, s = arg; *s && isxdigit(*s); s++, i++)
532 {};
533 if (i != 32) {
534 rpmlog(RPMLOG_NOTICE, _("malformed %s: %s\n"), "pkgid", arg);
535 return 1;
536 }
537
538 MD5[0] = '\0';
539 for (i = 0, t = MD5, s = arg; i < 16; i++, t++, s += 2)
540 *t = (nibble(s[0]) << 4) | nibble(s[1]);
541
542 tag = (qva->qva_source == RPMQV_PKGID
543 ? RPMTAG_SOURCEPKGID : RPMTAG_PKGID);
544 qva->qva_mi = rpmtsInitIterator(ts, tag, MD5, sizeof(MD5));
545 if (qva->qva_mi == NULL) {
546 rpmlog(RPMLOG_NOTICE, _("no package matches %s: %s\n"),
547 "pkgid", arg);
548 res = 1;
549 } else
550 res = rpmcliShowMatches(qva, ts);
551 } break;
552
553 case RPMQV_HDRID:
554 for (i = 0, s = arg; *s && isxdigit(*s); s++, i++)
555 {};
556 if (i != 40) {
557 rpmlog(RPMLOG_NOTICE, _("malformed %s: %s\n"), "hdrid", arg);
558 return 1;
559 }
560
561 qva->qva_mi = rpmtsInitIterator(ts, RPMTAG_SHA1HEADER, arg, 0);
562 if (qva->qva_mi == NULL) {
563 rpmlog(RPMLOG_NOTICE, _("no package matches %s: %s\n"),
564 "hdrid", arg);
565 res = 1;
566 } else
567 res = rpmcliShowMatches(qva, ts);
568 break;
569
570 case RPMQV_FILEID:
571 { unsigned char * t;
572 unsigned char * digest;
573 size_t dlen;
574
575 /* Insure even no. of digits and at least 8 digits. */
576 for (dlen = 0, s = arg; *s && isxdigit(*s); s++, dlen++)
577 {};
578 if ((dlen & 1) || dlen < 8) {
579 rpmlog(RPMLOG_ERR, _("malformed %s: %s\n"), "fileid", arg);
580 return 1;
581 }
582
583 dlen /= 2;
584 digest = memset(alloca(dlen), 0, dlen);
585 for (t = digest, s = arg; *s; t++, s += 2)
586 *t = (nibble(s[0]) << 4) | nibble(s[1]);
587
588 qva->qva_mi = rpmtsInitIterator(ts, RPMTAG_FILEDIGESTS, digest, dlen);
589 if (qva->qva_mi == NULL) {
590 rpmlog(RPMLOG_NOTICE, _("no package matches %s: %s\n"),
591 "fileid", arg);
592 res = 1;
593 } else
594 res = rpmcliShowMatches(qva, ts);
595 } break;
596
597 case RPMQV_TID:
598 { int mybase = 10;
599 const char * myarg = arg;
600 char * end = NULL;
601 unsigned iid;
602
603 /* XXX should be in strtoul */
604 if (*myarg == '0') {
605 myarg++;
606 mybase = 8;
607 if (*myarg == 'x') {
608 myarg++;
609 mybase = 16;
610 }
611 }
612 iid = (unsigned) strtoul(myarg, &end, mybase);
613 if ((*end) || (end == arg) || (iid == UINT_MAX)) {
614 rpmlog(RPMLOG_ERR, _("malformed %s: %s\n"), "tid", arg);
615 return 1;
616 }
617 qva->qva_mi = rpmtsInitIterator(ts, RPMTAG_INSTALLTID, &iid, sizeof(iid));
618 if (qva->qva_mi == NULL) {
619 rpmlog(RPMLOG_NOTICE, _("no package matches %s: %s\n"),
620 "tid", arg);
621 res = 1;
622 } else
623 res = rpmcliShowMatches(qva, ts);
624 } break;
625
626 case RPMQV_WHATNEEDS:
627 case RPMQV_WHATREQUIRES:
628 qva->qva_mi = rpmtsInitIterator(ts, RPMTAG_REQUIRENAME, arg, 0);
629 if (qva->qva_mi == NULL) {
630 rpmlog(RPMLOG_NOTICE, _("no package requires %s\n"), arg);
631 res = 1;
632 } else
633 res = rpmcliShowMatches(qva, ts);
634 break;
635
636 case RPMQV_WHATPROVIDES:
637 if (arg[0] != '/') {
638 provides_checked = 1;
639 qva->qva_mi = rpmtsInitIterator(ts, RPMTAG_PROVIDENAME, arg, 0);
640 if (qva->qva_mi == NULL) {
641 rpmlog(RPMLOG_NOTICE, _("no package provides %s\n"), arg);
642 res = 1;
643 } else
644 res = rpmcliShowMatches(qva, ts);
645 break;
646 }
647 /*@fallthrough@*/
648 case RPMQV_PATH:
649 { char * fn;
650
651 for (s = arg; *s != '\0'; s++)
652 if (!(*s == '.' || *s == '/'))
653 /*@loopbreak@*/ break;
654
655 if (*s == '\0') {
656 char fnbuf[PATH_MAX];
657 fn = Realpath(arg, fnbuf);
658 fn = xstrdup( (fn != NULL ? fn : arg) );
659 } else if (*arg != '/') {
660 const char *curDir = currentDirectory();
661 fn = (char *) rpmGetPath(curDir, "/", arg, NULL);
662 curDir = _free(curDir);
663 } else
664 fn = xstrdup(arg);
665 assert(fn != NULL);
666 (void) rpmCleanPath(fn);
667
668 qva->qva_mi = rpmtsInitIterator(ts, RPMTAG_BASENAMES, fn, 0);
669 if (qva->qva_mi == NULL && !provides_checked)
670 qva->qva_mi = rpmtsInitIterator(ts, RPMTAG_PROVIDENAME, fn, 0);
671
672 if (qva->qva_mi == NULL) {
673 struct stat sb;
674 if (Lstat(fn, &sb) != 0)
675 rpmlog(RPMLOG_NOTICE, _("file %s: %s\n"), fn, strerror(errno));
676 else
677 rpmlog(RPMLOG_NOTICE,
678 _("file %s is not owned by any package\n"), fn);
679 res = 1;
680 } else
681 res = rpmcliShowMatches(qva, ts);
682
683 fn = _free(fn);
684 } break;
685
686 case RPMQV_DBOFFSET:
687 { int mybase = 10;
688 const char * myarg = arg;
689 char * end = NULL;
690 unsigned recOffset;
691
692 /* XXX should be in strtoul */
693 if (*myarg == '0') {
694 myarg++;
695 mybase = 8;
696 if (*myarg == 'x') {
697 myarg++;
698 mybase = 16;
699 }
700 }
701 recOffset = (unsigned) strtoul(myarg, &end, mybase);
702 if ((*end) || (end == arg) || (recOffset == UINT_MAX)) {
703 rpmlog(RPMLOG_NOTICE, _("invalid package number: %s\n"), arg);
704 return 1;
705 }
706 rpmlog(RPMLOG_DEBUG, D_("package record number: %u\n"), recOffset);
707 qva->qva_mi = rpmtsInitIterator(ts, RPMDBI_PACKAGES, &recOffset, sizeof(recOffset));
708 if (qva->qva_mi == NULL) {
709 rpmlog(RPMLOG_NOTICE,
710 _("record %u could not be read\n"), recOffset);
711 res = 1;
712 } else
713 res = rpmcliShowMatches(qva, ts);
714 } break;
715
716 case RPMQV_PACKAGE:
717 /* XXX HACK to get rpmdbFindByLabel out of the API */
718 qva->qva_mi = rpmtsInitIterator(ts, RPMDBI_LABEL, arg, 0);
719 if (qva->qva_mi == NULL) {
720 rpmlog(RPMLOG_NOTICE, _("package %s is not installed\n"), arg);
721 res = 1;
722 } else {
723 res = rpmcliShowMatches(qva, ts);
724 /* detect foo.bogusarch empty iterations. */
725 if (qva->qva_showOK == 0 && qva->qva_showFAIL == 0) {
726 rpmlog(RPMLOG_NOTICE, _("package %s is not installed\n"), arg);
727 res = 1;
728 }
729 }
730 break;
731 }
732
733 return res;
734 }
735
736 int rpmcliArgIter(rpmts ts, QVA_t qva, ARGV_t argv)
737 /*@globals rpmioFtsOpts @*/
738 /*@modifies rpmioFtsOpts @*/
739 {
740 rpmRC rpmrc = RPMRC_NOTFOUND;
741 int ec = 0;
742
743 switch (qva->qva_source) {
744 case RPMQV_ALL:
745 qva->qva_gi = rpmgiNew(ts, RPMDBI_PACKAGES, NULL, 0);
746 qva->qva_rc = rpmgiSetArgs(qva->qva_gi, argv, rpmioFtsOpts, RPMGI_NONE);
747
748 if (rpmgiGetFlags(qva->qva_gi) & RPMGI_TSADD) /* Load the ts with headers. */
749 while ((rpmrc = rpmgiNext(qva->qva_gi)) == RPMRC_OK)
750 {};
751 if (rpmrc != RPMRC_NOTFOUND)
752 return 1; /* XXX should be no. of failures. */
753
754 /*@-nullpass@*/ /* FIX: argv can be NULL, cast to pass argv array */
755 ec = rpmQueryVerify(qva, ts, (const char *) argv);
756 /*@=nullpass@*/
757 rpmtsEmpty(ts);
758 break;
759 case RPMQV_RPM:
760 qva->qva_gi = rpmgiNew(ts, RPMDBI_ARGLIST, NULL, 0);
761 qva->qva_rc = rpmgiSetArgs(qva->qva_gi, argv, rpmioFtsOpts, giFlags);
762
763 if (rpmgiGetFlags(qva->qva_gi) & RPMGI_TSADD) /* Load the ts with headers. */
764 while ((rpmrc = rpmgiNext(qva->qva_gi)) == RPMRC_OK)
765 {};
766 if (rpmrc != RPMRC_NOTFOUND)
767 return 1; /* XXX should be no. of failures. */
768
769 /*@-nullpass@*/ /* FIX: argv can be NULL, cast to pass argv array */
770 ec = rpmQueryVerify(qva, ts, NULL);
771 /*@=nullpass@*/
772 rpmtsEmpty(ts);
773 break;
774 case RPMQV_HDLIST:
775 qva->qva_gi = rpmgiNew(ts, RPMDBI_HDLIST, NULL, 0);
776 qva->qva_rc = rpmgiSetArgs(qva->qva_gi, argv, rpmioFtsOpts, giFlags);
777
778 if (rpmgiGetFlags(qva->qva_gi) & RPMGI_TSADD) /* Load the ts with headers. */
779 while ((rpmrc = rpmgiNext(qva->qva_gi)) == RPMRC_OK)
780 {};
781 if (rpmrc != RPMRC_NOTFOUND)
782 return 1; /* XXX should be no. of failures. */
783
784 /*@-nullpass@*/ /* FIX: argv can be NULL, cast to pass argv array */
785 ec = rpmQueryVerify(qva, ts, NULL);
786 /*@=nullpass@*/
787 rpmtsEmpty(ts);
788 break;
789 case RPMQV_FTSWALK:
790 if (rpmioFtsOpts == 0)
791 rpmioFtsOpts = (FTS_COMFOLLOW | FTS_LOGICAL | FTS_NOSTAT);
792 qva->qva_gi = rpmgiNew(ts, RPMDBI_FTSWALK, NULL, 0);
793 qva->qva_rc = rpmgiSetArgs(qva->qva_gi, argv, rpmioFtsOpts, giFlags);
794
795 if (rpmgiGetFlags(qva->qva_gi) & RPMGI_TSADD) /* Load the ts with headers. */
796 while ((rpmrc = rpmgiNext(qva->qva_gi)) == RPMRC_OK)
797 {};
798 if (rpmrc != RPMRC_NOTFOUND)
799 return 1; /* XXX should be no. of failures. */
800
801 /*@-nullpass@*/ /* FIX: argv can be NULL, cast to pass argv array */
802 ec = rpmQueryVerify(qva, ts, NULL);
803 /*@=nullpass@*/
804 rpmtsEmpty(ts);
805 break;
806 default:
807 if (giFlags & RPMGI_TSADD) {
808 qva->qva_gi = rpmgiNew(ts, RPMDBI_LABEL, NULL, 0);
809 qva->qva_rc = rpmgiSetArgs(qva->qva_gi, argv, rpmioFtsOpts,
810 (giFlags | (RPMGI_NOGLOB )));
811 if (rpmgiGetFlags(qva->qva_gi) & RPMGI_TSADD) /* Load the ts with headers. */
812 while ((rpmrc = rpmgiNext(qva->qva_gi)) == RPMRC_OK)
813 {};
814 if (rpmrc != RPMRC_NOTFOUND)
815 return 1; /* XXX should be no. of failures. */
816 qva->qva_source = RPMQV_ALL;
817 /*@-nullpass@*/ /* FIX: argv can be NULL, cast to pass argv array */
818 ec = rpmQueryVerify(qva, ts, NULL);
819 /*@=nullpass@*/
820 rpmtsEmpty(ts);
821 } else {
822 qva->qva_gi = rpmgiNew(ts, RPMDBI_ARGLIST, NULL, 0);
823 qva->qva_rc = rpmgiSetArgs(qva->qva_gi, argv, rpmioFtsOpts,
824 (giFlags | (RPMGI_NOGLOB|RPMGI_NOHEADER)));
825 while ((rpmrc = rpmgiNext(qva->qva_gi)) == RPMRC_OK) {
826 const char * path;
827 path = rpmgiHdrPath(qva->qva_gi);
828 assert(path != NULL);
829 ec += rpmQueryVerify(qva, ts, path);
830 rpmtsEmpty(ts);
831 }
832 }
833 break;
834 }
835
836 qva->qva_gi = rpmgiFree(qva->qva_gi);
837
838 return ec;
839 }
840
841 int rpmcliQuery(rpmts ts, QVA_t qva, const char ** argv)
842 {
843 rpmdepFlags depFlags = qva->depFlags, odepFlags;
844 rpmtransFlags transFlags = qva->transFlags, otransFlags;
845 rpmVSFlags vsflags, ovsflags;
846 int ec = 0;
847
848 if (qva->qva_showPackage == NULL)
849 qva->qva_showPackage = showQueryPackage;
850
851 /* If --queryformat unspecified, then set default now. */
852 if (!(qva->qva_flags & _QUERY_FOR_BITS) && qva->qva_queryFormat == NULL) {
853 qva->qva_queryFormat = rpmExpand("%{?_query_all_fmt}\n", NULL);
854 if (!(qva->qva_queryFormat != NULL && *qva->qva_queryFormat != '\0')) {
855 qva->qva_queryFormat = _free(qva->qva_queryFormat);
856 qva->qva_queryFormat = xstrdup("%{name}-%{version}-%{release}.%{arch}\n");
857 }
858 }
859
860 vsflags = rpmExpandNumeric("%{?_vsflags_query}");
861 if (qva->qva_flags & VERIFY_DIGEST)
862 vsflags |= _RPMVSF_NODIGESTS;
863 if (qva->qva_flags & VERIFY_SIGNATURE)
864 vsflags |= _RPMVSF_NOSIGNATURES;
865 if (qva->qva_flags & VERIFY_HDRCHK)
866 vsflags |= RPMVSF_NOHDRCHK;
867
868 odepFlags = rpmtsSetDFlags(ts, depFlags);
869 otransFlags = rpmtsSetFlags(ts, transFlags);
870 ovsflags = rpmtsSetVSFlags(ts, vsflags);
871 ec = rpmcliArgIter(ts, qva, argv);
872 vsflags = rpmtsSetVSFlags(ts, ovsflags);
873 transFlags = rpmtsSetFlags(ts, otransFlags);
874 depFlags = rpmtsSetDFlags(ts, odepFlags);
875
876 if (qva->qva_showPackage == showQueryPackage)
877 qva->qva_showPackage = NULL;
878
879 return ec;
880 }