1d915a14eSPedro F. Giffuni /*-
2*4d846d26SWarner Losh * SPDX-License-Identifier: BSD-2-Clause
3d915a14eSPedro F. Giffuni *
474f2b975SAlexey Zelkin * Copyright (c) 2000, 2001 Alexey Zelkin <phantom@FreeBSD.org>
590423eceSAlexey Zelkin * All rights reserved.
690423eceSAlexey Zelkin *
790423eceSAlexey Zelkin * Redistribution and use in source and binary forms, with or without
890423eceSAlexey Zelkin * modification, are permitted provided that the following conditions
990423eceSAlexey Zelkin * are met:
1090423eceSAlexey Zelkin * 1. Redistributions of source code must retain the above copyright
1190423eceSAlexey Zelkin * notice, this list of conditions and the following disclaimer.
1290423eceSAlexey Zelkin * 2. Redistributions in binary form must reproduce the above copyright
1390423eceSAlexey Zelkin * notice, this list of conditions and the following disclaimer in the
1490423eceSAlexey Zelkin * documentation and/or other materials provided with the distribution.
1590423eceSAlexey Zelkin *
1690423eceSAlexey Zelkin * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1790423eceSAlexey Zelkin * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1890423eceSAlexey Zelkin * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1990423eceSAlexey Zelkin * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
2090423eceSAlexey Zelkin * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2190423eceSAlexey Zelkin * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2290423eceSAlexey Zelkin * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2390423eceSAlexey Zelkin * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2490423eceSAlexey Zelkin * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2590423eceSAlexey Zelkin * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2690423eceSAlexey Zelkin * SUCH DAMAGE.
2790423eceSAlexey Zelkin */
2890423eceSAlexey Zelkin
297d2cc62bSAlexey Zelkin #include "namespace.h"
3090423eceSAlexey Zelkin #include <sys/types.h>
3190423eceSAlexey Zelkin #include <sys/stat.h>
32688dfe45SGarrett Wollman
33f75bb0aaSAndrey A. Chernov #include <errno.h>
3490423eceSAlexey Zelkin #include <fcntl.h>
35688dfe45SGarrett Wollman #include <limits.h>
3690423eceSAlexey Zelkin #include <stdlib.h>
3790423eceSAlexey Zelkin #include <string.h>
38278d1a20SDaniel Eischen #include <unistd.h>
39278d1a20SDaniel Eischen #include "un-namespace.h"
4074f2b975SAlexey Zelkin
4190423eceSAlexey Zelkin #include "ldpart.h"
42683fe113SAlexey Zelkin #include "setlocale.h"
4390423eceSAlexey Zelkin
4490423eceSAlexey Zelkin static int split_lines(char *, const char *);
4590423eceSAlexey Zelkin
4690423eceSAlexey Zelkin int
__part_load_locale(const char * name,int * using_locale,char ** locale_buf,const char * category_filename,int locale_buf_size_max,int locale_buf_size_min,const char ** dst_localebuf)4790423eceSAlexey Zelkin __part_load_locale(const char *name,
4890423eceSAlexey Zelkin int *using_locale,
493dfdc427SJordan K. Hubbard char **locale_buf,
50f43a321bSAlexey Zelkin const char *category_filename,
51fc38c1e5SAlexey Zelkin int locale_buf_size_max,
52fc38c1e5SAlexey Zelkin int locale_buf_size_min,
53f75bb0aaSAndrey A. Chernov const char **dst_localebuf)
54f75bb0aaSAndrey A. Chernov {
5576692b80SAndrey A. Chernov int saverr, fd, i, num_lines;
5676692b80SAndrey A. Chernov char *lbuf, *p;
5790423eceSAlexey Zelkin const char *plim;
5890423eceSAlexey Zelkin char filename[PATH_MAX];
5990423eceSAlexey Zelkin struct stat st;
6076692b80SAndrey A. Chernov size_t namesize, bufsize;
6190423eceSAlexey Zelkin
62f75bb0aaSAndrey A. Chernov /* 'name' must be already checked. */
63dd7c41a3SYuri Pankov if (strcmp(name, "C") == 0 || strcmp(name, "POSIX") == 0 ||
64dd7c41a3SYuri Pankov strncmp(name, "C.", 2) == 0) {
6576692b80SAndrey A. Chernov *using_locale = 0;
6676692b80SAndrey A. Chernov return (_LDP_CACHE);
6776692b80SAndrey A. Chernov }
6890423eceSAlexey Zelkin
6990423eceSAlexey Zelkin /*
7074f2b975SAlexey Zelkin * If the locale name is the same as our cache, use the cache.
7190423eceSAlexey Zelkin */
723dfdc427SJordan K. Hubbard if (*locale_buf != NULL && strcmp(name, *locale_buf) == 0) {
7390423eceSAlexey Zelkin *using_locale = 1;
7476692b80SAndrey A. Chernov return (_LDP_CACHE);
7590423eceSAlexey Zelkin }
76f43a321bSAlexey Zelkin
7790423eceSAlexey Zelkin /*
7874f2b975SAlexey Zelkin * Slurp the locale file into the cache.
7990423eceSAlexey Zelkin */
8090423eceSAlexey Zelkin namesize = strlen(name) + 1;
8190423eceSAlexey Zelkin
82f75bb0aaSAndrey A. Chernov /* 'PathLocale' must be already set & checked. */
83683fe113SAlexey Zelkin
8490423eceSAlexey Zelkin /* Range checking not needed, 'name' size is limited */
8590423eceSAlexey Zelkin strcpy(filename, _PathLocale);
8690423eceSAlexey Zelkin strcat(filename, "/");
8790423eceSAlexey Zelkin strcat(filename, name);
8890423eceSAlexey Zelkin strcat(filename, "/");
89f43a321bSAlexey Zelkin strcat(filename, category_filename);
9005eb11cbSJilles Tjoelker if ((fd = _open(filename, O_RDONLY | O_CLOEXEC)) < 0)
9176692b80SAndrey A. Chernov return (_LDP_ERROR);
923b5b529fSDaniel Eischen if (_fstat(fd, &st) != 0)
9390423eceSAlexey Zelkin goto bad_locale;
94f75bb0aaSAndrey A. Chernov if (st.st_size <= 0) {
95f75bb0aaSAndrey A. Chernov errno = EFTYPE;
9690423eceSAlexey Zelkin goto bad_locale;
97f75bb0aaSAndrey A. Chernov }
9890423eceSAlexey Zelkin bufsize = namesize + st.st_size;
9976692b80SAndrey A. Chernov if ((lbuf = malloc(bufsize)) == NULL) {
10076692b80SAndrey A. Chernov errno = ENOMEM;
10190423eceSAlexey Zelkin goto bad_locale;
10276692b80SAndrey A. Chernov }
10390423eceSAlexey Zelkin (void)strcpy(lbuf, name);
10490423eceSAlexey Zelkin p = lbuf + namesize;
10590423eceSAlexey Zelkin plim = p + st.st_size;
10690423eceSAlexey Zelkin if (_read(fd, p, (size_t) st.st_size) != st.st_size)
10790423eceSAlexey Zelkin goto bad_lbuf;
10890423eceSAlexey Zelkin /*
10974f2b975SAlexey Zelkin * Parse the locale file into localebuf.
11090423eceSAlexey Zelkin */
111f75bb0aaSAndrey A. Chernov if (plim[-1] != '\n') {
112f75bb0aaSAndrey A. Chernov errno = EFTYPE;
11390423eceSAlexey Zelkin goto bad_lbuf;
114f75bb0aaSAndrey A. Chernov }
11590423eceSAlexey Zelkin num_lines = split_lines(p, plim);
116fc38c1e5SAlexey Zelkin if (num_lines >= locale_buf_size_max)
117fc38c1e5SAlexey Zelkin num_lines = locale_buf_size_max;
118fc38c1e5SAlexey Zelkin else if (num_lines >= locale_buf_size_min)
119fc38c1e5SAlexey Zelkin num_lines = locale_buf_size_min;
120f75bb0aaSAndrey A. Chernov else {
121f75bb0aaSAndrey A. Chernov errno = EFTYPE;
12276692b80SAndrey A. Chernov goto bad_lbuf;
123f75bb0aaSAndrey A. Chernov }
12476692b80SAndrey A. Chernov (void)_close(fd);
12590423eceSAlexey Zelkin /*
126f43a321bSAlexey Zelkin * Record the successful parse in the cache.
12790423eceSAlexey Zelkin */
1283dfdc427SJordan K. Hubbard if (*locale_buf != NULL)
1293dfdc427SJordan K. Hubbard free(*locale_buf);
1303dfdc427SJordan K. Hubbard *locale_buf = lbuf;
1313dfdc427SJordan K. Hubbard for (p = *locale_buf, i = 0; i < num_lines; i++)
13276692b80SAndrey A. Chernov dst_localebuf[i] = (p += strlen(p) + 1);
13376692b80SAndrey A. Chernov for (i = num_lines; i < locale_buf_size_max; i++)
13476692b80SAndrey A. Chernov dst_localebuf[i] = NULL;
13590423eceSAlexey Zelkin *using_locale = 1;
136ecc4c620SAndrey A. Chernov
13776692b80SAndrey A. Chernov return (_LDP_LOADED);
13890423eceSAlexey Zelkin
13990423eceSAlexey Zelkin bad_lbuf:
140ecc4c620SAndrey A. Chernov saverr = errno;
141ecc4c620SAndrey A. Chernov free(lbuf);
142ecc4c620SAndrey A. Chernov errno = saverr;
14390423eceSAlexey Zelkin bad_locale:
144ecc4c620SAndrey A. Chernov saverr = errno;
145ecc4c620SAndrey A. Chernov (void)_close(fd);
146ecc4c620SAndrey A. Chernov errno = saverr;
147ecc4c620SAndrey A. Chernov
14876692b80SAndrey A. Chernov return (_LDP_ERROR);
14990423eceSAlexey Zelkin }
15090423eceSAlexey Zelkin
15190423eceSAlexey Zelkin static int
split_lines(char * p,const char * plim)152ecc4c620SAndrey A. Chernov split_lines(char *p, const char *plim)
153ecc4c620SAndrey A. Chernov {
15490423eceSAlexey Zelkin int i;
15590423eceSAlexey Zelkin
15628aec5a6SAndrey A. Chernov i = 0;
15728aec5a6SAndrey A. Chernov while (p < plim) {
15828aec5a6SAndrey A. Chernov if (*p == '\n') {
15928aec5a6SAndrey A. Chernov *p = '\0';
16028aec5a6SAndrey A. Chernov i++;
16128aec5a6SAndrey A. Chernov }
16228aec5a6SAndrey A. Chernov p++;
16390423eceSAlexey Zelkin }
164ecc4c620SAndrey A. Chernov return (i);
16590423eceSAlexey Zelkin }
16690423eceSAlexey Zelkin
167