querycmd.c 19 KB

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