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