Change everything to store error code through provided pointer and not
[kopensolaris-gnu/glibc.git] / nss / nss_db / db-alias.c
1 /* Mail alias file parser in nss_db 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.
5
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.
10
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.
15
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.  */
20
21 #include <aliases.h>
22 #include <alloca.h>
23 #include <ctype.h>
24 #include <db_185.h>
25 #include <errno.h>
26 #include <fcntl.h>
27 #include <bits/libc-lock.h>
28 #include <paths.h>
29 #include <string.h>
30
31 #include "nsswitch.h"
32
33 /* Locks the static variables in this file.  */
34 __libc_lock_define_initialized (static, lock)
35 \f
36 /* Maintenance of the shared handle open on the database.  */
37
38 static DB *db;
39 static int keep_db;
40 static unsigned int entidx;     /* Index for `getaliasent_r'. */
41
42 /* Open database file if not already opened.  */
43 static enum nss_status
44 internal_setent (int stayopen)
45 {
46   enum nss_status status = NSS_STATUS_SUCCESS;
47
48   if (db == NULL)
49     {
50       db = __dbopen (_PATH_VARDB "aliases.db", O_RDONLY, 0, DB_BTREE, NULL);
51
52       if (db == NULL)
53         status = NSS_STATUS_UNAVAIL;
54       else
55         {
56           /* We have to make sure the file is  `closed on exec'.  */
57           int result, flags;
58
59           result = flags = fcntl ((*db->fd) (db), F_GETFD, 0);
60           if (result >= 0)
61             {
62               flags |= FD_CLOEXEC;
63               result = fcntl ((*db->fd) (db), F_SETFD, flags);
64             }
65           if (result < 0)
66             {
67               /* Something went wrong.  Close the stream and return a
68                  failure.  */
69               (*db->close) (db);
70               db = NULL;
71               status = NSS_STATUS_UNAVAIL;
72             }
73         }
74     }
75
76   /* Remember STAYOPEN flag.  */
77   if (db != NULL)
78     keep_db |= stayopen;
79
80   return status;
81 }
82
83
84 /* Thread-safe, exported version of that.  */
85 enum nss_status
86 _nss_db_setaliasent (int stayopen)
87 {
88   enum nss_status status;
89
90   __libc_lock_lock (lock);
91
92   status = internal_setent (stayopen);
93
94   /* Reset the sequential index.  */
95   entidx = 0;
96
97   __libc_lock_unlock (lock);
98
99   return status;
100 }
101
102
103 /* Close the database file.  */
104 static void
105 internal_endent (void)
106 {
107   if (db != NULL)
108     {
109       (*db->close) (db);
110       db = NULL;
111     }
112 }
113
114
115 /* Thread-safe, exported version of that.  */
116 enum nss_status
117 _nss_db_endaliasent (void)
118 {
119   __libc_lock_lock (lock);
120
121   internal_endent ();
122
123   /* Reset STAYOPEN flag.  */
124   keep_db = 0;
125
126   __libc_lock_unlock (lock);
127
128   return NSS_STATUS_SUCCESS;
129 }
130 \f
131 /* We provide the parse function here.  The parser in libnss_files
132    cannot be used.  The generation of the db file already resolved all
133    :include: statements so we simply have to parse the list and store
134    the result.  */
135 static enum nss_status
136 lookup (const DBT *key, struct aliasent *result, char *buffer,
137         size_t buflen, int *errnop)
138 {
139   enum nss_status status;
140   DBT value;
141
142   /* Open the database.  */
143   status = internal_setent (keep_db);
144   if (status != NSS_STATUS_SUCCESS)
145     return status;
146
147   if ((*db->get) (db, key, &value, 0) == 0)
148     {
149       const char *src = value.data;
150
151       result->alias_members_len = 0;
152
153       /* We now have to fill the BUFFER with all the information. */
154       if (buflen < key->size + 1)
155         {
156         no_more_room:
157           *errnop = ERANGE;
158           return NSS_STATUS_TRYAGAIN;
159         }
160
161       if (status == NSS_STATUS_SUCCESS)
162         {
163           char *cp;
164           size_t cnt;
165
166           buffer = stpncpy (buffer, key->data, key->size) + 1;
167           buflen -= key->size + 1;
168
169           while (*src != '\0')
170             {
171               const char *end, *upto;
172               while (isspace (*src))
173                 ++src;
174
175               end = strchr (src, ',');
176               if (end == NULL)
177                 end = strchr (src, '\0');
178               for (upto = end; upto > src && isspace (upto[-1]); --upto);
179
180               if (upto != src)
181                 {
182                   if ((upto - src) + __alignof__ (char *) > buflen)
183                     goto no_more_room;
184                   buffer = stpncpy (buffer, src, upto - src) + 1;
185                   buflen -= (upto - src) + __alignof (char *);
186                   ++result->alias_members_len;
187                 }
188               src = end + (*end != '\0');
189             }
190
191           /* Now prepare the return.  Provide string pointers for the
192              currently selected aliases.  */
193
194           /* Adjust the pointer so it is aligned for storing pointers.  */
195           buffer += __alignof__ (char *) - 1;
196           buffer -= ((buffer - (char *) 0) % __alignof__ (char *));
197           result->alias_members = (char **) buffer;
198
199           /* Compute addresses of alias entry strings.  */
200           cp = result->alias_name;
201           for (cnt = 0; cnt < result->alias_members_len; ++cnt)
202             {
203               cp = strchr (cp, '\0') + 1;
204               result->alias_members[cnt] = cp;
205             }
206
207           status = (result->alias_members_len == 0
208                     ? NSS_STATUS_RETURN : NSS_STATUS_SUCCESS);
209         }
210     }
211   else
212     status = NSS_STATUS_NOTFOUND;
213
214   if (! keep_db)
215     internal_endent ();
216
217   return status;
218 }
219 \f
220 enum nss_status
221 _nss_db_getaliasent_r (struct aliasent *result, char *buffer, size_t buflen,
222                        int *errnop)
223 {
224   /* Return next entry in host file.  */
225   enum nss_status status;
226   char buf[20];
227   DBT key;
228
229   __libc_lock_lock (lock);
230   key.size = 1 + snprintf (key.data = buf, sizeof buf, "0%u", entidx++);
231   status = lookup (&key, result, buffer, buflen, errnop);
232   __libc_lock_unlock (lock);
233
234   return status;
235 }
236
237
238 enum nss_status
239 _nss_db_getaliasbyname_r (const char *name, struct aliasent *result,
240                           char *buffer, size_t buflen, int *errnop)
241 {
242   DBT key;
243   enum nss_status status;
244
245   key.size = 1 + strlen (name);
246
247   key.data = __alloca (key.size);
248   ((char *) key.data)[0] = '.';
249   memcpy (&((char *) key.data)[1], name, key.size - 1);
250
251   __libc_lock_lock (lock);
252   status = lookup (&key, result, buffer, buflen, errnop);
253   __libc_lock_unlock (lock);
254
255   return status;
256 }