b6702b0366e0dbfc0228dc1025c189a97885482e
[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 not,
17    write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18    Boston, MA 02111-1307, 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    DATABASE -- string of the database file's name ("hosts", "passwd").
31
32    NEED_H_ERRNO - defined iff an arg `int *herrnop' is used.
33
34    Also see files-parse.c.
35 */
36
37 #define ENTNAME_r       CONCAT(ENTNAME,_r)
38
39 #define DATAFILE        "/etc/" DATABASE
40
41 #ifdef NEED_H_ERRNO
42 #define H_ERRNO_PROTO   , int *herrnop
43 #define H_ERRNO_ARG     , herrnop
44 #define H_ERRNO_SET(val) (*herrnop = (val))
45 #else
46 #define H_ERRNO_PROTO
47 #define H_ERRNO_ARG
48 #define H_ERRNO_SET(val) ((void) 0)
49 #endif
50
51 /* Locks the static variables in this file.  */
52 __libc_lock_define_initialized (static, lock)
53 \f
54 /* Maintenance of the shared stream open on the database file.  */
55
56 static FILE *stream;
57 static fpos_t position;
58 static enum { none, getent, getby } last_use;
59 static int keep_stream;
60
61 /* Open database file if not already opened.  */
62 static int
63 internal_setent (int stayopen)
64 {
65   int status = NSS_STATUS_SUCCESS;
66
67   if (stream == NULL)
68     {
69       stream = fopen (DATAFILE, "r");
70
71       if (stream == NULL)
72         status = NSS_STATUS_UNAVAIL;
73     }
74   else
75     rewind (stream);
76
77   /* Remember STAYOPEN flag.  */
78   if (stream != NULL)
79     keep_stream |= stayopen;
80
81   return status;
82 }
83
84
85 /* Thread-safe, exported version of that.  */
86 int
87 CONCAT(_nss_files_set,ENTNAME) (int stayopen)
88 {
89   int status;
90
91   __libc_lock_lock (lock);
92
93   status = internal_setent (stayopen);
94
95   if (status == NSS_STATUS_SUCCESS && fgetpos (stream, &position) < 0)
96     {
97       fclose (stream);
98       stream = NULL;
99       status = NSS_STATUS_UNAVAIL;
100     }
101
102   last_use = getent;
103
104   __libc_lock_unlock (lock);
105
106   return status;
107 }
108
109
110 /* Close the database file.  */
111 static void
112 internal_endent (void)
113 {
114   if (stream != NULL)
115     {
116       fclose (stream);
117       stream = NULL;
118     }
119 }
120
121
122 /* Thread-safe, exported version of that.  */
123 int
124 CONCAT(_nss_files_end,ENTNAME) (void)
125 {
126   __libc_lock_lock (lock);
127
128   internal_endent ();
129
130   /* Reset STAYOPEN flag.  */
131   keep_stream = 0;
132
133   __libc_lock_unlock (lock);
134
135   return NSS_STATUS_SUCCESS;
136 }
137 \f
138 /* Parsing the database file into `struct STRUCTURE' data structures.  */
139
140 static enum nss_status
141 internal_getent (struct STRUCTURE *result,
142                  char *buffer, int buflen H_ERRNO_PROTO)
143 {
144   char *p;
145   struct parser_data *data = (void *) buffer;
146   int linebuflen = buffer + buflen - data->linebuffer;
147
148   /* Be prepared that the set*ent function was not called before.  */
149   if (stream == NULL)
150     {
151       enum nss_status status;
152
153       status = internal_setent (0);
154       if (status != NSS_STATUS_SUCCESS)
155         return status;
156     }
157
158   if (buflen < (int) sizeof *data + 1)
159     {
160       __set_errno (ERANGE);
161       return NSS_STATUS_TRYAGAIN;
162     }
163
164   do
165     {
166       p = fgets (data->linebuffer, linebuflen, stream);
167       if (p == NULL)
168         {
169           /* End of file or read error.  */
170           H_ERRNO_SET (HOST_NOT_FOUND);
171           return NSS_STATUS_NOTFOUND;
172         }
173
174       /* Terminate the line for any case.  */
175       data->linebuffer[linebuflen - 1] = '\0';
176
177       /* Skip leading blanks.  */
178       while (isspace (*p))
179         ++p;
180     } while (*p == '\0' || *p == '#' || /* Ignore empty and comment lines.  */
181              /* Parse the line.  If it is invalid, loop to
182                 get the next line of the file to parse.  */
183              ! parse_line (p, result, data, buflen));
184
185   /* Filled in RESULT with the next entry from the database file.  */
186   return NSS_STATUS_SUCCESS;
187 }
188
189
190 /* Return the next entry from the database file, doing locking.  */
191 int
192 CONCAT(_nss_files_get,ENTNAME_r) (struct STRUCTURE *result,
193                                   char *buffer, int buflen H_ERRNO_PROTO)
194 {
195   /* Return next entry in host file.  */
196   int status = NSS_STATUS_SUCCESS;
197
198   __libc_lock_lock (lock);
199
200   /* If the last use was not by the getent function we need the
201      position the stream.  */
202   if (last_use != getent)
203     if (fsetpos (stream, &position) < 0)
204       status = NSS_STATUS_UNAVAIL;
205     else
206       last_use = getent;
207
208   if (status == NSS_STATUS_SUCCESS)
209     {
210       status = internal_getent (result, buffer, buflen H_ERRNO_ARG);
211
212       /* Remember this position.  */
213       fgetpos (stream, &position);
214     }
215
216   __libc_lock_unlock (lock);
217
218   return status;
219 }
220 \f
221 /* Macro for defining lookup functions for this file-based database.
222
223    NAME is the name of the lookup; e.g. `hostbyname'.
224
225    KEYSIZE and KEYPATTERN are ignored here but used by ../nss_db/db-XXX.c.
226
227    PROTO describes the arguments for the lookup key;
228    e.g. `const char *hostname'.
229
230    BREAK_IF_MATCH is a block of code which compares `struct STRUCTURE *result'
231    to the lookup key arguments and does `break;' if they match.  */
232
233 #define DB_LOOKUP(name, keysize, keypattern, break_if_match, proto...)        \
234 enum nss_status                                                               \
235 _nss_files_get##name##_r (proto,                                              \
236                           struct STRUCTURE *result,                           \
237                           char *buffer, int buflen H_ERRNO_PROTO)             \
238 {                                                                             \
239   enum nss_status status;                                                     \
240                                                                               \
241   __libc_lock_lock (lock);                                                    \
242                                                                               \
243   /* Reset file pointer to beginning or open file.  */                        \
244   internal_setent (keep_stream);                                              \
245                                                                               \
246   /* Tell getent function that we have repositioned the file pointer.  */     \
247   last_use = getby;                                                           \
248                                                                               \
249   while ((status = internal_getent (result, buffer, buflen H_ERRNO_ARG))      \
250          == NSS_STATUS_SUCCESS)                                               \
251     { break_if_match }                                                        \
252                                                                               \
253   if (! keep_stream)                                                          \
254     internal_endent ();                                                       \
255                                                                               \
256   __libc_lock_unlock (lock);                                                  \
257                                                                               \
258   return status;                                                              \
259 }