]>
git.ipfire.org Git - thirdparty/glibc.git/blob - nss/nss_files/files-alias.c
b18361f66cf9a49f87a92e03cfe955467352bb0e
1 /* Mail alias file parser in nss_files module.
2 Copyright (C) 1996, 1997, 1998 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
, int *errnop
)
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] = '\xff';
154 line
= fgets (first_unused
, room_left
, stream
);
156 /* Nothing to read. */
158 else if (first_unused
[room_left
- 1] != '\xff')
160 /* The line is too long for our buffer. */
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
204 && __strcasecmp (result
->alias_name
, match
) != 0);
208 while (isspace (*line
))
212 while (*line
!= '\0' && *line
!= ',')
213 *first_unused
++ = *line
++;
215 if (first_unused
!= cp
)
217 /* OK, we can have a regular entry or an include
221 *first_unused
++ = '\0';
223 if (strncmp (cp
, ":include:", 9) != 0)
225 if (room_left
< (first_unused
- cp
) + sizeof (char *))
227 room_left
-= (first_unused
- cp
) + sizeof (char *);
229 ++result
->alias_members_len
;
233 /* Oh well, we have to read the addressed file. */
235 char *old_line
= NULL
;
239 listfile
= fopen (&cp
[9], "r");
240 /* If the file does not exist we simply ignore
243 && (old_line
= strdup (line
)) != NULL
)
245 while (! feof (listfile
))
247 first_unused
[room_left
- 1] = '\xff';
248 line
= fgets (first_unused
, room_left
, listfile
);
251 if (first_unused
[room_left
- 1] != '\xff')
257 /* Parse the line. */
258 cp
= strpbrk (line
, "#\n");
264 while (isspace (*line
))
268 while (*line
!= '\0' && *line
!= ',')
269 *first_unused
++ = *line
++;
274 if (first_unused
!= cp
)
276 *first_unused
++ = '\0';
277 if (room_left
< ((first_unused
- cp
)
278 + __alignof__ (char *)))
283 room_left
-= ((first_unused
- cp
)
284 + __alignof__ (char *));
285 ++result
->alias_members_len
;
288 while (*line
!= '\0');
292 first_unused
[room_left
- 1] = '\0';
293 strncpy (first_unused
, old_line
, room_left
);
295 if (old_line
!= NULL
)
298 if (first_unused
[room_left
- 1] != '\0')
306 /* Get the next line. But we must be careful. We
307 must not read the whole line at once since it
308 might belong to the current alias. Simply read
309 the first character. If it is a white space we
310 have a continuation line. Otherwise it is the
311 beginning of a new alias and we can push back the
312 just read character. */
316 if (ch
== EOF
|| ch
== '\n' || !isspace (ch
))
320 /* Now prepare the return. Provide string
321 pointers for the currently selected aliases. */
325 /* Adjust the pointer so it is aligned for
327 first_unused
+= __alignof__ (char *) - 1;
328 first_unused
-= ((first_unused
- (char *) 0)
329 % __alignof__ (char *));
330 result
->alias_members
= (char **) first_unused
;
332 /* Compute addresses of alias entry strings. */
333 cp
= result
->alias_name
;
334 for (cnt
= 0; cnt
< result
->alias_members_len
; ++cnt
)
336 cp
= strchr (cp
, '\0') + 1;
337 result
->alias_members
[cnt
] = cp
;
340 status
= (result
->alias_members_len
== 0
341 ? NSS_STATUS_RETURN
: NSS_STATUS_SUCCESS
);
345 /* The just read character is a white space and so
347 first_unused
[room_left
- 1] = '\xff';
348 line
= fgets (first_unused
, room_left
, stream
);
349 if (first_unused
[room_left
- 1] != '\xff')
351 cp
= strpbrk (line
, "#\n");
358 if (status
!= NSS_STATUS_NOTFOUND
)
359 /* We read something. In any case break here. */
368 _nss_files_getaliasent_r (struct aliasent
*result
, char *buffer
, size_t buflen
,
371 /* Return next entry in host file. */
372 enum nss_status status
= NSS_STATUS_SUCCESS
;
374 __libc_lock_lock (lock
);
376 /* Be prepared that the set*ent function was not called before. */
378 status
= internal_setent ();
380 if (status
== NSS_STATUS_SUCCESS
)
382 /* If the last use was not by the getent function we need the
383 position the stream. */
384 if (last_use
!= getent
)
386 if (fsetpos (stream
, &position
) < 0)
387 status
= NSS_STATUS_UNAVAIL
;
392 if (status
== NSS_STATUS_SUCCESS
)
394 result
->alias_local
= 1;
396 /* Read lines until we get a definite result. */
398 status
= get_next_alias (NULL
, result
, buffer
, buflen
, errnop
);
399 while (status
== NSS_STATUS_RETURN
);
401 /* If we successfully read an entry remember this position. */
402 if (status
== NSS_STATUS_SUCCESS
)
403 fgetpos (stream
, &position
);
409 __libc_lock_unlock (lock
);
416 _nss_files_getaliasbyname_r (const char *name
, struct aliasent
*result
,
417 char *buffer
, size_t buflen
, int *errnop
)
419 /* Return next entry in host file. */
420 enum nss_status status
= NSS_STATUS_SUCCESS
;
424 __set_errno (EINVAL
);
425 return NSS_STATUS_UNAVAIL
;
428 __libc_lock_lock (lock
);
430 /* Open the stream or rest it. */
431 status
= internal_setent ();
434 if (status
== NSS_STATUS_SUCCESS
)
436 result
->alias_local
= 1;
438 /* Read lines until we get a definite result. */
440 status
= get_next_alias (name
, result
, buffer
, buflen
, errnop
);
441 while (status
== NSS_STATUS_RETURN
);
446 __libc_lock_unlock (lock
);