17c478bd9Sstevel@tonic-gate /* 27c478bd9Sstevel@tonic-gate * CDDL HEADER START 37c478bd9Sstevel@tonic-gate * 47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*46ae6f1eSdp * Common Development and Distribution License (the "License"). 6*46ae6f1eSdp * You may not use this file except in compliance with the License. 77c478bd9Sstevel@tonic-gate * 87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 117c478bd9Sstevel@tonic-gate * and limitations under the License. 127c478bd9Sstevel@tonic-gate * 137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 187c478bd9Sstevel@tonic-gate * 197c478bd9Sstevel@tonic-gate * CDDL HEADER END 207c478bd9Sstevel@tonic-gate */ 217c478bd9Sstevel@tonic-gate /* 221500b9a0Sgarypen * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 237c478bd9Sstevel@tonic-gate * Use is subject to license terms. 247c478bd9Sstevel@tonic-gate */ 257c478bd9Sstevel@tonic-gate 267c478bd9Sstevel@tonic-gate /* 277c478bd9Sstevel@tonic-gate * poold - dynamically adjust pool configuration according to load. 287c478bd9Sstevel@tonic-gate */ 297c478bd9Sstevel@tonic-gate #include <errno.h> 307c478bd9Sstevel@tonic-gate #include <jni.h> 317c478bd9Sstevel@tonic-gate #include <libintl.h> 327c478bd9Sstevel@tonic-gate #include <limits.h> 337c478bd9Sstevel@tonic-gate #include <link.h> 347c478bd9Sstevel@tonic-gate #include <locale.h> 357c478bd9Sstevel@tonic-gate #include <poll.h> 367c478bd9Sstevel@tonic-gate #include <pool.h> 377c478bd9Sstevel@tonic-gate #include <priv.h> 387c478bd9Sstevel@tonic-gate #include <pthread.h> 397c478bd9Sstevel@tonic-gate #include <signal.h> 407c478bd9Sstevel@tonic-gate #include <stdio.h> 417c478bd9Sstevel@tonic-gate #include <stdlib.h> 427c478bd9Sstevel@tonic-gate #include <string.h> 437c478bd9Sstevel@tonic-gate #include <syslog.h> 447c478bd9Sstevel@tonic-gate #include <unistd.h> 457c478bd9Sstevel@tonic-gate 467c478bd9Sstevel@tonic-gate #include <sys/stat.h> 477c478bd9Sstevel@tonic-gate #include <sys/types.h> 487c478bd9Sstevel@tonic-gate #include <sys/ucontext.h> 497c478bd9Sstevel@tonic-gate #include "utils.h" 507c478bd9Sstevel@tonic-gate 517c478bd9Sstevel@tonic-gate #define POOLD_DEF_CLASSPATH "/usr/lib/pool/JPool.jar" 527c478bd9Sstevel@tonic-gate #define POOLD_DEF_LIBPATH "/usr/lib/pool" 5326d8ba22Sgarypen #define SMF_SVC_INSTANCE "svc:/system/pools/dynamic:default" 547c478bd9Sstevel@tonic-gate 557c478bd9Sstevel@tonic-gate #define CLASS_FIELD_DESC(class_desc) "L" class_desc ";" 567c478bd9Sstevel@tonic-gate 577c478bd9Sstevel@tonic-gate #define LEVEL_CLASS_DESC "java/util/logging/Level" 587c478bd9Sstevel@tonic-gate #define POOLD_CLASS_DESC "com/sun/solaris/domain/pools/Poold" 597c478bd9Sstevel@tonic-gate #define SEVERITY_CLASS_DESC "com/sun/solaris/service/logging/Severity" 607c478bd9Sstevel@tonic-gate #define STRING_CLASS_DESC "java/lang/String" 617c478bd9Sstevel@tonic-gate #define SYSTEM_CLASS_DESC "java/lang/System" 627c478bd9Sstevel@tonic-gate #define LOGGER_CLASS_DESC "java/util/logging/Logger" 637c478bd9Sstevel@tonic-gate 647c478bd9Sstevel@tonic-gate extern char *optarg; 657c478bd9Sstevel@tonic-gate 667c478bd9Sstevel@tonic-gate static const char *pname; 677c478bd9Sstevel@tonic-gate 687c478bd9Sstevel@tonic-gate static enum { 697c478bd9Sstevel@tonic-gate LD_TERMINAL = 1, 707c478bd9Sstevel@tonic-gate LD_SYSLOG, 717c478bd9Sstevel@tonic-gate LD_JAVA 727c478bd9Sstevel@tonic-gate } log_dest = LD_SYSLOG; 737c478bd9Sstevel@tonic-gate 747c478bd9Sstevel@tonic-gate static const char PNAME_FMT[] = "%s: "; 757c478bd9Sstevel@tonic-gate static const char ERRNO_FMT[] = ": %s"; 767c478bd9Sstevel@tonic-gate 771500b9a0Sgarypen static pthread_mutex_t jvm_lock = PTHREAD_MUTEX_INITIALIZER; 781500b9a0Sgarypen static JavaVM *jvm; /* protected by jvm_lock */ 791500b9a0Sgarypen static int instance_running; /* protected by jvm_lock */ 801500b9a0Sgarypen static int lflag; /* specifies poold logging mode */ 817c478bd9Sstevel@tonic-gate 827c478bd9Sstevel@tonic-gate static jmethodID log_mid; 837c478bd9Sstevel@tonic-gate static jobject severity_err; 847c478bd9Sstevel@tonic-gate static jobject severity_notice; 857c478bd9Sstevel@tonic-gate static jobject base_log; 867c478bd9Sstevel@tonic-gate static jclass poold_class; 877c478bd9Sstevel@tonic-gate static jobject poold_instance; 887c478bd9Sstevel@tonic-gate 897c478bd9Sstevel@tonic-gate static sigset_t hdl_set; 907c478bd9Sstevel@tonic-gate 911500b9a0Sgarypen static void pu_notice(const char *fmt, ...); 92414388d7Ssl108498 static void pu_die(const char *fmt, ...) __NORETURN; 93414388d7Ssl108498 947c478bd9Sstevel@tonic-gate static void 957c478bd9Sstevel@tonic-gate usage(void) 967c478bd9Sstevel@tonic-gate { 977c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext("Usage:\t%s [-l <level>]\n"), pname); 987c478bd9Sstevel@tonic-gate 997c478bd9Sstevel@tonic-gate exit(E_USAGE); 1007c478bd9Sstevel@tonic-gate } 1017c478bd9Sstevel@tonic-gate 1027c478bd9Sstevel@tonic-gate static void 1031500b9a0Sgarypen check_thread_attached(JNIEnv **env) 1041500b9a0Sgarypen { 1051500b9a0Sgarypen int ret; 1061500b9a0Sgarypen 1071500b9a0Sgarypen ret = (*jvm)->GetEnv(jvm, (void **)env, JNI_VERSION_1_4); 1081500b9a0Sgarypen if (*env == NULL) { 1091500b9a0Sgarypen if (ret == JNI_EVERSION) { 1101500b9a0Sgarypen /* 1111500b9a0Sgarypen * Avoid recursively calling 1121500b9a0Sgarypen * check_thread_attached() 1131500b9a0Sgarypen */ 1141500b9a0Sgarypen if (log_dest == LD_JAVA) 1151500b9a0Sgarypen log_dest = LD_TERMINAL; 1161500b9a0Sgarypen pu_notice(gettext("incorrect JNI version")); 1171500b9a0Sgarypen exit(E_ERROR); 1181500b9a0Sgarypen } 1191500b9a0Sgarypen if ((*jvm)->AttachCurrentThreadAsDaemon(jvm, (void **)env, 1201500b9a0Sgarypen NULL) != 0) { 1211500b9a0Sgarypen /* 1221500b9a0Sgarypen * Avoid recursively calling 1231500b9a0Sgarypen * check_thread_attached() 1241500b9a0Sgarypen */ 1251500b9a0Sgarypen if (log_dest == LD_JAVA) 1261500b9a0Sgarypen log_dest = LD_TERMINAL; 1271500b9a0Sgarypen pu_notice(gettext("thread attach failed")); 1281500b9a0Sgarypen exit(E_ERROR); 1291500b9a0Sgarypen } 1301500b9a0Sgarypen } 1311500b9a0Sgarypen } 1321500b9a0Sgarypen 1331500b9a0Sgarypen /* 1341500b9a0Sgarypen * Output a message to the designated logging destination. 1351500b9a0Sgarypen * 1361500b9a0Sgarypen * severity - Specified the severity level when using LD_JAVA logging 1371500b9a0Sgarypen * fmt - specified the format of the output message 1381500b9a0Sgarypen * alist - varargs used in the output message 1391500b9a0Sgarypen */ 1401500b9a0Sgarypen static void 1417c478bd9Sstevel@tonic-gate pu_output(int severity, const char *fmt, va_list alist) 1427c478bd9Sstevel@tonic-gate { 1437c478bd9Sstevel@tonic-gate int err = errno; 1447c478bd9Sstevel@tonic-gate char line[255] = ""; 1457c478bd9Sstevel@tonic-gate jobject jseverity; 1467c478bd9Sstevel@tonic-gate jobject jline; 1471500b9a0Sgarypen JNIEnv *env = NULL; 1481500b9a0Sgarypen 1497c478bd9Sstevel@tonic-gate if (pname != NULL && log_dest == LD_TERMINAL) 1507c478bd9Sstevel@tonic-gate (void) snprintf(line, sizeof (line), gettext(PNAME_FMT), pname); 1517c478bd9Sstevel@tonic-gate 1527c478bd9Sstevel@tonic-gate (void) vsnprintf(line + strlen(line), sizeof (line) - strlen(line), 1537c478bd9Sstevel@tonic-gate fmt, alist); 1547c478bd9Sstevel@tonic-gate 1557c478bd9Sstevel@tonic-gate if (line[strlen(line) - 1] != '\n') 1567c478bd9Sstevel@tonic-gate (void) snprintf(line + strlen(line), sizeof (line) - 1577c478bd9Sstevel@tonic-gate strlen(line), gettext(ERRNO_FMT), strerror(err)); 1587c478bd9Sstevel@tonic-gate else 1597c478bd9Sstevel@tonic-gate line[strlen(line) - 1] = 0; 1607c478bd9Sstevel@tonic-gate 1617c478bd9Sstevel@tonic-gate switch (log_dest) { 1627c478bd9Sstevel@tonic-gate case LD_TERMINAL: 1637c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "%s\n", line); 1647c478bd9Sstevel@tonic-gate (void) fflush(stderr); 1657c478bd9Sstevel@tonic-gate break; 1667c478bd9Sstevel@tonic-gate case LD_SYSLOG: 1677c478bd9Sstevel@tonic-gate syslog(LOG_ERR, "%s", line); 1687c478bd9Sstevel@tonic-gate break; 1697c478bd9Sstevel@tonic-gate case LD_JAVA: 1707c478bd9Sstevel@tonic-gate if (severity == LOG_ERR) 1717c478bd9Sstevel@tonic-gate jseverity = severity_err; 1727c478bd9Sstevel@tonic-gate else 1737c478bd9Sstevel@tonic-gate jseverity = severity_notice; 1747c478bd9Sstevel@tonic-gate 1757c478bd9Sstevel@tonic-gate if (jvm) { 1761500b9a0Sgarypen check_thread_attached(&env); 1777c478bd9Sstevel@tonic-gate if ((jline = (*env)->NewStringUTF(env, line)) != NULL) 1787c478bd9Sstevel@tonic-gate (*env)->CallVoidMethod(env, base_log, log_mid, 1797c478bd9Sstevel@tonic-gate jseverity, jline); 1807c478bd9Sstevel@tonic-gate } 1817c478bd9Sstevel@tonic-gate } 1827c478bd9Sstevel@tonic-gate } 1837c478bd9Sstevel@tonic-gate 1841500b9a0Sgarypen /* 1851500b9a0Sgarypen * Notify the user with the supplied message. 1861500b9a0Sgarypen */ 1877c478bd9Sstevel@tonic-gate /*PRINTFLIKE1*/ 1887c478bd9Sstevel@tonic-gate static void 1897c478bd9Sstevel@tonic-gate pu_notice(const char *fmt, ...) 1907c478bd9Sstevel@tonic-gate { 1917c478bd9Sstevel@tonic-gate va_list alist; 1921500b9a0Sgarypen 1937c478bd9Sstevel@tonic-gate va_start(alist, fmt); 1947c478bd9Sstevel@tonic-gate pu_output(LOG_NOTICE, fmt, alist); 1957c478bd9Sstevel@tonic-gate va_end(alist); 1967c478bd9Sstevel@tonic-gate } 1977c478bd9Sstevel@tonic-gate 1981500b9a0Sgarypen /* 1991500b9a0Sgarypen * Stop the application executing inside the JVM. Always ensure that jvm_lock 2001500b9a0Sgarypen * is held before invoking this function. 2011500b9a0Sgarypen */ 2021500b9a0Sgarypen static void 2031500b9a0Sgarypen halt_application(void) 2041500b9a0Sgarypen { 2051500b9a0Sgarypen JNIEnv *env = NULL; 2061500b9a0Sgarypen jmethodID poold_shutdown_mid; 2071500b9a0Sgarypen 2081500b9a0Sgarypen if (jvm && instance_running) { 2091500b9a0Sgarypen check_thread_attached(&env); 2101500b9a0Sgarypen if ((poold_shutdown_mid = (*env)->GetMethodID( 2111500b9a0Sgarypen env, poold_class, "shutdown", "()V")) != NULL) { 2121500b9a0Sgarypen (*env)->CallVoidMethod(env, poold_instance, 2131500b9a0Sgarypen poold_shutdown_mid); 2141500b9a0Sgarypen } else { 2151500b9a0Sgarypen if (lflag && (*env)->ExceptionOccurred(env)) { 2161500b9a0Sgarypen (*env)->ExceptionDescribe(env); 2171500b9a0Sgarypen pu_notice("could not invoke proper shutdown\n"); 2181500b9a0Sgarypen } 2191500b9a0Sgarypen } 2201500b9a0Sgarypen instance_running = 0; 2211500b9a0Sgarypen } 2221500b9a0Sgarypen } 2231500b9a0Sgarypen 2241500b9a0Sgarypen /* 2251500b9a0Sgarypen * Warn the user with the supplied error message, halt the application, 2261500b9a0Sgarypen * destroy the JVM and then exit the process. 2271500b9a0Sgarypen */ 2287c478bd9Sstevel@tonic-gate /*PRINTFLIKE1*/ 2297c478bd9Sstevel@tonic-gate static void 2307c478bd9Sstevel@tonic-gate pu_die(const char *fmt, ...) 2317c478bd9Sstevel@tonic-gate { 2327c478bd9Sstevel@tonic-gate va_list alist; 2331500b9a0Sgarypen 2347c478bd9Sstevel@tonic-gate va_start(alist, fmt); 2357c478bd9Sstevel@tonic-gate pu_output(LOG_ERR, fmt, alist); 2367c478bd9Sstevel@tonic-gate va_end(alist); 2371500b9a0Sgarypen halt_application(); 2381500b9a0Sgarypen if (jvm) { 2391500b9a0Sgarypen (*jvm)->DestroyJavaVM(jvm); 2401500b9a0Sgarypen jvm = NULL; 2411500b9a0Sgarypen } 2427c478bd9Sstevel@tonic-gate exit(E_ERROR); 2437c478bd9Sstevel@tonic-gate } 2447c478bd9Sstevel@tonic-gate 2457c478bd9Sstevel@tonic-gate /* 2461500b9a0Sgarypen * Warn the user with the supplied error message and halt the 2471500b9a0Sgarypen * application. This function is very similar to pu_die(). However, 2481500b9a0Sgarypen * this function is designed to be called from the signal handling 2491500b9a0Sgarypen * routine (handle_sig()) where although we wish to let the user know 2501500b9a0Sgarypen * that an error has occurred, we do not wish to destroy the JVM or 2511500b9a0Sgarypen * exit the process. 2527c478bd9Sstevel@tonic-gate */ 2531500b9a0Sgarypen /*PRINTFLIKE1*/ 2547c478bd9Sstevel@tonic-gate static void 2551500b9a0Sgarypen pu_terminate(const char *fmt, ...) 2567c478bd9Sstevel@tonic-gate { 2571500b9a0Sgarypen va_list alist; 2587c478bd9Sstevel@tonic-gate 2591500b9a0Sgarypen va_start(alist, fmt); 2601500b9a0Sgarypen pu_output(LOG_ERR, fmt, alist); 2611500b9a0Sgarypen va_end(alist); 2621500b9a0Sgarypen halt_application(); 2637c478bd9Sstevel@tonic-gate } 2647c478bd9Sstevel@tonic-gate 2657c478bd9Sstevel@tonic-gate /* 2667c478bd9Sstevel@tonic-gate * If SIGHUP is invoked, we should just re-initialize poold. Since 2677c478bd9Sstevel@tonic-gate * there is no easy way to determine when it's safe to re-initialzie 2687c478bd9Sstevel@tonic-gate * poold, simply update a dummy property on the system element to 2697c478bd9Sstevel@tonic-gate * force pool_conf_update() to detect a change. 2707c478bd9Sstevel@tonic-gate * 2717c478bd9Sstevel@tonic-gate * Both SIGTERM and SIGINT are interpreted as instructions to 2727c478bd9Sstevel@tonic-gate * shutdown. 2737c478bd9Sstevel@tonic-gate */ 2747c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 2757c478bd9Sstevel@tonic-gate static void * 2767c478bd9Sstevel@tonic-gate handle_sig(void *arg) 2777c478bd9Sstevel@tonic-gate { 2781500b9a0Sgarypen pool_conf_t *conf = NULL; 2791500b9a0Sgarypen pool_elem_t *pe; 2801500b9a0Sgarypen pool_value_t *val; 2811500b9a0Sgarypen const char *err_desc; 2821500b9a0Sgarypen int keep_handling = 1; 2831500b9a0Sgarypen 2841500b9a0Sgarypen while (keep_handling) { 2857c478bd9Sstevel@tonic-gate int sig; 2867c478bd9Sstevel@tonic-gate char buf[SIG2STR_MAX]; 2877c478bd9Sstevel@tonic-gate 28826d8ba22Sgarypen if ((sig = sigwait(&hdl_set)) < 0) { 28926d8ba22Sgarypen /* 29026d8ba22Sgarypen * We used forkall() previously to ensure that 29126d8ba22Sgarypen * all threads started by the JVM are 29226d8ba22Sgarypen * duplicated in the child. Since forkall() 29326d8ba22Sgarypen * can cause blocking system calls to be 29426d8ba22Sgarypen * interrupted, check to see if the errno is 29526d8ba22Sgarypen * EINTR and if it is wait again. 29626d8ba22Sgarypen */ 29726d8ba22Sgarypen if (errno == EINTR) 2981500b9a0Sgarypen continue; 2991500b9a0Sgarypen (void) pthread_mutex_lock(&jvm_lock); 3001500b9a0Sgarypen pu_terminate("unexpected error: %d\n", errno); 3011500b9a0Sgarypen keep_handling = 0; 3021500b9a0Sgarypen } else 3031500b9a0Sgarypen (void) pthread_mutex_lock(&jvm_lock); 3047c478bd9Sstevel@tonic-gate (void) sig2str(sig, buf); 3057c478bd9Sstevel@tonic-gate switch (sig) { 3067c478bd9Sstevel@tonic-gate case SIGHUP: 3071500b9a0Sgarypen if ((conf = pool_conf_alloc()) == NULL) { 3081500b9a0Sgarypen err_desc = pool_strerror(pool_error()); 3091500b9a0Sgarypen goto destroy; 3101500b9a0Sgarypen } 3111500b9a0Sgarypen if (pool_conf_open(conf, pool_dynamic_location(), 3121500b9a0Sgarypen PO_RDWR) != 0) { 3131500b9a0Sgarypen err_desc = pool_strerror(pool_error()); 3141500b9a0Sgarypen goto destroy; 3151500b9a0Sgarypen } 3161500b9a0Sgarypen 3171500b9a0Sgarypen if ((val = pool_value_alloc()) == NULL) { 3181500b9a0Sgarypen err_desc = pool_strerror(pool_error()); 3191500b9a0Sgarypen goto destroy; 3201500b9a0Sgarypen } 3211500b9a0Sgarypen pe = pool_conf_to_elem(conf); 3221500b9a0Sgarypen pool_value_set_bool(val, 1); 3231500b9a0Sgarypen if (pool_put_property(conf, pe, "system.poold.sighup", 3241500b9a0Sgarypen val) != PO_SUCCESS) { 3251500b9a0Sgarypen err_desc = pool_strerror(pool_error()); 3261500b9a0Sgarypen pool_value_free(val); 3271500b9a0Sgarypen goto destroy; 3281500b9a0Sgarypen } 3291500b9a0Sgarypen pool_value_free(val); 3301500b9a0Sgarypen (void) pool_rm_property(conf, pe, 3311500b9a0Sgarypen "system.poold.sighup"); 3321500b9a0Sgarypen if (pool_conf_commit(conf, 0) != PO_SUCCESS) { 3331500b9a0Sgarypen err_desc = pool_strerror(pool_error()); 3341500b9a0Sgarypen goto destroy; 3351500b9a0Sgarypen } 336*46ae6f1eSdp (void) pool_conf_close(conf); 337*46ae6f1eSdp pool_conf_free(conf); 3381500b9a0Sgarypen break; 3391500b9a0Sgarypen destroy: 3401500b9a0Sgarypen if (conf) { 3411500b9a0Sgarypen (void) pool_conf_close(conf); 3421500b9a0Sgarypen pool_conf_free(conf); 3431500b9a0Sgarypen } 3441500b9a0Sgarypen pu_terminate(err_desc); 3451500b9a0Sgarypen keep_handling = 0; 3467c478bd9Sstevel@tonic-gate break; 3477c478bd9Sstevel@tonic-gate case SIGINT: 3487c478bd9Sstevel@tonic-gate case SIGTERM: 3497c478bd9Sstevel@tonic-gate default: 3501500b9a0Sgarypen pu_terminate("terminating due to signal: SIG%s\n", buf); 3511500b9a0Sgarypen keep_handling = 0; 3521500b9a0Sgarypen break; 3537c478bd9Sstevel@tonic-gate } 3541500b9a0Sgarypen (void) pthread_mutex_unlock(&jvm_lock); 3557c478bd9Sstevel@tonic-gate } 3561500b9a0Sgarypen pthread_exit(NULL); 3577c478bd9Sstevel@tonic-gate /*NOTREACHED*/ 3587c478bd9Sstevel@tonic-gate return (NULL); 3597c478bd9Sstevel@tonic-gate } 3607c478bd9Sstevel@tonic-gate 3611500b9a0Sgarypen /* 3621500b9a0Sgarypen * Return the name of the process 3631500b9a0Sgarypen */ 3647c478bd9Sstevel@tonic-gate static const char * 3657c478bd9Sstevel@tonic-gate pu_getpname(const char *arg0) 3667c478bd9Sstevel@tonic-gate { 3677c478bd9Sstevel@tonic-gate char *p; 3687c478bd9Sstevel@tonic-gate 3697c478bd9Sstevel@tonic-gate /* 3707c478bd9Sstevel@tonic-gate * Guard against '/' at end of command invocation. 3717c478bd9Sstevel@tonic-gate */ 3727c478bd9Sstevel@tonic-gate for (;;) { 3737c478bd9Sstevel@tonic-gate p = strrchr(arg0, '/'); 3747c478bd9Sstevel@tonic-gate if (p == NULL) { 3757c478bd9Sstevel@tonic-gate pname = arg0; 3767c478bd9Sstevel@tonic-gate break; 3777c478bd9Sstevel@tonic-gate } else { 3787c478bd9Sstevel@tonic-gate if (*(p + 1) == '\0') { 3797c478bd9Sstevel@tonic-gate *p = '\0'; 3807c478bd9Sstevel@tonic-gate continue; 3817c478bd9Sstevel@tonic-gate } 3827c478bd9Sstevel@tonic-gate 3837c478bd9Sstevel@tonic-gate pname = p + 1; 3847c478bd9Sstevel@tonic-gate break; 3857c478bd9Sstevel@tonic-gate } 3867c478bd9Sstevel@tonic-gate } 3877c478bd9Sstevel@tonic-gate 3887c478bd9Sstevel@tonic-gate return (pname); 3897c478bd9Sstevel@tonic-gate } 3907c478bd9Sstevel@tonic-gate 3917c478bd9Sstevel@tonic-gate int 3927c478bd9Sstevel@tonic-gate main(int argc, char *argv[]) 3937c478bd9Sstevel@tonic-gate { 3947c478bd9Sstevel@tonic-gate char c; 3957c478bd9Sstevel@tonic-gate char log_severity[16] = ""; 3967c478bd9Sstevel@tonic-gate JavaVMInitArgs vm_args; 3977c478bd9Sstevel@tonic-gate JavaVMOption vm_opts[5]; 3987c478bd9Sstevel@tonic-gate int nopts = 0; 3997c478bd9Sstevel@tonic-gate const char *classpath; 4007c478bd9Sstevel@tonic-gate const char *libpath; 4017c478bd9Sstevel@tonic-gate size_t len; 4027c478bd9Sstevel@tonic-gate const char *err_desc; 4037c478bd9Sstevel@tonic-gate JNIEnv *env; 4047c478bd9Sstevel@tonic-gate jmethodID poold_getinstancewcl_mid; 4057c478bd9Sstevel@tonic-gate jmethodID poold_run_mid; 4067c478bd9Sstevel@tonic-gate jobject log_severity_string = NULL; 4077c478bd9Sstevel@tonic-gate jobject log_severity_obj = NULL; 4087c478bd9Sstevel@tonic-gate jclass severity_class; 4097c478bd9Sstevel@tonic-gate jmethodID severity_cons_mid; 4107c478bd9Sstevel@tonic-gate jfieldID base_log_fid; 4117c478bd9Sstevel@tonic-gate pthread_t hdl_thread; 41226d8ba22Sgarypen FILE *p; 4137c478bd9Sstevel@tonic-gate 4141500b9a0Sgarypen (void) pthread_mutex_lock(&jvm_lock); 4157c478bd9Sstevel@tonic-gate pname = pu_getpname(argv[0]); 4167c478bd9Sstevel@tonic-gate openlog(pname, 0, LOG_DAEMON); 4177c478bd9Sstevel@tonic-gate (void) chdir("/"); 4187c478bd9Sstevel@tonic-gate 4197c478bd9Sstevel@tonic-gate (void) setlocale(LC_ALL, ""); 4207c478bd9Sstevel@tonic-gate #if !defined(TEXT_DOMAIN) /* Should be defined with cc -D. */ 4217c478bd9Sstevel@tonic-gate #define TEXT_DOMAIN "SYS_TEST" /* Use this only if it wasn't. */ 4227c478bd9Sstevel@tonic-gate #endif 4237c478bd9Sstevel@tonic-gate (void) textdomain(TEXT_DOMAIN); 4247c478bd9Sstevel@tonic-gate 4257c478bd9Sstevel@tonic-gate opterr = 0; 4267c478bd9Sstevel@tonic-gate while ((c = getopt(argc, argv, "l:P")) != EOF) { 4277c478bd9Sstevel@tonic-gate switch (c) { 4287c478bd9Sstevel@tonic-gate case 'l': /* -l option */ 4297c478bd9Sstevel@tonic-gate lflag++; 4307c478bd9Sstevel@tonic-gate (void) strlcpy(log_severity, optarg, 4317c478bd9Sstevel@tonic-gate sizeof (log_severity)); 4327c478bd9Sstevel@tonic-gate log_dest = LD_TERMINAL; 4337c478bd9Sstevel@tonic-gate break; 4347c478bd9Sstevel@tonic-gate default: 4357c478bd9Sstevel@tonic-gate usage(); 4367c478bd9Sstevel@tonic-gate /*NOTREACHED*/ 4377c478bd9Sstevel@tonic-gate } 4387c478bd9Sstevel@tonic-gate } 4397c478bd9Sstevel@tonic-gate 4407c478bd9Sstevel@tonic-gate /* 4417c478bd9Sstevel@tonic-gate * Check permission 4427c478bd9Sstevel@tonic-gate */ 4437c478bd9Sstevel@tonic-gate if (!priv_ineffect(PRIV_SYS_RES_CONFIG)) 4447c478bd9Sstevel@tonic-gate pu_die(gettext(ERR_PRIVILEGE), PRIV_SYS_RES_CONFIG); 4457c478bd9Sstevel@tonic-gate 4467c478bd9Sstevel@tonic-gate /* 44726d8ba22Sgarypen * In order to avoid problems with arbitrary thread selection 44826d8ba22Sgarypen * when handling asynchronous signals, dedicate a thread to 44926d8ba22Sgarypen * look after these signals. 45026d8ba22Sgarypen */ 45126d8ba22Sgarypen if (sigemptyset(&hdl_set) < 0 || 45226d8ba22Sgarypen sigaddset(&hdl_set, SIGHUP) < 0 || 45326d8ba22Sgarypen sigaddset(&hdl_set, SIGTERM) < 0 || 45426d8ba22Sgarypen sigaddset(&hdl_set, SIGINT) < 0 || 45526d8ba22Sgarypen pthread_sigmask(SIG_BLOCK, &hdl_set, NULL) || 45626d8ba22Sgarypen pthread_create(&hdl_thread, NULL, handle_sig, NULL)) 45726d8ba22Sgarypen pu_die(gettext("can't install signal handler")); 45826d8ba22Sgarypen 45926d8ba22Sgarypen /* 46026d8ba22Sgarypen * If the -l flag is supplied, terminate the SMF service and 46126d8ba22Sgarypen * run interactively from the command line. 46226d8ba22Sgarypen */ 46326d8ba22Sgarypen if (lflag) { 46426d8ba22Sgarypen char *cmd = "/usr/sbin/svcadm disable -st " SMF_SVC_INSTANCE; 46526d8ba22Sgarypen 46626d8ba22Sgarypen if (getenv("SMF_FMRI") != NULL) 46726d8ba22Sgarypen pu_die("-l option illegal: %s\n", SMF_SVC_INSTANCE); 46826d8ba22Sgarypen /* 46926d8ba22Sgarypen * Since disabling a service isn't synchronous, use the 47026d8ba22Sgarypen * synchronous option from svcadm to achieve synchronous 47126d8ba22Sgarypen * behaviour. 47226d8ba22Sgarypen * This is not very satisfactory, but since this is only 47326d8ba22Sgarypen * for use in debugging scenarios, it will do until there 47426d8ba22Sgarypen * is a C API to synchronously shutdown a service in SMF. 47526d8ba22Sgarypen */ 47626d8ba22Sgarypen if ((p = popen(cmd, "w")) == NULL || pclose(p) != 0) 47726d8ba22Sgarypen pu_die("could not temporarily disable service: %s\n", 47826d8ba22Sgarypen SMF_SVC_INSTANCE); 47926d8ba22Sgarypen } else { 48026d8ba22Sgarypen /* 48126d8ba22Sgarypen * Check if we are running as a SMF service. If we 48226d8ba22Sgarypen * aren't, terminate this process after enabling the 48326d8ba22Sgarypen * service. 48426d8ba22Sgarypen */ 48526d8ba22Sgarypen if (getenv("SMF_FMRI") == NULL) { 48626d8ba22Sgarypen char *cmd = "/usr/sbin/svcadm enable -s " \ 48726d8ba22Sgarypen SMF_SVC_INSTANCE; 48826d8ba22Sgarypen if ((p = popen(cmd, "w")) == NULL || pclose(p) != 0) 48926d8ba22Sgarypen pu_die("could not enable " 49026d8ba22Sgarypen "service: %s\n", SMF_SVC_INSTANCE); 49126d8ba22Sgarypen return (E_PO_SUCCESS); 49226d8ba22Sgarypen } 49326d8ba22Sgarypen } 49426d8ba22Sgarypen 49526d8ba22Sgarypen /* 4967c478bd9Sstevel@tonic-gate * Establish the classpath and LD_LIBRARY_PATH for native 4977c478bd9Sstevel@tonic-gate * methods, and get the interpreter going. 4987c478bd9Sstevel@tonic-gate */ 4997c478bd9Sstevel@tonic-gate if ((classpath = getenv("POOLD_CLASSPATH")) == NULL) { 5007c478bd9Sstevel@tonic-gate classpath = POOLD_DEF_CLASSPATH; 5017c478bd9Sstevel@tonic-gate } else { 5027c478bd9Sstevel@tonic-gate const char *cur = classpath; 5037c478bd9Sstevel@tonic-gate 5047c478bd9Sstevel@tonic-gate /* 5057c478bd9Sstevel@tonic-gate * Check the components to make sure they're absolute 5067c478bd9Sstevel@tonic-gate * paths. 5077c478bd9Sstevel@tonic-gate */ 5087c478bd9Sstevel@tonic-gate while (cur != NULL && *cur) { 5097c478bd9Sstevel@tonic-gate if (*cur != '/') 5107c478bd9Sstevel@tonic-gate pu_die(gettext( 5117c478bd9Sstevel@tonic-gate "POOLD_CLASSPATH must contain absolute " 5127c478bd9Sstevel@tonic-gate "components\n")); 5137c478bd9Sstevel@tonic-gate cur = strchr(cur + 1, ':'); 5147c478bd9Sstevel@tonic-gate } 5157c478bd9Sstevel@tonic-gate } 5167c478bd9Sstevel@tonic-gate vm_opts[nopts].optionString = malloc(len = strlen(classpath) + 5177c478bd9Sstevel@tonic-gate strlen("-Djava.class.path=") + 1); 5187c478bd9Sstevel@tonic-gate (void) strlcpy(vm_opts[nopts].optionString, "-Djava.class.path=", len); 5197c478bd9Sstevel@tonic-gate (void) strlcat(vm_opts[nopts++].optionString, classpath, len); 5207c478bd9Sstevel@tonic-gate 5217c478bd9Sstevel@tonic-gate if ((libpath = getenv("POOLD_LD_LIBRARY_PATH")) == NULL) 5227c478bd9Sstevel@tonic-gate libpath = POOLD_DEF_LIBPATH; 5237c478bd9Sstevel@tonic-gate vm_opts[nopts].optionString = malloc(len = strlen(libpath) + 5247c478bd9Sstevel@tonic-gate strlen("-Djava.library.path=") + 1); 5257c478bd9Sstevel@tonic-gate (void) strlcpy(vm_opts[nopts].optionString, "-Djava.library.path=", 5267c478bd9Sstevel@tonic-gate len); 5277c478bd9Sstevel@tonic-gate (void) strlcat(vm_opts[nopts++].optionString, libpath, len); 5287c478bd9Sstevel@tonic-gate 5297c478bd9Sstevel@tonic-gate vm_opts[nopts++].optionString = "-Xrs"; 5307c478bd9Sstevel@tonic-gate vm_opts[nopts++].optionString = "-enableassertions"; 5317c478bd9Sstevel@tonic-gate 5327c478bd9Sstevel@tonic-gate vm_args.options = vm_opts; 5337c478bd9Sstevel@tonic-gate vm_args.nOptions = nopts; 5347c478bd9Sstevel@tonic-gate vm_args.ignoreUnrecognized = JNI_FALSE; 5357c478bd9Sstevel@tonic-gate vm_args.version = 0x00010002; 5367c478bd9Sstevel@tonic-gate 5371500b9a0Sgarypen if (JNI_CreateJavaVM(&jvm, (void **)&env, &vm_args) < 0) 5387c478bd9Sstevel@tonic-gate pu_die(gettext("can't create Java VM")); 5397c478bd9Sstevel@tonic-gate 5407c478bd9Sstevel@tonic-gate /* 5417c478bd9Sstevel@tonic-gate * Locate the Poold class and construct an instance. A side 5427c478bd9Sstevel@tonic-gate * effect of this is that the poold instance's logHelper will be 5437c478bd9Sstevel@tonic-gate * initialized, establishing loggers for logging errors from 5447c478bd9Sstevel@tonic-gate * this point on. (Note, in the event of an unanticipated 5457c478bd9Sstevel@tonic-gate * exception, poold will invoke die() itself.) 5467c478bd9Sstevel@tonic-gate */ 5477c478bd9Sstevel@tonic-gate err_desc = gettext("JVM-related error initializing poold\n"); 5487c478bd9Sstevel@tonic-gate if ((poold_class = (*env)->FindClass(env, POOLD_CLASS_DESC)) == NULL) 5497c478bd9Sstevel@tonic-gate goto destroy; 5507c478bd9Sstevel@tonic-gate if ((poold_getinstancewcl_mid = (*env)->GetStaticMethodID(env, 5517c478bd9Sstevel@tonic-gate poold_class, "getInstanceWithConsoleLogging", "(" 5527c478bd9Sstevel@tonic-gate CLASS_FIELD_DESC(SEVERITY_CLASS_DESC) ")" 5537c478bd9Sstevel@tonic-gate CLASS_FIELD_DESC(POOLD_CLASS_DESC))) == NULL) 5547c478bd9Sstevel@tonic-gate goto destroy; 5557c478bd9Sstevel@tonic-gate if ((poold_run_mid = (*env)->GetMethodID(env, poold_class, "run", 5567c478bd9Sstevel@tonic-gate "()V")) == NULL) 5577c478bd9Sstevel@tonic-gate goto destroy; 5587c478bd9Sstevel@tonic-gate if ((severity_class = (*env)->FindClass(env, SEVERITY_CLASS_DESC)) 5597c478bd9Sstevel@tonic-gate == NULL) 5607c478bd9Sstevel@tonic-gate goto destroy; 5617c478bd9Sstevel@tonic-gate if ((severity_cons_mid = (*env)->GetStaticMethodID(env, severity_class, 5627c478bd9Sstevel@tonic-gate "getSeverityWithName", "(" CLASS_FIELD_DESC(STRING_CLASS_DESC) ")" 5637c478bd9Sstevel@tonic-gate CLASS_FIELD_DESC(SEVERITY_CLASS_DESC))) == NULL) 5647c478bd9Sstevel@tonic-gate goto destroy; 5657c478bd9Sstevel@tonic-gate 5667c478bd9Sstevel@tonic-gate /* 5677c478bd9Sstevel@tonic-gate * -l <level> was specified, indicating that messages are to be 5687c478bd9Sstevel@tonic-gate * logged to the console only. 5697c478bd9Sstevel@tonic-gate */ 5707c478bd9Sstevel@tonic-gate if (strlen(log_severity) > 0) { 5717c478bd9Sstevel@tonic-gate if ((log_severity_string = (*env)->NewStringUTF(env, 5727c478bd9Sstevel@tonic-gate log_severity)) == NULL) 5737c478bd9Sstevel@tonic-gate goto destroy; 5747c478bd9Sstevel@tonic-gate if ((log_severity_obj = (*env)->CallStaticObjectMethod(env, 5757c478bd9Sstevel@tonic-gate severity_class, severity_cons_mid, log_severity_string)) == 5767c478bd9Sstevel@tonic-gate NULL) { 5777c478bd9Sstevel@tonic-gate err_desc = gettext("invalid level specified\n"); 5787c478bd9Sstevel@tonic-gate goto destroy; 5797c478bd9Sstevel@tonic-gate } 5807c478bd9Sstevel@tonic-gate } else 5817c478bd9Sstevel@tonic-gate log_severity_obj = NULL; 5827c478bd9Sstevel@tonic-gate 5837c478bd9Sstevel@tonic-gate if ((poold_instance = (*env)->CallStaticObjectMethod(env, poold_class, 5847c478bd9Sstevel@tonic-gate poold_getinstancewcl_mid, log_severity_obj)) == NULL) 5857c478bd9Sstevel@tonic-gate goto destroy; 5867c478bd9Sstevel@tonic-gate 5877c478bd9Sstevel@tonic-gate /* 5887c478bd9Sstevel@tonic-gate * Grab a global reference to poold for use in our signal 5897c478bd9Sstevel@tonic-gate * handlers. 5907c478bd9Sstevel@tonic-gate */ 5917c478bd9Sstevel@tonic-gate poold_instance = (*env)->NewGlobalRef(env, poold_instance); 5927c478bd9Sstevel@tonic-gate 5937c478bd9Sstevel@tonic-gate /* 5947c478bd9Sstevel@tonic-gate * Ready LD_JAVA logging. 5957c478bd9Sstevel@tonic-gate */ 5967c478bd9Sstevel@tonic-gate err_desc = gettext("cannot initialize logging\n"); 5977c478bd9Sstevel@tonic-gate if ((log_severity_string = (*env)->NewStringUTF(env, "err")) == NULL) 5987c478bd9Sstevel@tonic-gate goto destroy; 5997c478bd9Sstevel@tonic-gate if (!(severity_err = (*env)->CallStaticObjectMethod(env, severity_class, 6007c478bd9Sstevel@tonic-gate severity_cons_mid, log_severity_string))) 6017c478bd9Sstevel@tonic-gate goto destroy; 6027c478bd9Sstevel@tonic-gate if (!(severity_err = (*env)->NewGlobalRef(env, severity_err))) 6037c478bd9Sstevel@tonic-gate goto destroy; 6047c478bd9Sstevel@tonic-gate 6057c478bd9Sstevel@tonic-gate if ((log_severity_string = (*env)->NewStringUTF(env, "notice")) == NULL) 6067c478bd9Sstevel@tonic-gate goto destroy; 6077c478bd9Sstevel@tonic-gate if (!(severity_notice = (*env)->CallStaticObjectMethod(env, 6087c478bd9Sstevel@tonic-gate severity_class, severity_cons_mid, log_severity_string))) 6097c478bd9Sstevel@tonic-gate goto destroy; 6107c478bd9Sstevel@tonic-gate if (!(severity_notice = (*env)->NewGlobalRef(env, severity_notice))) 6117c478bd9Sstevel@tonic-gate goto destroy; 6127c478bd9Sstevel@tonic-gate 6137c478bd9Sstevel@tonic-gate if (!(base_log_fid = (*env)->GetStaticFieldID(env, poold_class, 6147c478bd9Sstevel@tonic-gate "BASE_LOG", CLASS_FIELD_DESC(LOGGER_CLASS_DESC)))) 6157c478bd9Sstevel@tonic-gate goto destroy; 6167c478bd9Sstevel@tonic-gate if (!(base_log = (*env)->GetStaticObjectField(env, poold_class, 6177c478bd9Sstevel@tonic-gate base_log_fid))) 6187c478bd9Sstevel@tonic-gate goto destroy; 6197c478bd9Sstevel@tonic-gate if (!(base_log = (*env)->NewGlobalRef(env, base_log))) 6207c478bd9Sstevel@tonic-gate goto destroy; 6217c478bd9Sstevel@tonic-gate if (!(log_mid = (*env)->GetMethodID(env, (*env)->GetObjectClass(env, 6227c478bd9Sstevel@tonic-gate base_log), "log", "(" CLASS_FIELD_DESC(LEVEL_CLASS_DESC) 6237c478bd9Sstevel@tonic-gate CLASS_FIELD_DESC(STRING_CLASS_DESC) ")V"))) 6247c478bd9Sstevel@tonic-gate goto destroy; 6257c478bd9Sstevel@tonic-gate log_dest = LD_JAVA; 6267c478bd9Sstevel@tonic-gate 6277c478bd9Sstevel@tonic-gate /* 62826d8ba22Sgarypen * If invoked directly and -l is specified, forking is not 62926d8ba22Sgarypen * desired. 6307c478bd9Sstevel@tonic-gate */ 63126d8ba22Sgarypen if (!lflag) 63226d8ba22Sgarypen switch (forkall()) { 63326d8ba22Sgarypen case 0: 63426d8ba22Sgarypen (void) setsid(); 63526d8ba22Sgarypen (void) fclose(stdin); 63626d8ba22Sgarypen (void) fclose(stdout); 63726d8ba22Sgarypen (void) fclose(stderr); 63826d8ba22Sgarypen break; 63926d8ba22Sgarypen case -1: 64026d8ba22Sgarypen pu_die(gettext("cannot fork")); 64126d8ba22Sgarypen /*NOTREACHED*/ 64226d8ba22Sgarypen default: 64326d8ba22Sgarypen return (E_PO_SUCCESS); 64426d8ba22Sgarypen } 6457c478bd9Sstevel@tonic-gate 6467c478bd9Sstevel@tonic-gate instance_running = 1; 6471500b9a0Sgarypen (void) pthread_mutex_unlock(&jvm_lock); 6481500b9a0Sgarypen 6497c478bd9Sstevel@tonic-gate (*env)->CallVoidMethod(env, poold_instance, poold_run_mid); 6507c478bd9Sstevel@tonic-gate 6511500b9a0Sgarypen (void) pthread_mutex_lock(&jvm_lock); 6521500b9a0Sgarypen if ((*env)->ExceptionOccurred(env)) { 6537c478bd9Sstevel@tonic-gate goto destroy; 6541500b9a0Sgarypen } 6551500b9a0Sgarypen if (jvm) { 6567c478bd9Sstevel@tonic-gate (*jvm)->DestroyJavaVM(jvm); 6571500b9a0Sgarypen jvm = NULL; 6581500b9a0Sgarypen } 6591500b9a0Sgarypen (void) pthread_mutex_unlock(&jvm_lock); 6607c478bd9Sstevel@tonic-gate return (E_PO_SUCCESS); 6617c478bd9Sstevel@tonic-gate 6627c478bd9Sstevel@tonic-gate destroy: 6631500b9a0Sgarypen if (lflag && (*env)->ExceptionOccurred(env)) 6647c478bd9Sstevel@tonic-gate (*env)->ExceptionDescribe(env); 6657c478bd9Sstevel@tonic-gate pu_die(err_desc); 6667c478bd9Sstevel@tonic-gate } 667