query.c 18 KB

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