querycmd.c 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745
  1. /*
  2. * dpkg-query - program for query the dpkg database
  3. * querycmd.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. * Copyright © 2006-2009 Guillem Jover <guillem@debian.org>
  8. *
  9. * This is free software; you can redistribute it and/or modify
  10. * it under the terms of the GNU General Public License as published by
  11. * the Free Software Foundation; either version 2 of the License, or
  12. * (at your option) any later version.
  13. *
  14. * This is distributed in the hope that it will be useful,
  15. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  17. * GNU General Public License for more details.
  18. *
  19. * You should have received a copy of the GNU General Public License
  20. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  21. */
  22. #include <config.h>
  23. #include <compat.h>
  24. #include <sys/types.h>
  25. #include <sys/stat.h>
  26. #include <sys/ioctl.h>
  27. #include <sys/termios.h>
  28. #if HAVE_LOCALE_H
  29. #include <locale.h>
  30. #endif
  31. #include <string.h>
  32. #include <fcntl.h>
  33. #include <dirent.h>
  34. #include <fnmatch.h>
  35. #include <unistd.h>
  36. #include <stdlib.h>
  37. #include <stdio.h>
  38. #include <dpkg/i18n.h>
  39. #include <dpkg/dpkg.h>
  40. #include <dpkg/dpkg-db.h>
  41. #include <dpkg/pkg-array.h>
  42. #include <dpkg/pkg-format.h>
  43. #include <dpkg/pkg-show.h>
  44. #include <dpkg/path.h>
  45. #include <dpkg/myopt.h>
  46. #include "filesdb.h"
  47. #include "main.h"
  48. static const char* showformat = "${Package}\t${Version}\n";
  49. static int getwidth(void) {
  50. int fd;
  51. int res;
  52. struct winsize ws;
  53. const char* columns;
  54. if ((columns=getenv("COLUMNS")) && ((res=atoi(columns))>0))
  55. return res;
  56. else if (!isatty(1))
  57. return -1;
  58. else {
  59. if ((fd=open("/dev/tty",O_RDONLY))!=-1) {
  60. if (ioctl(fd, TIOCGWINSZ, &ws)==-1)
  61. ws.ws_col=80;
  62. close(fd);
  63. }
  64. return ws.ws_col;
  65. }
  66. }
  67. struct list_format {
  68. bool head;
  69. int nw, vw, dw;
  70. char format[80];
  71. };
  72. static void
  73. list_format_init(struct list_format *fmt, struct pkg_array *array)
  74. {
  75. int w;
  76. if (fmt->format[0] != '\0')
  77. return;
  78. w = getwidth();
  79. if (w == -1) {
  80. int i;
  81. fmt->nw = 14;
  82. fmt->vw = 14;
  83. fmt->dw = 44;
  84. for (i = 0; i < array->n_pkgs; i++) {
  85. int plen, vlen, dlen;
  86. plen = strlen(array->pkgs[i]->name);
  87. vlen = strlen(versiondescribe(&array->pkgs[i]->installed.version,
  88. vdew_nonambig));
  89. pkg_summary(array->pkgs[i], &dlen);
  90. if (plen > fmt->nw)
  91. fmt->nw = plen;
  92. if (vlen > fmt->vw)
  93. fmt->vw = vlen;
  94. if (dlen > fmt->dw)
  95. fmt->dw = dlen;
  96. }
  97. } else {
  98. w -= 80;
  99. /* Let's not try to deal with terminals that are too small. */
  100. if (w < 0)
  101. w = 0;
  102. /* Halve that so we can add it to both the name and description. */
  103. w >>= 2;
  104. /* Name width. */
  105. fmt->nw = (14 + w);
  106. /* Version width. */
  107. fmt->vw = (14 + w);
  108. /* Description width. */
  109. fmt->dw = (44 + (2 * w));
  110. }
  111. sprintf(fmt->format, "%%c%%c%%c %%-%d.%ds %%-%d.%ds %%.*s\n",
  112. fmt->nw, fmt->nw, fmt->vw, fmt->vw);
  113. }
  114. static void
  115. list_format_print_header(struct list_format *fmt)
  116. {
  117. int l;
  118. if (fmt->head)
  119. return;
  120. /* TRANSLATORS: This is the header that appears on 'dpkg-query -l'. The
  121. * string should remain under 80 characters. The uppercase letters in
  122. * the state values denote the abbreviated letter that will appear on
  123. * the first three columns, which should ideally match the English one
  124. * (e.g. Remove → supRimeix), see dpkg-query(1) for further details. The
  125. * translated message can use additional lines if needed. */
  126. fputs(_("\
  127. Desired=Unknown/Install/Remove/Purge/Hold\n\
  128. | Status=Not/Inst/Conf-files/Unpacked/halF-conf/Half-inst/trig-aWait/Trig-pend\n\
  129. |/ Err?=(none)/Reinst-required (Status,Err: uppercase=bad)\n"), stdout);
  130. printf(fmt->format, '|', '|', '/', _("Name"), _("Version"), 40,
  131. _("Description"));
  132. /* Status */
  133. printf("+++-");
  134. /* Package name. */
  135. for (l = 0; l < fmt->nw; l++)
  136. printf("=");
  137. printf("-");
  138. /* Version. */
  139. for (l = 0; l < fmt->vw; l++)
  140. printf("=");
  141. printf("-");
  142. /* Description. */
  143. for (l = 0; l < fmt->dw; l++)
  144. printf("=");
  145. printf("\n");
  146. fmt->head = true;
  147. }
  148. static void
  149. list1package(struct pkginfo *pkg, struct list_format *fmt, struct pkg_array *array)
  150. {
  151. int l;
  152. const char *pdesc;
  153. list_format_init(fmt, array);
  154. list_format_print_header(fmt);
  155. pdesc = pkg_summary(pkg, &l);
  156. l = min(l, fmt->dw);
  157. printf(fmt->format,
  158. "uihrp"[pkg->want],
  159. "ncHUFWti"[pkg->status],
  160. " R"[pkg->eflag],
  161. pkg->name,
  162. versiondescribe(&pkg->installed.version, vdew_nonambig),
  163. l, pdesc);
  164. }
  165. static int
  166. listpackages(const char *const *argv)
  167. {
  168. struct pkg_array array;
  169. struct pkginfo *pkg;
  170. int i;
  171. int failures = 0;
  172. struct list_format fmt;
  173. modstatdb_init(admindir,msdbrw_readonly);
  174. pkg_array_init_from_db(&array);
  175. pkg_array_sort(&array, pkg_sorter_by_name);
  176. fmt.head = false;
  177. fmt.format[0] = '\0';
  178. if (!*argv) {
  179. for (i = 0; i < array.n_pkgs; i++) {
  180. pkg = array.pkgs[i];
  181. if (pkg->status == stat_notinstalled) continue;
  182. list1package(pkg, &fmt, &array);
  183. }
  184. } else {
  185. int argc, ip, *found;
  186. for (argc = 0; argv[argc]; argc++);
  187. found = m_malloc(sizeof(int) * argc);
  188. memset(found, 0, sizeof(int) * argc);
  189. for (i = 0; i < array.n_pkgs; i++) {
  190. pkg = array.pkgs[i];
  191. for (ip = 0; ip < argc; ip++) {
  192. if (!fnmatch(argv[ip], pkg->name, 0)) {
  193. list1package(pkg, &fmt, &array);
  194. found[ip]++;
  195. break;
  196. }
  197. }
  198. }
  199. /* FIXME: we might get non-matching messages for sub-patterns specified
  200. * after their super-patterns, due to us skipping on first match. */
  201. for (ip = 0; ip < argc; ip++) {
  202. if (!found[ip]) {
  203. fprintf(stderr, _("No packages found matching %s.\n"), argv[ip]);
  204. failures++;
  205. }
  206. }
  207. }
  208. m_output(stdout, _("<standard output>"));
  209. m_output(stderr, _("<standard error>"));
  210. pkg_array_destroy(&array);
  211. modstatdb_shutdown();
  212. return failures;
  213. }
  214. static int searchoutput(struct filenamenode *namenode) {
  215. struct filepackages_iterator *iter;
  216. struct pkginfo *pkg_owner;
  217. int found;
  218. if (namenode->divert) {
  219. const char *name_from = namenode->divert->camefrom ?
  220. namenode->divert->camefrom->name : namenode->name;
  221. const char *name_to = namenode->divert->useinstead ?
  222. namenode->divert->useinstead->name : namenode->name;
  223. if (namenode->divert->pkg) {
  224. printf(_("diversion by %s from: %s\n"),
  225. namenode->divert->pkg->name, name_from);
  226. printf(_("diversion by %s to: %s\n"),
  227. namenode->divert->pkg->name, name_to);
  228. } else {
  229. printf(_("local diversion from: %s\n"), name_from);
  230. printf(_("local diversion to: %s\n"), name_to);
  231. }
  232. }
  233. found= 0;
  234. iter = filepackages_iter_new(namenode);
  235. while ((pkg_owner = filepackages_iter_next(iter))) {
  236. if (found)
  237. fputs(", ", stdout);
  238. fputs(pkg_owner->name, stdout);
  239. found++;
  240. }
  241. filepackages_iter_free(iter);
  242. if (found) printf(": %s\n",namenode->name);
  243. return found + (namenode->divert ? 1 : 0);
  244. }
  245. static int
  246. searchfiles(const char *const *argv)
  247. {
  248. struct filenamenode *namenode;
  249. struct fileiterator *it;
  250. const char *thisarg;
  251. int found;
  252. int failures = 0;
  253. struct varbuf path = VARBUF_INIT;
  254. static struct varbuf vb;
  255. if (!*argv)
  256. badusage(_("--search needs at least one file name pattern argument"));
  257. modstatdb_init(admindir,msdbrw_readonly|msdbrw_noavail);
  258. ensure_allinstfiles_available_quiet();
  259. ensure_diversions();
  260. while ((thisarg = *argv++) != NULL) {
  261. found= 0;
  262. /* Trim trailing ‘/’ and ‘/.’ from the argument if it's
  263. * not a pattern, just a path. */
  264. if (!strpbrk(thisarg, "*[?\\")) {
  265. varbuf_reset(&path);
  266. varbuf_add_str(&path, thisarg);
  267. varbuf_end_str(&path);
  268. varbuf_trunc(&path, path_trim_slash_slashdot(path.buf));
  269. thisarg = path.buf;
  270. }
  271. if (!strchr("*[?/",*thisarg)) {
  272. varbuf_reset(&vb);
  273. varbuf_add_char(&vb, '*');
  274. varbuf_add_str(&vb, thisarg);
  275. varbuf_add_char(&vb, '*');
  276. varbuf_end_str(&vb);
  277. thisarg= vb.buf;
  278. }
  279. if (!strpbrk(thisarg, "*[?\\")) {
  280. namenode= findnamenode(thisarg, 0);
  281. found += searchoutput(namenode);
  282. } else {
  283. it= iterfilestart();
  284. while ((namenode = iterfilenext(it)) != NULL) {
  285. if (fnmatch(thisarg,namenode->name,0)) continue;
  286. found+= searchoutput(namenode);
  287. }
  288. iterfileend(it);
  289. }
  290. if (!found) {
  291. fprintf(stderr, _("%s: no path found matching pattern %s.\n"), thisname,
  292. thisarg);
  293. failures++;
  294. m_output(stderr, _("<standard error>"));
  295. } else {
  296. m_output(stdout, _("<standard output>"));
  297. }
  298. }
  299. modstatdb_shutdown();
  300. varbuf_destroy(&path);
  301. return failures;
  302. }
  303. static int
  304. enqperpackage(const char *const *argv)
  305. {
  306. const char *thisarg;
  307. struct fileinlist *file;
  308. struct pkginfo *pkg;
  309. struct filenamenode *namenode;
  310. int failures = 0;
  311. if (!*argv)
  312. badusage(_("--%s needs at least one package name argument"), cipaction->olong);
  313. if (cipaction->arg_int == act_listfiles)
  314. modstatdb_init(admindir,msdbrw_readonly|msdbrw_noavail);
  315. else
  316. modstatdb_init(admindir,msdbrw_readonly);
  317. while ((thisarg = *argv++) != NULL) {
  318. pkg = pkg_db_find(thisarg);
  319. switch (cipaction->arg_int) {
  320. case act_status:
  321. if (pkg->status == stat_notinstalled &&
  322. pkg->priority == pri_unknown &&
  323. !(pkg->section && *pkg->section) &&
  324. !pkg->files &&
  325. pkg->want == want_unknown &&
  326. !pkg_is_informative(pkg, &pkg->installed)) {
  327. fprintf(stderr,_("Package `%s' is not installed and no info is available.\n"),pkg->name);
  328. failures++;
  329. } else {
  330. writerecord(stdout, _("<standard output>"), pkg, &pkg->installed);
  331. }
  332. break;
  333. case act_printavail:
  334. if (!pkg_is_informative(pkg, &pkg->available)) {
  335. fprintf(stderr,_("Package `%s' is not available.\n"),pkg->name);
  336. failures++;
  337. } else {
  338. writerecord(stdout, _("<standard output>"), pkg, &pkg->available);
  339. }
  340. break;
  341. case act_listfiles:
  342. switch (pkg->status) {
  343. case stat_notinstalled:
  344. fprintf(stderr,_("Package `%s' is not installed.\n"),pkg->name);
  345. failures++;
  346. break;
  347. default:
  348. ensure_packagefiles_available(pkg);
  349. ensure_diversions();
  350. file= pkg->clientdata->files;
  351. if (!file) {
  352. printf(_("Package `%s' does not contain any files (!)\n"),pkg->name);
  353. } else {
  354. while (file) {
  355. namenode= file->namenode;
  356. puts(namenode->name);
  357. if (namenode->divert && !namenode->divert->camefrom) {
  358. if (!namenode->divert->pkg)
  359. printf(_("locally diverted to: %s\n"),
  360. namenode->divert->useinstead->name);
  361. else if (pkg == namenode->divert->pkg)
  362. printf(_("package diverts others to: %s\n"),
  363. namenode->divert->useinstead->name);
  364. else
  365. printf(_("diverted by %s to: %s\n"),
  366. namenode->divert->pkg->name,
  367. namenode->divert->useinstead->name);
  368. }
  369. file= file->next;
  370. }
  371. }
  372. break;
  373. }
  374. break;
  375. default:
  376. internerr("unknown action '%d'", cipaction->arg_int);
  377. }
  378. if (*argv != NULL)
  379. putchar('\n');
  380. m_output(stdout, _("<standard output>"));
  381. }
  382. if (failures) {
  383. fputs(_("Use dpkg --info (= dpkg-deb --info) to examine archive files,\n"
  384. "and dpkg --contents (= dpkg-deb --contents) to list their contents.\n"),stderr);
  385. m_output(stderr, _("<standard error>"));
  386. }
  387. modstatdb_shutdown();
  388. return failures;
  389. }
  390. static int
  391. showpackages(const char *const *argv)
  392. {
  393. struct pkg_array array;
  394. struct pkginfo *pkg;
  395. struct pkg_format_node *fmt = pkg_format_parse(showformat);
  396. int i;
  397. int failures = 0;
  398. if (!fmt) {
  399. failures++;
  400. return failures;
  401. }
  402. modstatdb_init(admindir,msdbrw_readonly);
  403. pkg_array_init_from_db(&array);
  404. pkg_array_sort(&array, pkg_sorter_by_name);
  405. if (!*argv) {
  406. for (i = 0; i < array.n_pkgs; i++) {
  407. pkg = array.pkgs[i];
  408. if (pkg->status == stat_notinstalled) continue;
  409. pkg_format_show(fmt, pkg, &pkg->installed);
  410. }
  411. } else {
  412. int argc, ip, *found;
  413. for (argc = 0; argv[argc]; argc++);
  414. found = m_malloc(sizeof(int) * argc);
  415. memset(found, 0, sizeof(int) * argc);
  416. for (i = 0; i < array.n_pkgs; i++) {
  417. pkg = array.pkgs[i];
  418. for (ip = 0; ip < argc; ip++) {
  419. if (!fnmatch(argv[ip], pkg->name, 0)) {
  420. pkg_format_show(fmt, pkg, &pkg->installed);
  421. found[ip]++;
  422. break;
  423. }
  424. }
  425. }
  426. /* FIXME: we might get non-matching messages for sub-patterns specified
  427. * after their super-patterns, due to us skipping on first match. */
  428. for (ip = 0; ip < argc; ip++) {
  429. if (!found[ip]) {
  430. fprintf(stderr, _("No packages found matching %s.\n"), argv[ip]);
  431. failures++;
  432. }
  433. }
  434. }
  435. m_output(stdout, _("<standard output>"));
  436. m_output(stderr, _("<standard error>"));
  437. pkg_array_destroy(&array);
  438. pkg_format_free(fmt);
  439. modstatdb_shutdown();
  440. return failures;
  441. }
  442. static void
  443. control_path_file(struct pkginfo *pkg, const char *control_file)
  444. {
  445. const char *control_path;
  446. struct stat st;
  447. /* Do not expose internal database files. */
  448. if (strcmp(control_file, LISTFILE) == 0 ||
  449. strcmp(control_file, CONFFILESFILE) == 0)
  450. return;
  451. control_path = pkgadminfile(pkg, control_file);
  452. if (stat(control_path, &st) < 0)
  453. return;
  454. if (!S_ISREG(st.st_mode))
  455. return;
  456. printf("%s\n", control_path);
  457. }
  458. static void
  459. control_path_pkg(struct pkginfo *pkg)
  460. {
  461. DIR *db_dir;
  462. struct dirent *db_de;
  463. struct varbuf db_path;
  464. size_t db_path_len;
  465. varbuf_init(&db_path, 0);
  466. varbuf_add_str(&db_path, pkgadmindir());
  467. db_path_len = db_path.used;
  468. varbuf_end_str(&db_path);
  469. db_dir = opendir(db_path.buf);
  470. if (!db_dir)
  471. ohshite(_("cannot read info directory"));
  472. push_cleanup(cu_closedir, ~0, NULL, 0, 1, (void *)db_dir);
  473. while ((db_de = readdir(db_dir)) != NULL) {
  474. const char *p;
  475. /* Ignore dotfiles, including ‘.’ and ‘..’. */
  476. if (db_de->d_name[0] == '.')
  477. continue;
  478. /* Ignore anything odd. */
  479. p = strrchr(db_de->d_name, '.');
  480. if (!p)
  481. continue;
  482. /* Ignore files from other packages. */
  483. if (strlen(pkg->name) != (size_t)(p - db_de->d_name) ||
  484. strncmp(db_de->d_name, pkg->name, p - db_de->d_name))
  485. continue;
  486. /* Skip past the full stop. */
  487. p++;
  488. /* Do not expose internal database files. */
  489. if (strcmp(p, LISTFILE) == 0 ||
  490. strcmp(p, CONFFILESFILE) == 0)
  491. continue;
  492. if (strlen(p) > MAXCONTROLFILENAME)
  493. continue;
  494. varbuf_trunc(&db_path, db_path_len);
  495. varbuf_add_str(&db_path, db_de->d_name);
  496. varbuf_end_str(&db_path);
  497. printf("%s\n", db_path.buf);
  498. }
  499. pop_cleanup(ehflag_normaltidy); /* closedir */
  500. varbuf_destroy(&db_path);
  501. }
  502. static int
  503. control_path(const char *const *argv)
  504. {
  505. struct pkginfo *pkg;
  506. const char *pkg_name;
  507. const char *control_file;
  508. pkg_name = *argv++;
  509. if (!pkg_name)
  510. badusage(_("--%s needs at least one package name argument"),
  511. cipaction->olong);
  512. control_file = *argv++;
  513. if (control_file && *argv)
  514. badusage(_("--%s takes at most two arguments"), cipaction->olong);
  515. /* Validate control file name for sanity. */
  516. if (control_file) {
  517. const char *c;
  518. for (c = "/."; *c; c++)
  519. if (strchr(control_file, *c))
  520. badusage(_("control file contains %c"), *c);
  521. }
  522. modstatdb_init(admindir, msdbrw_readonly | msdbrw_noavail);
  523. pkg = pkg_db_find(pkg_name);
  524. if (pkg->status == stat_notinstalled)
  525. ohshit(_("Package `%s' is not installed.\n"), pkg->name);
  526. if (control_file)
  527. control_path_file(pkg, control_file);
  528. else
  529. control_path_pkg(pkg);
  530. modstatdb_shutdown();
  531. return 0;
  532. }
  533. static void DPKG_ATTR_NORET
  534. printversion(const struct cmdinfo *ci, const char *value)
  535. {
  536. printf(_("Debian %s package management program query tool version %s.\n"),
  537. DPKGQUERY, DPKG_VERSION_ARCH);
  538. printf(_(
  539. "This is free software; see the GNU General Public License version 2 or\n"
  540. "later for copying conditions. There is NO warranty.\n"));
  541. m_output(stdout, _("<standard output>"));
  542. exit(0);
  543. }
  544. static void DPKG_ATTR_NORET
  545. usage(const struct cmdinfo *ci, const char *value)
  546. {
  547. printf(_(
  548. "Usage: %s [<option> ...] <command>\n"
  549. "\n"), DPKGQUERY);
  550. printf(_(
  551. "Commands:\n"
  552. " -s|--status <package> ... Display package status details.\n"
  553. " -p|--print-avail <package> ... Display available version details.\n"
  554. " -L|--listfiles <package> ... List files `owned' by package(s).\n"
  555. " -l|--list [<pattern> ...] List packages concisely.\n"
  556. " -W|--show <pattern> ... Show information on package(s).\n"
  557. " -S|--search <pattern> ... Find package(s) owning file(s).\n"
  558. " -c|--control-path <package> [<file>]\n"
  559. " Print path for package control file.\n"
  560. "\n"));
  561. printf(_(
  562. " -h|--help Show this help message.\n"
  563. " --version Show the version.\n"
  564. "\n"));
  565. printf(_(
  566. "Options:\n"
  567. " --admindir=<directory> Use <directory> instead of %s.\n"
  568. " -f|--showformat=<format> Use alternative format for --show.\n"
  569. "\n"), ADMINDIR);
  570. printf(_(
  571. "Format syntax:\n"
  572. " A format is a string that will be output for each package. The format\n"
  573. " can include the standard escape sequences \\n (newline), \\r (carriage\n"
  574. " return) or \\\\ (plain backslash). Package information can be included\n"
  575. " by inserting variable references to package fields using the ${var[;width]}\n"
  576. " syntax. Fields will be right-aligned unless the width is negative in which\n"
  577. " case left alignment will be used.\n"));
  578. m_output(stdout, _("<standard output>"));
  579. exit(0);
  580. }
  581. const char thisname[]= "dpkg-query";
  582. const char printforhelp[]= N_("Use --help for help about querying packages.");
  583. const char *admindir;
  584. /* This table has both the action entries in it and the normal options.
  585. * The action entries are made with the ACTION macro, as they all
  586. * have a very similar structure. */
  587. static const struct cmdinfo cmdinfos[]= {
  588. ACTION( "listfiles", 'L', act_listfiles, enqperpackage ),
  589. ACTION( "status", 's', act_status, enqperpackage ),
  590. ACTION( "print-avail", 'p', act_printavail, enqperpackage ),
  591. ACTION( "list", 'l', act_listpackages, listpackages ),
  592. ACTION( "search", 'S', act_searchfiles, searchfiles ),
  593. ACTION( "show", 'W', act_listpackages, showpackages ),
  594. ACTION( "control-path", 'c', act_controlpath, control_path ),
  595. { "admindir", 0, 1, NULL, &admindir, NULL },
  596. { "showformat", 'f', 1, NULL, &showformat, NULL },
  597. { "help", 'h', 0, NULL, NULL, usage },
  598. { "version", 0, 0, NULL, NULL, printversion },
  599. { NULL, 0, 0, NULL, NULL, NULL }
  600. };
  601. int main(int argc, const char *const *argv) {
  602. int (*actionfunction)(const char *const *argv);
  603. int ret;
  604. setlocale(LC_ALL, "");
  605. bindtextdomain(PACKAGE, LOCALEDIR);
  606. textdomain(PACKAGE);
  607. admindir = pkgadmindir_init(ADMINDIR);
  608. standard_startup();
  609. myopt(&argv, cmdinfos);
  610. if (!cipaction) badusage(_("need an action option"));
  611. setvbuf(stdout, NULL, _IONBF, 0);
  612. filesdbinit();
  613. actionfunction = (int (*)(const char *const *))cipaction->arg_func;
  614. ret = actionfunction(argv);
  615. standard_shutdown();
  616. return !!ret;
  617. }