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