query.c 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564
  1. /*
  2. * dpkg-query - program for query the dpkg database
  3. * query.c - status enquiry and listing options
  4. *
  5. * Copyright © 1995,1996 Ian Jackson <ian@chiark.greenend.org.uk>
  6. * Copyright © 2000,2001 Wichert Akkerman <wakkerma@debian.org>
  7. *
  8. * This is free software; you can redistribute it and/or modify
  9. * it under the terms of the GNU General Public License as
  10. * published by the Free Software Foundation; either version 2,
  11. * or (at your option) any later version.
  12. *
  13. * This is distributed in the hope that it will be useful, but
  14. * WITHOUT ANY WARRANTY; without even the implied warranty of
  15. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16. * GNU General Public License for more details.
  17. *
  18. * You should have received a copy of the GNU General Public
  19. * License along with dpkg; if not, write to the Free Software
  20. * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  21. */
  22. #include <config.h>
  23. #include <compat.h>
  24. #include <dpkg-i18n.h>
  25. #include <stdio.h>
  26. #include <string.h>
  27. #include <stdlib.h>
  28. #include <fnmatch.h>
  29. #include <unistd.h>
  30. #include <sys/types.h>
  31. #include <sys/stat.h>
  32. #include <sys/ioctl.h>
  33. #include <sys/termios.h>
  34. #include <fcntl.h>
  35. #if HAVE_LOCALE_H
  36. #include <locale.h>
  37. #endif
  38. #include <dpkg.h>
  39. #include <dpkg-db.h>
  40. #include <dpkg-priv.h>
  41. #include <myopt.h>
  42. #include "pkg-array.h"
  43. #include "filesdb.h"
  44. #include "main.h"
  45. static int failures = 0;
  46. static const char* showformat = "${Package}\t${Version}\n";
  47. static int getwidth(void) {
  48. int fd;
  49. int res;
  50. struct winsize ws;
  51. const char* columns;
  52. if ((columns=getenv("COLUMNS")) && ((res=atoi(columns))>0))
  53. return res;
  54. else if (!isatty(1))
  55. return -1;
  56. else {
  57. if ((fd=open("/dev/tty",O_RDONLY))!=-1) {
  58. if (ioctl(fd, TIOCGWINSZ, &ws)==-1)
  59. ws.ws_col=80;
  60. close(fd);
  61. }
  62. return ws.ws_col;
  63. }
  64. }
  65. static void
  66. list1package(struct pkginfo *pkg, int *head, struct pkg_array *array)
  67. {
  68. int i,l,w;
  69. static int nw,vw,dw;
  70. const char *pdesc;
  71. static char format[80] = "";
  72. if (format[0]==0) {
  73. w=getwidth();
  74. if (w == -1) {
  75. nw=14, vw=14, dw=44;
  76. for (i = 0; i < array->n_pkgs; i++) {
  77. const char *pdesc;
  78. int plen, vlen, dlen;
  79. pdesc = pkg->installed.valid ? pkg->installed.description : NULL;
  80. if (!pdesc) pdesc= _("(no description available)");
  81. plen = strlen(array->pkgs[i]->name);
  82. vlen = strlen(versiondescribe(&array->pkgs[i]->installed.version,
  83. vdew_nonambig));
  84. dlen= strcspn(pdesc, "\n");
  85. if (plen > nw) nw = plen;
  86. if (vlen > vw) vw = vlen;
  87. if (dlen > dw) dw = dlen;
  88. }
  89. } else {
  90. w-=80;
  91. if (w<0) w=0; /* lets not try to deal with terminals that are too small */
  92. w>>=2; /* halve that so we can add that to the both the name and description */
  93. nw=(14+w); /* name width */
  94. vw=(14+w); /* version width */
  95. dw=(44+(2*w)); /* description width */
  96. }
  97. sprintf(format,"%%c%%c%%c %%-%d.%ds %%-%d.%ds %%.*s\n", nw, nw, vw, vw);
  98. }
  99. if (!*head) {
  100. fputs(_("\
  101. Desired=Unknown/Install/Remove/Purge/Hold\n\
  102. | Status=Not/Inst/Cfg-files/Unpacked/Failed-cfg/Half-inst/trig-aWait/Trig-pend\n\
  103. |/ Err?=(none)/Hold/Reinst-required/X=both-problems (Status,Err: uppercase=bad)\n"), stdout);
  104. printf(format,'|','|','/', _("Name"), _("Version"), 40, _("Description"));
  105. printf("+++-"); /* status */
  106. for (l=0;l<nw;l++) printf("="); printf("-"); /* packagename */
  107. for (l=0;l<vw;l++) printf("="); printf("-"); /* version */
  108. for (l=0;l<dw;l++) printf("="); /* description */
  109. printf("\n");
  110. *head= 1;
  111. }
  112. if (!pkg->installed.valid) blankpackageperfile(&pkg->installed);
  113. limiteddescription(pkg,dw,&pdesc,&l);
  114. printf(format,
  115. "uihrp"[pkg->want],
  116. "ncHUFWti"[pkg->status],
  117. " R?#"[pkg->eflag],
  118. pkg->name,
  119. versiondescribe(&pkg->installed.version, vdew_nonambig),
  120. l, pdesc);
  121. }
  122. void listpackages(const char *const *argv) {
  123. struct pkg_array array;
  124. struct pkginfo *pkg;
  125. int i, head;
  126. modstatdb_init(admindir,msdbrw_readonly);
  127. pkg_array_init_from_db(&array);
  128. pkg_array_sort(&array, pkglistqsortcmp);
  129. head = 0;
  130. if (!*argv) {
  131. for (i = 0; i < array.n_pkgs; i++) {
  132. pkg = array.pkgs[i];
  133. if (pkg->status == stat_notinstalled) continue;
  134. list1package(pkg, &head, &array);
  135. }
  136. } else {
  137. int argc, ip, *found;
  138. for (argc = 0; argv[argc]; argc++);
  139. found = m_malloc(sizeof(int) * argc);
  140. memset(found, 0, sizeof(int) * argc);
  141. for (i = 0; i < array.n_pkgs; i++) {
  142. pkg = array.pkgs[i];
  143. for (ip = 0; ip < argc; ip++) {
  144. if (!fnmatch(argv[ip], pkg->name, 0)) {
  145. list1package(pkg, &head, &array);
  146. found[ip]++;
  147. break;
  148. }
  149. }
  150. }
  151. /* FIXME: we might get non-matching messages for sub-patterns specified
  152. * after their super-patterns, due to us skipping on first match. */
  153. for (ip = 0; ip < argc; ip++) {
  154. if (!found[ip]) {
  155. fprintf(stderr, _("No packages found matching %s.\n"), argv[ip]);
  156. failures++;
  157. }
  158. }
  159. }
  160. if (ferror(stdout)) werr("stdout");
  161. if (ferror(stderr)) werr("stderr");
  162. pkg_array_free(&array);
  163. modstatdb_shutdown();
  164. }
  165. static int searchoutput(struct filenamenode *namenode) {
  166. int found, i;
  167. struct filepackages *packageslump;
  168. if (namenode->divert) {
  169. const char *name_from = namenode->divert->camefrom ?
  170. namenode->divert->camefrom->name : namenode->name;
  171. const char *name_to = namenode->divert->useinstead ?
  172. namenode->divert->useinstead->name : namenode->name;
  173. if (namenode->divert->pkg) {
  174. printf(_("diversion by %s from: %s\n"),
  175. namenode->divert->pkg->name, name_from);
  176. printf(_("diversion by %s to: %s\n"),
  177. namenode->divert->pkg->name, name_to);
  178. } else {
  179. printf(_("local diversion from: %s\n"), name_from);
  180. printf(_("local diversion to: %s\n"), name_to);
  181. }
  182. }
  183. found= 0;
  184. for (packageslump= namenode->packages;
  185. packageslump;
  186. packageslump= packageslump->more) {
  187. for (i=0; i < PERFILEPACKAGESLUMP && packageslump->pkgs[i]; i++) {
  188. if (found) fputs(", ",stdout);
  189. fputs(packageslump->pkgs[i]->name,stdout);
  190. found++;
  191. }
  192. }
  193. if (found) printf(": %s\n",namenode->name);
  194. return found + (namenode->divert ? 1 : 0);
  195. }
  196. void searchfiles(const char *const *argv) {
  197. struct filenamenode *namenode;
  198. struct fileiterator *it;
  199. const char *thisarg;
  200. int found;
  201. struct varbuf path = VARBUF_INIT;
  202. static struct varbuf vb;
  203. if (!*argv)
  204. badusage(_("--search needs at least one file name pattern argument"));
  205. modstatdb_init(admindir,msdbrw_readonly|msdbrw_noavail);
  206. ensure_allinstfiles_available_quiet();
  207. ensure_diversions();
  208. while ((thisarg = *argv++) != NULL) {
  209. found= 0;
  210. /* Trim trailing slash and slash dot from the argument if it's
  211. * not a pattern, just a path.
  212. */
  213. if (!strpbrk(thisarg, "*[?\\")) {
  214. varbufreset(&path);
  215. varbufaddstr(&path, thisarg);
  216. varbufaddc(&path, '\0');
  217. path.used = rtrim_slash_slashdot(path.buf);
  218. thisarg = path.buf;
  219. }
  220. if (!strchr("*[?/",*thisarg)) {
  221. varbufreset(&vb);
  222. varbufaddc(&vb,'*');
  223. varbufaddstr(&vb,thisarg);
  224. varbufaddc(&vb,'*');
  225. varbufaddc(&vb,0);
  226. thisarg= vb.buf;
  227. }
  228. if (!strpbrk(thisarg, "*[?\\")) {
  229. namenode= findnamenode(thisarg, 0);
  230. found += searchoutput(namenode);
  231. } else {
  232. it= iterfilestart();
  233. while ((namenode = iterfilenext(it)) != NULL) {
  234. if (fnmatch(thisarg,namenode->name,0)) continue;
  235. found+= searchoutput(namenode);
  236. }
  237. iterfileend(it);
  238. }
  239. if (!found) {
  240. fprintf(stderr,_("dpkg: %s not found.\n"),thisarg);
  241. failures++;
  242. if (ferror(stderr)) werr("stderr");
  243. } else {
  244. if (ferror(stdout)) werr("stdout");
  245. }
  246. }
  247. modstatdb_shutdown();
  248. varbuffree(&path);
  249. }
  250. void enqperpackage(const char *const *argv) {
  251. const char *thisarg;
  252. struct fileinlist *file;
  253. struct pkginfo *pkg;
  254. struct filenamenode *namenode;
  255. if (!*argv)
  256. badusage(_("--%s needs at least one package name argument"), cipaction->olong);
  257. if (cipaction->arg==act_listfiles)
  258. modstatdb_init(admindir,msdbrw_readonly|msdbrw_noavail);
  259. else
  260. modstatdb_init(admindir,msdbrw_readonly);
  261. while ((thisarg = *argv++) != NULL) {
  262. pkg= findpackage(thisarg);
  263. switch (cipaction->arg) {
  264. case act_status:
  265. if (pkg->status == stat_notinstalled &&
  266. pkg->priority == pri_unknown &&
  267. !(pkg->section && *pkg->section) &&
  268. !pkg->files &&
  269. pkg->want == want_unknown &&
  270. !informative(pkg,&pkg->installed)) {
  271. fprintf(stderr,_("Package `%s' is not installed and no info is available.\n"),pkg->name);
  272. failures++;
  273. } else {
  274. writerecord(stdout, "<stdout>", pkg, &pkg->installed);
  275. }
  276. break;
  277. case act_printavail:
  278. if (!informative(pkg,&pkg->available)) {
  279. fprintf(stderr,_("Package `%s' is not available.\n"),pkg->name);
  280. failures++;
  281. } else {
  282. writerecord(stdout, "<stdout>", pkg, &pkg->available);
  283. }
  284. break;
  285. case act_listfiles:
  286. switch (pkg->status) {
  287. case stat_notinstalled:
  288. fprintf(stderr,_("Package `%s' is not installed.\n"),pkg->name);
  289. failures++;
  290. break;
  291. default:
  292. ensure_packagefiles_available(pkg);
  293. ensure_diversions();
  294. file= pkg->clientdata->files;
  295. if (!file) {
  296. printf(_("Package `%s' does not contain any files (!)\n"),pkg->name);
  297. } else {
  298. while (file) {
  299. namenode= file->namenode;
  300. puts(namenode->name);
  301. if (namenode->divert && !namenode->divert->camefrom) {
  302. if (!namenode->divert->pkg)
  303. printf(_("locally diverted to: %s\n"),
  304. namenode->divert->useinstead->name);
  305. else if (pkg == namenode->divert->pkg)
  306. printf(_("package diverts others to: %s\n"),
  307. namenode->divert->useinstead->name);
  308. else
  309. printf(_("diverted by %s to: %s\n"),
  310. namenode->divert->pkg->name,
  311. namenode->divert->useinstead->name);
  312. }
  313. file= file->next;
  314. }
  315. }
  316. break;
  317. }
  318. break;
  319. default:
  320. internerr("unknown action '%d'", cipaction->arg);
  321. }
  322. if (*(argv + 1) == NULL)
  323. putchar('\n');
  324. if (ferror(stdout)) werr("stdout");
  325. }
  326. if (failures) {
  327. fputs(_("Use dpkg --info (= dpkg-deb --info) to examine archive files,\n"
  328. "and dpkg --contents (= dpkg-deb --contents) to list their contents.\n"),stderr);
  329. if (ferror(stdout)) werr("stdout");
  330. }
  331. modstatdb_shutdown();
  332. }
  333. void showpackages(const char *const *argv) {
  334. struct pkg_array array;
  335. struct pkginfo *pkg;
  336. int i;
  337. struct lstitem* fmt = parseformat(showformat);
  338. if (!fmt) {
  339. failures++;
  340. return;
  341. }
  342. modstatdb_init(admindir,msdbrw_readonly);
  343. pkg_array_init_from_db(&array);
  344. pkg_array_sort(&array, pkglistqsortcmp);
  345. if (!*argv) {
  346. for (i = 0; i < array.n_pkgs; i++) {
  347. pkg = array.pkgs[i];
  348. if (pkg->status == stat_notinstalled) continue;
  349. show1package(fmt,pkg);
  350. }
  351. } else {
  352. int argc, ip, *found;
  353. for (argc = 0; argv[argc]; argc++);
  354. found = m_malloc(sizeof(int) * argc);
  355. memset(found, 0, sizeof(int) * argc);
  356. for (i = 0; i < array.n_pkgs; i++) {
  357. pkg = array.pkgs[i];
  358. for (ip = 0; ip < argc; ip++) {
  359. if (!fnmatch(argv[ip], pkg->name, 0)) {
  360. show1package(fmt, pkg);
  361. found[ip]++;
  362. break;
  363. }
  364. }
  365. }
  366. /* FIXME: we might get non-matching messages for sub-patterns specified
  367. * after their super-patterns, due to us skipping on first match. */
  368. for (ip = 0; ip < argc; ip++) {
  369. if (!found[ip]) {
  370. fprintf(stderr, _("No packages found matching %s.\n"), argv[ip]);
  371. failures++;
  372. }
  373. }
  374. }
  375. if (ferror(stdout)) werr("stdout");
  376. if (ferror(stderr)) werr("stderr");
  377. pkg_array_free(&array);
  378. freeformat(fmt);
  379. modstatdb_shutdown();
  380. }
  381. void
  382. printversion(void)
  383. {
  384. if (printf(_("Debian `%s' package management program query tool\n"),
  385. DPKGQUERY) < 0) werr("stdout");
  386. if (printf(_("This is free software; see the GNU General Public License version 2 or\n"
  387. "later for copying conditions. There is NO warranty.\n"
  388. "See %s --license for copyright and license details.\n"),
  389. DPKGQUERY) < 0) werr("stdout");
  390. }
  391. void
  392. usage(void)
  393. {
  394. if (printf(_(
  395. "Usage: %s [<option> ...] <command>\n"
  396. "\n"), DPKGQUERY) < 0) werr ("stdout");
  397. if (printf(_(
  398. "Commands:\n"
  399. " -s|--status <package> ... Display package status details.\n"
  400. " -p|--print-avail <package> ... Display available version details.\n"
  401. " -L|--listfiles <package> ... List files `owned' by package(s).\n"
  402. " -l|--list [<pattern> ...] List packages concisely.\n"
  403. " -W|--show <pattern> ... Show information on package(s).\n"
  404. " -S|--search <pattern> ... Find package(s) owning file(s).\n"
  405. "\n")) < 0) werr ("stdout");
  406. if (printf(_(
  407. " -h|--help Show this help message.\n"
  408. " --version Show the version.\n"
  409. " --license|--licence Show the copyright licensing terms.\n"
  410. "\n")) < 0) werr ("stdout");
  411. if (printf(_(
  412. "Options:\n"
  413. " --admindir=<directory> Use <directory> instead of %s.\n"
  414. " -f|--showformat=<format> Use alternative format for --show.\n"
  415. "\n"), ADMINDIR) < 0) werr ("stdout");
  416. if (printf(_(
  417. "Format syntax:\n"
  418. " A format is a string that will be output for each package. The format\n"
  419. " can include the standard escape sequences \\n (newline), \\r (carriage\n"
  420. " return) or \\\\ (plain backslash). Package information can be included\n"
  421. " by inserting variable references to package fields using the ${var[;width]}\n"
  422. " syntax. Fields will be right-aligned unless the width is negative in which\n"
  423. " case left alignment will be used.\n")) < 0) werr ("stdout");
  424. }
  425. const char thisname[]= "dpkg-query";
  426. const char printforhelp[]= N_("\
  427. Use --help for help about querying packages;\n\
  428. Use --license for copyright license and lack of warranty (GNU GPL).");
  429. const struct cmdinfo *cipaction = NULL;
  430. int f_pending=0, f_recursive=0, f_alsoselect=1, f_skipsame=0, f_noact=0;
  431. int f_autodeconf=0, f_nodebsig=0;
  432. unsigned long f_debug=0;
  433. /* Change fc_overwrite to 1 to enable force-overwrite by default */
  434. int fc_hold=0;
  435. int fc_conflicts=0, fc_depends=0;
  436. int fc_badpath=0;
  437. const char *admindir= ADMINDIR;
  438. const char *instdir= "";
  439. static void setaction(const struct cmdinfo *cip, const char *value) {
  440. if (cipaction)
  441. badusage(_("conflicting actions -%c (--%s) and -%c (--%s)"),
  442. cip->oshort, cip->olong, cipaction->oshort, cipaction->olong);
  443. cipaction= cip;
  444. }
  445. static const struct cmdinfo cmdinfos[]= {
  446. /* This table has both the action entries in it and the normal options.
  447. * The action entries are made with the ACTION macro, as they all
  448. * have a very similar structure.
  449. */
  450. #define ACTION(longopt,shortopt,code,function) \
  451. { longopt, shortopt, 0, NULL, NULL, setaction, code, NULL, (voidfnp)function }
  452. #define OBSOLETE(longopt,shortopt) \
  453. { longopt, shortopt, 0, NULL, NULL, setobsolete, 0, NULL, NULL }
  454. ACTION( "listfiles", 'L', act_listfiles, enqperpackage ),
  455. ACTION( "status", 's', act_status, enqperpackage ),
  456. ACTION( "print-avail", 'p', act_printavail, enqperpackage ),
  457. ACTION( "list", 'l', act_listpackages, listpackages ),
  458. ACTION( "search", 'S', act_searchfiles, searchfiles ),
  459. ACTION( "show", 'W', act_listpackages, showpackages ),
  460. { "admindir", 0, 1, NULL, &admindir, NULL },
  461. { "showformat", 'f', 1, NULL, &showformat, NULL },
  462. { "help", 'h', 0, NULL, NULL, helponly },
  463. { "version", 0, 0, NULL, NULL, versiononly },
  464. /* UK spelling. */
  465. { "licence", 0, 0, NULL, NULL, showcopyright },
  466. /* US spelling */
  467. { "license", 0, 0, NULL, NULL, showcopyright },
  468. { NULL, 0, 0, NULL, NULL, NULL }
  469. };
  470. int main(int argc, const char *const *argv) {
  471. jmp_buf ejbuf;
  472. static void (*actionfunction)(const char *const *argv);
  473. setlocale(LC_ALL, "");
  474. bindtextdomain(PACKAGE, LOCALEDIR);
  475. textdomain(PACKAGE);
  476. standard_startup(&ejbuf);
  477. myopt(&argv, cmdinfos);
  478. if (!cipaction) badusage(_("need an action option"));
  479. setvbuf(stdout, NULL, _IONBF, 0);
  480. filesdbinit();
  481. actionfunction= (void (*)(const char* const*))cipaction->farg;
  482. actionfunction(argv);
  483. standard_shutdown();
  484. return !!failures;
  485. }