1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21
22 /*
23 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 */
26
27 /*
28 * syseventd - The system event daemon
29 *
30 * This daemon dispatches event buffers received from the
31 * kernel to all interested SLM clients. SLMs in turn
32 * deliver the buffers to their particular application
33 * clients.
34 */
35 #include <stdio.h>
36 #include <sys/types.h>
37 #include <dirent.h>
38 #include <stdarg.h>
39 #include <stddef.h>
40 #include <stdlib.h>
41 #include <dlfcn.h>
42 #include <door.h>
43 #include <errno.h>
44 #include <fcntl.h>
45 #include <signal.h>
46 #include <strings.h>
47 #include <unistd.h>
48 #include <synch.h>
49 #include <syslog.h>
50 #include <thread.h>
51 #include <libsysevent.h>
52 #include <limits.h>
53 #include <locale.h>
54 #include <sys/sysevent.h>
55 #include <sys/sysevent_impl.h>
56 #include <sys/modctl.h>
57 #include <sys/stat.h>
58 #include <sys/systeminfo.h>
59 #include <sys/wait.h>
60
61 #include "sysevent_signal.h"
62 #include "syseventd.h"
63 #include "message.h"
64
65 extern int insert_client(void *client, int client_type, int retry_limit);
66 extern void delete_client(int id);
67 extern void initialize_client_tbl(void);
68
69 extern struct sysevent_client *sysevent_client_tbl[];
70 extern mutex_t client_tbl_lock;
71
72 #define DEBUG_LEVEL_FORK 9 /* will run in background at all */
73 /* levels less than DEBUG_LEVEL_FORK */
74
75 int debug_level = 0;
76 char *root_dir = ""; /* Relative root for lock and door */
77
78 /* Maximum number of outstanding events dispatched */
79 #define SE_EVENT_DISPATCH_CNT 100
80
81 static int upcall_door; /* Kernel event door */
82 static int door_upcall_retval; /* Kernel event posting return value */
83 static int fini_pending = 0; /* fini pending flag */
84 static int deliver_buf = 0; /* Current event buffer from kernel */
85 static int dispatch_buf = 0; /* Current event buffer dispatched */
86 static sysevent_t **eventbuf; /* Global array of event buffers */
87 static struct ev_completion *event_compq; /* Event completion queue */
88 static mutex_t ev_comp_lock; /* Event completion queue lock */
89 static mutex_t err_mutex; /* error logging lock */
90 static mutex_t door_lock; /* sync door return access */
91 static rwlock_t mod_unload_lock; /* sync module unloading */
92
93 /* declarations and definitions for avoiding multiple daemons running */
94 #define DAEMON_LOCK_FILE "/var/run/syseventd.lock"
95 char local_lock_file[PATH_MAX + 1];
96 static int hold_daemon_lock;
97 static int daemon_lock_fd;
98
99 /*
100 * sema_eventbuf - guards against the global buffer eventbuf
101 * being written to before it has been dispatched to clients
102 *
103 * sema_dispatch - synchronizes between the kernel uploading thread
104 * (producer) and the userland dispatch_message thread (consumer).
105 *
106 * sema_resource - throttles outstanding event consumption.
107 *
108 * event_comp_cv - synchronizes threads waiting for the event completion queue
109 * to empty or become active.
110 */
111 static sema_t sema_eventbuf, sema_dispatch, sema_resource;
112 static cond_t event_comp_cv;
113
114 /* Self-tuning concurrency level */
115 #define MIN_CONCURRENCY_LEVEL 4
116 static int concurrency_level = MIN_CONCURRENCY_LEVEL;
117
118
119 /* SLM defines */
120 #define MODULE_SUFFIX ".so"
121 #define EVENT_FINI "slm_fini"
122 #define EVENT_INIT "slm_init"
123
124 #define SE_TIMEOUT 60 /* Client dispatch timeout (seconds) */
125
126 /* syslog message related */
127 static int logflag = 0;
128 static char *prog;
129
130 /* function prototypes */
131 static void door_upcall(void *cookie, char *args, size_t alen, door_desc_t *ddp,
132 uint_t ndid);
133 static void dispatch_message(void);
134 static int dispatch(void);
135 static void event_completion_thr(void);
136 static void usage(void);
137
138 static void syseventd_init(void);
139 static void syseventd_fini(int sig);
140
141 static pid_t enter_daemon_lock(void);
142 static void exit_daemon_lock(void);
143
144 static void
usage()145 usage()
146 {
147 (void) fprintf(stderr, "usage: syseventd [-d <debug_level>] "
148 "[-r <root_dir>]\n");
149 (void) fprintf(stderr, "higher debug levels get progressively ");
150 (void) fprintf(stderr, "more detailed debug information.\n");
151 (void) fprintf(stderr, "syseventd will run in background if ");
152 (void) fprintf(stderr, "run with a debug_level less than %d.\n",
153 DEBUG_LEVEL_FORK);
154 exit(2);
155 }
156
157
158 /* common exit function which ensures releasing locks */
159 void
syseventd_exit(int status)160 syseventd_exit(int status)
161 {
162 syseventd_print(1, "exit status = %d\n", status);
163
164 if (hold_daemon_lock) {
165 exit_daemon_lock();
166 }
167
168 exit(status);
169 }
170
171
172 /*
173 * hup_handler - SIGHUP handler. SIGHUP is used to force a reload of
174 * all SLMs. During fini, events are drained from all
175 * client event queues. The events that have been consumed
176 * by all clients are freed from the kernel event queue.
177 *
178 * Events that have not yet been delivered to all clients
179 * are not freed and will be replayed after all SLMs have
180 * been (re)loaded.
181 *
182 * After all client event queues have been drained, each
183 * SLM client is unloaded. The init phase will (re)load
184 * each SLM and initiate event replay and delivery from
185 * the kernel.
186 *
187 */
188 /*ARGSUSED*/
189 static void
hup_handler(int sig)190 hup_handler(int sig)
191 {
192 syseventd_err_print(SIGHUP_CAUGHT);
193 (void) fflush(0);
194 syseventd_fini(sig);
195 syseventd_init();
196 syseventd_err_print(DAEMON_RESTARTED);
197 (void) fflush(0);
198 }
199
200 /*
201 * Fault handler for other signals caught
202 */
203 /*ARGSUSED*/
204 static void
flt_handler(int sig)205 flt_handler(int sig)
206 {
207 char signame[SIG2STR_MAX];
208
209 if (sig2str(sig, signame) == -1) {
210 syseventd_err_print(UNKNOWN_SIGNAL_CAUGHT, sig);
211 }
212
213 (void) se_signal_sethandler(sig, SE_SIG_DFL, NULL);
214
215 switch (sig) {
216 case SIGINT:
217 case SIGSTOP:
218 case SIGTERM:
219 /* Close kernel door */
220 (void) door_revoke(upcall_door);
221
222 /* Gracefully exit current event delivery threads */
223 syseventd_fini(sig);
224
225 (void) fflush(0);
226 (void) se_signal_unblockall();
227 syseventd_exit(1);
228 /*NOTREACHED*/
229 case SIGCLD:
230 case SIGPWR:
231 case SIGWINCH:
232 case SIGURG:
233 case SIGCONT:
234 case SIGWAITING:
235 case SIGLWP:
236 case SIGFREEZE:
237 case SIGTHAW:
238 case SIGCANCEL:
239 case SIGXRES:
240 case SIGJVM1:
241 case SIGJVM2:
242 case SIGINFO:
243 /* No need to abort */
244 break;
245 default:
246 syseventd_err_print(FATAL_ERROR);
247 abort();
248
249 }
250 }
251
252 /*
253 * Daemon parent process only.
254 * Child process signal to indicate successful daemon initialization.
255 * This is the normal and expected exit path of the daemon parent.
256 */
257 /*ARGSUSED*/
258 static void
sigusr1(int sig)259 sigusr1(int sig)
260 {
261 syseventd_exit(0);
262 }
263
264 static void *
sigwait_thr(void * arg __unused)265 sigwait_thr(void *arg __unused)
266 {
267 int sig;
268 int err;
269 sigset_t signal_set;
270
271 for (;;) {
272 syseventd_print(3, "sigwait thread waiting for signal\n");
273 (void) sigfillset(&signal_set);
274 err = sigwait(&signal_set, &sig);
275 if (err) {
276 syseventd_exit(2);
277 }
278
279 /*
280 * Block all signals until the signal handler completes
281 */
282 if (sig == SIGHUP) {
283 hup_handler(sig);
284 } else {
285 flt_handler(sig);
286 }
287 }
288 return (NULL);
289 }
290
291 static void
set_root_dir(char * dir)292 set_root_dir(char *dir)
293 {
294 root_dir = malloc(strlen(dir) + 1);
295 if (root_dir == NULL) {
296 syseventd_err_print(INIT_ROOT_DIR_ERR, strerror(errno));
297 syseventd_exit(2);
298 }
299 (void) strcpy(root_dir, dir);
300 }
301
302 int
main(int argc,char ** argv)303 main(int argc, char **argv)
304 {
305 int i, c;
306 int fd;
307 pid_t pid;
308 int has_forked = 0;
309 extern char *optarg;
310
311 (void) setlocale(LC_ALL, "");
312 (void) textdomain(TEXT_DOMAIN);
313
314 if (getuid() != 0) {
315 (void) fprintf(stderr, "Must be root to run syseventd\n");
316 syseventd_exit(1);
317 }
318
319 if (argc > 5) {
320 usage();
321 }
322
323 if ((prog = strrchr(argv[0], '/')) == NULL) {
324 prog = argv[0];
325 } else {
326 prog++;
327 }
328
329 while ((c = getopt(argc, argv, "d:r:")) != EOF) {
330 switch (c) {
331 case 'd':
332 debug_level = atoi(optarg);
333 break;
334 case 'r':
335 /*
336 * Private flag for suninstall to run
337 * daemon during install.
338 */
339 set_root_dir(optarg);
340 break;
341 case '?':
342 default:
343 usage();
344 }
345 }
346
347 /* demonize ourselves */
348 if (debug_level < DEBUG_LEVEL_FORK) {
349
350 sigset_t mask;
351
352 (void) sigset(SIGUSR1, sigusr1);
353
354 (void) sigemptyset(&mask);
355 (void) sigaddset(&mask, SIGUSR1);
356 (void) sigprocmask(SIG_BLOCK, &mask, NULL);
357
358 if ((pid = fork()) == (pid_t)-1) {
359 (void) fprintf(stderr,
360 "syseventd: fork failed - %s\n", strerror(errno));
361 syseventd_exit(1);
362 }
363
364 if (pid != 0) {
365 /*
366 * parent
367 * handshake with the daemon so that dependents
368 * of the syseventd service don't start up until
369 * the service is actually functional
370 */
371 int status;
372 (void) sigprocmask(SIG_UNBLOCK, &mask, NULL);
373
374 if (waitpid(pid, &status, 0) != pid) {
375 /*
376 * child process signal indicating
377 * successful daemon initialization
378 */
379 syseventd_exit(0);
380 }
381 /* child exited implying unsuccessful startup */
382 syseventd_exit(1);
383 }
384
385 /* child */
386
387 has_forked = 1;
388 (void) sigset(SIGUSR1, SIG_DFL);
389 (void) sigprocmask(SIG_UNBLOCK, &mask, NULL);
390
391 (void) chdir("/");
392 (void) setsid();
393 if (debug_level <= 1) {
394 closefrom(0);
395 fd = open("/dev/null", 0);
396 (void) dup2(fd, 1);
397 (void) dup2(fd, 2);
398 logflag = 1;
399 }
400 }
401
402 openlog("syseventd", LOG_PID, LOG_DAEMON);
403
404 (void) mutex_init(&err_mutex, USYNC_THREAD, NULL);
405
406 syseventd_print(8,
407 "syseventd started, debug level = %d\n", debug_level);
408
409 /* only one instance of syseventd can run at a time */
410 if ((pid = enter_daemon_lock()) != getpid()) {
411 syseventd_print(1,
412 "event daemon pid %ld already running\n", pid);
413 exit(3);
414 }
415
416 /* initialize semaphores and eventbuf */
417 (void) sema_init(&sema_eventbuf, SE_EVENT_DISPATCH_CNT,
418 USYNC_THREAD, NULL);
419 (void) sema_init(&sema_dispatch, 0, USYNC_THREAD, NULL);
420 (void) sema_init(&sema_resource, SE_EVENT_DISPATCH_CNT,
421 USYNC_THREAD, NULL);
422 (void) cond_init(&event_comp_cv, USYNC_THREAD, NULL);
423 eventbuf = (sysevent_t **)calloc(SE_EVENT_DISPATCH_CNT,
424 sizeof (sysevent_t *));
425 if (eventbuf == NULL) {
426 syseventd_print(1, "Unable to allocate event buffer array\n");
427 exit(2);
428 }
429 for (i = 0; i < SE_EVENT_DISPATCH_CNT; ++i) {
430 eventbuf[i] = malloc(LOGEVENT_BUFSIZE);
431 if (eventbuf[i] == NULL) {
432 syseventd_print(1, "Unable to allocate event "
433 "buffers\n");
434 exit(2);
435 }
436 }
437
438 (void) mutex_init(&client_tbl_lock, USYNC_THREAD, NULL);
439 (void) mutex_init(&ev_comp_lock, USYNC_THREAD, NULL);
440 (void) mutex_init(&door_lock, USYNC_THREAD, NULL);
441 (void) rwlock_init(&mod_unload_lock, USYNC_THREAD, NULL);
442
443 event_compq = NULL;
444
445 syseventd_print(8, "start the message thread running\n");
446
447 /*
448 * Block all signals to all threads include the main thread.
449 * The sigwait_thr thread will process any signals and initiate
450 * a graceful recovery if possible.
451 */
452 if (se_signal_blockall() < 0) {
453 syseventd_err_print(INIT_SIG_BLOCK_ERR);
454 syseventd_exit(2);
455 }
456
457 if (thr_create(NULL, 0, (void *(*)(void *))dispatch_message,
458 (void *)0, 0, NULL) < 0) {
459 syseventd_err_print(INIT_THR_CREATE_ERR, strerror(errno));
460 syseventd_exit(2);
461 }
462 if (thr_create(NULL, 0,
463 (void *(*)(void *))event_completion_thr, NULL,
464 THR_BOUND, NULL) != 0) {
465 syseventd_err_print(INIT_THR_CREATE_ERR, strerror(errno));
466 syseventd_exit(2);
467 }
468 /* Create signal catching thread */
469 if (thr_create(NULL, 0, sigwait_thr, NULL, 0, NULL) < 0) {
470 syseventd_err_print(INIT_THR_CREATE_ERR, strerror(errno));
471 syseventd_exit(2);
472 }
473
474 setbuf(stdout, (char *)NULL);
475
476 /* Initialize and load SLM clients */
477 initialize_client_tbl();
478 syseventd_init();
479
480 /* signal parent to indicate successful daemon initialization */
481 if (has_forked) {
482 if (kill(getppid(), SIGUSR1) != 0) {
483 syseventd_err_print(
484 "signal to the parent failed - %s\n",
485 strerror(errno));
486 syseventd_exit(2);
487 }
488 }
489
490 syseventd_print(8, "Pausing\n");
491
492 for (;;) {
493 (void) pause();
494 }
495 /* NOTREACHED */
496 return (0);
497 }
498
499 /*
500 * door_upcall - called from the kernel via kernel sysevent door
501 * to upload event(s).
502 *
503 * This routine should never block. If resources are
504 * not available to immediately accept the event buffer
505 * EAGAIN is returned to the kernel.
506 *
507 * Once resources are available, the kernel is notified
508 * via a modctl interface to resume event delivery to
509 * syseventd.
510 *
511 */
512 /*ARGSUSED*/
513 static void
door_upcall(void * cookie,char * args,size_t alen,door_desc_t * ddp,uint_t ndid)514 door_upcall(void *cookie, char *args, size_t alen,
515 door_desc_t *ddp, uint_t ndid)
516 {
517 sysevent_t *ev;
518 int rval;
519
520
521 (void) mutex_lock(&door_lock);
522 if (args == NULL) {
523 rval = EINVAL;
524 } else if (sema_trywait(&sema_eventbuf)) {
525 ev = (sysevent_t *)
526 &((log_event_upcall_arg_t *)(void *)args)->buf;
527 syseventd_print(2, "door_upcall: busy event %llx "
528 "retry\n", sysevent_get_seq(ev));
529 rval = door_upcall_retval = EAGAIN;
530 } else {
531 /*
532 * Copy received message to local buffer.
533 */
534 size_t size;
535 ev = (sysevent_t *)
536 &((log_event_upcall_arg_t *)(void *)args)->buf;
537
538 syseventd_print(2, "door_upcall: event %llx in eventbuf %d\n",
539 sysevent_get_seq(ev), deliver_buf);
540 size = sysevent_get_size(ev) > LOGEVENT_BUFSIZE ?
541 LOGEVENT_BUFSIZE : sysevent_get_size(ev);
542 (void) bcopy(ev, eventbuf[deliver_buf], size);
543 deliver_buf = (deliver_buf + 1) % SE_EVENT_DISPATCH_CNT;
544 rval = 0;
545 (void) sema_post(&sema_dispatch);
546 }
547
548 (void) mutex_unlock(&door_lock);
549
550 /*
551 * Filling in return values for door_return
552 */
553 (void) door_return((void *)&rval, sizeof (rval), NULL, 0);
554 (void) door_return(NULL, 0, NULL, 0);
555 }
556
557 /*
558 * dispatch_message - dispatch message thread
559 * This thread spins until an event buffer is delivered
560 * delivered from the kernel.
561 *
562 * It will wait to dispatch an event to any clients
563 * until adequate resources are available to process
564 * the event buffer.
565 */
566 static void
dispatch_message(void)567 dispatch_message(void)
568 {
569 int error;
570
571 for (;;) {
572 syseventd_print(3, "dispatch_message: thread started\n");
573 /*
574 * Spin till a message comes
575 */
576 while (sema_wait(&sema_dispatch) != 0) {
577 syseventd_print(1,
578 "dispatch_message: sema_wait failed\n");
579 (void) sleep(1);
580 }
581
582 syseventd_print(3, "dispatch_message: sema_dispatch\n");
583
584 /*
585 * Wait for available resources
586 */
587 while (sema_wait(&sema_resource) != 0) {
588 syseventd_print(1, "dispatch_message: sema_wait "
589 "failed\n");
590 (void) sleep(1);
591 }
592
593 syseventd_print(2, "dispatch_message: eventbuf %d\n",
594 dispatch_buf);
595
596 /*
597 * Client dispatch
598 */
599 do {
600 error = dispatch();
601 } while (error == EAGAIN);
602
603 syseventd_print(2, "eventbuf %d dispatched\n", dispatch_buf);
604 dispatch_buf = (dispatch_buf + 1) % SE_EVENT_DISPATCH_CNT;
605
606 /*
607 * kernel received a busy signal -
608 * kickstart the kernel delivery thread
609 * door_lock blocks the kernel so we hold it for the
610 * shortest time possible.
611 */
612 (void) mutex_lock(&door_lock);
613 if (door_upcall_retval == EAGAIN && !fini_pending) {
614 syseventd_print(3, "dispatch_message: retrigger "
615 "door_upcall_retval = %d\n",
616 door_upcall_retval);
617 (void) modctl(MODEVENTS, (uintptr_t)MODEVENTS_FLUSH,
618 NULL, NULL, NULL, 0);
619 door_upcall_retval = 0;
620 }
621 (void) mutex_unlock(&door_lock);
622 }
623 /* NOTREACHED */
624 }
625
626 /*
627 * drain_eventq - Called to drain all pending events from the client's
628 * event queue.
629 */
630 static void
drain_eventq(struct sysevent_client * scp,int status)631 drain_eventq(struct sysevent_client *scp, int status)
632 {
633 struct event_dispatch_pkg *d_pkg;
634 struct event_dispatchq *eventq, *eventq_next;
635
636 syseventd_print(3, "Draining eventq for client %d\n",
637 scp->client_num);
638
639 eventq = scp->eventq;
640 while (eventq) {
641 /*
642 * Mark all dispatched events as completed, but indicate the
643 * error status
644 */
645 d_pkg = eventq->d_pkg;
646
647 syseventd_print(4, "drain event 0X%llx for client %d\n",
648 sysevent_get_seq(d_pkg->ev), scp->client_num);
649
650 if (d_pkg->completion_state == SE_NOT_DISPATCHED) {
651 d_pkg->completion_status = status;
652 d_pkg->completion_state = SE_COMPLETE;
653 (void) sema_post(d_pkg->completion_sema);
654 }
655
656 eventq_next = eventq->next;
657 free(eventq);
658 eventq = eventq_next;
659 scp->eventq = eventq;
660 }
661 }
662
663 /*
664 * client_deliver_event_thr - Client delivery thread
665 * This thread will process any events on this
666 * client's eventq.
667 */
668 static void *
client_deliver_event_thr(void * arg)669 client_deliver_event_thr(void *arg)
670 {
671 int flag, error, i;
672 sysevent_t *ev;
673 hrtime_t now;
674 module_t *mod;
675 struct event_dispatchq *eventq;
676 struct sysevent_client *scp;
677 struct event_dispatch_pkg *d_pkg;
678
679 scp = (struct sysevent_client *)arg;
680 mod = (module_t *)scp->client_data;
681
682 (void) mutex_lock(&scp->client_lock);
683 for (;;) {
684 while (scp->eventq == NULL) {
685
686 /*
687 * Client has been suspended or unloaded, go no further.
688 */
689 if (fini_pending) {
690 scp->client_flags &= ~SE_CLIENT_THR_RUNNING;
691 syseventd_print(3, "Client %d delivery thread "
692 "exiting flags: 0X%x\n",
693 scp->client_num, scp->client_flags);
694 (void) mutex_unlock(&scp->client_lock);
695 return (NULL);
696 }
697
698 (void) cond_wait(&scp->client_cv, &scp->client_lock);
699
700 }
701
702 /*
703 * Process events from the head of the eventq, eventq is locked
704 * going into the processing.
705 */
706 eventq = scp->eventq;
707 while (eventq != NULL) {
708 d_pkg = eventq->d_pkg;
709 d_pkg->completion_state = SE_OUTSTANDING;
710 scp->eventq = eventq->next;
711 free(eventq);
712 (void) mutex_unlock(&scp->client_lock);
713
714
715 flag = error = 0;
716 ev = d_pkg->ev;
717
718 syseventd_print(3, "Start delivery for client %d "
719 "with retry count %d\n",
720 scp->client_num, d_pkg->retry_count);
721
722 /*
723 * Retry limit has been reached by this client, indicate
724 * that no further retries are allowed
725 */
726 for (i = 0; i <= scp->retry_limit; ++i) {
727 if (i == scp->retry_limit)
728 flag = SE_NO_RETRY;
729
730 /* Start the clock for the event delivery */
731 d_pkg->start_time = gethrtime();
732
733 syseventd_print(9, "Deliver to module client "
734 "%s\n", mod->name);
735
736 error = mod->deliver_event(ev, flag);
737
738 /* Can not allow another retry */
739 if (i == scp->retry_limit)
740 error = 0;
741
742 /* Stop the clock */
743 now = gethrtime();
744
745 /*
746 * Suspend event processing and drain the
747 * event q for latent clients
748 */
749 if (now - d_pkg->start_time >
750 ((hrtime_t)SE_TIMEOUT * NANOSEC)) {
751 syseventd_print(1, "Unresponsive "
752 "client %d: Draining eventq and "
753 "suspending event delivery\n",
754 scp->client_num);
755 (void) mutex_lock(&scp->client_lock);
756 scp->client_flags &=
757 ~SE_CLIENT_THR_RUNNING;
758 scp->client_flags |=
759 SE_CLIENT_SUSPENDED;
760
761 /* Cleanup current event */
762 d_pkg->completion_status = EFAULT;
763 d_pkg->completion_state = SE_COMPLETE;
764 (void) sema_post(
765 d_pkg->completion_sema);
766
767 /*
768 * Drain the remaining events from the
769 * queue.
770 */
771 drain_eventq(scp, EINVAL);
772 (void) mutex_unlock(&scp->client_lock);
773 return (NULL);
774 }
775
776 /* Event delivery retry requested */
777 if (fini_pending || error != EAGAIN) {
778 break;
779 } else {
780 (void) sleep(SE_RETRY_TIME);
781 }
782 }
783
784 (void) mutex_lock(&scp->client_lock);
785 d_pkg->completion_status = error;
786 d_pkg->completion_state = SE_COMPLETE;
787 (void) sema_post(d_pkg->completion_sema);
788 syseventd_print(3, "Completed delivery with "
789 "error %d\n", error);
790 eventq = scp->eventq;
791 }
792
793 syseventd_print(3, "No more events to process for client %d\n",
794 scp->client_num);
795
796 /* Return if this was a synchronous delivery */
797 if (!SE_CLIENT_IS_THR_RUNNING(scp)) {
798 (void) mutex_unlock(&scp->client_lock);
799 return (NULL);
800 }
801
802 }
803 }
804
805 /*
806 * client_deliver_event - Client specific event delivery
807 * This routine will allocate and initialize the
808 * neccessary per-client dispatch data.
809 *
810 * If the eventq is not empty, it may be assumed that
811 * a delivery thread exists for this client and the
812 * dispatch data is appended to the eventq.
813 *
814 * The dispatch package is freed by the event completion
815 * thread (event_completion_thr) and the eventq entry
816 * is freed by the event delivery thread.
817 */
818 static struct event_dispatch_pkg *
client_deliver_event(struct sysevent_client * scp,sysevent_t * ev,sema_t * completion_sema)819 client_deliver_event(struct sysevent_client *scp, sysevent_t *ev,
820 sema_t *completion_sema)
821 {
822 size_t ev_sz = sysevent_get_size(ev);
823 struct event_dispatchq *newq, *tmp;
824 struct event_dispatch_pkg *d_pkg;
825
826 syseventd_print(3, "client_deliver_event: id 0x%llx size %d\n",
827 (longlong_t)sysevent_get_seq(ev), ev_sz);
828 if (debug_level == 9) {
829 se_print(stdout, ev);
830 }
831
832 /*
833 * Check for suspended client
834 */
835 (void) mutex_lock(&scp->client_lock);
836 if (SE_CLIENT_IS_SUSPENDED(scp) || !SE_CLIENT_IS_THR_RUNNING(scp)) {
837 (void) mutex_unlock(&scp->client_lock);
838 return (NULL);
839 }
840
841 /*
842 * Allocate a new dispatch package and eventq entry
843 */
844 newq = (struct event_dispatchq *)malloc(
845 sizeof (struct event_dispatchq));
846 if (newq == NULL) {
847 (void) mutex_unlock(&scp->client_lock);
848 return (NULL);
849 }
850
851 d_pkg = (struct event_dispatch_pkg *)malloc(
852 sizeof (struct event_dispatch_pkg));
853 if (d_pkg == NULL) {
854 free(newq);
855 (void) mutex_unlock(&scp->client_lock);
856 return (NULL);
857 }
858
859 /* Initialize the dispatch package */
860 d_pkg->scp = scp;
861 d_pkg->retry_count = 0;
862 d_pkg->completion_status = 0;
863 d_pkg->completion_state = SE_NOT_DISPATCHED;
864 d_pkg->completion_sema = completion_sema;
865 d_pkg->ev = ev;
866 newq->d_pkg = d_pkg;
867 newq->next = NULL;
868
869 if (scp->eventq != NULL) {
870
871 /* Add entry to the end of the eventq */
872 tmp = scp->eventq;
873 while (tmp->next != NULL)
874 tmp = tmp->next;
875 tmp->next = newq;
876 } else {
877 /* event queue empty, wakeup delivery thread */
878 scp->eventq = newq;
879 (void) cond_signal(&scp->client_cv);
880 }
881 (void) mutex_unlock(&scp->client_lock);
882
883 return (d_pkg);
884 }
885
886 /*
887 * event_completion_thr - Event completion thread. This thread routine
888 * waits for all client delivery thread to complete
889 * delivery of a particular event.
890 */
891 static void
event_completion_thr()892 event_completion_thr()
893 {
894 int ret, i, client_count, ok_to_free;
895 sysevent_id_t eid;
896 struct sysevent_client *scp;
897 struct ev_completion *ev_comp;
898 struct event_dispatchq *dispatchq;
899 struct event_dispatch_pkg *d_pkg;
900
901 (void) mutex_lock(&ev_comp_lock);
902 for (;;) {
903 while (event_compq == NULL) {
904 (void) cond_wait(&event_comp_cv, &ev_comp_lock);
905 }
906
907 /*
908 * Process event completions from the head of the
909 * completion queue
910 */
911 ev_comp = event_compq;
912 while (ev_comp) {
913 (void) mutex_unlock(&ev_comp_lock);
914 eid.eid_seq = sysevent_get_seq(ev_comp->ev);
915 sysevent_get_time(ev_comp->ev, &eid.eid_ts);
916 client_count = ev_comp->client_count;
917 ok_to_free = 1;
918
919 syseventd_print(3, "Wait for event completion of "
920 "event 0X%llx on %d clients\n",
921 eid.eid_seq, client_count);
922
923 while (client_count) {
924 syseventd_print(9, "Waiting for %d clients on "
925 "event id 0X%llx\n", client_count,
926 eid.eid_seq);
927
928 (void) sema_wait(&ev_comp->client_sema);
929 --client_count;
930 }
931
932 syseventd_print(3, "Cleaning up clients for event "
933 "0X%llx\n", eid.eid_seq);
934 dispatchq = ev_comp->dispatch_list;
935 while (dispatchq != NULL) {
936 d_pkg = dispatchq->d_pkg;
937 scp = d_pkg->scp;
938
939 if (d_pkg->completion_status == EAGAIN)
940 ok_to_free = 0;
941
942 syseventd_print(4, "Delivery of 0X%llx "
943 "complete for client %d retry count %d "
944 "status %d\n", eid.eid_seq,
945 scp->client_num,
946 d_pkg->retry_count,
947 d_pkg->completion_status);
948
949 free(d_pkg);
950 ev_comp->dispatch_list = dispatchq->next;
951 free(dispatchq);
952 dispatchq = ev_comp->dispatch_list;
953 }
954
955 if (ok_to_free) {
956 for (i = 0; i < MAX_MODCTL_RETRY; ++i) {
957 if ((ret = modctl(MODEVENTS,
958 (uintptr_t)MODEVENTS_FREEDATA,
959 (uintptr_t)&eid, NULL,
960 NULL, 0)) != 0) {
961 syseventd_print(1, "attempting "
962 "to free event 0X%llx\n",
963 eid.eid_seq);
964
965 /*
966 * Kernel may need time to
967 * move this event buffer to
968 * the sysevent sent queue
969 */
970 (void) sleep(1);
971 } else {
972 break;
973 }
974 }
975 if (ret) {
976 syseventd_print(1, "Unable to free "
977 "event 0X%llx from the "
978 "kernel\n", eid.eid_seq);
979 }
980 } else {
981 syseventd_print(1, "Not freeing event 0X%llx\n",
982 eid.eid_seq);
983 }
984
985 syseventd_print(2, "Event delivery complete for id "
986 "0X%llx\n", eid.eid_seq);
987
988 (void) mutex_lock(&ev_comp_lock);
989 event_compq = ev_comp->next;
990 free(ev_comp->ev);
991 free(ev_comp);
992 ev_comp = event_compq;
993 (void) sema_post(&sema_resource);
994 }
995
996 /*
997 * Event completion queue is empty, signal possible unload
998 * operation
999 */
1000 (void) cond_signal(&event_comp_cv);
1001
1002 syseventd_print(3, "No more events\n");
1003 }
1004 }
1005
1006 /*
1007 * dispatch - Dispatch the current event buffer to all valid SLM clients.
1008 */
1009 static int
dispatch(void)1010 dispatch(void)
1011 {
1012 int ev_sz, i, client_count = 0;
1013 sysevent_t *new_ev;
1014 sysevent_id_t eid;
1015 struct ev_completion *ev_comp, *tmp;
1016 struct event_dispatchq *dispatchq, *client_list;
1017 struct event_dispatch_pkg *d_pkg;
1018
1019 /* Check for module unload operation */
1020 if (rw_tryrdlock(&mod_unload_lock) != 0) {
1021 syseventd_print(2, "unload in progress abort delivery\n");
1022 (void) sema_post(&sema_eventbuf);
1023 (void) sema_post(&sema_resource);
1024 return (0);
1025 }
1026
1027 syseventd_print(3, "deliver dispatch buffer %d", dispatch_buf);
1028 eid.eid_seq = sysevent_get_seq(eventbuf[dispatch_buf]);
1029 sysevent_get_time(eventbuf[dispatch_buf], &eid.eid_ts);
1030 syseventd_print(3, "deliver msg id: 0x%llx\n", eid.eid_seq);
1031
1032 /*
1033 * ev_comp is used to hold event completion data. It is freed
1034 * by the event completion thread (event_completion_thr).
1035 */
1036 ev_comp = (struct ev_completion *)
1037 malloc(sizeof (struct ev_completion));
1038 if (ev_comp == NULL) {
1039 (void) rw_unlock(&mod_unload_lock);
1040 syseventd_print(1, "Can not allocate event completion buffer "
1041 "for event id 0X%llx\n", eid.eid_seq);
1042 return (EAGAIN);
1043 }
1044 ev_comp->dispatch_list = NULL;
1045 ev_comp->next = NULL;
1046 (void) sema_init(&ev_comp->client_sema, 0, USYNC_THREAD, NULL);
1047
1048 ev_sz = sysevent_get_size(eventbuf[dispatch_buf]);
1049 new_ev = calloc(1, ev_sz);
1050 if (new_ev == NULL) {
1051 free(ev_comp);
1052 (void) rw_unlock(&mod_unload_lock);
1053 syseventd_print(1, "Can not allocate new event buffer "
1054 "for event id 0X%llx\n", eid.eid_seq);
1055 return (EAGAIN);
1056 }
1057
1058
1059 /*
1060 * For long messages, copy additional data from kernel
1061 */
1062 if (ev_sz > LOGEVENT_BUFSIZE) {
1063 int ret = 0;
1064
1065 /* Ok to release eventbuf for next event buffer from kernel */
1066 (void) sema_post(&sema_eventbuf);
1067
1068 for (i = 0; i < MAX_MODCTL_RETRY; ++i) {
1069 if ((ret = modctl(MODEVENTS,
1070 (uintptr_t)MODEVENTS_GETDATA,
1071 (uintptr_t)&eid,
1072 (uintptr_t)ev_sz,
1073 (uintptr_t)new_ev, 0))
1074 == 0)
1075 break;
1076 else
1077 (void) sleep(1);
1078 }
1079 if (ret) {
1080 syseventd_print(1, "GET_DATA failed for 0X%llx:%llx\n",
1081 eid.eid_ts, eid.eid_seq);
1082 free(new_ev);
1083 free(ev_comp);
1084 (void) rw_unlock(&mod_unload_lock);
1085 return (EAGAIN);
1086 }
1087 } else {
1088 (void) bcopy(eventbuf[dispatch_buf], new_ev, ev_sz);
1089 /* Ok to release eventbuf for next event buffer from kernel */
1090 (void) sema_post(&sema_eventbuf);
1091 }
1092
1093
1094 /*
1095 * Deliver a copy of eventbuf to clients so
1096 * eventbuf can be used for the next message
1097 */
1098 for (i = 0; i < MAX_SLM; ++i) {
1099
1100 /* Don't bother for suspended or unloaded clients */
1101 if (!SE_CLIENT_IS_LOADED(sysevent_client_tbl[i]) ||
1102 SE_CLIENT_IS_SUSPENDED(sysevent_client_tbl[i]))
1103 continue;
1104
1105 /*
1106 * Allocate event dispatch queue entry. All queue entries
1107 * are freed by the event completion thread as client
1108 * delivery completes.
1109 */
1110 dispatchq = (struct event_dispatchq *)malloc(
1111 sizeof (struct event_dispatchq));
1112 if (dispatchq == NULL) {
1113 syseventd_print(1, "Can not allocate dispatch q "
1114 "for event id 0X%llx client %d\n", eid.eid_seq, i);
1115 continue;
1116 }
1117 dispatchq->next = NULL;
1118
1119 /* Initiate client delivery */
1120 d_pkg = client_deliver_event(sysevent_client_tbl[i],
1121 new_ev, &ev_comp->client_sema);
1122 if (d_pkg == NULL) {
1123 syseventd_print(1, "Can not allocate dispatch "
1124 "package for event id 0X%llx client %d\n",
1125 eid.eid_seq, i);
1126 free(dispatchq);
1127 continue;
1128 }
1129 dispatchq->d_pkg = d_pkg;
1130 ++client_count;
1131
1132 if (ev_comp->dispatch_list == NULL) {
1133 ev_comp->dispatch_list = dispatchq;
1134 client_list = dispatchq;
1135 } else {
1136 client_list->next = dispatchq;
1137 client_list = client_list->next;
1138 }
1139 }
1140
1141 ev_comp->client_count = client_count;
1142 ev_comp->ev = new_ev;
1143
1144 (void) mutex_lock(&ev_comp_lock);
1145
1146 if (event_compq == NULL) {
1147 syseventd_print(3, "Wakeup event completion thread for "
1148 "id 0X%llx\n", eid.eid_seq);
1149 event_compq = ev_comp;
1150 (void) cond_signal(&event_comp_cv);
1151 } else {
1152
1153 /* Add entry to the end of the event completion queue */
1154 tmp = event_compq;
1155 while (tmp->next != NULL)
1156 tmp = tmp->next;
1157 tmp->next = ev_comp;
1158 syseventd_print(3, "event added to completion queue for "
1159 "id 0X%llx\n", eid.eid_seq);
1160 }
1161 (void) mutex_unlock(&ev_comp_lock);
1162 (void) rw_unlock(&mod_unload_lock);
1163
1164 return (0);
1165 }
1166
1167 #define MODULE_DIR_HW "/usr/platform/%s/lib/sysevent/modules/"
1168 #define MODULE_DIR_GEN "/usr/lib/sysevent/modules/"
1169 #define MOD_DIR_NUM 3
1170 static char dirname[MOD_DIR_NUM][MAXPATHLEN];
1171
1172 static char *
dir_num2name(int dirnum)1173 dir_num2name(int dirnum)
1174 {
1175 char infobuf[MAXPATHLEN];
1176
1177 if (dirnum >= MOD_DIR_NUM)
1178 return (NULL);
1179
1180 if (dirname[0][0] == '\0') {
1181 if (sysinfo(SI_PLATFORM, infobuf, MAXPATHLEN) == -1) {
1182 syseventd_print(1, "dir_num2name: "
1183 "sysinfo error %s\n", strerror(errno));
1184 return (NULL);
1185 } else if (snprintf(dirname[0], sizeof (dirname[0]),
1186 MODULE_DIR_HW, infobuf) >= sizeof (dirname[0])) {
1187 syseventd_print(1, "dir_num2name: "
1188 "platform name too long: %s\n",
1189 infobuf);
1190 return (NULL);
1191 }
1192 if (sysinfo(SI_MACHINE, infobuf, MAXPATHLEN) == -1) {
1193 syseventd_print(1, "dir_num2name: "
1194 "sysinfo error %s\n", strerror(errno));
1195 return (NULL);
1196 } else if (snprintf(dirname[1], sizeof (dirname[1]),
1197 MODULE_DIR_HW, infobuf) >= sizeof (dirname[1])) {
1198 syseventd_print(1, "dir_num2name: "
1199 "machine name too long: %s\n",
1200 infobuf);
1201 return (NULL);
1202 }
1203 (void) strcpy(dirname[2], MODULE_DIR_GEN);
1204 }
1205
1206 return (dirname[dirnum]);
1207 }
1208
1209
1210 /*
1211 * load_modules - Load modules found in the common syseventd module directories
1212 * Modules that do not provide valid interfaces are rejected.
1213 */
1214 static void
load_modules(char * dirname)1215 load_modules(char *dirname)
1216 {
1217 int client_id;
1218 DIR *mod_dir;
1219 module_t *mod;
1220 struct dirent *entp;
1221 struct slm_mod_ops *mod_ops;
1222 struct sysevent_client *scp;
1223
1224 if (dirname == NULL)
1225 return;
1226
1227 /* Return silently if module directory does not exist */
1228 if ((mod_dir = opendir(dirname)) == NULL) {
1229 syseventd_print(1, "Unable to open module directory %s: %s\n",
1230 dirname, strerror(errno));
1231 return;
1232 }
1233
1234 syseventd_print(3, "loading modules from %s\n", dirname);
1235
1236 /*
1237 * Go through directory, looking for files ending with .so
1238 */
1239 while ((entp = readdir(mod_dir)) != NULL) {
1240 void *dlh, *f;
1241 char *tmp, modpath[MAXPATHLEN];
1242
1243 if (((tmp = strstr(entp->d_name, MODULE_SUFFIX)) == NULL) ||
1244 (tmp[strlen(MODULE_SUFFIX)] != '\0')) {
1245 continue;
1246 }
1247
1248 if (snprintf(modpath, sizeof (modpath), "%s%s",
1249 dirname, entp->d_name) >= sizeof (modpath)) {
1250 syseventd_err_print(INIT_PATH_ERR, modpath);
1251 continue;
1252 }
1253 if ((dlh = dlopen(modpath, RTLD_LAZY)) == NULL) {
1254 syseventd_err_print(LOAD_MOD_DLOPEN_ERR,
1255 modpath, dlerror());
1256 continue;
1257 } else if ((f = dlsym(dlh, EVENT_INIT)) == NULL) {
1258 syseventd_err_print(LOAD_MOD_NO_INIT,
1259 modpath, dlerror());
1260 (void) dlclose(dlh);
1261 continue;
1262 }
1263
1264 mod = malloc(sizeof (*mod));
1265 if (mod == NULL) {
1266 syseventd_err_print(LOAD_MOD_ALLOC_ERR, "mod",
1267 strerror(errno));
1268 (void) dlclose(dlh);
1269 continue;
1270 }
1271
1272 mod->name = strdup(entp->d_name);
1273 if (mod->name == NULL) {
1274 syseventd_err_print(LOAD_MOD_ALLOC_ERR, "mod->name",
1275 strerror(errno));
1276 (void) dlclose(dlh);
1277 free(mod);
1278 continue;
1279 }
1280
1281 mod->dlhandle = dlh;
1282 mod->event_mod_init = (struct slm_mod_ops *(*)())f;
1283
1284 /* load in other module functions */
1285 mod->event_mod_fini = (void (*)())dlsym(dlh, EVENT_FINI);
1286 if (mod->event_mod_fini == NULL) {
1287 syseventd_err_print(LOAD_MOD_DLSYM_ERR, mod->name,
1288 dlerror());
1289 free(mod->name);
1290 free(mod);
1291 (void) dlclose(dlh);
1292 continue;
1293 }
1294
1295 /* Call module init routine */
1296 if ((mod_ops = mod->event_mod_init()) == NULL) {
1297 syseventd_err_print(LOAD_MOD_EINVAL, mod->name);
1298 free(mod->name);
1299 free(mod);
1300 (void) dlclose(dlh);
1301 continue;
1302 }
1303 if (mod_ops->major_version != SE_MAJOR_VERSION) {
1304 syseventd_err_print(LOAD_MOD_VERSION_MISMATCH,
1305 mod->name, SE_MAJOR_VERSION,
1306 mod_ops->major_version);
1307 mod->event_mod_fini();
1308 free(mod->name);
1309 free(mod);
1310 (void) dlclose(dlh);
1311 continue;
1312 }
1313
1314 mod->deliver_event = mod_ops->deliver_event;
1315 /* Add module entry to client list */
1316 if ((client_id = insert_client((void *)mod, SLM_CLIENT,
1317 (mod_ops->retry_limit <= SE_MAX_RETRY_LIMIT ?
1318 mod_ops->retry_limit : SE_MAX_RETRY_LIMIT))) < 0) {
1319 syseventd_err_print(LOAD_MOD_ALLOC_ERR, "insert_client",
1320 strerror(errno));
1321 mod->event_mod_fini();
1322 free(mod->name);
1323 free(mod);
1324 (void) dlclose(dlh);
1325 continue;
1326 }
1327
1328 scp = sysevent_client_tbl[client_id];
1329 ++concurrency_level;
1330 (void) thr_setconcurrency(concurrency_level);
1331 if (thr_create(NULL, 0, client_deliver_event_thr,
1332 scp, THR_BOUND, &scp->tid) != 0) {
1333
1334 syseventd_err_print(LOAD_MOD_ALLOC_ERR, "insert_client",
1335 strerror(errno));
1336 mod->event_mod_fini();
1337 free(mod->name);
1338 free(mod);
1339 (void) dlclose(dlh);
1340 continue;
1341 }
1342 scp->client_flags |= SE_CLIENT_THR_RUNNING;
1343
1344 syseventd_print(3, "loaded module %s\n", entp->d_name);
1345 }
1346
1347 (void) closedir(mod_dir);
1348 syseventd_print(3, "modules loaded\n");
1349 }
1350
1351 /*
1352 * unload_modules - modules are unloaded prior to graceful shutdown or
1353 * before restarting the daemon upon receipt of
1354 * SIGHUP.
1355 */
1356 static void
unload_modules(int sig)1357 unload_modules(int sig)
1358 {
1359 int i, count, done;
1360 module_t *mod;
1361 struct sysevent_client *scp;
1362
1363 /*
1364 * unload modules that are ready, skip those that have not
1365 * drained their event queues.
1366 */
1367 count = done = 0;
1368 while (done < MAX_SLM) {
1369 /* Don't wait indefinitely for unresponsive clients */
1370 if (sig != SIGHUP && count > SE_TIMEOUT) {
1371 break;
1372 }
1373
1374 done = 0;
1375
1376 /* Shutdown clients */
1377 for (i = 0; i < MAX_SLM; ++i) {
1378 scp = sysevent_client_tbl[i];
1379 if (mutex_trylock(&scp->client_lock) == 0) {
1380 if (scp->client_type != SLM_CLIENT ||
1381 scp->client_data == NULL) {
1382 (void) mutex_unlock(&scp->client_lock);
1383 done++;
1384 continue;
1385 }
1386 } else {
1387 syseventd_print(3, "Skipping unload of "
1388 "client %d: client locked\n",
1389 scp->client_num);
1390 continue;
1391 }
1392
1393 /*
1394 * Drain the eventq and wait for delivery thread to
1395 * cleanly exit
1396 */
1397 drain_eventq(scp, EAGAIN);
1398 (void) cond_signal(&scp->client_cv);
1399 (void) mutex_unlock(&scp->client_lock);
1400 (void) thr_join(scp->tid, NULL, NULL);
1401
1402 /*
1403 * It is now safe to unload the module
1404 */
1405 mod = (module_t *)scp->client_data;
1406 syseventd_print(2, "Unload %s\n", mod->name);
1407 mod->event_mod_fini();
1408 (void) dlclose(mod->dlhandle);
1409 free(mod->name);
1410 (void) mutex_lock(&client_tbl_lock);
1411 delete_client(i);
1412 (void) mutex_unlock(&client_tbl_lock);
1413 ++done;
1414
1415 }
1416 ++count;
1417 (void) sleep(1);
1418 }
1419
1420 /*
1421 * Wait for event completions
1422 */
1423 syseventd_print(2, "waiting for event completions\n");
1424 (void) mutex_lock(&ev_comp_lock);
1425 while (event_compq != NULL) {
1426 (void) cond_wait(&event_comp_cv, &ev_comp_lock);
1427 }
1428 (void) mutex_unlock(&ev_comp_lock);
1429 }
1430
1431 /*
1432 * syseventd_init - Called at daemon (re)start-up time to load modules
1433 * and kickstart the kernel delivery engine.
1434 */
1435 static void
syseventd_init()1436 syseventd_init()
1437 {
1438 int i, fd;
1439 char local_door_file[PATH_MAX + 1];
1440
1441 fini_pending = 0;
1442
1443 concurrency_level = MIN_CONCURRENCY_LEVEL;
1444 (void) thr_setconcurrency(concurrency_level);
1445
1446 /*
1447 * Load client modules for event delivering
1448 */
1449 for (i = 0; i < MOD_DIR_NUM; ++i) {
1450 load_modules(dir_num2name(i));
1451 }
1452
1453 /*
1454 * Create kernel delivery door service
1455 */
1456 syseventd_print(8, "Create a door for kernel upcalls\n");
1457 if (snprintf(local_door_file, sizeof (local_door_file), "%s%s",
1458 root_dir, LOGEVENT_DOOR_UPCALL) >= sizeof (local_door_file)) {
1459 syseventd_err_print(INIT_PATH_ERR, local_door_file);
1460 syseventd_exit(5);
1461 }
1462
1463 /*
1464 * Remove door file for robustness.
1465 */
1466 if (unlink(local_door_file) != 0)
1467 syseventd_print(8, "Unlink of %s failed.\n", local_door_file);
1468
1469 fd = open(local_door_file, O_CREAT|O_RDWR, S_IREAD|S_IWRITE);
1470 if ((fd == -1) && (errno != EEXIST)) {
1471 syseventd_err_print(INIT_OPEN_DOOR_ERR, strerror(errno));
1472 syseventd_exit(5);
1473 }
1474 (void) close(fd);
1475
1476 upcall_door = door_create(door_upcall, NULL,
1477 DOOR_REFUSE_DESC | DOOR_NO_CANCEL);
1478 if (upcall_door == -1) {
1479 syseventd_err_print(INIT_CREATE_DOOR_ERR, strerror(errno));
1480 syseventd_exit(5);
1481 }
1482
1483 (void) fdetach(local_door_file);
1484 retry:
1485 if (fattach(upcall_door, local_door_file) != 0) {
1486 if (errno == EBUSY)
1487 goto retry;
1488 syseventd_err_print(INIT_FATTACH_ERR, strerror(errno));
1489 (void) door_revoke(upcall_door);
1490 syseventd_exit(5);
1491 }
1492
1493 /*
1494 * Tell kernel the door name and start delivery
1495 */
1496 syseventd_print(2,
1497 "local_door_file = %s\n", local_door_file);
1498 if (modctl(MODEVENTS,
1499 (uintptr_t)MODEVENTS_SET_DOOR_UPCALL_FILENAME,
1500 (uintptr_t)local_door_file, NULL, NULL, 0) < 0) {
1501 syseventd_err_print(INIT_DOOR_NAME_ERR, strerror(errno));
1502 syseventd_exit(6);
1503 }
1504
1505 door_upcall_retval = 0;
1506
1507 if (modctl(MODEVENTS, (uintptr_t)MODEVENTS_FLUSH, NULL, NULL, NULL, 0)
1508 < 0) {
1509 syseventd_err_print(KERNEL_REPLAY_ERR, strerror(errno));
1510 syseventd_exit(7);
1511 }
1512 }
1513
1514 /*
1515 * syseventd_fini - shut down daemon, but do not exit
1516 */
1517 static void
syseventd_fini(int sig)1518 syseventd_fini(int sig)
1519 {
1520 /*
1521 * Indicate that event queues should be drained and no
1522 * additional events be accepted
1523 */
1524 fini_pending = 1;
1525
1526 /* Close the kernel event door to halt delivery */
1527 (void) door_revoke(upcall_door);
1528
1529 syseventd_print(1, "Unloading modules\n");
1530 (void) rw_wrlock(&mod_unload_lock);
1531 unload_modules(sig);
1532 (void) rw_unlock(&mod_unload_lock);
1533
1534 }
1535
1536 /*
1537 * enter_daemon_lock - lock the daemon file lock
1538 *
1539 * Use an advisory lock to ensure that only one daemon process is active
1540 * in the system at any point in time. If the lock is held by another
1541 * process, do not block but return the pid owner of the lock to the
1542 * caller immediately. The lock is cleared if the holding daemon process
1543 * exits for any reason even if the lock file remains, so the daemon can
1544 * be restarted if necessary. The lock file is DAEMON_LOCK_FILE.
1545 */
1546 static pid_t
enter_daemon_lock(void)1547 enter_daemon_lock(void)
1548 {
1549 struct flock lock;
1550
1551 syseventd_print(8, "enter_daemon_lock: lock file = %s\n",
1552 DAEMON_LOCK_FILE);
1553
1554 if (snprintf(local_lock_file, sizeof (local_lock_file), "%s%s",
1555 root_dir, DAEMON_LOCK_FILE) >= sizeof (local_lock_file)) {
1556 syseventd_err_print(INIT_PATH_ERR, local_lock_file);
1557 syseventd_exit(8);
1558 }
1559 daemon_lock_fd = open(local_lock_file, O_CREAT|O_RDWR, 0644);
1560 if (daemon_lock_fd < 0) {
1561 syseventd_err_print(INIT_LOCK_OPEN_ERR,
1562 local_lock_file, strerror(errno));
1563 syseventd_exit(8);
1564 }
1565
1566 lock.l_type = F_WRLCK;
1567 lock.l_whence = SEEK_SET;
1568 lock.l_start = 0;
1569 lock.l_len = 0;
1570
1571 if (fcntl(daemon_lock_fd, F_SETLK, &lock) == -1) {
1572 if (fcntl(daemon_lock_fd, F_GETLK, &lock) == -1) {
1573 syseventd_err_print(INIT_LOCK_ERR,
1574 local_lock_file, strerror(errno));
1575 exit(2);
1576 }
1577 return (lock.l_pid);
1578 }
1579 hold_daemon_lock = 1;
1580
1581 return (getpid());
1582 }
1583
1584 /*
1585 * exit_daemon_lock - release the daemon file lock
1586 */
1587 static void
exit_daemon_lock(void)1588 exit_daemon_lock(void)
1589 {
1590 struct flock lock;
1591
1592 lock.l_type = F_UNLCK;
1593 lock.l_whence = SEEK_SET;
1594 lock.l_start = 0;
1595 lock.l_len = 0;
1596
1597 if (fcntl(daemon_lock_fd, F_SETLK, &lock) == -1) {
1598 syseventd_err_print(INIT_UNLOCK_ERR,
1599 local_lock_file, strerror(errno));
1600 }
1601
1602 if (close(daemon_lock_fd) == -1) {
1603 syseventd_err_print(INIT_LOCK_CLOSE_ERR,
1604 local_lock_file, strerror(errno));
1605 exit(-1);
1606 }
1607 }
1608
1609 /*
1610 * syseventd_err_print - print error messages to the terminal if not
1611 * yet daemonized or to syslog.
1612 */
1613 /*PRINTFLIKE1*/
1614 void
syseventd_err_print(char * message,...)1615 syseventd_err_print(char *message, ...)
1616 {
1617 va_list ap;
1618
1619 (void) mutex_lock(&err_mutex);
1620 va_start(ap, message);
1621
1622 if (logflag) {
1623 (void) vsyslog(LOG_ERR, message, ap);
1624 } else {
1625 (void) fprintf(stderr, "%s: ", prog);
1626 (void) vfprintf(stderr, message, ap);
1627 }
1628 va_end(ap);
1629 (void) mutex_unlock(&err_mutex);
1630 }
1631
1632 /*
1633 * syseventd_print - print messages to the terminal or to syslog
1634 * the following levels are implemented:
1635 *
1636 * 1 - transient errors that does not affect normal program flow
1637 * 2 - upcall/dispatch interaction
1638 * 3 - program flow trace as each message goes through the daemon
1639 * 8 - all the nit-gritty details of startup and shutdown
1640 * 9 - very verbose event flow tracing (no daemonization of syseventd)
1641 *
1642 */
1643 /*PRINTFLIKE2*/
1644 void
syseventd_print(int level,char * message,...)1645 syseventd_print(int level, char *message, ...)
1646 {
1647 va_list ap;
1648 static int newline = 1;
1649
1650 if (level > debug_level) {
1651 return;
1652 }
1653
1654 (void) mutex_lock(&err_mutex);
1655 va_start(ap, message);
1656 if (logflag) {
1657 (void) syslog(LOG_DEBUG, "%s[%ld]: ",
1658 prog, getpid());
1659 (void) vsyslog(LOG_DEBUG, message, ap);
1660 } else {
1661 if (newline) {
1662 (void) fprintf(stdout, "%s[%ld]: ",
1663 prog, getpid());
1664 (void) vfprintf(stdout, message, ap);
1665 } else {
1666 (void) vfprintf(stdout, message, ap);
1667 }
1668 }
1669 if (message[strlen(message)-1] == '\n') {
1670 newline = 1;
1671 } else {
1672 newline = 0;
1673 }
1674 va_end(ap);
1675 (void) mutex_unlock(&err_mutex);
1676 }
1677