1 | /* Copyright (C) 1991-2019 Free Software Foundation, Inc. |
2 | This file is part of the GNU C Library. |
3 | |
4 | The GNU C Library is free software; you can redistribute it and/or |
5 | modify it under the terms of the GNU Lesser General Public |
6 | License as published by the Free Software Foundation; either |
7 | version 2.1 of the License, or (at your option) any later version. |
8 | |
9 | The GNU C Library is distributed in the hope that it will be useful, |
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
12 | Lesser General Public License for more details. |
13 | |
14 | You should have received a copy of the GNU Lesser General Public |
15 | License along with the GNU C Library; if not, see |
16 | <http://www.gnu.org/licenses/>. */ |
17 | |
18 | #include <alloca.h> |
19 | #include <argz.h> |
20 | #include <errno.h> |
21 | #include <libc-lock.h> |
22 | #include <locale.h> |
23 | #include <stdlib.h> |
24 | #include <string.h> |
25 | #include <unistd.h> |
26 | |
27 | #include "localeinfo.h" |
28 | |
29 | #ifdef NL_CURRENT_INDIRECT |
30 | |
31 | /* For each category declare a special external symbol |
32 | _nl_current_CATEGORY_used with a weak reference. |
33 | This symbol will is defined in lc-CATEGORY.c and will be linked in |
34 | if anything uses _nl_current_CATEGORY (also defined in that module). |
35 | Also use a weak reference for the _nl_current_CATEGORY thread variable. */ |
36 | |
37 | # define DEFINE_CATEGORY(category, category_name, items, a) \ |
38 | extern char _nl_current_##category##_used; \ |
39 | weak_extern (_nl_current_##category##_used) \ |
40 | weak_extern (_nl_current_##category) |
41 | # include "categories.def" |
42 | # undef DEFINE_CATEGORY |
43 | |
44 | /* Now define a table of flags based on those special weak symbols' values. |
45 | _nl_current_used[CATEGORY] will be zero if _nl_current_CATEGORY is not |
46 | linked in. */ |
47 | static char *const _nl_current_used[] = |
48 | { |
49 | # define DEFINE_CATEGORY(category, category_name, items, a) \ |
50 | [category] = &_nl_current_##category##_used, |
51 | # include "categories.def" |
52 | # undef DEFINE_CATEGORY |
53 | }; |
54 | |
55 | # define CATEGORY_USED(category) (_nl_current_used[category] != 0) |
56 | |
57 | #else |
58 | |
59 | /* The shared library always loads all the categories, |
60 | and the current global settings are kept in _nl_global_locale. */ |
61 | |
62 | # define CATEGORY_USED(category) (1) |
63 | |
64 | #endif |
65 | |
66 | |
67 | /* Define an array of category names (also the environment variable names). */ |
68 | const union catnamestr_t _nl_category_names attribute_hidden = |
69 | { |
70 | { |
71 | #define DEFINE_CATEGORY(category, category_name, items, a) \ |
72 | category_name, |
73 | #include "categories.def" |
74 | #undef DEFINE_CATEGORY |
75 | } |
76 | }; |
77 | |
78 | const uint8_t _nl_category_name_idxs[__LC_LAST] attribute_hidden = |
79 | { |
80 | #define DEFINE_CATEGORY(category, category_name, items, a) \ |
81 | [category] = offsetof (union catnamestr_t, CATNAMEMF (__LINE__)), |
82 | #include "categories.def" |
83 | #undef DEFINE_CATEGORY |
84 | }; |
85 | |
86 | /* An array of their lengths, for convenience. */ |
87 | const uint8_t _nl_category_name_sizes[] attribute_hidden = |
88 | { |
89 | #define DEFINE_CATEGORY(category, category_name, items, a) \ |
90 | [category] = sizeof (category_name) - 1, |
91 | #include "categories.def" |
92 | #undef DEFINE_CATEGORY |
93 | [LC_ALL] = sizeof ("LC_ALL" ) - 1 |
94 | }; |
95 | |
96 | |
97 | #ifdef NL_CURRENT_INDIRECT |
98 | # define WEAK_POSTLOAD(postload) weak_extern (postload) |
99 | #else |
100 | # define WEAK_POSTLOAD(postload) /* Need strong refs in static linking. */ |
101 | #endif |
102 | |
103 | /* Declare the postload functions used below. */ |
104 | #undef NO_POSTLOAD |
105 | #define NO_POSTLOAD _nl_postload_ctype /* Harmless thing known to exist. */ |
106 | #define DEFINE_CATEGORY(category, category_name, items, postload) \ |
107 | extern void postload (void); WEAK_POSTLOAD (postload) |
108 | #include "categories.def" |
109 | #undef DEFINE_CATEGORY |
110 | #undef NO_POSTLOAD |
111 | |
112 | /* Define an array indexed by category of postload functions to call after |
113 | loading and installing that category's data. */ |
114 | static void (*const _nl_category_postload[]) (void) = |
115 | { |
116 | #define DEFINE_CATEGORY(category, category_name, items, postload) \ |
117 | [category] = postload, |
118 | #include "categories.def" |
119 | #undef DEFINE_CATEGORY |
120 | }; |
121 | |
122 | |
123 | /* Lock for protecting global data. */ |
124 | __libc_rwlock_define_initialized (, __libc_setlocale_lock attribute_hidden) |
125 | |
126 | /* Defined in loadmsgcat.c. */ |
127 | extern int _nl_msg_cat_cntr; |
128 | |
129 | |
130 | /* Use this when we come along an error. */ |
131 | #define ERROR_RETURN \ |
132 | do { \ |
133 | __set_errno (EINVAL); \ |
134 | return NULL; \ |
135 | } while (0) |
136 | |
137 | |
138 | /* Construct a new composite name. */ |
139 | static char * |
140 | new_composite_name (int category, const char *newnames[__LC_LAST]) |
141 | { |
142 | size_t last_len = 0; |
143 | size_t cumlen = 0; |
144 | int i; |
145 | char *new, *p; |
146 | int same = 1; |
147 | |
148 | for (i = 0; i < __LC_LAST; ++i) |
149 | if (i != LC_ALL) |
150 | { |
151 | const char *name = (category == LC_ALL ? newnames[i] |
152 | : category == i ? newnames[0] |
153 | : _nl_global_locale.__names[i]); |
154 | last_len = strlen (name); |
155 | cumlen += _nl_category_name_sizes[i] + 1 + last_len + 1; |
156 | if (same && name != newnames[0] && strcmp (name, newnames[0]) != 0) |
157 | same = 0; |
158 | } |
159 | |
160 | if (same) |
161 | { |
162 | /* All the categories use the same name. */ |
163 | if (strcmp (newnames[0], _nl_C_name) == 0 |
164 | || strcmp (newnames[0], _nl_POSIX_name) == 0) |
165 | return (char *) _nl_C_name; |
166 | |
167 | new = malloc (last_len + 1); |
168 | |
169 | return new == NULL ? NULL : memcpy (new, newnames[0], last_len + 1); |
170 | } |
171 | |
172 | new = malloc (cumlen); |
173 | if (new == NULL) |
174 | return NULL; |
175 | p = new; |
176 | for (i = 0; i < __LC_LAST; ++i) |
177 | if (i != LC_ALL) |
178 | { |
179 | /* Add "CATEGORY=NAME;" to the string. */ |
180 | const char *name = (category == LC_ALL ? newnames[i] |
181 | : category == i ? newnames[0] |
182 | : _nl_global_locale.__names[i]); |
183 | p = __stpcpy (p, _nl_category_names.str + _nl_category_name_idxs[i]); |
184 | *p++ = '='; |
185 | p = __stpcpy (p, name); |
186 | *p++ = ';'; |
187 | } |
188 | p[-1] = '\0'; /* Clobber the last ';'. */ |
189 | return new; |
190 | } |
191 | |
192 | |
193 | /* Put NAME in _nl_global_locale.__names. */ |
194 | static void |
195 | setname (int category, const char *name) |
196 | { |
197 | if (_nl_global_locale.__names[category] == name) |
198 | return; |
199 | |
200 | if (_nl_global_locale.__names[category] != _nl_C_name) |
201 | free ((char *) _nl_global_locale.__names[category]); |
202 | |
203 | _nl_global_locale.__names[category] = name; |
204 | } |
205 | |
206 | /* Put DATA in *_nl_current[CATEGORY]. */ |
207 | static void |
208 | setdata (int category, struct __locale_data *data) |
209 | { |
210 | if (CATEGORY_USED (category)) |
211 | { |
212 | _nl_global_locale.__locales[category] = data; |
213 | if (_nl_category_postload[category]) |
214 | (*_nl_category_postload[category]) (); |
215 | } |
216 | } |
217 | |
218 | char * |
219 | setlocale (int category, const char *locale) |
220 | { |
221 | char *locale_path; |
222 | size_t locale_path_len; |
223 | const char *locpath_var; |
224 | char *composite; |
225 | |
226 | /* Sanity check for CATEGORY argument. */ |
227 | if (__builtin_expect (category, 0) < 0 |
228 | || __builtin_expect (category, 0) >= __LC_LAST) |
229 | ERROR_RETURN; |
230 | |
231 | /* Does user want name of current locale? */ |
232 | if (locale == NULL) |
233 | return (char *) _nl_global_locale.__names[category]; |
234 | |
235 | /* Protect global data. */ |
236 | __libc_rwlock_wrlock (__libc_setlocale_lock); |
237 | |
238 | if (strcmp (locale, _nl_global_locale.__names[category]) == 0) |
239 | { |
240 | /* Changing to the same thing. */ |
241 | __libc_rwlock_unlock (__libc_setlocale_lock); |
242 | |
243 | return (char *) _nl_global_locale.__names[category]; |
244 | } |
245 | |
246 | /* We perhaps really have to load some data. So we determine the |
247 | path in which to look for the data now. The environment variable |
248 | `LOCPATH' must only be used when the binary has no SUID or SGID |
249 | bit set. If using the default path, we tell _nl_find_locale |
250 | by passing null and it can check the canonical locale archive. */ |
251 | locale_path = NULL; |
252 | locale_path_len = 0; |
253 | |
254 | locpath_var = getenv ("LOCPATH" ); |
255 | if (locpath_var != NULL && locpath_var[0] != '\0') |
256 | { |
257 | if (__argz_create_sep (locpath_var, ':', |
258 | &locale_path, &locale_path_len) != 0 |
259 | || __argz_add_sep (&locale_path, &locale_path_len, |
260 | _nl_default_locale_path, ':') != 0) |
261 | { |
262 | __libc_rwlock_unlock (__libc_setlocale_lock); |
263 | return NULL; |
264 | } |
265 | } |
266 | |
267 | if (category == LC_ALL) |
268 | { |
269 | /* The user wants to set all categories. The desired locales |
270 | for the individual categories can be selected by using a |
271 | composite locale name. This is a semi-colon separated list |
272 | of entries of the form `CATEGORY=VALUE'. */ |
273 | const char *newnames[__LC_LAST]; |
274 | struct __locale_data *newdata[__LC_LAST]; |
275 | /* Copy of the locale argument, for in-place splitting. */ |
276 | char *locale_copy = NULL; |
277 | |
278 | /* Set all name pointers to the argument name. */ |
279 | for (category = 0; category < __LC_LAST; ++category) |
280 | if (category != LC_ALL) |
281 | newnames[category] = (char *) locale; |
282 | |
283 | if (__glibc_unlikely (strchr (locale, ';') != NULL)) |
284 | { |
285 | /* This is a composite name. Make a copy and split it up. */ |
286 | locale_copy = __strdup (locale); |
287 | if (__glibc_unlikely (locale_copy == NULL)) |
288 | { |
289 | __libc_rwlock_unlock (__libc_setlocale_lock); |
290 | return NULL; |
291 | } |
292 | char *np = locale_copy; |
293 | char *cp; |
294 | int cnt; |
295 | |
296 | while ((cp = strchr (np, '=')) != NULL) |
297 | { |
298 | for (cnt = 0; cnt < __LC_LAST; ++cnt) |
299 | if (cnt != LC_ALL |
300 | && (size_t) (cp - np) == _nl_category_name_sizes[cnt] |
301 | && (memcmp (np, (_nl_category_names.str |
302 | + _nl_category_name_idxs[cnt]), cp - np) |
303 | == 0)) |
304 | break; |
305 | |
306 | if (cnt == __LC_LAST) |
307 | { |
308 | error_return: |
309 | __libc_rwlock_unlock (__libc_setlocale_lock); |
310 | free (locale_copy); |
311 | |
312 | /* Bogus category name. */ |
313 | ERROR_RETURN; |
314 | } |
315 | |
316 | /* Found the category this clause sets. */ |
317 | newnames[cnt] = ++cp; |
318 | cp = strchr (cp, ';'); |
319 | if (cp != NULL) |
320 | { |
321 | /* Examine the next clause. */ |
322 | *cp = '\0'; |
323 | np = cp + 1; |
324 | } |
325 | else |
326 | /* This was the last clause. We are done. */ |
327 | break; |
328 | } |
329 | |
330 | for (cnt = 0; cnt < __LC_LAST; ++cnt) |
331 | if (cnt != LC_ALL && newnames[cnt] == locale) |
332 | /* The composite name did not specify all categories. */ |
333 | goto error_return; |
334 | } |
335 | |
336 | /* Load the new data for each category. */ |
337 | while (category-- > 0) |
338 | if (category != LC_ALL) |
339 | { |
340 | newdata[category] = _nl_find_locale (locale_path, locale_path_len, |
341 | category, |
342 | &newnames[category]); |
343 | |
344 | if (newdata[category] == NULL) |
345 | { |
346 | #ifdef NL_CURRENT_INDIRECT |
347 | if (newnames[category] == _nl_C_name) |
348 | /* Null because it's the weak value of _nl_C_LC_FOO. */ |
349 | continue; |
350 | #endif |
351 | break; |
352 | } |
353 | |
354 | /* We must not simply free a global locale since we have |
355 | no control over the usage. So we mark it as |
356 | un-deletable. And yes, the 'if' is needed, the data |
357 | might be in read-only memory. */ |
358 | if (newdata[category]->usage_count != UNDELETABLE) |
359 | newdata[category]->usage_count = UNDELETABLE; |
360 | |
361 | /* Make a copy of locale name. */ |
362 | if (newnames[category] != _nl_C_name) |
363 | { |
364 | if (strcmp (newnames[category], |
365 | _nl_global_locale.__names[category]) == 0) |
366 | newnames[category] = _nl_global_locale.__names[category]; |
367 | else |
368 | { |
369 | newnames[category] = __strdup (newnames[category]); |
370 | if (newnames[category] == NULL) |
371 | break; |
372 | } |
373 | } |
374 | } |
375 | |
376 | /* Create new composite name. */ |
377 | composite = (category >= 0 |
378 | ? NULL : new_composite_name (LC_ALL, newnames)); |
379 | if (composite != NULL) |
380 | { |
381 | /* Now we have loaded all the new data. Put it in place. */ |
382 | for (category = 0; category < __LC_LAST; ++category) |
383 | if (category != LC_ALL) |
384 | { |
385 | setdata (category, newdata[category]); |
386 | setname (category, newnames[category]); |
387 | } |
388 | setname (LC_ALL, composite); |
389 | |
390 | /* We successfully loaded a new locale. Let the message catalog |
391 | functions know about this. */ |
392 | ++_nl_msg_cat_cntr; |
393 | } |
394 | else |
395 | for (++category; category < __LC_LAST; ++category) |
396 | if (category != LC_ALL && newnames[category] != _nl_C_name |
397 | && newnames[category] != _nl_global_locale.__names[category]) |
398 | free ((char *) newnames[category]); |
399 | |
400 | /* Critical section left. */ |
401 | __libc_rwlock_unlock (__libc_setlocale_lock); |
402 | |
403 | /* Free the resources. */ |
404 | free (locale_path); |
405 | free (locale_copy); |
406 | |
407 | return composite; |
408 | } |
409 | else |
410 | { |
411 | struct __locale_data *newdata = NULL; |
412 | const char *newname[1] = { locale }; |
413 | |
414 | if (CATEGORY_USED (category)) |
415 | { |
416 | /* Only actually load the data if anything will use it. */ |
417 | newdata = _nl_find_locale (locale_path, locale_path_len, category, |
418 | &newname[0]); |
419 | if (newdata == NULL) |
420 | goto abort_single; |
421 | |
422 | /* We must not simply free a global locale since we have no |
423 | control over the usage. So we mark it as un-deletable. |
424 | |
425 | Note: do not remove the `if', it's necessary to cope with |
426 | the builtin locale data. */ |
427 | if (newdata->usage_count != UNDELETABLE) |
428 | newdata->usage_count = UNDELETABLE; |
429 | } |
430 | |
431 | /* Make a copy of locale name. */ |
432 | if (newname[0] != _nl_C_name) |
433 | { |
434 | newname[0] = __strdup (newname[0]); |
435 | if (newname[0] == NULL) |
436 | goto abort_single; |
437 | } |
438 | |
439 | /* Create new composite name. */ |
440 | composite = new_composite_name (category, newname); |
441 | if (composite == NULL) |
442 | { |
443 | if (newname[0] != _nl_C_name) |
444 | free ((char *) newname[0]); |
445 | |
446 | /* Say that we don't have any data loaded. */ |
447 | abort_single: |
448 | newname[0] = NULL; |
449 | } |
450 | else |
451 | { |
452 | if (CATEGORY_USED (category)) |
453 | setdata (category, newdata); |
454 | |
455 | setname (category, newname[0]); |
456 | setname (LC_ALL, composite); |
457 | |
458 | /* We successfully loaded a new locale. Let the message catalog |
459 | functions know about this. */ |
460 | ++_nl_msg_cat_cntr; |
461 | } |
462 | |
463 | /* Critical section left. */ |
464 | __libc_rwlock_unlock (__libc_setlocale_lock); |
465 | |
466 | /* Free the resources (the locale path variable. */ |
467 | free (locale_path); |
468 | |
469 | return (char *) newname[0]; |
470 | } |
471 | } |
472 | libc_hidden_def (setlocale) |
473 | |
474 | static void __libc_freeres_fn_section |
475 | free_category (int category, |
476 | struct __locale_data *here, struct __locale_data *c_data) |
477 | { |
478 | struct loaded_l10nfile *runp = _nl_locale_file_list[category]; |
479 | |
480 | /* If this category is already "C" don't do anything. */ |
481 | if (here != c_data) |
482 | { |
483 | /* We have to be prepared that sometime later we still |
484 | might need the locale information. */ |
485 | setdata (category, c_data); |
486 | setname (category, _nl_C_name); |
487 | } |
488 | |
489 | while (runp != NULL) |
490 | { |
491 | struct loaded_l10nfile *curr = runp; |
492 | struct __locale_data *data = (struct __locale_data *) runp->data; |
493 | |
494 | if (data != NULL && data != c_data) |
495 | _nl_unload_locale (data); |
496 | runp = runp->next; |
497 | free ((char *) curr->filename); |
498 | free (curr); |
499 | } |
500 | } |
501 | |
502 | /* This is called from iconv/gconv_db.c's free_mem, as locales must |
503 | be freed before freeing gconv steps arrays. */ |
504 | void __libc_freeres_fn_section |
505 | _nl_locale_subfreeres (void) |
506 | { |
507 | #ifdef NL_CURRENT_INDIRECT |
508 | /* We don't use the loop because we want to have individual weak |
509 | symbol references here. */ |
510 | # define DEFINE_CATEGORY(category, category_name, items, a) \ |
511 | if (CATEGORY_USED (category)) \ |
512 | { \ |
513 | extern struct __locale_data _nl_C_##category; \ |
514 | weak_extern (_nl_C_##category) \ |
515 | free_category (category, *_nl_current_##category, &_nl_C_##category); \ |
516 | } |
517 | # include "categories.def" |
518 | # undef DEFINE_CATEGORY |
519 | #else |
520 | int category; |
521 | |
522 | for (category = 0; category < __LC_LAST; ++category) |
523 | if (category != LC_ALL) |
524 | free_category (category, _NL_CURRENT_DATA (category), |
525 | _nl_C_locobj.__locales[category]); |
526 | #endif |
527 | |
528 | setname (LC_ALL, _nl_C_name); |
529 | |
530 | /* This frees the data structures associated with the locale archive. |
531 | The locales from the archive are not in the file list, so we have |
532 | not called _nl_unload_locale on them above. */ |
533 | _nl_archive_subfreeres (); |
534 | } |
535 | |