b9c3579d5b582a313e3ce6ab50ea181468753057
[kopensolaris-gnu/glibc.git] / nss / nss_files / files-XXX.c
1 /* Common code for file-based databases in nss_files module.
2 Copyright (C) 1996 Free Software Foundation, Inc.
3 This file is part of the GNU C Library.
4
5 The GNU C Library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Library General Public License as
7 published by the Free Software Foundation; either version 2 of the
8 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 Library General Public License for more details.
14
15 You should have received a copy of the GNU Library General Public
16 License along with the GNU C Library; see the file COPYING.LIB.  If
17 not, write to the Free Software Foundation, Inc., 675 Mass Ave,
18 Cambridge, MA 02139, USA.  */
19
20 #include <stdio.h>
21 #include <ctype.h>
22 #include <assert.h>
23 #include <libc-lock.h>
24 #include "nsswitch.h"
25
26 /* These symbols are defined by the including source file:
27
28    ENTNAME -- database name of the structure and functions (hostent, pwent).
29    STRUCTURE -- struct name, define only if not ENTNAME (passwd, group).
30    DATAFILE -- string of the database file's name.
31
32    NEED_H_ERRNO - defined iff an arg `int *herrnop' is used.
33    MIDLINE_COMMENTS - defined iff # before \n terminates a database line.
34 */
35
36 #define ENTNAME_r CONCAT(ENTNAME,_r)
37
38 #ifdef NEED_H_ERRNO
39 #define H_ERRNO_PROTO   , int *herrnop
40 #define H_ERRNO_ARG     , herrnop
41 #define H_ERRNO_SET(val) (*herrnop = (val))
42 #else
43 #define H_ERRNO_PROTO
44 #define H_ERRNO_ARG
45 #define H_ERRNO_SET(val) ((void) 0)
46 #endif
47
48 /* Locks the static variables in this file.  */
49 __libc_lock_define_initialized (static, lock);
50 \f
51 /* Maintenance of the shared stream open on the database file.  */
52
53 static FILE *stream;
54 static int keep_stream;
55
56 /* Open database file if not already opened.  */
57 static int
58 internal_setent (int stayopen)
59 {
60   int status = NSS_STATUS_SUCCESS;
61
62   if (stream == NULL)
63     {
64       stream = fopen (DATAFILE, "r");
65
66       if (stream == NULL)
67         status = NSS_STATUS_UNAVAIL;
68     }
69   else
70     rewind (stream);
71
72   /* Remember STAYOPEN flag.  */
73   if (stream != NULL)
74     keep_stream |= stayopen;
75
76   return status;
77 }
78
79
80 /* Thread-safe, exported version of that.  */
81 int
82 CONCAT(_nss_files_set,ENTNAME) (int stayopen)
83 {
84   int status;
85
86   __libc_lock_lock (lock);
87
88   status = internal_setent (stayopen);
89
90   __libc_lock_unlock (lock);
91
92   return status;
93 }
94
95
96 /* Close the database file.  */
97 static void
98 internal_endent (void)
99 {
100   if (stream != NULL)
101     {
102       fclose (stream);
103       stream = NULL;
104     }
105 }
106
107
108 /* Thread-safe, exported version of that.  */
109 int
110 CONCAT(_nss_files_end,ENTNAME) (void)
111 {
112   __libc_lock_lock (lock);
113
114   internal_endent ();
115
116   /* Reset STAYOPEN flag.  */
117   keep_stream = 0;
118
119   __libc_lock_unlock (lock);
120
121   return NSS_STATUS_SUCCESS;
122 }
123 \f
124 /* Parsing the database file into `struct STRUCTURE' data structures.  */
125
126 static enum nss_status
127 internal_getent (struct STRUCTURE *result,
128                  char *buffer, int buflen H_ERRNO_PROTO)
129 {
130   char *p;
131   struct parser_data *data = (void *) buffer;
132   int linebuflen = buffer + buflen - data->linebuffer;
133
134   /* Be prepared that the set*ent function was not called before.  */
135   if (stream == NULL)
136     {
137       enum nss_status status;
138
139       status = internal_setent (0);
140       if (status != NSS_STATUS_SUCCESS)
141         return status;
142     }
143
144   if (buflen < (int) sizeof *data + 1)
145     {
146       errno = ERANGE;
147       return NSS_STATUS_TRYAGAIN;
148     }
149
150   do
151     {
152       p = fgets (data->linebuffer, linebuflen, stream);
153       if (p == NULL)
154         {
155           /* End of file or read error.  */
156           H_ERRNO_SET (HOST_NOT_FOUND);
157           return NSS_STATUS_NOTFOUND;
158         }
159
160       /* Terminate the line for any case.  */
161       data->linebuffer[linebuflen - 1] = '\0';
162
163       /* Skip leading blanks.  */
164       while (isspace (*p))
165         ++p;
166     } while (*p == '\0' || *p == '#' || /* Ignore empty and comment lines.  */
167              /* Parse the line.  If it is invalid, loop to
168                 get the next line of the file to parse.  */
169              ! parse_line (p, result, data, buflen));
170
171   /* Filled in RESULT with the next entry from the database file.  */
172   return NSS_STATUS_SUCCESS;
173 }
174
175
176 /* Return the next entry from the database file, doing locking.  */
177 int
178 CONCAT(_nss_files_get,ENTNAME_r) (struct STRUCTURE *result,
179                                   char *buffer, int buflen H_ERRNO_PROTO)
180 {
181   /* Return next entry in host file.  */
182   int status;
183
184   __libc_lock_lock (lock);
185
186   status = internal_getent (result, buffer, buflen H_ERRNO_ARG);
187
188   __libc_lock_unlock (lock);
189
190   return status;
191 }
192 \f
193 /* Macro for defining lookup functions for this file-based database.
194
195    NAME is the name of the lookup; e.g. `hostbyname'.
196
197    PROTO describes the arguments for the lookup key;
198    e.g. `const char *hostname'.
199
200    BREAK_IF_MATCH is a block of code which compares `struct STRUCTURE *result'
201    to the lookup key arguments and does `break;' if they match.  */
202
203 #define DB_LOOKUP(name, break_if_match, proto...)                             \
204 enum nss_status                                                               \
205 _nss_files_get##name##_r (proto,                                              \
206                           struct STRUCTURE *result,                           \
207                           char *buffer, int buflen H_ERRNO_PROTO)             \
208 {                                                                             \
209   enum nss_status status;                                                     \
210                                                                               \
211   __libc_lock_lock (lock);                                                    \
212                                                                               \
213   /* Reset file pointer to beginning or open file.  */                        \
214   internal_setent (keep_stream);                                              \
215                                                                               \
216   while ((status = internal_getent (result, buffer, buflen H_ERRNO_ARG))      \
217          == NSS_STATUS_SUCCESS)                                               \
218     { break_if_match }                                                        \
219                                                                               \
220   if (! keep_stream)                                                          \
221     internal_endent ();                                                       \
222                                                                               \
223   __libc_lock_unlock (lock);                                                  \
224                                                                               \
225   return status;                                                              \
226 }