]> git.ipfire.org Git - thirdparty/glibc.git/blob - nss/getent.c
Update copyright year.
[thirdparty/glibc.git] / nss / getent.c
1 /* Copyright (c) 1998-2008, 2009, 2010 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 "), "2010");
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 (ntohl (inet_addr (key[i])), AF_UNSPEC);
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 fputs (gettext ("\
909 For bug reporting instructions, please see:\n\
910 <http://www.gnu.org/software/libc/bugs.html>.\n"), fp);
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 }