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 57c478bd9Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 67c478bd9Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 77c478bd9Sstevel@tonic-gate * with the License. 87c478bd9Sstevel@tonic-gate * 97c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 107c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 117c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 127c478bd9Sstevel@tonic-gate * and limitations under the License. 137c478bd9Sstevel@tonic-gate * 147c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 157c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 167c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 177c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 187c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 197c478bd9Sstevel@tonic-gate * 207c478bd9Sstevel@tonic-gate * CDDL HEADER END 217c478bd9Sstevel@tonic-gate */ 227c478bd9Sstevel@tonic-gate /* 23*1500b9a0Sgarypen * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 247c478bd9Sstevel@tonic-gate * Use is subject to license terms. 257c478bd9Sstevel@tonic-gate */ 267c478bd9Sstevel@tonic-gate 277c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 287c478bd9Sstevel@tonic-gate 297c478bd9Sstevel@tonic-gate /* 307c478bd9Sstevel@tonic-gate * poold - dynamically adjust pool configuration according to load. 317c478bd9Sstevel@tonic-gate */ 327c478bd9Sstevel@tonic-gate #include <errno.h> 337c478bd9Sstevel@tonic-gate #include <jni.h> 347c478bd9Sstevel@tonic-gate #include <libintl.h> 357c478bd9Sstevel@tonic-gate #include <limits.h> 367c478bd9Sstevel@tonic-gate #include <link.h> 377c478bd9Sstevel@tonic-gate #include <locale.h> 387c478bd9Sstevel@tonic-gate #include <poll.h> 397c478bd9Sstevel@tonic-gate #include <pool.h> 407c478bd9Sstevel@tonic-gate #include <priv.h> 417c478bd9Sstevel@tonic-gate #include <pthread.h> 427c478bd9Sstevel@tonic-gate #include <signal.h> 437c478bd9Sstevel@tonic-gate #include <stdio.h> 447c478bd9Sstevel@tonic-gate #include <stdlib.h> 457c478bd9Sstevel@tonic-gate #include <string.h> 467c478bd9Sstevel@tonic-gate #include <syslog.h> 477c478bd9Sstevel@tonic-gate #include <unistd.h> 487c478bd9Sstevel@tonic-gate 497c478bd9Sstevel@tonic-gate #include <sys/stat.h> 507c478bd9Sstevel@tonic-gate #include <sys/types.h> 517c478bd9Sstevel@tonic-gate #include <sys/ucontext.h> 527c478bd9Sstevel@tonic-gate #include "utils.h" 537c478bd9Sstevel@tonic-gate 547c478bd9Sstevel@tonic-gate #define POOLD_DEF_CLASSPATH "/usr/lib/pool/JPool.jar" 557c478bd9Sstevel@tonic-gate #define POOLD_DEF_LIBPATH "/usr/lib/pool" 5626d8ba22Sgarypen #define SMF_SVC_INSTANCE "svc:/system/pools/dynamic:default" 577c478bd9Sstevel@tonic-gate 587c478bd9Sstevel@tonic-gate #if defined(sparc) 597c478bd9Sstevel@tonic-gate #define PLAT "sparc" 607c478bd9Sstevel@tonic-gate #else 617c478bd9Sstevel@tonic-gate #if defined(i386) 627c478bd9Sstevel@tonic-gate #define PLAT "i386" 637c478bd9Sstevel@tonic-gate #else 647c478bd9Sstevel@tonic-gate #error Unrecognized platform. 657c478bd9Sstevel@tonic-gate #endif 667c478bd9Sstevel@tonic-gate #endif 677c478bd9Sstevel@tonic-gate 687c478bd9Sstevel@tonic-gate #define CLASS_FIELD_DESC(class_desc) "L" class_desc ";" 697c478bd9Sstevel@tonic-gate 707c478bd9Sstevel@tonic-gate #define LEVEL_CLASS_DESC "java/util/logging/Level" 717c478bd9Sstevel@tonic-gate #define POOLD_CLASS_DESC "com/sun/solaris/domain/pools/Poold" 727c478bd9Sstevel@tonic-gate #define SEVERITY_CLASS_DESC "com/sun/solaris/service/logging/Severity" 737c478bd9Sstevel@tonic-gate #define STRING_CLASS_DESC "java/lang/String" 747c478bd9Sstevel@tonic-gate #define SYSTEM_CLASS_DESC "java/lang/System" 757c478bd9Sstevel@tonic-gate #define LOGGER_CLASS_DESC "java/util/logging/Logger" 767c478bd9Sstevel@tonic-gate 777c478bd9Sstevel@tonic-gate extern char *optarg; 787c478bd9Sstevel@tonic-gate 797c478bd9Sstevel@tonic-gate static const char *pname; 807c478bd9Sstevel@tonic-gate 817c478bd9Sstevel@tonic-gate static enum { 827c478bd9Sstevel@tonic-gate LD_TERMINAL = 1, 837c478bd9Sstevel@tonic-gate LD_SYSLOG, 847c478bd9Sstevel@tonic-gate LD_JAVA 857c478bd9Sstevel@tonic-gate } log_dest = LD_SYSLOG; 867c478bd9Sstevel@tonic-gate 877c478bd9Sstevel@tonic-gate static const char PNAME_FMT[] = "%s: "; 887c478bd9Sstevel@tonic-gate static const char ERRNO_FMT[] = ": %s"; 897c478bd9Sstevel@tonic-gate 90*1500b9a0Sgarypen static pthread_mutex_t jvm_lock = PTHREAD_MUTEX_INITIALIZER; 91*1500b9a0Sgarypen static JavaVM *jvm; /* protected by jvm_lock */ 92*1500b9a0Sgarypen static int instance_running; /* protected by jvm_lock */ 93*1500b9a0Sgarypen static int lflag; /* specifies poold logging mode */ 947c478bd9Sstevel@tonic-gate 957c478bd9Sstevel@tonic-gate static jmethodID log_mid; 967c478bd9Sstevel@tonic-gate static jobject severity_err; 977c478bd9Sstevel@tonic-gate static jobject severity_notice; 987c478bd9Sstevel@tonic-gate static jobject base_log; 997c478bd9Sstevel@tonic-gate static jclass poold_class; 1007c478bd9Sstevel@tonic-gate static jobject poold_instance; 1017c478bd9Sstevel@tonic-gate 1027c478bd9Sstevel@tonic-gate static sigset_t hdl_set; 1037c478bd9Sstevel@tonic-gate 104*1500b9a0Sgarypen static void pu_notice(const char *fmt, ...); 105414388d7Ssl108498 static void pu_die(const char *fmt, ...) __NORETURN; 106414388d7Ssl108498 1077c478bd9Sstevel@tonic-gate static void 1087c478bd9Sstevel@tonic-gate usage(void) 1097c478bd9Sstevel@tonic-gate { 1107c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext("Usage:\t%s [-l <level>]\n"), pname); 1117c478bd9Sstevel@tonic-gate 1127c478bd9Sstevel@tonic-gate exit(E_USAGE); 1137c478bd9Sstevel@tonic-gate } 1147c478bd9Sstevel@tonic-gate 1157c478bd9Sstevel@tonic-gate static void 116*1500b9a0Sgarypen check_thread_attached(JNIEnv **env) 117*1500b9a0Sgarypen { 118*1500b9a0Sgarypen int ret; 119*1500b9a0Sgarypen 120*1500b9a0Sgarypen ret = (*jvm)->GetEnv(jvm, (void **)env, JNI_VERSION_1_4); 121*1500b9a0Sgarypen if (*env == NULL) { 122*1500b9a0Sgarypen if (ret == JNI_EVERSION) { 123*1500b9a0Sgarypen /* 124*1500b9a0Sgarypen * Avoid recursively calling 125*1500b9a0Sgarypen * check_thread_attached() 126*1500b9a0Sgarypen */ 127*1500b9a0Sgarypen if (log_dest == LD_JAVA) 128*1500b9a0Sgarypen log_dest = LD_TERMINAL; 129*1500b9a0Sgarypen pu_notice(gettext("incorrect JNI version")); 130*1500b9a0Sgarypen exit(E_ERROR); 131*1500b9a0Sgarypen } 132*1500b9a0Sgarypen if ((*jvm)->AttachCurrentThreadAsDaemon(jvm, (void **)env, 133*1500b9a0Sgarypen NULL) != 0) { 134*1500b9a0Sgarypen /* 135*1500b9a0Sgarypen * Avoid recursively calling 136*1500b9a0Sgarypen * check_thread_attached() 137*1500b9a0Sgarypen */ 138*1500b9a0Sgarypen if (log_dest == LD_JAVA) 139*1500b9a0Sgarypen log_dest = LD_TERMINAL; 140*1500b9a0Sgarypen pu_notice(gettext("thread attach failed")); 141*1500b9a0Sgarypen exit(E_ERROR); 142*1500b9a0Sgarypen } 143*1500b9a0Sgarypen } 144*1500b9a0Sgarypen } 145*1500b9a0Sgarypen 146*1500b9a0Sgarypen /* 147*1500b9a0Sgarypen * Output a message to the designated logging destination. 148*1500b9a0Sgarypen * 149*1500b9a0Sgarypen * severity - Specified the severity level when using LD_JAVA logging 150*1500b9a0Sgarypen * fmt - specified the format of the output message 151*1500b9a0Sgarypen * alist - varargs used in the output message 152*1500b9a0Sgarypen */ 153*1500b9a0Sgarypen static void 1547c478bd9Sstevel@tonic-gate pu_output(int severity, const char *fmt, va_list alist) 1557c478bd9Sstevel@tonic-gate { 1567c478bd9Sstevel@tonic-gate int err = errno; 1577c478bd9Sstevel@tonic-gate char line[255] = ""; 1587c478bd9Sstevel@tonic-gate jobject jseverity; 1597c478bd9Sstevel@tonic-gate jobject jline; 160*1500b9a0Sgarypen JNIEnv *env = NULL; 161*1500b9a0Sgarypen 1627c478bd9Sstevel@tonic-gate if (pname != NULL && log_dest == LD_TERMINAL) 1637c478bd9Sstevel@tonic-gate (void) snprintf(line, sizeof (line), gettext(PNAME_FMT), pname); 1647c478bd9Sstevel@tonic-gate 1657c478bd9Sstevel@tonic-gate (void) vsnprintf(line + strlen(line), sizeof (line) - strlen(line), 1667c478bd9Sstevel@tonic-gate fmt, alist); 1677c478bd9Sstevel@tonic-gate 1687c478bd9Sstevel@tonic-gate if (line[strlen(line) - 1] != '\n') 1697c478bd9Sstevel@tonic-gate (void) snprintf(line + strlen(line), sizeof (line) - 1707c478bd9Sstevel@tonic-gate strlen(line), gettext(ERRNO_FMT), strerror(err)); 1717c478bd9Sstevel@tonic-gate else 1727c478bd9Sstevel@tonic-gate line[strlen(line) - 1] = 0; 1737c478bd9Sstevel@tonic-gate 1747c478bd9Sstevel@tonic-gate switch (log_dest) { 1757c478bd9Sstevel@tonic-gate case LD_TERMINAL: 1767c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "%s\n", line); 1777c478bd9Sstevel@tonic-gate (void) fflush(stderr); 1787c478bd9Sstevel@tonic-gate break; 1797c478bd9Sstevel@tonic-gate case LD_SYSLOG: 1807c478bd9Sstevel@tonic-gate syslog(LOG_ERR, "%s", line); 1817c478bd9Sstevel@tonic-gate break; 1827c478bd9Sstevel@tonic-gate case LD_JAVA: 1837c478bd9Sstevel@tonic-gate if (severity == LOG_ERR) 1847c478bd9Sstevel@tonic-gate jseverity = severity_err; 1857c478bd9Sstevel@tonic-gate else 1867c478bd9Sstevel@tonic-gate jseverity = severity_notice; 1877c478bd9Sstevel@tonic-gate 1887c478bd9Sstevel@tonic-gate if (jvm) { 189*1500b9a0Sgarypen check_thread_attached(&env); 1907c478bd9Sstevel@tonic-gate if ((jline = (*env)->NewStringUTF(env, line)) != NULL) 1917c478bd9Sstevel@tonic-gate (*env)->CallVoidMethod(env, base_log, log_mid, 1927c478bd9Sstevel@tonic-gate jseverity, jline); 1937c478bd9Sstevel@tonic-gate } 1947c478bd9Sstevel@tonic-gate } 1957c478bd9Sstevel@tonic-gate } 1967c478bd9Sstevel@tonic-gate 197*1500b9a0Sgarypen /* 198*1500b9a0Sgarypen * Notify the user with the supplied message. 199*1500b9a0Sgarypen */ 2007c478bd9Sstevel@tonic-gate /*PRINTFLIKE1*/ 2017c478bd9Sstevel@tonic-gate static void 2027c478bd9Sstevel@tonic-gate pu_notice(const char *fmt, ...) 2037c478bd9Sstevel@tonic-gate { 2047c478bd9Sstevel@tonic-gate va_list alist; 205*1500b9a0Sgarypen 2067c478bd9Sstevel@tonic-gate va_start(alist, fmt); 2077c478bd9Sstevel@tonic-gate pu_output(LOG_NOTICE, fmt, alist); 2087c478bd9Sstevel@tonic-gate va_end(alist); 2097c478bd9Sstevel@tonic-gate } 2107c478bd9Sstevel@tonic-gate 211*1500b9a0Sgarypen /* 212*1500b9a0Sgarypen * Stop the application executing inside the JVM. Always ensure that jvm_lock 213*1500b9a0Sgarypen * is held before invoking this function. 214*1500b9a0Sgarypen */ 215*1500b9a0Sgarypen static void 216*1500b9a0Sgarypen halt_application(void) 217*1500b9a0Sgarypen { 218*1500b9a0Sgarypen JNIEnv *env = NULL; 219*1500b9a0Sgarypen jmethodID poold_shutdown_mid; 220*1500b9a0Sgarypen 221*1500b9a0Sgarypen if (jvm && instance_running) { 222*1500b9a0Sgarypen check_thread_attached(&env); 223*1500b9a0Sgarypen if ((poold_shutdown_mid = (*env)->GetMethodID( 224*1500b9a0Sgarypen env, poold_class, "shutdown", "()V")) != NULL) { 225*1500b9a0Sgarypen (*env)->CallVoidMethod(env, poold_instance, 226*1500b9a0Sgarypen poold_shutdown_mid); 227*1500b9a0Sgarypen } else { 228*1500b9a0Sgarypen if (lflag && (*env)->ExceptionOccurred(env)) { 229*1500b9a0Sgarypen (*env)->ExceptionDescribe(env); 230*1500b9a0Sgarypen pu_notice("could not invoke proper shutdown\n"); 231*1500b9a0Sgarypen } 232*1500b9a0Sgarypen } 233*1500b9a0Sgarypen instance_running = 0; 234*1500b9a0Sgarypen } 235*1500b9a0Sgarypen } 236*1500b9a0Sgarypen 237*1500b9a0Sgarypen /* 238*1500b9a0Sgarypen * Warn the user with the supplied error message, halt the application, 239*1500b9a0Sgarypen * destroy the JVM and then exit the process. 240*1500b9a0Sgarypen */ 2417c478bd9Sstevel@tonic-gate /*PRINTFLIKE1*/ 2427c478bd9Sstevel@tonic-gate static void 2437c478bd9Sstevel@tonic-gate pu_die(const char *fmt, ...) 2447c478bd9Sstevel@tonic-gate { 2457c478bd9Sstevel@tonic-gate va_list alist; 246*1500b9a0Sgarypen 2477c478bd9Sstevel@tonic-gate va_start(alist, fmt); 2487c478bd9Sstevel@tonic-gate pu_output(LOG_ERR, fmt, alist); 2497c478bd9Sstevel@tonic-gate va_end(alist); 250*1500b9a0Sgarypen halt_application(); 251*1500b9a0Sgarypen if (jvm) { 252*1500b9a0Sgarypen (*jvm)->DestroyJavaVM(jvm); 253*1500b9a0Sgarypen jvm = NULL; 254*1500b9a0Sgarypen } 2557c478bd9Sstevel@tonic-gate exit(E_ERROR); 2567c478bd9Sstevel@tonic-gate } 2577c478bd9Sstevel@tonic-gate 2587c478bd9Sstevel@tonic-gate /* 259*1500b9a0Sgarypen * Warn the user with the supplied error message and halt the 260*1500b9a0Sgarypen * application. This function is very similar to pu_die(). However, 261*1500b9a0Sgarypen * this function is designed to be called from the signal handling 262*1500b9a0Sgarypen * routine (handle_sig()) where although we wish to let the user know 263*1500b9a0Sgarypen * that an error has occurred, we do not wish to destroy the JVM or 264*1500b9a0Sgarypen * exit the process. 2657c478bd9Sstevel@tonic-gate */ 266*1500b9a0Sgarypen /*PRINTFLIKE1*/ 2677c478bd9Sstevel@tonic-gate static void 268*1500b9a0Sgarypen pu_terminate(const char *fmt, ...) 2697c478bd9Sstevel@tonic-gate { 270*1500b9a0Sgarypen va_list alist; 2717c478bd9Sstevel@tonic-gate 272*1500b9a0Sgarypen va_start(alist, fmt); 273*1500b9a0Sgarypen pu_output(LOG_ERR, fmt, alist); 274*1500b9a0Sgarypen va_end(alist); 275*1500b9a0Sgarypen halt_application(); 2767c478bd9Sstevel@tonic-gate } 2777c478bd9Sstevel@tonic-gate 2787c478bd9Sstevel@tonic-gate /* 2797c478bd9Sstevel@tonic-gate * If SIGHUP is invoked, we should just re-initialize poold. Since 2807c478bd9Sstevel@tonic-gate * there is no easy way to determine when it's safe to re-initialzie 2817c478bd9Sstevel@tonic-gate * poold, simply update a dummy property on the system element to 2827c478bd9Sstevel@tonic-gate * force pool_conf_update() to detect a change. 2837c478bd9Sstevel@tonic-gate * 2847c478bd9Sstevel@tonic-gate * Both SIGTERM and SIGINT are interpreted as instructions to 2857c478bd9Sstevel@tonic-gate * shutdown. 2867c478bd9Sstevel@tonic-gate */ 2877c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 2887c478bd9Sstevel@tonic-gate static void * 2897c478bd9Sstevel@tonic-gate handle_sig(void *arg) 2907c478bd9Sstevel@tonic-gate { 291*1500b9a0Sgarypen pool_conf_t *conf = NULL; 292*1500b9a0Sgarypen pool_elem_t *pe; 293*1500b9a0Sgarypen pool_value_t *val; 294*1500b9a0Sgarypen const char *err_desc; 295*1500b9a0Sgarypen int keep_handling = 1; 296*1500b9a0Sgarypen 297*1500b9a0Sgarypen while (keep_handling) { 2987c478bd9Sstevel@tonic-gate int sig; 2997c478bd9Sstevel@tonic-gate char buf[SIG2STR_MAX]; 3007c478bd9Sstevel@tonic-gate 30126d8ba22Sgarypen if ((sig = sigwait(&hdl_set)) < 0) { 30226d8ba22Sgarypen /* 30326d8ba22Sgarypen * We used forkall() previously to ensure that 30426d8ba22Sgarypen * all threads started by the JVM are 30526d8ba22Sgarypen * duplicated in the child. Since forkall() 30626d8ba22Sgarypen * can cause blocking system calls to be 30726d8ba22Sgarypen * interrupted, check to see if the errno is 30826d8ba22Sgarypen * EINTR and if it is wait again. 30926d8ba22Sgarypen */ 31026d8ba22Sgarypen if (errno == EINTR) 311*1500b9a0Sgarypen continue; 312*1500b9a0Sgarypen (void) pthread_mutex_lock(&jvm_lock); 313*1500b9a0Sgarypen pu_terminate("unexpected error: %d\n", errno); 314*1500b9a0Sgarypen keep_handling = 0; 315*1500b9a0Sgarypen } else 316*1500b9a0Sgarypen (void) pthread_mutex_lock(&jvm_lock); 3177c478bd9Sstevel@tonic-gate (void) sig2str(sig, buf); 3187c478bd9Sstevel@tonic-gate switch (sig) { 3197c478bd9Sstevel@tonic-gate case SIGHUP: 320*1500b9a0Sgarypen if ((conf = pool_conf_alloc()) == NULL) { 321*1500b9a0Sgarypen err_desc = pool_strerror(pool_error()); 322*1500b9a0Sgarypen goto destroy; 323*1500b9a0Sgarypen } 324*1500b9a0Sgarypen if (pool_conf_open(conf, pool_dynamic_location(), 325*1500b9a0Sgarypen PO_RDWR) != 0) { 326*1500b9a0Sgarypen err_desc = pool_strerror(pool_error()); 327*1500b9a0Sgarypen goto destroy; 328*1500b9a0Sgarypen } 329*1500b9a0Sgarypen 330*1500b9a0Sgarypen if ((val = pool_value_alloc()) == NULL) { 331*1500b9a0Sgarypen err_desc = pool_strerror(pool_error()); 332*1500b9a0Sgarypen goto destroy; 333*1500b9a0Sgarypen } 334*1500b9a0Sgarypen pe = pool_conf_to_elem(conf); 335*1500b9a0Sgarypen pool_value_set_bool(val, 1); 336*1500b9a0Sgarypen if (pool_put_property(conf, pe, "system.poold.sighup", 337*1500b9a0Sgarypen val) != PO_SUCCESS) { 338*1500b9a0Sgarypen err_desc = pool_strerror(pool_error()); 339*1500b9a0Sgarypen pool_value_free(val); 340*1500b9a0Sgarypen goto destroy; 341*1500b9a0Sgarypen } 342*1500b9a0Sgarypen pool_value_free(val); 343*1500b9a0Sgarypen (void) pool_rm_property(conf, pe, 344*1500b9a0Sgarypen "system.poold.sighup"); 345*1500b9a0Sgarypen if (pool_conf_commit(conf, 0) != PO_SUCCESS) { 346*1500b9a0Sgarypen err_desc = pool_strerror(pool_error()); 347*1500b9a0Sgarypen goto destroy; 348*1500b9a0Sgarypen } 349*1500b9a0Sgarypen break; 350*1500b9a0Sgarypen destroy: 351*1500b9a0Sgarypen if (conf) { 352*1500b9a0Sgarypen (void) pool_conf_close(conf); 353*1500b9a0Sgarypen pool_conf_free(conf); 354*1500b9a0Sgarypen } 355*1500b9a0Sgarypen pu_terminate(err_desc); 356*1500b9a0Sgarypen keep_handling = 0; 3577c478bd9Sstevel@tonic-gate break; 3587c478bd9Sstevel@tonic-gate case SIGINT: 3597c478bd9Sstevel@tonic-gate case SIGTERM: 3607c478bd9Sstevel@tonic-gate default: 361*1500b9a0Sgarypen pu_terminate("terminating due to signal: SIG%s\n", buf); 362*1500b9a0Sgarypen keep_handling = 0; 363*1500b9a0Sgarypen break; 3647c478bd9Sstevel@tonic-gate } 365*1500b9a0Sgarypen (void) pthread_mutex_unlock(&jvm_lock); 3667c478bd9Sstevel@tonic-gate } 367*1500b9a0Sgarypen pthread_exit(NULL); 3687c478bd9Sstevel@tonic-gate /*NOTREACHED*/ 3697c478bd9Sstevel@tonic-gate return (NULL); 3707c478bd9Sstevel@tonic-gate } 3717c478bd9Sstevel@tonic-gate 372*1500b9a0Sgarypen /* 373*1500b9a0Sgarypen * Return the name of the process 374*1500b9a0Sgarypen */ 3757c478bd9Sstevel@tonic-gate static const char * 3767c478bd9Sstevel@tonic-gate pu_getpname(const char *arg0) 3777c478bd9Sstevel@tonic-gate { 3787c478bd9Sstevel@tonic-gate char *p; 3797c478bd9Sstevel@tonic-gate 3807c478bd9Sstevel@tonic-gate /* 3817c478bd9Sstevel@tonic-gate * Guard against '/' at end of command invocation. 3827c478bd9Sstevel@tonic-gate */ 3837c478bd9Sstevel@tonic-gate for (;;) { 3847c478bd9Sstevel@tonic-gate p = strrchr(arg0, '/'); 3857c478bd9Sstevel@tonic-gate if (p == NULL) { 3867c478bd9Sstevel@tonic-gate pname = arg0; 3877c478bd9Sstevel@tonic-gate break; 3887c478bd9Sstevel@tonic-gate } else { 3897c478bd9Sstevel@tonic-gate if (*(p + 1) == '\0') { 3907c478bd9Sstevel@tonic-gate *p = '\0'; 3917c478bd9Sstevel@tonic-gate continue; 3927c478bd9Sstevel@tonic-gate } 3937c478bd9Sstevel@tonic-gate 3947c478bd9Sstevel@tonic-gate pname = p + 1; 3957c478bd9Sstevel@tonic-gate break; 3967c478bd9Sstevel@tonic-gate } 3977c478bd9Sstevel@tonic-gate } 3987c478bd9Sstevel@tonic-gate 3997c478bd9Sstevel@tonic-gate return (pname); 4007c478bd9Sstevel@tonic-gate } 4017c478bd9Sstevel@tonic-gate 4027c478bd9Sstevel@tonic-gate int 4037c478bd9Sstevel@tonic-gate main(int argc, char *argv[]) 4047c478bd9Sstevel@tonic-gate { 4057c478bd9Sstevel@tonic-gate char c; 4067c478bd9Sstevel@tonic-gate char log_severity[16] = ""; 4077c478bd9Sstevel@tonic-gate JavaVMInitArgs vm_args; 4087c478bd9Sstevel@tonic-gate JavaVMOption vm_opts[5]; 4097c478bd9Sstevel@tonic-gate int nopts = 0; 4107c478bd9Sstevel@tonic-gate const char *classpath; 4117c478bd9Sstevel@tonic-gate const char *libpath; 4127c478bd9Sstevel@tonic-gate size_t len; 4137c478bd9Sstevel@tonic-gate const char *err_desc; 4147c478bd9Sstevel@tonic-gate JNIEnv *env; 4157c478bd9Sstevel@tonic-gate jmethodID poold_getinstancewcl_mid; 4167c478bd9Sstevel@tonic-gate jmethodID poold_run_mid; 4177c478bd9Sstevel@tonic-gate jobject log_severity_string = NULL; 4187c478bd9Sstevel@tonic-gate jobject log_severity_obj = NULL; 4197c478bd9Sstevel@tonic-gate jclass severity_class; 4207c478bd9Sstevel@tonic-gate jmethodID severity_cons_mid; 4217c478bd9Sstevel@tonic-gate jfieldID base_log_fid; 4227c478bd9Sstevel@tonic-gate pthread_t hdl_thread; 42326d8ba22Sgarypen FILE *p; 4247c478bd9Sstevel@tonic-gate 425*1500b9a0Sgarypen (void) pthread_mutex_lock(&jvm_lock); 4267c478bd9Sstevel@tonic-gate pname = pu_getpname(argv[0]); 4277c478bd9Sstevel@tonic-gate openlog(pname, 0, LOG_DAEMON); 4287c478bd9Sstevel@tonic-gate (void) chdir("/"); 4297c478bd9Sstevel@tonic-gate 4307c478bd9Sstevel@tonic-gate (void) setlocale(LC_ALL, ""); 4317c478bd9Sstevel@tonic-gate #if !defined(TEXT_DOMAIN) /* Should be defined with cc -D. */ 4327c478bd9Sstevel@tonic-gate #define TEXT_DOMAIN "SYS_TEST" /* Use this only if it wasn't. */ 4337c478bd9Sstevel@tonic-gate #endif 4347c478bd9Sstevel@tonic-gate (void) textdomain(TEXT_DOMAIN); 4357c478bd9Sstevel@tonic-gate 4367c478bd9Sstevel@tonic-gate opterr = 0; 4377c478bd9Sstevel@tonic-gate while ((c = getopt(argc, argv, "l:P")) != EOF) { 4387c478bd9Sstevel@tonic-gate switch (c) { 4397c478bd9Sstevel@tonic-gate case 'l': /* -l option */ 4407c478bd9Sstevel@tonic-gate lflag++; 4417c478bd9Sstevel@tonic-gate (void) strlcpy(log_severity, optarg, 4427c478bd9Sstevel@tonic-gate sizeof (log_severity)); 4437c478bd9Sstevel@tonic-gate log_dest = LD_TERMINAL; 4447c478bd9Sstevel@tonic-gate break; 4457c478bd9Sstevel@tonic-gate default: 4467c478bd9Sstevel@tonic-gate usage(); 4477c478bd9Sstevel@tonic-gate /*NOTREACHED*/ 4487c478bd9Sstevel@tonic-gate } 4497c478bd9Sstevel@tonic-gate } 4507c478bd9Sstevel@tonic-gate 4517c478bd9Sstevel@tonic-gate /* 4527c478bd9Sstevel@tonic-gate * Check permission 4537c478bd9Sstevel@tonic-gate */ 4547c478bd9Sstevel@tonic-gate if (!priv_ineffect(PRIV_SYS_RES_CONFIG)) 4557c478bd9Sstevel@tonic-gate pu_die(gettext(ERR_PRIVILEGE), PRIV_SYS_RES_CONFIG); 4567c478bd9Sstevel@tonic-gate 4577c478bd9Sstevel@tonic-gate /* 45826d8ba22Sgarypen * In order to avoid problems with arbitrary thread selection 45926d8ba22Sgarypen * when handling asynchronous signals, dedicate a thread to 46026d8ba22Sgarypen * look after these signals. 46126d8ba22Sgarypen */ 46226d8ba22Sgarypen if (sigemptyset(&hdl_set) < 0 || 46326d8ba22Sgarypen sigaddset(&hdl_set, SIGHUP) < 0 || 46426d8ba22Sgarypen sigaddset(&hdl_set, SIGTERM) < 0 || 46526d8ba22Sgarypen sigaddset(&hdl_set, SIGINT) < 0 || 46626d8ba22Sgarypen pthread_sigmask(SIG_BLOCK, &hdl_set, NULL) || 46726d8ba22Sgarypen pthread_create(&hdl_thread, NULL, handle_sig, NULL)) 46826d8ba22Sgarypen pu_die(gettext("can't install signal handler")); 46926d8ba22Sgarypen 47026d8ba22Sgarypen /* 47126d8ba22Sgarypen * If the -l flag is supplied, terminate the SMF service and 47226d8ba22Sgarypen * run interactively from the command line. 47326d8ba22Sgarypen */ 47426d8ba22Sgarypen if (lflag) { 47526d8ba22Sgarypen char *cmd = "/usr/sbin/svcadm disable -st " SMF_SVC_INSTANCE; 47626d8ba22Sgarypen 47726d8ba22Sgarypen if (getenv("SMF_FMRI") != NULL) 47826d8ba22Sgarypen pu_die("-l option illegal: %s\n", SMF_SVC_INSTANCE); 47926d8ba22Sgarypen /* 48026d8ba22Sgarypen * Since disabling a service isn't synchronous, use the 48126d8ba22Sgarypen * synchronous option from svcadm to achieve synchronous 48226d8ba22Sgarypen * behaviour. 48326d8ba22Sgarypen * This is not very satisfactory, but since this is only 48426d8ba22Sgarypen * for use in debugging scenarios, it will do until there 48526d8ba22Sgarypen * is a C API to synchronously shutdown a service in SMF. 48626d8ba22Sgarypen */ 48726d8ba22Sgarypen if ((p = popen(cmd, "w")) == NULL || pclose(p) != 0) 48826d8ba22Sgarypen pu_die("could not temporarily disable service: %s\n", 48926d8ba22Sgarypen SMF_SVC_INSTANCE); 49026d8ba22Sgarypen } else { 49126d8ba22Sgarypen /* 49226d8ba22Sgarypen * Check if we are running as a SMF service. If we 49326d8ba22Sgarypen * aren't, terminate this process after enabling the 49426d8ba22Sgarypen * service. 49526d8ba22Sgarypen */ 49626d8ba22Sgarypen if (getenv("SMF_FMRI") == NULL) { 49726d8ba22Sgarypen char *cmd = "/usr/sbin/svcadm enable -s " \ 49826d8ba22Sgarypen SMF_SVC_INSTANCE; 49926d8ba22Sgarypen if ((p = popen(cmd, "w")) == NULL || pclose(p) != 0) 50026d8ba22Sgarypen pu_die("could not enable " 50126d8ba22Sgarypen "service: %s\n", SMF_SVC_INSTANCE); 50226d8ba22Sgarypen return (E_PO_SUCCESS); 50326d8ba22Sgarypen } 50426d8ba22Sgarypen } 50526d8ba22Sgarypen 50626d8ba22Sgarypen /* 5077c478bd9Sstevel@tonic-gate * Establish the classpath and LD_LIBRARY_PATH for native 5087c478bd9Sstevel@tonic-gate * methods, and get the interpreter going. 5097c478bd9Sstevel@tonic-gate */ 5107c478bd9Sstevel@tonic-gate if ((classpath = getenv("POOLD_CLASSPATH")) == NULL) { 5117c478bd9Sstevel@tonic-gate classpath = POOLD_DEF_CLASSPATH; 5127c478bd9Sstevel@tonic-gate } else { 5137c478bd9Sstevel@tonic-gate const char *cur = classpath; 5147c478bd9Sstevel@tonic-gate 5157c478bd9Sstevel@tonic-gate /* 5167c478bd9Sstevel@tonic-gate * Check the components to make sure they're absolute 5177c478bd9Sstevel@tonic-gate * paths. 5187c478bd9Sstevel@tonic-gate */ 5197c478bd9Sstevel@tonic-gate while (cur != NULL && *cur) { 5207c478bd9Sstevel@tonic-gate if (*cur != '/') 5217c478bd9Sstevel@tonic-gate pu_die(gettext( 5227c478bd9Sstevel@tonic-gate "POOLD_CLASSPATH must contain absolute " 5237c478bd9Sstevel@tonic-gate "components\n")); 5247c478bd9Sstevel@tonic-gate cur = strchr(cur + 1, ':'); 5257c478bd9Sstevel@tonic-gate } 5267c478bd9Sstevel@tonic-gate } 5277c478bd9Sstevel@tonic-gate vm_opts[nopts].optionString = malloc(len = strlen(classpath) + 5287c478bd9Sstevel@tonic-gate strlen("-Djava.class.path=") + 1); 5297c478bd9Sstevel@tonic-gate (void) strlcpy(vm_opts[nopts].optionString, "-Djava.class.path=", len); 5307c478bd9Sstevel@tonic-gate (void) strlcat(vm_opts[nopts++].optionString, classpath, len); 5317c478bd9Sstevel@tonic-gate 5327c478bd9Sstevel@tonic-gate if ((libpath = getenv("POOLD_LD_LIBRARY_PATH")) == NULL) 5337c478bd9Sstevel@tonic-gate libpath = POOLD_DEF_LIBPATH; 5347c478bd9Sstevel@tonic-gate vm_opts[nopts].optionString = malloc(len = strlen(libpath) + 5357c478bd9Sstevel@tonic-gate strlen("-Djava.library.path=") + 1); 5367c478bd9Sstevel@tonic-gate (void) strlcpy(vm_opts[nopts].optionString, "-Djava.library.path=", 5377c478bd9Sstevel@tonic-gate len); 5387c478bd9Sstevel@tonic-gate (void) strlcat(vm_opts[nopts++].optionString, libpath, len); 5397c478bd9Sstevel@tonic-gate 5407c478bd9Sstevel@tonic-gate vm_opts[nopts++].optionString = "-Xrs"; 5417c478bd9Sstevel@tonic-gate vm_opts[nopts++].optionString = "-enableassertions"; 5427c478bd9Sstevel@tonic-gate 5437c478bd9Sstevel@tonic-gate vm_args.options = vm_opts; 5447c478bd9Sstevel@tonic-gate vm_args.nOptions = nopts; 5457c478bd9Sstevel@tonic-gate vm_args.ignoreUnrecognized = JNI_FALSE; 5467c478bd9Sstevel@tonic-gate vm_args.version = 0x00010002; 5477c478bd9Sstevel@tonic-gate 548*1500b9a0Sgarypen if (JNI_CreateJavaVM(&jvm, (void **)&env, &vm_args) < 0) 5497c478bd9Sstevel@tonic-gate pu_die(gettext("can't create Java VM")); 5507c478bd9Sstevel@tonic-gate 5517c478bd9Sstevel@tonic-gate /* 5527c478bd9Sstevel@tonic-gate * Locate the Poold class and construct an instance. A side 5537c478bd9Sstevel@tonic-gate * effect of this is that the poold instance's logHelper will be 5547c478bd9Sstevel@tonic-gate * initialized, establishing loggers for logging errors from 5557c478bd9Sstevel@tonic-gate * this point on. (Note, in the event of an unanticipated 5567c478bd9Sstevel@tonic-gate * exception, poold will invoke die() itself.) 5577c478bd9Sstevel@tonic-gate */ 5587c478bd9Sstevel@tonic-gate err_desc = gettext("JVM-related error initializing poold\n"); 5597c478bd9Sstevel@tonic-gate if ((poold_class = (*env)->FindClass(env, POOLD_CLASS_DESC)) == NULL) 5607c478bd9Sstevel@tonic-gate goto destroy; 5617c478bd9Sstevel@tonic-gate if ((poold_getinstancewcl_mid = (*env)->GetStaticMethodID(env, 5627c478bd9Sstevel@tonic-gate poold_class, "getInstanceWithConsoleLogging", "(" 5637c478bd9Sstevel@tonic-gate CLASS_FIELD_DESC(SEVERITY_CLASS_DESC) ")" 5647c478bd9Sstevel@tonic-gate CLASS_FIELD_DESC(POOLD_CLASS_DESC))) == NULL) 5657c478bd9Sstevel@tonic-gate goto destroy; 5667c478bd9Sstevel@tonic-gate if ((poold_run_mid = (*env)->GetMethodID(env, poold_class, "run", 5677c478bd9Sstevel@tonic-gate "()V")) == NULL) 5687c478bd9Sstevel@tonic-gate goto destroy; 5697c478bd9Sstevel@tonic-gate if ((severity_class = (*env)->FindClass(env, SEVERITY_CLASS_DESC)) 5707c478bd9Sstevel@tonic-gate == NULL) 5717c478bd9Sstevel@tonic-gate goto destroy; 5727c478bd9Sstevel@tonic-gate if ((severity_cons_mid = (*env)->GetStaticMethodID(env, severity_class, 5737c478bd9Sstevel@tonic-gate "getSeverityWithName", "(" CLASS_FIELD_DESC(STRING_CLASS_DESC) ")" 5747c478bd9Sstevel@tonic-gate CLASS_FIELD_DESC(SEVERITY_CLASS_DESC))) == NULL) 5757c478bd9Sstevel@tonic-gate goto destroy; 5767c478bd9Sstevel@tonic-gate 5777c478bd9Sstevel@tonic-gate /* 5787c478bd9Sstevel@tonic-gate * -l <level> was specified, indicating that messages are to be 5797c478bd9Sstevel@tonic-gate * logged to the console only. 5807c478bd9Sstevel@tonic-gate */ 5817c478bd9Sstevel@tonic-gate if (strlen(log_severity) > 0) { 5827c478bd9Sstevel@tonic-gate if ((log_severity_string = (*env)->NewStringUTF(env, 5837c478bd9Sstevel@tonic-gate log_severity)) == NULL) 5847c478bd9Sstevel@tonic-gate goto destroy; 5857c478bd9Sstevel@tonic-gate if ((log_severity_obj = (*env)->CallStaticObjectMethod(env, 5867c478bd9Sstevel@tonic-gate severity_class, severity_cons_mid, log_severity_string)) == 5877c478bd9Sstevel@tonic-gate NULL) { 5887c478bd9Sstevel@tonic-gate err_desc = gettext("invalid level specified\n"); 5897c478bd9Sstevel@tonic-gate goto destroy; 5907c478bd9Sstevel@tonic-gate } 5917c478bd9Sstevel@tonic-gate } else 5927c478bd9Sstevel@tonic-gate log_severity_obj = NULL; 5937c478bd9Sstevel@tonic-gate 5947c478bd9Sstevel@tonic-gate if ((poold_instance = (*env)->CallStaticObjectMethod(env, poold_class, 5957c478bd9Sstevel@tonic-gate poold_getinstancewcl_mid, log_severity_obj)) == NULL) 5967c478bd9Sstevel@tonic-gate goto destroy; 5977c478bd9Sstevel@tonic-gate 5987c478bd9Sstevel@tonic-gate /* 5997c478bd9Sstevel@tonic-gate * Grab a global reference to poold for use in our signal 6007c478bd9Sstevel@tonic-gate * handlers. 6017c478bd9Sstevel@tonic-gate */ 6027c478bd9Sstevel@tonic-gate poold_instance = (*env)->NewGlobalRef(env, poold_instance); 6037c478bd9Sstevel@tonic-gate 6047c478bd9Sstevel@tonic-gate /* 6057c478bd9Sstevel@tonic-gate * Ready LD_JAVA logging. 6067c478bd9Sstevel@tonic-gate */ 6077c478bd9Sstevel@tonic-gate err_desc = gettext("cannot initialize logging\n"); 6087c478bd9Sstevel@tonic-gate if ((log_severity_string = (*env)->NewStringUTF(env, "err")) == NULL) 6097c478bd9Sstevel@tonic-gate goto destroy; 6107c478bd9Sstevel@tonic-gate if (!(severity_err = (*env)->CallStaticObjectMethod(env, severity_class, 6117c478bd9Sstevel@tonic-gate severity_cons_mid, log_severity_string))) 6127c478bd9Sstevel@tonic-gate goto destroy; 6137c478bd9Sstevel@tonic-gate if (!(severity_err = (*env)->NewGlobalRef(env, severity_err))) 6147c478bd9Sstevel@tonic-gate goto destroy; 6157c478bd9Sstevel@tonic-gate 6167c478bd9Sstevel@tonic-gate if ((log_severity_string = (*env)->NewStringUTF(env, "notice")) == NULL) 6177c478bd9Sstevel@tonic-gate goto destroy; 6187c478bd9Sstevel@tonic-gate if (!(severity_notice = (*env)->CallStaticObjectMethod(env, 6197c478bd9Sstevel@tonic-gate severity_class, severity_cons_mid, log_severity_string))) 6207c478bd9Sstevel@tonic-gate goto destroy; 6217c478bd9Sstevel@tonic-gate if (!(severity_notice = (*env)->NewGlobalRef(env, severity_notice))) 6227c478bd9Sstevel@tonic-gate goto destroy; 6237c478bd9Sstevel@tonic-gate 6247c478bd9Sstevel@tonic-gate if (!(base_log_fid = (*env)->GetStaticFieldID(env, poold_class, 6257c478bd9Sstevel@tonic-gate "BASE_LOG", CLASS_FIELD_DESC(LOGGER_CLASS_DESC)))) 6267c478bd9Sstevel@tonic-gate goto destroy; 6277c478bd9Sstevel@tonic-gate if (!(base_log = (*env)->GetStaticObjectField(env, poold_class, 6287c478bd9Sstevel@tonic-gate base_log_fid))) 6297c478bd9Sstevel@tonic-gate goto destroy; 6307c478bd9Sstevel@tonic-gate if (!(base_log = (*env)->NewGlobalRef(env, base_log))) 6317c478bd9Sstevel@tonic-gate goto destroy; 6327c478bd9Sstevel@tonic-gate if (!(log_mid = (*env)->GetMethodID(env, (*env)->GetObjectClass(env, 6337c478bd9Sstevel@tonic-gate base_log), "log", "(" CLASS_FIELD_DESC(LEVEL_CLASS_DESC) 6347c478bd9Sstevel@tonic-gate CLASS_FIELD_DESC(STRING_CLASS_DESC) ")V"))) 6357c478bd9Sstevel@tonic-gate goto destroy; 6367c478bd9Sstevel@tonic-gate log_dest = LD_JAVA; 6377c478bd9Sstevel@tonic-gate 6387c478bd9Sstevel@tonic-gate /* 63926d8ba22Sgarypen * If invoked directly and -l is specified, forking is not 64026d8ba22Sgarypen * desired. 6417c478bd9Sstevel@tonic-gate */ 64226d8ba22Sgarypen if (!lflag) 64326d8ba22Sgarypen switch (forkall()) { 64426d8ba22Sgarypen case 0: 64526d8ba22Sgarypen (void) setsid(); 64626d8ba22Sgarypen (void) fclose(stdin); 64726d8ba22Sgarypen (void) fclose(stdout); 64826d8ba22Sgarypen (void) fclose(stderr); 64926d8ba22Sgarypen break; 65026d8ba22Sgarypen case -1: 65126d8ba22Sgarypen pu_die(gettext("cannot fork")); 65226d8ba22Sgarypen /*NOTREACHED*/ 65326d8ba22Sgarypen default: 65426d8ba22Sgarypen return (E_PO_SUCCESS); 65526d8ba22Sgarypen } 6567c478bd9Sstevel@tonic-gate 6577c478bd9Sstevel@tonic-gate instance_running = 1; 658*1500b9a0Sgarypen (void) pthread_mutex_unlock(&jvm_lock); 659*1500b9a0Sgarypen 6607c478bd9Sstevel@tonic-gate (*env)->CallVoidMethod(env, poold_instance, poold_run_mid); 6617c478bd9Sstevel@tonic-gate 662*1500b9a0Sgarypen (void) pthread_mutex_lock(&jvm_lock); 663*1500b9a0Sgarypen if ((*env)->ExceptionOccurred(env)) { 6647c478bd9Sstevel@tonic-gate goto destroy; 665*1500b9a0Sgarypen } 666*1500b9a0Sgarypen if (jvm) { 6677c478bd9Sstevel@tonic-gate (*jvm)->DestroyJavaVM(jvm); 668*1500b9a0Sgarypen jvm = NULL; 669*1500b9a0Sgarypen } 670*1500b9a0Sgarypen (void) pthread_mutex_unlock(&jvm_lock); 6717c478bd9Sstevel@tonic-gate return (E_PO_SUCCESS); 6727c478bd9Sstevel@tonic-gate 6737c478bd9Sstevel@tonic-gate destroy: 674*1500b9a0Sgarypen if (lflag && (*env)->ExceptionOccurred(env)) 6757c478bd9Sstevel@tonic-gate (*env)->ExceptionDescribe(env); 6767c478bd9Sstevel@tonic-gate pu_die(err_desc); 6777c478bd9Sstevel@tonic-gate } 678