Extend getent to handle the shadow database.
[platform/upstream/glibc.git] / nss / getent.c
1 /* Copyright (c) 1998-2008, 2009 Free Software Foundation, Inc.
2    This file is part of the GNU C Library.
3    Contributed by Thorsten Kukuk <kukuk@suse.de>, 1998.
4
5    The GNU C Library is free software; you can redistribute it and/or
6    modify it under the terms of the GNU Lesser General Public
7    License as published by the Free Software Foundation; either
8    version 2.1 of the License, or (at your option) any later version.
9
10    The GNU C Library is distributed in the hope that it will be useful,
11    but WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13    Lesser General Public License for more details.
14
15    You should have received a copy of the GNU Lesser General Public
16    License along with the GNU C Library; if not, write to the Free
17    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
18    02111-1307 USA.  */
19
20 /* getent: get entries from administrative database.  */
21
22 #include <aliases.h>
23 #include <argp.h>
24 #include <ctype.h>
25 #include <error.h>
26 #include <grp.h>
27 #include <gshadow.h>
28 #include <libintl.h>
29 #include <locale.h>
30 #include <mcheck.h>
31 #include <netdb.h>
32 #include <pwd.h>
33 #include <shadow.h>
34 #include <stdio.h>
35 #include <stdlib.h>
36 #include <string.h>
37 #include <arpa/inet.h>
38 #include <arpa/nameser.h>
39 #include <netinet/ether.h>
40 #include <netinet/in.h>
41 #include <sys/socket.h>
42
43 /* Get libc version number.  */
44 #include <version.h>
45
46 #define PACKAGE _libc_intl_domainname
47
48 /* Name and version of program.  */
49 static void print_version (FILE *stream, struct argp_state *state);
50 void (*argp_program_version_hook) (FILE *, struct argp_state *) = print_version;
51
52 /* Short description of parameters.  */
53 static const char args_doc[] = N_("database [key ...]");
54
55 /* Supported options. */
56 static const struct argp_option args_options[] =
57   {
58     { "service", 's', "CONFIG", 0, N_("Service configuration to be used") },
59     { NULL, 0, NULL, 0, NULL },
60   };
61
62 /* Short description of program.  */
63 static const char doc[] = N_("Get entries from administrative database.");
64
65 /* Prototype for option handler.  */
66 static error_t parse_option (int key, char *arg, struct argp_state *state);
67
68 /* Function to print some extra text in the help message.  */
69 static char *more_help (int key, const char *text, void *input);
70
71 /* Data structure to communicate with argp functions.  */
72 static struct argp argp =
73   {
74     args_options, parse_option, args_doc, doc, NULL, more_help
75   };
76
77 /* Print the version information.  */
78 static void
79 print_version (FILE *stream, struct argp_state *state)
80 {
81   fprintf (stream, "getent (GNU %s) %s\n", PACKAGE, VERSION);
82   fprintf (stream, gettext ("\
83 Copyright (C) %s Free Software Foundation, Inc.\n\
84 This is free software; see the source for copying conditions.  There is NO\n\
85 warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\
86 "), "2009");
87   fprintf (stream, gettext ("Written by %s.\n"), "Thorsten Kukuk");
88 }
89
90 /* This is for aliases */
91 static inline void
92 print_aliases (struct aliasent *alias)
93 {
94   unsigned int i = 0;
95
96   printf ("%s: ", alias->alias_name);
97   for  (i = strlen (alias->alias_name); i < 14; ++i)
98     fputs_unlocked (" ", stdout);
99
100   for (i = 0; i < alias->alias_members_len; ++i)
101     printf ("%s%s",
102             alias->alias_members [i],
103             i + 1 == alias->alias_members_len ? "\n" : ", ");
104 }
105
106 static int
107 aliases_keys (int number, char *key[])
108 {
109   int result = 0;
110   int i;
111   struct aliasent *alias;
112
113   if (number == 0)
114     {
115       setaliasent ();
116       while ((alias = getaliasent ()) != NULL)
117         print_aliases (alias);
118       endaliasent ();
119       return result;
120     }
121
122   for (i = 0; i < number; ++i)
123     {
124       alias = getaliasbyname (key[i]);
125
126       if (alias == NULL)
127         result = 2;
128       else
129         print_aliases (alias);
130     }
131
132   return result;
133 }
134
135 /* This is for ethers */
136 static int
137 ethers_keys (int number, char *key[])
138 {
139   int result = 0;
140   int i;
141
142   if (number == 0)
143     {
144       fprintf (stderr, _("Enumeration not supported on %s\n"), "ethers");
145       return 3;
146     }
147
148   for (i = 0; i < number; ++i)
149     {
150       struct ether_addr *ethp, eth;
151       char buffer [1024], *p;
152
153       ethp = ether_aton (key[i]);
154       if (ethp != NULL)
155         {
156           if (ether_ntohost (buffer, ethp))
157             {
158               result = 2;
159               continue;
160             }
161           p = buffer;
162         }
163       else
164         {
165           if (ether_hostton (key[i], &eth))
166             {
167               result = 2;
168               continue;
169             }
170           p = key[i];
171           ethp = &eth;
172         }
173       printf ("%s %s\n", ether_ntoa (ethp), p);
174     }
175
176   return result;
177 }
178
179 /* This is for group */
180 static inline void
181 print_group (struct group *grp)
182 {
183   unsigned int i = 0;
184
185   printf ("%s:%s:%lu:", grp->gr_name ? grp->gr_name : "",
186           grp->gr_passwd ? grp->gr_passwd : "",
187           (unsigned long int) grp->gr_gid);
188
189   while (grp->gr_mem[i] != NULL)
190     {
191       fputs_unlocked (grp->gr_mem[i], stdout);
192       ++i;
193       if (grp->gr_mem[i] != NULL)
194         putchar_unlocked (',');
195     }
196   putchar_unlocked ('\n');
197 }
198
199 static int
200 group_keys (int number, char *key[])
201 {
202   int result = 0;
203   int i;
204   struct group *grp;
205
206   if (number == 0)
207     {
208       setgrent ();
209       while ((grp = getgrent ()) != NULL)
210         print_group (grp);
211       endgrent ();
212       return result;
213     }
214
215   for (i = 0; i < number; ++i)
216     {
217       errno = 0;
218       char *ep;
219       gid_t arg_gid = strtoul(key[i], &ep, 10);
220
221       if (errno != EINVAL && *key[i] != '\0' && *ep == '\0')
222         /* Valid numeric gid.  */
223         grp = getgrgid (arg_gid);
224       else
225         grp = getgrnam (key[i]);
226
227       if (grp == NULL)
228         result = 2;
229       else
230         print_group (grp);
231     }
232
233   return result;
234 }
235
236 /* This is for gshadow */
237 static void
238 print_gshadow (struct sgrp *sg)
239 {
240   unsigned int i = 0;
241
242   printf ("%s:%s:",
243           sg->sg_namp ? sg->sg_namp : "",
244           sg->sg_passwd ? sg->sg_passwd : "");
245
246   while (sg->sg_adm[i] != NULL)
247     {
248       fputs_unlocked (sg->sg_adm[i], stdout);
249       ++i;
250       if (sg->sg_adm[i] != NULL)
251         putchar_unlocked (',');
252     }
253
254   putchar_unlocked (':');
255
256   i = 0;
257   while (sg->sg_mem[i] != NULL)
258     {
259       fputs_unlocked (sg->sg_mem[i], stdout);
260       ++i;
261       if (sg->sg_mem[i] != NULL)
262         putchar_unlocked (',');
263     }
264
265   putchar_unlocked ('\n');
266 }
267
268 static int
269 gshadow_keys (int number, char *key[])
270 {
271   int result = 0;
272   int i;
273
274   if (number == 0)
275     {
276       struct sgrp *sg;
277
278       setsgent ();
279       while ((sg = getsgent ()) != NULL)
280         print_gshadow (sg);
281       endsgent ();
282       return result;
283     }
284
285   for (i = 0; i < number; ++i)
286     {
287       struct sgrp *sg;
288
289       sg = getsgnam (key[i]);
290
291       if (sg == NULL)
292         result = 2;
293       else
294         print_gshadow (sg);
295     }
296
297   return result;
298 }
299
300 /* This is for hosts */
301 static void
302 print_hosts (struct hostent *host)
303 {
304   unsigned int cnt;
305
306   for (cnt = 0; host->h_addr_list[cnt] != NULL; ++cnt)
307     {
308       char buf[INET6_ADDRSTRLEN];
309       const char *ip = inet_ntop (host->h_addrtype, host->h_addr_list[cnt],
310                                   buf, sizeof (buf));
311
312       printf ("%-15s %s", ip, host->h_name);
313
314       unsigned int i;
315       for (i = 0; host->h_aliases[i] != NULL; ++i)
316         {
317           putchar_unlocked (' ');
318           fputs_unlocked (host->h_aliases[i], stdout);
319         }
320       putchar_unlocked ('\n');
321     }
322 }
323
324 static int
325 hosts_keys (int number, char *key[])
326 {
327   int result = 0;
328   int i;
329   struct hostent *host;
330
331   if (number == 0)
332     {
333       sethostent (0);
334       while ((host = gethostent ()) != NULL)
335         print_hosts (host);
336       endhostent ();
337       return result;
338     }
339
340   for (i = 0; i < number; ++i)
341     {
342       struct hostent *host = NULL;
343       char addr[IN6ADDRSZ];
344
345       if (inet_pton (AF_INET6, key[i], &addr) > 0)
346         host = gethostbyaddr (addr, IN6ADDRSZ, AF_INET6);
347       else if (inet_pton (AF_INET, key[i], &addr) > 0)
348         host = gethostbyaddr (addr, INADDRSZ, AF_INET);
349       else if ((host = gethostbyname2 (key[i], AF_INET6)) == NULL)
350         host = gethostbyname2 (key[i], AF_INET);
351
352       if (host == NULL)
353         result = 2;
354       else
355         print_hosts (host);
356     }
357
358   return result;
359 }
360
361 /* This is for hosts, but using getaddrinfo */
362 static int
363 ahosts_keys_int (int af, int xflags, int number, char *key[])
364 {
365   int result = 0;
366   int i;
367   struct hostent *host;
368
369   if (number == 0)
370     {
371       sethostent (0);
372       while ((host = gethostent ()) != NULL)
373         print_hosts (host);
374       endhostent ();
375       return result;
376     }
377
378   struct addrinfo hint;
379   memset (&hint, '\0', sizeof (hint));
380   hint.ai_flags = AI_V4MAPPED | AI_ADDRCONFIG | AI_CANONNAME | xflags;
381   hint.ai_family = af;
382
383   for (i = 0; i < number; ++i)
384     {
385       struct addrinfo *res;
386
387       if (getaddrinfo (key[i], NULL, &hint, &res) != 0)
388         result = 2;
389       else
390         {
391           struct addrinfo *runp = res;
392
393           while (runp != NULL)
394             {
395               char sockbuf[20];
396               const char *sockstr;
397               if (runp->ai_socktype == SOCK_STREAM)
398                 sockstr = "STREAM";
399               else if (runp->ai_socktype == SOCK_DGRAM)
400                 sockstr = "DGRAM";
401               else if (runp->ai_socktype == SOCK_RAW)
402                 sockstr = "RAW";
403 #ifdef SOCK_SEQPACKET
404               else if (runp->ai_socktype == SOCK_SEQPACKET)
405                 sockstr = "SEQPACKET";
406 #endif
407 #ifdef SOCK_RDM
408               else if (runp->ai_socktype == SOCK_RDM)
409                 sockstr = "RDM";
410 #endif
411 #ifdef SOCK_DCCP
412               else if (runp->ai_socktype == SOCK_DCCP)
413                 sockstr = "DCCP";
414 #endif
415 #ifdef SOCK_PACKET
416               else if (runp->ai_socktype == SOCK_PACKET)
417                 sockstr = "PACKET";
418 #endif
419               else
420                 {
421                   snprintf (sockbuf, sizeof (sockbuf), "%d",
422                             runp->ai_socktype);
423                   sockstr = sockbuf;
424                 }
425
426               char buf[INET6_ADDRSTRLEN];
427               printf ("%-15s %-6s %s\n",
428                       inet_ntop (runp->ai_family,
429                                  runp->ai_family == AF_INET
430                                  ? (void *) &((struct sockaddr_in *) runp->ai_addr)->sin_addr
431                                  : (void *) &((struct sockaddr_in6 *) runp->ai_addr)->sin6_addr,
432                                  buf, sizeof (buf)),
433                       sockstr,
434                       runp->ai_canonname ?: "");
435
436               runp = runp->ai_next;
437             }
438
439           freeaddrinfo (res);
440         }
441     }
442
443   return result;
444 }
445
446 static int
447 ahosts_keys (int number, char *key[])
448 {
449   return ahosts_keys_int (AF_UNSPEC, 0, number, key);
450 }
451
452 static int
453 ahostsv4_keys (int number, char *key[])
454 {
455   return ahosts_keys_int (AF_INET, 0, number, key);
456 }
457
458 static int
459 ahostsv6_keys (int number, char *key[])
460 {
461   return ahosts_keys_int (AF_INET6, AI_V4MAPPED, number, key);
462 }
463
464 /* This is for netgroup */
465 static int
466 netgroup_keys (int number, char *key[])
467 {
468   int result = 0;
469   int i;
470
471   if (number == 0)
472     {
473       fprintf (stderr, _("Enumeration not supported on %s\n"), "netgroup");
474       return 3;
475     }
476
477   for (i = 0; i < number; ++i)
478     {
479       if (!setnetgrent (key[i]))
480         result = 2;
481       else
482         {
483           char *p[3];
484
485           printf ("%-21s", key[i]);
486
487           while (getnetgrent (p, p + 1, p + 2))
488             printf (" (%s, %s, %s)", p[0] ?: " ", p[1] ?: "", p[2] ?: "");
489           putchar_unlocked ('\n');
490         }
491     }
492
493   endnetgrent ();
494
495   return result;
496 }
497
498 /* This is for networks */
499 static void
500 print_networks (struct netent *net)
501 {
502   unsigned int i;
503   struct in_addr ip;
504   ip.s_addr = htonl (net->n_net);
505
506   printf ("%-21s %s", net->n_name, inet_ntoa (ip));
507
508   i = 0;
509   while (net->n_aliases[i] != NULL)
510     {
511       putchar_unlocked (' ');
512       fputs_unlocked (net->n_aliases[i], stdout);
513       ++i;
514     }
515   putchar_unlocked ('\n');
516 }
517
518 static int
519 networks_keys (int number, char *key[])
520 {
521   int result = 0;
522   int i;
523   struct netent *net;
524
525   if (number == 0)
526     {
527       setnetent (0);
528       while ((net = getnetent ()) != NULL)
529         print_networks (net);
530       endnetent ();
531       return result;
532     }
533
534   for (i = 0; i < number; ++i)
535     {
536       if (isdigit (key[i][0]))
537         net = getnetbyaddr (inet_addr (key[i]), AF_UNIX);
538       else
539         net = getnetbyname (key[i]);
540
541       if (net == NULL)
542         result = 2;
543       else
544         print_networks (net);
545     }
546
547   return result;
548 }
549
550 /* Now is all for passwd */
551 static inline void
552 print_passwd (struct passwd *pwd)
553 {
554   printf ("%s:%s:%lu:%lu:%s:%s:%s\n",
555           pwd->pw_name ? pwd->pw_name : "",
556           pwd->pw_passwd ? pwd->pw_passwd : "",
557           (unsigned long int) pwd->pw_uid,
558           (unsigned long int) pwd->pw_gid,
559           pwd->pw_gecos ? pwd->pw_gecos : "",
560           pwd->pw_dir ? pwd->pw_dir : "",
561           pwd->pw_shell ? pwd->pw_shell : "");
562 }
563
564 static int
565 passwd_keys (int number, char *key[])
566 {
567   int result = 0;
568   int i;
569   struct passwd *pwd;
570
571   if (number == 0)
572     {
573       setpwent ();
574       while ((pwd = getpwent ()) != NULL)
575         print_passwd (pwd);
576       endpwent ();
577       return result;
578     }
579
580   for (i = 0; i < number; ++i)
581     {
582       errno = 0;
583       char *ep;
584       uid_t arg_uid = strtoul(key[i], &ep, 10);
585
586       if (errno != EINVAL && *key[i] != '\0' && *ep == '\0')
587         /* Valid numeric uid.  */
588         pwd = getpwuid (arg_uid);
589       else
590         pwd = getpwnam (key[i]);
591
592       if (pwd == NULL)
593         result = 2;
594       else
595         print_passwd (pwd);
596     }
597
598   return result;
599 }
600
601 /* This is for protocols */
602 static inline void
603 print_protocols (struct protoent *proto)
604 {
605   unsigned int i;
606
607   printf ("%-21s %d", proto->p_name, proto->p_proto);
608
609   i = 0;
610   while (proto->p_aliases[i] != NULL)
611     {
612       putchar_unlocked (' ');
613       fputs_unlocked (proto->p_aliases[i], stdout);
614       ++i;
615     }
616   putchar_unlocked ('\n');
617 }
618
619 static int
620 protocols_keys (int number, char *key[])
621 {
622   int result = 0;
623   int i;
624   struct protoent *proto;
625
626   if (number == 0)
627     {
628       setprotoent (0);
629       while ((proto = getprotoent ()) != NULL)
630         print_protocols (proto);
631       endprotoent ();
632       return result;
633     }
634
635   for (i = 0; i < number; ++i)
636     {
637       if (isdigit (key[i][0]))
638         proto = getprotobynumber (atol (key[i]));
639       else
640         proto = getprotobyname (key[i]);
641
642       if (proto == NULL)
643         result = 2;
644       else
645         print_protocols (proto);
646     }
647
648   return result;
649 }
650
651 /* Now is all for rpc */
652 static inline void
653 print_rpc (struct rpcent *rpc)
654 {
655   int i;
656
657   printf ("%-15s %d%s",
658           rpc->r_name, rpc->r_number, rpc->r_aliases[0] ? " " : "");
659
660   for (i = 0; rpc->r_aliases[i]; ++i)
661     printf (" %s", rpc->r_aliases[i]);
662   putchar_unlocked ('\n');
663 }
664
665 static int
666 rpc_keys (int number, char *key[])
667 {
668   int result = 0;
669   int i;
670   struct rpcent *rpc;
671
672   if (number == 0)
673     {
674       setrpcent (0);
675       while ((rpc = getrpcent ()) != NULL)
676         print_rpc (rpc);
677       endrpcent ();
678       return result;
679     }
680
681   for (i = 0; i < number; ++i)
682     {
683       if (isdigit (key[i][0]))
684         rpc = getrpcbynumber (atol (key[i]));
685       else
686         rpc = getrpcbyname (key[i]);
687
688       if (rpc == NULL)
689         result = 2;
690       else
691         print_rpc (rpc);
692     }
693
694   return result;
695 }
696
697 /* for services */
698 static void
699 print_services (struct servent *serv)
700 {
701   unsigned int i;
702
703   printf ("%-21s %d/%s", serv->s_name, ntohs (serv->s_port), serv->s_proto);
704
705   i = 0;
706   while (serv->s_aliases[i] != NULL)
707     {
708       putchar_unlocked (' ');
709       fputs_unlocked (serv->s_aliases[i], stdout);
710       ++i;
711     }
712   putchar_unlocked ('\n');
713 }
714
715 static int
716 services_keys (int number, char *key[])
717 {
718   int result = 0;
719   int i;
720   struct servent *serv;
721
722   if (!number)
723     {
724       setservent (0);
725       while ((serv = getservent ()) != NULL)
726         print_services (serv);
727       endservent ();
728       return result;
729     }
730
731   for (i = 0; i < number; ++i)
732     {
733       struct servent *serv;
734       char *proto = strchr (key[i], '/');
735
736       if (proto != NULL)
737         *proto++ = '\0';
738
739       if (isdigit (key[i][0]))
740         serv = getservbyport (htons (atol (key[i])), proto);
741       else
742         serv = getservbyname (key[i], proto);
743
744       if (serv == NULL)
745         result = 2;
746       else
747         print_services (serv);
748     }
749
750   return result;
751 }
752
753 /* This is for shadow */
754 static void
755 print_shadow (struct spwd *sp)
756 {
757   printf ("%s:%s:",
758           sp->sp_namp ? sp->sp_namp : "",
759           sp->sp_pwdp ? sp->sp_pwdp : "");
760
761 #define SHADOW_FIELD(n) \
762   if (sp->n == -1)                                                            \
763     putchar_unlocked (':');                                                   \
764   else                                                                        \
765     printf ("%ld:", sp->n)
766
767   SHADOW_FIELD (sp_lstchg);
768   SHADOW_FIELD (sp_min);
769   SHADOW_FIELD (sp_max);
770   SHADOW_FIELD (sp_warn);
771   SHADOW_FIELD (sp_inact);
772   SHADOW_FIELD (sp_expire);
773   if (sp->sp_flag == ~0ul)
774     putchar_unlocked ('\n');
775   else
776     printf ("%lu\n", sp->sp_flag);
777 }
778
779 static int
780 shadow_keys (int number, char *key[])
781 {
782   int result = 0;
783   int i;
784
785   if (number == 0)
786     {
787       struct spwd *sp;
788
789       setspent ();
790       while ((sp = getspent ()) != NULL)
791         print_shadow (sp);
792       endpwent ();
793       return result;
794     }
795
796   for (i = 0; i < number; ++i)
797     {
798       struct spwd *sp;
799
800       sp = getspnam (key[i]);
801
802       if (sp == NULL)
803         result = 2;
804       else
805         print_shadow (sp);
806     }
807
808   return result;
809 }
810
811 struct
812   {
813     const char *name;
814     int (*func) (int number, char *key[]);
815   } databases[] =
816   {
817 #define D(name) { #name, name ## _keys },
818 D(ahosts)
819 D(ahostsv4)
820 D(ahostsv6)
821 D(aliases)
822 D(ethers)
823 D(group)
824 D(gshadow)
825 D(hosts)
826 D(netgroup)
827 D(networks)
828 D(passwd)
829 D(protocols)
830 D(rpc)
831 D(services)
832 D(shadow)
833 #undef D
834     { NULL, NULL }
835   };
836
837 /* Handle arguments found by argp. */
838 static error_t
839 parse_option (int key, char *arg, struct argp_state *state)
840 {
841   char *endp;
842   switch (key)
843     {
844     case 's':
845       endp = strchr (arg, ':');
846       if (endp == NULL)
847         /* No specific database, change them all.  */
848         for (int i = 0; databases[i].name != NULL; ++i)
849           __nss_configure_lookup (databases[i].name, arg);
850       else
851         {
852           int i;
853           for (i = 0; databases[i].name != NULL; ++i)
854             if (strncmp (databases[i].name, arg, endp - arg) == 0)
855               {
856                 __nss_configure_lookup (databases[i].name, endp + 1);
857                 break;
858               }
859           if (databases[i].name == NULL)
860             error (EXIT_FAILURE, 0, gettext ("Unknown database name"));
861         }
862       break;
863
864     default:
865       return ARGP_ERR_UNKNOWN;
866     }
867
868   return 0;
869 }
870
871
872 static char *
873 more_help (int key, const char *text, void *input)
874 {
875   switch (key)
876     {
877       size_t len;
878       char *doc;
879       FILE *fp;
880
881     case ARGP_KEY_HELP_EXTRA:
882       /* We print some extra information.  */
883       fp = open_memstream (&doc, &len);
884       if (fp != NULL)
885         {
886           fputs_unlocked (_("Supported databases:\n"), fp);
887
888           for (int i = 0, col = 0; databases[i].name != NULL; ++i)
889             {
890               len = strlen (databases[i].name);
891               if (i != 0)
892                 {
893                   if (col + len > 72)
894                     {
895                       col = 0;
896                       fputc_unlocked ('\n', fp);
897                     }
898                   else
899                     fputc_unlocked (' ', fp);
900                 }
901
902               fputs_unlocked (databases[i].name, fp);
903               col += len + 1;
904             }
905
906           fputs ("\n\n", fp);
907
908           fprintf (fp, gettext ("\
909 For bug reporting instructions, please see:\n\
910 <http://www.gnu.org/software/libc/bugs.html>.\n"));
911
912           if (fclose (fp) == 0)
913             return doc;
914         }
915       break;
916
917     default:
918       break;
919     }
920   return (char *) text;
921 }
922
923
924 /* the main function */
925 int
926 main (int argc, char *argv[])
927 {
928   /* Debugging support.  */
929   mtrace ();
930
931   /* Set locale via LC_ALL.  */
932   setlocale (LC_ALL, "");
933   /* Set the text message domain.  */
934   textdomain (PACKAGE);
935
936   /* Parse and process arguments.  */
937   int remaining;
938   argp_parse (&argp, argc, argv, 0, &remaining, NULL);
939
940   if ((argc - remaining) < 1)
941     {
942       error (0, 0, gettext ("wrong number of arguments"));
943       argp_help (&argp, stdout, ARGP_HELP_SEE, program_invocation_short_name);
944       return 1;
945     }
946
947   for (int i = 0; databases[i].name; ++i)
948     if (argv[remaining][0] == databases[i].name[0]
949         && !strcmp (argv[remaining], databases[i].name))
950       return databases[i].func (argc - remaining - 1, &argv[remaining + 1]);
951
952   fprintf (stderr, _("Unknown database: %s\n"), argv[remaining]);
953   argp_help (&argp, stdout, ARGP_HELP_SEE, program_invocation_short_name);
954   return 1;
955 }