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 2017 Nexenta Systems, Inc. 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 * 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 * 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 * 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 107 delete_category(FILE *f) 108 { 109 (void) fclose(f); 110 (void) unlink(category_file()); 111 } 112 113 void 114 close_category(FILE *f) 115 { 116 if (fchmod(fileno(f), 0644) < 0 || 117 fclose(f) != 0) { 118 errf(strerror(errno)); 119 delete_category(f); 120 } 121 if (verbose) { 122 (void) fprintf(stdout, _("done.\n")); 123 (void) fflush(stdout); 124 } 125 } 126 127 /* 128 * This function is used when copying the category from another 129 * locale. Note that the copy is actually performed using a hard 130 * link for efficiency. 131 */ 132 void 133 copy_category(char *src) 134 { 135 char srcpath[PATH_MAX]; 136 int rv; 137 138 (void) snprintf(srcpath, sizeof (srcpath), "%s/%s/LCL_DATA", 139 src, category_name()); 140 rv = access(srcpath, R_OK); 141 if ((rv != 0) && (strchr(srcpath, '/') == NULL)) { 142 /* Maybe we should try the system locale */ 143 (void) snprintf(srcpath, sizeof (srcpath), 144 "/usr/lib/locale/%s/%s/LCL_DATA", src, category_name()); 145 rv = access(srcpath, R_OK); 146 } 147 148 if (rv != 0) { 149 errf(_("source locale data unavailable"), src); 150 return; 151 } 152 153 if (verbose > 1) { 154 (void) printf(_("Copying category %s from %s: "), 155 category_name(), src); 156 (void) fflush(stdout); 157 } 158 159 /* make the parent directory */ 160 (void) mkdirp(dirname(category_file()), 0755); 161 162 if (link(srcpath, category_file()) != 0) { 163 errf(_("unable to copy locale data: %s"), strerror(errno)); 164 return; 165 } 166 if (verbose > 1) { 167 (void) printf(_("done.\n")); 168 } 169 } 170 171 int 172 putl_category(const char *s, FILE *f) 173 { 174 if (s && fputs(s, f) == EOF) { 175 errf(strerror(errno)); 176 delete_category(f); 177 return (EOF); 178 } 179 if (fputc('\n', f) == EOF) { 180 errf(strerror(errno)); 181 delete_category(f); 182 return (EOF); 183 } 184 return (0); 185 } 186 187 int 188 wr_category(void *buf, size_t sz, FILE *f) 189 { 190 if (!sz) { 191 return (0); 192 } 193 if (fwrite(buf, sz, 1, f) < 1) { 194 errf(strerror(errno)); 195 return (EOF); 196 } 197 return (0); 198 } 199 200 int yyparse(void); 201 202 static void 203 usage(void) 204 { 205 (void) fprintf(stderr, 206 _("Usage: localedef [options] localename\n")); 207 (void) fprintf(stderr, ("[options] are:\n")); 208 (void) fprintf(stderr, (" -c : ignore warnings\n")); 209 (void) fprintf(stderr, (" -v : verbose output\n")); 210 (void) fprintf(stderr, (" -U : ignore undefined symbols\n")); 211 (void) fprintf(stderr, (" -f charmap : use given charmap file\n")); 212 (void) fprintf(stderr, (" -u encoding : assume encoding\n")); 213 (void) fprintf(stderr, (" -w widths : use screen widths file\n")); 214 (void) fprintf(stderr, (" -i locsrc : source file for locale\n")); 215 exit(4); 216 } 217 218 int 219 main(int argc, char **argv) 220 { 221 int c; 222 char *lfname = NULL; 223 char *cfname = NULL; 224 char *wfname = NULL; 225 DIR *dir; 226 227 init_charmap(); 228 init_collate(); 229 init_ctype(); 230 init_messages(); 231 init_monetary(); 232 init_numeric(); 233 init_time(); 234 235 yydebug = 0; 236 237 (void) setlocale(LC_ALL, ""); 238 (void) textdomain(TEXT_DOMAIN); 239 240 while ((c = getopt(argc, argv, "w:i:cf:u:vU")) != -1) { 241 switch (c) { 242 case 'v': 243 verbose++; 244 break; 245 case 'i': 246 lfname = optarg; 247 break; 248 case 'u': 249 set_wide_encoding(optarg); 250 break; 251 case 'f': 252 cfname = optarg; 253 break; 254 case 'U': 255 undefok++; 256 break; 257 case 'c': 258 warnok++; 259 break; 260 case 'w': 261 wfname = optarg; 262 break; 263 case '?': 264 usage(); 265 break; 266 } 267 } 268 269 if ((argc - 1) != (optind)) { 270 usage(); 271 } 272 locname = argv[argc - 1]; 273 if (verbose) { 274 (void) printf(_("Processing locale %s.\n"), locname); 275 } 276 277 if (cfname) { 278 if (verbose) 279 (void) printf(_("Loading charmap %s.\n"), cfname); 280 reset_scanner(cfname); 281 (void) yyparse(); 282 } 283 284 if (wfname) { 285 if (verbose) 286 (void) printf(_("Loading widths %s.\n"), wfname); 287 reset_scanner(wfname); 288 (void) yyparse(); 289 } 290 291 if (verbose) { 292 (void) printf(_("Loading POSIX portable characters.\n")); 293 } 294 add_charmap_posix(); 295 296 if (lfname) { 297 reset_scanner(lfname); 298 } else { 299 reset_scanner(NULL); 300 } 301 302 /* make the directory for the locale if not already present */ 303 while ((dir = opendir(locname)) == NULL) { 304 if ((errno != ENOENT) || 305 (mkdir(locname, 0755) < 0)) { 306 errf(strerror(errno)); 307 } 308 } 309 (void) closedir(dir); 310 311 (void) mkdirp(dirname(category_file()), 0755); 312 313 (void) yyparse(); 314 if (verbose) { 315 (void) printf(_("All done.\n")); 316 } 317 return (warnings ? 1 : 0); 318 } 319