querycmd.c 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703
  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]->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->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->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. }
  213. m_output(stdout, _("<standard output>"));
  214. m_output(stderr, _("<standard error>"));
  215. pkg_array_destroy(&array);
  216. modstatdb_shutdown();
  217. return failures;
  218. }
  219. static int searchoutput(struct filenamenode *namenode) {
  220. struct filepackages_iterator *iter;
  221. struct pkginfo *pkg_owner;
  222. int found;
  223. if (namenode->divert) {
  224. const char *name_from = namenode->divert->camefrom ?
  225. namenode->divert->camefrom->name : namenode->name;
  226. const char *name_to = namenode->divert->useinstead ?
  227. namenode->divert->useinstead->name : namenode->name;
  228. if (namenode->divert->pkg) {
  229. printf(_("diversion by %s from: %s\n"),
  230. namenode->divert->pkg->name, name_from);
  231. printf(_("diversion by %s to: %s\n"),
  232. namenode->divert->pkg->name, name_to);
  233. } else {
  234. printf(_("local diversion from: %s\n"), name_from);
  235. printf(_("local diversion to: %s\n"), name_to);
  236. }
  237. }
  238. found= 0;
  239. iter = filepackages_iter_new(namenode);
  240. while ((pkg_owner = filepackages_iter_next(iter))) {
  241. if (found)
  242. fputs(", ", stdout);
  243. fputs(pkg_owner->name, stdout);
  244. found++;
  245. }
  246. filepackages_iter_free(iter);
  247. if (found) printf(": %s\n",namenode->name);
  248. return found + (namenode->divert ? 1 : 0);
  249. }
  250. static int
  251. searchfiles(const char *const *argv)
  252. {
  253. struct filenamenode *namenode;
  254. struct fileiterator *it;
  255. const char *thisarg;
  256. int found;
  257. int failures = 0;
  258. struct varbuf path = VARBUF_INIT;
  259. static struct varbuf vb;
  260. if (!*argv)
  261. badusage(_("--search needs at least one file name pattern argument"));
  262. modstatdb_open(msdbrw_readonly);
  263. ensure_allinstfiles_available_quiet();
  264. ensure_diversions();
  265. while ((thisarg = *argv++) != NULL) {
  266. found= 0;
  267. /* Trim trailing ‘/’ and ‘/.’ from the argument if it's
  268. * not a pattern, just a path. */
  269. if (!strpbrk(thisarg, "*[?\\")) {
  270. varbuf_reset(&path);
  271. varbuf_add_str(&path, thisarg);
  272. varbuf_end_str(&path);
  273. varbuf_trunc(&path, path_trim_slash_slashdot(path.buf));
  274. thisarg = path.buf;
  275. }
  276. if (!strchr("*[?/",*thisarg)) {
  277. varbuf_reset(&vb);
  278. varbuf_add_char(&vb, '*');
  279. varbuf_add_str(&vb, thisarg);
  280. varbuf_add_char(&vb, '*');
  281. varbuf_end_str(&vb);
  282. thisarg= vb.buf;
  283. }
  284. if (!strpbrk(thisarg, "*[?\\")) {
  285. namenode= findnamenode(thisarg, 0);
  286. found += searchoutput(namenode);
  287. } else {
  288. it= iterfilestart();
  289. while ((namenode = iterfilenext(it)) != NULL) {
  290. if (fnmatch(thisarg,namenode->name,0)) continue;
  291. found+= searchoutput(namenode);
  292. }
  293. iterfileend(it);
  294. }
  295. if (!found) {
  296. fprintf(stderr, _("%s: no path found matching pattern %s.\n"),
  297. dpkg_get_progname(), thisarg);
  298. failures++;
  299. m_output(stderr, _("<standard error>"));
  300. } else {
  301. m_output(stdout, _("<standard output>"));
  302. }
  303. }
  304. modstatdb_shutdown();
  305. varbuf_destroy(&path);
  306. return failures;
  307. }
  308. static int
  309. enqperpackage(const char *const *argv)
  310. {
  311. const char *thisarg;
  312. struct fileinlist *file;
  313. struct pkginfo *pkg;
  314. struct filenamenode *namenode;
  315. int failures = 0;
  316. if (!*argv)
  317. badusage(_("--%s needs at least one package name argument"), cipaction->olong);
  318. if (cipaction->arg_int == act_printavail)
  319. modstatdb_open(msdbrw_readonly | msdbrw_available_readonly);
  320. else
  321. modstatdb_open(msdbrw_readonly);
  322. while ((thisarg = *argv++) != NULL) {
  323. pkg = pkg_db_find(thisarg);
  324. switch (cipaction->arg_int) {
  325. case act_status:
  326. if (pkg->status == stat_notinstalled &&
  327. pkg->priority == pri_unknown &&
  328. !(pkg->section && *pkg->section) &&
  329. !pkg->files &&
  330. pkg->want == want_unknown &&
  331. !pkg_is_informative(pkg, &pkg->installed)) {
  332. fprintf(stderr,_("Package `%s' is not installed and no info is available.\n"),pkg->name);
  333. failures++;
  334. } else {
  335. writerecord(stdout, _("<standard output>"), pkg, &pkg->installed);
  336. }
  337. break;
  338. case act_printavail:
  339. if (!pkg_is_informative(pkg, &pkg->available)) {
  340. fprintf(stderr,_("Package `%s' is not available.\n"),pkg->name);
  341. failures++;
  342. } else {
  343. writerecord(stdout, _("<standard output>"), pkg, &pkg->available);
  344. }
  345. break;
  346. case act_listfiles:
  347. switch (pkg->status) {
  348. case stat_notinstalled:
  349. fprintf(stderr,_("Package `%s' is not installed.\n"),pkg->name);
  350. failures++;
  351. break;
  352. default:
  353. ensure_packagefiles_available(pkg);
  354. ensure_diversions();
  355. file= pkg->clientdata->files;
  356. if (!file) {
  357. printf(_("Package `%s' does not contain any files (!)\n"),pkg->name);
  358. } else {
  359. while (file) {
  360. namenode= file->namenode;
  361. puts(namenode->name);
  362. if (namenode->divert && !namenode->divert->camefrom) {
  363. if (!namenode->divert->pkg)
  364. printf(_("locally diverted to: %s\n"),
  365. namenode->divert->useinstead->name);
  366. else if (pkg == namenode->divert->pkg)
  367. printf(_("package diverts others to: %s\n"),
  368. namenode->divert->useinstead->name);
  369. else
  370. printf(_("diverted by %s to: %s\n"),
  371. namenode->divert->pkg->name,
  372. namenode->divert->useinstead->name);
  373. }
  374. file= file->next;
  375. }
  376. }
  377. break;
  378. }
  379. break;
  380. default:
  381. internerr("unknown action '%d'", cipaction->arg_int);
  382. }
  383. if (*argv != NULL)
  384. putchar('\n');
  385. m_output(stdout, _("<standard output>"));
  386. }
  387. if (failures) {
  388. fputs(_("Use dpkg --info (= dpkg-deb --info) to examine archive files,\n"
  389. "and dpkg --contents (= dpkg-deb --contents) to list their contents.\n"),stderr);
  390. m_output(stderr, _("<standard error>"));
  391. }
  392. modstatdb_shutdown();
  393. return failures;
  394. }
  395. static int
  396. showpackages(const char *const *argv)
  397. {
  398. struct pkg_array array;
  399. struct pkginfo *pkg;
  400. struct pkg_format_node *fmt = pkg_format_parse(showformat);
  401. int i;
  402. int failures = 0;
  403. if (!fmt) {
  404. failures++;
  405. return failures;
  406. }
  407. if (!*argv)
  408. modstatdb_open(msdbrw_readonly);
  409. else
  410. modstatdb_open(msdbrw_readonly | msdbrw_available_readonly);
  411. pkg_array_init_from_db(&array);
  412. pkg_array_sort(&array, pkg_sorter_by_name);
  413. if (!*argv) {
  414. for (i = 0; i < array.n_pkgs; i++) {
  415. pkg = array.pkgs[i];
  416. if (pkg->status == stat_notinstalled) continue;
  417. pkg_format_show(fmt, pkg, &pkg->installed);
  418. }
  419. } else {
  420. int argc, ip, *found;
  421. for (argc = 0; argv[argc]; argc++);
  422. found = m_malloc(sizeof(int) * argc);
  423. memset(found, 0, sizeof(int) * argc);
  424. for (i = 0; i < array.n_pkgs; i++) {
  425. pkg = array.pkgs[i];
  426. for (ip = 0; ip < argc; ip++) {
  427. if (!fnmatch(argv[ip], pkg->name, 0)) {
  428. pkg_format_show(fmt, pkg, &pkg->installed);
  429. found[ip]++;
  430. break;
  431. }
  432. }
  433. }
  434. /* FIXME: we might get non-matching messages for sub-patterns specified
  435. * after their super-patterns, due to us skipping on first match. */
  436. for (ip = 0; ip < argc; ip++) {
  437. if (!found[ip]) {
  438. fprintf(stderr, _("No packages found matching %s.\n"), argv[ip]);
  439. failures++;
  440. }
  441. }
  442. }
  443. m_output(stdout, _("<standard output>"));
  444. m_output(stderr, _("<standard error>"));
  445. pkg_array_destroy(&array);
  446. pkg_format_free(fmt);
  447. modstatdb_shutdown();
  448. return failures;
  449. }
  450. static void
  451. pkg_infodb_print_filename(const char *filename, const char *filetype)
  452. {
  453. /* Do not expose internal database files. */
  454. if (strcmp(filetype, LISTFILE) == 0 ||
  455. strcmp(filetype, CONFFILESFILE) == 0)
  456. return;
  457. if (strlen(filetype) > MAXCONTROLFILENAME)
  458. return;
  459. printf("%s\n", filename);
  460. }
  461. static void
  462. control_path_file(struct pkginfo *pkg, const char *control_file)
  463. {
  464. const char *control_path;
  465. struct stat st;
  466. control_path = pkgadminfile(pkg, control_file);
  467. if (stat(control_path, &st) < 0)
  468. return;
  469. if (!S_ISREG(st.st_mode))
  470. return;
  471. pkg_infodb_print_filename(control_path, control_file);
  472. }
  473. static int
  474. control_path(const char *const *argv)
  475. {
  476. struct pkginfo *pkg;
  477. const char *pkg_name;
  478. const char *control_file;
  479. pkg_name = *argv++;
  480. if (!pkg_name)
  481. badusage(_("--%s needs at least one package name argument"),
  482. cipaction->olong);
  483. control_file = *argv++;
  484. if (control_file && *argv)
  485. badusage(_("--%s takes at most two arguments"), cipaction->olong);
  486. /* Validate control file name for sanity. */
  487. if (control_file) {
  488. const char *c;
  489. for (c = "/."; *c; c++)
  490. if (strchr(control_file, *c))
  491. badusage(_("control file contains %c"), *c);
  492. }
  493. modstatdb_open(msdbrw_readonly);
  494. pkg = pkg_db_find(pkg_name);
  495. if (pkg->status == stat_notinstalled)
  496. ohshit(_("Package `%s' is not installed.\n"), pkg->name);
  497. if (control_file)
  498. control_path_file(pkg, control_file);
  499. else
  500. pkg_infodb_foreach(pkg, pkg_infodb_print_filename);
  501. modstatdb_shutdown();
  502. return 0;
  503. }
  504. static void DPKG_ATTR_NORET
  505. printversion(const struct cmdinfo *ci, const char *value)
  506. {
  507. printf(_("Debian %s package management program query tool version %s.\n"),
  508. DPKGQUERY, DPKG_VERSION_ARCH);
  509. printf(_(
  510. "This is free software; see the GNU General Public License version 2 or\n"
  511. "later for copying conditions. There is NO warranty.\n"));
  512. m_output(stdout, _("<standard output>"));
  513. exit(0);
  514. }
  515. static void DPKG_ATTR_NORET
  516. usage(const struct cmdinfo *ci, const char *value)
  517. {
  518. printf(_(
  519. "Usage: %s [<option> ...] <command>\n"
  520. "\n"), DPKGQUERY);
  521. printf(_(
  522. "Commands:\n"
  523. " -s|--status <package> ... Display package status details.\n"
  524. " -p|--print-avail <package> ... Display available version details.\n"
  525. " -L|--listfiles <package> ... List files `owned' by package(s).\n"
  526. " -l|--list [<pattern> ...] List packages concisely.\n"
  527. " -W|--show [<pattern> ...] Show information on package(s).\n"
  528. " -S|--search <pattern> ... Find package(s) owning file(s).\n"
  529. " -c|--control-path <package> [<file>]\n"
  530. " Print path for package control file.\n"
  531. "\n"));
  532. printf(_(
  533. " -h|--help Show this help message.\n"
  534. " --version Show the version.\n"
  535. "\n"));
  536. printf(_(
  537. "Options:\n"
  538. " --admindir=<directory> Use <directory> instead of %s.\n"
  539. " -f|--showformat=<format> Use alternative format for --show.\n"
  540. "\n"), ADMINDIR);
  541. printf(_(
  542. "Format syntax:\n"
  543. " A format is a string that will be output for each package. The format\n"
  544. " can include the standard escape sequences \\n (newline), \\r (carriage\n"
  545. " return) or \\\\ (plain backslash). Package information can be included\n"
  546. " by inserting variable references to package fields using the ${var[;width]}\n"
  547. " syntax. Fields will be right-aligned unless the width is negative in which\n"
  548. " case left alignment will be used.\n"));
  549. m_output(stdout, _("<standard output>"));
  550. exit(0);
  551. }
  552. static const char printforhelp[] = N_(
  553. "Use --help for help about querying packages.");
  554. static const char *admindir;
  555. /* This table has both the action entries in it and the normal options.
  556. * The action entries are made with the ACTION macro, as they all
  557. * have a very similar structure. */
  558. static const struct cmdinfo cmdinfos[]= {
  559. ACTION( "listfiles", 'L', act_listfiles, enqperpackage ),
  560. ACTION( "status", 's', act_status, enqperpackage ),
  561. ACTION( "print-avail", 'p', act_printavail, enqperpackage ),
  562. ACTION( "list", 'l', act_listpackages, listpackages ),
  563. ACTION( "search", 'S', act_searchfiles, searchfiles ),
  564. ACTION( "show", 'W', act_listpackages, showpackages ),
  565. ACTION( "control-path", 'c', act_controlpath, control_path ),
  566. { "admindir", 0, 1, NULL, &admindir, NULL },
  567. { "showformat", 'f', 1, NULL, &showformat, NULL },
  568. { "help", 'h', 0, NULL, NULL, usage },
  569. { "version", 0, 0, NULL, NULL, printversion },
  570. { NULL, 0, 0, NULL, NULL, NULL }
  571. };
  572. int main(int argc, const char *const *argv) {
  573. int ret;
  574. setlocale(LC_ALL, "");
  575. bindtextdomain(PACKAGE, LOCALEDIR);
  576. textdomain(PACKAGE);
  577. dpkg_set_progname("dpkg-query");
  578. standard_startup();
  579. myopt(&argv, cmdinfos, printforhelp);
  580. admindir = dpkg_db_set_dir(admindir);
  581. if (!cipaction) badusage(_("need an action option"));
  582. setvbuf(stdout, NULL, _IONBF, 0);
  583. filesdbinit();
  584. ret = cipaction->action(argv);
  585. standard_shutdown();
  586. return !!ret;
  587. }