Update.
[platform/upstream/glibc.git] / catgets / open_catalog.c
1 /* Copyright (C) 1996, 1997, 1998 Free Software Foundation, Inc.
2    This file is part of the GNU C Library.
3    Contributed by Ulrich Drepper, <drepper@gnu.ai.mit.edu>.
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 not,
17    write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18    Boston, MA 02111-1307, USA.  */
19
20 #include <byteswap.h>
21 #include <endian.h>
22 #include <fcntl.h>
23 #include <string.h>
24 #include <stdlib.h>
25 #include <unistd.h>
26 #include <sys/mman.h>
27 #include <sys/stat.h>
28
29 #include "catgetsinfo.h"
30
31
32 #define SWAPU32(w) bswap_32 (w)
33
34
35 void
36 __open_catalog (__nl_catd catalog)
37 {
38   int fd = -1;
39   struct stat st;
40   int swapping;
41
42   /* Make sure we are alone.  */
43   __libc_lock_lock (catalog->lock);
44
45   /* Check whether there was no other thread faster.  */
46   if (catalog->status != closed)
47     /* While we waited some other thread tried to open the catalog.  */
48     goto unlock_return;
49
50   if (strchr (catalog->cat_name, '/') != NULL || catalog->nlspath == NULL)
51     fd = __open (catalog->cat_name, O_RDONLY);
52   else
53     {
54       const char *run_nlspath = catalog->nlspath;
55 #define ENOUGH(n)                                                             \
56   if (bufact + (n) >=bufmax)                                                  \
57     {                                                                         \
58       char *old_buf = buf;                                                    \
59       bufmax += 256 + (n);                                                    \
60       buf = (char *) alloca (bufmax);                                         \
61       memcpy (buf, old_buf, bufact);                                          \
62     }
63
64       /* The RUN_NLSPATH variable contains a colon separated list of
65          descriptions where we expect to find catalogs.  We have to
66          recognize certain % substitutions and stop when we found the
67          first existing file.  */
68       char *buf;
69       size_t bufact;
70       size_t bufmax;
71       size_t len;
72
73       buf = NULL;
74       bufmax = 0;
75
76       fd = -1;
77       while (*run_nlspath != '\0')
78         {
79           bufact = 0;
80           while (*run_nlspath != ':' && *run_nlspath != '\0')
81             if (*run_nlspath == '%')
82               {
83                 const char *tmp;
84
85                 ++run_nlspath;  /* We have seen the `%'.  */
86                 switch (*run_nlspath++)
87                   {
88                   case 'N':
89                     /* Use the catalog name.  */
90                     len = strlen (catalog->cat_name);
91                     ENOUGH (len);
92                     memcpy (&buf[bufact], catalog->cat_name, len);
93                     bufact += len;
94                     break;
95                   case 'L':
96                     /* Use the current locale category value.  */
97                     len = strlen (catalog->env_var);
98                     ENOUGH (len);
99                     memcpy (&buf[bufact], catalog->env_var, len);
100                     bufact += len;
101                     break;
102                   case 'l':
103                     /* Use language element of locale category value.  */
104                     tmp = catalog->env_var;
105                     do
106                       {
107                         ENOUGH (1);
108                         buf[bufact++] = *tmp++;
109                       }
110                     while (*tmp != '\0' && *tmp != '_' && *tmp != '.');
111                     break;
112                   case 't':
113                     /* Use territory element of locale category value.  */
114                     tmp = catalog->env_var;
115                     do
116                       ++tmp;
117                     while (*tmp != '\0' && *tmp != '_' && *tmp != '.');
118                     if (*tmp == '_')
119                       {
120                         ++tmp;
121                         do
122                           {
123                             ENOUGH (1);
124                             buf[bufact++] = *tmp;
125                           }
126                         while (*tmp != '\0' && *tmp != '.');
127                       }
128                     break;
129                   case 'c':
130                     /* Use code set element of locale category value.  */
131                     tmp = catalog->env_var;
132                     do
133                       ++tmp;
134                     while (*tmp != '\0' && *tmp != '.');
135                     if (*tmp == '.')
136                       {
137                         ++tmp;
138                         do
139                           {
140                             ENOUGH (1);
141                             buf[bufact++] = *tmp;
142                           }
143                         while (*tmp != '\0');
144                       }
145                     break;
146                   case '%':
147                     ENOUGH (1);
148                     buf[bufact++] = '%';
149                     break;
150                   default:
151                     /* Unknown variable: ignore this path element.  */
152                     bufact = 0;
153                     while (*run_nlspath != '\0' && *run_nlspath != ':')
154                       ++run_nlspath;
155                     break;
156                   }
157               }
158             else
159               {
160                 ENOUGH (1);
161                 buf[bufact++] = *run_nlspath++;
162               }
163           ENOUGH (1);
164           buf[bufact] = '\0';
165
166           if (bufact != 0)
167             {
168               fd = __open (buf, O_RDONLY);
169               if (fd >= 0)
170                 break;
171             }
172
173           ++run_nlspath;
174         }
175     }
176
177   /* Avoid dealing with directories and block devices */
178   if (fd < 0 || __fstat (fd, &st) < 0 || !S_ISREG (st.st_mode))
179     {
180       catalog->status = nonexisting;
181       goto unlock_return;
182     }
183
184 #ifndef MAP_COPY
185     /* Linux seems to lack read-only copy-on-write.  */
186 # define MAP_COPY MAP_PRIVATE
187 #endif
188 #ifndef MAP_FILE
189     /* Some systems do not have this flag; it is superfluous.  */
190 # define MAP_FILE 0
191 #endif
192 #ifndef MAP_INHERIT
193     /* Some systems might lack this; they lose.  */
194 # define MAP_INHERIT 0
195 #endif
196   catalog->file_size = st.st_size;
197   catalog->file_ptr =
198     (struct catalog_obj *) __mmap (NULL, st.st_size, PROT_READ,
199                                    MAP_FILE|MAP_COPY|MAP_INHERIT, fd, 0);
200   if (catalog->file_ptr != (struct catalog_obj *) MAP_FAILED)
201     /* Tell the world we managed to mmap the file.  */
202     catalog->status = mmapped;
203   else
204     {
205       /* mmap failed perhaps because the system call is not
206          implemented.  Try to load the file.  */
207       size_t todo;
208       catalog->file_ptr = malloc (st.st_size);
209       if (catalog->file_ptr == NULL)
210         {
211           catalog->status = nonexisting;
212           goto unlock_return;
213         }
214       todo = st.st_size;
215       /* Save read, handle partial reads.  */
216       do
217         {
218           size_t now = __read (fd, (((char *) &catalog->file_ptr)
219                                     + (st.st_size - todo)), todo);
220           if (now == 0)
221             {
222               free ((void *) catalog->file_ptr);
223               catalog->status = nonexisting;
224               goto unlock_return;
225             }
226           todo -= now;
227         }
228       while (todo > 0);
229       catalog->status = malloced;
230     }
231
232   /* We don't need the file anymore.  */
233   __close (fd);
234   fd = -1;
235
236   /* Determine whether the file is a catalog file and if yes whether
237      it is written using the correct byte order.  Else we have to swap
238      the values.  */
239   if (catalog->file_ptr->magic == CATGETS_MAGIC)
240     swapping = 0;
241   else if (catalog->file_ptr->magic == SWAPU32 (CATGETS_MAGIC))
242     swapping = 1;
243   else
244     {
245       /* Invalid file.  Free the resources and mark catalog as not
246          usable.  */
247       if (catalog->status == mmapped)
248         __munmap ((void *) catalog->file_ptr, catalog->file_size);
249       else
250         free (catalog->file_ptr);
251       catalog->status = nonexisting;
252       goto unlock_return;
253     }
254
255 #define SWAP(x) (swapping ? SWAPU32 (x) : (x))
256
257   /* Get dimensions of the used hashing table.  */
258   catalog->plane_size = SWAP (catalog->file_ptr->plane_size);
259   catalog->plane_depth = SWAP (catalog->file_ptr->plane_depth);
260
261   /* The file contains two versions of the pointer tables.  Pick the
262      right one for the local byte order.  */
263 #if __BYTE_ORDER == __LITTLE_ENDIAN
264   catalog->name_ptr = &catalog->file_ptr->name_ptr[0];
265 #elif __BYTE_ORDER == __BIG_ENDIAN
266   catalog->name_ptr = &catalog->file_ptr->name_ptr[catalog->plane_size
267                                                   * catalog->plane_depth
268                                                   * 3];
269 #else
270 # error Cannot handle __BYTE_ORDER byte order
271 #endif
272
273   /* The rest of the file contains all the strings.  They are
274      addressed relative to the position of the first string.  */
275   catalog->strings =
276     (const char *) &catalog->file_ptr->name_ptr[catalog->plane_size
277                                                * catalog->plane_depth * 3 * 2];
278
279   /* Release the lock again.  */
280  unlock_return:
281   if (fd != -1)
282     __close (fd);
283   __libc_lock_unlock (catalog->lock);
284 }