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