1 /*
  2  * Copyright (c) 1994, 2025, Oracle and/or its affiliates. All rights reserved.
  3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  4  *
  5  * This code is free software; you can redistribute it and/or modify it
  6  * under the terms of the GNU General Public License version 2 only, as
  7  * published by the Free Software Foundation.  Oracle designates this
  8  * particular file as subject to the "Classpath" exception as provided
  9  * by Oracle in the LICENSE file that accompanied this code.
 10  *
 11  * This code is distributed in the hope that it will be useful, but WITHOUT
 12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 14  * version 2 for more details (a copy is included in the LICENSE file that
 15  * accompanied this code).
 16  *
 17  * You should have received a copy of the GNU General Public License version
 18  * 2 along with this work; if not, write to the Free Software Foundation,
 19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 20  *
 21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 22  * or visit www.oracle.com if you need additional information or have any
 23  * questions.
 24  */
 25 
 26 #include <assert.h>
 27 #include <string.h>
 28 
 29 #include "jni.h"
 30 #include "jni_util.h"
 31 #include "jvm.h"
 32 #include "java_props.h"
 33 
 34 #include "java_lang_System.h"
 35 #include "jdk_internal_util_SystemProps_Raw.h"
 36 
 37 #define OBJ "Ljava/lang/Object;"
 38 
 39 /* Only register the performance-critical methods */
 40 static JNINativeMethod methods[] = {
 41     {"currentTimeMillis", "()J",              (void *)&JVM_CurrentTimeMillis},
 42     {"nanoTime",          "()J",              (void *)&JVM_NanoTime},
 43     {"arraycopy",     "(" OBJ "I" OBJ "II)V", (void *)&JVM_ArrayCopy},
 44 };
 45 
 46 #undef OBJ
 47 
 48 JNIEXPORT void JNICALL
 49 Java_java_lang_System_registerNatives(JNIEnv *env, jclass cls)
 50 {
 51     (*env)->RegisterNatives(env, cls,
 52                             methods, sizeof(methods)/sizeof(methods[0]));
 53 }
 54 
 55 JNIEXPORT jint JNICALL
 56 Java_java_lang_System_identityHashCode(JNIEnv *env, jobject this, jobject x)
 57 {
 58     return JVM_IHashCode(env, x);
 59 }
 60 
 61 /* VENDOR, VENDOR_URL, VENDOR_URL_BUG are set in VersionProps.java.template. */
 62 
 63 /*
 64  * Store the UTF-8 string encoding of the value in the array
 65  * at the index if the value is non-null.  Store nothing if the value is null.
 66  * On any error, return from Java_jdk_internal_util_SystemProps_00024Raw_platformProperties.
 67  */
 68 #define PUTPROP(array, prop_index, val)                    \
 69     if (val != NULL) {                                     \
 70         jstring jval = (*env)->NewStringUTF(env, val);     \
 71         if (jval == NULL)                                  \
 72             return NULL;                                   \
 73         (*env)->SetObjectArrayElement(env, array, jdk_internal_util_SystemProps_Raw_##prop_index, jval); \
 74         if ((*env)->ExceptionCheck(env))                \
 75             return NULL;                                   \
 76         (*env)->DeleteLocalRef(env, jval);                 \
 77     }
 78 
 79 /*
 80  * Store the Platform string encoding of the value in the array
 81  * at the index if the value is non-null.  Store nothing if the value is null.
 82  * On any error, return from Java_jdk_internal_util_SystemProps_00024Raw_platformProperties.
 83  */
 84 #define PUTPROP_PlatformString(array, prop_index, val)     \
 85     if (val != NULL) {                                     \
 86         jstring jval = GetStringPlatform(env, val);        \
 87         if (jval == NULL)                                  \
 88             return NULL;                                   \
 89         (*env)->SetObjectArrayElement(env, array, jdk_internal_util_SystemProps_Raw_##prop_index, jval); \
 90         if ((*env)->ExceptionCheck(env))                \
 91             return NULL;                                   \
 92         (*env)->DeleteLocalRef(env, jval);                 \
 93     }
 94 
 95 /*
 96  * Gather the system properties and return as a String[].
 97  * The first FIXED_LENGTH entries are the platform defined property values, no names.
 98  * The remaining array indices are alternating key/value pairs
 99  * supplied by the VM including those defined on the command line
100  * using -Dkey=value that may override the platform defined value.
101  * The caller is responsible for replacing platform provided values as needed.
102  *
103  * Class:     jdk_internal_util_SystemProps_Raw
104  * Method:    platformProperties
105  * Signature: ()[Ljava/lang/String;
106  */
107 JNIEXPORT jobjectArray JNICALL
108 Java_jdk_internal_util_SystemProps_00024Raw_platformProperties(JNIEnv *env, jclass cla)
109 {
110     java_props_t *sprops;
111     jobject propArray = NULL;
112     jclass classString;
113     int nstrings = jdk_internal_util_SystemProps_Raw_FIXED_LENGTH;
114 
115     // Get the platform specific values
116     sprops = GetJavaProperties(env);
117     CHECK_NULL_RETURN(sprops, NULL);
118 
119     /*
120      * !!! DO NOT call PUTPROP_PlatformString (NewStringPlatform) before this line !!!
121      */
122     InitializeEncoding(env, sprops->sun_jnu_encoding);
123 
124     // Ensure capacity for the array and for a string for each fixed length element
125     if ((*env)->EnsureLocalCapacity(env, nstrings + 2) < 0) {
126         return NULL;
127     }
128 
129     // Allocate an array of String for all the well known props
130     classString = JNU_ClassString(env);
131     CHECK_NULL_RETURN(classString, NULL);
132 
133     propArray = (*env)->NewObjectArray(env, nstrings, classString, NULL);
134     CHECK_NULL_RETURN(propArray, NULL);
135 
136     /* os properties */
137     PUTPROP(propArray, _os_name_NDX, sprops->os_name);
138     PUTPROP(propArray, _os_version_NDX, sprops->os_version);
139     PUTPROP(propArray, _os_arch_NDX, sprops->os_arch);
140 
141 #ifdef JDK_ARCH_ABI_PROP_NAME
142     PUTPROP(propArray, _sun_arch_abi_NDX, sprops->sun_arch_abi);
143 #endif
144 
145     /* file system properties */
146     PUTPROP(propArray, _file_separator_NDX, sprops->file_separator);
147     PUTPROP(propArray, _path_separator_NDX, sprops->path_separator);
148     PUTPROP(propArray, _line_separator_NDX, sprops->line_separator);
149 
150     /* basic encoding properties, always non-NULL */
151     assert(sprops->encoding != NULL);
152     assert(sprops->sun_jnu_encoding != NULL);
153     PUTPROP(propArray, _native_encoding_NDX, sprops->encoding);
154     PUTPROP(propArray, _sun_jnu_encoding_NDX, sprops->sun_jnu_encoding);
155 
156     /* encodings for standard streams, may be NULL */
157     PUTPROP(propArray, _stdin_encoding_NDX, sprops->stdin_encoding);
158     PUTPROP(propArray, _stdout_encoding_NDX, sprops->stdout_encoding);
159     PUTPROP(propArray, _stderr_encoding_NDX, sprops->stderr_encoding);
160 
161     /* unicode_encoding specifies the default endianness */
162     PUTPROP(propArray, _sun_io_unicode_encoding_NDX, sprops->unicode_encoding);
163     PUTPROP(propArray, _sun_cpu_endian_NDX, sprops->cpu_endian);
164     PUTPROP(propArray, _sun_cpu_isalist_NDX, sprops->cpu_isalist);
165 
166 #ifdef MACOSX
167     /* Proxy setting properties */
168     if (sprops->httpProxyEnabled) {
169         PUTPROP(propArray, _http_proxyHost_NDX, sprops->httpHost);
170         PUTPROP(propArray, _http_proxyPort_NDX, sprops->httpPort);
171     }
172 
173     if (sprops->httpsProxyEnabled) {
174         PUTPROP(propArray, _https_proxyHost_NDX, sprops->httpsHost);
175         PUTPROP(propArray, _https_proxyPort_NDX, sprops->httpsPort);
176     }
177 
178     if (sprops->ftpProxyEnabled) {
179         PUTPROP(propArray, _ftp_proxyHost_NDX, sprops->ftpHost);
180         PUTPROP(propArray, _ftp_proxyPort_NDX, sprops->ftpPort);
181     }
182 
183     if (sprops->socksProxyEnabled) {
184         PUTPROP(propArray, _socksProxyHost_NDX, sprops->socksHost);
185         PUTPROP(propArray, _socksProxyPort_NDX, sprops->socksPort);
186     }
187 
188     // Mac OS X only has a single proxy exception list which applies
189     // to all protocols
190     if (sprops->exceptionList) {
191         PUTPROP(propArray, _http_nonProxyHosts_NDX, sprops->exceptionList);
192         PUTPROP(propArray, _ftp_nonProxyHosts_NDX, sprops->exceptionList);
193         PUTPROP(propArray, _socksNonProxyHosts_NDX, sprops->exceptionList);
194     }
195 #endif
196 
197     /* data model */
198     if (sizeof(sprops) == 4) {
199         sprops->data_model = "32";
200     } else if (sizeof(sprops) == 8) {
201         sprops->data_model = "64";
202     } else {
203         sprops->data_model = "unknown";
204     }
205     PUTPROP(propArray, _sun_arch_data_model_NDX, sprops->data_model);
206 
207     /* patch level */
208     PUTPROP(propArray, _sun_os_patch_level_NDX, sprops->patch_level);
209 
210     PUTPROP_PlatformString(propArray, _java_io_tmpdir_NDX, sprops->tmp_dir);
211 
212     PUTPROP_PlatformString(propArray, _user_name_NDX, sprops->user_name);
213     PUTPROP_PlatformString(propArray, _user_home_NDX, sprops->user_home);
214     PUTPROP_PlatformString(propArray, _user_dir_NDX, sprops->user_dir);
215 
216    /*
217     * Set i18n related property fields from platform.
218     */
219    PUTPROP(propArray, _display_language_NDX, sprops->display_language);
220    PUTPROP(propArray, _display_script_NDX, sprops->display_script);
221    PUTPROP(propArray, _display_country_NDX, sprops->display_country);
222    PUTPROP(propArray, _display_variant_NDX, sprops->display_variant);
223 
224    PUTPROP(propArray, _format_language_NDX, sprops->format_language);
225    PUTPROP(propArray, _format_script_NDX, sprops->format_script);
226    PUTPROP(propArray, _format_country_NDX, sprops->format_country);
227    PUTPROP(propArray, _format_variant_NDX, sprops->format_variant);
228 
229    return propArray;
230 }
231 
232 /*
233  * Gather the VM and command line properties and return as a String[].
234  * The array indices are alternating key/value pairs
235  * supplied by the VM including those defined on the command line
236  * using -Dkey=value that may override the platform defined value.
237  *
238  * Note: The platform encoding must have been set.
239  *
240  * Class:     jdk_internal_util_SystemProps_Raw
241  * Method:    vmProperties
242  * Signature: ()[Ljava/lang/String;
243  */
244 JNIEXPORT jobjectArray JNICALL
245 Java_jdk_internal_util_SystemProps_00024Raw_vmProperties(JNIEnv *env, jclass cla)
246 {
247     jobjectArray cmdProps = JVM_GetProperties(env);
248     return cmdProps;
249 }
250 
251 /*
252  * The following three functions implement setter methods for
253  * java.lang.System.{in, out, err}. They are natively implemented
254  * because they violate the semantics of the language (i.e. set final
255  * variable).
256  */
257 JNIEXPORT void JNICALL
258 Java_java_lang_System_setIn0(JNIEnv *env, jclass cla, jobject stream)
259 {
260     jfieldID fid =
261         (*env)->GetStaticFieldID(env,cla,"in","Ljava/io/InputStream;");
262     if (fid == 0)
263         return;
264     (*env)->SetStaticObjectField(env,cla,fid,stream);
265 }
266 
267 JNIEXPORT void JNICALL
268 Java_java_lang_System_setOut0(JNIEnv *env, jclass cla, jobject stream)
269 {
270     jfieldID fid =
271         (*env)->GetStaticFieldID(env,cla,"out","Ljava/io/PrintStream;");
272     if (fid == 0)
273         return;
274     (*env)->SetStaticObjectField(env,cla,fid,stream);
275 }
276 
277 JNIEXPORT void JNICALL
278 Java_java_lang_System_setErr0(JNIEnv *env, jclass cla, jobject stream)
279 {
280     jfieldID fid =
281         (*env)->GetStaticFieldID(env,cla,"err","Ljava/io/PrintStream;");
282     if (fid == 0)
283         return;
284     (*env)->SetStaticObjectField(env,cla,fid,stream);
285 }
286 
287 static void cpchars(jchar *dst, char *src, int n)
288 {
289     int i;
290     for (i = 0; i < n; i++) {
291         dst[i] = src[i];
292     }
293 }
294 
295 JNIEXPORT jboolean JNICALL
296 Java_java_lang_System_AOTIsTraining(JNIEnv *env, jclass ign)
297 {
298     jboolean isTraining = JVM_AOTIsTraining(env);
299     return isTraining;
300 }
301 
302 JNIEXPORT void JNICALL
303 Java_java_lang_System_AOTEndTraining(JNIEnv *env, jclass ign)
304 {
305     JVM_AOTEndTraining(env);
306 }
307 
308 JNIEXPORT jstring JNICALL
309 Java_java_lang_System_mapLibraryName(JNIEnv *env, jclass ign, jstring libname)
310 {
311     int len;
312     int prefix_len = (int) strlen(JNI_LIB_PREFIX);
313     int suffix_len = (int) strlen(JNI_LIB_SUFFIX);
314 
315     jchar chars[256];
316     if (libname == NULL) {
317         JNU_ThrowNullPointerException(env, 0);
318         return NULL;
319     }
320     len = (*env)->GetStringLength(env, libname);
321     if (len > 240) {
322         JNU_ThrowIllegalArgumentException(env, "name too long");
323         return NULL;
324     }
325     cpchars(chars, JNI_LIB_PREFIX, prefix_len);
326     (*env)->GetStringRegion(env, libname, 0, len, chars + prefix_len);
327     len += prefix_len;
328     cpchars(chars + len, JNI_LIB_SUFFIX, suffix_len);
329     len += suffix_len;
330 
331     return (*env)->NewString(env, chars, len);
332 }