15 /*@access Header@*/ /* XXX compared with NULL */
16 /*@access rpmdbMatchIterator@*/ /* XXX compared with NULL */
18 /* ======================================================================== */
19 static char * permsString(int mode)
21 char *perms = xstrdup("----------");
25 else if (S_ISLNK(mode))
27 else if (S_ISFIFO(mode))
29 else if (S_ISSOCK(mode))
31 else if (S_ISCHR(mode))
33 else if (S_ISBLK(mode))
37 if (mode & S_IRUSR) perms[1] = 'r';
38 if (mode & S_IWUSR) perms[2] = 'w';
39 if (mode & S_IXUSR) perms[3] = 'x';
41 if (mode & S_IRGRP) perms[4] = 'r';
42 if (mode & S_IWGRP) perms[5] = 'w';
43 if (mode & S_IXGRP) perms[6] = 'x';
45 if (mode & S_IROTH) perms[7] = 'r';
46 if (mode & S_IWOTH) perms[8] = 'w';
47 if (mode & S_IXOTH) perms[9] = 'x';
50 perms[3] = ((mode & S_IXUSR) ? 's' : 'S');
53 perms[6] = ((mode & S_IXGRP) ? 's' : 'S');
56 perms[9] = ((mode & S_IXOTH) ? 't' : 'T');
62 static void printFileInfo(char * te, const char * name,
63 unsigned int size, unsigned short mode,
65 unsigned short rdev, unsigned int nlink,
66 const char * owner, const char * group,
67 int uid, int gid, const char * linkto)
70 char ownerfield[9], groupfield[9];
71 char timefield[100] = "";
72 time_t when = mtime; /* important if sizeof(int_32) ! sizeof(time_t) */
75 static struct tm nowtm;
76 const char * namefield = name;
79 /* On first call, grab snapshot of now */
83 nowtm = *tm; /* structure assignment */
86 perms = permsString(mode);
89 strncpy(ownerfield, owner, 8);
91 sprintf(ownerfield, "%-8d", uid);
95 strncpy(groupfield, group, 8);
97 sprintf(groupfield, "%-8d", gid);
100 /* this is normally right */
101 sprintf(sizefield, "%12u", size);
103 /* this knows too much about dev_t */
106 char *nf = alloca(strlen(name) + sizeof(" -> ") + strlen(linkto));
107 sprintf(nf, "%s -> %s", name, linkto);
109 } else if (S_ISCHR(mode)) {
111 sprintf(sizefield, "%3u, %3u", ((unsigned)(rdev >> 8) & 0xff),
112 ((unsigned)rdev & 0xff));
113 } else if (S_ISBLK(mode)) {
115 sprintf(sizefield, "%3u, %3u", ((unsigned)(rdev >> 8) & 0xff),
116 ((unsigned)rdev & 0xff));
119 /* Convert file mtime to display format */
120 tm = localtime(&when);
122 if (now > when + 6L * 30L * 24L * 60L * 60L || /* Old. */
123 now < when - 60L * 60L) /* In the future. */
125 /* The file is fairly old or in the future.
126 * POSIX says the cutoff is 6 months old;
127 * approximate this by 6*30 days.
128 * Allow a 1 hour slop factor for what is considered "the future",
129 * to allow for NFS server/client clock disagreement.
130 * Show the year instead of the time of day.
136 (void)strftime(timefield, sizeof(timefield) - 1, fmt, tm);
139 sprintf(te, "%s %4d %-8s%-8s %10s %s %s", perms,
140 (int)nlink, ownerfield, groupfield, sizefield, timefield, namefield);
141 if (perms) free(perms);
144 static inline const char * queryHeader(Header h, const char * qfmt)
149 str = headerSprintf(h, qfmt, rpmTagTable, rpmHeaderFormats, &errstr);
151 rpmError(RPMERR_QFMT, _("incorrect format: %s\n"), errstr);
155 static int countLinks(int_16 * fileRdevList, int_32 * fileInodeList, int nfiles,
160 /* XXX rpm-3.3.12 has not RPMTAG_FILEINODES */
161 if (!(fileRdevList && fileInodeList && nfiles > 0))
163 while (nfiles-- > 0) {
164 if (fileRdevList[nfiles] != fileRdevList[xfile])
166 if (fileInodeList[nfiles] != fileInodeList[xfile])
173 int showQueryPackage(QVA_t *qva, /*@unused@*/rpmdb rpmdb, Header h)
177 int queryFlags = qva->qva_flags;
178 const char *queryFormat = qva->qva_queryFormat;
181 char * prefix = NULL;
182 const char ** dirNames = NULL;
183 const char ** baseNames = NULL;
184 const char ** fileMD5List = NULL;
185 const char ** fileOwnerList = NULL;
186 const char ** fileGroupList = NULL;
187 const char ** fileLinktoList = NULL;
188 const char * fileStatesList;
189 int_32 * fileFlagsList, * fileMTimeList, * fileSizeList;
190 int_32 * fileUIDList = NULL;
191 int_32 * fileGIDList = NULL;
192 int_32 * fileInodeList = NULL;
193 uint_16 * fileModeList;
194 uint_16 * fileRdevList;
196 int rc = 0; /* XXX FIXME: need real return code */
200 te = t = xmalloc(BUFSIZ);
203 if (!queryFormat && !queryFlags) {
204 const char * name, * version, * release;
205 headerNVR(h, &name, &version, &release);
206 te = stpcpy(te, name);
207 te = stpcpy( stpcpy(te, "-"), version);
208 te = stpcpy( stpcpy(te, "-"), release);
213 const char * str = queryHeader(h, queryFormat);
216 size_t tb = (te - t);
217 size_t sb = strlen(str);
219 if (sb >= (BUFSIZ - tb)) {
220 t = xrealloc(t, BUFSIZ+sb);
223 te = stpcpy(te, str);
228 if (!(queryFlags & QUERY_FOR_LIST))
231 if (!headerGetEntry(h, RPMTAG_BASENAMES, &type,
232 (void **) &baseNames, &count)) {
233 te = stpcpy(te, _("(contains no files)"));
236 if (!headerGetEntry(h, RPMTAG_FILESTATES, &type,
237 (void **) &fileStatesList, &count)) {
238 fileStatesList = NULL;
240 headerGetEntry(h, RPMTAG_DIRNAMES, NULL, (void **) &dirNames, NULL);
241 headerGetEntry(h, RPMTAG_DIRINDEXES, NULL, (void **) &dirIndexes, NULL);
242 headerGetEntry(h, RPMTAG_FILEFLAGS, &type, (void **)&fileFlagsList, &count);
243 headerGetEntry(h, RPMTAG_FILESIZES, &type, (void **) &fileSizeList, &count);
244 headerGetEntry(h, RPMTAG_FILEMODES, &type, (void **) &fileModeList, &count);
245 headerGetEntry(h, RPMTAG_FILEMTIMES, &type, (void **)&fileMTimeList,&count);
246 headerGetEntry(h, RPMTAG_FILERDEVS, &type, (void **) &fileRdevList, &count);
247 headerGetEntry(h, RPMTAG_FILEINODES, &type, (void **)&fileInodeList,&count);
248 headerGetEntry(h, RPMTAG_FILELINKTOS,&type,(void **)&fileLinktoList,&count);
249 headerGetEntry(h, RPMTAG_FILEMD5S, &type, (void **) &fileMD5List, &count);
251 if (!headerGetEntry(h, RPMTAG_FILEUIDS, &type,
252 (void **) &fileUIDList, &count)) {
254 } else if (!headerGetEntry(h, RPMTAG_FILEGIDS, &type,
255 (void **) &fileGIDList, &count)) {
259 if (!headerGetEntry(h, RPMTAG_FILEUSERNAME, &type,
260 (void **) &fileOwnerList, &count)) {
261 fileOwnerList = NULL;
262 } else if (!headerGetEntry(h, RPMTAG_FILEGROUPNAME, &type,
263 (void **) &fileGroupList, &count)) {
264 fileGroupList = NULL;
267 for (i = 0; i < count; i++) {
268 /* If querying only docs, skip non-doc files. */
269 if ((queryFlags & QUERY_FOR_DOCS)
270 && !(fileFlagsList[i] & RPMFILE_DOC))
272 /* If querying only configs, skip non-config files. */
273 if ((queryFlags & QUERY_FOR_CONFIG)
274 && !(fileFlagsList[i] & RPMFILE_CONFIG))
277 if (!rpmIsVerbose() && prefix)
278 te = stpcpy(te, prefix);
280 if (queryFlags & QUERY_FOR_STATE) {
281 if (fileStatesList) {
282 switch (fileStatesList[i]) {
283 case RPMFILE_STATE_NORMAL:
284 te = stpcpy(te, _("normal ")); break;
285 case RPMFILE_STATE_REPLACED:
286 te = stpcpy(te, _("replaced ")); break;
287 case RPMFILE_STATE_NOTINSTALLED:
288 te = stpcpy(te, _("not installed ")); break;
289 case RPMFILE_STATE_NETSHARED:
290 te = stpcpy(te, _("net shared ")); break;
292 sprintf(te, _("(unknown %3d) "), (int)fileStatesList[i]);
297 te = stpcpy(te, _("(no state) "));
301 if (queryFlags & QUERY_FOR_DUMPFILES) {
302 sprintf(te, "%s%s %d %d %s 0%o ",
303 dirNames[dirIndexes[i]], baseNames[i],
304 fileSizeList[i], fileMTimeList[i],
305 fileMD5List[i], fileModeList[i]);
308 if (fileOwnerList && fileGroupList) {
309 sprintf(te, "%s %s", fileOwnerList[i], fileGroupList[i]);
311 } else if (fileUIDList && fileGIDList) {
312 sprintf(te, "%d %d", fileUIDList[i], fileGIDList[i]);
315 rpmError(RPMERR_INTERNAL,
316 _("package has neither file owner or id lists\n"));
319 sprintf(te, " %s %s %u ",
320 fileFlagsList[i] & RPMFILE_CONFIG ? "1" : "0",
321 fileFlagsList[i] & RPMFILE_DOC ? "1" : "0",
322 (unsigned)fileRdevList[i]);
325 if (strlen(fileLinktoList[i]))
326 sprintf(te, "%s", fileLinktoList[i]);
330 } else if (!rpmIsVerbose()) {
331 te = stpcpy(te, dirNames[dirIndexes[i]]);
332 te = stpcpy(te, baseNames[i]);
337 filespec = xmalloc(strlen(dirNames[dirIndexes[i]])
338 + strlen(baseNames[i]) + 1);
339 strcpy(filespec, dirNames[dirIndexes[i]]);
340 strcat(filespec, baseNames[i]);
342 nlink = countLinks(fileRdevList, fileInodeList, count, i);
343 if (fileOwnerList && fileGroupList) {
344 printFileInfo(te, filespec, fileSizeList[i],
345 fileModeList[i], fileMTimeList[i],
346 fileRdevList[i], nlink,
348 fileGroupList[i], -1,
349 -1, fileLinktoList[i]);
351 } else if (fileUIDList && fileGIDList) {
352 printFileInfo(te, filespec, fileSizeList[i],
353 fileModeList[i], fileMTimeList[i],
354 fileRdevList[i], nlink,
355 NULL, NULL, fileUIDList[i],
360 rpmError(RPMERR_INTERNAL,
361 _("package has neither file owner or id lists\n"));
369 rpmMessage(RPMMESS_NORMAL, "%s", t);
383 rpmMessage(RPMMESS_NORMAL, "%s", t);
386 if (dirNames) free(dirNames);
387 if (baseNames) free(baseNames);
388 if (fileLinktoList) free(fileLinktoList);
389 if (fileMD5List) free(fileMD5List);
390 if (fileOwnerList) free(fileOwnerList);
391 if (fileGroupList) free(fileGroupList);
396 printNewSpecfile(Spec spec)
398 Header h = spec->packages->header;
399 struct speclines *sl = spec->sl;
400 struct spectags *st = spec->st;
401 const char * msgstr = NULL;
404 if (sl == NULL || st == NULL)
407 for (i = 0; i < st->st_ntags; i++) {
408 struct spectag * t = st->st_t + i;
409 const char * tn = tagName(t->t_tag);
414 (void) stpcpy( stpcpy( stpcpy( fmt, "%{"), tn), "}\n");
415 if (msgstr) free((void *)msgstr);
416 msgstr = headerSprintf(h, fmt, rpmTagTable, rpmHeaderFormats, &errstr);
417 if (msgstr == NULL) {
418 rpmError(RPMERR_QFMT, _("can't query %s: %s\n"), tn, errstr);
425 free(sl->sl_lines[t->t_startx]);
426 sl->sl_lines[t->t_startx] = NULL;
427 if (t->t_lang && strcmp(t->t_lang, RPMBUILD_DEFAULT_LANG))
429 { char *buf = xmalloc(strlen(tn) + sizeof(": ") + strlen(msgstr));
430 (void) stpcpy( stpcpy( stpcpy(buf, tn), ": "), msgstr);
431 sl->sl_lines[t->t_startx] = buf;
434 case RPMTAG_DESCRIPTION:
435 for (j = 1; j < t->t_nlines; j++) {
436 free(sl->sl_lines[t->t_startx + j]);
437 sl->sl_lines[t->t_startx + j] = NULL;
439 if (t->t_lang && strcmp(t->t_lang, RPMBUILD_DEFAULT_LANG)) {
440 free(sl->sl_lines[t->t_startx]);
441 sl->sl_lines[t->t_startx] = NULL;
444 sl->sl_lines[t->t_startx + 1] = xstrdup(msgstr);
446 sl->sl_lines[t->t_startx + 2] = xstrdup("\n\n");
450 if (msgstr) free((void *)msgstr);
452 for (i = 0; i < sl->sl_nlines; i++) {
453 if (sl->sl_lines[i] == NULL)
455 printf("%s", sl->sl_lines[i]);
459 void rpmDisplayQueryTags(FILE * f)
461 const struct headerTagTableEntry * t;
463 const struct headerSprintfExtension * ext = rpmHeaderFormats;
465 for (i = 0, t = rpmTagTable; i < rpmTagTableSize; i++, t++) {
466 fprintf(f, "%s\n", t->name + 7);
470 if (ext->type == HEADER_EXT_MORE) {
474 /* XXX don't print query tags twice. */
475 for (i = 0, t = rpmTagTable; i < rpmTagTableSize; i++, t++) {
476 if (!strcmp(t->name, ext->name))
479 if (i >= rpmTagTableSize && ext->type == HEADER_EXT_TAG)
480 fprintf(f, "%s\n", ext->name + 7);
485 int showMatches(QVA_t *qva, rpmdbMatchIterator mi, QVF_t showPackage)
490 while ((h = rpmdbNextIterator(mi)) != NULL) {
492 if ((rc = showPackage(qva, rpmdbGetIteratorRpmDB(mi), h)) != 0)
495 rpmdbFreeIterator(mi);
500 * @todo Eliminate linkage loop into librpmbuild.a
502 int (*parseSpecVec) (Spec *specp, const char *specFile, const char *rootdir,
503 const char *buildRoot, int inBuildArch, const char *passPhrase,
504 char *cookie, int anyarch, int force) = NULL;
506 * @todo Eliminate linkage loop into librpmbuild.a
508 void (*freeSpecVec) (Spec spec) = NULL;
510 int rpmQueryVerify(QVA_t *qva, rpmQVSources source, const char * arg,
511 rpmdb rpmdb, QVF_t showPackage)
513 rpmdbMatchIterator mi = NULL;
523 const char ** argv = NULL;
526 rc = rpmGlob(arg, &argc, &argv);
529 for (i = 0; i < argc; i++) {
531 fd = Fopen(argv[i], "r.ufdio");
534 rpmError(RPMERR_OPEN, _("open of %s failed: %s\n"), argv[i],
546 retcode = rpmReadPackageHeader(fd, &h, &isSource, NULL, NULL);
553 rpmError(RPMERR_QUERY,
554 _("old format source packages cannot be queried\n"));
558 retcode = showPackage(qva, rpmdb, h);
562 rpmError(RPMERR_QUERY,
563 _("%s does not appear to be a RPM package\n"), argv[i]);
566 rpmError(RPMERR_QUERY,
567 _("query of %s failed\n"), argv[i]);
573 for (i = 0; i < argc; i++)
574 free((void *)argv[i]);
580 if (showPackage != showQueryPackage)
583 /* XXX Eliminate linkage dependency loop */
584 if (parseSpecVec == NULL || freeSpecVec == NULL)
589 char * buildRoot = NULL;
591 char * passPhrase = "";
596 rc = parseSpecVec(&spec, arg, "/", buildRoot, inBuildArch, passPhrase,
597 cookie, anyarch, force);
598 if (rc || spec == NULL) {
600 rpmError(RPMERR_QUERY,
601 _("query of specfile %s failed, can't parse\n"), arg);
602 if (spec != NULL) freeSpecVec(spec);
608 printNewSpecfile(spec);
614 for (pkg = spec->packages; pkg != NULL; pkg = pkg->next) {
615 showPackage(qva, NULL, pkg->header);
621 /* RPMDBI_PACKAGES */
622 mi = rpmdbInitIterator(rpmdb, RPMDBI_PACKAGES, NULL, 0);
624 rpmError(RPMERR_QUERYINFO, _("no packages\n"));
627 retcode = showMatches(qva, mi, showPackage);
632 mi = rpmdbInitIterator(rpmdb, RPMTAG_GROUP, arg, 0);
634 rpmError(RPMERR_QUERYINFO,
635 _("group %s does not contain any packages\n"), arg);
638 retcode = showMatches(qva, mi, showPackage);
642 case RPMQV_TRIGGEREDBY:
643 mi = rpmdbInitIterator(rpmdb, RPMTAG_TRIGGERNAME, arg, 0);
645 rpmError(RPMERR_QUERYINFO, _("no package triggers %s\n"), arg);
648 retcode = showMatches(qva, mi, showPackage);
652 case RPMQV_WHATREQUIRES:
653 mi = rpmdbInitIterator(rpmdb, RPMTAG_REQUIRENAME, arg, 0);
655 rpmError(RPMERR_QUERYINFO, _("no package requires %s\n"), arg);
658 retcode = showMatches(qva, mi, showPackage);
662 case RPMQV_WHATPROVIDES:
664 mi = rpmdbInitIterator(rpmdb, RPMTAG_PROVIDENAME, arg, 0);
666 rpmError(RPMERR_QUERYINFO, _("no package provides %s\n"), arg);
669 retcode = showMatches(qva, mi, showPackage);
678 for (s = arg; *s; s++)
679 if (!(*s == '.' || *s == '/')) break;
682 char fnbuf[PATH_MAX];
683 fn = /*@-unrecog@*/ realpath(arg, fnbuf) /*@=unrecog@*/;
684 fn = xstrdup( (fn ? fn : arg) );
687 (void) rpmCleanPath(fn);
689 mi = rpmdbInitIterator(rpmdb, RPMTAG_BASENAMES, fn, 0);
692 if (access(fn, F_OK) != 0)
696 rpmError(RPMERR_QUERY,
697 _("file %s: %s\n"), fn, strerror(myerrno));
700 rpmError(RPMERR_QUERYINFO,
701 _("file %s is not owned by any package\n"), fn);
706 retcode = showMatches(qva, mi, showPackage);
713 const char * myarg = arg;
716 /* XXX should be in strtoul */
725 recOffset = strtoul(myarg, &end, mybase);
726 if ((*end) || (end == arg) || (recOffset == ULONG_MAX)) {
727 rpmError(RPMERR_QUERY, _("invalid package number: %s\n"), arg);
730 rpmMessage(RPMMESS_DEBUG, _("package record number: %u\n"), recOffset);
731 /* RPMDBI_PACKAGES */
732 mi = rpmdbInitIterator(rpmdb, RPMDBI_PACKAGES, &recOffset, sizeof(recOffset));
734 rpmError(RPMERR_QUERY,
735 _("record %d could not be read\n"), recOffset);
738 retcode = showMatches(qva, mi, showPackage);
743 /* XXX HACK to get rpmdbFindByLabel out of the API */
744 mi = rpmdbInitIterator(rpmdb, RPMDBI_LABEL, arg, 0);
746 rpmError(RPMERR_QUERYINFO, _("package %s is not installed\n"), arg);
749 retcode = showMatches(qva, mi, showPackage);
757 int rpmQuery(QVA_t *qva, rpmQVSources source, const char * arg)
767 if (rpmdbOpen(qva->qva_prefix, &rpmdb, O_RDONLY, 0644))
772 rc = rpmQueryVerify(qva, source, arg, rpmdb, showQueryPackage);