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