Path: blob/master/src/java.base/unix/native/libjava/java_props_md.c
67848 views
/*1* Copyright (c) 1998, 2021, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425#if defined(__linux__) || defined(_ALLBSD_SOURCE)26#include <stdio.h>27#include <ctype.h>28#endif29#include <pwd.h>30#include <locale.h>31#ifndef ARCHPROPNAME32#error "The macro ARCHPROPNAME has not been defined"33#endif34#include <sys/utsname.h> /* For os_name and os_version */35#include <langinfo.h> /* For nl_langinfo */36#include <stdlib.h>37#include <string.h>38#include <sys/types.h>39#include <unistd.h>40#include <sys/param.h>41#include <time.h>42#include <errno.h>4344#ifdef MACOSX45#include "java_props_macosx.h"46#endif4748#if defined(_ALLBSD_SOURCE)49#if !defined(P_tmpdir)50#include <paths.h>51#define P_tmpdir _PATH_VARTMP52#endif53#endif5455#include "locale_str.h"56#include "java_props.h"5758#if !defined(_ALLBSD_SOURCE)59#ifdef __linux__60#ifndef CODESET61#define CODESET _NL_CTYPE_CODESET_NAME62#endif63#else64#ifdef ALT_CODESET_KEY65#define CODESET ALT_CODESET_KEY66#endif67#endif68#endif /* !_ALLBSD_SOURCE */6970/* Take an array of string pairs (map of key->value) and a string (key).71* Examine each pair in the map to see if the first string (key) matches the72* string. If so, store the second string of the pair (value) in the value and73* return 1. Otherwise do nothing and return 0. The end of the map is74* indicated by an empty string at the start of a pair (key of "").75*/76static int77mapLookup(char* map[], const char* key, char** value) {78int i;79for (i = 0; strcmp(map[i], ""); i += 2){80if (!strcmp(key, map[i])){81*value = map[i + 1];82return 1;83}84}85return 0;86}8788#ifndef P_tmpdir89#define P_tmpdir "/var/tmp"90#endif9192static int ParseLocale(JNIEnv* env, int cat, char ** std_language, char ** std_script,93char ** std_country, char ** std_variant, char ** std_encoding) {94char *temp = NULL;95char *language = NULL, *country = NULL, *variant = NULL,96*encoding = NULL;97char *p, *encoding_variant, *old_temp, *old_ev;98char *lc;99100/* Query the locale set for the category */101102#ifdef MACOSX103lc = setupMacOSXLocale(cat); // malloc'd memory, need to free104#else105lc = setlocale(cat, NULL);106#endif107108#ifndef __linux__109if (lc == NULL) {110return 0;111}112113temp = malloc(strlen(lc) + 1);114if (temp == NULL) {115#ifdef MACOSX116free(lc); // malloced memory117#endif118JNU_ThrowOutOfMemoryError(env, NULL);119return 0;120}121122if (cat == LC_CTYPE) {123/*124* Workaround for Solaris bug 4201684: Xlib doesn't like @euro125* locales. Since we don't depend on the libc @euro behavior,126* we just remove the qualifier.127* On Linux, the bug doesn't occur; on the other hand, @euro128* is needed there because it's a shortcut that also determines129* the encoding - without it, we wouldn't get ISO-8859-15.130* Therefore, this code section is Solaris-specific.131*/132strcpy(temp, lc);133p = strstr(temp, "@euro");134if (p != NULL) {135*p = '\0';136setlocale(LC_ALL, temp);137}138}139#else140if (lc == NULL || !strcmp(lc, "C") || !strcmp(lc, "POSIX")) {141lc = "en_US";142}143144temp = malloc(strlen(lc) + 1);145if (temp == NULL) {146JNU_ThrowOutOfMemoryError(env, NULL);147return 0;148}149150#endif151152/*153* locale string format in Solaris is154* <language name>_<country name>.<encoding name>@<variant name>155* <country name>, <encoding name>, and <variant name> are optional.156*/157158strcpy(temp, lc);159#ifdef MACOSX160free(lc); // malloced memory161#endif162/* Parse the language, country, encoding, and variant from the163* locale. Any of the elements may be missing, but they must occur164* in the order language_country.encoding@variant, and must be165* preceded by their delimiter (except for language).166*167* If the locale name (without .encoding@variant, if any) matches168* any of the names in the locale_aliases list, map it to the169* corresponding full locale name. Most of the entries in the170* locale_aliases list are locales that include a language name but171* no country name, and this facility is used to map each language172* to a default country if that's possible. It's also used to map173* the Solaris locale aliases to their proper Java locale IDs.174*/175176encoding_variant = malloc(strlen(temp)+1);177if (encoding_variant == NULL) {178free(temp);179JNU_ThrowOutOfMemoryError(env, NULL);180return 0;181}182183if ((p = strchr(temp, '.')) != NULL) {184strcpy(encoding_variant, p); /* Copy the leading '.' */185*p = '\0';186} else if ((p = strchr(temp, '@')) != NULL) {187strcpy(encoding_variant, p); /* Copy the leading '@' */188*p = '\0';189} else {190*encoding_variant = '\0';191}192193if (mapLookup(locale_aliases, temp, &p)) {194old_temp = temp;195temp = realloc(temp, strlen(p)+1);196if (temp == NULL) {197free(old_temp);198free(encoding_variant);199JNU_ThrowOutOfMemoryError(env, NULL);200return 0;201}202strcpy(temp, p);203old_ev = encoding_variant;204encoding_variant = realloc(encoding_variant, strlen(temp)+1);205if (encoding_variant == NULL) {206free(old_ev);207free(temp);208JNU_ThrowOutOfMemoryError(env, NULL);209return 0;210}211// check the "encoding_variant" again, if any.212if ((p = strchr(temp, '.')) != NULL) {213strcpy(encoding_variant, p); /* Copy the leading '.' */214*p = '\0';215} else if ((p = strchr(temp, '@')) != NULL) {216strcpy(encoding_variant, p); /* Copy the leading '@' */217*p = '\0';218}219}220221language = temp;222if ((country = strchr(temp, '_')) != NULL) {223*country++ = '\0';224}225226p = encoding_variant;227if ((encoding = strchr(p, '.')) != NULL) {228p[encoding++ - p] = '\0';229p = encoding;230}231if ((variant = strchr(p, '@')) != NULL) {232p[variant++ - p] = '\0';233}234235/* Normalize the language name */236if (std_language != NULL) {237*std_language = "en";238if (language != NULL && mapLookup(language_names, language, std_language) == 0) {239*std_language = malloc(strlen(language)+1);240strcpy(*std_language, language);241}242}243244/* Normalize the country name */245if (std_country != NULL && country != NULL) {246if (mapLookup(country_names, country, std_country) == 0) {247*std_country = malloc(strlen(country)+1);248strcpy(*std_country, country);249}250}251252/* Normalize the script and variant name. Note that we only use253* variants listed in the mapping array; others are ignored.254*/255if (variant != NULL) {256if (std_script != NULL) {257mapLookup(script_names, variant, std_script);258}259260if (std_variant != NULL) {261mapLookup(variant_names, variant, std_variant);262}263}264265/* Normalize the encoding name. Note that we IGNORE the string266* 'encoding' extracted from the locale name above. Instead, we use the267* more reliable method of calling nl_langinfo(CODESET). This function268* returns an empty string if no encoding is set for the given locale269* (e.g., the C or POSIX locales); we use the default ISO 8859-1270* converter for such locales.271*/272if (std_encoding != NULL) {273/* OK, not so reliable - nl_langinfo() gives wrong answers on274* Euro locales, in particular. */275if (strcmp(p, "ISO8859-15") == 0)276p = "ISO8859-15";277else278p = nl_langinfo(CODESET);279280/* Convert the bare "646" used on Solaris to a proper IANA name */281if (strcmp(p, "646") == 0)282p = "ISO646-US";283284/* return same result nl_langinfo would return for en_UK,285* in order to use optimizations. */286*std_encoding = (*p != '\0') ? p : "ISO8859-1";287288#ifdef __linux__289/*290* Remap the encoding string to a different value for japanese291* locales on linux so that customized converters are used instead292* of the default converter for "EUC-JP". The customized converters293* omit support for the JIS0212 encoding which is not supported by294* the variant of "EUC-JP" encoding used on linux295*/296if (strcmp(p, "EUC-JP") == 0) {297*std_encoding = "EUC-JP-LINUX";298}299#endif300301#ifdef _AIX302if (strcmp(p, "big5") == 0) {303/* On AIX Traditional Chinese Big5 codeset is mapped to IBM-950 */304*std_encoding = "IBM-950";305} else if (strcmp(p, "IBM-943") == 0) {306/*307* On AIX, IBM-943 is mapped to IBM-943C in which symbol 'yen' and308* 'overline' are replaced with 'backslash' and 'tilde' from ASCII309* making first 96 code points same as ASCII.310*/311*std_encoding = "IBM-943C";312}313#endif314315#ifdef MACOSX316/*317* For the case on MacOS X where encoding is set to US-ASCII, but we318* don't have any encoding hints from LANG/LC_ALL/LC_CTYPE, use UTF-8319* instead.320*321* The contents of ASCII files will still be read and displayed322* correctly, but so will files containing UTF-8 characters beyond the323* standard ASCII range.324*325* Specifically, this allows apps launched by double-clicking a .jar326* file to correctly read UTF-8 files using the default encoding (see327* 8011194).328*/329const char* env_lang = getenv("LANG");330const char* env_lc_all = getenv("LC_ALL");331const char* env_lc_ctype = getenv("LC_CTYPE");332333if (strcmp(p,"US-ASCII") == 0 &&334(env_lang == NULL || strlen(env_lang) == 0) &&335(env_lc_all == NULL || strlen(env_lc_all) == 0) &&336(env_lc_ctype == NULL || strlen(env_lc_ctype) == 0)) {337*std_encoding = "UTF-8";338}339#endif340}341342free(temp);343free(encoding_variant);344345return 1;346}347348/* This function gets called very early, before VM_CALLS are setup.349* Do not use any of the VM_CALLS entries!!!350*/351java_props_t *352GetJavaProperties(JNIEnv *env)353{354static java_props_t sprops;355char *v; /* tmp var */356357if (sprops.user_dir) {358return &sprops;359}360361/* tmp dir */362sprops.tmp_dir = P_tmpdir;363#ifdef MACOSX364/* darwin has a per-user temp dir */365static char tmp_path[PATH_MAX];366int pathSize = confstr(_CS_DARWIN_USER_TEMP_DIR, tmp_path, PATH_MAX);367if (pathSize > 0 && pathSize <= PATH_MAX) {368sprops.tmp_dir = tmp_path;369}370#endif /* MACOSX */371372/* patches/service packs installed */373sprops.patch_level = NULL; // leave it undefined374375#ifdef SI_ISALIST376/* supported instruction sets */377{378char list[258];379sysinfo(SI_ISALIST, list, sizeof(list));380sprops.cpu_isalist = strdup(list);381}382#else383sprops.cpu_isalist = NULL;384#endif385386/* endianness of platform */387{388unsigned int endianTest = 0xff000000;389if (((char*)(&endianTest))[0] != 0)390sprops.cpu_endian = "big";391else392sprops.cpu_endian = "little";393}394395/* os properties */396{397#ifdef MACOSX398setOSNameAndVersion(&sprops);399#else400struct utsname name;401uname(&name);402sprops.os_name = strdup(name.sysname);403#ifdef _AIX404{405char *os_version = malloc(strlen(name.version) +406strlen(name.release) + 2);407if (os_version != NULL) {408strcpy(os_version, name.version);409strcat(os_version, ".");410strcat(os_version, name.release);411}412sprops.os_version = os_version;413}414#else415sprops.os_version = strdup(name.release);416#endif /* _AIX */417#endif /* MACOSX */418419sprops.os_arch = ARCHPROPNAME;420}421422/* ABI property (optional) */423#ifdef JDK_ARCH_ABI_PROP_NAME424sprops.sun_arch_abi = JDK_ARCH_ABI_PROP_NAME;425#endif426427/* Determine the language, country, variant, and encoding from the host,428* and store these in the user.language, user.country, user.variant and429* file.encoding system properties. */430setlocale(LC_ALL, "");431if (ParseLocale(env, LC_CTYPE,432&(sprops.format_language),433&(sprops.format_script),434&(sprops.format_country),435&(sprops.format_variant),436&(sprops.encoding))) {437ParseLocale(env, LC_MESSAGES,438&(sprops.display_language),439&(sprops.display_script),440&(sprops.display_country),441&(sprops.display_variant),442NULL);443} else {444sprops.display_language = "en";445sprops.encoding = "ISO8859-1";446}447448/* ParseLocale failed with OOME */449JNU_CHECK_EXCEPTION_RETURN(env, NULL);450451#ifdef MACOSX452sprops.sun_jnu_encoding = "UTF-8";453#else454sprops.sun_jnu_encoding = sprops.encoding;455#endif456if (isatty(STDOUT_FILENO) == 1) {457sprops.sun_stdout_encoding = sprops.encoding;458}459if (isatty(STDERR_FILENO) == 1) {460sprops.sun_stderr_encoding = sprops.encoding;461}462463#ifdef _ALLBSD_SOURCE464#if BYTE_ORDER == _LITTLE_ENDIAN465sprops.unicode_encoding = "UnicodeLittle";466#else467sprops.unicode_encoding = "UnicodeBig";468#endif469#else /* !_ALLBSD_SOURCE */470#ifdef __linux__471#if __BYTE_ORDER == __LITTLE_ENDIAN472sprops.unicode_encoding = "UnicodeLittle";473#else474sprops.unicode_encoding = "UnicodeBig";475#endif476#else477sprops.unicode_encoding = "UnicodeBig";478#endif479#endif /* _ALLBSD_SOURCE */480481/* user properties */482{483struct passwd *pwent = getpwuid(getuid());484sprops.user_name = pwent ? strdup(pwent->pw_name) : "?";485#ifdef MACOSX486setUserHome(&sprops);487#else488sprops.user_home = pwent ? strdup(pwent->pw_dir) : NULL;489#endif490if (sprops.user_home == NULL) {491sprops.user_home = "?";492}493}494495/* User TIMEZONE496* We defer setting up timezone until it's actually necessary.497* Refer to TimeZone.getDefault(). The system property498* is able to be set by the command line interface -Duser.timezone.499*/500tzset(); /* for compatibility */501502/* Current directory */503{504char buf[MAXPATHLEN];505errno = 0;506if (getcwd(buf, sizeof(buf)) == NULL)507JNU_ThrowByName(env, "java/lang/Error",508"Properties init: Could not determine current working directory.");509else510sprops.user_dir = strdup(buf);511}512513sprops.file_separator = "/";514sprops.path_separator = ":";515sprops.line_separator = "\n";516517#ifdef MACOSX518setProxyProperties(&sprops);519#endif520521return &sprops;522}523524jstring525GetStringPlatform(JNIEnv *env, nchar* cstr)526{527return JNU_NewStringPlatform(env, cstr);528}529530531