query.c 19 KB

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