40bb7df81eedcbfccd0fbe219ac83601d0c8db54
[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   /* Reset STAYOPEN flag.  */
107   keep_stream = 0;
108 }
109
110
111 /* Thread-safe, exported version of that.  */
112 int
113 CONCAT(_nss_files_end,ENTNAME) (void)
114 {
115   __libc_lock_lock (lock);
116
117   internal_endent ();
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   /* Someone called internal_setent before calling us, so if the
135      stream is not open now the file could not be opened.  */
136   if (stream == NULL)
137     {
138       H_ERRNO_SET (NETDB_INTERNAL);
139       return NSS_STATUS_UNAVAIL;
140     }
141
142   if (buflen < sizeof *data + 1)
143     {
144       errno = ERANGE;
145       return NSS_STATUS_NOTFOUND;
146     }
147
148   do
149     {
150       p = fgets (data->linebuffer, linebuflen, stream);
151       if (p == NULL)
152         {
153           /* End of file or read error.  */
154           H_ERRNO_SET (HOST_NOT_FOUND);
155           return NSS_STATUS_NOTFOUND;
156         }
157
158       /* Skip leading blanks.  */
159       while (isspace (*p))
160         ++p;
161     } while (*p == '\0' || *p == '#' || /* Ignore empty and comment lines.  */
162              /* Parse the line.  If it is invalid, loop to
163                 get the next line of the file to parse.  */
164              ! parse_line (p, result, data, buflen));
165
166   /* Filled in RESULT with the next entry from the database file.  */
167   return NSS_STATUS_SUCCESS;
168 }
169
170
171 /* Return the next entry from the database file, doing locking.  */
172 int
173 CONCAT(_nss_files_get,ENTNAME_r) (struct STRUCTURE *result,
174                                   char *buffer, int buflen H_ERRNO_PROTO)
175 {
176   /* Return next entry in host file.  */
177   int status;
178
179   __libc_lock_lock (lock);
180
181   status = internal_getent (result, buffer, buflen H_ERRNO_ARG);
182
183   __libc_lock_unlock (lock);
184
185   return status;
186 }
187 \f
188 /* Macro for defining lookup functions for this file-based database.
189
190    NAME is the name of the lookup; e.g. `hostbyname'.
191
192    PROTO describes the arguments for the lookup key;
193    e.g. `const char *hostname'.
194
195    BREAK_IF_MATCH is a block of code which compares `struct STRUCTURE *result'
196    to the lookup key arguments and does `break;' if they match.  */
197
198 #define DB_LOOKUP(name, break_if_match, proto...)                             \
199 enum nss_status                                                               \
200 _nss_files_get##name##_r (proto,                                              \
201                           struct STRUCTURE *result,                           \
202                           char *buffer, int buflen H_ERRNO_PROTO)             \
203 {                                                                             \
204   enum nss_status status;                                                     \
205                                                                               \
206   __libc_lock_lock (lock);                                                    \
207                                                                               \
208   /* Reset file pointer to beginning or open file.  */                        \
209   internal_setent (keep_stream);                                              \
210                                                                               \
211   while ((status = internal_getent (result, buffer, buflen H_ERRNO_ARG))      \
212          == NSS_STATUS_SUCCESS)                                               \
213     { break_if_match }                                                        \
214                                                                               \
215   if (! keep_stream)                                                          \
216     internal_endent ();                                                       \
217                                                                               \
218   __libc_lock_unlock (lock);                                                  \
219                                                                               \
220   return status;                                                              \
221 }