xref: /illumos-gate/usr/src/cmd/localedef/localedef.c (revision afab0816ecb604f0099a09ad8ee398f0d7b77b1c)
1 /*
2  * This file and its contents are supplied under the terms of the
3  * Common Development and Distribution License ("CDDL"), version 1.0.
4  * You may only use this file in accordance with the terms of version
5  * 1.0 of the CDDL.
6  *
7  * A full copy of the text of the CDDL should have accompanied this
8  * source.  A copy of the CDDL is also available via the Internet at
9  * http://www.illumos.org/license/CDDL.
10  */
11 
12 /*
13  * Copyright 2010 Nexenta Systems, Inc.  All rights reserved.
14  */
15 
16 /*
17  * POSIX localedef.
18  */
19 
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <errno.h>
23 #include <sys/types.h>
24 #include <sys/stat.h>
25 #include <string.h>
26 #include <unistd.h>
27 #include <libgen.h>
28 #include <stddef.h>
29 #include <unistd.h>
30 #include <limits.h>
31 #include <locale.h>
32 #include <dirent.h>
33 #include "localedef.h"
34 #include "parser.tab.h"
35 
36 #ifndef	TEXT_DOMAIN
37 #define	TEXT_DOMAIN	"SYS_TEST"
38 #endif
39 
40 int verbose = 0;
41 int undefok = 0;
42 int warnok = 0;
43 static char *locname = NULL;
44 static char locpath[PATH_MAX];
45 
46 const char *
47 category_name(void)
48 {
49 	switch (get_category()) {
50 	case T_CHARMAP:
51 		return ("CHARMAP");
52 	case T_COLLATE:
53 		return ("LC_COLLATE");
54 	case T_CTYPE:
55 		return ("LC_CTYPE");
56 	case T_MESSAGES:
57 		return ("LC_MESSAGES");
58 	case T_MONETARY:
59 		return ("LC_MONETARY");
60 	case T_NUMERIC:
61 		return ("LC_NUMERIC");
62 	case T_TIME:
63 		return ("LC_TIME");
64 	default:
65 		INTERR;
66 		return (NULL);
67 	}
68 }
69 
70 static char *
71 category_file(void)
72 {
73 	(void) snprintf(locpath, sizeof (locpath), "%s/%s/LCL_DATA",
74 	    locname, category_name());
75 	return (locpath);
76 }
77 
78 FILE *
79 open_category(void)
80 {
81 	FILE *file;
82 
83 	if (verbose) {
84 		(void) printf(_("Writing category %s: "), category_name());
85 		(void) fflush(stdout);
86 	}
87 
88 	/* make the parent directory */
89 	(void) mkdirp(dirname(category_file()), 0755);
90 
91 	/*
92 	 * note that we have to regenerate the file name, as dirname
93 	 * clobbered it.
94 	 */
95 	file = fopen(category_file(), "w");
96 	if (file == NULL) {
97 		errf(strerror(errno));
98 		return (NULL);
99 	}
100 	return (file);
101 }
102 
103 void
104 close_category(FILE *f)
105 {
106 	if (fchmod(fileno(f), 0644) < 0) {
107 		(void) fclose(f);
108 		(void) unlink(category_file());
109 		errf(strerror(errno));
110 	}
111 	if (fclose(f) < 0) {
112 		(void) unlink(category_file());
113 		errf(strerror(errno));
114 	}
115 	if (verbose) {
116 		(void) fprintf(stdout, _("done.\n"));
117 		(void) fflush(stdout);
118 	}
119 }
120 
121 /*
122  * This function is used when copying the category from another
123  * locale.  Note that the copy is actually performed using a hard
124  * link for efficiency.
125  */
126 void
127 copy_category(char *src)
128 {
129 	char	srcpath[PATH_MAX];
130 	int	rv;
131 
132 	(void) snprintf(srcpath, sizeof (srcpath), "%s/%s/LCL_DATA",
133 	    src, category_name());
134 	rv = access(srcpath, R_OK);
135 	if ((rv != 0) && (strchr(srcpath, '/') == NULL)) {
136 		/* Maybe we should try the system locale */
137 		(void) snprintf(srcpath, sizeof (srcpath),
138 		    "/usr/lib/locale/%s/%s/LCL_DATA", src, category_name());
139 		rv = access(srcpath, R_OK);
140 	}
141 
142 	if (rv != 0) {
143 		errf(_("source locale data unavailable"), src);
144 		return;
145 	}
146 
147 	if (verbose > 1) {
148 		(void) printf(_("Copying category %s from %s: "),
149 		    category_name(), src);
150 		(void) fflush(stdout);
151 	}
152 
153 	/* make the parent directory */
154 	(void) mkdirp(dirname(category_file()), 0755);
155 
156 	if (link(srcpath, category_file()) != 0) {
157 		errf(_("unable to copy locale data: %s"), strerror(errno));
158 		return;
159 	}
160 	if (verbose > 1) {
161 		(void) printf(_("done.\n"));
162 	}
163 }
164 
165 int
166 putl_category(const char *s, FILE *f)
167 {
168 	if (s && fputs(s, f) == EOF) {
169 		(void) fclose(f);
170 		(void) unlink(category_file());
171 		errf(strerror(errno));
172 		return (EOF);
173 	}
174 	if (fputc('\n', f) == EOF) {
175 		(void) fclose(f);
176 		(void) unlink(category_file());
177 		errf(strerror(errno));
178 		return (EOF);
179 	}
180 	return (0);
181 }
182 
183 int
184 wr_category(void *buf, size_t sz, FILE *f)
185 {
186 	if (!sz) {
187 		return (0);
188 	}
189 	if (fwrite(buf, sz, 1, f) < 1) {
190 		(void) fclose(f);
191 		(void) unlink(category_file());
192 		errf(strerror(errno));
193 		return (EOF);
194 	}
195 	return (0);
196 }
197 
198 int yyparse(void);
199 
200 static void
201 usage(void)
202 {
203 	(void) fprintf(stderr,
204 	    _("Usage: localedef [-v] [-f charmap] [-i locsrc] [-u encoding] "
205 	    "[-v] [-U] localename\n"));
206 	exit(4);
207 }
208 
209 int
210 main(int argc, char **argv)
211 {
212 	int c;
213 	char *lfname = NULL;
214 	char *cfname = NULL;
215 	DIR *dir;
216 
217 	init_charmap();
218 	init_collate();
219 	init_ctype();
220 	init_messages();
221 	init_monetary();
222 	init_numeric();
223 	init_time();
224 
225 	yydebug = 0;
226 
227 	(void) setlocale(LC_ALL, "");
228 	(void) textdomain(TEXT_DOMAIN);
229 
230 	while ((c = getopt(argc, argv, "i:cf:u:vU")) != -1) {
231 		switch (c) {
232 		case 'v':
233 			verbose++;
234 			break;
235 		case 'i':
236 			lfname = optarg;
237 			break;
238 		case 'u':
239 			set_wide_encoding(optarg);
240 			break;
241 		case 'f':
242 			cfname = optarg;
243 			break;
244 		case 'U':
245 			undefok++;
246 			break;
247 		case 'c':
248 			warnok++;
249 			break;
250 		case '?':
251 			usage();
252 			break;
253 		}
254 	}
255 
256 	if ((argc - 1) != (optind)) {
257 		usage();
258 	}
259 	locname = argv[argc - 1];
260 	if (verbose) {
261 		(void) printf(_("Processing locale %s.\n"), locname);
262 	}
263 
264 	if (cfname) {
265 		if (verbose)
266 			(void) printf(_("Loading charmap %s.\n"), cfname);
267 		reset_scanner(cfname);
268 		(void) yyparse();
269 	}
270 
271 	if (verbose) {
272 		(void) printf(_("Loading POSIX portable characters.\n"));
273 	}
274 	add_charmap_posix();
275 
276 	if (lfname) {
277 		reset_scanner(lfname);
278 	} else {
279 		reset_scanner(NULL);
280 	}
281 
282 	/* make the directory for the locale if not already present */
283 	while ((dir = opendir(locname)) == NULL) {
284 		if ((errno != ENOENT) ||
285 		    (mkdir(locname, 0755) <  0)) {
286 			errf(strerror(errno));
287 		}
288 	}
289 	(void) closedir(dir);
290 
291 	(void) mkdirp(dirname(category_file()), 0755);
292 
293 	(void) yyparse();
294 	if (verbose) {
295 		(void) printf(_("All done.\n"));
296 	}
297 	return (warnings ? 1 : 0);
298 }
299