Path: blob/master/src/java.base/unix/native/libjava/java_props_md.c
41119 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#ifdef __ANDROID__49// From https://android.googlesource.com/platform/bionic/+/master/libc/bionic/langinfo.cpp50/*51* Copyright (C) 2016 The Android Open Source Project52* All rights reserved.53*54* Redistribution and use in source and binary forms, with or without55* modification, are permitted provided that the following conditions56* are met:57* * Redistributions of source code must retain the above copyright58* notice, this list of conditions and the following disclaimer.59* * Redistributions in binary form must reproduce the above copyright60* notice, this list of conditions and the following disclaimer in61* the documentation and/or other materials provided with the62* distribution.63*64* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS65* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT66* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS67* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE68* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,69* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,70* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS71* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED72* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,73* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT74* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF75* SUCH DAMAGE.76*/7778char* nl_langinfo(nl_item item) {79const char* result = "";80switch (item) {81case CODESET: result = (MB_CUR_MAX == 1) ? "ASCII" : "UTF-8"; break;82case D_T_FMT: result = "%F %T %z"; break;83case D_FMT: result = "%F"; break;84case T_FMT: result = "%T"; break;85case T_FMT_AMPM: result = "%I:%M:%S %p"; break;86case AM_STR: result = "AM"; break;87case PM_STR: result = "PM"; break;88case DAY_1: result = "Sunday"; break;89case DAY_2: result = "Monday"; break;90case DAY_3: result = "Tuesday"; break;91case DAY_4: result = "Wednesday"; break;92case DAY_5: result = "Thursday"; break;93case DAY_6: result = "Friday"; break;94case DAY_7: result = "Saturday"; break;95case ABDAY_1: result = "Sun"; break;96case ABDAY_2: result = "Mon"; break;97case ABDAY_3: result = "Tue"; break;98case ABDAY_4: result = "Wed"; break;99case ABDAY_5: result = "Thu"; break;100case ABDAY_6: result = "Fri"; break;101case ABDAY_7: result = "Sat"; break;102case MON_1: result = "January"; break;103case MON_2: result = "February"; break;104case MON_3: result = "March"; break;105case MON_4: result = "April"; break;106case MON_5: result = "May"; break;107case MON_6: result = "June"; break;108case MON_7: result = "July"; break;109case MON_8: result = "August"; break;110case MON_9: result = "September"; break;111case MON_10: result = "October"; break;112case MON_11: result = "November"; break;113case MON_12: result = "December"; break;114case ABMON_1: result = "Jan"; break;115case ABMON_2: result = "Feb"; break;116case ABMON_3: result = "Mar"; break;117case ABMON_4: result = "Apr"; break;118case ABMON_5: result = "May"; break;119case ABMON_6: result = "Jun"; break;120case ABMON_7: result = "Jul"; break;121case ABMON_8: result = "Aug"; break;122case ABMON_9: result = "Sep"; break;123case ABMON_10: result = "Oct"; break;124case ABMON_11: result = "Nov"; break;125case ABMON_12: result = "Dec"; break;126case ERA: result = ""; break;127case ERA_D_FMT: result = ""; break;128case ERA_D_T_FMT: result = ""; break;129case ERA_T_FMT: result = ""; break;130case ALT_DIGITS: result = ""; break;131case RADIXCHAR: result = "."; break;132case THOUSEP: result = ""; break;133case YESEXPR: result = "^[yY]"; break;134case NOEXPR: result = "^[nN]"; break;135case CRNCYSTR: result = ""; break;136default: break;137}138return (char*) result;139}140#endif141142#if defined(_ALLBSD_SOURCE)143#if !defined(P_tmpdir)144#include <paths.h>145#define P_tmpdir _PATH_VARTMP146#endif147#endif148149#include "locale_str.h"150#include "java_props.h"151152#if !defined(_ALLBSD_SOURCE)153#ifdef __linux__154#ifndef CODESET155#define CODESET _NL_CTYPE_CODESET_NAME156#endif157#else158#ifdef ALT_CODESET_KEY159#define CODESET ALT_CODESET_KEY160#endif161#endif162#endif /* !_ALLBSD_SOURCE */163164/* Take an array of string pairs (map of key->value) and a string (key).165* Examine each pair in the map to see if the first string (key) matches the166* string. If so, store the second string of the pair (value) in the value and167* return 1. Otherwise do nothing and return 0. The end of the map is168* indicated by an empty string at the start of a pair (key of "").169*/170static int171mapLookup(char* map[], const char* key, char** value) {172int i;173for (i = 0; strcmp(map[i], ""); i += 2){174if (!strcmp(key, map[i])){175*value = map[i + 1];176return 1;177}178}179return 0;180}181182#ifndef P_tmpdir183#define P_tmpdir "/var/tmp"184#endif185186static int ParseLocale(JNIEnv* env, int cat, char ** std_language, char ** std_script,187char ** std_country, char ** std_variant, char ** std_encoding) {188char *temp = NULL;189char *language = NULL, *country = NULL, *variant = NULL,190*encoding = NULL;191char *p, *encoding_variant, *old_temp, *old_ev;192char *lc;193194/* Query the locale set for the category */195196#ifdef MACOSX197lc = setupMacOSXLocale(cat); // malloc'd memory, need to free198#else199lc = setlocale(cat, NULL);200#endif201202#ifndef __linux__203if (lc == NULL) {204return 0;205}206207temp = malloc(strlen(lc) + 1);208if (temp == NULL) {209#ifdef MACOSX210free(lc); // malloced memory211#endif212JNU_ThrowOutOfMemoryError(env, NULL);213return 0;214}215216if (cat == LC_CTYPE) {217/*218* Workaround for Solaris bug 4201684: Xlib doesn't like @euro219* locales. Since we don't depend on the libc @euro behavior,220* we just remove the qualifier.221* On Linux, the bug doesn't occur; on the other hand, @euro222* is needed there because it's a shortcut that also determines223* the encoding - without it, we wouldn't get ISO-8859-15.224* Therefore, this code section is Solaris-specific.225*/226strcpy(temp, lc);227p = strstr(temp, "@euro");228if (p != NULL) {229*p = '\0';230setlocale(LC_ALL, temp);231}232}233#else234if (lc == NULL || !strcmp(lc, "C") || !strcmp(lc, "POSIX")) {235lc = "en_US";236}237238temp = malloc(strlen(lc) + 1);239if (temp == NULL) {240JNU_ThrowOutOfMemoryError(env, NULL);241return 0;242}243244#endif245246/*247* locale string format in Solaris is248* <language name>_<country name>.<encoding name>@<variant name>249* <country name>, <encoding name>, and <variant name> are optional.250*/251252strcpy(temp, lc);253#ifdef MACOSX254free(lc); // malloced memory255#endif256/* Parse the language, country, encoding, and variant from the257* locale. Any of the elements may be missing, but they must occur258* in the order language_country.encoding@variant, and must be259* preceded by their delimiter (except for language).260*261* If the locale name (without .encoding@variant, if any) matches262* any of the names in the locale_aliases list, map it to the263* corresponding full locale name. Most of the entries in the264* locale_aliases list are locales that include a language name but265* no country name, and this facility is used to map each language266* to a default country if that's possible. It's also used to map267* the Solaris locale aliases to their proper Java locale IDs.268*/269270encoding_variant = malloc(strlen(temp)+1);271if (encoding_variant == NULL) {272free(temp);273JNU_ThrowOutOfMemoryError(env, NULL);274return 0;275}276277if ((p = strchr(temp, '.')) != NULL) {278strcpy(encoding_variant, p); /* Copy the leading '.' */279*p = '\0';280} else if ((p = strchr(temp, '@')) != NULL) {281strcpy(encoding_variant, p); /* Copy the leading '@' */282*p = '\0';283} else {284*encoding_variant = '\0';285}286287if (mapLookup(locale_aliases, temp, &p)) {288old_temp = temp;289temp = realloc(temp, strlen(p)+1);290if (temp == NULL) {291free(old_temp);292free(encoding_variant);293JNU_ThrowOutOfMemoryError(env, NULL);294return 0;295}296strcpy(temp, p);297old_ev = encoding_variant;298encoding_variant = realloc(encoding_variant, strlen(temp)+1);299if (encoding_variant == NULL) {300free(old_ev);301free(temp);302JNU_ThrowOutOfMemoryError(env, NULL);303return 0;304}305// check the "encoding_variant" again, if any.306if ((p = strchr(temp, '.')) != NULL) {307strcpy(encoding_variant, p); /* Copy the leading '.' */308*p = '\0';309} else if ((p = strchr(temp, '@')) != NULL) {310strcpy(encoding_variant, p); /* Copy the leading '@' */311*p = '\0';312}313}314315language = temp;316if ((country = strchr(temp, '_')) != NULL) {317*country++ = '\0';318}319320p = encoding_variant;321if ((encoding = strchr(p, '.')) != NULL) {322p[encoding++ - p] = '\0';323p = encoding;324}325if ((variant = strchr(p, '@')) != NULL) {326p[variant++ - p] = '\0';327}328329/* Normalize the language name */330if (std_language != NULL) {331*std_language = "en";332if (language != NULL && mapLookup(language_names, language, std_language) == 0) {333*std_language = malloc(strlen(language)+1);334strcpy(*std_language, language);335}336}337338/* Normalize the country name */339if (std_country != NULL && country != NULL) {340if (mapLookup(country_names, country, std_country) == 0) {341*std_country = malloc(strlen(country)+1);342strcpy(*std_country, country);343}344}345346/* Normalize the script and variant name. Note that we only use347* variants listed in the mapping array; others are ignored.348*/349if (variant != NULL) {350if (std_script != NULL) {351mapLookup(script_names, variant, std_script);352}353354if (std_variant != NULL) {355mapLookup(variant_names, variant, std_variant);356}357}358359/* Normalize the encoding name. Note that we IGNORE the string360* 'encoding' extracted from the locale name above. Instead, we use the361* more reliable method of calling nl_langinfo(CODESET). This function362* returns an empty string if no encoding is set for the given locale363* (e.g., the C or POSIX locales); we use the default ISO 8859-1364* converter for such locales.365*/366if (std_encoding != NULL) {367/* OK, not so reliable - nl_langinfo() gives wrong answers on368* Euro locales, in particular. */369if (strcmp(p, "ISO8859-15") == 0)370p = "ISO8859-15";371else372p = nl_langinfo(CODESET);373374/* Convert the bare "646" used on Solaris to a proper IANA name */375if (strcmp(p, "646") == 0)376p = "ISO646-US";377378/* return same result nl_langinfo would return for en_UK,379* in order to use optimizations. */380*std_encoding = (*p != '\0') ? p : "ISO8859-1";381382#ifdef __linux__383/*384* Remap the encoding string to a different value for japanese385* locales on linux so that customized converters are used instead386* of the default converter for "EUC-JP". The customized converters387* omit support for the JIS0212 encoding which is not supported by388* the variant of "EUC-JP" encoding used on linux389*/390if (strcmp(p, "EUC-JP") == 0) {391*std_encoding = "EUC-JP-LINUX";392}393#endif394395#ifdef _AIX396if (strcmp(p, "big5") == 0) {397/* On AIX Traditional Chinese Big5 codeset is mapped to IBM-950 */398*std_encoding = "IBM-950";399} else if (strcmp(p, "IBM-943") == 0) {400/*401* On AIX, IBM-943 is mapped to IBM-943C in which symbol 'yen' and402* 'overline' are replaced with 'backslash' and 'tilde' from ASCII403* making first 96 code points same as ASCII.404*/405*std_encoding = "IBM-943C";406}407#endif408409#ifdef MACOSX410/*411* For the case on MacOS X where encoding is set to US-ASCII, but we412* don't have any encoding hints from LANG/LC_ALL/LC_CTYPE, use UTF-8413* instead.414*415* The contents of ASCII files will still be read and displayed416* correctly, but so will files containing UTF-8 characters beyond the417* standard ASCII range.418*419* Specifically, this allows apps launched by double-clicking a .jar420* file to correctly read UTF-8 files using the default encoding (see421* 8011194).422*/423const char* env_lang = getenv("LANG");424const char* env_lc_all = getenv("LC_ALL");425const char* env_lc_ctype = getenv("LC_CTYPE");426427if (strcmp(p,"US-ASCII") == 0 &&428(env_lang == NULL || strlen(env_lang) == 0) &&429(env_lc_all == NULL || strlen(env_lc_all) == 0) &&430(env_lc_ctype == NULL || strlen(env_lc_ctype) == 0)) {431*std_encoding = "UTF-8";432}433#endif434}435436free(temp);437free(encoding_variant);438439return 1;440}441442/* This function gets called very early, before VM_CALLS are setup.443* Do not use any of the VM_CALLS entries!!!444*/445java_props_t *446GetJavaProperties(JNIEnv *env)447{448static java_props_t sprops;449char *v; /* tmp var */450451if (sprops.user_dir) {452return &sprops;453}454455/* tmp dir */456sprops.tmp_dir = P_tmpdir;457#ifdef MACOSX458/* darwin has a per-user temp dir */459static char tmp_path[PATH_MAX];460int pathSize = confstr(_CS_DARWIN_USER_TEMP_DIR, tmp_path, PATH_MAX);461if (pathSize > 0 && pathSize <= PATH_MAX) {462sprops.tmp_dir = tmp_path;463}464#endif /* MACOSX */465466/* patches/service packs installed */467sprops.patch_level = NULL; // leave it undefined468469#ifdef SI_ISALIST470/* supported instruction sets */471{472char list[258];473sysinfo(SI_ISALIST, list, sizeof(list));474sprops.cpu_isalist = strdup(list);475}476#else477sprops.cpu_isalist = NULL;478#endif479480/* endianness of platform */481{482unsigned int endianTest = 0xff000000;483if (((char*)(&endianTest))[0] != 0)484sprops.cpu_endian = "big";485else486sprops.cpu_endian = "little";487}488489/* os properties */490{491#ifdef MACOSX492setOSNameAndVersion(&sprops);493#else494struct utsname name;495uname(&name);496sprops.os_name = strdup(name.sysname);497#ifdef _AIX498{499char *os_version = malloc(strlen(name.version) +500strlen(name.release) + 2);501if (os_version != NULL) {502strcpy(os_version, name.version);503strcat(os_version, ".");504strcat(os_version, name.release);505}506sprops.os_version = os_version;507}508#else509sprops.os_version = strdup(name.release);510#endif /* _AIX */511#endif /* MACOSX */512513sprops.os_arch = ARCHPROPNAME;514}515516/* ABI property (optional) */517#ifdef JDK_ARCH_ABI_PROP_NAME518sprops.sun_arch_abi = JDK_ARCH_ABI_PROP_NAME;519#endif520521/* Determine the language, country, variant, and encoding from the host,522* and store these in the user.language, user.country, user.variant and523* file.encoding system properties. */524setlocale(LC_ALL, "");525if (ParseLocale(env, LC_CTYPE,526&(sprops.format_language),527&(sprops.format_script),528&(sprops.format_country),529&(sprops.format_variant),530&(sprops.encoding))) {531ParseLocale(env, LC_MESSAGES,532&(sprops.display_language),533&(sprops.display_script),534&(sprops.display_country),535&(sprops.display_variant),536NULL);537} else {538sprops.display_language = "en";539sprops.encoding = "ISO8859-1";540}541542/* ParseLocale failed with OOME */543JNU_CHECK_EXCEPTION_RETURN(env, NULL);544545#ifdef MACOSX546sprops.sun_jnu_encoding = "UTF-8";547#else548sprops.sun_jnu_encoding = sprops.encoding;549#endif550if (isatty(STDOUT_FILENO) == 1) {551sprops.sun_stdout_encoding = sprops.encoding;552}553if (isatty(STDERR_FILENO) == 1) {554sprops.sun_stderr_encoding = sprops.encoding;555}556557#ifdef _ALLBSD_SOURCE558#if BYTE_ORDER == _LITTLE_ENDIAN559sprops.unicode_encoding = "UnicodeLittle";560#else561sprops.unicode_encoding = "UnicodeBig";562#endif563#else /* !_ALLBSD_SOURCE */564#ifdef __linux__565#if __BYTE_ORDER == __LITTLE_ENDIAN566sprops.unicode_encoding = "UnicodeLittle";567#else568sprops.unicode_encoding = "UnicodeBig";569#endif570#else571sprops.unicode_encoding = "UnicodeBig";572#endif573#endif /* _ALLBSD_SOURCE */574575/* user properties */576{577struct passwd *pwent = getpwuid(getuid());578sprops.user_name = pwent ? strdup(pwent->pw_name) : "?";579#ifdef MACOSX580setUserHome(&sprops);581#else582sprops.user_home = pwent ? strdup(pwent->pw_dir) : NULL;583#endif584if (sprops.user_home == NULL) {585sprops.user_home = "?";586}587}588589/* User TIMEZONE590* We defer setting up timezone until it's actually necessary.591* Refer to TimeZone.getDefault(). The system property592* is able to be set by the command line interface -Duser.timezone.593*/594tzset(); /* for compatibility */595596/* Current directory */597{598char buf[MAXPATHLEN];599errno = 0;600if (getcwd(buf, sizeof(buf)) == NULL)601JNU_ThrowByName(env, "java/lang/Error",602"Properties init: Could not determine current working directory.");603else604sprops.user_dir = strdup(buf);605}606607sprops.file_separator = "/";608sprops.path_separator = ":";609sprops.line_separator = "\n";610611#ifdef MACOSX612setProxyProperties(&sprops);613#endif614615return &sprops;616}617618jstring619GetStringPlatform(JNIEnv *env, nchar* cstr)620{621return JNU_NewStringPlatform(env, cstr);622}623624625