]>
git.ipfire.org Git - thirdparty/glibc.git/blob - nss/nss_files/files-alias.c
1 /* Mail alias file parser in nss_files module.
2 Copyright (C) 1996, 1997 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. */
25 #include <bits/libc-lock.h>
32 /* Locks the static variables in this file. */
33 __libc_lock_define_initialized (static, lock
)
35 /* Maintenance of the shared stream open on the database file. */
38 static fpos_t position
;
39 static enum { none
, getent
, getby
} last_use
;
42 static enum nss_status
43 internal_setent (void)
45 enum nss_status status
= NSS_STATUS_SUCCESS
;
49 stream
= fopen ("/etc/aliases", "r");
52 status
= errno
== EAGAIN
? NSS_STATUS_TRYAGAIN
: NSS_STATUS_UNAVAIL
;
55 /* We have to make sure the file is `closed on exec'. */
58 result
= flags
= fcntl (fileno (stream
), F_GETFD
, 0);
62 result
= fcntl (fileno (stream
), F_SETFD
, flags
);
66 /* Something went wrong. Close the stream and return a
70 status
= NSS_STATUS_UNAVAIL
;
81 /* Thread-safe, exported version of that. */
83 _nss_files_setaliasent (void)
85 enum nss_status status
;
87 __libc_lock_lock (lock
);
89 status
= internal_setent ();
91 if (status
== NSS_STATUS_SUCCESS
&& fgetpos (stream
, &position
) < 0)
95 status
= NSS_STATUS_UNAVAIL
;
100 __libc_lock_unlock (lock
);
106 /* Close the database file. */
108 internal_endent (void)
118 /* Thread-safe, exported version of that. */
120 _nss_files_endaliasent (void)
122 __libc_lock_lock (lock
);
126 __libc_lock_unlock (lock
);
128 return NSS_STATUS_SUCCESS
;
131 /* Parsing the database file into `struct aliasent' data structures. */
132 static enum nss_status
133 get_next_alias (const char *match
, struct aliasent
*result
,
134 char *buffer
, size_t buflen
)
136 enum nss_status status
= NSS_STATUS_NOTFOUND
;
139 result
->alias_members_len
= 0;
143 /* Now we are ready to process the input. We have to read a
144 line and all its continuations and construct the array of
145 string pointers. This pointers and the names itself have to
146 be placed in BUFFER. */
147 char *first_unused
= buffer
;
148 size_t room_left
= buflen
- (buflen
% __alignof__ (char *));
151 /* Read the first line. It must contain the alias name and
152 possibly some alias names. */
153 first_unused
[room_left
- 1] = '\0';
154 line
= fgets (first_unused
, room_left
, stream
);
156 /* Nothing to read. */
158 else if (first_unused
[room_left
- 1] != '\0')
160 /* The line is too long for our buffer. */
162 __set_errno (ERANGE
);
163 status
= NSS_STATUS_TRYAGAIN
;
170 /* If we are in IGNORE mode and the first character in the
171 line is a white space we ignore the line and start
173 if (ignore
&& isspace (*first_unused
))
176 /* Terminate the line for any case. */
177 cp
= strpbrk (first_unused
, "#\n");
181 /* Skip leading blanks. */
182 while (isspace (*line
))
185 result
->alias_name
= first_unused
;
186 while (*line
!= '\0' && *line
!= ':')
187 *first_unused
++ = *line
++;
188 if (*line
== '\0' || result
->alias_name
== first_unused
)
189 /* No valid name. Ignore the line. */
192 *first_unused
++ = '\0';
193 if (room_left
< (size_t) (first_unused
- result
->alias_name
))
195 room_left
-= first_unused
- result
->alias_name
;
198 /* When we search for a specific alias we can avoid all the
199 difficult parts and compare now with the name we are
200 looking for. If it does not match we simply ignore all
201 lines until the next line containing the start of a new
203 ignore
= match
!= NULL
&& strcmp (result
->alias_name
, match
) != 0;
207 while (isspace (*line
))
211 while (*line
!= '\0' && *line
!= ',')
212 *first_unused
++ = *line
++;
214 if (first_unused
!= cp
)
216 /* OK, we can have a regular entry or an include
220 *first_unused
++ = '\0';
222 if (strncmp (cp
, ":include:", 9) != 0)
224 if (room_left
< (first_unused
- cp
) + sizeof (char *))
226 room_left
-= (first_unused
- cp
) + sizeof (char *);
228 ++result
->alias_members_len
;
232 /* Oh well, we have to read the addressed file. */
234 char *old_line
= NULL
;
238 listfile
= fopen (&cp
[9], "r");
239 /* If the file does not exist we simply ignore
242 && (old_line
= strdup (line
)) != NULL
)
244 while (! feof (listfile
))
246 first_unused
[room_left
- 1] = '\0';
247 line
= fgets (first_unused
, room_left
, listfile
);
250 if (first_unused
[room_left
- 1] != '\0')
256 /* Parse the line. */
257 cp
= strpbrk (line
, "#\n");
263 while (isspace (*line
))
267 while (*line
!= '\0' && *line
!= ',')
268 *first_unused
++ = *line
++;
273 if (first_unused
!= cp
)
275 *first_unused
++ = '\0';
276 if (room_left
< ((first_unused
- cp
)
277 + __alignof__ (char *)))
282 room_left
-= ((first_unused
- cp
)
283 + __alignof__ (char *));
284 ++result
->alias_members_len
;
287 while (*line
!= '\0');
291 first_unused
[room_left
- 1] = '\0';
292 strncpy (first_unused
, old_line
, room_left
);
294 if (old_line
!= NULL
)
297 if (first_unused
[room_left
- 1] != '\0')
305 /* Get the next line. But we must be careful. We
306 must not read the whole line at once since it
307 might belong to the current alias. Simply read
308 the first character. If it is a white space we
309 have a continuation line. Otherwise it is the
310 beginning of a new alias and we can push back the
311 just read character. */
315 if (ch
== EOF
|| ch
== '\n' || !isspace (ch
))
319 /* Now prepare the return. Provide string
320 pointers for the currently selected aliases. */
324 /* Adjust the pointer so it is aligned for
326 first_unused
+= __alignof__ (char *) - 1;
327 first_unused
-= ((first_unused
- (char *) 0)
328 % __alignof__ (char *));
329 result
->alias_members
= (char **) first_unused
;
331 /* Compute addresses of alias entry strings. */
332 cp
= result
->alias_name
;
333 for (cnt
= 0; cnt
< result
->alias_members_len
; ++cnt
)
335 cp
= strchr (cp
, '\0') + 1;
336 result
->alias_members
[cnt
] = cp
;
339 status
= (result
->alias_members_len
== 0
340 ? NSS_STATUS_RETURN
: NSS_STATUS_SUCCESS
);
344 /* The just read character is a white space and so
346 first_unused
[room_left
- 1] = '\0';
347 line
= fgets (first_unused
, room_left
, stream
);
348 if (first_unused
[room_left
- 1] != '\0')
350 cp
= strpbrk (line
, "#\n");
357 if (status
!= NSS_STATUS_NOTFOUND
)
358 /* We read something. In any case break here. */
367 _nss_files_getaliasent_r (struct aliasent
*result
, char *buffer
, size_t buflen
)
369 /* Return next entry in host file. */
370 enum nss_status status
= NSS_STATUS_SUCCESS
;
372 __libc_lock_lock (lock
);
374 /* Be prepared that the set*ent function was not called before. */
376 status
= internal_setent ();
378 if (status
== NSS_STATUS_SUCCESS
)
380 /* If the last use was not by the getent function we need the
381 position the stream. */
382 if (last_use
!= getent
)
383 if (fsetpos (stream
, &position
) < 0)
384 status
= NSS_STATUS_UNAVAIL
;
388 if (status
== NSS_STATUS_SUCCESS
)
390 result
->alias_local
= 1;
392 /* Read lines until we get a definite result. */
394 status
= get_next_alias (NULL
, result
, buffer
, buflen
);
395 while (status
== NSS_STATUS_RETURN
);
397 /* If we successfully read an entry remember this position. */
398 if (status
== NSS_STATUS_SUCCESS
)
399 fgetpos (stream
, &position
);
405 __libc_lock_unlock (lock
);
412 _nss_files_getaliasbyname_r (const char *name
, struct aliasent
*result
,
413 char *buffer
, size_t buflen
)
415 /* Return next entry in host file. */
416 enum nss_status status
= NSS_STATUS_SUCCESS
;
420 __set_errno (EINVAL
);
421 return NSS_STATUS_UNAVAIL
;
424 __libc_lock_lock (lock
);
426 /* Open the stream or rest it. */
427 status
= internal_setent ();
430 if (status
== NSS_STATUS_SUCCESS
)
432 result
->alias_local
= 1;
434 /* Read lines until we get a definite result. */
436 status
= get_next_alias (name
, result
, buffer
, buflen
);
437 while (status
== NSS_STATUS_RETURN
);
442 __libc_lock_unlock (lock
);