]> 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
177 printf ("%s:%s:%ld:", grp->gr_name ? grp->gr_name : "",
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 {
7d6a8338 209 if (isdigit (key[i][0]))
8e9b2075
UD
210 {
211 char *ep;
0308a475 212 gid_t arg_gid = strtoul (key[i], &ep, 10);
8e9b2075
UD
213
214 if (*key[i] != '\0' && *ep == '\0') /* valid numeric uid */
215 grp = getgrgid (arg_gid);
216 else
217 grp = NULL;
218 }
7d6a8338
UD
219 else
220 grp = getgrnam (key[i]);
221
222 if (grp == NULL)
223 result = 2;
224 else
225 print_group (grp);
226 }
227
228 return result;
229}
230
232b4655 231/* This is for hosts */
25337753 232static void
232b4655
UD
233print_hosts (struct hostent *host)
234{
fdcd8f9c 235 unsigned int cnt;
232b4655 236
fdcd8f9c 237 for (cnt = 0; host->h_addr_list[cnt] != NULL; ++cnt)
232b4655 238 {
fdcd8f9c
UD
239 char buf[INET6_ADDRSTRLEN];
240 const char *ip = inet_ntop (host->h_addrtype, host->h_addr_list[cnt],
241 buf, sizeof (buf));
242
243 printf ("%-15s %s", ip, host->h_name);
244
245 unsigned int i;
246 for (i = 0; host->h_aliases[i] != NULL; ++i)
247 {
248 putchar_unlocked (' ');
249 fputs_unlocked (host->h_aliases[i], stdout);
250 }
251 putchar_unlocked ('\n');
232b4655 252 }
232b4655
UD
253}
254
255static int
256hosts_keys (int number, char *key[])
257{
258 int result = 0;
259 int i;
260 struct hostent *host;
261
9d0881aa 262 if (number == 0)
232b4655
UD
263 {
264 sethostent (0);
9d0881aa 265 while ((host = gethostent ()) != NULL)
232b4655
UD
266 print_hosts (host);
267 endhostent ();
268 return result;
269 }
270
271 for (i = 0; i < number; ++i)
272 {
273 struct hostent *host = NULL;
274
275 if (strchr (key[i], ':') != NULL)
276 {
277 char addr[IN6ADDRSZ];
278 if (inet_pton (AF_INET6, key[i], &addr))
279 host = gethostbyaddr (addr, sizeof (addr), AF_INET6);
280 }
281 else if (isdigit (key[i][0]))
282 {
283 char addr[INADDRSZ];
284 if (inet_pton (AF_INET, key[i], &addr))
285 host = gethostbyaddr (addr, sizeof (addr), AF_INET);
286 }
287 else if ((host = gethostbyname2 (key[i], AF_INET6)) == NULL)
288 host = gethostbyname2 (key[i], AF_INET);
289
290 if (host == NULL)
291 result = 2;
292 else
293 print_hosts (host);
294 }
295
296 return result;
297}
298
29bfc945
UD
299/* This is for hosts, but using getaddrinfo */
300static int
301ahosts_keys (int number, char *key[])
302{
303 int result = 0;
304 int i;
305 struct hostent *host;
306
307 if (number == 0)
308 {
309 sethostent (0);
310 while ((host = gethostent ()) != NULL)
311 print_hosts (host);
312 endhostent ();
313 return result;
314 }
315
316 struct addrinfo hint;
317 memset (&hint, '\0', sizeof (hint));
318 hint.ai_flags = AI_V4MAPPED | AI_ADDRCONFIG | AI_CANONNAME;
319 hint.ai_family = AF_UNSPEC;
320
321 for (i = 0; i < number; ++i)
322 {
323 struct addrinfo *res;
324
325 if (getaddrinfo (key[i], NULL, &hint, &res) != 0)
326 result = 2;
327 else
328 {
329 struct addrinfo *runp = res;
330
331 while (runp != NULL)
332 {
333 char sockbuf[20];
334 const char *sockstr;
335 if (runp->ai_socktype == SOCK_STREAM)
336 sockstr = "STREAM";
337 else if (runp->ai_socktype == SOCK_DGRAM)
338 sockstr = "DGRAM";
339 else if (runp->ai_socktype == SOCK_RAW)
340 sockstr = "RAW";
341 else
342 {
343 snprintf (sockbuf, sizeof (sockbuf), "%d",
344 runp->ai_socktype);
345 sockstr = sockbuf;
346 }
347
348 char buf[INET6_ADDRSTRLEN];
349 printf ("%-15s %-6s %s\n",
350 inet_ntop (runp->ai_family,
351 &((struct sockaddr_in *) runp->ai_addr)->sin_addr,
352 buf, sizeof (buf)),
353 sockstr,
354 runp->ai_canonname);
355
356 runp = runp->ai_next;
357 }
358
359 freeaddrinfo (res);
360 }
361 }
362
363 return result;
364}
365
232b4655
UD
366/* This is for netgroup */
367static int
368netgroup_keys (int number, char *key[])
369{
370 int result = 0;
9d0881aa 371 int i;
232b4655 372
9d0881aa 373 if (number == 0)
232b4655
UD
374 {
375 fprintf (stderr, _("Enumeration not supported on %s\n"), "netgroup");
376 return 3;
377 }
378
379 for (i = 0; i < number; ++i)
380 {
381 if (!setnetgrent (key[i]))
382 result = 2;
383 else
384 {
385 char *p[3];
386
9d0881aa 387 printf ("%-21s", key[i]);
232b4655
UD
388
389 while (getnetgrent (p, p + 1, p + 2))
390 printf (" (%s, %s, %s)", p[0] ?: " ", p[1] ?: "", p[2] ?: "");
9d0881aa 391 putchar_unlocked ('\n');
232b4655
UD
392 }
393 }
394
395 return result;
396}
397
7d6a8338 398/* This is for networks */
25337753 399static void
7d6a8338
UD
400print_networks (struct netent *net)
401{
402 unsigned int i;
403 struct in_addr ip;
404 ip.s_addr = htonl (net->n_net);
405
9d0881aa 406 printf ("%-21s %s", net->n_name, inet_ntoa (ip));
7d6a8338
UD
407
408 i = 0;
409 while (net->n_aliases[i] != NULL)
410 {
9d0881aa
UD
411 putchar_unlocked (' ');
412 fputs_unlocked (net->n_aliases[i], stdout);
7d6a8338
UD
413 ++i;
414 if (net->n_aliases[i] != NULL)
9d0881aa 415 putchar_unlocked (',');
7d6a8338 416 }
9d0881aa 417 putchar_unlocked ('\n');
7d6a8338
UD
418}
419
232b4655 420static int
7d6a8338
UD
421networks_keys (int number, char *key[])
422{
423 int result = 0;
424 int i;
232b4655 425 struct netent *net;
7d6a8338 426
9d0881aa 427 if (number == 0)
7d6a8338 428 {
232b4655 429 setnetent (0);
9d0881aa 430 while ((net = getnetent ()) != NULL)
232b4655
UD
431 print_networks (net);
432 endnetent ();
433 return result;
434 }
7d6a8338 435
232b4655
UD
436 for (i = 0; i < number; ++i)
437 {
7d6a8338
UD
438 if (isdigit (key[i][0]))
439 net = getnetbyaddr (inet_addr (key[i]), AF_UNIX);
440 else
441 net = getnetbyname (key[i]);
442
443 if (net == NULL)
444 result = 2;
445 else
446 print_networks (net);
447 }
448
449 return result;
450}
451
452/* Now is all for passwd */
453static inline void
454print_passwd (struct passwd *pwd)
455{
456 printf ("%s:%s:%ld:%ld:%s:%s:%s\n",
457 pwd->pw_name ? pwd->pw_name : "",
458 pwd->pw_passwd ? pwd->pw_passwd : "",
9d0881aa
UD
459 (unsigned long int) pwd->pw_uid,
460 (unsigned long int) pwd->pw_gid,
7d6a8338
UD
461 pwd->pw_gecos ? pwd->pw_gecos : "",
462 pwd->pw_dir ? pwd->pw_dir : "",
463 pwd->pw_shell ? pwd->pw_shell : "");
464}
465
232b4655 466static int
7d6a8338
UD
467passwd_keys (int number, char *key[])
468{
469 int result = 0;
470 int i;
232b4655 471 struct passwd *pwd;
7d6a8338 472
9d0881aa 473 if (number == 0)
7d6a8338 474 {
232b4655 475 setpwent ();
9d0881aa 476 while ((pwd = getpwent ()) != NULL)
232b4655
UD
477 print_passwd (pwd);
478 endpwent ();
479 return result;
480 }
7d6a8338 481
232b4655
UD
482 for (i = 0; i < number; ++i)
483 {
7d6a8338 484 if (isdigit (key[i][0]))
8e9b2075
UD
485 {
486 char *ep;
0308a475 487 uid_t arg_uid = strtoul (key[i], &ep, 10);
8e9b2075
UD
488
489 if (*key[i] != '\0' && *ep == '\0') /* valid numeric uid */
490 pwd = getpwuid (arg_uid);
491 else
492 pwd = NULL;
493 }
7d6a8338
UD
494 else
495 pwd = getpwnam (key[i]);
496
497 if (pwd == NULL)
498 result = 2;
499 else
500 print_passwd (pwd);
501 }
502
503 return result;
504}
505
506/* This is for protocols */
507static inline void
508print_protocols (struct protoent *proto)
509{
510 unsigned int i;
511
9d0881aa 512 printf ("%-21s %d", proto->p_name, proto->p_proto);
7d6a8338
UD
513
514 i = 0;
515 while (proto->p_aliases[i] != NULL)
516 {
9d0881aa
UD
517 putchar_unlocked (' ');
518 fputs_unlocked (proto->p_aliases[i], stdout);
7d6a8338
UD
519 ++i;
520 }
9d0881aa 521 putchar_unlocked ('\n');
7d6a8338
UD
522}
523
232b4655 524static int
7d6a8338
UD
525protocols_keys (int number, char *key[])
526{
527 int result = 0;
528 int i;
232b4655 529 struct protoent *proto;
7d6a8338 530
9d0881aa 531 if (number == 0)
7d6a8338 532 {
232b4655 533 setprotoent (0);
9d0881aa 534 while ((proto = getprotoent ()) != NULL)
232b4655
UD
535 print_protocols (proto);
536 endprotoent ();
537 return result;
538 }
7d6a8338 539
232b4655
UD
540 for (i = 0; i < number; ++i)
541 {
7d6a8338
UD
542 if (isdigit (key[i][0]))
543 proto = getprotobynumber (atol (key[i]));
544 else
545 proto = getprotobyname (key[i]);
546
547 if (proto == NULL)
548 result = 2;
549 else
550 print_protocols (proto);
551 }
552
553 return result;
554}
555
232b4655 556/* Now is all for rpc */
7d6a8338 557static inline void
232b4655 558print_rpc (struct rpcent *rpc)
7d6a8338 559{
232b4655 560 int i;
7d6a8338 561
9d0881aa
UD
562 printf ("%-15s %d%s",
563 rpc->r_name, rpc->r_number, rpc->r_aliases[0] ? " " : "");
7d6a8338 564
232b4655
UD
565 for (i = 0; rpc->r_aliases[i]; ++i)
566 printf (" %s", rpc->r_aliases[i]);
9d0881aa 567 putchar_unlocked ('\n');
7d6a8338
UD
568}
569
232b4655
UD
570static int
571rpc_keys (int number, char *key[])
7d6a8338
UD
572{
573 int result = 0;
574 int i;
232b4655 575 struct rpcent *rpc;
7d6a8338 576
9d0881aa 577 if (number == 0)
7d6a8338 578 {
232b4655 579 setrpcent (0);
9d0881aa 580 while ((rpc = getrpcent ()) != NULL)
232b4655
UD
581 print_rpc (rpc);
582 endrpcent ();
583 return result;
584 }
7d6a8338 585
232b4655
UD
586 for (i = 0; i < number; ++i)
587 {
588 if (isdigit (key[i][0]))
589 rpc = getrpcbynumber (atol (key[i]));
590 else
591 rpc = getrpcbyname (key[i]);
7d6a8338 592
232b4655 593 if (rpc == NULL)
7d6a8338
UD
594 result = 2;
595 else
232b4655 596 print_rpc (rpc);
7d6a8338
UD
597 }
598
599 return result;
600}
601
602/* for services */
232b4655 603static void
7d6a8338
UD
604print_services (struct servent *serv)
605{
606 unsigned int i;
607
9d0881aa 608 printf ("%-21s %d/%s", serv->s_name, ntohs (serv->s_port), serv->s_proto);
7d6a8338
UD
609
610 i = 0;
611 while (serv->s_aliases[i] != NULL)
612 {
9d0881aa
UD
613 putchar_unlocked (' ');
614 fputs_unlocked (serv->s_aliases[i], stdout);
7d6a8338
UD
615 ++i;
616 }
9d0881aa 617 putchar_unlocked ('\n');
7d6a8338
UD
618}
619
232b4655 620static int
7d6a8338
UD
621services_keys (int number, char *key[])
622{
623 int result = 0;
624 int i;
232b4655
UD
625 struct servent *serv;
626
627 if (!number)
628 {
629 setservent (0);
9d0881aa 630 while ((serv = getservent ()) != NULL)
232b4655
UD
631 print_services (serv);
632 endservent ();
633 return result;
634 }
7d6a8338
UD
635
636 for (i = 0; i < number; ++i)
637 {
638 struct servent *serv;
639 char *proto = strchr (key[i], '/');
640
641 if (proto == NULL)
642 {
643 setservent (0);
644 if (isdigit (key[i][0]))
645 {
646 int port = htons (atol (key[i]));
647 while ((serv = getservent ()) != NULL)
648 if (serv->s_port == port)
649 {
650 print_services (serv);
651 break;
652 }
653 }
654 else
655 {
232b4655
UD
656 int j;
657
7d6a8338
UD
658 while ((serv = getservent ()) != NULL)
659 if (strcmp (serv->s_name, key[i]) == 0)
660 {
661 print_services (serv);
662 break;
663 }
232b4655
UD
664 else
665 for (j = 0; serv->s_aliases[j]; ++j)
666 if (strcmp (serv->s_aliases[j], key[i]) == 0)
667 {
668 print_services (serv);
669 break;
670 }
7d6a8338
UD
671 }
672 endservent ();
673 }
674 else
675 {
676 *proto++ = '\0';
677
678 if (isdigit (key[i][0]))
9f835f5f 679 serv = getservbyport (htons (atol (key[i])), proto);
7d6a8338
UD
680 else
681 serv = getservbyname (key[i], proto);
682
683 if (serv == NULL)
684 result = 2;
685 else
686 print_services (serv);
687 }
688 }
689
690 return result;
691}
692
232b4655 693/* This is for shadow */
25337753 694static void
232b4655 695print_shadow (struct spwd *sp)
7d6a8338 696{
232b4655
UD
697 printf ("%s:%s:",
698 sp->sp_namp ? sp->sp_namp : "",
699 sp->sp_pwdp ? sp->sp_pwdp : "");
700
9d0881aa
UD
701#define SHADOW_FIELD(n) \
702 if (sp->n == -1) \
703 putchar_unlocked (':'); \
704 else \
232b4655
UD
705 printf ("%ld:", sp->n)
706
707 SHADOW_FIELD (sp_lstchg);
708 SHADOW_FIELD (sp_min);
709 SHADOW_FIELD (sp_max);
710 SHADOW_FIELD (sp_warn);
711 SHADOW_FIELD (sp_inact);
712 SHADOW_FIELD (sp_expire);
713 if (sp->sp_flag == ~0ul)
9d0881aa 714 putchar_unlocked ('\n');
232b4655
UD
715 else
716 printf ("%lu\n", sp->sp_flag);
717}
7d6a8338 718
232b4655
UD
719static int
720shadow_keys (int number, char *key[])
721{
722 int result = 0;
723 int i;
7d6a8338 724
9d0881aa 725 if (number == 0)
7d6a8338 726 {
232b4655
UD
727 struct spwd *sp;
728
729 setspent ();
9d0881aa 730 while ((sp = getspent ()) != NULL)
232b4655
UD
731 print_shadow (sp);
732 endpwent ();
733 return result;
7d6a8338
UD
734 }
735
232b4655 736 for (i = 0; i < number; ++i)
7d6a8338 737 {
232b4655 738 struct spwd *sp;
7d6a8338 739
232b4655 740 sp = getspnam (key[i]);
7d6a8338 741
232b4655
UD
742 if (sp == NULL)
743 result = 2;
7d6a8338 744 else
232b4655
UD
745 print_shadow (sp);
746 }
7d6a8338 747
232b4655
UD
748 return result;
749}
7d6a8338 750
232b4655
UD
751struct
752 {
753 const char *name;
754 int (*func) (int number, char *key[]);
755 } databases[] =
756 {
757#define D(name) { #name, name ## _keys },
29bfc945 758D(ahosts)
232b4655
UD
759D(aliases)
760D(ethers)
761D(group)
762D(hosts)
763D(netgroup)
764D(networks)
765D(passwd)
766D(protocols)
767D(rpc)
768D(services)
769D(shadow)
770#undef D
9d0881aa 771 { NULL, NULL }
232b4655
UD
772 };
773
9d0881aa
UD
774/* Handle arguments found by argp. */
775static error_t
776parse_option (int key, char *arg, struct argp_state *state)
777{
778 int i;
779 switch (key)
780 {
781 case 's':
782 for (i = 0; databases[i].name; ++i)
783 __nss_configure_lookup (databases[i].name, arg);
784 break;
785
786 default:
787 return ARGP_ERR_UNKNOWN;
788 }
789
790 return 0;
791}
792
232b4655 793/* build doc */
25337753 794static void
232b4655
UD
795build_doc (void)
796{
797 int i, j, len;
798 char *short_doc, *long_doc, *doc, *p;
7d6a8338 799
232b4655
UD
800 short_doc = _("getent - get entries from administrative database.");
801 long_doc = _("Supported databases:");
802 len = strlen (short_doc) + strlen (long_doc) + 3;
803
804 for (i = 0; databases[i].name; ++i)
805 len += strlen (databases[i].name) + 1;
806
807 doc = (char *) malloc (len);
9d0881aa 808 if (doc == NULL)
232b4655
UD
809 doc = short_doc;
810 else
811 {
812 p = stpcpy (doc, short_doc);
813 *p++ = '\v';
814 p = stpcpy (p, long_doc);
815 *p++ = '\n';
816
817 for (i = 0, j = 0; databases[i].name; ++i)
7d6a8338 818 {
232b4655 819 len = strlen (databases[i].name);
9d0881aa 820 if (i != 0)
7d6a8338 821 {
9d0881aa 822 if (j + len > 72)
232b4655
UD
823 {
824 j = 0;
825 *p++ = '\n';
826 }
827 else
828 *p++ = ' ';
7d6a8338 829 }
232b4655 830
9d0881aa 831 p = mempcpy (p, databases[i].name, len);
232b4655 832 j += len + 1;
7d6a8338 833 }
232b4655
UD
834 }
835
836 argp.doc = doc;
837}
838
839/* the main function */
840int
841main (int argc, char *argv[])
842{
843 int remaining, i;
844
845 /* Set locale via LC_ALL. */
846 setlocale (LC_ALL, "");
847 /* Set the text message domain. */
848 textdomain (PACKAGE);
849
850 /* Build argp.doc. */
851 build_doc ();
852
853 /* Parse and process arguments. */
854 argp_parse (&argp, argc, argv, 0, &remaining, NULL);
855
856 if ((argc - remaining) < 1)
857 {
858 error (0, 0, gettext ("wrong number of arguments"));
7d6a8338
UD
859 argp_help (&argp, stdout, ARGP_HELP_SEE, program_invocation_short_name);
860 return 1;
861 }
862
232b4655 863 for (i = 0; databases[i].name; ++i)
9d0881aa
UD
864 if (argv[remaining][0] == databases[i].name[0]
865 && !strcmp (argv[remaining], databases[i].name))
866 return databases[i].func (argc - remaining - 1, &argv[remaining + 1]);
232b4655 867
9d0881aa 868 fprintf (stderr, _("Unknown database: %s\n"), argv[remaining]);
232b4655
UD
869 argp_help (&argp, stdout, ARGP_HELP_SEE, program_invocation_short_name);
870 return 1;
7d6a8338 871}