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