Update copyright notices with scripts/update-copyrights
[platform/upstream/glibc.git] / nss / getent.c
1 /* Copyright (c) 1998-2014 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 "), "2013");
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 }