query.c 16 KB

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