query.c 19 KB

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