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 580ab886dSwesolows * Common Development and Distribution License (the "License"). 680ab886dSwesolows * 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 */ 2180ab886dSwesolows 227c478bd9Sstevel@tonic-gate /* 235ad1f010SStephen Hanson * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 247c478bd9Sstevel@tonic-gate * Use is subject to license terms. 257c478bd9Sstevel@tonic-gate */ 267c478bd9Sstevel@tonic-gate 277c478bd9Sstevel@tonic-gate /* 287c478bd9Sstevel@tonic-gate * syseventd - The system event daemon 297c478bd9Sstevel@tonic-gate * 307c478bd9Sstevel@tonic-gate * This daemon dispatches event buffers received from the 317c478bd9Sstevel@tonic-gate * kernel to all interested SLM clients. SLMs in turn 327c478bd9Sstevel@tonic-gate * deliver the buffers to their particular application 337c478bd9Sstevel@tonic-gate * clients. 347c478bd9Sstevel@tonic-gate */ 357c478bd9Sstevel@tonic-gate #include <stdio.h> 367c478bd9Sstevel@tonic-gate #include <sys/types.h> 377c478bd9Sstevel@tonic-gate #include <dirent.h> 387c478bd9Sstevel@tonic-gate #include <stdarg.h> 397c478bd9Sstevel@tonic-gate #include <stddef.h> 407c478bd9Sstevel@tonic-gate #include <stdlib.h> 417c478bd9Sstevel@tonic-gate #include <dlfcn.h> 427c478bd9Sstevel@tonic-gate #include <door.h> 437c478bd9Sstevel@tonic-gate #include <errno.h> 447c478bd9Sstevel@tonic-gate #include <fcntl.h> 457c478bd9Sstevel@tonic-gate #include <signal.h> 467c478bd9Sstevel@tonic-gate #include <strings.h> 477c478bd9Sstevel@tonic-gate #include <unistd.h> 487c478bd9Sstevel@tonic-gate #include <synch.h> 497c478bd9Sstevel@tonic-gate #include <syslog.h> 507c478bd9Sstevel@tonic-gate #include <thread.h> 517c478bd9Sstevel@tonic-gate #include <libsysevent.h> 527c478bd9Sstevel@tonic-gate #include <limits.h> 537c478bd9Sstevel@tonic-gate #include <locale.h> 547c478bd9Sstevel@tonic-gate #include <sys/sysevent.h> 557c478bd9Sstevel@tonic-gate #include <sys/sysevent_impl.h> 567c478bd9Sstevel@tonic-gate #include <sys/modctl.h> 577c478bd9Sstevel@tonic-gate #include <sys/stat.h> 587c478bd9Sstevel@tonic-gate #include <sys/systeminfo.h> 597c478bd9Sstevel@tonic-gate #include <sys/wait.h> 607c478bd9Sstevel@tonic-gate 617c478bd9Sstevel@tonic-gate #include "sysevent_signal.h" 627c478bd9Sstevel@tonic-gate #include "syseventd.h" 637c478bd9Sstevel@tonic-gate #include "message.h" 647c478bd9Sstevel@tonic-gate 657c478bd9Sstevel@tonic-gate extern int insert_client(void *client, int client_type, int retry_limit); 667c478bd9Sstevel@tonic-gate extern void delete_client(int id); 677c478bd9Sstevel@tonic-gate extern void initialize_client_tbl(void); 687c478bd9Sstevel@tonic-gate 697c478bd9Sstevel@tonic-gate extern struct sysevent_client *sysevent_client_tbl[]; 707c478bd9Sstevel@tonic-gate extern mutex_t client_tbl_lock; 717c478bd9Sstevel@tonic-gate 727c478bd9Sstevel@tonic-gate #define DEBUG_LEVEL_FORK 9 /* will run in background at all */ 737c478bd9Sstevel@tonic-gate /* levels less than DEBUG_LEVEL_FORK */ 747c478bd9Sstevel@tonic-gate 757c478bd9Sstevel@tonic-gate int debug_level = 0; 767c478bd9Sstevel@tonic-gate char *root_dir = ""; /* Relative root for lock and door */ 777c478bd9Sstevel@tonic-gate 787c478bd9Sstevel@tonic-gate /* Maximum number of outstanding events dispatched */ 797c478bd9Sstevel@tonic-gate #define SE_EVENT_DISPATCH_CNT 100 807c478bd9Sstevel@tonic-gate 817c478bd9Sstevel@tonic-gate static int upcall_door; /* Kernel event door */ 827c478bd9Sstevel@tonic-gate static int door_upcall_retval; /* Kernel event posting return value */ 837c478bd9Sstevel@tonic-gate static int fini_pending = 0; /* fini pending flag */ 847c478bd9Sstevel@tonic-gate static int deliver_buf = 0; /* Current event buffer from kernel */ 857c478bd9Sstevel@tonic-gate static int dispatch_buf = 0; /* Current event buffer dispatched */ 867c478bd9Sstevel@tonic-gate static sysevent_t **eventbuf; /* Global array of event buffers */ 877c478bd9Sstevel@tonic-gate static struct ev_completion *event_compq; /* Event completion queue */ 887c478bd9Sstevel@tonic-gate static mutex_t ev_comp_lock; /* Event completion queue lock */ 897c478bd9Sstevel@tonic-gate static mutex_t err_mutex; /* error logging lock */ 907c478bd9Sstevel@tonic-gate static mutex_t door_lock; /* sync door return access */ 917c478bd9Sstevel@tonic-gate static rwlock_t mod_unload_lock; /* sync module unloading */ 927c478bd9Sstevel@tonic-gate 937c478bd9Sstevel@tonic-gate /* declarations and definitions for avoiding multiple daemons running */ 94c6fc6dddSEric Schrock #define DAEMON_LOCK_FILE "/var/run/syseventd.lock" 957c478bd9Sstevel@tonic-gate char local_lock_file[PATH_MAX + 1]; 967c478bd9Sstevel@tonic-gate static int hold_daemon_lock; 977c478bd9Sstevel@tonic-gate static int daemon_lock_fd; 987c478bd9Sstevel@tonic-gate 997c478bd9Sstevel@tonic-gate /* 1007c478bd9Sstevel@tonic-gate * sema_eventbuf - guards against the global buffer eventbuf 1017c478bd9Sstevel@tonic-gate * being written to before it has been dispatched to clients 1027c478bd9Sstevel@tonic-gate * 1037c478bd9Sstevel@tonic-gate * sema_dispatch - synchronizes between the kernel uploading thread 1047c478bd9Sstevel@tonic-gate * (producer) and the userland dispatch_message thread (consumer). 1057c478bd9Sstevel@tonic-gate * 1067c478bd9Sstevel@tonic-gate * sema_resource - throttles outstanding event consumption. 1077c478bd9Sstevel@tonic-gate * 1087c478bd9Sstevel@tonic-gate * event_comp_cv - synchronizes threads waiting for the event completion queue 1097c478bd9Sstevel@tonic-gate * to empty or become active. 1107c478bd9Sstevel@tonic-gate */ 1117c478bd9Sstevel@tonic-gate static sema_t sema_eventbuf, sema_dispatch, sema_resource; 1127c478bd9Sstevel@tonic-gate static cond_t event_comp_cv; 1137c478bd9Sstevel@tonic-gate 1147c478bd9Sstevel@tonic-gate /* Self-tuning concurrency level */ 1157c478bd9Sstevel@tonic-gate #define MIN_CONCURRENCY_LEVEL 4 1167c478bd9Sstevel@tonic-gate static int concurrency_level = MIN_CONCURRENCY_LEVEL; 1177c478bd9Sstevel@tonic-gate 1187c478bd9Sstevel@tonic-gate 1197c478bd9Sstevel@tonic-gate /* SLM defines */ 1207c478bd9Sstevel@tonic-gate #define MODULE_SUFFIX ".so" 1217c478bd9Sstevel@tonic-gate #define EVENT_FINI "slm_fini" 1227c478bd9Sstevel@tonic-gate #define EVENT_INIT "slm_init" 1237c478bd9Sstevel@tonic-gate 1247c478bd9Sstevel@tonic-gate #define SE_TIMEOUT 60 /* Client dispatch timeout (seconds) */ 1257c478bd9Sstevel@tonic-gate 1267c478bd9Sstevel@tonic-gate /* syslog message related */ 1277c478bd9Sstevel@tonic-gate static int logflag = 0; 1287c478bd9Sstevel@tonic-gate static char *prog; 1297c478bd9Sstevel@tonic-gate 1307c478bd9Sstevel@tonic-gate /* function prototypes */ 1317c478bd9Sstevel@tonic-gate static void door_upcall(void *cookie, char *args, size_t alen, door_desc_t *ddp, 1327c478bd9Sstevel@tonic-gate uint_t ndid); 1337c478bd9Sstevel@tonic-gate static void dispatch_message(void); 1347c478bd9Sstevel@tonic-gate static int dispatch(void); 1357c478bd9Sstevel@tonic-gate static void event_completion_thr(void); 1367c478bd9Sstevel@tonic-gate static void usage(void); 1377c478bd9Sstevel@tonic-gate 1387c478bd9Sstevel@tonic-gate static void syseventd_init(void); 1397c478bd9Sstevel@tonic-gate static void syseventd_fini(int sig); 1407c478bd9Sstevel@tonic-gate 1417c478bd9Sstevel@tonic-gate static pid_t enter_daemon_lock(void); 1427c478bd9Sstevel@tonic-gate static void exit_daemon_lock(void); 1437c478bd9Sstevel@tonic-gate 1447c478bd9Sstevel@tonic-gate static void 1457c478bd9Sstevel@tonic-gate usage() { 1467c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "usage: syseventd [-d <debug_level>] " 1477c478bd9Sstevel@tonic-gate "[-r <root_dir>]\n"); 1487c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "higher debug levels get progressively "); 1497c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "more detailed debug information.\n"); 1507c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "syseventd will run in background if "); 1517c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "run with a debug_level less than %d.\n", 1527c478bd9Sstevel@tonic-gate DEBUG_LEVEL_FORK); 1537c478bd9Sstevel@tonic-gate exit(2); 1547c478bd9Sstevel@tonic-gate } 1557c478bd9Sstevel@tonic-gate 1567c478bd9Sstevel@tonic-gate 1577c478bd9Sstevel@tonic-gate /* common exit function which ensures releasing locks */ 1587c478bd9Sstevel@tonic-gate void 1597c478bd9Sstevel@tonic-gate syseventd_exit(int status) 1607c478bd9Sstevel@tonic-gate { 1617c478bd9Sstevel@tonic-gate syseventd_print(1, "exit status = %d\n", status); 1627c478bd9Sstevel@tonic-gate 1637c478bd9Sstevel@tonic-gate if (hold_daemon_lock) { 1647c478bd9Sstevel@tonic-gate exit_daemon_lock(); 1657c478bd9Sstevel@tonic-gate } 1667c478bd9Sstevel@tonic-gate 1677c478bd9Sstevel@tonic-gate exit(status); 1687c478bd9Sstevel@tonic-gate } 1697c478bd9Sstevel@tonic-gate 1707c478bd9Sstevel@tonic-gate 1717c478bd9Sstevel@tonic-gate /* 1727c478bd9Sstevel@tonic-gate * hup_handler - SIGHUP handler. SIGHUP is used to force a reload of 1737c478bd9Sstevel@tonic-gate * all SLMs. During fini, events are drained from all 1747c478bd9Sstevel@tonic-gate * client event queues. The events that have been consumed 1757c478bd9Sstevel@tonic-gate * by all clients are freed from the kernel event queue. 1767c478bd9Sstevel@tonic-gate * 1777c478bd9Sstevel@tonic-gate * Events that have not yet been delivered to all clients 1787c478bd9Sstevel@tonic-gate * are not freed and will be replayed after all SLMs have 1797c478bd9Sstevel@tonic-gate * been (re)loaded. 1807c478bd9Sstevel@tonic-gate * 1817c478bd9Sstevel@tonic-gate * After all client event queues have been drained, each 1827c478bd9Sstevel@tonic-gate * SLM client is unloaded. The init phase will (re)load 1837c478bd9Sstevel@tonic-gate * each SLM and initiate event replay and delivery from 1847c478bd9Sstevel@tonic-gate * the kernel. 1857c478bd9Sstevel@tonic-gate * 1867c478bd9Sstevel@tonic-gate */ 1877c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 1887c478bd9Sstevel@tonic-gate static void 1897c478bd9Sstevel@tonic-gate hup_handler(int sig) 1907c478bd9Sstevel@tonic-gate { 1917c478bd9Sstevel@tonic-gate syseventd_err_print(SIGHUP_CAUGHT); 1927c478bd9Sstevel@tonic-gate (void) fflush(0); 1937c478bd9Sstevel@tonic-gate syseventd_fini(sig); 1947c478bd9Sstevel@tonic-gate syseventd_init(); 1957c478bd9Sstevel@tonic-gate syseventd_err_print(DAEMON_RESTARTED); 1967c478bd9Sstevel@tonic-gate (void) fflush(0); 1977c478bd9Sstevel@tonic-gate } 1987c478bd9Sstevel@tonic-gate 1997c478bd9Sstevel@tonic-gate /* 2007c478bd9Sstevel@tonic-gate * Fault handler for other signals caught 2017c478bd9Sstevel@tonic-gate */ 2027c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 2037c478bd9Sstevel@tonic-gate static void 2047c478bd9Sstevel@tonic-gate flt_handler(int sig) 2057c478bd9Sstevel@tonic-gate { 2067c478bd9Sstevel@tonic-gate char signame[SIG2STR_MAX]; 2077c478bd9Sstevel@tonic-gate 2087c478bd9Sstevel@tonic-gate if (sig2str(sig, signame) == -1) { 2097c478bd9Sstevel@tonic-gate syseventd_err_print(UNKNOWN_SIGNAL_CAUGHT, sig); 2107c478bd9Sstevel@tonic-gate } 2117c478bd9Sstevel@tonic-gate 2127c478bd9Sstevel@tonic-gate (void) se_signal_sethandler(sig, SIG_DFL, NULL); 2137c478bd9Sstevel@tonic-gate 2147c478bd9Sstevel@tonic-gate switch (sig) { 2157c478bd9Sstevel@tonic-gate case SIGINT: 2167c478bd9Sstevel@tonic-gate case SIGSTOP: 2177c478bd9Sstevel@tonic-gate case SIGTERM: 2187c478bd9Sstevel@tonic-gate /* Close kernel door */ 2197c478bd9Sstevel@tonic-gate (void) door_revoke(upcall_door); 2207c478bd9Sstevel@tonic-gate 2217c478bd9Sstevel@tonic-gate /* Gracefully exit current event delivery threads */ 2227c478bd9Sstevel@tonic-gate syseventd_fini(sig); 2237c478bd9Sstevel@tonic-gate 2247c478bd9Sstevel@tonic-gate (void) fflush(0); 2257c478bd9Sstevel@tonic-gate (void) se_signal_unblockall(); 2267c478bd9Sstevel@tonic-gate syseventd_exit(1); 2277c478bd9Sstevel@tonic-gate /*NOTREACHED*/ 2285ad1f010SStephen Hanson case SIGCLD: 229b0daa853SStephen Hanson case SIGPWR: 230b0daa853SStephen Hanson case SIGWINCH: 231b0daa853SStephen Hanson case SIGURG: 232b0daa853SStephen Hanson case SIGCONT: 233b0daa853SStephen Hanson case SIGWAITING: 234b0daa853SStephen Hanson case SIGLWP: 235b0daa853SStephen Hanson case SIGFREEZE: 236b0daa853SStephen Hanson case SIGTHAW: 237b0daa853SStephen Hanson case SIGCANCEL: 238b0daa853SStephen Hanson case SIGXRES: 239b0daa853SStephen Hanson case SIGJVM1: 240b0daa853SStephen Hanson case SIGJVM2: 241*19d32b9aSRobert Mustacchi case SIGINFO: 242b0daa853SStephen Hanson /* No need to abort */ 2435ad1f010SStephen Hanson break; 2447c478bd9Sstevel@tonic-gate default: 2457c478bd9Sstevel@tonic-gate syseventd_err_print(FATAL_ERROR); 2465ad1f010SStephen Hanson abort(); 2477c478bd9Sstevel@tonic-gate 2487c478bd9Sstevel@tonic-gate } 2497c478bd9Sstevel@tonic-gate } 2507c478bd9Sstevel@tonic-gate 251b3a85157Sjg /* 252b3a85157Sjg * Daemon parent process only. 253b3a85157Sjg * Child process signal to indicate successful daemon initialization. 254b3a85157Sjg * This is the normal and expected exit path of the daemon parent. 255b3a85157Sjg */ 256b3a85157Sjg /*ARGSUSED*/ 257b3a85157Sjg static void 258b3a85157Sjg sigusr1(int sig) 259b3a85157Sjg { 260b3a85157Sjg syseventd_exit(0); 261b3a85157Sjg } 262b3a85157Sjg 2637c478bd9Sstevel@tonic-gate static void 2647c478bd9Sstevel@tonic-gate sigwait_thr() 2657c478bd9Sstevel@tonic-gate { 2667c478bd9Sstevel@tonic-gate int sig; 2677c478bd9Sstevel@tonic-gate int err; 2687c478bd9Sstevel@tonic-gate sigset_t signal_set; 2697c478bd9Sstevel@tonic-gate 2707c478bd9Sstevel@tonic-gate for (;;) { 2717c478bd9Sstevel@tonic-gate syseventd_print(3, "sigwait thread waiting for signal\n"); 2727c478bd9Sstevel@tonic-gate (void) sigfillset(&signal_set); 2737c478bd9Sstevel@tonic-gate err = sigwait(&signal_set, &sig); 2747c478bd9Sstevel@tonic-gate if (err) { 2757c478bd9Sstevel@tonic-gate syseventd_exit(2); 2767c478bd9Sstevel@tonic-gate } 2777c478bd9Sstevel@tonic-gate 2787c478bd9Sstevel@tonic-gate /* 2797c478bd9Sstevel@tonic-gate * Block all signals until the signal handler completes 2807c478bd9Sstevel@tonic-gate */ 2817c478bd9Sstevel@tonic-gate if (sig == SIGHUP) { 2827c478bd9Sstevel@tonic-gate hup_handler(sig); 2837c478bd9Sstevel@tonic-gate } else { 2847c478bd9Sstevel@tonic-gate flt_handler(sig); 2857c478bd9Sstevel@tonic-gate } 2867c478bd9Sstevel@tonic-gate } 2877c478bd9Sstevel@tonic-gate /* NOTREACHED */ 2887c478bd9Sstevel@tonic-gate } 2897c478bd9Sstevel@tonic-gate 2907c478bd9Sstevel@tonic-gate static void 2917c478bd9Sstevel@tonic-gate set_root_dir(char *dir) 2927c478bd9Sstevel@tonic-gate { 2937c478bd9Sstevel@tonic-gate root_dir = malloc(strlen(dir) + 1); 2947c478bd9Sstevel@tonic-gate if (root_dir == NULL) { 2957c478bd9Sstevel@tonic-gate syseventd_err_print(INIT_ROOT_DIR_ERR, strerror(errno)); 2967c478bd9Sstevel@tonic-gate syseventd_exit(2); 2977c478bd9Sstevel@tonic-gate } 2987c478bd9Sstevel@tonic-gate (void) strcpy(root_dir, dir); 2997c478bd9Sstevel@tonic-gate } 3007c478bd9Sstevel@tonic-gate 30180ab886dSwesolows int 3027c478bd9Sstevel@tonic-gate main(int argc, char **argv) 3037c478bd9Sstevel@tonic-gate { 3047c478bd9Sstevel@tonic-gate int i, c; 3057c478bd9Sstevel@tonic-gate int fd; 3067c478bd9Sstevel@tonic-gate pid_t pid; 307b3a85157Sjg int has_forked = 0; 3087c478bd9Sstevel@tonic-gate extern char *optarg; 3097c478bd9Sstevel@tonic-gate 3107c478bd9Sstevel@tonic-gate (void) setlocale(LC_ALL, ""); 3117c478bd9Sstevel@tonic-gate (void) textdomain(TEXT_DOMAIN); 3127c478bd9Sstevel@tonic-gate 3137c478bd9Sstevel@tonic-gate if (getuid() != 0) { 3147c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "Must be root to run syseventd\n"); 3157c478bd9Sstevel@tonic-gate syseventd_exit(1); 3167c478bd9Sstevel@tonic-gate } 3177c478bd9Sstevel@tonic-gate 3187c478bd9Sstevel@tonic-gate if (argc > 5) { 3197c478bd9Sstevel@tonic-gate usage(); 3207c478bd9Sstevel@tonic-gate } 3217c478bd9Sstevel@tonic-gate 3227c478bd9Sstevel@tonic-gate if ((prog = strrchr(argv[0], '/')) == NULL) { 3237c478bd9Sstevel@tonic-gate prog = argv[0]; 3247c478bd9Sstevel@tonic-gate } else { 3257c478bd9Sstevel@tonic-gate prog++; 3267c478bd9Sstevel@tonic-gate } 3277c478bd9Sstevel@tonic-gate 3285ad1f010SStephen Hanson while ((c = getopt(argc, argv, "d:r:")) != EOF) { 3297c478bd9Sstevel@tonic-gate switch (c) { 3307c478bd9Sstevel@tonic-gate case 'd': 3317c478bd9Sstevel@tonic-gate debug_level = atoi(optarg); 3327c478bd9Sstevel@tonic-gate break; 3337c478bd9Sstevel@tonic-gate case 'r': 3347c478bd9Sstevel@tonic-gate /* 3357c478bd9Sstevel@tonic-gate * Private flag for suninstall to run 3367c478bd9Sstevel@tonic-gate * daemon during install. 3377c478bd9Sstevel@tonic-gate */ 3387c478bd9Sstevel@tonic-gate set_root_dir(optarg); 3397c478bd9Sstevel@tonic-gate break; 3407c478bd9Sstevel@tonic-gate case '?': 3417c478bd9Sstevel@tonic-gate default: 3427c478bd9Sstevel@tonic-gate usage(); 3437c478bd9Sstevel@tonic-gate } 3447c478bd9Sstevel@tonic-gate } 3457c478bd9Sstevel@tonic-gate 3467c478bd9Sstevel@tonic-gate /* demonize ourselves */ 3477c478bd9Sstevel@tonic-gate if (debug_level < DEBUG_LEVEL_FORK) { 3487c478bd9Sstevel@tonic-gate 349b3a85157Sjg sigset_t mask; 350b3a85157Sjg 351b3a85157Sjg (void) sigset(SIGUSR1, sigusr1); 352b3a85157Sjg 353b3a85157Sjg (void) sigemptyset(&mask); 354b3a85157Sjg (void) sigaddset(&mask, SIGUSR1); 355b3a85157Sjg (void) sigprocmask(SIG_BLOCK, &mask, NULL); 356b3a85157Sjg 357b3a85157Sjg if ((pid = fork()) == (pid_t)-1) { 358b3a85157Sjg (void) fprintf(stderr, 359b3a85157Sjg "syseventd: fork failed - %s\n", strerror(errno)); 360b3a85157Sjg syseventd_exit(1); 361b3a85157Sjg } 362b3a85157Sjg 363b3a85157Sjg if (pid != 0) { 364b3a85157Sjg /* 365b3a85157Sjg * parent 366b3a85157Sjg * handshake with the daemon so that dependents 367b3a85157Sjg * of the syseventd service don't start up until 368b3a85157Sjg * the service is actually functional 369b3a85157Sjg */ 370b3a85157Sjg int status; 371b3a85157Sjg (void) sigprocmask(SIG_UNBLOCK, &mask, NULL); 372b3a85157Sjg 373b3a85157Sjg if (waitpid(pid, &status, 0) != pid) { 374b3a85157Sjg /* 375b3a85157Sjg * child process signal indicating 376b3a85157Sjg * successful daemon initialization 377b3a85157Sjg */ 3787c478bd9Sstevel@tonic-gate syseventd_exit(0); 3797c478bd9Sstevel@tonic-gate } 380b3a85157Sjg /* child exited implying unsuccessful startup */ 381b3a85157Sjg syseventd_exit(1); 382b3a85157Sjg } 3837c478bd9Sstevel@tonic-gate 3847c478bd9Sstevel@tonic-gate /* child */ 3857c478bd9Sstevel@tonic-gate 386b3a85157Sjg has_forked = 1; 387b3a85157Sjg (void) sigset(SIGUSR1, SIG_DFL); 388b3a85157Sjg (void) sigprocmask(SIG_UNBLOCK, &mask, NULL); 389b3a85157Sjg 3907c478bd9Sstevel@tonic-gate (void) chdir("/"); 3917c478bd9Sstevel@tonic-gate (void) setsid(); 3927c478bd9Sstevel@tonic-gate if (debug_level <= 1) { 3937c478bd9Sstevel@tonic-gate closefrom(0); 3947c478bd9Sstevel@tonic-gate fd = open("/dev/null", 0); 3957c478bd9Sstevel@tonic-gate (void) dup2(fd, 1); 3967c478bd9Sstevel@tonic-gate (void) dup2(fd, 2); 3977c478bd9Sstevel@tonic-gate logflag = 1; 3987c478bd9Sstevel@tonic-gate } 3997c478bd9Sstevel@tonic-gate } 4007c478bd9Sstevel@tonic-gate 4017c478bd9Sstevel@tonic-gate openlog("syseventd", LOG_PID, LOG_DAEMON); 4027c478bd9Sstevel@tonic-gate 4037c478bd9Sstevel@tonic-gate (void) mutex_init(&err_mutex, USYNC_THREAD, NULL); 4047c478bd9Sstevel@tonic-gate 4057c478bd9Sstevel@tonic-gate syseventd_print(8, 4067c478bd9Sstevel@tonic-gate "syseventd started, debug level = %d\n", debug_level); 4077c478bd9Sstevel@tonic-gate 4087c478bd9Sstevel@tonic-gate /* only one instance of syseventd can run at a time */ 4097c478bd9Sstevel@tonic-gate if ((pid = enter_daemon_lock()) != getpid()) { 4107c478bd9Sstevel@tonic-gate syseventd_print(1, 4117c478bd9Sstevel@tonic-gate "event daemon pid %ld already running\n", pid); 4127c478bd9Sstevel@tonic-gate exit(3); 4137c478bd9Sstevel@tonic-gate } 4147c478bd9Sstevel@tonic-gate 4157c478bd9Sstevel@tonic-gate /* initialize semaphores and eventbuf */ 4167c478bd9Sstevel@tonic-gate (void) sema_init(&sema_eventbuf, SE_EVENT_DISPATCH_CNT, 4177c478bd9Sstevel@tonic-gate USYNC_THREAD, NULL); 4187c478bd9Sstevel@tonic-gate (void) sema_init(&sema_dispatch, 0, USYNC_THREAD, NULL); 4197c478bd9Sstevel@tonic-gate (void) sema_init(&sema_resource, SE_EVENT_DISPATCH_CNT, 4207c478bd9Sstevel@tonic-gate USYNC_THREAD, NULL); 4217c478bd9Sstevel@tonic-gate (void) cond_init(&event_comp_cv, USYNC_THREAD, NULL); 4227c478bd9Sstevel@tonic-gate eventbuf = (sysevent_t **)calloc(SE_EVENT_DISPATCH_CNT, 4237c478bd9Sstevel@tonic-gate sizeof (sysevent_t *)); 4247c478bd9Sstevel@tonic-gate if (eventbuf == NULL) { 4257c478bd9Sstevel@tonic-gate syseventd_print(1, "Unable to allocate event buffer array\n"); 4267c478bd9Sstevel@tonic-gate exit(2); 4277c478bd9Sstevel@tonic-gate } 4287c478bd9Sstevel@tonic-gate for (i = 0; i < SE_EVENT_DISPATCH_CNT; ++i) { 4297c478bd9Sstevel@tonic-gate eventbuf[i] = malloc(LOGEVENT_BUFSIZE); 4307c478bd9Sstevel@tonic-gate if (eventbuf[i] == NULL) { 4317c478bd9Sstevel@tonic-gate syseventd_print(1, "Unable to allocate event " 4327c478bd9Sstevel@tonic-gate "buffers\n"); 4337c478bd9Sstevel@tonic-gate exit(2); 4347c478bd9Sstevel@tonic-gate } 4357c478bd9Sstevel@tonic-gate } 4367c478bd9Sstevel@tonic-gate 4377c478bd9Sstevel@tonic-gate (void) mutex_init(&client_tbl_lock, USYNC_THREAD, NULL); 4387c478bd9Sstevel@tonic-gate (void) mutex_init(&ev_comp_lock, USYNC_THREAD, NULL); 4397c478bd9Sstevel@tonic-gate (void) mutex_init(&door_lock, USYNC_THREAD, NULL); 4407c478bd9Sstevel@tonic-gate (void) rwlock_init(&mod_unload_lock, USYNC_THREAD, NULL); 4417c478bd9Sstevel@tonic-gate 4427c478bd9Sstevel@tonic-gate event_compq = NULL; 4437c478bd9Sstevel@tonic-gate 4447c478bd9Sstevel@tonic-gate syseventd_print(8, "start the message thread running\n"); 4457c478bd9Sstevel@tonic-gate 4467c478bd9Sstevel@tonic-gate /* 4477c478bd9Sstevel@tonic-gate * Block all signals to all threads include the main thread. 4487c478bd9Sstevel@tonic-gate * The sigwait_thr thread will process any signals and initiate 4497c478bd9Sstevel@tonic-gate * a graceful recovery if possible. 4507c478bd9Sstevel@tonic-gate */ 4517c478bd9Sstevel@tonic-gate if (se_signal_blockall() < 0) { 4527c478bd9Sstevel@tonic-gate syseventd_err_print(INIT_SIG_BLOCK_ERR); 4537c478bd9Sstevel@tonic-gate syseventd_exit(2); 4547c478bd9Sstevel@tonic-gate } 4557c478bd9Sstevel@tonic-gate 4567c478bd9Sstevel@tonic-gate if (thr_create(NULL, NULL, (void *(*)(void *))dispatch_message, 4577c478bd9Sstevel@tonic-gate (void *)0, 0, NULL) < 0) { 4587c478bd9Sstevel@tonic-gate syseventd_err_print(INIT_THR_CREATE_ERR, strerror(errno)); 4597c478bd9Sstevel@tonic-gate syseventd_exit(2); 4607c478bd9Sstevel@tonic-gate } 4617c478bd9Sstevel@tonic-gate if (thr_create(NULL, NULL, 4627c478bd9Sstevel@tonic-gate (void *(*)(void *))event_completion_thr, NULL, 4637c478bd9Sstevel@tonic-gate THR_BOUND, NULL) != 0) { 4647c478bd9Sstevel@tonic-gate syseventd_err_print(INIT_THR_CREATE_ERR, strerror(errno)); 4657c478bd9Sstevel@tonic-gate syseventd_exit(2); 4667c478bd9Sstevel@tonic-gate } 4677c478bd9Sstevel@tonic-gate /* Create signal catching thread */ 4687c478bd9Sstevel@tonic-gate if (thr_create(NULL, NULL, (void *(*)(void *))sigwait_thr, 4697c478bd9Sstevel@tonic-gate NULL, 0, NULL) < 0) { 4707c478bd9Sstevel@tonic-gate syseventd_err_print(INIT_THR_CREATE_ERR, strerror(errno)); 4717c478bd9Sstevel@tonic-gate syseventd_exit(2); 4727c478bd9Sstevel@tonic-gate } 4737c478bd9Sstevel@tonic-gate 4747c478bd9Sstevel@tonic-gate setbuf(stdout, (char *)NULL); 4757c478bd9Sstevel@tonic-gate 4767c478bd9Sstevel@tonic-gate /* Initialize and load SLM clients */ 4777c478bd9Sstevel@tonic-gate initialize_client_tbl(); 4787c478bd9Sstevel@tonic-gate syseventd_init(); 4797c478bd9Sstevel@tonic-gate 480b3a85157Sjg /* signal parent to indicate successful daemon initialization */ 481b3a85157Sjg if (has_forked) { 482b3a85157Sjg if (kill(getppid(), SIGUSR1) != 0) { 483b3a85157Sjg syseventd_err_print( 484b3a85157Sjg "signal to the parent failed - %s\n", 485b3a85157Sjg strerror(errno)); 486b3a85157Sjg syseventd_exit(2); 487b3a85157Sjg } 488b3a85157Sjg } 489b3a85157Sjg 4907c478bd9Sstevel@tonic-gate syseventd_print(8, "Pausing\n"); 4917c478bd9Sstevel@tonic-gate 4927c478bd9Sstevel@tonic-gate for (;;) { 4937c478bd9Sstevel@tonic-gate (void) pause(); 4947c478bd9Sstevel@tonic-gate } 4957c478bd9Sstevel@tonic-gate /* NOTREACHED */ 49680ab886dSwesolows return (0); 4977c478bd9Sstevel@tonic-gate } 4987c478bd9Sstevel@tonic-gate 4997c478bd9Sstevel@tonic-gate /* 5007c478bd9Sstevel@tonic-gate * door_upcall - called from the kernel via kernel sysevent door 5017c478bd9Sstevel@tonic-gate * to upload event(s). 5027c478bd9Sstevel@tonic-gate * 5037c478bd9Sstevel@tonic-gate * This routine should never block. If resources are 5047c478bd9Sstevel@tonic-gate * not available to immediately accept the event buffer 5057c478bd9Sstevel@tonic-gate * EAGAIN is returned to the kernel. 5067c478bd9Sstevel@tonic-gate * 5077c478bd9Sstevel@tonic-gate * Once resources are available, the kernel is notified 5087c478bd9Sstevel@tonic-gate * via a modctl interface to resume event delivery to 5097c478bd9Sstevel@tonic-gate * syseventd. 5107c478bd9Sstevel@tonic-gate * 5117c478bd9Sstevel@tonic-gate */ 5127c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 5137c478bd9Sstevel@tonic-gate static void 5147c478bd9Sstevel@tonic-gate door_upcall(void *cookie, char *args, size_t alen, 5157c478bd9Sstevel@tonic-gate door_desc_t *ddp, uint_t ndid) 5167c478bd9Sstevel@tonic-gate { 5177c478bd9Sstevel@tonic-gate sysevent_t *ev; 5187c478bd9Sstevel@tonic-gate int rval; 5197c478bd9Sstevel@tonic-gate 5207c478bd9Sstevel@tonic-gate 5217c478bd9Sstevel@tonic-gate (void) mutex_lock(&door_lock); 5227c478bd9Sstevel@tonic-gate if (args == NULL) { 5237c478bd9Sstevel@tonic-gate rval = EINVAL; 5247c478bd9Sstevel@tonic-gate } else if (sema_trywait(&sema_eventbuf)) { 5257c478bd9Sstevel@tonic-gate ev = (sysevent_t *) 5267c478bd9Sstevel@tonic-gate &((log_event_upcall_arg_t *)(void *)args)->buf; 5277c478bd9Sstevel@tonic-gate syseventd_print(2, "door_upcall: busy event %llx " 5287c478bd9Sstevel@tonic-gate "retry\n", sysevent_get_seq(ev)); 5297c478bd9Sstevel@tonic-gate rval = door_upcall_retval = EAGAIN; 5307c478bd9Sstevel@tonic-gate } else { 5317c478bd9Sstevel@tonic-gate /* 5327c478bd9Sstevel@tonic-gate * Copy received message to local buffer. 5337c478bd9Sstevel@tonic-gate */ 5347c478bd9Sstevel@tonic-gate size_t size; 5357c478bd9Sstevel@tonic-gate ev = (sysevent_t *) 5367c478bd9Sstevel@tonic-gate &((log_event_upcall_arg_t *)(void *)args)->buf; 5377c478bd9Sstevel@tonic-gate 5387c478bd9Sstevel@tonic-gate syseventd_print(2, "door_upcall: event %llx in eventbuf %d\n", 5397c478bd9Sstevel@tonic-gate sysevent_get_seq(ev), deliver_buf); 5407c478bd9Sstevel@tonic-gate size = sysevent_get_size(ev) > LOGEVENT_BUFSIZE ? 5417c478bd9Sstevel@tonic-gate LOGEVENT_BUFSIZE : sysevent_get_size(ev); 5427c478bd9Sstevel@tonic-gate (void) bcopy(ev, eventbuf[deliver_buf], size); 5437c478bd9Sstevel@tonic-gate deliver_buf = (deliver_buf + 1) % SE_EVENT_DISPATCH_CNT; 5447c478bd9Sstevel@tonic-gate rval = 0; 5457c478bd9Sstevel@tonic-gate (void) sema_post(&sema_dispatch); 5467c478bd9Sstevel@tonic-gate } 5477c478bd9Sstevel@tonic-gate 5487c478bd9Sstevel@tonic-gate (void) mutex_unlock(&door_lock); 5497c478bd9Sstevel@tonic-gate 5507c478bd9Sstevel@tonic-gate /* 5517c478bd9Sstevel@tonic-gate * Filling in return values for door_return 5527c478bd9Sstevel@tonic-gate */ 5537c478bd9Sstevel@tonic-gate (void) door_return((void *)&rval, sizeof (rval), NULL, 0); 5547c478bd9Sstevel@tonic-gate (void) door_return(NULL, 0, NULL, 0); 5557c478bd9Sstevel@tonic-gate } 5567c478bd9Sstevel@tonic-gate 5577c478bd9Sstevel@tonic-gate /* 5587c478bd9Sstevel@tonic-gate * dispatch_message - dispatch message thread 5597c478bd9Sstevel@tonic-gate * This thread spins until an event buffer is delivered 5607c478bd9Sstevel@tonic-gate * delivered from the kernel. 5617c478bd9Sstevel@tonic-gate * 5627c478bd9Sstevel@tonic-gate * It will wait to dispatch an event to any clients 5637c478bd9Sstevel@tonic-gate * until adequate resources are available to process 5647c478bd9Sstevel@tonic-gate * the event buffer. 5657c478bd9Sstevel@tonic-gate */ 5667c478bd9Sstevel@tonic-gate static void 5677c478bd9Sstevel@tonic-gate dispatch_message(void) 5687c478bd9Sstevel@tonic-gate { 5697c478bd9Sstevel@tonic-gate int error; 5707c478bd9Sstevel@tonic-gate 5717c478bd9Sstevel@tonic-gate for (;;) { 5727c478bd9Sstevel@tonic-gate syseventd_print(3, "dispatch_message: thread started\n"); 5737c478bd9Sstevel@tonic-gate /* 5747c478bd9Sstevel@tonic-gate * Spin till a message comes 5757c478bd9Sstevel@tonic-gate */ 5767c478bd9Sstevel@tonic-gate while (sema_wait(&sema_dispatch) != 0) { 5777c478bd9Sstevel@tonic-gate syseventd_print(1, 5787c478bd9Sstevel@tonic-gate "dispatch_message: sema_wait failed\n"); 5797c478bd9Sstevel@tonic-gate (void) sleep(1); 5807c478bd9Sstevel@tonic-gate } 5817c478bd9Sstevel@tonic-gate 5827c478bd9Sstevel@tonic-gate syseventd_print(3, "dispatch_message: sema_dispatch\n"); 5837c478bd9Sstevel@tonic-gate 5847c478bd9Sstevel@tonic-gate /* 5857c478bd9Sstevel@tonic-gate * Wait for available resources 5867c478bd9Sstevel@tonic-gate */ 5877c478bd9Sstevel@tonic-gate while (sema_wait(&sema_resource) != 0) { 5887c478bd9Sstevel@tonic-gate syseventd_print(1, "dispatch_message: sema_wait " 5897c478bd9Sstevel@tonic-gate "failed\n"); 5907c478bd9Sstevel@tonic-gate (void) sleep(1); 5917c478bd9Sstevel@tonic-gate } 5927c478bd9Sstevel@tonic-gate 5937c478bd9Sstevel@tonic-gate syseventd_print(2, "dispatch_message: eventbuf %d\n", 5947c478bd9Sstevel@tonic-gate dispatch_buf); 5957c478bd9Sstevel@tonic-gate 5967c478bd9Sstevel@tonic-gate /* 5977c478bd9Sstevel@tonic-gate * Client dispatch 5987c478bd9Sstevel@tonic-gate */ 5997c478bd9Sstevel@tonic-gate do { 6007c478bd9Sstevel@tonic-gate error = dispatch(); 6017c478bd9Sstevel@tonic-gate } while (error == EAGAIN); 6027c478bd9Sstevel@tonic-gate 6037c478bd9Sstevel@tonic-gate syseventd_print(2, "eventbuf %d dispatched\n", dispatch_buf); 6047c478bd9Sstevel@tonic-gate dispatch_buf = (dispatch_buf + 1) % SE_EVENT_DISPATCH_CNT; 6057c478bd9Sstevel@tonic-gate 6067c478bd9Sstevel@tonic-gate /* 6077c478bd9Sstevel@tonic-gate * kernel received a busy signal - 6087c478bd9Sstevel@tonic-gate * kickstart the kernel delivery thread 6097c478bd9Sstevel@tonic-gate * door_lock blocks the kernel so we hold it for the 6107c478bd9Sstevel@tonic-gate * shortest time possible. 6117c478bd9Sstevel@tonic-gate */ 6127c478bd9Sstevel@tonic-gate (void) mutex_lock(&door_lock); 6137c478bd9Sstevel@tonic-gate if (door_upcall_retval == EAGAIN && !fini_pending) { 6147c478bd9Sstevel@tonic-gate syseventd_print(3, "dispatch_message: retrigger " 6157c478bd9Sstevel@tonic-gate "door_upcall_retval = %d\n", 6167c478bd9Sstevel@tonic-gate door_upcall_retval); 6177c478bd9Sstevel@tonic-gate (void) modctl(MODEVENTS, (uintptr_t)MODEVENTS_FLUSH, 6187c478bd9Sstevel@tonic-gate NULL, NULL, NULL, 0); 6197c478bd9Sstevel@tonic-gate door_upcall_retval = 0; 6207c478bd9Sstevel@tonic-gate } 6217c478bd9Sstevel@tonic-gate (void) mutex_unlock(&door_lock); 6227c478bd9Sstevel@tonic-gate } 6237c478bd9Sstevel@tonic-gate /* NOTREACHED */ 6247c478bd9Sstevel@tonic-gate } 6257c478bd9Sstevel@tonic-gate 6267c478bd9Sstevel@tonic-gate /* 6277c478bd9Sstevel@tonic-gate * drain_eventq - Called to drain all pending events from the client's 6287c478bd9Sstevel@tonic-gate * event queue. 6297c478bd9Sstevel@tonic-gate */ 6307c478bd9Sstevel@tonic-gate static void 6317c478bd9Sstevel@tonic-gate drain_eventq(struct sysevent_client *scp, int status) 6327c478bd9Sstevel@tonic-gate { 6337c478bd9Sstevel@tonic-gate struct event_dispatch_pkg *d_pkg; 6347c478bd9Sstevel@tonic-gate struct event_dispatchq *eventq, *eventq_next; 6357c478bd9Sstevel@tonic-gate 6367c478bd9Sstevel@tonic-gate syseventd_print(3, "Draining eventq for client %d\n", 6377c478bd9Sstevel@tonic-gate scp->client_num); 6387c478bd9Sstevel@tonic-gate 6397c478bd9Sstevel@tonic-gate eventq = scp->eventq; 6407c478bd9Sstevel@tonic-gate while (eventq) { 6417c478bd9Sstevel@tonic-gate /* 6427c478bd9Sstevel@tonic-gate * Mark all dispatched events as completed, but indicate the 6437c478bd9Sstevel@tonic-gate * error status 6447c478bd9Sstevel@tonic-gate */ 6457c478bd9Sstevel@tonic-gate d_pkg = eventq->d_pkg; 6467c478bd9Sstevel@tonic-gate 6477c478bd9Sstevel@tonic-gate syseventd_print(4, "drain event 0X%llx for client %d\n", 6487c478bd9Sstevel@tonic-gate sysevent_get_seq(d_pkg->ev), scp->client_num); 6497c478bd9Sstevel@tonic-gate 6507c478bd9Sstevel@tonic-gate if (d_pkg->completion_state == SE_NOT_DISPATCHED) { 6517c478bd9Sstevel@tonic-gate d_pkg->completion_status = status; 6527c478bd9Sstevel@tonic-gate d_pkg->completion_state = SE_COMPLETE; 6537c478bd9Sstevel@tonic-gate (void) sema_post(d_pkg->completion_sema); 6547c478bd9Sstevel@tonic-gate } 6557c478bd9Sstevel@tonic-gate 6567c478bd9Sstevel@tonic-gate eventq_next = eventq->next; 6577c478bd9Sstevel@tonic-gate free(eventq); 6587c478bd9Sstevel@tonic-gate eventq = eventq_next; 6597c478bd9Sstevel@tonic-gate scp->eventq = eventq; 6607c478bd9Sstevel@tonic-gate } 6617c478bd9Sstevel@tonic-gate } 6627c478bd9Sstevel@tonic-gate 6637c478bd9Sstevel@tonic-gate /* 6647c478bd9Sstevel@tonic-gate * client_deliver_event_thr - Client delivery thread 6657c478bd9Sstevel@tonic-gate * This thread will process any events on this 6667c478bd9Sstevel@tonic-gate * client's eventq. 6677c478bd9Sstevel@tonic-gate */ 6687c478bd9Sstevel@tonic-gate static void 6697c478bd9Sstevel@tonic-gate client_deliver_event_thr(void *arg) 6707c478bd9Sstevel@tonic-gate { 6717c478bd9Sstevel@tonic-gate int flag, error, i; 6727c478bd9Sstevel@tonic-gate sysevent_t *ev; 6737c478bd9Sstevel@tonic-gate hrtime_t now; 6747c478bd9Sstevel@tonic-gate module_t *mod; 6757c478bd9Sstevel@tonic-gate struct event_dispatchq *eventq; 6767c478bd9Sstevel@tonic-gate struct sysevent_client *scp; 6777c478bd9Sstevel@tonic-gate struct event_dispatch_pkg *d_pkg; 6787c478bd9Sstevel@tonic-gate 6797c478bd9Sstevel@tonic-gate scp = (struct sysevent_client *)arg; 6807c478bd9Sstevel@tonic-gate mod = (module_t *)scp->client_data; 6817c478bd9Sstevel@tonic-gate 6827c478bd9Sstevel@tonic-gate (void) mutex_lock(&scp->client_lock); 6837c478bd9Sstevel@tonic-gate for (;;) { 6847c478bd9Sstevel@tonic-gate while (scp->eventq == NULL) { 6857c478bd9Sstevel@tonic-gate 6867c478bd9Sstevel@tonic-gate /* 6877c478bd9Sstevel@tonic-gate * Client has been suspended or unloaded, go no further. 6887c478bd9Sstevel@tonic-gate */ 6897c478bd9Sstevel@tonic-gate if (fini_pending) { 6907c478bd9Sstevel@tonic-gate scp->client_flags &= ~SE_CLIENT_THR_RUNNING; 6917c478bd9Sstevel@tonic-gate syseventd_print(3, "Client %d delivery thread " 6927c478bd9Sstevel@tonic-gate "exiting flags: 0X%x\n", 6937c478bd9Sstevel@tonic-gate scp->client_num, scp->client_flags); 6947c478bd9Sstevel@tonic-gate (void) mutex_unlock(&scp->client_lock); 6957c478bd9Sstevel@tonic-gate return; 6967c478bd9Sstevel@tonic-gate } 6977c478bd9Sstevel@tonic-gate 6987c478bd9Sstevel@tonic-gate (void) cond_wait(&scp->client_cv, &scp->client_lock); 6997c478bd9Sstevel@tonic-gate 7007c478bd9Sstevel@tonic-gate } 7017c478bd9Sstevel@tonic-gate 7027c478bd9Sstevel@tonic-gate /* 7037c478bd9Sstevel@tonic-gate * Process events from the head of the eventq, eventq is locked 7047c478bd9Sstevel@tonic-gate * going into the processing. 7057c478bd9Sstevel@tonic-gate */ 7067c478bd9Sstevel@tonic-gate eventq = scp->eventq; 7077c478bd9Sstevel@tonic-gate while (eventq != NULL) { 7087c478bd9Sstevel@tonic-gate d_pkg = eventq->d_pkg; 7097c478bd9Sstevel@tonic-gate d_pkg->completion_state = SE_OUTSTANDING; 7105ad1f010SStephen Hanson scp->eventq = eventq->next; 7115ad1f010SStephen Hanson free(eventq); 7127c478bd9Sstevel@tonic-gate (void) mutex_unlock(&scp->client_lock); 7137c478bd9Sstevel@tonic-gate 7147c478bd9Sstevel@tonic-gate 7157c478bd9Sstevel@tonic-gate flag = error = 0; 7167c478bd9Sstevel@tonic-gate ev = d_pkg->ev; 7177c478bd9Sstevel@tonic-gate 7187c478bd9Sstevel@tonic-gate syseventd_print(3, "Start delivery for client %d " 7197c478bd9Sstevel@tonic-gate "with retry count %d\n", 7207c478bd9Sstevel@tonic-gate scp->client_num, d_pkg->retry_count); 7217c478bd9Sstevel@tonic-gate 7227c478bd9Sstevel@tonic-gate /* 7237c478bd9Sstevel@tonic-gate * Retry limit has been reached by this client, indicate 7247c478bd9Sstevel@tonic-gate * that no further retries are allowed 7257c478bd9Sstevel@tonic-gate */ 7267c478bd9Sstevel@tonic-gate for (i = 0; i <= scp->retry_limit; ++i) { 7277c478bd9Sstevel@tonic-gate if (i == scp->retry_limit) 7287c478bd9Sstevel@tonic-gate flag = SE_NO_RETRY; 7297c478bd9Sstevel@tonic-gate 7307c478bd9Sstevel@tonic-gate /* Start the clock for the event delivery */ 7317c478bd9Sstevel@tonic-gate d_pkg->start_time = gethrtime(); 7327c478bd9Sstevel@tonic-gate 7337c478bd9Sstevel@tonic-gate syseventd_print(9, "Deliver to module client " 7347c478bd9Sstevel@tonic-gate "%s\n", mod->name); 7357c478bd9Sstevel@tonic-gate 7367c478bd9Sstevel@tonic-gate error = mod->deliver_event(ev, flag); 7377c478bd9Sstevel@tonic-gate 7387c478bd9Sstevel@tonic-gate /* Can not allow another retry */ 7397c478bd9Sstevel@tonic-gate if (i == scp->retry_limit) 7407c478bd9Sstevel@tonic-gate error = 0; 7417c478bd9Sstevel@tonic-gate 7427c478bd9Sstevel@tonic-gate /* Stop the clock */ 7437c478bd9Sstevel@tonic-gate now = gethrtime(); 7447c478bd9Sstevel@tonic-gate 7457c478bd9Sstevel@tonic-gate /* 7467c478bd9Sstevel@tonic-gate * Suspend event processing and drain the 7477c478bd9Sstevel@tonic-gate * event q for latent clients 7487c478bd9Sstevel@tonic-gate */ 7497c478bd9Sstevel@tonic-gate if (now - d_pkg->start_time > 7507c478bd9Sstevel@tonic-gate ((hrtime_t)SE_TIMEOUT * NANOSEC)) { 7517c478bd9Sstevel@tonic-gate syseventd_print(1, "Unresponsive " 7527c478bd9Sstevel@tonic-gate "client %d: Draining eventq and " 7537c478bd9Sstevel@tonic-gate "suspending event delivery\n", 7547c478bd9Sstevel@tonic-gate scp->client_num); 7557c478bd9Sstevel@tonic-gate (void) mutex_lock(&scp->client_lock); 7567c478bd9Sstevel@tonic-gate scp->client_flags &= 7577c478bd9Sstevel@tonic-gate ~SE_CLIENT_THR_RUNNING; 7587c478bd9Sstevel@tonic-gate scp->client_flags |= 7597c478bd9Sstevel@tonic-gate SE_CLIENT_SUSPENDED; 7607c478bd9Sstevel@tonic-gate 7617c478bd9Sstevel@tonic-gate /* Cleanup current event */ 7627c478bd9Sstevel@tonic-gate d_pkg->completion_status = EFAULT; 7637c478bd9Sstevel@tonic-gate d_pkg->completion_state = SE_COMPLETE; 7647c478bd9Sstevel@tonic-gate (void) sema_post( 7657c478bd9Sstevel@tonic-gate d_pkg->completion_sema); 7667c478bd9Sstevel@tonic-gate 7677c478bd9Sstevel@tonic-gate /* 7687c478bd9Sstevel@tonic-gate * Drain the remaining events from the 7697c478bd9Sstevel@tonic-gate * queue. 7707c478bd9Sstevel@tonic-gate */ 7717c478bd9Sstevel@tonic-gate drain_eventq(scp, EINVAL); 7727c478bd9Sstevel@tonic-gate (void) mutex_unlock(&scp->client_lock); 7737c478bd9Sstevel@tonic-gate return; 7747c478bd9Sstevel@tonic-gate } 7757c478bd9Sstevel@tonic-gate 7767c478bd9Sstevel@tonic-gate /* Event delivery retry requested */ 7777c478bd9Sstevel@tonic-gate if (fini_pending || error != EAGAIN) { 7787c478bd9Sstevel@tonic-gate break; 7797c478bd9Sstevel@tonic-gate } else { 7807c478bd9Sstevel@tonic-gate (void) sleep(SE_RETRY_TIME); 7817c478bd9Sstevel@tonic-gate } 7827c478bd9Sstevel@tonic-gate } 7837c478bd9Sstevel@tonic-gate 7847c478bd9Sstevel@tonic-gate (void) mutex_lock(&scp->client_lock); 7857c478bd9Sstevel@tonic-gate d_pkg->completion_status = error; 7867c478bd9Sstevel@tonic-gate d_pkg->completion_state = SE_COMPLETE; 7877c478bd9Sstevel@tonic-gate (void) sema_post(d_pkg->completion_sema); 7887c478bd9Sstevel@tonic-gate syseventd_print(3, "Completed delivery with " 7897c478bd9Sstevel@tonic-gate "error %d\n", error); 790540db9a9SStephen Hanson eventq = scp->eventq; 7917c478bd9Sstevel@tonic-gate } 7927c478bd9Sstevel@tonic-gate 7937c478bd9Sstevel@tonic-gate syseventd_print(3, "No more events to process for client %d\n", 7947c478bd9Sstevel@tonic-gate scp->client_num); 7957c478bd9Sstevel@tonic-gate 7967c478bd9Sstevel@tonic-gate /* Return if this was a synchronous delivery */ 7977c478bd9Sstevel@tonic-gate if (!SE_CLIENT_IS_THR_RUNNING(scp)) { 7987c478bd9Sstevel@tonic-gate (void) mutex_unlock(&scp->client_lock); 7997c478bd9Sstevel@tonic-gate return; 8007c478bd9Sstevel@tonic-gate } 8017c478bd9Sstevel@tonic-gate 8027c478bd9Sstevel@tonic-gate } 8037c478bd9Sstevel@tonic-gate } 8047c478bd9Sstevel@tonic-gate 8057c478bd9Sstevel@tonic-gate /* 8067c478bd9Sstevel@tonic-gate * client_deliver_event - Client specific event delivery 8077c478bd9Sstevel@tonic-gate * This routine will allocate and initialize the 8087c478bd9Sstevel@tonic-gate * neccessary per-client dispatch data. 8097c478bd9Sstevel@tonic-gate * 8107c478bd9Sstevel@tonic-gate * If the eventq is not empty, it may be assumed that 8117c478bd9Sstevel@tonic-gate * a delivery thread exists for this client and the 8127c478bd9Sstevel@tonic-gate * dispatch data is appended to the eventq. 8137c478bd9Sstevel@tonic-gate * 8147c478bd9Sstevel@tonic-gate * The dispatch package is freed by the event completion 8157c478bd9Sstevel@tonic-gate * thread (event_completion_thr) and the eventq entry 8167c478bd9Sstevel@tonic-gate * is freed by the event delivery thread. 8177c478bd9Sstevel@tonic-gate */ 8187c478bd9Sstevel@tonic-gate static struct event_dispatch_pkg * 8197c478bd9Sstevel@tonic-gate client_deliver_event(struct sysevent_client *scp, sysevent_t *ev, 8207c478bd9Sstevel@tonic-gate sema_t *completion_sema) 8217c478bd9Sstevel@tonic-gate { 8227c478bd9Sstevel@tonic-gate size_t ev_sz = sysevent_get_size(ev); 8237c478bd9Sstevel@tonic-gate struct event_dispatchq *newq, *tmp; 8247c478bd9Sstevel@tonic-gate struct event_dispatch_pkg *d_pkg; 8257c478bd9Sstevel@tonic-gate 8267c478bd9Sstevel@tonic-gate syseventd_print(3, "client_deliver_event: id 0x%llx size %d\n", 8277c478bd9Sstevel@tonic-gate (longlong_t)sysevent_get_seq(ev), ev_sz); 8287c478bd9Sstevel@tonic-gate if (debug_level == 9) { 8297c478bd9Sstevel@tonic-gate se_print(stdout, ev); 8307c478bd9Sstevel@tonic-gate } 8317c478bd9Sstevel@tonic-gate 8327c478bd9Sstevel@tonic-gate /* 8337c478bd9Sstevel@tonic-gate * Check for suspended client 8347c478bd9Sstevel@tonic-gate */ 8357c478bd9Sstevel@tonic-gate (void) mutex_lock(&scp->client_lock); 8367c478bd9Sstevel@tonic-gate if (SE_CLIENT_IS_SUSPENDED(scp) || !SE_CLIENT_IS_THR_RUNNING(scp)) { 8377c478bd9Sstevel@tonic-gate (void) mutex_unlock(&scp->client_lock); 8387c478bd9Sstevel@tonic-gate return (NULL); 8397c478bd9Sstevel@tonic-gate } 8407c478bd9Sstevel@tonic-gate 8417c478bd9Sstevel@tonic-gate /* 8427c478bd9Sstevel@tonic-gate * Allocate a new dispatch package and eventq entry 8437c478bd9Sstevel@tonic-gate */ 8447c478bd9Sstevel@tonic-gate newq = (struct event_dispatchq *)malloc( 8457c478bd9Sstevel@tonic-gate sizeof (struct event_dispatchq)); 8467c478bd9Sstevel@tonic-gate if (newq == NULL) { 8477c478bd9Sstevel@tonic-gate (void) mutex_unlock(&scp->client_lock); 8487c478bd9Sstevel@tonic-gate return (NULL); 8497c478bd9Sstevel@tonic-gate } 8507c478bd9Sstevel@tonic-gate 8517c478bd9Sstevel@tonic-gate d_pkg = (struct event_dispatch_pkg *)malloc( 8527c478bd9Sstevel@tonic-gate sizeof (struct event_dispatch_pkg)); 8537c478bd9Sstevel@tonic-gate if (d_pkg == NULL) { 8547c478bd9Sstevel@tonic-gate free(newq); 8557c478bd9Sstevel@tonic-gate (void) mutex_unlock(&scp->client_lock); 8567c478bd9Sstevel@tonic-gate return (NULL); 8577c478bd9Sstevel@tonic-gate } 8587c478bd9Sstevel@tonic-gate 8597c478bd9Sstevel@tonic-gate /* Initialize the dispatch package */ 8607c478bd9Sstevel@tonic-gate d_pkg->scp = scp; 8617c478bd9Sstevel@tonic-gate d_pkg->retry_count = 0; 8627c478bd9Sstevel@tonic-gate d_pkg->completion_status = 0; 8637c478bd9Sstevel@tonic-gate d_pkg->completion_state = SE_NOT_DISPATCHED; 8647c478bd9Sstevel@tonic-gate d_pkg->completion_sema = completion_sema; 8657c478bd9Sstevel@tonic-gate d_pkg->ev = ev; 8667c478bd9Sstevel@tonic-gate newq->d_pkg = d_pkg; 8677c478bd9Sstevel@tonic-gate newq->next = NULL; 8687c478bd9Sstevel@tonic-gate 8697c478bd9Sstevel@tonic-gate if (scp->eventq != NULL) { 8707c478bd9Sstevel@tonic-gate 8717c478bd9Sstevel@tonic-gate /* Add entry to the end of the eventq */ 8727c478bd9Sstevel@tonic-gate tmp = scp->eventq; 8737c478bd9Sstevel@tonic-gate while (tmp->next != NULL) 8747c478bd9Sstevel@tonic-gate tmp = tmp->next; 8757c478bd9Sstevel@tonic-gate tmp->next = newq; 8767c478bd9Sstevel@tonic-gate } else { 8777c478bd9Sstevel@tonic-gate /* event queue empty, wakeup delivery thread */ 8787c478bd9Sstevel@tonic-gate scp->eventq = newq; 8797c478bd9Sstevel@tonic-gate (void) cond_signal(&scp->client_cv); 8807c478bd9Sstevel@tonic-gate } 8817c478bd9Sstevel@tonic-gate (void) mutex_unlock(&scp->client_lock); 8827c478bd9Sstevel@tonic-gate 8837c478bd9Sstevel@tonic-gate return (d_pkg); 8847c478bd9Sstevel@tonic-gate } 8857c478bd9Sstevel@tonic-gate 8867c478bd9Sstevel@tonic-gate /* 8877c478bd9Sstevel@tonic-gate * event_completion_thr - Event completion thread. This thread routine 8887c478bd9Sstevel@tonic-gate * waits for all client delivery thread to complete 8897c478bd9Sstevel@tonic-gate * delivery of a particular event. 8907c478bd9Sstevel@tonic-gate */ 8917c478bd9Sstevel@tonic-gate static void 8927c478bd9Sstevel@tonic-gate event_completion_thr() 8937c478bd9Sstevel@tonic-gate { 8947c478bd9Sstevel@tonic-gate int ret, i, client_count, ok_to_free; 8957c478bd9Sstevel@tonic-gate sysevent_id_t eid; 8967c478bd9Sstevel@tonic-gate struct sysevent_client *scp; 8977c478bd9Sstevel@tonic-gate struct ev_completion *ev_comp; 8987c478bd9Sstevel@tonic-gate struct event_dispatchq *dispatchq; 8997c478bd9Sstevel@tonic-gate struct event_dispatch_pkg *d_pkg; 9007c478bd9Sstevel@tonic-gate 9017c478bd9Sstevel@tonic-gate (void) mutex_lock(&ev_comp_lock); 9027c478bd9Sstevel@tonic-gate for (;;) { 9037c478bd9Sstevel@tonic-gate while (event_compq == NULL) { 9047c478bd9Sstevel@tonic-gate (void) cond_wait(&event_comp_cv, &ev_comp_lock); 9057c478bd9Sstevel@tonic-gate } 9067c478bd9Sstevel@tonic-gate 9077c478bd9Sstevel@tonic-gate /* 9087c478bd9Sstevel@tonic-gate * Process event completions from the head of the 9097c478bd9Sstevel@tonic-gate * completion queue 9107c478bd9Sstevel@tonic-gate */ 9117c478bd9Sstevel@tonic-gate ev_comp = event_compq; 9127c478bd9Sstevel@tonic-gate while (ev_comp) { 9137c478bd9Sstevel@tonic-gate (void) mutex_unlock(&ev_comp_lock); 9147c478bd9Sstevel@tonic-gate eid.eid_seq = sysevent_get_seq(ev_comp->ev); 9157c478bd9Sstevel@tonic-gate sysevent_get_time(ev_comp->ev, &eid.eid_ts); 9167c478bd9Sstevel@tonic-gate client_count = ev_comp->client_count; 9177c478bd9Sstevel@tonic-gate ok_to_free = 1; 9187c478bd9Sstevel@tonic-gate 9197c478bd9Sstevel@tonic-gate syseventd_print(3, "Wait for event completion of " 9207c478bd9Sstevel@tonic-gate "event 0X%llx on %d clients\n", 9217c478bd9Sstevel@tonic-gate eid.eid_seq, client_count); 9227c478bd9Sstevel@tonic-gate 9237c478bd9Sstevel@tonic-gate while (client_count) { 9247c478bd9Sstevel@tonic-gate syseventd_print(9, "Waiting for %d clients on " 9257c478bd9Sstevel@tonic-gate "event id 0X%llx\n", client_count, 9267c478bd9Sstevel@tonic-gate eid.eid_seq); 9277c478bd9Sstevel@tonic-gate 9287c478bd9Sstevel@tonic-gate (void) sema_wait(&ev_comp->client_sema); 9297c478bd9Sstevel@tonic-gate --client_count; 9307c478bd9Sstevel@tonic-gate } 9317c478bd9Sstevel@tonic-gate 9327c478bd9Sstevel@tonic-gate syseventd_print(3, "Cleaning up clients for event " 9337c478bd9Sstevel@tonic-gate "0X%llx\n", eid.eid_seq); 9347c478bd9Sstevel@tonic-gate dispatchq = ev_comp->dispatch_list; 9357c478bd9Sstevel@tonic-gate while (dispatchq != NULL) { 9367c478bd9Sstevel@tonic-gate d_pkg = dispatchq->d_pkg; 9377c478bd9Sstevel@tonic-gate scp = d_pkg->scp; 9387c478bd9Sstevel@tonic-gate 9397c478bd9Sstevel@tonic-gate if (d_pkg->completion_status == EAGAIN) 9407c478bd9Sstevel@tonic-gate ok_to_free = 0; 9417c478bd9Sstevel@tonic-gate 9427c478bd9Sstevel@tonic-gate syseventd_print(4, "Delivery of 0X%llx " 9437c478bd9Sstevel@tonic-gate "complete for client %d retry count %d " 9447c478bd9Sstevel@tonic-gate "status %d\n", eid.eid_seq, 9457c478bd9Sstevel@tonic-gate scp->client_num, 9467c478bd9Sstevel@tonic-gate d_pkg->retry_count, 9477c478bd9Sstevel@tonic-gate d_pkg->completion_status); 9487c478bd9Sstevel@tonic-gate 9497c478bd9Sstevel@tonic-gate free(d_pkg); 9507c478bd9Sstevel@tonic-gate ev_comp->dispatch_list = dispatchq->next; 9517c478bd9Sstevel@tonic-gate free(dispatchq); 9527c478bd9Sstevel@tonic-gate dispatchq = ev_comp->dispatch_list; 9537c478bd9Sstevel@tonic-gate } 9547c478bd9Sstevel@tonic-gate 9557c478bd9Sstevel@tonic-gate if (ok_to_free) { 9567c478bd9Sstevel@tonic-gate for (i = 0; i < MAX_MODCTL_RETRY; ++i) { 9577c478bd9Sstevel@tonic-gate if ((ret = modctl(MODEVENTS, 9587c478bd9Sstevel@tonic-gate (uintptr_t)MODEVENTS_FREEDATA, 9597c478bd9Sstevel@tonic-gate (uintptr_t)&eid, NULL, 9607c478bd9Sstevel@tonic-gate NULL, 0)) != 0) { 9617c478bd9Sstevel@tonic-gate syseventd_print(1, "attempting " 9627c478bd9Sstevel@tonic-gate "to free event 0X%llx\n", 9637c478bd9Sstevel@tonic-gate eid.eid_seq); 9647c478bd9Sstevel@tonic-gate 9657c478bd9Sstevel@tonic-gate /* 9667c478bd9Sstevel@tonic-gate * Kernel may need time to 9677c478bd9Sstevel@tonic-gate * move this event buffer to 9687c478bd9Sstevel@tonic-gate * the sysevent sent queue 9697c478bd9Sstevel@tonic-gate */ 9707c478bd9Sstevel@tonic-gate (void) sleep(1); 9717c478bd9Sstevel@tonic-gate } else { 9727c478bd9Sstevel@tonic-gate break; 9737c478bd9Sstevel@tonic-gate } 9747c478bd9Sstevel@tonic-gate } 9757c478bd9Sstevel@tonic-gate if (ret) { 9767c478bd9Sstevel@tonic-gate syseventd_print(1, "Unable to free " 9777c478bd9Sstevel@tonic-gate "event 0X%llx from the " 9787c478bd9Sstevel@tonic-gate "kernel\n", eid.eid_seq); 9797c478bd9Sstevel@tonic-gate } 9807c478bd9Sstevel@tonic-gate } else { 9817c478bd9Sstevel@tonic-gate syseventd_print(1, "Not freeing event 0X%llx\n", 9827c478bd9Sstevel@tonic-gate eid.eid_seq); 9837c478bd9Sstevel@tonic-gate } 9847c478bd9Sstevel@tonic-gate 9857c478bd9Sstevel@tonic-gate syseventd_print(2, "Event delivery complete for id " 9867c478bd9Sstevel@tonic-gate "0X%llx\n", eid.eid_seq); 9877c478bd9Sstevel@tonic-gate 9887c478bd9Sstevel@tonic-gate (void) mutex_lock(&ev_comp_lock); 9897c478bd9Sstevel@tonic-gate event_compq = ev_comp->next; 9907c478bd9Sstevel@tonic-gate free(ev_comp->ev); 9917c478bd9Sstevel@tonic-gate free(ev_comp); 9927c478bd9Sstevel@tonic-gate ev_comp = event_compq; 9937c478bd9Sstevel@tonic-gate (void) sema_post(&sema_resource); 9947c478bd9Sstevel@tonic-gate } 9957c478bd9Sstevel@tonic-gate 9967c478bd9Sstevel@tonic-gate /* 9977c478bd9Sstevel@tonic-gate * Event completion queue is empty, signal possible unload 9987c478bd9Sstevel@tonic-gate * operation 9997c478bd9Sstevel@tonic-gate */ 10007c478bd9Sstevel@tonic-gate (void) cond_signal(&event_comp_cv); 10017c478bd9Sstevel@tonic-gate 10027c478bd9Sstevel@tonic-gate syseventd_print(3, "No more events\n"); 10037c478bd9Sstevel@tonic-gate } 10047c478bd9Sstevel@tonic-gate } 10057c478bd9Sstevel@tonic-gate 10067c478bd9Sstevel@tonic-gate /* 10077c478bd9Sstevel@tonic-gate * dispatch - Dispatch the current event buffer to all valid SLM clients. 10087c478bd9Sstevel@tonic-gate */ 10097c478bd9Sstevel@tonic-gate static int 10107c478bd9Sstevel@tonic-gate dispatch(void) 10117c478bd9Sstevel@tonic-gate { 10127c478bd9Sstevel@tonic-gate int ev_sz, i, client_count = 0; 10137c478bd9Sstevel@tonic-gate sysevent_t *new_ev; 10147c478bd9Sstevel@tonic-gate sysevent_id_t eid; 10157c478bd9Sstevel@tonic-gate struct ev_completion *ev_comp, *tmp; 10167c478bd9Sstevel@tonic-gate struct event_dispatchq *dispatchq, *client_list; 10177c478bd9Sstevel@tonic-gate struct event_dispatch_pkg *d_pkg; 10187c478bd9Sstevel@tonic-gate 10197c478bd9Sstevel@tonic-gate /* Check for module unload operation */ 10207c478bd9Sstevel@tonic-gate if (rw_tryrdlock(&mod_unload_lock) != 0) { 10217c478bd9Sstevel@tonic-gate syseventd_print(2, "unload in progress abort delivery\n"); 10227c478bd9Sstevel@tonic-gate (void) sema_post(&sema_eventbuf); 10237c478bd9Sstevel@tonic-gate (void) sema_post(&sema_resource); 10247c478bd9Sstevel@tonic-gate return (0); 10257c478bd9Sstevel@tonic-gate } 10267c478bd9Sstevel@tonic-gate 10277c478bd9Sstevel@tonic-gate syseventd_print(3, "deliver dispatch buffer %d", dispatch_buf); 10287c478bd9Sstevel@tonic-gate eid.eid_seq = sysevent_get_seq(eventbuf[dispatch_buf]); 10297c478bd9Sstevel@tonic-gate sysevent_get_time(eventbuf[dispatch_buf], &eid.eid_ts); 10307c478bd9Sstevel@tonic-gate syseventd_print(3, "deliver msg id: 0x%llx\n", eid.eid_seq); 10317c478bd9Sstevel@tonic-gate 10327c478bd9Sstevel@tonic-gate /* 10337c478bd9Sstevel@tonic-gate * ev_comp is used to hold event completion data. It is freed 10347c478bd9Sstevel@tonic-gate * by the event completion thread (event_completion_thr). 10357c478bd9Sstevel@tonic-gate */ 10367c478bd9Sstevel@tonic-gate ev_comp = (struct ev_completion *) 10377c478bd9Sstevel@tonic-gate malloc(sizeof (struct ev_completion)); 10387c478bd9Sstevel@tonic-gate if (ev_comp == NULL) { 10397c478bd9Sstevel@tonic-gate (void) rw_unlock(&mod_unload_lock); 10407c478bd9Sstevel@tonic-gate syseventd_print(1, "Can not allocate event completion buffer " 10417c478bd9Sstevel@tonic-gate "for event id 0X%llx\n", eid.eid_seq); 10427c478bd9Sstevel@tonic-gate return (EAGAIN); 10437c478bd9Sstevel@tonic-gate } 10447c478bd9Sstevel@tonic-gate ev_comp->dispatch_list = NULL; 10457c478bd9Sstevel@tonic-gate ev_comp->next = NULL; 10467c478bd9Sstevel@tonic-gate (void) sema_init(&ev_comp->client_sema, 0, USYNC_THREAD, NULL); 10477c478bd9Sstevel@tonic-gate 10487c478bd9Sstevel@tonic-gate ev_sz = sysevent_get_size(eventbuf[dispatch_buf]); 10497c478bd9Sstevel@tonic-gate new_ev = calloc(1, ev_sz); 10507c478bd9Sstevel@tonic-gate if (new_ev == NULL) { 10517c478bd9Sstevel@tonic-gate free(ev_comp); 10527c478bd9Sstevel@tonic-gate (void) rw_unlock(&mod_unload_lock); 10537c478bd9Sstevel@tonic-gate syseventd_print(1, "Can not allocate new event buffer " 10547c478bd9Sstevel@tonic-gate "for event id 0X%llx\n", eid.eid_seq); 10557c478bd9Sstevel@tonic-gate return (EAGAIN); 10567c478bd9Sstevel@tonic-gate } 10577c478bd9Sstevel@tonic-gate 10587c478bd9Sstevel@tonic-gate 10597c478bd9Sstevel@tonic-gate /* 10607c478bd9Sstevel@tonic-gate * For long messages, copy additional data from kernel 10617c478bd9Sstevel@tonic-gate */ 10627c478bd9Sstevel@tonic-gate if (ev_sz > LOGEVENT_BUFSIZE) { 10637c478bd9Sstevel@tonic-gate int ret = 0; 10647c478bd9Sstevel@tonic-gate 10657c478bd9Sstevel@tonic-gate /* Ok to release eventbuf for next event buffer from kernel */ 10667c478bd9Sstevel@tonic-gate (void) sema_post(&sema_eventbuf); 10677c478bd9Sstevel@tonic-gate 10687c478bd9Sstevel@tonic-gate for (i = 0; i < MAX_MODCTL_RETRY; ++i) { 10697c478bd9Sstevel@tonic-gate if ((ret = modctl(MODEVENTS, 10707c478bd9Sstevel@tonic-gate (uintptr_t)MODEVENTS_GETDATA, 10717c478bd9Sstevel@tonic-gate (uintptr_t)&eid, 10727c478bd9Sstevel@tonic-gate (uintptr_t)ev_sz, 10737c478bd9Sstevel@tonic-gate (uintptr_t)new_ev, 0)) 10747c478bd9Sstevel@tonic-gate == 0) 10757c478bd9Sstevel@tonic-gate break; 10767c478bd9Sstevel@tonic-gate else 10777c478bd9Sstevel@tonic-gate (void) sleep(1); 10787c478bd9Sstevel@tonic-gate } 10797c478bd9Sstevel@tonic-gate if (ret) { 10807c478bd9Sstevel@tonic-gate syseventd_print(1, "GET_DATA failed for 0X%llx:%llx\n", 10817c478bd9Sstevel@tonic-gate eid.eid_ts, eid.eid_seq); 10827c478bd9Sstevel@tonic-gate free(new_ev); 10837c478bd9Sstevel@tonic-gate free(ev_comp); 10847c478bd9Sstevel@tonic-gate (void) rw_unlock(&mod_unload_lock); 10857c478bd9Sstevel@tonic-gate return (EAGAIN); 10867c478bd9Sstevel@tonic-gate } 10877c478bd9Sstevel@tonic-gate } else { 10887c478bd9Sstevel@tonic-gate (void) bcopy(eventbuf[dispatch_buf], new_ev, ev_sz); 10897c478bd9Sstevel@tonic-gate /* Ok to release eventbuf for next event buffer from kernel */ 10907c478bd9Sstevel@tonic-gate (void) sema_post(&sema_eventbuf); 10917c478bd9Sstevel@tonic-gate } 10927c478bd9Sstevel@tonic-gate 10937c478bd9Sstevel@tonic-gate 10947c478bd9Sstevel@tonic-gate /* 10957c478bd9Sstevel@tonic-gate * Deliver a copy of eventbuf to clients so 10967c478bd9Sstevel@tonic-gate * eventbuf can be used for the next message 10977c478bd9Sstevel@tonic-gate */ 10987c478bd9Sstevel@tonic-gate for (i = 0; i < MAX_SLM; ++i) { 10997c478bd9Sstevel@tonic-gate 11007c478bd9Sstevel@tonic-gate /* Don't bother for suspended or unloaded clients */ 11017c478bd9Sstevel@tonic-gate if (!SE_CLIENT_IS_LOADED(sysevent_client_tbl[i]) || 11027c478bd9Sstevel@tonic-gate SE_CLIENT_IS_SUSPENDED(sysevent_client_tbl[i])) 11037c478bd9Sstevel@tonic-gate continue; 11047c478bd9Sstevel@tonic-gate 11057c478bd9Sstevel@tonic-gate /* 11067c478bd9Sstevel@tonic-gate * Allocate event dispatch queue entry. All queue entries 11077c478bd9Sstevel@tonic-gate * are freed by the event completion thread as client 11087c478bd9Sstevel@tonic-gate * delivery completes. 11097c478bd9Sstevel@tonic-gate */ 11107c478bd9Sstevel@tonic-gate dispatchq = (struct event_dispatchq *)malloc( 11117c478bd9Sstevel@tonic-gate sizeof (struct event_dispatchq)); 11127c478bd9Sstevel@tonic-gate if (dispatchq == NULL) { 11137c478bd9Sstevel@tonic-gate syseventd_print(1, "Can not allocate dispatch q " 11147c478bd9Sstevel@tonic-gate "for event id 0X%llx client %d\n", eid.eid_seq, i); 11157c478bd9Sstevel@tonic-gate continue; 11167c478bd9Sstevel@tonic-gate } 11177c478bd9Sstevel@tonic-gate dispatchq->next = NULL; 11187c478bd9Sstevel@tonic-gate 11197c478bd9Sstevel@tonic-gate /* Initiate client delivery */ 11207c478bd9Sstevel@tonic-gate d_pkg = client_deliver_event(sysevent_client_tbl[i], 11217c478bd9Sstevel@tonic-gate new_ev, &ev_comp->client_sema); 11227c478bd9Sstevel@tonic-gate if (d_pkg == NULL) { 11237c478bd9Sstevel@tonic-gate syseventd_print(1, "Can not allocate dispatch " 11247c478bd9Sstevel@tonic-gate "package for event id 0X%llx client %d\n", 11257c478bd9Sstevel@tonic-gate eid.eid_seq, i); 11267c478bd9Sstevel@tonic-gate free(dispatchq); 11277c478bd9Sstevel@tonic-gate continue; 11287c478bd9Sstevel@tonic-gate } 11297c478bd9Sstevel@tonic-gate dispatchq->d_pkg = d_pkg; 11307c478bd9Sstevel@tonic-gate ++client_count; 11317c478bd9Sstevel@tonic-gate 11327c478bd9Sstevel@tonic-gate if (ev_comp->dispatch_list == NULL) { 11337c478bd9Sstevel@tonic-gate ev_comp->dispatch_list = dispatchq; 11347c478bd9Sstevel@tonic-gate client_list = dispatchq; 11357c478bd9Sstevel@tonic-gate } else { 11367c478bd9Sstevel@tonic-gate client_list->next = dispatchq; 11377c478bd9Sstevel@tonic-gate client_list = client_list->next; 11387c478bd9Sstevel@tonic-gate } 11397c478bd9Sstevel@tonic-gate } 11407c478bd9Sstevel@tonic-gate 11417c478bd9Sstevel@tonic-gate ev_comp->client_count = client_count; 11427c478bd9Sstevel@tonic-gate ev_comp->ev = new_ev; 11437c478bd9Sstevel@tonic-gate 11447c478bd9Sstevel@tonic-gate (void) mutex_lock(&ev_comp_lock); 11457c478bd9Sstevel@tonic-gate 11467c478bd9Sstevel@tonic-gate if (event_compq == NULL) { 11477c478bd9Sstevel@tonic-gate syseventd_print(3, "Wakeup event completion thread for " 11487c478bd9Sstevel@tonic-gate "id 0X%llx\n", eid.eid_seq); 11497c478bd9Sstevel@tonic-gate event_compq = ev_comp; 11507c478bd9Sstevel@tonic-gate (void) cond_signal(&event_comp_cv); 11517c478bd9Sstevel@tonic-gate } else { 11527c478bd9Sstevel@tonic-gate 11537c478bd9Sstevel@tonic-gate /* Add entry to the end of the event completion queue */ 11547c478bd9Sstevel@tonic-gate tmp = event_compq; 11557c478bd9Sstevel@tonic-gate while (tmp->next != NULL) 11567c478bd9Sstevel@tonic-gate tmp = tmp->next; 11577c478bd9Sstevel@tonic-gate tmp->next = ev_comp; 11587c478bd9Sstevel@tonic-gate syseventd_print(3, "event added to completion queue for " 11597c478bd9Sstevel@tonic-gate "id 0X%llx\n", eid.eid_seq); 11607c478bd9Sstevel@tonic-gate } 11617c478bd9Sstevel@tonic-gate (void) mutex_unlock(&ev_comp_lock); 11627c478bd9Sstevel@tonic-gate (void) rw_unlock(&mod_unload_lock); 11637c478bd9Sstevel@tonic-gate 11647c478bd9Sstevel@tonic-gate return (0); 11657c478bd9Sstevel@tonic-gate } 11667c478bd9Sstevel@tonic-gate 11677c478bd9Sstevel@tonic-gate #define MODULE_DIR_HW "/usr/platform/%s/lib/sysevent/modules/" 11687c478bd9Sstevel@tonic-gate #define MODULE_DIR_GEN "/usr/lib/sysevent/modules/" 11697c478bd9Sstevel@tonic-gate #define MOD_DIR_NUM 3 11707c478bd9Sstevel@tonic-gate static char dirname[MOD_DIR_NUM][MAXPATHLEN]; 11717c478bd9Sstevel@tonic-gate 11727c478bd9Sstevel@tonic-gate static char * 11737c478bd9Sstevel@tonic-gate dir_num2name(int dirnum) 11747c478bd9Sstevel@tonic-gate { 11757c478bd9Sstevel@tonic-gate char infobuf[MAXPATHLEN]; 11767c478bd9Sstevel@tonic-gate 11777c478bd9Sstevel@tonic-gate if (dirnum >= MOD_DIR_NUM) 11787c478bd9Sstevel@tonic-gate return (NULL); 11797c478bd9Sstevel@tonic-gate 11807c478bd9Sstevel@tonic-gate if (dirname[0][0] == '\0') { 11817c478bd9Sstevel@tonic-gate if (sysinfo(SI_PLATFORM, infobuf, MAXPATHLEN) == -1) { 11827c478bd9Sstevel@tonic-gate syseventd_print(1, "dir_num2name: " 11837c478bd9Sstevel@tonic-gate "sysinfo error %s\n", strerror(errno)); 11847c478bd9Sstevel@tonic-gate return (NULL); 11857c478bd9Sstevel@tonic-gate } else if (snprintf(dirname[0], sizeof (dirname[0]), 11867c478bd9Sstevel@tonic-gate MODULE_DIR_HW, infobuf) >= sizeof (dirname[0])) { 11877c478bd9Sstevel@tonic-gate syseventd_print(1, "dir_num2name: " 11887c478bd9Sstevel@tonic-gate "platform name too long: %s\n", 11897c478bd9Sstevel@tonic-gate infobuf); 11907c478bd9Sstevel@tonic-gate return (NULL); 11917c478bd9Sstevel@tonic-gate } 11927c478bd9Sstevel@tonic-gate if (sysinfo(SI_MACHINE, infobuf, MAXPATHLEN) == -1) { 11937c478bd9Sstevel@tonic-gate syseventd_print(1, "dir_num2name: " 11947c478bd9Sstevel@tonic-gate "sysinfo error %s\n", strerror(errno)); 11957c478bd9Sstevel@tonic-gate return (NULL); 11967c478bd9Sstevel@tonic-gate } else if (snprintf(dirname[1], sizeof (dirname[1]), 11977c478bd9Sstevel@tonic-gate MODULE_DIR_HW, infobuf) >= sizeof (dirname[1])) { 11987c478bd9Sstevel@tonic-gate syseventd_print(1, "dir_num2name: " 11997c478bd9Sstevel@tonic-gate "machine name too long: %s\n", 12007c478bd9Sstevel@tonic-gate infobuf); 12017c478bd9Sstevel@tonic-gate return (NULL); 12027c478bd9Sstevel@tonic-gate } 12037c478bd9Sstevel@tonic-gate (void) strcpy(dirname[2], MODULE_DIR_GEN); 12047c478bd9Sstevel@tonic-gate } 12057c478bd9Sstevel@tonic-gate 12067c478bd9Sstevel@tonic-gate return (dirname[dirnum]); 12077c478bd9Sstevel@tonic-gate } 12087c478bd9Sstevel@tonic-gate 12097c478bd9Sstevel@tonic-gate 12107c478bd9Sstevel@tonic-gate /* 12117c478bd9Sstevel@tonic-gate * load_modules - Load modules found in the common syseventd module directories 12127c478bd9Sstevel@tonic-gate * Modules that do not provide valid interfaces are rejected. 12137c478bd9Sstevel@tonic-gate */ 12147c478bd9Sstevel@tonic-gate static void 12157c478bd9Sstevel@tonic-gate load_modules(char *dirname) 12167c478bd9Sstevel@tonic-gate { 12177c478bd9Sstevel@tonic-gate int client_id; 12187c478bd9Sstevel@tonic-gate DIR *mod_dir; 12197c478bd9Sstevel@tonic-gate module_t *mod; 12204bc0a2efScasper struct dirent *entp; 12217c478bd9Sstevel@tonic-gate struct slm_mod_ops *mod_ops; 12227c478bd9Sstevel@tonic-gate struct sysevent_client *scp; 12237c478bd9Sstevel@tonic-gate 12247c478bd9Sstevel@tonic-gate if (dirname == NULL) 12257c478bd9Sstevel@tonic-gate return; 12267c478bd9Sstevel@tonic-gate 12277c478bd9Sstevel@tonic-gate /* Return silently if module directory does not exist */ 12287c478bd9Sstevel@tonic-gate if ((mod_dir = opendir(dirname)) == NULL) { 12297c478bd9Sstevel@tonic-gate syseventd_print(1, "Unable to open module directory %s: %s\n", 12307c478bd9Sstevel@tonic-gate dirname, strerror(errno)); 12317c478bd9Sstevel@tonic-gate return; 12327c478bd9Sstevel@tonic-gate } 12337c478bd9Sstevel@tonic-gate 12347c478bd9Sstevel@tonic-gate syseventd_print(3, "loading modules from %s\n", dirname); 12357c478bd9Sstevel@tonic-gate 12367c478bd9Sstevel@tonic-gate /* 12377c478bd9Sstevel@tonic-gate * Go through directory, looking for files ending with .so 12387c478bd9Sstevel@tonic-gate */ 12394bc0a2efScasper while ((entp = readdir(mod_dir)) != NULL) { 12407c478bd9Sstevel@tonic-gate void *dlh, *f; 12417c478bd9Sstevel@tonic-gate char *tmp, modpath[MAXPATHLEN]; 12427c478bd9Sstevel@tonic-gate 12437c478bd9Sstevel@tonic-gate if (((tmp = strstr(entp->d_name, MODULE_SUFFIX)) == NULL) || 12447c478bd9Sstevel@tonic-gate (tmp[strlen(MODULE_SUFFIX)] != '\0')) { 12457c478bd9Sstevel@tonic-gate continue; 12467c478bd9Sstevel@tonic-gate } 12477c478bd9Sstevel@tonic-gate 12487c478bd9Sstevel@tonic-gate if (snprintf(modpath, sizeof (modpath), "%s%s", 12497c478bd9Sstevel@tonic-gate dirname, entp->d_name) >= sizeof (modpath)) { 12507c478bd9Sstevel@tonic-gate syseventd_err_print(INIT_PATH_ERR, modpath); 12517c478bd9Sstevel@tonic-gate continue; 12527c478bd9Sstevel@tonic-gate } 12537c478bd9Sstevel@tonic-gate if ((dlh = dlopen(modpath, RTLD_LAZY)) == NULL) { 12547c478bd9Sstevel@tonic-gate syseventd_err_print(LOAD_MOD_DLOPEN_ERR, 12557c478bd9Sstevel@tonic-gate modpath, dlerror()); 12567c478bd9Sstevel@tonic-gate continue; 12577c478bd9Sstevel@tonic-gate } else if ((f = dlsym(dlh, EVENT_INIT)) == NULL) { 12587c478bd9Sstevel@tonic-gate syseventd_err_print(LOAD_MOD_NO_INIT, 12597c478bd9Sstevel@tonic-gate modpath, dlerror()); 12607c478bd9Sstevel@tonic-gate (void) dlclose(dlh); 12617c478bd9Sstevel@tonic-gate continue; 12627c478bd9Sstevel@tonic-gate } 12637c478bd9Sstevel@tonic-gate 12647c478bd9Sstevel@tonic-gate mod = malloc(sizeof (*mod)); 12657c478bd9Sstevel@tonic-gate if (mod == NULL) { 12667c478bd9Sstevel@tonic-gate syseventd_err_print(LOAD_MOD_ALLOC_ERR, "mod", 12677c478bd9Sstevel@tonic-gate strerror(errno)); 12687c478bd9Sstevel@tonic-gate (void) dlclose(dlh); 12697c478bd9Sstevel@tonic-gate continue; 12707c478bd9Sstevel@tonic-gate } 12717c478bd9Sstevel@tonic-gate 12727c478bd9Sstevel@tonic-gate mod->name = strdup(entp->d_name); 12737c478bd9Sstevel@tonic-gate if (mod->name == NULL) { 12747c478bd9Sstevel@tonic-gate syseventd_err_print(LOAD_MOD_ALLOC_ERR, "mod->name", 12757c478bd9Sstevel@tonic-gate strerror(errno)); 12767c478bd9Sstevel@tonic-gate (void) dlclose(dlh); 12777c478bd9Sstevel@tonic-gate free(mod); 12787c478bd9Sstevel@tonic-gate continue; 12797c478bd9Sstevel@tonic-gate } 12807c478bd9Sstevel@tonic-gate 12817c478bd9Sstevel@tonic-gate mod->dlhandle = dlh; 12827c478bd9Sstevel@tonic-gate mod->event_mod_init = (struct slm_mod_ops *(*)())f; 12837c478bd9Sstevel@tonic-gate 12847c478bd9Sstevel@tonic-gate /* load in other module functions */ 12857c478bd9Sstevel@tonic-gate mod->event_mod_fini = (void (*)())dlsym(dlh, EVENT_FINI); 12867c478bd9Sstevel@tonic-gate if (mod->event_mod_fini == NULL) { 12877c478bd9Sstevel@tonic-gate syseventd_err_print(LOAD_MOD_DLSYM_ERR, mod->name, 12887c478bd9Sstevel@tonic-gate dlerror()); 12897c478bd9Sstevel@tonic-gate free(mod->name); 12907c478bd9Sstevel@tonic-gate free(mod); 12917c478bd9Sstevel@tonic-gate (void) dlclose(dlh); 12927c478bd9Sstevel@tonic-gate continue; 12937c478bd9Sstevel@tonic-gate } 12947c478bd9Sstevel@tonic-gate 12957c478bd9Sstevel@tonic-gate /* Call module init routine */ 12967c478bd9Sstevel@tonic-gate if ((mod_ops = mod->event_mod_init()) == NULL) { 12977c478bd9Sstevel@tonic-gate syseventd_err_print(LOAD_MOD_EINVAL, mod->name); 12987c478bd9Sstevel@tonic-gate free(mod->name); 12997c478bd9Sstevel@tonic-gate free(mod); 13007c478bd9Sstevel@tonic-gate (void) dlclose(dlh); 13017c478bd9Sstevel@tonic-gate continue; 13027c478bd9Sstevel@tonic-gate } 13037c478bd9Sstevel@tonic-gate if (mod_ops->major_version != SE_MAJOR_VERSION) { 13047c478bd9Sstevel@tonic-gate syseventd_err_print(LOAD_MOD_VERSION_MISMATCH, 13057c478bd9Sstevel@tonic-gate mod->name, SE_MAJOR_VERSION, 13067c478bd9Sstevel@tonic-gate mod_ops->major_version); 13077c478bd9Sstevel@tonic-gate mod->event_mod_fini(); 13087c478bd9Sstevel@tonic-gate free(mod->name); 13097c478bd9Sstevel@tonic-gate free(mod); 13107c478bd9Sstevel@tonic-gate (void) dlclose(dlh); 13117c478bd9Sstevel@tonic-gate continue; 13127c478bd9Sstevel@tonic-gate } 13137c478bd9Sstevel@tonic-gate 13147c478bd9Sstevel@tonic-gate mod->deliver_event = mod_ops->deliver_event; 13157c478bd9Sstevel@tonic-gate /* Add module entry to client list */ 13167c478bd9Sstevel@tonic-gate if ((client_id = insert_client((void *)mod, SLM_CLIENT, 13177c478bd9Sstevel@tonic-gate (mod_ops->retry_limit <= SE_MAX_RETRY_LIMIT ? 1318b3a85157Sjg mod_ops->retry_limit : SE_MAX_RETRY_LIMIT))) < 0) { 13197c478bd9Sstevel@tonic-gate syseventd_err_print(LOAD_MOD_ALLOC_ERR, "insert_client", 13207c478bd9Sstevel@tonic-gate strerror(errno)); 13217c478bd9Sstevel@tonic-gate mod->event_mod_fini(); 13227c478bd9Sstevel@tonic-gate free(mod->name); 13237c478bd9Sstevel@tonic-gate free(mod); 13247c478bd9Sstevel@tonic-gate (void) dlclose(dlh); 13257c478bd9Sstevel@tonic-gate continue; 13267c478bd9Sstevel@tonic-gate } 13277c478bd9Sstevel@tonic-gate 13287c478bd9Sstevel@tonic-gate scp = sysevent_client_tbl[client_id]; 13297c478bd9Sstevel@tonic-gate ++concurrency_level; 13307c478bd9Sstevel@tonic-gate (void) thr_setconcurrency(concurrency_level); 13317c478bd9Sstevel@tonic-gate if (thr_create(NULL, 0, 13327c478bd9Sstevel@tonic-gate (void *(*)(void *))client_deliver_event_thr, 13337c478bd9Sstevel@tonic-gate (void *)scp, THR_BOUND, &scp->tid) != 0) { 13347c478bd9Sstevel@tonic-gate 13357c478bd9Sstevel@tonic-gate syseventd_err_print(LOAD_MOD_ALLOC_ERR, "insert_client", 13367c478bd9Sstevel@tonic-gate strerror(errno)); 13377c478bd9Sstevel@tonic-gate mod->event_mod_fini(); 13387c478bd9Sstevel@tonic-gate free(mod->name); 13397c478bd9Sstevel@tonic-gate free(mod); 13407c478bd9Sstevel@tonic-gate (void) dlclose(dlh); 13417c478bd9Sstevel@tonic-gate continue; 13427c478bd9Sstevel@tonic-gate } 13437c478bd9Sstevel@tonic-gate scp->client_flags |= SE_CLIENT_THR_RUNNING; 13447c478bd9Sstevel@tonic-gate 13457c478bd9Sstevel@tonic-gate syseventd_print(3, "loaded module %s\n", entp->d_name); 13467c478bd9Sstevel@tonic-gate } 13477c478bd9Sstevel@tonic-gate 13487c478bd9Sstevel@tonic-gate (void) closedir(mod_dir); 13497c478bd9Sstevel@tonic-gate syseventd_print(3, "modules loaded\n"); 13507c478bd9Sstevel@tonic-gate } 13517c478bd9Sstevel@tonic-gate 13527c478bd9Sstevel@tonic-gate /* 13537c478bd9Sstevel@tonic-gate * unload_modules - modules are unloaded prior to graceful shutdown or 13547c478bd9Sstevel@tonic-gate * before restarting the daemon upon receipt of 13557c478bd9Sstevel@tonic-gate * SIGHUP. 13567c478bd9Sstevel@tonic-gate */ 13577c478bd9Sstevel@tonic-gate static void 13587c478bd9Sstevel@tonic-gate unload_modules(int sig) 13597c478bd9Sstevel@tonic-gate { 13607c478bd9Sstevel@tonic-gate int i, count, done; 13617c478bd9Sstevel@tonic-gate module_t *mod; 13627c478bd9Sstevel@tonic-gate struct sysevent_client *scp; 13637c478bd9Sstevel@tonic-gate 13647c478bd9Sstevel@tonic-gate /* 13657c478bd9Sstevel@tonic-gate * unload modules that are ready, skip those that have not 13667c478bd9Sstevel@tonic-gate * drained their event queues. 13677c478bd9Sstevel@tonic-gate */ 13687c478bd9Sstevel@tonic-gate count = done = 0; 13697c478bd9Sstevel@tonic-gate while (done < MAX_SLM) { 13707c478bd9Sstevel@tonic-gate /* Don't wait indefinitely for unresponsive clients */ 13717c478bd9Sstevel@tonic-gate if (sig != SIGHUP && count > SE_TIMEOUT) { 13727c478bd9Sstevel@tonic-gate break; 13737c478bd9Sstevel@tonic-gate } 13747c478bd9Sstevel@tonic-gate 13757c478bd9Sstevel@tonic-gate done = 0; 13767c478bd9Sstevel@tonic-gate 13777c478bd9Sstevel@tonic-gate /* Shutdown clients */ 13787c478bd9Sstevel@tonic-gate for (i = 0; i < MAX_SLM; ++i) { 13797c478bd9Sstevel@tonic-gate scp = sysevent_client_tbl[i]; 13807c478bd9Sstevel@tonic-gate if (mutex_trylock(&scp->client_lock) == 0) { 13817c478bd9Sstevel@tonic-gate if (scp->client_type != SLM_CLIENT || 13827c478bd9Sstevel@tonic-gate scp->client_data == NULL) { 13837c478bd9Sstevel@tonic-gate (void) mutex_unlock(&scp->client_lock); 13847c478bd9Sstevel@tonic-gate done++; 13857c478bd9Sstevel@tonic-gate continue; 13867c478bd9Sstevel@tonic-gate } 13877c478bd9Sstevel@tonic-gate } else { 13887c478bd9Sstevel@tonic-gate syseventd_print(3, "Skipping unload of " 13897c478bd9Sstevel@tonic-gate "client %d: client locked\n", 13907c478bd9Sstevel@tonic-gate scp->client_num); 13917c478bd9Sstevel@tonic-gate continue; 13927c478bd9Sstevel@tonic-gate } 13937c478bd9Sstevel@tonic-gate 13947c478bd9Sstevel@tonic-gate /* 13957c478bd9Sstevel@tonic-gate * Drain the eventq and wait for delivery thread to 13967c478bd9Sstevel@tonic-gate * cleanly exit 13977c478bd9Sstevel@tonic-gate */ 13987c478bd9Sstevel@tonic-gate drain_eventq(scp, EAGAIN); 13997c478bd9Sstevel@tonic-gate (void) cond_signal(&scp->client_cv); 14007c478bd9Sstevel@tonic-gate (void) mutex_unlock(&scp->client_lock); 14017c478bd9Sstevel@tonic-gate (void) thr_join(scp->tid, NULL, NULL); 14027c478bd9Sstevel@tonic-gate 14037c478bd9Sstevel@tonic-gate /* 14047c478bd9Sstevel@tonic-gate * It is now safe to unload the module 14057c478bd9Sstevel@tonic-gate */ 14067c478bd9Sstevel@tonic-gate mod = (module_t *)scp->client_data; 14077c478bd9Sstevel@tonic-gate syseventd_print(2, "Unload %s\n", mod->name); 14087c478bd9Sstevel@tonic-gate mod->event_mod_fini(); 14097c478bd9Sstevel@tonic-gate (void) dlclose(mod->dlhandle); 14107c478bd9Sstevel@tonic-gate free(mod->name); 14117c478bd9Sstevel@tonic-gate (void) mutex_lock(&client_tbl_lock); 14127c478bd9Sstevel@tonic-gate delete_client(i); 14137c478bd9Sstevel@tonic-gate (void) mutex_unlock(&client_tbl_lock); 14147c478bd9Sstevel@tonic-gate ++done; 14157c478bd9Sstevel@tonic-gate 14167c478bd9Sstevel@tonic-gate } 14177c478bd9Sstevel@tonic-gate ++count; 14187c478bd9Sstevel@tonic-gate (void) sleep(1); 14197c478bd9Sstevel@tonic-gate } 14207c478bd9Sstevel@tonic-gate 14217c478bd9Sstevel@tonic-gate /* 14227c478bd9Sstevel@tonic-gate * Wait for event completions 14237c478bd9Sstevel@tonic-gate */ 14247c478bd9Sstevel@tonic-gate syseventd_print(2, "waiting for event completions\n"); 14257c478bd9Sstevel@tonic-gate (void) mutex_lock(&ev_comp_lock); 14267c478bd9Sstevel@tonic-gate while (event_compq != NULL) { 14277c478bd9Sstevel@tonic-gate (void) cond_wait(&event_comp_cv, &ev_comp_lock); 14287c478bd9Sstevel@tonic-gate } 14297c478bd9Sstevel@tonic-gate (void) mutex_unlock(&ev_comp_lock); 14307c478bd9Sstevel@tonic-gate } 14317c478bd9Sstevel@tonic-gate 14327c478bd9Sstevel@tonic-gate /* 14337c478bd9Sstevel@tonic-gate * syseventd_init - Called at daemon (re)start-up time to load modules 14347c478bd9Sstevel@tonic-gate * and kickstart the kernel delivery engine. 14357c478bd9Sstevel@tonic-gate */ 14367c478bd9Sstevel@tonic-gate static void 14377c478bd9Sstevel@tonic-gate syseventd_init() 14387c478bd9Sstevel@tonic-gate { 14397c478bd9Sstevel@tonic-gate int i, fd; 14407c478bd9Sstevel@tonic-gate char local_door_file[PATH_MAX + 1]; 14417c478bd9Sstevel@tonic-gate 14427c478bd9Sstevel@tonic-gate fini_pending = 0; 14437c478bd9Sstevel@tonic-gate 14447c478bd9Sstevel@tonic-gate concurrency_level = MIN_CONCURRENCY_LEVEL; 14457c478bd9Sstevel@tonic-gate (void) thr_setconcurrency(concurrency_level); 14467c478bd9Sstevel@tonic-gate 14477c478bd9Sstevel@tonic-gate /* 14487c478bd9Sstevel@tonic-gate * Load client modules for event delivering 14497c478bd9Sstevel@tonic-gate */ 14507c478bd9Sstevel@tonic-gate for (i = 0; i < MOD_DIR_NUM; ++i) { 14517c478bd9Sstevel@tonic-gate load_modules(dir_num2name(i)); 14527c478bd9Sstevel@tonic-gate } 14537c478bd9Sstevel@tonic-gate 14547c478bd9Sstevel@tonic-gate /* 14557c478bd9Sstevel@tonic-gate * Create kernel delivery door service 14567c478bd9Sstevel@tonic-gate */ 14577c478bd9Sstevel@tonic-gate syseventd_print(8, "Create a door for kernel upcalls\n"); 14587c478bd9Sstevel@tonic-gate if (snprintf(local_door_file, sizeof (local_door_file), "%s%s", 14597c478bd9Sstevel@tonic-gate root_dir, LOGEVENT_DOOR_UPCALL) >= sizeof (local_door_file)) { 14607c478bd9Sstevel@tonic-gate syseventd_err_print(INIT_PATH_ERR, local_door_file); 14617c478bd9Sstevel@tonic-gate syseventd_exit(5); 14627c478bd9Sstevel@tonic-gate } 14637c478bd9Sstevel@tonic-gate 14647c478bd9Sstevel@tonic-gate /* 14657c478bd9Sstevel@tonic-gate * Remove door file for robustness. 14667c478bd9Sstevel@tonic-gate */ 14677c478bd9Sstevel@tonic-gate if (unlink(local_door_file) != 0) 14687c478bd9Sstevel@tonic-gate syseventd_print(8, "Unlink of %s failed.\n", local_door_file); 14697c478bd9Sstevel@tonic-gate 14707c478bd9Sstevel@tonic-gate fd = open(local_door_file, O_CREAT|O_RDWR, S_IREAD|S_IWRITE); 14717c478bd9Sstevel@tonic-gate if ((fd == -1) && (errno != EEXIST)) { 14727c478bd9Sstevel@tonic-gate syseventd_err_print(INIT_OPEN_DOOR_ERR, strerror(errno)); 14737c478bd9Sstevel@tonic-gate syseventd_exit(5); 14747c478bd9Sstevel@tonic-gate } 14757c478bd9Sstevel@tonic-gate (void) close(fd); 14767c478bd9Sstevel@tonic-gate 14777c478bd9Sstevel@tonic-gate upcall_door = door_create(door_upcall, NULL, 14787c478bd9Sstevel@tonic-gate DOOR_REFUSE_DESC | DOOR_NO_CANCEL); 14797c478bd9Sstevel@tonic-gate if (upcall_door == -1) { 14807c478bd9Sstevel@tonic-gate syseventd_err_print(INIT_CREATE_DOOR_ERR, strerror(errno)); 14817c478bd9Sstevel@tonic-gate syseventd_exit(5); 14827c478bd9Sstevel@tonic-gate } 14837c478bd9Sstevel@tonic-gate 14847c478bd9Sstevel@tonic-gate (void) fdetach(local_door_file); 14857c478bd9Sstevel@tonic-gate retry: 14867c478bd9Sstevel@tonic-gate if (fattach(upcall_door, local_door_file) != 0) { 14877c478bd9Sstevel@tonic-gate if (errno == EBUSY) 14887c478bd9Sstevel@tonic-gate goto retry; 14897c478bd9Sstevel@tonic-gate syseventd_err_print(INIT_FATTACH_ERR, strerror(errno)); 14907c478bd9Sstevel@tonic-gate (void) door_revoke(upcall_door); 14917c478bd9Sstevel@tonic-gate syseventd_exit(5); 14927c478bd9Sstevel@tonic-gate } 14937c478bd9Sstevel@tonic-gate 14947c478bd9Sstevel@tonic-gate /* 14957c478bd9Sstevel@tonic-gate * Tell kernel the door name and start delivery 14967c478bd9Sstevel@tonic-gate */ 14977c478bd9Sstevel@tonic-gate syseventd_print(2, 14987c478bd9Sstevel@tonic-gate "local_door_file = %s\n", local_door_file); 14997c478bd9Sstevel@tonic-gate if (modctl(MODEVENTS, 15007c478bd9Sstevel@tonic-gate (uintptr_t)MODEVENTS_SET_DOOR_UPCALL_FILENAME, 15017c478bd9Sstevel@tonic-gate (uintptr_t)local_door_file, NULL, NULL, 0) < 0) { 15027c478bd9Sstevel@tonic-gate syseventd_err_print(INIT_DOOR_NAME_ERR, strerror(errno)); 15037c478bd9Sstevel@tonic-gate syseventd_exit(6); 15047c478bd9Sstevel@tonic-gate } 15057c478bd9Sstevel@tonic-gate 15067c478bd9Sstevel@tonic-gate door_upcall_retval = 0; 15077c478bd9Sstevel@tonic-gate 15087c478bd9Sstevel@tonic-gate if (modctl(MODEVENTS, (uintptr_t)MODEVENTS_FLUSH, NULL, NULL, NULL, 0) 15097c478bd9Sstevel@tonic-gate < 0) { 15107c478bd9Sstevel@tonic-gate syseventd_err_print(KERNEL_REPLAY_ERR, strerror(errno)); 15117c478bd9Sstevel@tonic-gate syseventd_exit(7); 15127c478bd9Sstevel@tonic-gate } 15137c478bd9Sstevel@tonic-gate } 15147c478bd9Sstevel@tonic-gate 15157c478bd9Sstevel@tonic-gate /* 15167c478bd9Sstevel@tonic-gate * syseventd_fini - shut down daemon, but do not exit 15177c478bd9Sstevel@tonic-gate */ 15187c478bd9Sstevel@tonic-gate static void 15197c478bd9Sstevel@tonic-gate syseventd_fini(int sig) 15207c478bd9Sstevel@tonic-gate { 15217c478bd9Sstevel@tonic-gate /* 15227c478bd9Sstevel@tonic-gate * Indicate that event queues should be drained and no 15237c478bd9Sstevel@tonic-gate * additional events be accepted 15247c478bd9Sstevel@tonic-gate */ 15257c478bd9Sstevel@tonic-gate fini_pending = 1; 15267c478bd9Sstevel@tonic-gate 15277c478bd9Sstevel@tonic-gate /* Close the kernel event door to halt delivery */ 15287c478bd9Sstevel@tonic-gate (void) door_revoke(upcall_door); 15297c478bd9Sstevel@tonic-gate 15307c478bd9Sstevel@tonic-gate syseventd_print(1, "Unloading modules\n"); 15317c478bd9Sstevel@tonic-gate (void) rw_wrlock(&mod_unload_lock); 15327c478bd9Sstevel@tonic-gate unload_modules(sig); 15337c478bd9Sstevel@tonic-gate (void) rw_unlock(&mod_unload_lock); 15347c478bd9Sstevel@tonic-gate 15357c478bd9Sstevel@tonic-gate } 15367c478bd9Sstevel@tonic-gate 15377c478bd9Sstevel@tonic-gate /* 15387c478bd9Sstevel@tonic-gate * enter_daemon_lock - lock the daemon file lock 15397c478bd9Sstevel@tonic-gate * 15407c478bd9Sstevel@tonic-gate * Use an advisory lock to ensure that only one daemon process is active 15417c478bd9Sstevel@tonic-gate * in the system at any point in time. If the lock is held by another 15427c478bd9Sstevel@tonic-gate * process, do not block but return the pid owner of the lock to the 15437c478bd9Sstevel@tonic-gate * caller immediately. The lock is cleared if the holding daemon process 15447c478bd9Sstevel@tonic-gate * exits for any reason even if the lock file remains, so the daemon can 15457c478bd9Sstevel@tonic-gate * be restarted if necessary. The lock file is DAEMON_LOCK_FILE. 15467c478bd9Sstevel@tonic-gate */ 15477c478bd9Sstevel@tonic-gate static pid_t 15487c478bd9Sstevel@tonic-gate enter_daemon_lock(void) 15497c478bd9Sstevel@tonic-gate { 15507c478bd9Sstevel@tonic-gate struct flock lock; 15517c478bd9Sstevel@tonic-gate 15527c478bd9Sstevel@tonic-gate syseventd_print(8, "enter_daemon_lock: lock file = %s\n", 15537c478bd9Sstevel@tonic-gate DAEMON_LOCK_FILE); 15547c478bd9Sstevel@tonic-gate 15557c478bd9Sstevel@tonic-gate if (snprintf(local_lock_file, sizeof (local_lock_file), "%s%s", 15567c478bd9Sstevel@tonic-gate root_dir, DAEMON_LOCK_FILE) >= sizeof (local_lock_file)) { 15577c478bd9Sstevel@tonic-gate syseventd_err_print(INIT_PATH_ERR, local_lock_file); 15587c478bd9Sstevel@tonic-gate syseventd_exit(8); 15597c478bd9Sstevel@tonic-gate } 15607c478bd9Sstevel@tonic-gate daemon_lock_fd = open(local_lock_file, O_CREAT|O_RDWR, 0644); 15617c478bd9Sstevel@tonic-gate if (daemon_lock_fd < 0) { 15627c478bd9Sstevel@tonic-gate syseventd_err_print(INIT_LOCK_OPEN_ERR, 15637c478bd9Sstevel@tonic-gate local_lock_file, strerror(errno)); 15647c478bd9Sstevel@tonic-gate syseventd_exit(8); 15657c478bd9Sstevel@tonic-gate } 15667c478bd9Sstevel@tonic-gate 15677c478bd9Sstevel@tonic-gate lock.l_type = F_WRLCK; 15687c478bd9Sstevel@tonic-gate lock.l_whence = SEEK_SET; 15697c478bd9Sstevel@tonic-gate lock.l_start = 0; 15707c478bd9Sstevel@tonic-gate lock.l_len = 0; 15717c478bd9Sstevel@tonic-gate 15727c478bd9Sstevel@tonic-gate if (fcntl(daemon_lock_fd, F_SETLK, &lock) == -1) { 15737c478bd9Sstevel@tonic-gate if (fcntl(daemon_lock_fd, F_GETLK, &lock) == -1) { 15747c478bd9Sstevel@tonic-gate syseventd_err_print(INIT_LOCK_ERR, 15757c478bd9Sstevel@tonic-gate local_lock_file, strerror(errno)); 15767c478bd9Sstevel@tonic-gate exit(2); 15777c478bd9Sstevel@tonic-gate } 15787c478bd9Sstevel@tonic-gate return (lock.l_pid); 15797c478bd9Sstevel@tonic-gate } 15807c478bd9Sstevel@tonic-gate hold_daemon_lock = 1; 15817c478bd9Sstevel@tonic-gate 15827c478bd9Sstevel@tonic-gate return (getpid()); 15837c478bd9Sstevel@tonic-gate } 15847c478bd9Sstevel@tonic-gate 15857c478bd9Sstevel@tonic-gate /* 15867c478bd9Sstevel@tonic-gate * exit_daemon_lock - release the daemon file lock 15877c478bd9Sstevel@tonic-gate */ 15887c478bd9Sstevel@tonic-gate static void 15897c478bd9Sstevel@tonic-gate exit_daemon_lock(void) 15907c478bd9Sstevel@tonic-gate { 15917c478bd9Sstevel@tonic-gate struct flock lock; 15927c478bd9Sstevel@tonic-gate 15937c478bd9Sstevel@tonic-gate lock.l_type = F_UNLCK; 15947c478bd9Sstevel@tonic-gate lock.l_whence = SEEK_SET; 15957c478bd9Sstevel@tonic-gate lock.l_start = 0; 15967c478bd9Sstevel@tonic-gate lock.l_len = 0; 15977c478bd9Sstevel@tonic-gate 15987c478bd9Sstevel@tonic-gate if (fcntl(daemon_lock_fd, F_SETLK, &lock) == -1) { 15997c478bd9Sstevel@tonic-gate syseventd_err_print(INIT_UNLOCK_ERR, 16007c478bd9Sstevel@tonic-gate local_lock_file, strerror(errno)); 16017c478bd9Sstevel@tonic-gate } 16027c478bd9Sstevel@tonic-gate 16037c478bd9Sstevel@tonic-gate if (close(daemon_lock_fd) == -1) { 16047c478bd9Sstevel@tonic-gate syseventd_err_print(INIT_LOCK_CLOSE_ERR, 16057c478bd9Sstevel@tonic-gate local_lock_file, strerror(errno)); 16067c478bd9Sstevel@tonic-gate exit(-1); 16077c478bd9Sstevel@tonic-gate } 16087c478bd9Sstevel@tonic-gate } 16097c478bd9Sstevel@tonic-gate 16107c478bd9Sstevel@tonic-gate /* 16117c478bd9Sstevel@tonic-gate * syseventd_err_print - print error messages to the terminal if not 16127c478bd9Sstevel@tonic-gate * yet daemonized or to syslog. 16137c478bd9Sstevel@tonic-gate */ 16147c478bd9Sstevel@tonic-gate /*PRINTFLIKE1*/ 16157c478bd9Sstevel@tonic-gate void 16167c478bd9Sstevel@tonic-gate syseventd_err_print(char *message, ...) 16177c478bd9Sstevel@tonic-gate { 16187c478bd9Sstevel@tonic-gate va_list ap; 16197c478bd9Sstevel@tonic-gate 16207c478bd9Sstevel@tonic-gate (void) mutex_lock(&err_mutex); 16217c478bd9Sstevel@tonic-gate va_start(ap, message); 16227c478bd9Sstevel@tonic-gate 16237c478bd9Sstevel@tonic-gate if (logflag) { 16247c478bd9Sstevel@tonic-gate (void) vsyslog(LOG_ERR, message, ap); 16257c478bd9Sstevel@tonic-gate } else { 16267c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "%s: ", prog); 16277c478bd9Sstevel@tonic-gate (void) vfprintf(stderr, message, ap); 16287c478bd9Sstevel@tonic-gate } 16297c478bd9Sstevel@tonic-gate va_end(ap); 16307c478bd9Sstevel@tonic-gate (void) mutex_unlock(&err_mutex); 16317c478bd9Sstevel@tonic-gate } 16327c478bd9Sstevel@tonic-gate 16337c478bd9Sstevel@tonic-gate /* 16347c478bd9Sstevel@tonic-gate * syseventd_print - print messages to the terminal or to syslog 16357c478bd9Sstevel@tonic-gate * the following levels are implemented: 16367c478bd9Sstevel@tonic-gate * 16377c478bd9Sstevel@tonic-gate * 1 - transient errors that does not affect normal program flow 16387c478bd9Sstevel@tonic-gate * 2 - upcall/dispatch interaction 16397c478bd9Sstevel@tonic-gate * 3 - program flow trace as each message goes through the daemon 16407c478bd9Sstevel@tonic-gate * 8 - all the nit-gritty details of startup and shutdown 16417c478bd9Sstevel@tonic-gate * 9 - very verbose event flow tracing (no daemonization of syseventd) 16427c478bd9Sstevel@tonic-gate * 16437c478bd9Sstevel@tonic-gate */ 16447c478bd9Sstevel@tonic-gate /*PRINTFLIKE2*/ 16457c478bd9Sstevel@tonic-gate void 16467c478bd9Sstevel@tonic-gate syseventd_print(int level, char *message, ...) 16477c478bd9Sstevel@tonic-gate { 16487c478bd9Sstevel@tonic-gate va_list ap; 16497c478bd9Sstevel@tonic-gate static int newline = 1; 16507c478bd9Sstevel@tonic-gate 16517c478bd9Sstevel@tonic-gate if (level > debug_level) { 16527c478bd9Sstevel@tonic-gate return; 16537c478bd9Sstevel@tonic-gate } 16547c478bd9Sstevel@tonic-gate 16557c478bd9Sstevel@tonic-gate (void) mutex_lock(&err_mutex); 16567c478bd9Sstevel@tonic-gate va_start(ap, message); 16577c478bd9Sstevel@tonic-gate if (logflag) { 16587c478bd9Sstevel@tonic-gate (void) syslog(LOG_DEBUG, "%s[%ld]: ", 16597c478bd9Sstevel@tonic-gate prog, getpid()); 16607c478bd9Sstevel@tonic-gate (void) vsyslog(LOG_DEBUG, message, ap); 16617c478bd9Sstevel@tonic-gate } else { 16627c478bd9Sstevel@tonic-gate if (newline) { 16637c478bd9Sstevel@tonic-gate (void) fprintf(stdout, "%s[%ld]: ", 16647c478bd9Sstevel@tonic-gate prog, getpid()); 16657c478bd9Sstevel@tonic-gate (void) vfprintf(stdout, message, ap); 16667c478bd9Sstevel@tonic-gate } else { 16677c478bd9Sstevel@tonic-gate (void) vfprintf(stdout, message, ap); 16687c478bd9Sstevel@tonic-gate } 16697c478bd9Sstevel@tonic-gate } 16707c478bd9Sstevel@tonic-gate if (message[strlen(message)-1] == '\n') { 16717c478bd9Sstevel@tonic-gate newline = 1; 16727c478bd9Sstevel@tonic-gate } else { 16737c478bd9Sstevel@tonic-gate newline = 0; 16747c478bd9Sstevel@tonic-gate } 16757c478bd9Sstevel@tonic-gate va_end(ap); 16767c478bd9Sstevel@tonic-gate (void) mutex_unlock(&err_mutex); 16777c478bd9Sstevel@tonic-gate } 1678