query.c 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554
  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 <stdio.h>
  26. #include <string.h>
  27. #include <stdlib.h>
  28. #include <fnmatch.h>
  29. #include <assert.h>
  30. #include <unistd.h>
  31. #include <sys/types.h>
  32. #include <sys/stat.h>
  33. #include <sys/ioctl.h>
  34. #include <sys/termios.h>
  35. #include <fcntl.h>
  36. #include <config.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 = "${pkg:Package}\t${pkg: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. ws.ws_col=res;
  96. else if (!isatty(1))
  97. ws.ws_col=80;
  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. }
  105. return ws.ws_col;
  106. }
  107. static void list1package(struct pkginfo *pkg, int *head) {
  108. int l,w;
  109. static int nw,vw,dw;
  110. const char *pdesc;
  111. static char format[80] = "";
  112. if (format[0]==0) {
  113. w=getwidth()-80; /* get spare width */
  114. if (w<0) w=0; /* lets not try to deal with terminals that are too small */
  115. w>>=2; /* halve that so we can add that to the both the name and description */
  116. nw=(14+w); /* name width */
  117. vw=(14+w); /* version width */
  118. dw=(44+(2*w)); /* description width */
  119. sprintf(format,"%%c%%c%%c %%-%d.%ds %%-%d.%ds %%.*s\n", nw, nw, vw, vw);
  120. }
  121. if (!*head) {
  122. fputs(_("\
  123. Desired=Unknown/Install/Remove/Purge/Hold\n\
  124. | Status=Not/Installed/Config-files/Unpacked/Failed-config/Half-installed\n\
  125. |/ Err?=(none)/Hold/Reinst-required/X=both-problems (Status,Err: uppercase=bad)\n"), stdout);
  126. printf(format,'|','|','/', _("Name"), _("Version"), 40, _("Description"));
  127. printf("+++-"); /* status */
  128. for (l=0;l<nw;l++) printf("="); printf("-"); /* packagename */
  129. for (l=0;l<vw;l++) printf("="); printf("-"); /* version */
  130. for (l=0;l<dw;l++) printf("="); /* description */
  131. printf("\n");
  132. *head= 1;
  133. }
  134. if (!pkg->installed.valid) blankpackageperfile(&pkg->installed);
  135. limiteddescription(pkg,dw,&pdesc,&l);
  136. printf(format,
  137. "uihrp"[pkg->want],
  138. "nUFiHc"[pkg->status],
  139. " R?#"[pkg->eflag],
  140. pkg->name,
  141. versiondescribe(&pkg->installed.version,vdew_never),
  142. l, pdesc);
  143. }
  144. void listpackages(const char *const *argv) {
  145. struct pkgiterator *it;
  146. struct pkginfo *pkg;
  147. struct pkginfo **pkgl;
  148. const char *thisarg;
  149. int np, i, head, found;
  150. modstatdb_init(admindir,msdbrw_readonly);
  151. np= countpackages();
  152. pkgl= m_malloc(sizeof(struct pkginfo*)*np);
  153. it= iterpkgstart(); i=0;
  154. while ((pkg= iterpkgnext(it))) {
  155. assert(i<np);
  156. pkgl[i++]= pkg;
  157. }
  158. iterpkgend(it);
  159. assert(i==np);
  160. qsort(pkgl,np,sizeof(struct pkginfo*),pkglistqsortcmp);
  161. head=0;
  162. if (!*argv) {
  163. for (i=0; i<np; i++) {
  164. pkg= pkgl[i];
  165. if (pkg->status == stat_notinstalled) continue;
  166. list1package(pkg,&head);
  167. }
  168. } else {
  169. while ((thisarg= *argv++)) {
  170. found= 0;
  171. for (i=0; i<np; i++) {
  172. pkg= pkgl[i];
  173. if (fnmatch(thisarg,pkg->name,0)) continue;
  174. list1package(pkg,&head); found++;
  175. }
  176. if (!found) {
  177. fprintf(stderr,_("No packages found matching %s.\n"),thisarg);
  178. nerrs++;
  179. }
  180. }
  181. }
  182. if (ferror(stdout)) werr("stdout");
  183. if (ferror(stderr)) werr("stderr");
  184. modstatdb_shutdown();
  185. }
  186. static int searchoutput(struct filenamenode *namenode) {
  187. int found, i;
  188. struct filepackages *packageslump;
  189. if (namenode->divert) {
  190. for (i=0; i<2; i++) {
  191. if (namenode->divert->pkg) printf(_("diversion by %s"),namenode->divert->pkg->name);
  192. else printf(_("local diversion"));
  193. printf(" %s: %s\n", i ? _("to") : _("from"),
  194. i ?
  195. (namenode->divert->useinstead
  196. ? namenode->divert->useinstead->name
  197. : namenode->name)
  198. :
  199. (namenode->divert->camefrom
  200. ? namenode->divert->camefrom->name
  201. : namenode->name));
  202. }
  203. }
  204. found= 0;
  205. for (packageslump= namenode->packages;
  206. packageslump;
  207. packageslump= packageslump->more) {
  208. for (i=0; i < PERFILEPACKAGESLUMP && packageslump->pkgs[i]; i++) {
  209. if (found) fputs(", ",stdout);
  210. fputs(packageslump->pkgs[i]->name,stdout);
  211. found++;
  212. }
  213. }
  214. if (found) printf(": %s\n",namenode->name);
  215. return found + (namenode->divert ? 1 : 0);
  216. }
  217. void searchfiles(const char *const *argv) {
  218. struct filenamenode *namenode;
  219. struct fileiterator *it;
  220. const char *thisarg;
  221. int found;
  222. static struct varbuf vb;
  223. if (!*argv)
  224. badusage(_("--search needs at least one file name pattern argument"));
  225. modstatdb_init(admindir,msdbrw_readonly|msdbrw_noavail);
  226. ensure_allinstfiles_available_quiet();
  227. ensure_diversions();
  228. while ((thisarg= *argv++) != 0) {
  229. found= 0;
  230. if (!strchr("*[?/",*thisarg)) {
  231. varbufreset(&vb);
  232. varbufaddc(&vb,'*');
  233. varbufaddstr(&vb,thisarg);
  234. varbufaddc(&vb,'*');
  235. varbufaddc(&vb,0);
  236. thisarg= vb.buf;
  237. }
  238. if (strcspn(thisarg,"*[?\\") == strlen(thisarg)) {
  239. namenode= findnamenode(thisarg, 0);
  240. found += searchoutput(namenode);
  241. } else {
  242. it= iterfilestart();
  243. while ((namenode= iterfilenext(it)) != 0) {
  244. if (fnmatch(thisarg,namenode->name,0)) continue;
  245. found+= searchoutput(namenode);
  246. }
  247. iterfileend(it);
  248. }
  249. if (!found) {
  250. fprintf(stderr,_("dpkg: %s not found.\n"),thisarg);
  251. nerrs++;
  252. if (ferror(stderr)) werr("stderr");
  253. } else {
  254. if (ferror(stdout)) werr("stdout");
  255. }
  256. }
  257. modstatdb_shutdown();
  258. }
  259. void enqperpackage(const char *const *argv) {
  260. int failures;
  261. const char *thisarg;
  262. struct fileinlist *file;
  263. struct pkginfo *pkg;
  264. struct filenamenode *namenode;
  265. if (!*argv)
  266. badusage(_("--%s needs at least one package name argument"), cipaction->olong);
  267. failures= 0;
  268. if (cipaction->arg==act_listfiles)
  269. modstatdb_init(admindir,msdbrw_readonly|msdbrw_noavail);
  270. else
  271. modstatdb_init(admindir,msdbrw_readonly);
  272. while ((thisarg= *argv++) != 0) {
  273. pkg= findpackage(thisarg);
  274. switch (cipaction->arg) {
  275. case act_status:
  276. if (pkg->status == stat_notinstalled &&
  277. pkg->priority == pri_unknown &&
  278. !(pkg->section && *pkg->section) &&
  279. !pkg->files &&
  280. pkg->want == want_unknown &&
  281. !informative(pkg,&pkg->installed)) {
  282. fprintf(stderr,_("Package `%s' is not installed and no info is available.\n"),pkg->name);
  283. failures++;
  284. } else {
  285. writerecord(stdout, "<stdout>", pkg, &pkg->installed);
  286. }
  287. break;
  288. case act_printavail:
  289. if (!informative(pkg,&pkg->available)) {
  290. fprintf(stderr,_("Package `%s' is not available.\n"),pkg->name);
  291. failures++;
  292. } else {
  293. writerecord(stdout, "<stdout>", pkg, &pkg->available);
  294. }
  295. break;
  296. case act_listfiles:
  297. switch (pkg->status) {
  298. case stat_notinstalled:
  299. fprintf(stderr,_("Package `%s' is not installed.\n"),pkg->name);
  300. failures++;
  301. break;
  302. default:
  303. ensure_packagefiles_available(pkg);
  304. ensure_diversions();
  305. file= pkg->clientdata->files;
  306. if (!file) {
  307. printf(_("Package `%s' does not contain any files (!)\n"),pkg->name);
  308. } else {
  309. while (file) {
  310. namenode= file->namenode;
  311. puts(namenode->name);
  312. if (namenode->divert && !namenode->divert->camefrom) {
  313. if (!namenode->divert->pkg) printf(_("locally diverted"));
  314. else if (pkg == namenode->divert->pkg) printf(_("package diverts others"));
  315. else printf(_("diverted by %s"),namenode->divert->pkg->name);
  316. printf(_(" to: %s\n"),namenode->divert->useinstead->name);
  317. }
  318. file= file->next;
  319. }
  320. }
  321. break;
  322. }
  323. break;
  324. default:
  325. internerr("unknown action");
  326. }
  327. putchar('\n');
  328. if (ferror(stdout)) werr("stdout");
  329. }
  330. if (failures) {
  331. nerrs++;
  332. fputs(_("Use dpkg --info (= dpkg-deb --info) to examine archive files,\n"
  333. "and dpkg --contents (= dpkg-deb --contents) to list their contents.\n"),stderr);
  334. if (ferror(stdout)) werr("stdout");
  335. }
  336. modstatdb_shutdown();
  337. }
  338. void showpackages(const char *const *argv) {
  339. struct pkgiterator *it;
  340. struct pkginfo *pkg;
  341. struct pkginfo **pkgl;
  342. const char *thisarg;
  343. int np, i, found;
  344. struct lstitem* fmt = parseformat(showformat);
  345. if (!fmt) {
  346. nerrs++;
  347. return;
  348. }
  349. modstatdb_init(admindir,msdbrw_readonly);
  350. np= countpackages();
  351. pkgl= m_malloc(sizeof(struct pkginfo*)*np);
  352. it= iterpkgstart(); i=0;
  353. while ((pkg= iterpkgnext(it))) {
  354. assert(i<np);
  355. pkgl[i++]= pkg;
  356. }
  357. iterpkgend(it);
  358. assert(i==np);
  359. qsort(pkgl,np,sizeof(struct pkginfo*),pkglistqsortcmp);
  360. if (!*argv) {
  361. for (i=0; i<np; i++) {
  362. pkg= pkgl[i];
  363. if (pkg->status == stat_notinstalled) continue;
  364. show1package(fmt,pkg);
  365. }
  366. } else {
  367. while ((thisarg= *argv++)) {
  368. found= 0;
  369. for (i=0; i<np; i++) {
  370. pkg= pkgl[i];
  371. if (fnmatch(thisarg,pkg->name,0)) continue;
  372. show1package(fmt,pkg); found++;
  373. }
  374. if (!found) {
  375. fprintf(stderr,_("No packages found matching %s.\n"),thisarg);
  376. nerrs++;
  377. }
  378. }
  379. }
  380. if (ferror(stdout)) werr("stdout");
  381. if (ferror(stderr)) werr("stderr");
  382. freeformat(fmt);
  383. modstatdb_shutdown();
  384. }
  385. static void printversion(void) {
  386. if (fputs(_("Debian `"), stdout) < 0) werr("stdout");
  387. if (fputs(DPKGQUERY, stdout) < 0) werr("stdout");
  388. if (fputs(_("' package management program query tool\n"), stdout) < 0)
  389. werr("stdout");
  390. if (fputs(_( "This is free software; see the GNU General Public Licence version 2 or\n"
  391. "later for copying conditions. There is NO warranty.\n"
  392. "See " DPKGQUERY " --licence for copyright and license details.\n"),
  393. stdout) < 0) werr("stdout");
  394. }
  395. /*
  396. options that need fixing:
  397. dpkg --yet-to-unpack \n\
  398. */
  399. static void usage(void) {
  400. if (fprintf (stdout, _("\
  401. Usage: " DPKGQUERY " [<option>] <command>\n\
  402. Commands:\n\
  403. -s|--status <package-name> ... display package status details\n\
  404. -p|--print-avail <package-name> ... display available version details\n\
  405. -L|--listfiles <package-name> ... list files `owned' by package(s)\n\
  406. -l|--list [<pattern> ...] list packages concisely\n\
  407. -W|--show <pattern> ... show information on package(s)\n\
  408. -S|--search <pattern> ... find package(s) owning file(s)\n\
  409. --help | --version show this help / version number\n\
  410. --licence print copyright licensing terms\n\
  411. \n\
  412. Options:\n\
  413. --admindir=<directory> Use <directory> instead of %s\n\
  414. --showformat=<format> Use alternative format for --show\n\
  415. \n\
  416. Format syntax:\n\
  417. A format is a string that will be output for each package. The format\n\
  418. can include the standard escape sequences \\n (newline), \\r (carriage\n\
  419. return) or \\\\ (plain backslash). Package information can be included\n\
  420. by inserting variable references to package fields using the ${var[;width]}\n\
  421. syntax. Fields will be right-aligned unless the width is negative in which\n\
  422. case left aligenment will be used. \n\
  423. "),
  424. ADMINDIR) < 0) werr ("stdout");
  425. }
  426. const char thisname[]= "dpkg-query";
  427. const char printforhelp[]= N_("\
  428. Use --help for help about querying packages;\n\
  429. Use --licence for copyright licence and lack of warranty (GNU GPL).\n\
  430. \n");
  431. const struct cmdinfo *cipaction= 0;
  432. int f_pending=0, f_recursive=0, f_alsoselect=1, f_skipsame=0, f_noact=0;
  433. int f_autodeconf=0, f_nodebsig=0;
  434. unsigned long f_debug=0;
  435. /* Change fc_overwrite to 1 to enable force-overwrite by default */
  436. int fc_hold=0;
  437. int fc_conflicts=0, fc_depends=0;
  438. int fc_badpath=0;
  439. int errabort = 50;
  440. const char *admindir= ADMINDIR;
  441. const char *instdir= "";
  442. struct packageinlist *ignoredependss=0;
  443. static void helponly(const struct cmdinfo *cip, const char *value) NONRETURNING;
  444. static void helponly(const struct cmdinfo *cip, const char *value) {
  445. usage(); exit(0);
  446. }
  447. static void versiononly(const struct cmdinfo *cip, const char *value) NONRETURNING;
  448. static void versiononly(const struct cmdinfo *cip, const char *value) {
  449. printversion(); exit(0);
  450. }
  451. static void setaction(const struct cmdinfo *cip, const char *value) {
  452. if (cipaction)
  453. badusage(_("conflicting actions --%s and --%s"),cip->olong,cipaction->olong);
  454. cipaction= cip;
  455. }
  456. static const struct cmdinfo cmdinfos[]= {
  457. /* This table has both the action entries in it and the normal options.
  458. * The action entries are made with the ACTION macro, as they all
  459. * have a very similar structure.
  460. */
  461. #define ACTION(longopt,shortopt,code,function) \
  462. { longopt, shortopt, 0,0,0, setaction, code, 0, (voidfnp)function }
  463. #define OBSOLETE(longopt,shortopt) \
  464. { longopt, shortopt, 0,0,0, setobsolete, 0, 0, 0 }
  465. ACTION( "listfiles", 'L', act_listfiles, enqperpackage ),
  466. ACTION( "status", 's', act_status, enqperpackage ),
  467. ACTION( "print-avail", 'p', act_printavail, enqperpackage ),
  468. ACTION( "list", 'l', act_listpackages, listpackages ),
  469. ACTION( "search", 'S', act_searchfiles, searchfiles ),
  470. ACTION( "show", 'W', act_listpackages, showpackages ),
  471. { "admindir", 0, 1, 0, &admindir, 0 },
  472. { "showformat", 0, 1, 0, &showformat, 0 },
  473. { "help", 'h', 0, 0, 0, helponly },
  474. { "version", 0, 0, 0, 0, versiononly },
  475. { "licence",/* UK spelling */ 0,0,0,0, showcopyright },
  476. { "license",/* US spelling */ 0,0,0,0, showcopyright },
  477. { 0, 0 }
  478. };
  479. int main(int argc, const char *const *argv) {
  480. jmp_buf ejbuf;
  481. static void (*actionfunction)(const char *const *argv);
  482. standard_startup(&ejbuf, argc, &argv, NULL, 0, cmdinfos);
  483. if (!cipaction) badusage(_("need an action option"));
  484. setvbuf(stdout,0,_IONBF,0);
  485. filesdbinit();
  486. actionfunction= (void (*)(const char* const*))cipaction->farg;
  487. actionfunction(argv);
  488. standard_shutdown(0);
  489. return reportbroken_retexitstatus();
  490. }