xref: /illumos-gate/usr/src/cmd/localedef/localedef.c (revision e1508819)
16b5e5868SGarrett D'Amore /*
26b5e5868SGarrett D'Amore  * This file and its contents are supplied under the terms of the
36b5e5868SGarrett D'Amore  * Common Development and Distribution License ("CDDL"), version 1.0.
45aec55ebSGarrett D'Amore  * You may only use this file in accordance with the terms of version
55aec55ebSGarrett D'Amore  * 1.0 of the CDDL.
66b5e5868SGarrett D'Amore  *
76b5e5868SGarrett D'Amore  * A full copy of the text of the CDDL should have accompanied this
86b5e5868SGarrett D'Amore  * source.  A copy of the CDDL is also available via the Internet at
96b5e5868SGarrett D'Amore  * http://www.illumos.org/license/CDDL.
106b5e5868SGarrett D'Amore  */
116b5e5868SGarrett D'Amore 
126b5e5868SGarrett D'Amore /*
13*e1508819SYuri Pankov  * Copyright 2017 Nexenta Systems, Inc.
142da1cd3aSGarrett D'Amore  * Copyright 2013 DEY Storage Systems, Inc.
156b5e5868SGarrett D'Amore  */
166b5e5868SGarrett D'Amore 
176b5e5868SGarrett D'Amore /*
186b5e5868SGarrett D'Amore  * POSIX localedef.
196b5e5868SGarrett D'Amore  */
206b5e5868SGarrett D'Amore 
216b5e5868SGarrett D'Amore #include <stdio.h>
226b5e5868SGarrett D'Amore #include <stdlib.h>
236b5e5868SGarrett D'Amore #include <errno.h>
246b5e5868SGarrett D'Amore #include <sys/types.h>
256b5e5868SGarrett D'Amore #include <sys/stat.h>
266b5e5868SGarrett D'Amore #include <string.h>
276b5e5868SGarrett D'Amore #include <unistd.h>
286b5e5868SGarrett D'Amore #include <libgen.h>
296b5e5868SGarrett D'Amore #include <stddef.h>
306b5e5868SGarrett D'Amore #include <unistd.h>
316b5e5868SGarrett D'Amore #include <limits.h>
326b5e5868SGarrett D'Amore #include <locale.h>
336b5e5868SGarrett D'Amore #include <dirent.h>
346b5e5868SGarrett D'Amore #include "localedef.h"
356b5e5868SGarrett D'Amore #include "parser.tab.h"
366b5e5868SGarrett D'Amore 
376b5e5868SGarrett D'Amore #ifndef	TEXT_DOMAIN
386b5e5868SGarrett D'Amore #define	TEXT_DOMAIN	"SYS_TEST"
396b5e5868SGarrett D'Amore #endif
406b5e5868SGarrett D'Amore 
416b5e5868SGarrett D'Amore int verbose = 0;
426b5e5868SGarrett D'Amore int undefok = 0;
436b5e5868SGarrett D'Amore int warnok = 0;
446b5e5868SGarrett D'Amore static char *locname = NULL;
456b5e5868SGarrett D'Amore static char locpath[PATH_MAX];
466b5e5868SGarrett D'Amore 
476b5e5868SGarrett D'Amore const char *
category_name(void)486b5e5868SGarrett D'Amore category_name(void)
496b5e5868SGarrett D'Amore {
506b5e5868SGarrett D'Amore 	switch (get_category()) {
516b5e5868SGarrett D'Amore 	case T_CHARMAP:
526b5e5868SGarrett D'Amore 		return ("CHARMAP");
532da1cd3aSGarrett D'Amore 	case T_WIDTH:
542da1cd3aSGarrett D'Amore 		return ("WIDTH");
556b5e5868SGarrett D'Amore 	case T_COLLATE:
566b5e5868SGarrett D'Amore 		return ("LC_COLLATE");
576b5e5868SGarrett D'Amore 	case T_CTYPE:
586b5e5868SGarrett D'Amore 		return ("LC_CTYPE");
596b5e5868SGarrett D'Amore 	case T_MESSAGES:
606b5e5868SGarrett D'Amore 		return ("LC_MESSAGES");
616b5e5868SGarrett D'Amore 	case T_MONETARY:
626b5e5868SGarrett D'Amore 		return ("LC_MONETARY");
636b5e5868SGarrett D'Amore 	case T_NUMERIC:
646b5e5868SGarrett D'Amore 		return ("LC_NUMERIC");
656b5e5868SGarrett D'Amore 	case T_TIME:
666b5e5868SGarrett D'Amore 		return ("LC_TIME");
676b5e5868SGarrett D'Amore 	default:
686b5e5868SGarrett D'Amore 		INTERR;
696b5e5868SGarrett D'Amore 		return (NULL);
706b5e5868SGarrett D'Amore 	}
716b5e5868SGarrett D'Amore }
726b5e5868SGarrett D'Amore 
736b5e5868SGarrett D'Amore static char *
category_file(void)746b5e5868SGarrett D'Amore category_file(void)
756b5e5868SGarrett D'Amore {
766b5e5868SGarrett D'Amore 	(void) snprintf(locpath, sizeof (locpath), "%s/%s/LCL_DATA",
776b5e5868SGarrett D'Amore 	    locname, category_name());
786b5e5868SGarrett D'Amore 	return (locpath);
796b5e5868SGarrett D'Amore }
806b5e5868SGarrett D'Amore 
816b5e5868SGarrett D'Amore FILE *
open_category(void)826b5e5868SGarrett D'Amore open_category(void)
836b5e5868SGarrett D'Amore {
846b5e5868SGarrett D'Amore 	FILE *file;
856b5e5868SGarrett D'Amore 
866b5e5868SGarrett D'Amore 	if (verbose) {
876b5e5868SGarrett D'Amore 		(void) printf(_("Writing category %s: "), category_name());
886b5e5868SGarrett D'Amore 		(void) fflush(stdout);
896b5e5868SGarrett D'Amore 	}
906b5e5868SGarrett D'Amore 
916b5e5868SGarrett D'Amore 	/* make the parent directory */
926b5e5868SGarrett D'Amore 	(void) mkdirp(dirname(category_file()), 0755);
936b5e5868SGarrett D'Amore 
946b5e5868SGarrett D'Amore 	/*
956b5e5868SGarrett D'Amore 	 * note that we have to regenerate the file name, as dirname
966b5e5868SGarrett D'Amore 	 * clobbered it.
976b5e5868SGarrett D'Amore 	 */
986b5e5868SGarrett D'Amore 	file = fopen(category_file(), "w");
996b5e5868SGarrett D'Amore 	if (file == NULL) {
1006b5e5868SGarrett D'Amore 		errf(strerror(errno));
1016b5e5868SGarrett D'Amore 		return (NULL);
1026b5e5868SGarrett D'Amore 	}
1036b5e5868SGarrett D'Amore 	return (file);
1046b5e5868SGarrett D'Amore }
1056b5e5868SGarrett D'Amore 
106*e1508819SYuri Pankov void
delete_category(FILE * f)107*e1508819SYuri Pankov delete_category(FILE *f)
108*e1508819SYuri Pankov {
109*e1508819SYuri Pankov 	(void) fclose(f);
110*e1508819SYuri Pankov 	(void) unlink(category_file());
111*e1508819SYuri Pankov }
112*e1508819SYuri Pankov 
1136b5e5868SGarrett D'Amore void
close_category(FILE * f)1146b5e5868SGarrett D'Amore close_category(FILE *f)
1156b5e5868SGarrett D'Amore {
116*e1508819SYuri Pankov 	if (fchmod(fileno(f), 0644) < 0 ||
117*e1508819SYuri Pankov 	    fclose(f) != 0) {
1186b5e5868SGarrett D'Amore 		errf(strerror(errno));
119*e1508819SYuri Pankov 		delete_category(f);
1206b5e5868SGarrett D'Amore 	}
1216b5e5868SGarrett D'Amore 	if (verbose) {
1226b5e5868SGarrett D'Amore 		(void) fprintf(stdout, _("done.\n"));
1236b5e5868SGarrett D'Amore 		(void) fflush(stdout);
1246b5e5868SGarrett D'Amore 	}
1256b5e5868SGarrett D'Amore }
1266b5e5868SGarrett D'Amore 
1276b5e5868SGarrett D'Amore /*
1286b5e5868SGarrett D'Amore  * This function is used when copying the category from another
1296b5e5868SGarrett D'Amore  * locale.  Note that the copy is actually performed using a hard
1306b5e5868SGarrett D'Amore  * link for efficiency.
1316b5e5868SGarrett D'Amore  */
1326b5e5868SGarrett D'Amore void
copy_category(char * src)1336b5e5868SGarrett D'Amore copy_category(char *src)
1346b5e5868SGarrett D'Amore {
1356b5e5868SGarrett D'Amore 	char	srcpath[PATH_MAX];
1366b5e5868SGarrett D'Amore 	int	rv;
1376b5e5868SGarrett D'Amore 
1386b5e5868SGarrett D'Amore 	(void) snprintf(srcpath, sizeof (srcpath), "%s/%s/LCL_DATA",
1396b5e5868SGarrett D'Amore 	    src, category_name());
1406b5e5868SGarrett D'Amore 	rv = access(srcpath, R_OK);
1416b5e5868SGarrett D'Amore 	if ((rv != 0) && (strchr(srcpath, '/') == NULL)) {
1426b5e5868SGarrett D'Amore 		/* Maybe we should try the system locale */
1436b5e5868SGarrett D'Amore 		(void) snprintf(srcpath, sizeof (srcpath),
1446b5e5868SGarrett D'Amore 		    "/usr/lib/locale/%s/%s/LCL_DATA", src, category_name());
1456b5e5868SGarrett D'Amore 		rv = access(srcpath, R_OK);
1466b5e5868SGarrett D'Amore 	}
1476b5e5868SGarrett D'Amore 
1486b5e5868SGarrett D'Amore 	if (rv != 0) {
1496b5e5868SGarrett D'Amore 		errf(_("source locale data unavailable"), src);
1506b5e5868SGarrett D'Amore 		return;
1516b5e5868SGarrett D'Amore 	}
1526b5e5868SGarrett D'Amore 
1536b5e5868SGarrett D'Amore 	if (verbose > 1) {
1546b5e5868SGarrett D'Amore 		(void) printf(_("Copying category %s from %s: "),
1556b5e5868SGarrett D'Amore 		    category_name(), src);
1566b5e5868SGarrett D'Amore 		(void) fflush(stdout);
1576b5e5868SGarrett D'Amore 	}
1586b5e5868SGarrett D'Amore 
1596b5e5868SGarrett D'Amore 	/* make the parent directory */
1606b5e5868SGarrett D'Amore 	(void) mkdirp(dirname(category_file()), 0755);
1616b5e5868SGarrett D'Amore 
1626b5e5868SGarrett D'Amore 	if (link(srcpath, category_file()) != 0) {
1636b5e5868SGarrett D'Amore 		errf(_("unable to copy locale data: %s"), strerror(errno));
1646b5e5868SGarrett D'Amore 		return;
1656b5e5868SGarrett D'Amore 	}
1666b5e5868SGarrett D'Amore 	if (verbose > 1) {
1676b5e5868SGarrett D'Amore 		(void) printf(_("done.\n"));
1686b5e5868SGarrett D'Amore 	}
1696b5e5868SGarrett D'Amore }
1706b5e5868SGarrett D'Amore 
1716b5e5868SGarrett D'Amore int
putl_category(const char * s,FILE * f)1726b5e5868SGarrett D'Amore putl_category(const char *s, FILE *f)
1736b5e5868SGarrett D'Amore {
1746b5e5868SGarrett D'Amore 	if (s && fputs(s, f) == EOF) {
1756b5e5868SGarrett D'Amore 		errf(strerror(errno));
176*e1508819SYuri Pankov 		delete_category(f);
1776b5e5868SGarrett D'Amore 		return (EOF);
1786b5e5868SGarrett D'Amore 	}
1796b5e5868SGarrett D'Amore 	if (fputc('\n', f) == EOF) {
1806b5e5868SGarrett D'Amore 		errf(strerror(errno));
181*e1508819SYuri Pankov 		delete_category(f);
1826b5e5868SGarrett D'Amore 		return (EOF);
1836b5e5868SGarrett D'Amore 	}
1846b5e5868SGarrett D'Amore 	return (0);
1856b5e5868SGarrett D'Amore }
1866b5e5868SGarrett D'Amore 
1876b5e5868SGarrett D'Amore int
wr_category(void * buf,size_t sz,FILE * f)1886b5e5868SGarrett D'Amore wr_category(void *buf, size_t sz, FILE *f)
1896b5e5868SGarrett D'Amore {
1906b5e5868SGarrett D'Amore 	if (!sz) {
1916b5e5868SGarrett D'Amore 		return (0);
1926b5e5868SGarrett D'Amore 	}
1936b5e5868SGarrett D'Amore 	if (fwrite(buf, sz, 1, f) < 1) {
1946b5e5868SGarrett D'Amore 		errf(strerror(errno));
1956b5e5868SGarrett D'Amore 		return (EOF);
1966b5e5868SGarrett D'Amore 	}
1976b5e5868SGarrett D'Amore 	return (0);
1986b5e5868SGarrett D'Amore }
1996b5e5868SGarrett D'Amore 
2006b5e5868SGarrett D'Amore int yyparse(void);
2016b5e5868SGarrett D'Amore 
2026b5e5868SGarrett D'Amore static void
usage(void)2036b5e5868SGarrett D'Amore usage(void)
2046b5e5868SGarrett D'Amore {
2056b5e5868SGarrett D'Amore 	(void) fprintf(stderr,
2062da1cd3aSGarrett D'Amore 	    _("Usage: localedef [options] localename\n"));
2072da1cd3aSGarrett D'Amore 	(void) fprintf(stderr, ("[options] are:\n"));
2082da1cd3aSGarrett D'Amore 	(void) fprintf(stderr, ("  -c          : ignore warnings\n"));
2092da1cd3aSGarrett D'Amore 	(void) fprintf(stderr, ("  -v          : verbose output\n"));
2102da1cd3aSGarrett D'Amore 	(void) fprintf(stderr, ("  -U          : ignore undefined symbols\n"));
2112da1cd3aSGarrett D'Amore 	(void) fprintf(stderr, ("  -f charmap  : use given charmap file\n"));
2122da1cd3aSGarrett D'Amore 	(void) fprintf(stderr, ("  -u encoding : assume encoding\n"));
2132da1cd3aSGarrett D'Amore 	(void) fprintf(stderr, ("  -w widths   : use screen widths file\n"));
2142da1cd3aSGarrett D'Amore 	(void) fprintf(stderr, ("  -i locsrc   : source file for locale\n"));
2156b5e5868SGarrett D'Amore 	exit(4);
2166b5e5868SGarrett D'Amore }
2176b5e5868SGarrett D'Amore 
2186b5e5868SGarrett D'Amore int
main(int argc,char ** argv)2196b5e5868SGarrett D'Amore main(int argc, char **argv)
2206b5e5868SGarrett D'Amore {
2216b5e5868SGarrett D'Amore 	int c;
2226b5e5868SGarrett D'Amore 	char *lfname = NULL;
2236b5e5868SGarrett D'Amore 	char *cfname = NULL;
2242da1cd3aSGarrett D'Amore 	char *wfname = NULL;
2256b5e5868SGarrett D'Amore 	DIR *dir;
2266b5e5868SGarrett D'Amore 
2276b5e5868SGarrett D'Amore 	init_charmap();
2286b5e5868SGarrett D'Amore 	init_collate();
2296b5e5868SGarrett D'Amore 	init_ctype();
2306b5e5868SGarrett D'Amore 	init_messages();
2316b5e5868SGarrett D'Amore 	init_monetary();
2326b5e5868SGarrett D'Amore 	init_numeric();
2336b5e5868SGarrett D'Amore 	init_time();
2346b5e5868SGarrett D'Amore 
2356b5e5868SGarrett D'Amore 	yydebug = 0;
2366b5e5868SGarrett D'Amore 
2376b5e5868SGarrett D'Amore 	(void) setlocale(LC_ALL, "");
2386b5e5868SGarrett D'Amore 	(void) textdomain(TEXT_DOMAIN);
2396b5e5868SGarrett D'Amore 
2402da1cd3aSGarrett D'Amore 	while ((c = getopt(argc, argv, "w:i:cf:u:vU")) != -1) {
2416b5e5868SGarrett D'Amore 		switch (c) {
2426b5e5868SGarrett D'Amore 		case 'v':
2436b5e5868SGarrett D'Amore 			verbose++;
2446b5e5868SGarrett D'Amore 			break;
2456b5e5868SGarrett D'Amore 		case 'i':
2466b5e5868SGarrett D'Amore 			lfname = optarg;
2476b5e5868SGarrett D'Amore 			break;
2486b5e5868SGarrett D'Amore 		case 'u':
2496b5e5868SGarrett D'Amore 			set_wide_encoding(optarg);
2506b5e5868SGarrett D'Amore 			break;
2516b5e5868SGarrett D'Amore 		case 'f':
2526b5e5868SGarrett D'Amore 			cfname = optarg;
2536b5e5868SGarrett D'Amore 			break;
2546b5e5868SGarrett D'Amore 		case 'U':
2556b5e5868SGarrett D'Amore 			undefok++;
2566b5e5868SGarrett D'Amore 			break;
2576b5e5868SGarrett D'Amore 		case 'c':
2586b5e5868SGarrett D'Amore 			warnok++;
2596b5e5868SGarrett D'Amore 			break;
2602da1cd3aSGarrett D'Amore 		case 'w':
2612da1cd3aSGarrett D'Amore 			wfname = optarg;
2622da1cd3aSGarrett D'Amore 			break;
2636b5e5868SGarrett D'Amore 		case '?':
2646b5e5868SGarrett D'Amore 			usage();
2656b5e5868SGarrett D'Amore 			break;
2666b5e5868SGarrett D'Amore 		}
2676b5e5868SGarrett D'Amore 	}
2686b5e5868SGarrett D'Amore 
2696b5e5868SGarrett D'Amore 	if ((argc - 1) != (optind)) {
2706b5e5868SGarrett D'Amore 		usage();
2716b5e5868SGarrett D'Amore 	}
2726b5e5868SGarrett D'Amore 	locname = argv[argc - 1];
2736b5e5868SGarrett D'Amore 	if (verbose) {
2746b5e5868SGarrett D'Amore 		(void) printf(_("Processing locale %s.\n"), locname);
2756b5e5868SGarrett D'Amore 	}
2766b5e5868SGarrett D'Amore 
2776b5e5868SGarrett D'Amore 	if (cfname) {
2786b5e5868SGarrett D'Amore 		if (verbose)
2796b5e5868SGarrett D'Amore 			(void) printf(_("Loading charmap %s.\n"), cfname);
2806b5e5868SGarrett D'Amore 		reset_scanner(cfname);
2816b5e5868SGarrett D'Amore 		(void) yyparse();
2826b5e5868SGarrett D'Amore 	}
2836b5e5868SGarrett D'Amore 
2842da1cd3aSGarrett D'Amore 	if (wfname) {
2852da1cd3aSGarrett D'Amore 		if (verbose)
2862da1cd3aSGarrett D'Amore 			(void) printf(_("Loading widths %s.\n"), wfname);
2872da1cd3aSGarrett D'Amore 		reset_scanner(wfname);
2882da1cd3aSGarrett D'Amore 		(void) yyparse();
2892da1cd3aSGarrett D'Amore 	}
2902da1cd3aSGarrett D'Amore 
2916b5e5868SGarrett D'Amore 	if (verbose) {
2926b5e5868SGarrett D'Amore 		(void) printf(_("Loading POSIX portable characters.\n"));
2936b5e5868SGarrett D'Amore 	}
2946b5e5868SGarrett D'Amore 	add_charmap_posix();
2956b5e5868SGarrett D'Amore 
2966b5e5868SGarrett D'Amore 	if (lfname) {
2976b5e5868SGarrett D'Amore 		reset_scanner(lfname);
2986b5e5868SGarrett D'Amore 	} else {
2996b5e5868SGarrett D'Amore 		reset_scanner(NULL);
3006b5e5868SGarrett D'Amore 	}
3016b5e5868SGarrett D'Amore 
3026b5e5868SGarrett D'Amore 	/* make the directory for the locale if not already present */
3036b5e5868SGarrett D'Amore 	while ((dir = opendir(locname)) == NULL) {
3046b5e5868SGarrett D'Amore 		if ((errno != ENOENT) ||
3056b5e5868SGarrett D'Amore 		    (mkdir(locname, 0755) <  0)) {
3066b5e5868SGarrett D'Amore 			errf(strerror(errno));
3076b5e5868SGarrett D'Amore 		}
3086b5e5868SGarrett D'Amore 	}
3096b5e5868SGarrett D'Amore 	(void) closedir(dir);
3106b5e5868SGarrett D'Amore 
3116b5e5868SGarrett D'Amore 	(void) mkdirp(dirname(category_file()), 0755);
3126b5e5868SGarrett D'Amore 
3136b5e5868SGarrett D'Amore 	(void) yyparse();
3146b5e5868SGarrett D'Amore 	if (verbose) {
3156b5e5868SGarrett D'Amore 		(void) printf(_("All done.\n"));
3166b5e5868SGarrett D'Amore 	}
3176b5e5868SGarrett D'Amore 	return (warnings ? 1 : 0);
3186b5e5868SGarrett D'Amore }
319