1 /* Mail alias file parser in nss_files module.
2 Copyright (C) 1996 Free Software Foundation, Inc.
3 This file is part of the GNU C Library.
4 Contributed by Ulrich Drepper <drepper@cygnus.com>, 1996.
6 The GNU C Library is free software; you can redistribute it and/or
7 modify it under the terms of the GNU Library General Public License as
8 published by the Free Software Foundation; either version 2 of the
9 License, or (at your option) any later version.
11 The GNU C Library is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Library General Public License for more details.
16 You should have received a copy of the GNU Library General Public
17 License along with the GNU C Library; see the file COPYING.LIB. If not,
18 write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19 Boston, MA 02111-1307, USA. */
23 #include <libc-lock.h>
30 /* Locks the static variables in this file. */
31 __libc_lock_define_initialized (static, lock)
33 /* Maintenance of the shared stream open on the database file. */
36 static fpos_t position;
37 static enum { none, getent, getby } last_use;
40 static enum nss_status
41 internal_setent (void)
43 enum nss_status status = NSS_STATUS_SUCCESS;
47 stream = fopen ("/etc/aliases", "r");
50 status = NSS_STATUS_UNAVAIL;
59 /* Thread-safe, exported version of that. */
61 _nss_files_setaliasent (void)
63 enum nss_status status;
65 __libc_lock_lock (lock);
67 status = internal_setent ();
69 if (status == NSS_STATUS_SUCCESS && fgetpos (stream, &position) < 0)
73 status = NSS_STATUS_UNAVAIL;
78 __libc_lock_unlock (lock);
84 /* Close the database file. */
86 internal_endent (void)
96 /* Thread-safe, exported version of that. */
98 _nss_files_endaliasent (void)
100 __libc_lock_lock (lock);
104 __libc_lock_unlock (lock);
106 return NSS_STATUS_SUCCESS;
109 /* Parsing the database file into `struct aliasent' data structures. */
110 static enum nss_status
111 get_next_alias (const char *match, struct aliasent *result,
112 char *buffer, size_t buflen)
114 enum nss_status status = NSS_STATUS_NOTFOUND;
117 result->alias_members_len = 0;
121 /* Now we are ready to process the input. We have to read a
122 line and all its continuations and construct the array of
123 string pointers. This pointers and the names itself have to
124 be placed in BUFFER. */
125 char *first_unused = buffer;
126 size_t room_left = buflen - (buflen % __alignof__ (char *));
129 /* Read the first line. It must contain the alias name and
130 possibly some alias names. */
131 first_unused[room_left - 1] = '\0';
132 line = fgets (first_unused, room_left, stream);
134 /* Nothing to read. */
136 else if (first_unused[room_left - 1] != '\0')
138 /* The line is too long for our buffer. */
140 __set_errno (ERANGE);
141 status = NSS_STATUS_TRYAGAIN;
148 /* If we are in IGNORE mode and the first character in the
149 line is a white space we ignore the line and start
151 if (ignore && isspace (first_unused))
154 /* Terminate the line for any case. */
155 cp = strpbrk (first_unused, "#\n");
159 /* Skip leading blanks. */
160 while (isspace (*line))
163 result->alias_name = first_unused;
164 while (*line != '\0' && *line != ':')
165 *first_unused++ = *line++;
166 if (*line == '\0' || result->alias_name == first_unused)
167 /* No valid name. Ignore the line. */
170 *first_unused++ = '\0';
171 if (room_left < (size_t) (first_unused - result->alias_name))
173 room_left -= first_unused - result->alias_name;
176 /* When we search for a specific alias we can avoid all the
177 difficult parts and compare now with the name we are
178 looking for. If it does not match we simply ignore all
179 lines until the next line containing the start of a new
181 ignore = match != NULL && strcmp (result->alias_name, match) == 0;
185 while (isspace (*line))
189 while (*line != '\0' && *line != ',')
190 *first_unused++ = *line++;
192 if (first_unused != cp)
196 /* OK, we can have a regular entry or an include
198 *first_unused++ = '\0';
205 if (strncmp (cp, ":include:", 9) != 0)
207 if (room_left < (first_unused - cp) + sizeof (char *))
209 room_left -= (first_unused - cp) + sizeof (char *);
211 ++result->alias_members_len;
215 /* Oh well, we have to read the addressed file. */
217 char *old_line = NULL;
221 listfile = fopen (&cp[9], "r");
222 /* If the file does not exist we simply ignore
225 && (old_line = strdup (line)) != NULL)
227 while (! feof (listfile))
229 first_unused[room_left - 1] = '\0';
230 line = fgets (first_unused, room_left, listfile);
233 if (first_unused[room_left - 1] != '\0')
239 /* Parse the line. */
240 cp = strpbrk (line, "#\n");
246 while (isspace (*line))
250 while (*line != '\0' && *line != ',')
251 *first_unused++ = *line++;
256 if (first_unused != cp)
258 *first_unused++ = '\0';
259 if (room_left < ((first_unused - cp)
260 + __alignof__ (char *)))
265 room_left -= ((first_unused - cp)
266 + __alignof__ (char *));
267 ++result->alias_members_len;
270 while (*line != '\0');
274 first_unused[room_left - 1] = '\0';
275 strncpy (first_unused, old_line, room_left);
277 if (old_line != NULL)
280 if (first_unused[room_left - 1] != '\0')
288 /* Get the next line. But we must be careful. We
289 must not read the whole line at once since it
290 might belong to the current alias. Simply read
291 the first character. If it is a white space we
292 have a continuation line. Otherwise it is the
293 beginning of a new alias and we can push back the
294 just read character. */
297 first_unused[room_left - 1] = '\0';
300 if (ch == EOF || !isspace (ch))
304 /* Now prepare the return. Provide string
305 pointers for the currently selected aliases. */
309 /* Adjust the pointer so it is aligned for
311 first_unused += __alignof__ (char *) - 1;
312 first_unused -= ((first_unused - (char *) 0)
313 % __alignof__ (char *));
314 result->alias_members = (char **) first_unused;
316 /* Compute addresses of alias entry strings. */
317 cp = result->alias_name;
318 for (cnt = 0; cnt < result->alias_members_len; ++cnt)
320 cp = strchr (cp, '\0') + 1;
321 result->alias_members[cnt] = cp;
324 status = (result->alias_members_len == 0
325 ? NSS_STATUS_RETURN : NSS_STATUS_SUCCESS);
329 /* The just read character is a white space and so
331 cp = strpbrk (line, "#\n");
338 if (status != NSS_STATUS_NOTFOUND)
339 /* We read something. In any case break here. */
348 _nss_files_getaliasent_r (struct aliasent *result, char *buffer, size_t buflen)
350 /* Return next entry in host file. */
351 enum nss_status status = NSS_STATUS_SUCCESS;
353 __libc_lock_lock (lock);
355 /* Be prepared that the set*ent function was not called before. */
357 status = internal_setent ();
359 if (status == NSS_STATUS_SUCCESS)
361 /* If the last use was not by the getent function we need the
362 position the stream. */
363 if (last_use != getent)
364 if (fsetpos (stream, &position) < 0)
365 status = NSS_STATUS_UNAVAIL;
369 if (status == NSS_STATUS_SUCCESS)
371 result->alias_local = 1;
373 /* Read lines until we get a definite result. */
375 status = get_next_alias (NULL, result, buffer, buflen);
376 while (status == NSS_STATUS_RETURN);
378 /* If we successfully read an entry remember this position. */
379 if (status == NSS_STATUS_SUCCESS)
380 fgetpos (stream, &position);
386 __libc_lock_unlock (lock);
393 _nss_files_getaliasbyname_r (const char *name, struct aliasent *result,
394 char *buffer, size_t buflen)
396 /* Return next entry in host file. */
397 enum nss_status status = NSS_STATUS_SUCCESS;
401 __set_errno (EINVAL);
402 return NSS_STATUS_UNAVAIL;
405 __libc_lock_lock (lock);
407 /* Open the stream or rest it. */
408 status = internal_setent ();
411 if (status == NSS_STATUS_SUCCESS)
413 result->alias_local = 1;
415 /* Read lines until we get a definite result. */
417 status = get_next_alias (name, result, buffer, buflen);
418 while (status == NSS_STATUS_RETURN);
421 __libc_lock_unlock (lock);