1 /* gen-fixed-nsswitch.c --- generate fixed name service data structures
2 Copyright (C) 1996-1999, 2001-2006, 2007 Free Software Foundation, Inc.
3 This file is part of the GNU C Library.
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.
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.
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
30 #include "gnu/lib-names.h"
33 /* Provide a fallback definition to allow this file to be compiled outside
35 #ifndef internal_function
36 # define internal_function
40 /* Simple utilities. */
42 void __attribute__ ((noreturn))
43 error (const char *message)
45 fprintf (stderr, "%s\n", message);
56 error ("out of memory");
62 return check_alloc (malloc (size));
66 /* Format ARGS according to FORMAT, and return the result as a
69 saprintf (const char *format, ...)
75 va_start (args, format);
76 len = vsnprintf (NULL, 0, format, args);
79 buf = xmalloc (len + 1);
80 va_start (args, format);
81 assert (len == vsnprintf (buf, len + 1, format, args));
89 /* Data structures representing the configuration file in memory. */
91 /* These are copied from nsswitch.h.
93 We could simply #include that file, but this program runs on the
94 build machine and links against the build machine's libraries,
95 whereas that header is meant for use by target code; it uses
96 'libc_hidden_proto', 'internal_function', and related hair. Since
97 we've copied the parsing code, we might as well copy the data
98 structure definitions as well. */
100 /* Actions performed after lookup finished. */
108 typedef struct service_library
110 /* Name of service (`files', `dns', `nis', ...). */
112 /* Pointer to the loaded shared library. */
114 /* And the link to the next entry. */
115 struct service_library *next;
119 /* For mapping a function name to a function pointer. It is known in
120 nsswitch.c:nss_lookup_function that a string pointer for the lookup key
121 is the first member. */
124 const char *fct_name;
129 typedef struct service_user
131 /* And the link to the next entry. */
132 struct service_user *next;
133 /* Action according to result. */
134 lookup_actions actions[5];
135 /* Link to the underlying library object. */
136 service_library *library;
137 /* Collection of known functions.
139 With OPTION_EGLIBC_NSSWITCH enabled, this is the root of a
140 'tsearch'-style tree.
142 With OPTION_EGLIBC_NSSWITCH disabled, this is an array of
143 pointers to known_function structures, NULL-terminated. */
147 const known_function **array;
149 /* Name of the service (`files', `dns', `nis', ...). */
153 /* To access the action based on the status value use this macro. */
154 #define nss_next_action(ni, status) ((ni)->actions[2 + status])
157 typedef struct name_database_entry
159 /* And the link to the next entry. */
160 struct name_database_entry *next;
161 /* List of service to be used. */
162 service_user *service;
163 /* Name of the database. */
165 } name_database_entry;
168 typedef struct name_database
170 /* List of all known databases. */
171 name_database_entry *entry;
172 /* List of libraries with service implementation. */
173 service_library *library;
178 /* Gathering the contents of the FIXED_FUNCTIONS file. */
180 /* It should be possible to generate this list automatically by
181 looking at the services and databases used in the nsswitch.conf
182 file, and having a hard-coded set of queries supported on each
185 /* We #include the FIXED_FUNCTIONS file several times to build an
186 array of function structures holding its data. */
188 fk_end = 0, /* Last entry. */
189 fk_setent, /* Like setpwent. */
190 fk_getent, /* Like getpwent. */
191 fk_endent, /* Like endpwent. */
192 fk_getby, /* Like gethostbyname. */
193 fk_get /* Like getpwnam. */
198 /* What kind of function this is. */
199 enum function_kind kind;
201 /* The database and service of the function being hardwired in. */
202 char *database, *service;
204 /* The kind of entry being queried, for 'fk_setent', 'fk_getent',
205 'fk_endent', and 'fk_getby' functions. */
208 /* The key, for 'fk_getby' entries. */
211 /* The value and key, for 'fk_get' entries. */
216 const struct function functions[] =
219 #define DEFINE_ENT(database, service, entry) \
220 { fk_setent, #database, #service, #entry }, \
221 { fk_getent, #database, #service, #entry }, \
222 { fk_endent, #database, #service, #entry },
223 #define DEFINE_GETBY(database, service, entry, key) \
224 { fk_getby, #database, #service, #entry, #key },
225 #define DEFINE_GET(database, service, value_and_key) \
226 { fk_get, #database, #service, NULL, NULL, #value_and_key },
228 #include FIXED_FUNCTIONS
238 /* Parsing the config file. Functions copied from nsswitch.c. */
240 #define __strchrnul strchrnul
241 #define __getline getline
242 #define __strncasecmp strncasecmp
244 /* Prototypes for the local functions. */
245 static name_database *nss_parse_file (const char *fname) internal_function;
246 static name_database_entry *nss_getline (char *line) internal_function;
247 static service_user *nss_parse_service_list (const char *line)
250 static name_database *
252 nss_parse_file (const char *fname)
255 name_database *result;
256 name_database_entry *last;
260 /* Open the configuration file. */
261 fp = fopen (fname, "rc");
265 // /* No threads use this stream. */
266 // __fsetlocking (fp, FSETLOCKING_BYCALLER);
268 result = (name_database *) xmalloc (sizeof (name_database));
270 result->entry = NULL;
271 result->library = NULL;
277 name_database_entry *this;
280 n = __getline (&line, &len, fp);
283 if (line[n - 1] == '\n')
286 /* Because the file format does not know any form of quoting we
287 can search forward for the next '#' character and if found
288 make it terminating the line. */
289 *__strchrnul (line, '#') = '\0';
291 /* If the line is blank it is ignored. */
295 /* Each line completely specifies the actions for a database. */
296 this = nss_getline (line);
302 result->entry = this;
307 while (!feof_unlocked (fp));
309 /* Free the buffer. */
311 /* Close configuration file. */
318 /* Read the source names:
319 `( <source> ( "[" "!"? (<status> "=" <action> )+ "]" )? )*'
321 static service_user *
323 nss_parse_service_list (const char *line)
325 service_user *result = NULL, **nextp = &result;
329 service_user *new_service;
332 while (isspace (line[0]))
335 /* No source specified. */
338 /* Read <source> identifier. */
340 while (line[0] != '\0' && !isspace (line[0]) && line[0] != '[')
346 new_service = (service_user *) xmalloc (sizeof (*new_service));
347 new_service->name = (char *) xmalloc (line - name + 1);
349 *((char *) __mempcpy ((char *) new_service->name, name, line - name))
352 /* Set default actions. */
353 new_service->actions[2 + NSS_STATUS_TRYAGAIN] = NSS_ACTION_CONTINUE;
354 new_service->actions[2 + NSS_STATUS_UNAVAIL] = NSS_ACTION_CONTINUE;
355 new_service->actions[2 + NSS_STATUS_NOTFOUND] = NSS_ACTION_CONTINUE;
356 new_service->actions[2 + NSS_STATUS_SUCCESS] = NSS_ACTION_RETURN;
357 new_service->actions[2 + NSS_STATUS_RETURN] = NSS_ACTION_RETURN;
358 new_service->library = NULL;
359 new_service->known.tree = NULL;
360 new_service->next = NULL;
362 while (isspace (line[0]))
367 /* Read criterions. */
370 while (line[0] != '\0' && isspace (line[0]));
375 enum nss_status status;
376 lookup_actions action;
378 /* Grok ! before name to mean all statii but that one. */
379 not = line[0] == '!';
383 /* Read status name. */
385 while (line[0] != '\0' && !isspace (line[0]) && line[0] != '='
389 /* Compare with known statii. */
390 if (line - name == 7)
392 if (__strncasecmp (name, "SUCCESS", 7) == 0)
393 status = NSS_STATUS_SUCCESS;
394 else if (__strncasecmp (name, "UNAVAIL", 7) == 0)
395 status = NSS_STATUS_UNAVAIL;
399 else if (line - name == 8)
401 if (__strncasecmp (name, "NOTFOUND", 8) == 0)
402 status = NSS_STATUS_NOTFOUND;
403 else if (__strncasecmp (name, "TRYAGAIN", 8) == 0)
404 status = NSS_STATUS_TRYAGAIN;
411 while (isspace (line[0]))
417 while (isspace (line[0]));
420 while (line[0] != '\0' && !isspace (line[0]) && line[0] != '='
424 if (line - name == 6 && __strncasecmp (name, "RETURN", 6) == 0)
425 action = NSS_ACTION_RETURN;
426 else if (line - name == 8
427 && __strncasecmp (name, "CONTINUE", 8) == 0)
428 action = NSS_ACTION_CONTINUE;
434 /* Save the current action setting for this status,
435 set them all to the given action, and reset this one. */
436 const lookup_actions save = new_service->actions[2 + status];
437 new_service->actions[2 + NSS_STATUS_TRYAGAIN] = action;
438 new_service->actions[2 + NSS_STATUS_UNAVAIL] = action;
439 new_service->actions[2 + NSS_STATUS_NOTFOUND] = action;
440 new_service->actions[2 + NSS_STATUS_SUCCESS] = action;
441 new_service->actions[2 + status] = save;
444 new_service->actions[2 + status] = action;
446 /* Skip white spaces. */
447 while (isspace (line[0]))
450 while (line[0] != ']');
456 *nextp = new_service;
457 nextp = &new_service->next;
461 static name_database_entry *
463 nss_getline (char *line)
466 name_database_entry *result;
469 /* Ignore leading white spaces. ATTENTION: this is different from
470 what is implemented in Solaris. The Solaris man page says a line
471 beginning with a white space character is ignored. We regard
472 this as just another misfeature in Solaris. */
473 while (isspace (line[0]))
476 /* Recognize `<database> ":"'. */
478 while (line[0] != '\0' && !isspace (line[0]) && line[0] != ':')
480 if (line[0] == '\0' || name == line)
485 len = strlen (name) + 1;
487 result = (name_database_entry *) xmalloc (sizeof (*result));
488 result->name = (char *) xmalloc (len);
490 /* Save the database name. */
491 memcpy ((char *) result->name, name, len);
493 /* Parse the list of services. */
494 result->service = nss_parse_service_list (line);
502 /* Generating code for statically initialized nsswitch structures. */
505 /* Return the service-neutral suffix of the name of the service
506 library function referred to by the function F. The result is
507 allocated with malloc. */
509 known_function_suffix (const struct function *f)
514 return saprintf ("set%sent", f->entry);
517 return saprintf ("get%sent_r", f->entry);
520 return saprintf ("end%sent", f->entry);
523 return saprintf ("get%sby%s_r", f->entry, f->key);
526 return saprintf ("get%s_r", f->value_and_key);
534 /* Return the name of the service library function referred to by the
535 function F. The result is allocated with malloc. */
537 known_function_name (const struct function *f)
539 return saprintf ("_nss_%s_%s", f->service, known_function_suffix (f));
543 /* Write initialized known_function structures to OUT for
544 all the functions we'll use. */
546 generate_known_functions (FILE *out)
550 /* First, generate weak references to the functions. The service
551 libraries depend on libc, and if these references weren't weak,
552 we'd be making libc depend circularly on the service
554 for (i = 0; functions[i].kind; i++)
556 char *name = known_function_name (&functions[i]);
557 fprintf (out, "typeof (%s) %s __attribute__ ((weak));\n",
562 /* Then, a table mapping names to functions. */
563 fputs ("static const known_function fixed_known_functions[] = {\n",
565 for (i = 0; functions[i].kind; i++)
567 const struct function *f = &functions[i];
568 char *suffix = known_function_suffix (f);
570 fprintf (out, " /* %2d */ { \"%s\", _nss_%s_%s },\n",
571 i, suffix, f->service, suffix);
578 /* Print code to OUT for an initialized array of pointers to the
579 'known_function' structures needed for USER, which is for
580 DATABASE. Return its name, allocated with malloc. */
582 generate_known_function_list (FILE *out,
583 const name_database_entry *database,
584 const service_user *user)
586 char *list_name = saprintf ("fixed_%s_%s_known_funcs",
587 database->name, user->name);
588 fprintf (out, "static const known_function *%s[] = {\n",
591 for (i = 0; functions[i].kind; i++)
592 if (strcmp (functions[i].database, database->name) == 0
593 && strcmp (functions[i].service, user->name) == 0)
594 fprintf (out, " &fixed_known_functions[%d], /* %s */\n",
595 i, known_function_name (&functions[i]));
596 fputs (" NULL\n", out);
604 /* Return the name of the status value STATUS, as a statically
607 lookup_status_name (enum nss_status status)
611 case NSS_STATUS_TRYAGAIN: return "NSS_STATUS_TRYAGAIN";
612 case NSS_STATUS_UNAVAIL: return "NSS_STATUS_UNAVAIL";
613 case NSS_STATUS_NOTFOUND: return "NSS_STATUS_NOTFOUND";
614 case NSS_STATUS_SUCCESS: return "NSS_STATUS_SUCCESS";
615 case NSS_STATUS_RETURN: return "NSS_STATUS_RETURN";
621 /* Return the name of ACTION as a statically allocated string. */
623 lookup_action_name (lookup_actions action)
627 case NSS_ACTION_CONTINUE: return "NSS_ACTION_CONTINUE";
628 case NSS_ACTION_RETURN: return "NSS_ACTION_RETURN";
634 /* Print code to OUT for the list of service_user structures starting
635 with USER, which are all for DATABASE. Return the name of the
636 first structure in that list, or zero if USER is NULL. */
638 generate_service_user_list (FILE *out,
639 name_database_entry *database,
644 /* Generate the tail of the list. */
645 char *next_name = generate_service_user_list (out, database, user->next);
646 /* Generate our known function list. */
647 char *known_function_list_name =
648 generate_known_function_list (out, database, user);
650 char *name = saprintf ("fixed_%s_%s_user", database->name, user->name);
652 fprintf (out, "static const service_user %s = {\n", name);
654 fprintf (out, " (service_user *) &%s,\n", next_name);
656 fprintf (out, " NULL, /* no next entry */\n");
659 for (i = 0; i < sizeof (user->actions) / sizeof (user->actions[0]); i++)
660 fprintf (out, " %s, /* %s */\n",
661 lookup_action_name (user->actions[i]),
662 lookup_status_name (i - 2));
663 fputs (" },\n", out);
664 fprintf (out, " NULL, /* we never need the service library */\n");
665 fprintf (out, " { .array = %s },\n", known_function_list_name);
666 fprintf (out, " \"%s\"\n", user->name);
677 /* Print code to OUT for the list of name_database_entry structures
678 starting with DATABASE. Return the name of the first structure
679 in that list, or zero if DATABASE is NULL. */
681 generate_name_database_entries (FILE *out, name_database_entry *database)
685 char *next_name = generate_name_database_entries (out, database->next);
686 char *service_user_name
687 = generate_service_user_list (out, database, database->service);
688 char *name = saprintf ("fixed_%s_name_database", database->name);
690 fprintf (out, "static const name_database_entry %s = {\n", name);
693 fprintf (out, " (name_database_entry *) &%s,\n", next_name);
695 fprintf (out, " NULL,\n");
697 if (service_user_name)
698 fprintf (out, " (service_user *) &%s,\n", service_user_name);
700 fprintf (out, " NULL,\n");
702 fprintf (out, " \"%s\"\n", database->name);
703 fprintf (out, "};\n");
714 generate_name_database (FILE *out, name_database *service_table)
716 /* Produce a linked list of the known name_database_entry
718 char *entries = generate_name_database_entries (out, service_table->entry);
720 /* Now produce the main structure that points to them all. */
721 fprintf (out, "static const name_database fixed_name_database = {\n");
723 fprintf (out, " (name_database_entry *) &%s,\n", entries);
725 fprintf (out, " NULL,\n");
726 fputs (" NULL /* we don't need the libraries */\n"
733 /* Generating the list of service libraries we generate references to. */
735 /* String with revision number of the shared object files. */
736 static const char *const nss_shlib_revision = LIBNSS_FILES_SO + 15;
739 generate_service_lib_list (FILE *out, name_database *service_table)
744 for (i = 0; functions[i].kind; i++)
746 /* Mention each service library only once. */
747 for (j = 0; j < i; j++)
748 if (strcmp (functions[i].service, functions[j].service) == 0)
755 fprintf (out, "-lnss_%s",
756 functions[i].service,
767 main (int argc, char **argv)
771 fprintf (stderr, "usage: gen-fixed-nsswitch HEADER SERVLIBS CONFIG\n");
775 name_database *service_table = nss_parse_file (argv[3]);
777 FILE *header = fopen (argv[1], "w");
781 "gen-fixed-nsswitch: couldn't open output file %s: %s\n",
782 argv[1], strerror (errno));
785 fputs ("/* Generated by nss/gen-fixed-nsswitch.c. */\n", header);
786 fputs ("\n", header);
787 generate_known_functions (header);
788 generate_name_database (header, service_table);
791 FILE *service_lib_list = fopen (argv[2], "w");
792 if (! service_lib_list)
795 "gen-fixed-nsswitch: couldn't open output file %s: %s\n",
796 argv[2], strerror (errno));
799 generate_service_lib_list (service_lib_list, service_table);
800 fclose (service_lib_list);