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
usage()145*30699046SRichard Lowe usage()
146*30699046SRichard Lowe {
1477c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "usage: syseventd [-d <debug_level>] "
1487c478bd9Sstevel@tonic-gate "[-r <root_dir>]\n");
1497c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "higher debug levels get progressively ");
1507c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "more detailed debug information.\n");
1517c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "syseventd will run in background if ");
1527c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "run with a debug_level less than %d.\n",
1537c478bd9Sstevel@tonic-gate DEBUG_LEVEL_FORK);
1547c478bd9Sstevel@tonic-gate exit(2);
1557c478bd9Sstevel@tonic-gate }
1567c478bd9Sstevel@tonic-gate
1577c478bd9Sstevel@tonic-gate
1587c478bd9Sstevel@tonic-gate /* common exit function which ensures releasing locks */
1597c478bd9Sstevel@tonic-gate void
syseventd_exit(int status)1607c478bd9Sstevel@tonic-gate syseventd_exit(int status)
1617c478bd9Sstevel@tonic-gate {
1627c478bd9Sstevel@tonic-gate syseventd_print(1, "exit status = %d\n", status);
1637c478bd9Sstevel@tonic-gate
1647c478bd9Sstevel@tonic-gate if (hold_daemon_lock) {
1657c478bd9Sstevel@tonic-gate exit_daemon_lock();
1667c478bd9Sstevel@tonic-gate }
1677c478bd9Sstevel@tonic-gate
1687c478bd9Sstevel@tonic-gate exit(status);
1697c478bd9Sstevel@tonic-gate }
1707c478bd9Sstevel@tonic-gate
1717c478bd9Sstevel@tonic-gate
1727c478bd9Sstevel@tonic-gate /*
1737c478bd9Sstevel@tonic-gate * hup_handler - SIGHUP handler. SIGHUP is used to force a reload of
1747c478bd9Sstevel@tonic-gate * all SLMs. During fini, events are drained from all
1757c478bd9Sstevel@tonic-gate * client event queues. The events that have been consumed
1767c478bd9Sstevel@tonic-gate * by all clients are freed from the kernel event queue.
1777c478bd9Sstevel@tonic-gate *
1787c478bd9Sstevel@tonic-gate * Events that have not yet been delivered to all clients
1797c478bd9Sstevel@tonic-gate * are not freed and will be replayed after all SLMs have
1807c478bd9Sstevel@tonic-gate * been (re)loaded.
1817c478bd9Sstevel@tonic-gate *
1827c478bd9Sstevel@tonic-gate * After all client event queues have been drained, each
1837c478bd9Sstevel@tonic-gate * SLM client is unloaded. The init phase will (re)load
1847c478bd9Sstevel@tonic-gate * each SLM and initiate event replay and delivery from
1857c478bd9Sstevel@tonic-gate * the kernel.
1867c478bd9Sstevel@tonic-gate *
1877c478bd9Sstevel@tonic-gate */
1887c478bd9Sstevel@tonic-gate /*ARGSUSED*/
1897c478bd9Sstevel@tonic-gate static void
hup_handler(int sig)1907c478bd9Sstevel@tonic-gate hup_handler(int sig)
1917c478bd9Sstevel@tonic-gate {
1927c478bd9Sstevel@tonic-gate syseventd_err_print(SIGHUP_CAUGHT);
1937c478bd9Sstevel@tonic-gate (void) fflush(0);
1947c478bd9Sstevel@tonic-gate syseventd_fini(sig);
1957c478bd9Sstevel@tonic-gate syseventd_init();
1967c478bd9Sstevel@tonic-gate syseventd_err_print(DAEMON_RESTARTED);
1977c478bd9Sstevel@tonic-gate (void) fflush(0);
1987c478bd9Sstevel@tonic-gate }
1997c478bd9Sstevel@tonic-gate
2007c478bd9Sstevel@tonic-gate /*
2017c478bd9Sstevel@tonic-gate * Fault handler for other signals caught
2027c478bd9Sstevel@tonic-gate */
2037c478bd9Sstevel@tonic-gate /*ARGSUSED*/
2047c478bd9Sstevel@tonic-gate static void
flt_handler(int sig)2057c478bd9Sstevel@tonic-gate flt_handler(int sig)
2067c478bd9Sstevel@tonic-gate {
2077c478bd9Sstevel@tonic-gate char signame[SIG2STR_MAX];
2087c478bd9Sstevel@tonic-gate
2097c478bd9Sstevel@tonic-gate if (sig2str(sig, signame) == -1) {
2107c478bd9Sstevel@tonic-gate syseventd_err_print(UNKNOWN_SIGNAL_CAUGHT, sig);
2117c478bd9Sstevel@tonic-gate }
2127c478bd9Sstevel@tonic-gate
213*30699046SRichard Lowe (void) se_signal_sethandler(sig, SE_SIG_DFL, NULL);
2147c478bd9Sstevel@tonic-gate
2157c478bd9Sstevel@tonic-gate switch (sig) {
2167c478bd9Sstevel@tonic-gate case SIGINT:
2177c478bd9Sstevel@tonic-gate case SIGSTOP:
2187c478bd9Sstevel@tonic-gate case SIGTERM:
2197c478bd9Sstevel@tonic-gate /* Close kernel door */
2207c478bd9Sstevel@tonic-gate (void) door_revoke(upcall_door);
2217c478bd9Sstevel@tonic-gate
2227c478bd9Sstevel@tonic-gate /* Gracefully exit current event delivery threads */
2237c478bd9Sstevel@tonic-gate syseventd_fini(sig);
2247c478bd9Sstevel@tonic-gate
2257c478bd9Sstevel@tonic-gate (void) fflush(0);
2267c478bd9Sstevel@tonic-gate (void) se_signal_unblockall();
2277c478bd9Sstevel@tonic-gate syseventd_exit(1);
2287c478bd9Sstevel@tonic-gate /*NOTREACHED*/
2295ad1f010SStephen Hanson case SIGCLD:
230b0daa853SStephen Hanson case SIGPWR:
231b0daa853SStephen Hanson case SIGWINCH:
232b0daa853SStephen Hanson case SIGURG:
233b0daa853SStephen Hanson case SIGCONT:
234b0daa853SStephen Hanson case SIGWAITING:
235b0daa853SStephen Hanson case SIGLWP:
236b0daa853SStephen Hanson case SIGFREEZE:
237b0daa853SStephen Hanson case SIGTHAW:
238b0daa853SStephen Hanson case SIGCANCEL:
239b0daa853SStephen Hanson case SIGXRES:
240b0daa853SStephen Hanson case SIGJVM1:
241b0daa853SStephen Hanson case SIGJVM2:
24219d32b9aSRobert Mustacchi case SIGINFO:
243b0daa853SStephen Hanson /* No need to abort */
2445ad1f010SStephen Hanson break;
2457c478bd9Sstevel@tonic-gate default:
2467c478bd9Sstevel@tonic-gate syseventd_err_print(FATAL_ERROR);
2475ad1f010SStephen Hanson abort();
2487c478bd9Sstevel@tonic-gate
2497c478bd9Sstevel@tonic-gate }
2507c478bd9Sstevel@tonic-gate }
2517c478bd9Sstevel@tonic-gate
252b3a85157Sjg /*
253b3a85157Sjg * Daemon parent process only.
254b3a85157Sjg * Child process signal to indicate successful daemon initialization.
255b3a85157Sjg * This is the normal and expected exit path of the daemon parent.
256b3a85157Sjg */
257b3a85157Sjg /*ARGSUSED*/
258b3a85157Sjg static void
sigusr1(int sig)259b3a85157Sjg sigusr1(int sig)
260b3a85157Sjg {
261b3a85157Sjg syseventd_exit(0);
262b3a85157Sjg }
263b3a85157Sjg
2645b784b07SToomas Soome static void *
sigwait_thr(void * arg __unused)2655b784b07SToomas Soome sigwait_thr(void *arg __unused)
2667c478bd9Sstevel@tonic-gate {
2677c478bd9Sstevel@tonic-gate int sig;
2687c478bd9Sstevel@tonic-gate int err;
2697c478bd9Sstevel@tonic-gate sigset_t signal_set;
2707c478bd9Sstevel@tonic-gate
2717c478bd9Sstevel@tonic-gate for (;;) {
2727c478bd9Sstevel@tonic-gate syseventd_print(3, "sigwait thread waiting for signal\n");
2737c478bd9Sstevel@tonic-gate (void) sigfillset(&signal_set);
2747c478bd9Sstevel@tonic-gate err = sigwait(&signal_set, &sig);
2757c478bd9Sstevel@tonic-gate if (err) {
2767c478bd9Sstevel@tonic-gate syseventd_exit(2);
2777c478bd9Sstevel@tonic-gate }
2787c478bd9Sstevel@tonic-gate
2797c478bd9Sstevel@tonic-gate /*
2807c478bd9Sstevel@tonic-gate * Block all signals until the signal handler completes
2817c478bd9Sstevel@tonic-gate */
2827c478bd9Sstevel@tonic-gate if (sig == SIGHUP) {
2837c478bd9Sstevel@tonic-gate hup_handler(sig);
2847c478bd9Sstevel@tonic-gate } else {
2857c478bd9Sstevel@tonic-gate flt_handler(sig);
2867c478bd9Sstevel@tonic-gate }
2877c478bd9Sstevel@tonic-gate }
2885b784b07SToomas Soome return (NULL);
2897c478bd9Sstevel@tonic-gate }
2907c478bd9Sstevel@tonic-gate
2917c478bd9Sstevel@tonic-gate static void
set_root_dir(char * dir)2927c478bd9Sstevel@tonic-gate set_root_dir(char *dir)
2937c478bd9Sstevel@tonic-gate {
2947c478bd9Sstevel@tonic-gate root_dir = malloc(strlen(dir) + 1);
2957c478bd9Sstevel@tonic-gate if (root_dir == NULL) {
2967c478bd9Sstevel@tonic-gate syseventd_err_print(INIT_ROOT_DIR_ERR, strerror(errno));
2977c478bd9Sstevel@tonic-gate syseventd_exit(2);
2987c478bd9Sstevel@tonic-gate }
2997c478bd9Sstevel@tonic-gate (void) strcpy(root_dir, dir);
3007c478bd9Sstevel@tonic-gate }
3017c478bd9Sstevel@tonic-gate
30280ab886dSwesolows int
main(int argc,char ** argv)3037c478bd9Sstevel@tonic-gate main(int argc, char **argv)
3047c478bd9Sstevel@tonic-gate {
3057c478bd9Sstevel@tonic-gate int i, c;
3067c478bd9Sstevel@tonic-gate int fd;
3077c478bd9Sstevel@tonic-gate pid_t pid;
308b3a85157Sjg int has_forked = 0;
3097c478bd9Sstevel@tonic-gate extern char *optarg;
3107c478bd9Sstevel@tonic-gate
3117c478bd9Sstevel@tonic-gate (void) setlocale(LC_ALL, "");
3127c478bd9Sstevel@tonic-gate (void) textdomain(TEXT_DOMAIN);
3137c478bd9Sstevel@tonic-gate
3147c478bd9Sstevel@tonic-gate if (getuid() != 0) {
3157c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "Must be root to run syseventd\n");
3167c478bd9Sstevel@tonic-gate syseventd_exit(1);
3177c478bd9Sstevel@tonic-gate }
3187c478bd9Sstevel@tonic-gate
3197c478bd9Sstevel@tonic-gate if (argc > 5) {
3207c478bd9Sstevel@tonic-gate usage();
3217c478bd9Sstevel@tonic-gate }
3227c478bd9Sstevel@tonic-gate
3237c478bd9Sstevel@tonic-gate if ((prog = strrchr(argv[0], '/')) == NULL) {
3247c478bd9Sstevel@tonic-gate prog = argv[0];
3257c478bd9Sstevel@tonic-gate } else {
3267c478bd9Sstevel@tonic-gate prog++;
3277c478bd9Sstevel@tonic-gate }
3287c478bd9Sstevel@tonic-gate
3295ad1f010SStephen Hanson while ((c = getopt(argc, argv, "d:r:")) != EOF) {
3307c478bd9Sstevel@tonic-gate switch (c) {
3317c478bd9Sstevel@tonic-gate case 'd':
3327c478bd9Sstevel@tonic-gate debug_level = atoi(optarg);
3337c478bd9Sstevel@tonic-gate break;
3347c478bd9Sstevel@tonic-gate case 'r':
3357c478bd9Sstevel@tonic-gate /*
3367c478bd9Sstevel@tonic-gate * Private flag for suninstall to run
3377c478bd9Sstevel@tonic-gate * daemon during install.
3387c478bd9Sstevel@tonic-gate */
3397c478bd9Sstevel@tonic-gate set_root_dir(optarg);
3407c478bd9Sstevel@tonic-gate break;
3417c478bd9Sstevel@tonic-gate case '?':
3427c478bd9Sstevel@tonic-gate default:
3437c478bd9Sstevel@tonic-gate usage();
3447c478bd9Sstevel@tonic-gate }
3457c478bd9Sstevel@tonic-gate }
3467c478bd9Sstevel@tonic-gate
3477c478bd9Sstevel@tonic-gate /* demonize ourselves */
3487c478bd9Sstevel@tonic-gate if (debug_level < DEBUG_LEVEL_FORK) {
3497c478bd9Sstevel@tonic-gate
350b3a85157Sjg sigset_t mask;
351b3a85157Sjg
352b3a85157Sjg (void) sigset(SIGUSR1, sigusr1);
353b3a85157Sjg
354b3a85157Sjg (void) sigemptyset(&mask);
355b3a85157Sjg (void) sigaddset(&mask, SIGUSR1);
356b3a85157Sjg (void) sigprocmask(SIG_BLOCK, &mask, NULL);
357b3a85157Sjg
358b3a85157Sjg if ((pid = fork()) == (pid_t)-1) {
359b3a85157Sjg (void) fprintf(stderr,
360b3a85157Sjg "syseventd: fork failed - %s\n", strerror(errno));
361b3a85157Sjg syseventd_exit(1);
362b3a85157Sjg }
363b3a85157Sjg
364b3a85157Sjg if (pid != 0) {
365b3a85157Sjg /*
366b3a85157Sjg * parent
367b3a85157Sjg * handshake with the daemon so that dependents
368b3a85157Sjg * of the syseventd service don't start up until
369b3a85157Sjg * the service is actually functional
370b3a85157Sjg */
371b3a85157Sjg int status;
372b3a85157Sjg (void) sigprocmask(SIG_UNBLOCK, &mask, NULL);
373b3a85157Sjg
374b3a85157Sjg if (waitpid(pid, &status, 0) != pid) {
375b3a85157Sjg /*
376b3a85157Sjg * child process signal indicating
377b3a85157Sjg * successful daemon initialization
378b3a85157Sjg */
3797c478bd9Sstevel@tonic-gate syseventd_exit(0);
3807c478bd9Sstevel@tonic-gate }
381b3a85157Sjg /* child exited implying unsuccessful startup */
382b3a85157Sjg syseventd_exit(1);
383b3a85157Sjg }
3847c478bd9Sstevel@tonic-gate
3857c478bd9Sstevel@tonic-gate /* child */
3867c478bd9Sstevel@tonic-gate
387b3a85157Sjg has_forked = 1;
388b3a85157Sjg (void) sigset(SIGUSR1, SIG_DFL);
389b3a85157Sjg (void) sigprocmask(SIG_UNBLOCK, &mask, NULL);
390b3a85157Sjg
3917c478bd9Sstevel@tonic-gate (void) chdir("/");
3927c478bd9Sstevel@tonic-gate (void) setsid();
3937c478bd9Sstevel@tonic-gate if (debug_level <= 1) {
3947c478bd9Sstevel@tonic-gate closefrom(0);
3957c478bd9Sstevel@tonic-gate fd = open("/dev/null", 0);
3967c478bd9Sstevel@tonic-gate (void) dup2(fd, 1);
3977c478bd9Sstevel@tonic-gate (void) dup2(fd, 2);
3987c478bd9Sstevel@tonic-gate logflag = 1;
3997c478bd9Sstevel@tonic-gate }
4007c478bd9Sstevel@tonic-gate }
4017c478bd9Sstevel@tonic-gate
4027c478bd9Sstevel@tonic-gate openlog("syseventd", LOG_PID, LOG_DAEMON);
4037c478bd9Sstevel@tonic-gate
4047c478bd9Sstevel@tonic-gate (void) mutex_init(&err_mutex, USYNC_THREAD, NULL);
4057c478bd9Sstevel@tonic-gate
4067c478bd9Sstevel@tonic-gate syseventd_print(8,
4077c478bd9Sstevel@tonic-gate "syseventd started, debug level = %d\n", debug_level);
4087c478bd9Sstevel@tonic-gate
4097c478bd9Sstevel@tonic-gate /* only one instance of syseventd can run at a time */
4107c478bd9Sstevel@tonic-gate if ((pid = enter_daemon_lock()) != getpid()) {
4117c478bd9Sstevel@tonic-gate syseventd_print(1,
4127c478bd9Sstevel@tonic-gate "event daemon pid %ld already running\n", pid);
4137c478bd9Sstevel@tonic-gate exit(3);
4147c478bd9Sstevel@tonic-gate }
4157c478bd9Sstevel@tonic-gate
4167c478bd9Sstevel@tonic-gate /* initialize semaphores and eventbuf */
4177c478bd9Sstevel@tonic-gate (void) sema_init(&sema_eventbuf, SE_EVENT_DISPATCH_CNT,
4187c478bd9Sstevel@tonic-gate USYNC_THREAD, NULL);
4197c478bd9Sstevel@tonic-gate (void) sema_init(&sema_dispatch, 0, USYNC_THREAD, NULL);
4207c478bd9Sstevel@tonic-gate (void) sema_init(&sema_resource, SE_EVENT_DISPATCH_CNT,
4217c478bd9Sstevel@tonic-gate USYNC_THREAD, NULL);
4227c478bd9Sstevel@tonic-gate (void) cond_init(&event_comp_cv, USYNC_THREAD, NULL);
4237c478bd9Sstevel@tonic-gate eventbuf = (sysevent_t **)calloc(SE_EVENT_DISPATCH_CNT,
4247c478bd9Sstevel@tonic-gate sizeof (sysevent_t *));
4257c478bd9Sstevel@tonic-gate if (eventbuf == NULL) {
4267c478bd9Sstevel@tonic-gate syseventd_print(1, "Unable to allocate event buffer array\n");
4277c478bd9Sstevel@tonic-gate exit(2);
4287c478bd9Sstevel@tonic-gate }
4297c478bd9Sstevel@tonic-gate for (i = 0; i < SE_EVENT_DISPATCH_CNT; ++i) {
4307c478bd9Sstevel@tonic-gate eventbuf[i] = malloc(LOGEVENT_BUFSIZE);
4317c478bd9Sstevel@tonic-gate if (eventbuf[i] == NULL) {
4327c478bd9Sstevel@tonic-gate syseventd_print(1, "Unable to allocate event "
4337c478bd9Sstevel@tonic-gate "buffers\n");
4347c478bd9Sstevel@tonic-gate exit(2);
4357c478bd9Sstevel@tonic-gate }
4367c478bd9Sstevel@tonic-gate }
4377c478bd9Sstevel@tonic-gate
4387c478bd9Sstevel@tonic-gate (void) mutex_init(&client_tbl_lock, USYNC_THREAD, NULL);
4397c478bd9Sstevel@tonic-gate (void) mutex_init(&ev_comp_lock, USYNC_THREAD, NULL);
4407c478bd9Sstevel@tonic-gate (void) mutex_init(&door_lock, USYNC_THREAD, NULL);
4417c478bd9Sstevel@tonic-gate (void) rwlock_init(&mod_unload_lock, USYNC_THREAD, NULL);
4427c478bd9Sstevel@tonic-gate
4437c478bd9Sstevel@tonic-gate event_compq = NULL;
4447c478bd9Sstevel@tonic-gate
4457c478bd9Sstevel@tonic-gate syseventd_print(8, "start the message thread running\n");
4467c478bd9Sstevel@tonic-gate
4477c478bd9Sstevel@tonic-gate /*
4487c478bd9Sstevel@tonic-gate * Block all signals to all threads include the main thread.
4497c478bd9Sstevel@tonic-gate * The sigwait_thr thread will process any signals and initiate
4507c478bd9Sstevel@tonic-gate * a graceful recovery if possible.
4517c478bd9Sstevel@tonic-gate */
4527c478bd9Sstevel@tonic-gate if (se_signal_blockall() < 0) {
4537c478bd9Sstevel@tonic-gate syseventd_err_print(INIT_SIG_BLOCK_ERR);
4547c478bd9Sstevel@tonic-gate syseventd_exit(2);
4557c478bd9Sstevel@tonic-gate }
4567c478bd9Sstevel@tonic-gate
457c7cb3c8bSToomas Soome if (thr_create(NULL, 0, (void *(*)(void *))dispatch_message,
4587c478bd9Sstevel@tonic-gate (void *)0, 0, NULL) < 0) {
4597c478bd9Sstevel@tonic-gate syseventd_err_print(INIT_THR_CREATE_ERR, strerror(errno));
4607c478bd9Sstevel@tonic-gate syseventd_exit(2);
4617c478bd9Sstevel@tonic-gate }
462c7cb3c8bSToomas Soome if (thr_create(NULL, 0,
4637c478bd9Sstevel@tonic-gate (void *(*)(void *))event_completion_thr, NULL,
4647c478bd9Sstevel@tonic-gate THR_BOUND, NULL) != 0) {
4657c478bd9Sstevel@tonic-gate syseventd_err_print(INIT_THR_CREATE_ERR, strerror(errno));
4667c478bd9Sstevel@tonic-gate syseventd_exit(2);
4677c478bd9Sstevel@tonic-gate }
4687c478bd9Sstevel@tonic-gate /* Create signal catching thread */
4695b784b07SToomas Soome if (thr_create(NULL, 0, sigwait_thr, 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
door_upcall(void * cookie,char * args,size_t alen,door_desc_t * ddp,uint_t ndid)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
dispatch_message(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
drain_eventq(struct sysevent_client * scp,int status)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 */
6685b784b07SToomas Soome static void *
client_deliver_event_thr(void * arg)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);
6955b784b07SToomas Soome return (NULL);
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);
7735b784b07SToomas Soome return (NULL);
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);
7995b784b07SToomas Soome return (NULL);
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 *
client_deliver_event(struct sysevent_client * scp,sysevent_t * ev,sema_t * completion_sema)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
event_completion_thr()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
dispatch(void)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 *
dir_num2name(int dirnum)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
load_modules(char * dirname)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);
13315b784b07SToomas Soome if (thr_create(NULL, 0, client_deliver_event_thr,
13325b784b07SToomas Soome scp, THR_BOUND, &scp->tid) != 0) {
13337c478bd9Sstevel@tonic-gate
13347c478bd9Sstevel@tonic-gate syseventd_err_print(LOAD_MOD_ALLOC_ERR, "insert_client",
13357c478bd9Sstevel@tonic-gate strerror(errno));
13367c478bd9Sstevel@tonic-gate mod->event_mod_fini();
13377c478bd9Sstevel@tonic-gate free(mod->name);
13387c478bd9Sstevel@tonic-gate free(mod);
13397c478bd9Sstevel@tonic-gate (void) dlclose(dlh);
13407c478bd9Sstevel@tonic-gate continue;
13417c478bd9Sstevel@tonic-gate }
13427c478bd9Sstevel@tonic-gate scp->client_flags |= SE_CLIENT_THR_RUNNING;
13437c478bd9Sstevel@tonic-gate
13447c478bd9Sstevel@tonic-gate syseventd_print(3, "loaded module %s\n", entp->d_name);
13457c478bd9Sstevel@tonic-gate }
13467c478bd9Sstevel@tonic-gate
13477c478bd9Sstevel@tonic-gate (void) closedir(mod_dir);
13487c478bd9Sstevel@tonic-gate syseventd_print(3, "modules loaded\n");
13497c478bd9Sstevel@tonic-gate }
13507c478bd9Sstevel@tonic-gate
13517c478bd9Sstevel@tonic-gate /*
13527c478bd9Sstevel@tonic-gate * unload_modules - modules are unloaded prior to graceful shutdown or
13537c478bd9Sstevel@tonic-gate * before restarting the daemon upon receipt of
13547c478bd9Sstevel@tonic-gate * SIGHUP.
13557c478bd9Sstevel@tonic-gate */
13567c478bd9Sstevel@tonic-gate static void
unload_modules(int sig)13577c478bd9Sstevel@tonic-gate unload_modules(int sig)
13587c478bd9Sstevel@tonic-gate {
13597c478bd9Sstevel@tonic-gate int i, count, done;
13607c478bd9Sstevel@tonic-gate module_t *mod;
13617c478bd9Sstevel@tonic-gate struct sysevent_client *scp;
13627c478bd9Sstevel@tonic-gate
13637c478bd9Sstevel@tonic-gate /*
13647c478bd9Sstevel@tonic-gate * unload modules that are ready, skip those that have not
13657c478bd9Sstevel@tonic-gate * drained their event queues.
13667c478bd9Sstevel@tonic-gate */
13677c478bd9Sstevel@tonic-gate count = done = 0;
13687c478bd9Sstevel@tonic-gate while (done < MAX_SLM) {
13697c478bd9Sstevel@tonic-gate /* Don't wait indefinitely for unresponsive clients */
13707c478bd9Sstevel@tonic-gate if (sig != SIGHUP && count > SE_TIMEOUT) {
13717c478bd9Sstevel@tonic-gate break;
13727c478bd9Sstevel@tonic-gate }
13737c478bd9Sstevel@tonic-gate
13747c478bd9Sstevel@tonic-gate done = 0;
13757c478bd9Sstevel@tonic-gate
13767c478bd9Sstevel@tonic-gate /* Shutdown clients */
13777c478bd9Sstevel@tonic-gate for (i = 0; i < MAX_SLM; ++i) {
13787c478bd9Sstevel@tonic-gate scp = sysevent_client_tbl[i];
13797c478bd9Sstevel@tonic-gate if (mutex_trylock(&scp->client_lock) == 0) {
13807c478bd9Sstevel@tonic-gate if (scp->client_type != SLM_CLIENT ||
13817c478bd9Sstevel@tonic-gate scp->client_data == NULL) {
13827c478bd9Sstevel@tonic-gate (void) mutex_unlock(&scp->client_lock);
13837c478bd9Sstevel@tonic-gate done++;
13847c478bd9Sstevel@tonic-gate continue;
13857c478bd9Sstevel@tonic-gate }
13867c478bd9Sstevel@tonic-gate } else {
13877c478bd9Sstevel@tonic-gate syseventd_print(3, "Skipping unload of "
13887c478bd9Sstevel@tonic-gate "client %d: client locked\n",
13897c478bd9Sstevel@tonic-gate scp->client_num);
13907c478bd9Sstevel@tonic-gate continue;
13917c478bd9Sstevel@tonic-gate }
13927c478bd9Sstevel@tonic-gate
13937c478bd9Sstevel@tonic-gate /*
13947c478bd9Sstevel@tonic-gate * Drain the eventq and wait for delivery thread to
13957c478bd9Sstevel@tonic-gate * cleanly exit
13967c478bd9Sstevel@tonic-gate */
13977c478bd9Sstevel@tonic-gate drain_eventq(scp, EAGAIN);
13987c478bd9Sstevel@tonic-gate (void) cond_signal(&scp->client_cv);
13997c478bd9Sstevel@tonic-gate (void) mutex_unlock(&scp->client_lock);
14007c478bd9Sstevel@tonic-gate (void) thr_join(scp->tid, NULL, NULL);
14017c478bd9Sstevel@tonic-gate
14027c478bd9Sstevel@tonic-gate /*
14037c478bd9Sstevel@tonic-gate * It is now safe to unload the module
14047c478bd9Sstevel@tonic-gate */
14057c478bd9Sstevel@tonic-gate mod = (module_t *)scp->client_data;
14067c478bd9Sstevel@tonic-gate syseventd_print(2, "Unload %s\n", mod->name);
14077c478bd9Sstevel@tonic-gate mod->event_mod_fini();
14087c478bd9Sstevel@tonic-gate (void) dlclose(mod->dlhandle);
14097c478bd9Sstevel@tonic-gate free(mod->name);
14107c478bd9Sstevel@tonic-gate (void) mutex_lock(&client_tbl_lock);
14117c478bd9Sstevel@tonic-gate delete_client(i);
14127c478bd9Sstevel@tonic-gate (void) mutex_unlock(&client_tbl_lock);
14137c478bd9Sstevel@tonic-gate ++done;
14147c478bd9Sstevel@tonic-gate
14157c478bd9Sstevel@tonic-gate }
14167c478bd9Sstevel@tonic-gate ++count;
14177c478bd9Sstevel@tonic-gate (void) sleep(1);
14187c478bd9Sstevel@tonic-gate }
14197c478bd9Sstevel@tonic-gate
14207c478bd9Sstevel@tonic-gate /*
14217c478bd9Sstevel@tonic-gate * Wait for event completions
14227c478bd9Sstevel@tonic-gate */
14237c478bd9Sstevel@tonic-gate syseventd_print(2, "waiting for event completions\n");
14247c478bd9Sstevel@tonic-gate (void) mutex_lock(&ev_comp_lock);
14257c478bd9Sstevel@tonic-gate while (event_compq != NULL) {
14267c478bd9Sstevel@tonic-gate (void) cond_wait(&event_comp_cv, &ev_comp_lock);
14277c478bd9Sstevel@tonic-gate }
14287c478bd9Sstevel@tonic-gate (void) mutex_unlock(&ev_comp_lock);
14297c478bd9Sstevel@tonic-gate }
14307c478bd9Sstevel@tonic-gate
14317c478bd9Sstevel@tonic-gate /*
14327c478bd9Sstevel@tonic-gate * syseventd_init - Called at daemon (re)start-up time to load modules
14337c478bd9Sstevel@tonic-gate * and kickstart the kernel delivery engine.
14347c478bd9Sstevel@tonic-gate */
14357c478bd9Sstevel@tonic-gate static void
syseventd_init()14367c478bd9Sstevel@tonic-gate syseventd_init()
14377c478bd9Sstevel@tonic-gate {
14387c478bd9Sstevel@tonic-gate int i, fd;
14397c478bd9Sstevel@tonic-gate char local_door_file[PATH_MAX + 1];
14407c478bd9Sstevel@tonic-gate
14417c478bd9Sstevel@tonic-gate fini_pending = 0;
14427c478bd9Sstevel@tonic-gate
14437c478bd9Sstevel@tonic-gate concurrency_level = MIN_CONCURRENCY_LEVEL;
14447c478bd9Sstevel@tonic-gate (void) thr_setconcurrency(concurrency_level);
14457c478bd9Sstevel@tonic-gate
14467c478bd9Sstevel@tonic-gate /*
14477c478bd9Sstevel@tonic-gate * Load client modules for event delivering
14487c478bd9Sstevel@tonic-gate */
14497c478bd9Sstevel@tonic-gate for (i = 0; i < MOD_DIR_NUM; ++i) {
14507c478bd9Sstevel@tonic-gate load_modules(dir_num2name(i));
14517c478bd9Sstevel@tonic-gate }
14527c478bd9Sstevel@tonic-gate
14537c478bd9Sstevel@tonic-gate /*
14547c478bd9Sstevel@tonic-gate * Create kernel delivery door service
14557c478bd9Sstevel@tonic-gate */
14567c478bd9Sstevel@tonic-gate syseventd_print(8, "Create a door for kernel upcalls\n");
14577c478bd9Sstevel@tonic-gate if (snprintf(local_door_file, sizeof (local_door_file), "%s%s",
14587c478bd9Sstevel@tonic-gate root_dir, LOGEVENT_DOOR_UPCALL) >= sizeof (local_door_file)) {
14597c478bd9Sstevel@tonic-gate syseventd_err_print(INIT_PATH_ERR, local_door_file);
14607c478bd9Sstevel@tonic-gate syseventd_exit(5);
14617c478bd9Sstevel@tonic-gate }
14627c478bd9Sstevel@tonic-gate
14637c478bd9Sstevel@tonic-gate /*
14647c478bd9Sstevel@tonic-gate * Remove door file for robustness.
14657c478bd9Sstevel@tonic-gate */
14667c478bd9Sstevel@tonic-gate if (unlink(local_door_file) != 0)
14677c478bd9Sstevel@tonic-gate syseventd_print(8, "Unlink of %s failed.\n", local_door_file);
14687c478bd9Sstevel@tonic-gate
14697c478bd9Sstevel@tonic-gate fd = open(local_door_file, O_CREAT|O_RDWR, S_IREAD|S_IWRITE);
14707c478bd9Sstevel@tonic-gate if ((fd == -1) && (errno != EEXIST)) {
14717c478bd9Sstevel@tonic-gate syseventd_err_print(INIT_OPEN_DOOR_ERR, strerror(errno));
14727c478bd9Sstevel@tonic-gate syseventd_exit(5);
14737c478bd9Sstevel@tonic-gate }
14747c478bd9Sstevel@tonic-gate (void) close(fd);
14757c478bd9Sstevel@tonic-gate
14767c478bd9Sstevel@tonic-gate upcall_door = door_create(door_upcall, NULL,
14777c478bd9Sstevel@tonic-gate DOOR_REFUSE_DESC | DOOR_NO_CANCEL);
14787c478bd9Sstevel@tonic-gate if (upcall_door == -1) {
14797c478bd9Sstevel@tonic-gate syseventd_err_print(INIT_CREATE_DOOR_ERR, strerror(errno));
14807c478bd9Sstevel@tonic-gate syseventd_exit(5);
14817c478bd9Sstevel@tonic-gate }
14827c478bd9Sstevel@tonic-gate
14837c478bd9Sstevel@tonic-gate (void) fdetach(local_door_file);
14847c478bd9Sstevel@tonic-gate retry:
14857c478bd9Sstevel@tonic-gate if (fattach(upcall_door, local_door_file) != 0) {
14867c478bd9Sstevel@tonic-gate if (errno == EBUSY)
14877c478bd9Sstevel@tonic-gate goto retry;
14887c478bd9Sstevel@tonic-gate syseventd_err_print(INIT_FATTACH_ERR, strerror(errno));
14897c478bd9Sstevel@tonic-gate (void) door_revoke(upcall_door);
14907c478bd9Sstevel@tonic-gate syseventd_exit(5);
14917c478bd9Sstevel@tonic-gate }
14927c478bd9Sstevel@tonic-gate
14937c478bd9Sstevel@tonic-gate /*
14947c478bd9Sstevel@tonic-gate * Tell kernel the door name and start delivery
14957c478bd9Sstevel@tonic-gate */
14967c478bd9Sstevel@tonic-gate syseventd_print(2,
14977c478bd9Sstevel@tonic-gate "local_door_file = %s\n", local_door_file);
14987c478bd9Sstevel@tonic-gate if (modctl(MODEVENTS,
14997c478bd9Sstevel@tonic-gate (uintptr_t)MODEVENTS_SET_DOOR_UPCALL_FILENAME,
15007c478bd9Sstevel@tonic-gate (uintptr_t)local_door_file, NULL, NULL, 0) < 0) {
15017c478bd9Sstevel@tonic-gate syseventd_err_print(INIT_DOOR_NAME_ERR, strerror(errno));
15027c478bd9Sstevel@tonic-gate syseventd_exit(6);
15037c478bd9Sstevel@tonic-gate }
15047c478bd9Sstevel@tonic-gate
15057c478bd9Sstevel@tonic-gate door_upcall_retval = 0;
15067c478bd9Sstevel@tonic-gate
15077c478bd9Sstevel@tonic-gate if (modctl(MODEVENTS, (uintptr_t)MODEVENTS_FLUSH, NULL, NULL, NULL, 0)
15087c478bd9Sstevel@tonic-gate < 0) {
15097c478bd9Sstevel@tonic-gate syseventd_err_print(KERNEL_REPLAY_ERR, strerror(errno));
15107c478bd9Sstevel@tonic-gate syseventd_exit(7);
15117c478bd9Sstevel@tonic-gate }
15127c478bd9Sstevel@tonic-gate }
15137c478bd9Sstevel@tonic-gate
15147c478bd9Sstevel@tonic-gate /*
15157c478bd9Sstevel@tonic-gate * syseventd_fini - shut down daemon, but do not exit
15167c478bd9Sstevel@tonic-gate */
15177c478bd9Sstevel@tonic-gate static void
syseventd_fini(int sig)15187c478bd9Sstevel@tonic-gate syseventd_fini(int sig)
15197c478bd9Sstevel@tonic-gate {
15207c478bd9Sstevel@tonic-gate /*
15217c478bd9Sstevel@tonic-gate * Indicate that event queues should be drained and no
15227c478bd9Sstevel@tonic-gate * additional events be accepted
15237c478bd9Sstevel@tonic-gate */
15247c478bd9Sstevel@tonic-gate fini_pending = 1;
15257c478bd9Sstevel@tonic-gate
15267c478bd9Sstevel@tonic-gate /* Close the kernel event door to halt delivery */
15277c478bd9Sstevel@tonic-gate (void) door_revoke(upcall_door);
15287c478bd9Sstevel@tonic-gate
15297c478bd9Sstevel@tonic-gate syseventd_print(1, "Unloading modules\n");
15307c478bd9Sstevel@tonic-gate (void) rw_wrlock(&mod_unload_lock);
15317c478bd9Sstevel@tonic-gate unload_modules(sig);
15327c478bd9Sstevel@tonic-gate (void) rw_unlock(&mod_unload_lock);
15337c478bd9Sstevel@tonic-gate
15347c478bd9Sstevel@tonic-gate }
15357c478bd9Sstevel@tonic-gate
15367c478bd9Sstevel@tonic-gate /*
15377c478bd9Sstevel@tonic-gate * enter_daemon_lock - lock the daemon file lock
15387c478bd9Sstevel@tonic-gate *
15397c478bd9Sstevel@tonic-gate * Use an advisory lock to ensure that only one daemon process is active
15407c478bd9Sstevel@tonic-gate * in the system at any point in time. If the lock is held by another
15417c478bd9Sstevel@tonic-gate * process, do not block but return the pid owner of the lock to the
15427c478bd9Sstevel@tonic-gate * caller immediately. The lock is cleared if the holding daemon process
15437c478bd9Sstevel@tonic-gate * exits for any reason even if the lock file remains, so the daemon can
15447c478bd9Sstevel@tonic-gate * be restarted if necessary. The lock file is DAEMON_LOCK_FILE.
15457c478bd9Sstevel@tonic-gate */
15467c478bd9Sstevel@tonic-gate static pid_t
enter_daemon_lock(void)15477c478bd9Sstevel@tonic-gate enter_daemon_lock(void)
15487c478bd9Sstevel@tonic-gate {
15497c478bd9Sstevel@tonic-gate struct flock lock;
15507c478bd9Sstevel@tonic-gate
15517c478bd9Sstevel@tonic-gate syseventd_print(8, "enter_daemon_lock: lock file = %s\n",
15527c478bd9Sstevel@tonic-gate DAEMON_LOCK_FILE);
15537c478bd9Sstevel@tonic-gate
15547c478bd9Sstevel@tonic-gate if (snprintf(local_lock_file, sizeof (local_lock_file), "%s%s",
15557c478bd9Sstevel@tonic-gate root_dir, DAEMON_LOCK_FILE) >= sizeof (local_lock_file)) {
15567c478bd9Sstevel@tonic-gate syseventd_err_print(INIT_PATH_ERR, local_lock_file);
15577c478bd9Sstevel@tonic-gate syseventd_exit(8);
15587c478bd9Sstevel@tonic-gate }
15597c478bd9Sstevel@tonic-gate daemon_lock_fd = open(local_lock_file, O_CREAT|O_RDWR, 0644);
15607c478bd9Sstevel@tonic-gate if (daemon_lock_fd < 0) {
15617c478bd9Sstevel@tonic-gate syseventd_err_print(INIT_LOCK_OPEN_ERR,
15627c478bd9Sstevel@tonic-gate local_lock_file, strerror(errno));
15637c478bd9Sstevel@tonic-gate syseventd_exit(8);
15647c478bd9Sstevel@tonic-gate }
15657c478bd9Sstevel@tonic-gate
15667c478bd9Sstevel@tonic-gate lock.l_type = F_WRLCK;
15677c478bd9Sstevel@tonic-gate lock.l_whence = SEEK_SET;
15687c478bd9Sstevel@tonic-gate lock.l_start = 0;
15697c478bd9Sstevel@tonic-gate lock.l_len = 0;
15707c478bd9Sstevel@tonic-gate
15717c478bd9Sstevel@tonic-gate if (fcntl(daemon_lock_fd, F_SETLK, &lock) == -1) {
15727c478bd9Sstevel@tonic-gate if (fcntl(daemon_lock_fd, F_GETLK, &lock) == -1) {
15737c478bd9Sstevel@tonic-gate syseventd_err_print(INIT_LOCK_ERR,
15747c478bd9Sstevel@tonic-gate local_lock_file, strerror(errno));
15757c478bd9Sstevel@tonic-gate exit(2);
15767c478bd9Sstevel@tonic-gate }
15777c478bd9Sstevel@tonic-gate return (lock.l_pid);
15787c478bd9Sstevel@tonic-gate }
15797c478bd9Sstevel@tonic-gate hold_daemon_lock = 1;
15807c478bd9Sstevel@tonic-gate
15817c478bd9Sstevel@tonic-gate return (getpid());
15827c478bd9Sstevel@tonic-gate }
15837c478bd9Sstevel@tonic-gate
15847c478bd9Sstevel@tonic-gate /*
15857c478bd9Sstevel@tonic-gate * exit_daemon_lock - release the daemon file lock
15867c478bd9Sstevel@tonic-gate */
15877c478bd9Sstevel@tonic-gate static void
exit_daemon_lock(void)15887c478bd9Sstevel@tonic-gate exit_daemon_lock(void)
15897c478bd9Sstevel@tonic-gate {
15907c478bd9Sstevel@tonic-gate struct flock lock;
15917c478bd9Sstevel@tonic-gate
15927c478bd9Sstevel@tonic-gate lock.l_type = F_UNLCK;
15937c478bd9Sstevel@tonic-gate lock.l_whence = SEEK_SET;
15947c478bd9Sstevel@tonic-gate lock.l_start = 0;
15957c478bd9Sstevel@tonic-gate lock.l_len = 0;
15967c478bd9Sstevel@tonic-gate
15977c478bd9Sstevel@tonic-gate if (fcntl(daemon_lock_fd, F_SETLK, &lock) == -1) {
15987c478bd9Sstevel@tonic-gate syseventd_err_print(INIT_UNLOCK_ERR,
15997c478bd9Sstevel@tonic-gate local_lock_file, strerror(errno));
16007c478bd9Sstevel@tonic-gate }
16017c478bd9Sstevel@tonic-gate
16027c478bd9Sstevel@tonic-gate if (close(daemon_lock_fd) == -1) {
16037c478bd9Sstevel@tonic-gate syseventd_err_print(INIT_LOCK_CLOSE_ERR,
16047c478bd9Sstevel@tonic-gate local_lock_file, strerror(errno));
16057c478bd9Sstevel@tonic-gate exit(-1);
16067c478bd9Sstevel@tonic-gate }
16077c478bd9Sstevel@tonic-gate }
16087c478bd9Sstevel@tonic-gate
16097c478bd9Sstevel@tonic-gate /*
16107c478bd9Sstevel@tonic-gate * syseventd_err_print - print error messages to the terminal if not
16117c478bd9Sstevel@tonic-gate * yet daemonized or to syslog.
16127c478bd9Sstevel@tonic-gate */
16137c478bd9Sstevel@tonic-gate /*PRINTFLIKE1*/
16147c478bd9Sstevel@tonic-gate void
syseventd_err_print(char * message,...)16157c478bd9Sstevel@tonic-gate syseventd_err_print(char *message, ...)
16167c478bd9Sstevel@tonic-gate {
16177c478bd9Sstevel@tonic-gate va_list ap;
16187c478bd9Sstevel@tonic-gate
16197c478bd9Sstevel@tonic-gate (void) mutex_lock(&err_mutex);
16207c478bd9Sstevel@tonic-gate va_start(ap, message);
16217c478bd9Sstevel@tonic-gate
16227c478bd9Sstevel@tonic-gate if (logflag) {
16237c478bd9Sstevel@tonic-gate (void) vsyslog(LOG_ERR, message, ap);
16247c478bd9Sstevel@tonic-gate } else {
16257c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "%s: ", prog);
16267c478bd9Sstevel@tonic-gate (void) vfprintf(stderr, message, ap);
16277c478bd9Sstevel@tonic-gate }
16287c478bd9Sstevel@tonic-gate va_end(ap);
16297c478bd9Sstevel@tonic-gate (void) mutex_unlock(&err_mutex);
16307c478bd9Sstevel@tonic-gate }
16317c478bd9Sstevel@tonic-gate
16327c478bd9Sstevel@tonic-gate /*
16337c478bd9Sstevel@tonic-gate * syseventd_print - print messages to the terminal or to syslog
16347c478bd9Sstevel@tonic-gate * the following levels are implemented:
16357c478bd9Sstevel@tonic-gate *
16367c478bd9Sstevel@tonic-gate * 1 - transient errors that does not affect normal program flow
16377c478bd9Sstevel@tonic-gate * 2 - upcall/dispatch interaction
16387c478bd9Sstevel@tonic-gate * 3 - program flow trace as each message goes through the daemon
16397c478bd9Sstevel@tonic-gate * 8 - all the nit-gritty details of startup and shutdown
16407c478bd9Sstevel@tonic-gate * 9 - very verbose event flow tracing (no daemonization of syseventd)
16417c478bd9Sstevel@tonic-gate *
16427c478bd9Sstevel@tonic-gate */
16437c478bd9Sstevel@tonic-gate /*PRINTFLIKE2*/
16447c478bd9Sstevel@tonic-gate void
syseventd_print(int level,char * message,...)16457c478bd9Sstevel@tonic-gate syseventd_print(int level, char *message, ...)
16467c478bd9Sstevel@tonic-gate {
16477c478bd9Sstevel@tonic-gate va_list ap;
16487c478bd9Sstevel@tonic-gate static int newline = 1;
16497c478bd9Sstevel@tonic-gate
16507c478bd9Sstevel@tonic-gate if (level > debug_level) {
16517c478bd9Sstevel@tonic-gate return;
16527c478bd9Sstevel@tonic-gate }
16537c478bd9Sstevel@tonic-gate
16547c478bd9Sstevel@tonic-gate (void) mutex_lock(&err_mutex);
16557c478bd9Sstevel@tonic-gate va_start(ap, message);
16567c478bd9Sstevel@tonic-gate if (logflag) {
16577c478bd9Sstevel@tonic-gate (void) syslog(LOG_DEBUG, "%s[%ld]: ",
16587c478bd9Sstevel@tonic-gate prog, getpid());
16597c478bd9Sstevel@tonic-gate (void) vsyslog(LOG_DEBUG, message, ap);
16607c478bd9Sstevel@tonic-gate } else {
16617c478bd9Sstevel@tonic-gate if (newline) {
16627c478bd9Sstevel@tonic-gate (void) fprintf(stdout, "%s[%ld]: ",
16637c478bd9Sstevel@tonic-gate prog, getpid());
16647c478bd9Sstevel@tonic-gate (void) vfprintf(stdout, message, ap);
16657c478bd9Sstevel@tonic-gate } else {
16667c478bd9Sstevel@tonic-gate (void) vfprintf(stdout, message, ap);
16677c478bd9Sstevel@tonic-gate }
16687c478bd9Sstevel@tonic-gate }
16697c478bd9Sstevel@tonic-gate if (message[strlen(message)-1] == '\n') {
16707c478bd9Sstevel@tonic-gate newline = 1;
16717c478bd9Sstevel@tonic-gate } else {
16727c478bd9Sstevel@tonic-gate newline = 0;
16737c478bd9Sstevel@tonic-gate }
16747c478bd9Sstevel@tonic-gate va_end(ap);
16757c478bd9Sstevel@tonic-gate (void) mutex_unlock(&err_mutex);
16767c478bd9Sstevel@tonic-gate }
1677