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 5bc9ec910Snakanon * Common Development and Distribution License (the "License"). 6bc9ec910Snakanon * You may not use this file except in compliance with the License. 77c478bd9Sstevel@tonic-gate * 87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 117c478bd9Sstevel@tonic-gate * and limitations under the License. 127c478bd9Sstevel@tonic-gate * 137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 187c478bd9Sstevel@tonic-gate * 197c478bd9Sstevel@tonic-gate * CDDL HEADER END 207c478bd9Sstevel@tonic-gate */ 217c478bd9Sstevel@tonic-gate /* 22c6fc6dddSEric Schrock * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 237c478bd9Sstevel@tonic-gate * Use is subject to license terms. 247c478bd9Sstevel@tonic-gate */ 257c478bd9Sstevel@tonic-gate 267c478bd9Sstevel@tonic-gate /* 277c478bd9Sstevel@tonic-gate * sysevent_conf_mod - syseventd daemon sysevent.conf module 287c478bd9Sstevel@tonic-gate * 297c478bd9Sstevel@tonic-gate * This module provides a configuration file registration 307c478bd9Sstevel@tonic-gate * mechanism whereby event producers can define an event 317c478bd9Sstevel@tonic-gate * specification to be matched against events, with an 327c478bd9Sstevel@tonic-gate * associated command line to be invoked for each matching event. 337c478bd9Sstevel@tonic-gate * It includes a simple macro capability for flexibility in 347c478bd9Sstevel@tonic-gate * generating arbitrary command line formats from event-associated 357c478bd9Sstevel@tonic-gate * data, and a user specification so that commands can be invoked 367c478bd9Sstevel@tonic-gate * with reduced privileges to eliminate a security risk. 377c478bd9Sstevel@tonic-gate * 387c478bd9Sstevel@tonic-gate * sysevent.conf files contain event specifications and associated 397c478bd9Sstevel@tonic-gate * command path and optional arguments. System events received 407c478bd9Sstevel@tonic-gate * from the kernel by the sysevent daemon, syseventd, are 417c478bd9Sstevel@tonic-gate * compared against the event specifications in the sysevent.conf 427c478bd9Sstevel@tonic-gate * files. The command as specified by pathname and arguments 437c478bd9Sstevel@tonic-gate * is invoked for each matching event. 447c478bd9Sstevel@tonic-gate * 457c478bd9Sstevel@tonic-gate * All sysevent.conf files reside in /etc/sysevent/config. 467c478bd9Sstevel@tonic-gate * 477c478bd9Sstevel@tonic-gate */ 487c478bd9Sstevel@tonic-gate 497c478bd9Sstevel@tonic-gate 507c478bd9Sstevel@tonic-gate #include <stdio.h> 517c478bd9Sstevel@tonic-gate 527c478bd9Sstevel@tonic-gate #include <unistd.h> 537c478bd9Sstevel@tonic-gate #include <stdarg.h> 547c478bd9Sstevel@tonic-gate #include <stdlib.h> 557c478bd9Sstevel@tonic-gate #include <string.h> 567c478bd9Sstevel@tonic-gate #include <strings.h> 577c478bd9Sstevel@tonic-gate #include <limits.h> 587c478bd9Sstevel@tonic-gate #include <thread.h> 597c478bd9Sstevel@tonic-gate #include <synch.h> 607c478bd9Sstevel@tonic-gate #include <errno.h> 617c478bd9Sstevel@tonic-gate #include <fcntl.h> 627c478bd9Sstevel@tonic-gate #include <ctype.h> 637c478bd9Sstevel@tonic-gate #include <pwd.h> 647c478bd9Sstevel@tonic-gate #include <syslog.h> 657c478bd9Sstevel@tonic-gate #include <sys/types.h> 667c478bd9Sstevel@tonic-gate #include <sys/stat.h> 677c478bd9Sstevel@tonic-gate #include <sys/sunddi.h> 687c478bd9Sstevel@tonic-gate #include <sys/sysevent.h> 697c478bd9Sstevel@tonic-gate #include <libsysevent.h> 707c478bd9Sstevel@tonic-gate #include <libnvpair.h> 717c478bd9Sstevel@tonic-gate #include <dirent.h> 727c478bd9Sstevel@tonic-gate #include <locale.h> 737c478bd9Sstevel@tonic-gate #include <signal.h> 747c478bd9Sstevel@tonic-gate #include <wait.h> 757c478bd9Sstevel@tonic-gate 767c478bd9Sstevel@tonic-gate #include "syseventd.h" 777c478bd9Sstevel@tonic-gate #include "syseventconfd_door.h" 787c478bd9Sstevel@tonic-gate #include "sysevent_conf_mod.h" 797c478bd9Sstevel@tonic-gate #include "message_conf_mod.h" 807c478bd9Sstevel@tonic-gate 817c478bd9Sstevel@tonic-gate 827c478bd9Sstevel@tonic-gate static char *whoami = "sysevent_conf_mod"; 837c478bd9Sstevel@tonic-gate 847c478bd9Sstevel@tonic-gate /* 857c478bd9Sstevel@tonic-gate * Event sequencing, time stamp and retry count 867c478bd9Sstevel@tonic-gate */ 877c478bd9Sstevel@tonic-gate static int ev_nretries; /* retry count per event */ 887c478bd9Sstevel@tonic-gate static uint64_t ev_seq; /* current event sequencing number */ 897c478bd9Sstevel@tonic-gate static hrtime_t ev_ts; /* current event timestamp */ 907c478bd9Sstevel@tonic-gate static int first_event; /* first event since init */ 917c478bd9Sstevel@tonic-gate 927c478bd9Sstevel@tonic-gate /* 937c478bd9Sstevel@tonic-gate * State of the sysevent conf table, derived from 947c478bd9Sstevel@tonic-gate * the /etc/sysevent/config files 957c478bd9Sstevel@tonic-gate */ 967c478bd9Sstevel@tonic-gate static conftab_t *conftab = NULL; 977c478bd9Sstevel@tonic-gate static syseventtab_t *syseventtab = NULL; 987c478bd9Sstevel@tonic-gate static syseventtab_t *syseventtab_tail = NULL; 99*c7cb3c8bSToomas Soome static sysevent_handle_t *confd_handle = NULL; 1007c478bd9Sstevel@tonic-gate 1017c478bd9Sstevel@tonic-gate /* 1027c478bd9Sstevel@tonic-gate * The cmd queue is a queue of commands ready to be sent 1037c478bd9Sstevel@tonic-gate * to syseventconfd. Each command consists of the path 1047c478bd9Sstevel@tonic-gate * and arguments to be fork/exec'ed. The daemon is unable 1057c478bd9Sstevel@tonic-gate * to handle events during an active fork/exec and returns 1067c478bd9Sstevel@tonic-gate * EAGAIN as a result. It is grossly inefficient to bounce 1077c478bd9Sstevel@tonic-gate * these events back to syseventd, so we queue them here for delivery. 1087c478bd9Sstevel@tonic-gate */ 1097c478bd9Sstevel@tonic-gate static cmdqueue_t *cmdq = NULL; 1107c478bd9Sstevel@tonic-gate static cmdqueue_t *cmdq_tail = NULL; 1117c478bd9Sstevel@tonic-gate static mutex_t cmdq_lock; 1127c478bd9Sstevel@tonic-gate static cond_t cmdq_cv; 1137c478bd9Sstevel@tonic-gate static int cmdq_cnt; 1147c478bd9Sstevel@tonic-gate static thread_t cmdq_thr_id; 1157c478bd9Sstevel@tonic-gate static cond_t cmdq_thr_cv; 1167c478bd9Sstevel@tonic-gate static int want_fini; 1177c478bd9Sstevel@tonic-gate 1187c478bd9Sstevel@tonic-gate /* 1197c478bd9Sstevel@tonic-gate * State of the door channel to syseventconfd 1207c478bd9Sstevel@tonic-gate */ 1217c478bd9Sstevel@tonic-gate static int confd_state = CONFD_STATE_NOT_RUNNING; 1227c478bd9Sstevel@tonic-gate 1237c478bd9Sstevel@tonic-gate /* 1247c478bd9Sstevel@tonic-gate * Number of times to retry event after restarting syeventconfd 1257c478bd9Sstevel@tonic-gate */ 1267c478bd9Sstevel@tonic-gate static int confd_retries; 1277c478bd9Sstevel@tonic-gate 1287c478bd9Sstevel@tonic-gate /* 1297c478bd9Sstevel@tonic-gate * Number of times to retry a failed transport 1307c478bd9Sstevel@tonic-gate */ 1317c478bd9Sstevel@tonic-gate static int transport_retries; 1327c478bd9Sstevel@tonic-gate 1337c478bd9Sstevel@tonic-gate /* 1347c478bd9Sstevel@tonic-gate * Normal sleep time when syseventconfd returns EAGAIN 1357c478bd9Sstevel@tonic-gate * is one second but to avoid thrashing, sleep for 1367c478bd9Sstevel@tonic-gate * something larger when syseventconfd not responding. 1377c478bd9Sstevel@tonic-gate * This should never happen of course but it seems better 1387c478bd9Sstevel@tonic-gate * to attempt to handle possible errors gracefully. 1397c478bd9Sstevel@tonic-gate */ 1407c478bd9Sstevel@tonic-gate static int confd_err_msg_emitted; 1417c478bd9Sstevel@tonic-gate 1427c478bd9Sstevel@tonic-gate 1437c478bd9Sstevel@tonic-gate static int sysevent_conf_dummy_event(sysevent_t *, int); 1447c478bd9Sstevel@tonic-gate 1457c478bd9Sstevel@tonic-gate /* 1467c478bd9Sstevel@tonic-gate * External references 1477c478bd9Sstevel@tonic-gate */ 1487c478bd9Sstevel@tonic-gate extern int debug_level; 1497c478bd9Sstevel@tonic-gate extern char *root_dir; 1507c478bd9Sstevel@tonic-gate extern void syseventd_print(int level, char *format, ...); 1517c478bd9Sstevel@tonic-gate extern void syseventd_err_print(char *format, ...); 1527c478bd9Sstevel@tonic-gate 1537c478bd9Sstevel@tonic-gate 1547c478bd9Sstevel@tonic-gate 1557c478bd9Sstevel@tonic-gate static struct slm_mod_ops sysevent_conf_mod_ops = { 1567c478bd9Sstevel@tonic-gate SE_MAJOR_VERSION, /* syseventd module major version */ 1577c478bd9Sstevel@tonic-gate SE_MINOR_VERSION, /* syseventd module minor version */ 1587c478bd9Sstevel@tonic-gate SE_MAX_RETRY_LIMIT, /* max retry if EAGAIN */ 1597c478bd9Sstevel@tonic-gate &sysevent_conf_event /* event handler */ 1607c478bd9Sstevel@tonic-gate }; 1617c478bd9Sstevel@tonic-gate 1627c478bd9Sstevel@tonic-gate static struct slm_mod_ops sysevent_conf_dummy_mod_ops = { 1637c478bd9Sstevel@tonic-gate SE_MAJOR_VERSION, /* syseventd module major version */ 1647c478bd9Sstevel@tonic-gate SE_MINOR_VERSION, /* syseventd module minor version */ 1657c478bd9Sstevel@tonic-gate 0, /* no retries, always succeeds */ 1667c478bd9Sstevel@tonic-gate &sysevent_conf_dummy_event /* dummy event handler */ 1677c478bd9Sstevel@tonic-gate }; 1687c478bd9Sstevel@tonic-gate 1697c478bd9Sstevel@tonic-gate 1707c478bd9Sstevel@tonic-gate 1717c478bd9Sstevel@tonic-gate /* 1727c478bd9Sstevel@tonic-gate * skip_spaces() - skip to next non-space character 1737c478bd9Sstevel@tonic-gate */ 1747c478bd9Sstevel@tonic-gate static char * 1757c478bd9Sstevel@tonic-gate skip_spaces(char **cpp) 1767c478bd9Sstevel@tonic-gate { 1777c478bd9Sstevel@tonic-gate char *cp = *cpp; 1787c478bd9Sstevel@tonic-gate 1797c478bd9Sstevel@tonic-gate while (*cp == ' ' || *cp == '\t') 1807c478bd9Sstevel@tonic-gate cp++; 1817c478bd9Sstevel@tonic-gate if (*cp == 0) { 1827c478bd9Sstevel@tonic-gate *cpp = 0; 1837c478bd9Sstevel@tonic-gate return (NULL); 1847c478bd9Sstevel@tonic-gate } 1857c478bd9Sstevel@tonic-gate return (cp); 1867c478bd9Sstevel@tonic-gate } 1877c478bd9Sstevel@tonic-gate 1887c478bd9Sstevel@tonic-gate 1897c478bd9Sstevel@tonic-gate /* 1907c478bd9Sstevel@tonic-gate * Get next white-space separated field. 1917c478bd9Sstevel@tonic-gate * next_field() will not check any characters on next line. 1927c478bd9Sstevel@tonic-gate * Each entry is composed of a single line. 1937c478bd9Sstevel@tonic-gate */ 1947c478bd9Sstevel@tonic-gate static char * 1957c478bd9Sstevel@tonic-gate next_field(char **cpp) 1967c478bd9Sstevel@tonic-gate { 1977c478bd9Sstevel@tonic-gate char *cp = *cpp; 1987c478bd9Sstevel@tonic-gate char *start; 1997c478bd9Sstevel@tonic-gate 2007c478bd9Sstevel@tonic-gate while (*cp == ' ' || *cp == '\t') 2017c478bd9Sstevel@tonic-gate cp++; 2027c478bd9Sstevel@tonic-gate if (*cp == 0) { 2037c478bd9Sstevel@tonic-gate *cpp = 0; 2047c478bd9Sstevel@tonic-gate return (NULL); 2057c478bd9Sstevel@tonic-gate } 2067c478bd9Sstevel@tonic-gate start = cp; 2077c478bd9Sstevel@tonic-gate while (*cp && *cp != ' ' && *cp != '\t') 2087c478bd9Sstevel@tonic-gate cp++; 2097c478bd9Sstevel@tonic-gate if (*cp != 0) 2107c478bd9Sstevel@tonic-gate *cp++ = 0; 2117c478bd9Sstevel@tonic-gate *cpp = cp; 2127c478bd9Sstevel@tonic-gate return (start); 2137c478bd9Sstevel@tonic-gate } 2147c478bd9Sstevel@tonic-gate 2157c478bd9Sstevel@tonic-gate 2167c478bd9Sstevel@tonic-gate 2177c478bd9Sstevel@tonic-gate /* 2187c478bd9Sstevel@tonic-gate * The following functions are simple wrappers/equivalents 2197c478bd9Sstevel@tonic-gate * for malloc, realloc, free, strdup and a special free 2207c478bd9Sstevel@tonic-gate * for strdup. 2217c478bd9Sstevel@tonic-gate * 2227c478bd9Sstevel@tonic-gate * These functions ensure that any failed mallocs are 2237c478bd9Sstevel@tonic-gate * reported via syslog() so if a command is not evoked 2247c478bd9Sstevel@tonic-gate * in response to an event, the reason should be logged. 2257c478bd9Sstevel@tonic-gate * These functions also provide a convenient place for 2267c478bd9Sstevel@tonic-gate * hooks for checking for memory leaks. 2277c478bd9Sstevel@tonic-gate */ 2287c478bd9Sstevel@tonic-gate 2297c478bd9Sstevel@tonic-gate static void * 2307c478bd9Sstevel@tonic-gate sc_malloc(size_t n) 2317c478bd9Sstevel@tonic-gate { 2327c478bd9Sstevel@tonic-gate void *p; 2337c478bd9Sstevel@tonic-gate 2347c478bd9Sstevel@tonic-gate p = malloc(n); 2357c478bd9Sstevel@tonic-gate if (p == NULL) { 2367c478bd9Sstevel@tonic-gate syslog(LOG_ERR, OUT_OF_MEMORY_ERR); 2377c478bd9Sstevel@tonic-gate } 2387c478bd9Sstevel@tonic-gate return (p); 2397c478bd9Sstevel@tonic-gate } 2407c478bd9Sstevel@tonic-gate 2417c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 2427c478bd9Sstevel@tonic-gate static void * 2437c478bd9Sstevel@tonic-gate sc_realloc(void *p, size_t current, size_t n) 2447c478bd9Sstevel@tonic-gate { 2457c478bd9Sstevel@tonic-gate p = realloc(p, n); 2467c478bd9Sstevel@tonic-gate if (p == NULL) { 2477c478bd9Sstevel@tonic-gate syslog(LOG_ERR, OUT_OF_MEMORY_ERR); 2487c478bd9Sstevel@tonic-gate } 2497c478bd9Sstevel@tonic-gate return (p); 2507c478bd9Sstevel@tonic-gate } 2517c478bd9Sstevel@tonic-gate 2527c478bd9Sstevel@tonic-gate 2537c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 2547c478bd9Sstevel@tonic-gate static void 2557c478bd9Sstevel@tonic-gate sc_free(void *p, size_t n) 2567c478bd9Sstevel@tonic-gate { 2577c478bd9Sstevel@tonic-gate free(p); 2587c478bd9Sstevel@tonic-gate } 2597c478bd9Sstevel@tonic-gate 2607c478bd9Sstevel@tonic-gate 2617c478bd9Sstevel@tonic-gate static char * 2627c478bd9Sstevel@tonic-gate sc_strdup(char *cp) 2637c478bd9Sstevel@tonic-gate { 2647c478bd9Sstevel@tonic-gate char *new; 2657c478bd9Sstevel@tonic-gate 2667c478bd9Sstevel@tonic-gate new = malloc((unsigned)(strlen(cp) + 1)); 2677c478bd9Sstevel@tonic-gate if (new == NULL) { 2687c478bd9Sstevel@tonic-gate syslog(LOG_ERR, OUT_OF_MEMORY_ERR); 2697c478bd9Sstevel@tonic-gate return (NULL); 2707c478bd9Sstevel@tonic-gate } 2717c478bd9Sstevel@tonic-gate (void) strcpy(new, cp); 2727c478bd9Sstevel@tonic-gate return (new); 2737c478bd9Sstevel@tonic-gate } 2747c478bd9Sstevel@tonic-gate 2757c478bd9Sstevel@tonic-gate 2767c478bd9Sstevel@tonic-gate static void 2777c478bd9Sstevel@tonic-gate sc_strfree(char *s) 2787c478bd9Sstevel@tonic-gate { 2797c478bd9Sstevel@tonic-gate if (s) 2807c478bd9Sstevel@tonic-gate free(s); 2817c478bd9Sstevel@tonic-gate } 2827c478bd9Sstevel@tonic-gate 2837c478bd9Sstevel@tonic-gate 2847c478bd9Sstevel@tonic-gate /* 2857c478bd9Sstevel@tonic-gate * The following functions provide some simple dynamic string 2867c478bd9Sstevel@tonic-gate * capability. This module has no hard-coded maximum string 2877c478bd9Sstevel@tonic-gate * lengths and should be able to parse and generate arbitrarily 2887c478bd9Sstevel@tonic-gate * long strings, macro expansion and command lines. 2897c478bd9Sstevel@tonic-gate * 2907c478bd9Sstevel@tonic-gate * Each string must be explicitly allocated and freed. 2917c478bd9Sstevel@tonic-gate */ 2927c478bd9Sstevel@tonic-gate 2937c478bd9Sstevel@tonic-gate /* 2947c478bd9Sstevel@tonic-gate * Allocate a dynamic string, with a hint to indicate how 2957c478bd9Sstevel@tonic-gate * much memory to dynamically add to the string as it grows 2967c478bd9Sstevel@tonic-gate * beyond its existing bounds, so as to avoid excessive 2977c478bd9Sstevel@tonic-gate * reallocs as a string grows. 2987c478bd9Sstevel@tonic-gate */ 2997c478bd9Sstevel@tonic-gate static str_t * 3007c478bd9Sstevel@tonic-gate initstr(int hint) 3017c478bd9Sstevel@tonic-gate { 3027c478bd9Sstevel@tonic-gate str_t *str; 3037c478bd9Sstevel@tonic-gate 3047c478bd9Sstevel@tonic-gate if ((str = sc_malloc(sizeof (str_t))) == NULL) 3057c478bd9Sstevel@tonic-gate return (NULL); 3067c478bd9Sstevel@tonic-gate str->s_str = NULL; 3077c478bd9Sstevel@tonic-gate str->s_len = 0; 3087c478bd9Sstevel@tonic-gate str->s_alloc = 0; 3097c478bd9Sstevel@tonic-gate str->s_hint = hint; 3107c478bd9Sstevel@tonic-gate return (str); 3117c478bd9Sstevel@tonic-gate } 3127c478bd9Sstevel@tonic-gate 3137c478bd9Sstevel@tonic-gate 3147c478bd9Sstevel@tonic-gate /* 3157c478bd9Sstevel@tonic-gate * Free a dynamically-allocated string 3167c478bd9Sstevel@tonic-gate */ 3177c478bd9Sstevel@tonic-gate static void 3187c478bd9Sstevel@tonic-gate freestr(str_t *str) 3197c478bd9Sstevel@tonic-gate { 3207c478bd9Sstevel@tonic-gate if (str->s_str) { 3217c478bd9Sstevel@tonic-gate sc_free(str->s_str, str->s_alloc); 3227c478bd9Sstevel@tonic-gate } 3237c478bd9Sstevel@tonic-gate sc_free(str, sizeof (str_t)); 3247c478bd9Sstevel@tonic-gate } 3257c478bd9Sstevel@tonic-gate 3267c478bd9Sstevel@tonic-gate 3277c478bd9Sstevel@tonic-gate /* 3287c478bd9Sstevel@tonic-gate * Reset a dynamically-allocated string, allows reuse 3297c478bd9Sstevel@tonic-gate * rather than freeing the old and allocating a new one. 3307c478bd9Sstevel@tonic-gate */ 3317c478bd9Sstevel@tonic-gate static void 3327c478bd9Sstevel@tonic-gate resetstr(str_t *str) 3337c478bd9Sstevel@tonic-gate { 3347c478bd9Sstevel@tonic-gate str->s_len = 0; 3357c478bd9Sstevel@tonic-gate } 3367c478bd9Sstevel@tonic-gate 3377c478bd9Sstevel@tonic-gate 3387c478bd9Sstevel@tonic-gate /* 3397c478bd9Sstevel@tonic-gate * Copy a (simple) string onto a dynamically-allocated string 3407c478bd9Sstevel@tonic-gate */ 3417c478bd9Sstevel@tonic-gate static int 3427c478bd9Sstevel@tonic-gate strcopys(str_t *str, char *s) 3437c478bd9Sstevel@tonic-gate { 3447c478bd9Sstevel@tonic-gate char *new_str; 3457c478bd9Sstevel@tonic-gate int len = strlen(s) + 1; 3467c478bd9Sstevel@tonic-gate 3477c478bd9Sstevel@tonic-gate if (str->s_alloc < len) { 3487c478bd9Sstevel@tonic-gate new_str = (str->s_str == NULL) ? 3497c478bd9Sstevel@tonic-gate sc_malloc(len+str->s_hint) : 3507c478bd9Sstevel@tonic-gate sc_realloc(str->s_str, str->s_alloc, len+str->s_hint); 3517c478bd9Sstevel@tonic-gate if (new_str == NULL) { 3527c478bd9Sstevel@tonic-gate return (1); 3537c478bd9Sstevel@tonic-gate } 3547c478bd9Sstevel@tonic-gate str->s_str = new_str; 3557c478bd9Sstevel@tonic-gate str->s_alloc = len + str->s_hint; 3567c478bd9Sstevel@tonic-gate } 3577c478bd9Sstevel@tonic-gate (void) strcpy(str->s_str, s); 3587c478bd9Sstevel@tonic-gate str->s_len = len - 1; 3597c478bd9Sstevel@tonic-gate return (0); 3607c478bd9Sstevel@tonic-gate } 3617c478bd9Sstevel@tonic-gate 3627c478bd9Sstevel@tonic-gate 3637c478bd9Sstevel@tonic-gate /* 3647c478bd9Sstevel@tonic-gate * Concatenate a (simple) string onto a dynamically-allocated string 3657c478bd9Sstevel@tonic-gate */ 3667c478bd9Sstevel@tonic-gate static int 3677c478bd9Sstevel@tonic-gate strcats(str_t *str, char *s) 3687c478bd9Sstevel@tonic-gate { 3697c478bd9Sstevel@tonic-gate char *new_str; 3707c478bd9Sstevel@tonic-gate int len = str->s_len + strlen(s) + 1; 3717c478bd9Sstevel@tonic-gate 3727c478bd9Sstevel@tonic-gate if (str->s_alloc < len) { 3737c478bd9Sstevel@tonic-gate new_str = (str->s_str == NULL) ? sc_malloc(len+str->s_hint) : 3747c478bd9Sstevel@tonic-gate sc_realloc(str->s_str, str->s_alloc, len+str->s_hint); 3757c478bd9Sstevel@tonic-gate if (new_str == NULL) { 3767c478bd9Sstevel@tonic-gate return (1); 3777c478bd9Sstevel@tonic-gate } 3787c478bd9Sstevel@tonic-gate str->s_str = new_str; 3797c478bd9Sstevel@tonic-gate str->s_alloc = len + str->s_hint; 3807c478bd9Sstevel@tonic-gate } 3817c478bd9Sstevel@tonic-gate (void) strcpy(str->s_str + str->s_len, s); 3827c478bd9Sstevel@tonic-gate str->s_len = len - 1; 3837c478bd9Sstevel@tonic-gate return (0); 3847c478bd9Sstevel@tonic-gate } 3857c478bd9Sstevel@tonic-gate 3867c478bd9Sstevel@tonic-gate 3877c478bd9Sstevel@tonic-gate /* 3887c478bd9Sstevel@tonic-gate * Concatenate a character onto a dynamically-allocated string 3897c478bd9Sstevel@tonic-gate */ 3907c478bd9Sstevel@tonic-gate static int 3917c478bd9Sstevel@tonic-gate strcatc(str_t *str, int c) 3927c478bd9Sstevel@tonic-gate { 3937c478bd9Sstevel@tonic-gate char *new_str; 3947c478bd9Sstevel@tonic-gate int len = str->s_len + 2; 3957c478bd9Sstevel@tonic-gate 3967c478bd9Sstevel@tonic-gate if (str->s_alloc < len) { 3977c478bd9Sstevel@tonic-gate new_str = (str->s_str == NULL) ? sc_malloc(len+str->s_hint) : 3987c478bd9Sstevel@tonic-gate sc_realloc(str->s_str, str->s_alloc, len+str->s_hint); 3997c478bd9Sstevel@tonic-gate if (new_str == NULL) { 4007c478bd9Sstevel@tonic-gate return (1); 4017c478bd9Sstevel@tonic-gate } 4027c478bd9Sstevel@tonic-gate str->s_str = new_str; 4037c478bd9Sstevel@tonic-gate str->s_alloc = len + str->s_hint; 4047c478bd9Sstevel@tonic-gate } 4057c478bd9Sstevel@tonic-gate *(str->s_str + str->s_len) = (char)c; 4067c478bd9Sstevel@tonic-gate *(str->s_str + str->s_len + 1) = 0; 4077c478bd9Sstevel@tonic-gate str->s_len++; 4087c478bd9Sstevel@tonic-gate return (0); 4097c478bd9Sstevel@tonic-gate } 4107c478bd9Sstevel@tonic-gate 4117c478bd9Sstevel@tonic-gate /* 4127c478bd9Sstevel@tonic-gate * fgets() equivalent using a dynamically-allocated string 4137c478bd9Sstevel@tonic-gate */ 4147c478bd9Sstevel@tonic-gate static char * 4157c478bd9Sstevel@tonic-gate fstrgets(str_t *line, FILE *fp) 4167c478bd9Sstevel@tonic-gate { 4177c478bd9Sstevel@tonic-gate int c; 4187c478bd9Sstevel@tonic-gate 4197c478bd9Sstevel@tonic-gate resetstr(line); 4207c478bd9Sstevel@tonic-gate while ((c = fgetc(fp)) != EOF) { 4217c478bd9Sstevel@tonic-gate if (strcatc(line, c)) 4227c478bd9Sstevel@tonic-gate return (NULL); 4237c478bd9Sstevel@tonic-gate if (c == '\n') 4247c478bd9Sstevel@tonic-gate break; 4257c478bd9Sstevel@tonic-gate } 4267c478bd9Sstevel@tonic-gate if (line->s_len == 0) 4277c478bd9Sstevel@tonic-gate return (NULL); 4287c478bd9Sstevel@tonic-gate return (line->s_str); 4297c478bd9Sstevel@tonic-gate } 4307c478bd9Sstevel@tonic-gate 4317c478bd9Sstevel@tonic-gate /* 4327c478bd9Sstevel@tonic-gate * Truncate a dynamically-allocated string at index position 'pos' 4337c478bd9Sstevel@tonic-gate */ 4347c478bd9Sstevel@tonic-gate static void 4357c478bd9Sstevel@tonic-gate strtrunc(str_t *str, int pos) 4367c478bd9Sstevel@tonic-gate { 4377c478bd9Sstevel@tonic-gate if (str->s_len > pos) { 4387c478bd9Sstevel@tonic-gate str->s_len = pos; 4397c478bd9Sstevel@tonic-gate *(str->s_str + pos) = 0; 4407c478bd9Sstevel@tonic-gate } 4417c478bd9Sstevel@tonic-gate } 4427c478bd9Sstevel@tonic-gate 4437c478bd9Sstevel@tonic-gate 4447c478bd9Sstevel@tonic-gate 4457c478bd9Sstevel@tonic-gate /* 4467c478bd9Sstevel@tonic-gate * Parse a sysevent.conf file, adding each entry spec to the event table. 4477c478bd9Sstevel@tonic-gate * 4487c478bd9Sstevel@tonic-gate * The format of an entry in a sysevent.conf file is: 4497c478bd9Sstevel@tonic-gate * 4507c478bd9Sstevel@tonic-gate * class subclass vendor publisher user reserved1 reserved path arguments 4517c478bd9Sstevel@tonic-gate * 4527c478bd9Sstevel@tonic-gate * Fields are separated by either SPACE or TAB characters. A 4537c478bd9Sstevel@tonic-gate * '#' (number sign) at the beginning of a line indicates a 4547c478bd9Sstevel@tonic-gate * comment. Comment lines and blank lines are ignored. 4557c478bd9Sstevel@tonic-gate * 4567c478bd9Sstevel@tonic-gate * class 4577c478bd9Sstevel@tonic-gate * The class of the event. 4587c478bd9Sstevel@tonic-gate * 4597c478bd9Sstevel@tonic-gate * subclass 4607c478bd9Sstevel@tonic-gate * The subclass of the event. 4617c478bd9Sstevel@tonic-gate * 4627c478bd9Sstevel@tonic-gate * vendor 4637c478bd9Sstevel@tonic-gate * The name of the vendor defining the event, usually the 4647c478bd9Sstevel@tonic-gate * stock symbol. Events generated by system components 4657c478bd9Sstevel@tonic-gate * provided by Sun Microsystems, Inc. always define vendor 4667c478bd9Sstevel@tonic-gate * as 'SUNW'. 4677c478bd9Sstevel@tonic-gate * 4687c478bd9Sstevel@tonic-gate * publisher 4697c478bd9Sstevel@tonic-gate * The name of the application, driver or system module 4707c478bd9Sstevel@tonic-gate * producing the event. 4717c478bd9Sstevel@tonic-gate * 4727c478bd9Sstevel@tonic-gate * user 4737c478bd9Sstevel@tonic-gate * The name of the user under which the command should be 4747c478bd9Sstevel@tonic-gate * run. This allows commands to run with access privileges 4757c478bd9Sstevel@tonic-gate * other than those for root. The user field should be '-' 4767c478bd9Sstevel@tonic-gate * for commands to be run as root. 4777c478bd9Sstevel@tonic-gate * 4787c478bd9Sstevel@tonic-gate * reserved1 4797c478bd9Sstevel@tonic-gate * Must be '-'. 4807c478bd9Sstevel@tonic-gate * 4817c478bd9Sstevel@tonic-gate * reserved2 4827c478bd9Sstevel@tonic-gate * Must be '-'. 4837c478bd9Sstevel@tonic-gate * 4847c478bd9Sstevel@tonic-gate * path 4857c478bd9Sstevel@tonic-gate * Pathname of the command to be invoked for matching events. 4867c478bd9Sstevel@tonic-gate * 4877c478bd9Sstevel@tonic-gate * arguments 4887c478bd9Sstevel@tonic-gate * Optional argument with possible macro substitution to permit 4897c478bd9Sstevel@tonic-gate * arbitrary command line construction with event-specific data. 4907c478bd9Sstevel@tonic-gate */ 4917c478bd9Sstevel@tonic-gate static void 4927c478bd9Sstevel@tonic-gate parse_conf_file(char *conf_file) 4937c478bd9Sstevel@tonic-gate { 4947c478bd9Sstevel@tonic-gate char conf_path[PATH_MAX]; 4957c478bd9Sstevel@tonic-gate FILE *fp; 4967c478bd9Sstevel@tonic-gate char *lp; 4977c478bd9Sstevel@tonic-gate str_t *line; 4987c478bd9Sstevel@tonic-gate int lineno = 0; 4997c478bd9Sstevel@tonic-gate char *vendor, *publisher; 5007c478bd9Sstevel@tonic-gate char *class, *subclass; 5017c478bd9Sstevel@tonic-gate char *user; 5027c478bd9Sstevel@tonic-gate char *reserved1, *reserved2; 5037c478bd9Sstevel@tonic-gate char *path, *args; 5047c478bd9Sstevel@tonic-gate syseventtab_t *sep; 5057c478bd9Sstevel@tonic-gate struct passwd pwd; 5067c478bd9Sstevel@tonic-gate struct passwd *pwdp; 5077c478bd9Sstevel@tonic-gate char pwdbuf[1024]; 5087c478bd9Sstevel@tonic-gate int do_setuid; 5097c478bd9Sstevel@tonic-gate pid_t saved_uid; 5107c478bd9Sstevel@tonic-gate gid_t saved_gid; 5117c478bd9Sstevel@tonic-gate int i, err; 5127c478bd9Sstevel@tonic-gate 5137c478bd9Sstevel@tonic-gate (void) snprintf(conf_path, PATH_MAX, "%s/%s", 5147c478bd9Sstevel@tonic-gate SYSEVENT_CONFIG_DIR, conf_file); 5157c478bd9Sstevel@tonic-gate 5167c478bd9Sstevel@tonic-gate syseventd_print(DBG_CONF_FILE, "%s: reading %s\n", whoami, conf_path); 5177c478bd9Sstevel@tonic-gate 5187c478bd9Sstevel@tonic-gate if ((fp = fopen(conf_path, "r")) == NULL) { 5197c478bd9Sstevel@tonic-gate syslog(LOG_ERR, CANNOT_OPEN_ERR, conf_file, strerror(errno)); 5207c478bd9Sstevel@tonic-gate return; 5217c478bd9Sstevel@tonic-gate } 5227c478bd9Sstevel@tonic-gate 5237c478bd9Sstevel@tonic-gate if ((line = initstr(128)) == NULL) 5247c478bd9Sstevel@tonic-gate return; 5257c478bd9Sstevel@tonic-gate 5267c478bd9Sstevel@tonic-gate while ((lp = fstrgets(line, fp)) != NULL) { 5277c478bd9Sstevel@tonic-gate lineno++; 5287c478bd9Sstevel@tonic-gate if (*lp == '\n' || *lp == '#') 5297c478bd9Sstevel@tonic-gate continue; 5307c478bd9Sstevel@tonic-gate *(lp + strlen(lp)-1) = 0; 5317c478bd9Sstevel@tonic-gate 5327c478bd9Sstevel@tonic-gate syseventd_print(DBG_CONF_FILE, "[%d]: %s\n", 5337c478bd9Sstevel@tonic-gate lineno, lp); 5347c478bd9Sstevel@tonic-gate 5353e11238aSjg if ((class = next_field(&lp)) == NULL) 5363e11238aSjg goto mal_formed; 5373e11238aSjg if ((subclass = next_field(&lp)) == NULL) 5383e11238aSjg goto mal_formed; 5393e11238aSjg if ((vendor = next_field(&lp)) == NULL) 5403e11238aSjg goto mal_formed; 5413e11238aSjg if ((publisher = next_field(&lp)) == NULL) 5423e11238aSjg goto mal_formed; 5433e11238aSjg if ((user = next_field(&lp)) == NULL) 5443e11238aSjg goto mal_formed; 5453e11238aSjg if ((reserved1 = next_field(&lp)) == NULL) 5463e11238aSjg goto mal_formed; 5473e11238aSjg if ((reserved2 = next_field(&lp)) == NULL) 5483e11238aSjg goto mal_formed; 5493e11238aSjg if ((path = next_field(&lp)) == NULL) 5503e11238aSjg goto mal_formed; 5513e11238aSjg args = skip_spaces(&lp); 5527c478bd9Sstevel@tonic-gate 5537c478bd9Sstevel@tonic-gate /* 5547c478bd9Sstevel@tonic-gate * validate user 5557c478bd9Sstevel@tonic-gate */ 5567c478bd9Sstevel@tonic-gate do_setuid = 0; 5577c478bd9Sstevel@tonic-gate if ((strcmp(user, "-") != 0) && (strcmp(user, "root") != 0)) { 5587c478bd9Sstevel@tonic-gate i = getpwnam_r(user, &pwd, pwdbuf, 5597c478bd9Sstevel@tonic-gate sizeof (pwdbuf), &pwdp); 5607c478bd9Sstevel@tonic-gate if (i != 0 || pwdp == NULL) { 5617c478bd9Sstevel@tonic-gate syslog(LOG_ERR, NO_USER_ERR, 5627c478bd9Sstevel@tonic-gate conf_file, lineno, user); 5637c478bd9Sstevel@tonic-gate continue; 5647c478bd9Sstevel@tonic-gate } 5657c478bd9Sstevel@tonic-gate do_setuid = 1; 5667c478bd9Sstevel@tonic-gate } 5677c478bd9Sstevel@tonic-gate 5687c478bd9Sstevel@tonic-gate /* 5697c478bd9Sstevel@tonic-gate * validate reserved fields 5707c478bd9Sstevel@tonic-gate */ 5717c478bd9Sstevel@tonic-gate if (strcmp(reserved1, "-") != 0) { 5727c478bd9Sstevel@tonic-gate syslog(LOG_ERR, RESERVED_FIELD_ERR, 5737c478bd9Sstevel@tonic-gate conf_file, lineno, reserved1); 5747c478bd9Sstevel@tonic-gate continue; 5757c478bd9Sstevel@tonic-gate } 5767c478bd9Sstevel@tonic-gate if (strcmp(reserved2, "-") != 0) { 5777c478bd9Sstevel@tonic-gate syslog(LOG_ERR, RESERVED_FIELD_ERR, 5787c478bd9Sstevel@tonic-gate conf_file, lineno, reserved2); 5797c478bd9Sstevel@tonic-gate continue; 5807c478bd9Sstevel@tonic-gate } 5817c478bd9Sstevel@tonic-gate 5827c478bd9Sstevel@tonic-gate /* 5837c478bd9Sstevel@tonic-gate * ensure path is executable by user 5847c478bd9Sstevel@tonic-gate */ 5857c478bd9Sstevel@tonic-gate err = 0; 5867c478bd9Sstevel@tonic-gate if (do_setuid) { 5877c478bd9Sstevel@tonic-gate saved_uid = getuid(); 5887c478bd9Sstevel@tonic-gate saved_gid = getgid(); 5897c478bd9Sstevel@tonic-gate if (setregid(pwdp->pw_gid, -1) == -1) { 5907c478bd9Sstevel@tonic-gate syslog(LOG_ERR, SETREGID_ERR, 5917c478bd9Sstevel@tonic-gate whoami, pwdp->pw_gid, strerror(errno)); 5927c478bd9Sstevel@tonic-gate err = -1; 5937c478bd9Sstevel@tonic-gate } 5947c478bd9Sstevel@tonic-gate if (setreuid(pwdp->pw_uid, -1) == -1) { 5957c478bd9Sstevel@tonic-gate syslog(LOG_ERR, SETREUID_ERR, 5967c478bd9Sstevel@tonic-gate whoami, pwdp->pw_uid, strerror(errno)); 5977c478bd9Sstevel@tonic-gate err = -1; 5987c478bd9Sstevel@tonic-gate } 5997c478bd9Sstevel@tonic-gate } 6007c478bd9Sstevel@tonic-gate if ((i = access(path, X_OK)) == -1) { 6017c478bd9Sstevel@tonic-gate syslog(LOG_ERR, CANNOT_EXECUTE_ERR, 6027c478bd9Sstevel@tonic-gate conf_file, lineno, path, strerror(errno)); 6037c478bd9Sstevel@tonic-gate } 6047c478bd9Sstevel@tonic-gate if (do_setuid) { 6057c478bd9Sstevel@tonic-gate if (setreuid(saved_uid, -1) == -1) { 6067c478bd9Sstevel@tonic-gate syslog(LOG_ERR, SETREUID_ERR, 6077c478bd9Sstevel@tonic-gate whoami, saved_uid, strerror(errno)); 6087c478bd9Sstevel@tonic-gate err = -1; 6097c478bd9Sstevel@tonic-gate } 6107c478bd9Sstevel@tonic-gate if (setregid(saved_gid, -1) == -1) { 6117c478bd9Sstevel@tonic-gate syslog(LOG_ERR, SETREGID_ERR, 6127c478bd9Sstevel@tonic-gate whoami, saved_gid, strerror(errno)); 6137c478bd9Sstevel@tonic-gate err = -1; 6147c478bd9Sstevel@tonic-gate } 6157c478bd9Sstevel@tonic-gate } 6167c478bd9Sstevel@tonic-gate if (i == -1 || err == -1) 6177c478bd9Sstevel@tonic-gate continue; 6187c478bd9Sstevel@tonic-gate 6197c478bd9Sstevel@tonic-gate /* 6207c478bd9Sstevel@tonic-gate * all sanity tests successful - perform allocations 6217c478bd9Sstevel@tonic-gate * to add entry to table 6227c478bd9Sstevel@tonic-gate */ 6237c478bd9Sstevel@tonic-gate if ((sep = sc_malloc(sizeof (syseventtab_t))) == NULL) 6247c478bd9Sstevel@tonic-gate break; 6257c478bd9Sstevel@tonic-gate 6267c478bd9Sstevel@tonic-gate sep->se_conf_file = conf_file; 6277c478bd9Sstevel@tonic-gate sep->se_lineno = lineno; 6287c478bd9Sstevel@tonic-gate sep->se_vendor = sc_strdup(vendor); 6297c478bd9Sstevel@tonic-gate sep->se_publisher = sc_strdup(publisher); 6307c478bd9Sstevel@tonic-gate sep->se_class = sc_strdup(class); 6317c478bd9Sstevel@tonic-gate sep->se_subclass = sc_strdup(subclass); 6327c478bd9Sstevel@tonic-gate sep->se_user = sc_strdup(user); 6337c478bd9Sstevel@tonic-gate if (do_setuid) { 6347c478bd9Sstevel@tonic-gate sep->se_uid = pwdp->pw_uid; 6357c478bd9Sstevel@tonic-gate sep->se_gid = pwdp->pw_gid; 6367c478bd9Sstevel@tonic-gate } else { 6377c478bd9Sstevel@tonic-gate sep->se_uid = 0; 6387c478bd9Sstevel@tonic-gate sep->se_gid = 0; 6397c478bd9Sstevel@tonic-gate } 6407c478bd9Sstevel@tonic-gate sep->se_reserved1 = sc_strdup(reserved1); 6417c478bd9Sstevel@tonic-gate sep->se_reserved2 = sc_strdup(reserved2); 6427c478bd9Sstevel@tonic-gate sep->se_path = sc_strdup(path); 6437c478bd9Sstevel@tonic-gate sep->se_args = (args == NULL) ? NULL : sc_strdup(args); 6447c478bd9Sstevel@tonic-gate sep->se_next = NULL; 6457c478bd9Sstevel@tonic-gate 6467c478bd9Sstevel@tonic-gate if (sep->se_vendor == NULL || sep->se_publisher == NULL || 6477c478bd9Sstevel@tonic-gate sep->se_class == NULL || sep->se_subclass == NULL || 6487c478bd9Sstevel@tonic-gate sep->se_user == NULL || sep->se_reserved1 == NULL || 6497c478bd9Sstevel@tonic-gate sep->se_reserved2 == NULL || sep->se_path == NULL || 6507c478bd9Sstevel@tonic-gate (args && sep->se_args == NULL)) { 6517c478bd9Sstevel@tonic-gate sc_strfree(sep->se_vendor); 6527c478bd9Sstevel@tonic-gate sc_strfree(sep->se_publisher); 6537c478bd9Sstevel@tonic-gate sc_strfree(sep->se_class); 6547c478bd9Sstevel@tonic-gate sc_strfree(sep->se_subclass); 6557c478bd9Sstevel@tonic-gate sc_strfree(sep->se_user); 6567c478bd9Sstevel@tonic-gate sc_strfree(sep->se_reserved1); 6577c478bd9Sstevel@tonic-gate sc_strfree(sep->se_reserved2); 6587c478bd9Sstevel@tonic-gate sc_strfree(sep->se_path); 6597c478bd9Sstevel@tonic-gate sc_strfree(sep->se_args); 6607c478bd9Sstevel@tonic-gate sc_free(sep, sizeof (syseventtab_t)); 6617c478bd9Sstevel@tonic-gate break; 6627c478bd9Sstevel@tonic-gate } 6637c478bd9Sstevel@tonic-gate 6647c478bd9Sstevel@tonic-gate /* 6657c478bd9Sstevel@tonic-gate * link new entry into the table 6667c478bd9Sstevel@tonic-gate */ 6677c478bd9Sstevel@tonic-gate if (syseventtab == NULL) { 6687c478bd9Sstevel@tonic-gate syseventtab = sep; 6697c478bd9Sstevel@tonic-gate syseventtab_tail = sep; 6707c478bd9Sstevel@tonic-gate } else { 6717c478bd9Sstevel@tonic-gate syseventtab_tail->se_next = sep; 6727c478bd9Sstevel@tonic-gate syseventtab_tail = sep; 6737c478bd9Sstevel@tonic-gate } 6747c478bd9Sstevel@tonic-gate 6757c478bd9Sstevel@tonic-gate if (debug_level >= DBG_DETAILED) { 6767c478bd9Sstevel@tonic-gate syseventtab_t *sp; 6777c478bd9Sstevel@tonic-gate for (sp = syseventtab; sp; sp = sp->se_next) { 6787c478bd9Sstevel@tonic-gate syseventd_print(DBG_DETAILED, 6797c478bd9Sstevel@tonic-gate " vendor=%s\n", sp->se_vendor); 6807c478bd9Sstevel@tonic-gate syseventd_print(DBG_DETAILED, 6817c478bd9Sstevel@tonic-gate " publisher=%s\n", sp->se_publisher); 6827c478bd9Sstevel@tonic-gate syseventd_print(DBG_DETAILED, 6837c478bd9Sstevel@tonic-gate " class=%s\n", sp->se_class); 6847c478bd9Sstevel@tonic-gate syseventd_print(DBG_DETAILED, 6857c478bd9Sstevel@tonic-gate " subclass=%s\n", sp->se_subclass); 6867c478bd9Sstevel@tonic-gate syseventd_print(DBG_DETAILED, 6877c478bd9Sstevel@tonic-gate " user=%s uid=%d gid=%d\n", 6887c478bd9Sstevel@tonic-gate sp->se_user, sp->se_uid, sp->se_gid); 6897c478bd9Sstevel@tonic-gate syseventd_print(DBG_DETAILED, 6907c478bd9Sstevel@tonic-gate " reserved1=%s\n", sp->se_reserved1); 6917c478bd9Sstevel@tonic-gate syseventd_print(DBG_DETAILED, 6927c478bd9Sstevel@tonic-gate " reserved2=%s\n", sp->se_reserved2); 6937c478bd9Sstevel@tonic-gate syseventd_print(DBG_DETAILED, 6947c478bd9Sstevel@tonic-gate " path=%s\n", sp->se_path); 6957c478bd9Sstevel@tonic-gate if (sp->se_args != NULL) { 6967c478bd9Sstevel@tonic-gate syseventd_print(DBG_DETAILED, 6977c478bd9Sstevel@tonic-gate " args=%s\n", sp->se_args); 6987c478bd9Sstevel@tonic-gate } 6997c478bd9Sstevel@tonic-gate } 7007c478bd9Sstevel@tonic-gate } 7017c478bd9Sstevel@tonic-gate 7027c478bd9Sstevel@tonic-gate continue; 7037c478bd9Sstevel@tonic-gate 7047c478bd9Sstevel@tonic-gate mal_formed: 7057c478bd9Sstevel@tonic-gate syslog(LOG_ERR, SYNTAX_ERR, conf_file, lineno); 7067c478bd9Sstevel@tonic-gate } 7077c478bd9Sstevel@tonic-gate 7087c478bd9Sstevel@tonic-gate freestr(line); 7097c478bd9Sstevel@tonic-gate (void) fclose(fp); 7107c478bd9Sstevel@tonic-gate } 7117c478bd9Sstevel@tonic-gate 7127c478bd9Sstevel@tonic-gate 7137c478bd9Sstevel@tonic-gate /* 7147c478bd9Sstevel@tonic-gate * Build the events specification table, a summation of all 7157c478bd9Sstevel@tonic-gate * event specification found in the installed sysevent.conf 7167c478bd9Sstevel@tonic-gate * configuration files. 7177c478bd9Sstevel@tonic-gate * 7187c478bd9Sstevel@tonic-gate * All sysevent.conf files reside in the /etc/sysevent/config 7197c478bd9Sstevel@tonic-gate * and may contain zero or more event/command specifications. 7207c478bd9Sstevel@tonic-gate * A sysevent.conf file should be named as follows: 7217c478bd9Sstevel@tonic-gate * 7227c478bd9Sstevel@tonic-gate * <vendor>,[<publisher>,][<class>,]sysevent.conf 7237c478bd9Sstevel@tonic-gate * 7247c478bd9Sstevel@tonic-gate * Event/command specifications delivered by the base Solaris 7257c478bd9Sstevel@tonic-gate * system are provided in /etc/sysevent/config/SUNW,sysevent.conf. 7267c478bd9Sstevel@tonic-gate * Event/command specifications delivered by optional 7277c478bd9Sstevel@tonic-gate * Sun-supplied packages may install additional sysevent.conf 7287c478bd9Sstevel@tonic-gate * files in /etc/sysevent/config using vendor SUNW, and additional 7297c478bd9Sstevel@tonic-gate * publisher and/or event class naming to distinguish the 7307c478bd9Sstevel@tonic-gate * events required for those products. Products provided 7317c478bd9Sstevel@tonic-gate * by third-party hardware or software companies may 7327c478bd9Sstevel@tonic-gate * distinguish their sysevent.conf files by vendor, and 7337c478bd9Sstevel@tonic-gate * by publisher and/or event class within vendor. 7347c478bd9Sstevel@tonic-gate * 7357c478bd9Sstevel@tonic-gate * Files residing in /etc/sysevent/config with a '.' (period) 7367c478bd9Sstevel@tonic-gate * as the first character of the name and files with a suffix 7377c478bd9Sstevel@tonic-gate * of other than "sysevent.conf" are ignored. 7387c478bd9Sstevel@tonic-gate */ 7397c478bd9Sstevel@tonic-gate static void 7407c478bd9Sstevel@tonic-gate build_event_table() 7417c478bd9Sstevel@tonic-gate { 7427c478bd9Sstevel@tonic-gate conftab_t *cfp = NULL; 7437c478bd9Sstevel@tonic-gate DIR *dir; 7447c478bd9Sstevel@tonic-gate struct dirent *result; 7457c478bd9Sstevel@tonic-gate conftab_t *new_cfp; 7467c478bd9Sstevel@tonic-gate char *str; 7477c478bd9Sstevel@tonic-gate 7487c478bd9Sstevel@tonic-gate if ((dir = opendir(SYSEVENT_CONFIG_DIR)) == NULL) { 7497c478bd9Sstevel@tonic-gate syslog(LOG_ERR, CANNOT_OPEN_ERR, 7507c478bd9Sstevel@tonic-gate SYSEVENT_CONFIG_DIR, strerror(errno)); 7517c478bd9Sstevel@tonic-gate return; 7527c478bd9Sstevel@tonic-gate } 7537c478bd9Sstevel@tonic-gate 7544bc0a2efScasper while ((result = readdir(dir)) != NULL) { 7557c478bd9Sstevel@tonic-gate if (result->d_name[0] == '.') 7567c478bd9Sstevel@tonic-gate continue; 7577c478bd9Sstevel@tonic-gate 7587c478bd9Sstevel@tonic-gate /* 7597c478bd9Sstevel@tonic-gate * file must have extension "sysevent.conf" 7607c478bd9Sstevel@tonic-gate */ 7617c478bd9Sstevel@tonic-gate if ((str = strrchr(result->d_name, ',')) != NULL) { 7627c478bd9Sstevel@tonic-gate str++; 7637c478bd9Sstevel@tonic-gate } else { 7647c478bd9Sstevel@tonic-gate str = result->d_name; 7657c478bd9Sstevel@tonic-gate } 7667c478bd9Sstevel@tonic-gate if (strcmp(str, "sysevent.conf") != 0) { 7677c478bd9Sstevel@tonic-gate syseventd_print(DBG_CONF_FILE, 7687c478bd9Sstevel@tonic-gate "%s: ignoring %s\n", whoami, str); 7697c478bd9Sstevel@tonic-gate continue; 7707c478bd9Sstevel@tonic-gate } 7717c478bd9Sstevel@tonic-gate 7727c478bd9Sstevel@tonic-gate /* 7737c478bd9Sstevel@tonic-gate * Add to file table and parse this conf file 7747c478bd9Sstevel@tonic-gate */ 7757c478bd9Sstevel@tonic-gate if ((str = sc_strdup(result->d_name)) == NULL) 7767c478bd9Sstevel@tonic-gate goto err; 7777c478bd9Sstevel@tonic-gate if ((new_cfp = sc_malloc(sizeof (conftab_t))) == NULL) { 7787c478bd9Sstevel@tonic-gate sc_strfree(str); 7797c478bd9Sstevel@tonic-gate goto err; 7807c478bd9Sstevel@tonic-gate } 7817c478bd9Sstevel@tonic-gate if (conftab == NULL) { 7827c478bd9Sstevel@tonic-gate conftab = new_cfp; 7837c478bd9Sstevel@tonic-gate } else { 7847c478bd9Sstevel@tonic-gate for (cfp = conftab; cfp->cf_next; cfp = cfp->cf_next) 7857c478bd9Sstevel@tonic-gate ; 7867c478bd9Sstevel@tonic-gate cfp->cf_next = new_cfp; 7877c478bd9Sstevel@tonic-gate } 7887c478bd9Sstevel@tonic-gate cfp = new_cfp; 7897c478bd9Sstevel@tonic-gate cfp->cf_conf_file = str; 7907c478bd9Sstevel@tonic-gate cfp->cf_next = NULL; 7917c478bd9Sstevel@tonic-gate 7927c478bd9Sstevel@tonic-gate parse_conf_file(cfp->cf_conf_file); 7937c478bd9Sstevel@tonic-gate } 7947c478bd9Sstevel@tonic-gate 7957c478bd9Sstevel@tonic-gate err: 7967c478bd9Sstevel@tonic-gate if (closedir(dir) == -1) { 7977c478bd9Sstevel@tonic-gate if (errno == EAGAIN) 7987c478bd9Sstevel@tonic-gate goto err; 7997c478bd9Sstevel@tonic-gate syslog(LOG_ERR, CLOSEDIR_ERR, 8007c478bd9Sstevel@tonic-gate SYSEVENT_CONFIG_DIR, strerror(errno)); 8017c478bd9Sstevel@tonic-gate } 8027c478bd9Sstevel@tonic-gate } 8037c478bd9Sstevel@tonic-gate 8047c478bd9Sstevel@tonic-gate 8057c478bd9Sstevel@tonic-gate static int 8067c478bd9Sstevel@tonic-gate enter_lock(char *lock_file) 8077c478bd9Sstevel@tonic-gate { 8087c478bd9Sstevel@tonic-gate struct flock lock; 8097c478bd9Sstevel@tonic-gate int lock_fd; 8107c478bd9Sstevel@tonic-gate 811c6fc6dddSEric Schrock (void) strlcpy(lock_file, LOCK_FILENAME, PATH_MAX); 8127c478bd9Sstevel@tonic-gate lock_fd = open(lock_file, O_CREAT|O_RDWR, 0644); 8137c478bd9Sstevel@tonic-gate if (lock_fd < 0) { 8147c478bd9Sstevel@tonic-gate syslog(LOG_ERR, MSG_LOCK_CREATE_ERR, 8157c478bd9Sstevel@tonic-gate whoami, lock_file, strerror(errno)); 8167c478bd9Sstevel@tonic-gate return (-1); 8177c478bd9Sstevel@tonic-gate } 8187c478bd9Sstevel@tonic-gate 8197c478bd9Sstevel@tonic-gate lock.l_type = F_WRLCK; 8207c478bd9Sstevel@tonic-gate lock.l_whence = SEEK_SET; 8217c478bd9Sstevel@tonic-gate lock.l_start = 0; 8227c478bd9Sstevel@tonic-gate lock.l_len = 0; 8237c478bd9Sstevel@tonic-gate 8247c478bd9Sstevel@tonic-gate retry: 8257c478bd9Sstevel@tonic-gate if (fcntl(lock_fd, F_SETLKW, &lock) == -1) { 8267c478bd9Sstevel@tonic-gate if (errno == EAGAIN || errno == EINTR) 8277c478bd9Sstevel@tonic-gate goto retry; 8287c478bd9Sstevel@tonic-gate (void) close(lock_fd); 8297c478bd9Sstevel@tonic-gate syslog(LOG_ERR, MSG_LOCK_SET_ERR, 8307c478bd9Sstevel@tonic-gate whoami, lock_file, strerror(errno)); 8317c478bd9Sstevel@tonic-gate return (-1); 8327c478bd9Sstevel@tonic-gate } 8337c478bd9Sstevel@tonic-gate 8347c478bd9Sstevel@tonic-gate return (lock_fd); 8357c478bd9Sstevel@tonic-gate } 8367c478bd9Sstevel@tonic-gate 8377c478bd9Sstevel@tonic-gate 8387c478bd9Sstevel@tonic-gate static void 8397c478bd9Sstevel@tonic-gate exit_lock(int lock_fd, char *lock_file) 8407c478bd9Sstevel@tonic-gate { 8417c478bd9Sstevel@tonic-gate struct flock lock; 8427c478bd9Sstevel@tonic-gate 8437c478bd9Sstevel@tonic-gate lock.l_type = F_UNLCK; 8447c478bd9Sstevel@tonic-gate lock.l_whence = SEEK_SET; 8457c478bd9Sstevel@tonic-gate lock.l_start = 0; 8467c478bd9Sstevel@tonic-gate lock.l_len = 0; 8477c478bd9Sstevel@tonic-gate 8487c478bd9Sstevel@tonic-gate if (fcntl(lock_fd, F_SETLK, &lock) == -1) { 8497c478bd9Sstevel@tonic-gate syslog(LOG_ERR, MSG_LOCK_CLR_ERR, 8507c478bd9Sstevel@tonic-gate whoami, lock_file, strerror(errno)); 8517c478bd9Sstevel@tonic-gate } 8527c478bd9Sstevel@tonic-gate 8537c478bd9Sstevel@tonic-gate if (close(lock_fd) == -1) { 8547c478bd9Sstevel@tonic-gate syslog(LOG_ERR, MSG_LOCK_CLOSE_ERR, 8557c478bd9Sstevel@tonic-gate whoami, lock_file, strerror(errno)); 8567c478bd9Sstevel@tonic-gate } 8577c478bd9Sstevel@tonic-gate } 8587c478bd9Sstevel@tonic-gate 8597c478bd9Sstevel@tonic-gate 8607c478bd9Sstevel@tonic-gate /* 8617c478bd9Sstevel@tonic-gate * Free the events specification table, constructed by 8627c478bd9Sstevel@tonic-gate * parsing all the sysevent.conf files found. 8637c478bd9Sstevel@tonic-gate * 8647c478bd9Sstevel@tonic-gate * The free of this table is in response to a HUP 8657c478bd9Sstevel@tonic-gate * given to the syseventd daemon, permitting the 8667c478bd9Sstevel@tonic-gate * table to be rebuilt after adding a new sysevent.conf 8677c478bd9Sstevel@tonic-gate * file or changing an existing one without shutting 8687c478bd9Sstevel@tonic-gate * down the daemon. 8697c478bd9Sstevel@tonic-gate */ 8707c478bd9Sstevel@tonic-gate static void 8717c478bd9Sstevel@tonic-gate free_event_table() 8727c478bd9Sstevel@tonic-gate { 8737c478bd9Sstevel@tonic-gate syseventtab_t *sep; 8747c478bd9Sstevel@tonic-gate syseventtab_t *sep_next; 8757c478bd9Sstevel@tonic-gate conftab_t *cfp; 8767c478bd9Sstevel@tonic-gate conftab_t *cfp_next; 8777c478bd9Sstevel@tonic-gate 8787c478bd9Sstevel@tonic-gate sep = syseventtab; 8797c478bd9Sstevel@tonic-gate while (sep) { 8807c478bd9Sstevel@tonic-gate sc_strfree(sep->se_vendor); 8817c478bd9Sstevel@tonic-gate sc_strfree(sep->se_publisher); 8827c478bd9Sstevel@tonic-gate sc_strfree(sep->se_class); 8837c478bd9Sstevel@tonic-gate sc_strfree(sep->se_subclass); 8847c478bd9Sstevel@tonic-gate sc_strfree(sep->se_user); 8857c478bd9Sstevel@tonic-gate sc_strfree(sep->se_reserved1); 8867c478bd9Sstevel@tonic-gate sc_strfree(sep->se_reserved2); 8877c478bd9Sstevel@tonic-gate sc_strfree(sep->se_path); 8887c478bd9Sstevel@tonic-gate if (sep->se_args) 8897c478bd9Sstevel@tonic-gate sc_strfree(sep->se_args); 8907c478bd9Sstevel@tonic-gate sep_next = sep->se_next; 8917c478bd9Sstevel@tonic-gate sc_free(sep, sizeof (syseventtab_t)); 8927c478bd9Sstevel@tonic-gate sep = sep_next; 8937c478bd9Sstevel@tonic-gate } 8947c478bd9Sstevel@tonic-gate syseventtab = NULL; 8957c478bd9Sstevel@tonic-gate 8967c478bd9Sstevel@tonic-gate cfp = conftab; 8977c478bd9Sstevel@tonic-gate while (cfp) { 8987c478bd9Sstevel@tonic-gate sc_strfree(cfp->cf_conf_file); 8997c478bd9Sstevel@tonic-gate cfp_next = cfp->cf_next; 9007c478bd9Sstevel@tonic-gate sc_free(cfp, sizeof (conftab_t)); 9017c478bd9Sstevel@tonic-gate cfp = cfp_next; 9027c478bd9Sstevel@tonic-gate } 9037c478bd9Sstevel@tonic-gate conftab = NULL; 9047c478bd9Sstevel@tonic-gate } 9057c478bd9Sstevel@tonic-gate 9067c478bd9Sstevel@tonic-gate 9077c478bd9Sstevel@tonic-gate 9087c478bd9Sstevel@tonic-gate static char ident_chars[] = "_"; 9097c478bd9Sstevel@tonic-gate 9107c478bd9Sstevel@tonic-gate /* 9117c478bd9Sstevel@tonic-gate * Return a dynamically-allocated string containing the 9127c478bd9Sstevel@tonic-gate * the next identifier in the string being parsed, pointed 9137c478bd9Sstevel@tonic-gate * at by 'id'. 'end' returns a pointer to the character 9147c478bd9Sstevel@tonic-gate * after the identifier. 9157c478bd9Sstevel@tonic-gate * 9167c478bd9Sstevel@tonic-gate * Identifiers are all alphanumeric ascii characters and 9177c478bd9Sstevel@tonic-gate * those contained in ident_chars. 9187c478bd9Sstevel@tonic-gate * 9197c478bd9Sstevel@tonic-gate * The returned string must be explicitly freed via 9207c478bd9Sstevel@tonic-gate * freestr(). 9217c478bd9Sstevel@tonic-gate */ 9227c478bd9Sstevel@tonic-gate static str_t * 9237c478bd9Sstevel@tonic-gate snip_identifier(char *id, char **end) 9247c478bd9Sstevel@tonic-gate { 9257c478bd9Sstevel@tonic-gate str_t *token; 9267c478bd9Sstevel@tonic-gate 9277c478bd9Sstevel@tonic-gate if ((token = initstr(32)) == NULL) 9287c478bd9Sstevel@tonic-gate return (NULL); 9297c478bd9Sstevel@tonic-gate 9307c478bd9Sstevel@tonic-gate while (*id != 0) { 9317c478bd9Sstevel@tonic-gate if (isascii(*id) && 9327c478bd9Sstevel@tonic-gate (isalnum(*id) || strchr(ident_chars, *id) != NULL)) { 9337c478bd9Sstevel@tonic-gate if (strcatc(token, *id++)) { 9347c478bd9Sstevel@tonic-gate freestr(token); 9357c478bd9Sstevel@tonic-gate return (NULL); 9367c478bd9Sstevel@tonic-gate } 9377c478bd9Sstevel@tonic-gate } else { 9387c478bd9Sstevel@tonic-gate *end = id; 9397c478bd9Sstevel@tonic-gate return (token); 9407c478bd9Sstevel@tonic-gate } 9417c478bd9Sstevel@tonic-gate } 9427c478bd9Sstevel@tonic-gate 9437c478bd9Sstevel@tonic-gate *end = id; 9447c478bd9Sstevel@tonic-gate return (token); 9457c478bd9Sstevel@tonic-gate } 9467c478bd9Sstevel@tonic-gate 9477c478bd9Sstevel@tonic-gate 9487c478bd9Sstevel@tonic-gate /* 9497c478bd9Sstevel@tonic-gate * Identical to snip_identifier(), but the identifier 9507c478bd9Sstevel@tonic-gate * is delimited by the characters { and }. 9517c478bd9Sstevel@tonic-gate */ 9527c478bd9Sstevel@tonic-gate static str_t * 9537c478bd9Sstevel@tonic-gate snip_delimited_identifier(char *id, char **end) 9547c478bd9Sstevel@tonic-gate { 9557c478bd9Sstevel@tonic-gate str_t *token; 9567c478bd9Sstevel@tonic-gate 9577c478bd9Sstevel@tonic-gate if ((token = initstr(32)) == NULL) 9587c478bd9Sstevel@tonic-gate return (NULL); 9597c478bd9Sstevel@tonic-gate 9607c478bd9Sstevel@tonic-gate while (*id != 0) { 9617c478bd9Sstevel@tonic-gate if (*id == '}') { 9627c478bd9Sstevel@tonic-gate *end = id+1; 9637c478bd9Sstevel@tonic-gate return (token); 9647c478bd9Sstevel@tonic-gate } 9657c478bd9Sstevel@tonic-gate if (strcatc(token, *id++)) { 9667c478bd9Sstevel@tonic-gate freestr(token); 9677c478bd9Sstevel@tonic-gate return (NULL); 9687c478bd9Sstevel@tonic-gate } 9697c478bd9Sstevel@tonic-gate } 9707c478bd9Sstevel@tonic-gate 9717c478bd9Sstevel@tonic-gate if (*id == 0) { 9727c478bd9Sstevel@tonic-gate freestr(token); 9737c478bd9Sstevel@tonic-gate return (NULL); 9747c478bd9Sstevel@tonic-gate } 9757c478bd9Sstevel@tonic-gate 9767c478bd9Sstevel@tonic-gate *end = id; 9777c478bd9Sstevel@tonic-gate return (token); 9787c478bd9Sstevel@tonic-gate } 9797c478bd9Sstevel@tonic-gate 9807c478bd9Sstevel@tonic-gate 9817c478bd9Sstevel@tonic-gate /* 9827c478bd9Sstevel@tonic-gate * Return a string with the name of the attribute type 9837c478bd9Sstevel@tonic-gate */ 9847c478bd9Sstevel@tonic-gate static char *nv_attr_type_strings[] = { 9857c478bd9Sstevel@tonic-gate "unknown", 9867c478bd9Sstevel@tonic-gate "boolean", 9877c478bd9Sstevel@tonic-gate "byte", 9887c478bd9Sstevel@tonic-gate "int16", 9897c478bd9Sstevel@tonic-gate "uint16", 9907c478bd9Sstevel@tonic-gate "int32", 9917c478bd9Sstevel@tonic-gate "uint32", 9927c478bd9Sstevel@tonic-gate "int64", 9937c478bd9Sstevel@tonic-gate "uint64", 9947c478bd9Sstevel@tonic-gate "string", 9957c478bd9Sstevel@tonic-gate "byte-array", 9967c478bd9Sstevel@tonic-gate "int16-array", 9977c478bd9Sstevel@tonic-gate "uint16-array", 9987c478bd9Sstevel@tonic-gate "int32-array", 9997c478bd9Sstevel@tonic-gate "uint32-array", 10007c478bd9Sstevel@tonic-gate "int64-array", 10017c478bd9Sstevel@tonic-gate "uint64-array", 10027c478bd9Sstevel@tonic-gate "string-array", 10037c478bd9Sstevel@tonic-gate "hrtime" 10047c478bd9Sstevel@tonic-gate }; 10057c478bd9Sstevel@tonic-gate 10067c478bd9Sstevel@tonic-gate static char * 10077c478bd9Sstevel@tonic-gate se_attr_type_to_str(int se_attr_type) 10087c478bd9Sstevel@tonic-gate { 10097c478bd9Sstevel@tonic-gate if (se_attr_type >= 0 && 10107c478bd9Sstevel@tonic-gate se_attr_type < sizeof (nv_attr_type_strings) / sizeof (char *)) { 10117c478bd9Sstevel@tonic-gate return (nv_attr_type_strings[se_attr_type]); 10127c478bd9Sstevel@tonic-gate } 10137c478bd9Sstevel@tonic-gate return (nv_attr_type_strings[DATA_TYPE_UNKNOWN]); 10147c478bd9Sstevel@tonic-gate } 10157c478bd9Sstevel@tonic-gate 10167c478bd9Sstevel@tonic-gate 10177c478bd9Sstevel@tonic-gate /* 10187c478bd9Sstevel@tonic-gate * Find and return the data matching the macro name 'token' 10197c478bd9Sstevel@tonic-gate * 10207c478bd9Sstevel@tonic-gate * Predefined macros are simply substituted with the 10217c478bd9Sstevel@tonic-gate * data from the event header: 10227c478bd9Sstevel@tonic-gate * 10237c478bd9Sstevel@tonic-gate * $vendor - the vendor string defining the event. 10247c478bd9Sstevel@tonic-gate * 10257c478bd9Sstevel@tonic-gate * $publisher - the publisher string defining the event. 10267c478bd9Sstevel@tonic-gate * 10277c478bd9Sstevel@tonic-gate * $class - the class string defining the event. 10287c478bd9Sstevel@tonic-gate * 10297c478bd9Sstevel@tonic-gate * $subclass - the subclass string defining the event. 10307c478bd9Sstevel@tonic-gate * 10317c478bd9Sstevel@tonic-gate * $sequence - the sequence number of the event. 10327c478bd9Sstevel@tonic-gate * 10337c478bd9Sstevel@tonic-gate * $timestamp - the timestamp of the event. 10347c478bd9Sstevel@tonic-gate * 10357c478bd9Sstevel@tonic-gate * Attributes with signed data types (DATA_TYPE_INT16, 10367c478bd9Sstevel@tonic-gate * DATA_TYPE_INT32 and DATA_TYPE_INT64) are expanded 10377c478bd9Sstevel@tonic-gate * as decimal digits. 10387c478bd9Sstevel@tonic-gate * 10397c478bd9Sstevel@tonic-gate * Attributes with unsigned data types (DATA_TYPE_BYTE, 10407c478bd9Sstevel@tonic-gate * DATA_TYPE_UINT16, DATA_TYPE_UINT32, DATA_TYPE_UINT64 and 10417c478bd9Sstevel@tonic-gate * DATA_TYPE_HTTIME) are expanded as hexadecimal digits 10427c478bd9Sstevel@tonic-gate * with a "0x" prefix. 10437c478bd9Sstevel@tonic-gate * 10447c478bd9Sstevel@tonic-gate * Attributes with string data type (DATA_TYPE_STRING) 10457c478bd9Sstevel@tonic-gate * are expanded with the string data. The data is 10467c478bd9Sstevel@tonic-gate * not quoted. If if it desired that the quoted strings 10477c478bd9Sstevel@tonic-gate * be generated on the command line, put quotes around 10487c478bd9Sstevel@tonic-gate * the macro call in the arguments. 10497c478bd9Sstevel@tonic-gate * 10507c478bd9Sstevel@tonic-gate * Array types are expanded with each element expanded 10517c478bd9Sstevel@tonic-gate * as defined for that scalar type, with a space separating 10527c478bd9Sstevel@tonic-gate * each element substitution. 10537c478bd9Sstevel@tonic-gate */ 10547c478bd9Sstevel@tonic-gate 10557c478bd9Sstevel@tonic-gate static str_t * 10567c478bd9Sstevel@tonic-gate find_macro_definition(sysevent_t *ev, nvlist_t *nvlist, syseventtab_t *sep, 10577c478bd9Sstevel@tonic-gate char *token, sysevent_hdr_info_t *hdr) 10587c478bd9Sstevel@tonic-gate { 10597c478bd9Sstevel@tonic-gate nvpair_t *nvp; 10607c478bd9Sstevel@tonic-gate int nmatches; 10617c478bd9Sstevel@tonic-gate char num[64]; 10627c478bd9Sstevel@tonic-gate str_t *replacement; 10637c478bd9Sstevel@tonic-gate int i; 10647c478bd9Sstevel@tonic-gate uint_t nelems; 10657c478bd9Sstevel@tonic-gate union { 10667c478bd9Sstevel@tonic-gate uchar_t x_byte; 10677c478bd9Sstevel@tonic-gate int16_t x_int16; 10687c478bd9Sstevel@tonic-gate uint16_t x_uint16; 10697c478bd9Sstevel@tonic-gate int32_t x_int32; 10707c478bd9Sstevel@tonic-gate uint32_t x_uint32; 10717c478bd9Sstevel@tonic-gate int64_t x_int64; 10727c478bd9Sstevel@tonic-gate uint64_t x_uint64; 10737c478bd9Sstevel@tonic-gate hrtime_t x_time; 10747c478bd9Sstevel@tonic-gate char *x_string; 10757c478bd9Sstevel@tonic-gate uchar_t *x_byte_array; 10767c478bd9Sstevel@tonic-gate int16_t *x_int16_array; 10777c478bd9Sstevel@tonic-gate int32_t *x_int32_array; 10787c478bd9Sstevel@tonic-gate int64_t *x_int64_array; 10797c478bd9Sstevel@tonic-gate uint16_t *x_uint16_array; 10807c478bd9Sstevel@tonic-gate uint32_t *x_uint32_array; 10817c478bd9Sstevel@tonic-gate uint64_t *x_uint64_array; 10827c478bd9Sstevel@tonic-gate char **x_string_array; 10837c478bd9Sstevel@tonic-gate } x; 10847c478bd9Sstevel@tonic-gate 10857c478bd9Sstevel@tonic-gate 10867c478bd9Sstevel@tonic-gate if ((replacement = initstr(128)) == NULL) { 10877c478bd9Sstevel@tonic-gate return (NULL); 10887c478bd9Sstevel@tonic-gate } 10897c478bd9Sstevel@tonic-gate 10907c478bd9Sstevel@tonic-gate if (strcmp(token, "vendor") == 0) { 10917c478bd9Sstevel@tonic-gate if (strcopys(replacement, hdr->vendor)) { 10927c478bd9Sstevel@tonic-gate freestr(replacement); 10937c478bd9Sstevel@tonic-gate return (NULL); 10947c478bd9Sstevel@tonic-gate } 10957c478bd9Sstevel@tonic-gate return (replacement); 10967c478bd9Sstevel@tonic-gate } 10977c478bd9Sstevel@tonic-gate 10987c478bd9Sstevel@tonic-gate if (strcmp(token, "publisher") == 0) { 10997c478bd9Sstevel@tonic-gate if (strcopys(replacement, hdr->publisher)) { 11007c478bd9Sstevel@tonic-gate freestr(replacement); 11017c478bd9Sstevel@tonic-gate return (NULL); 11027c478bd9Sstevel@tonic-gate } 11037c478bd9Sstevel@tonic-gate return (replacement); 11047c478bd9Sstevel@tonic-gate } 11057c478bd9Sstevel@tonic-gate 11067c478bd9Sstevel@tonic-gate if (strcmp(token, "class") == 0) { 11077c478bd9Sstevel@tonic-gate if (strcopys(replacement, hdr->class)) { 11087c478bd9Sstevel@tonic-gate freestr(replacement); 11097c478bd9Sstevel@tonic-gate return (NULL); 11107c478bd9Sstevel@tonic-gate } 11117c478bd9Sstevel@tonic-gate return (replacement); 11127c478bd9Sstevel@tonic-gate } 11137c478bd9Sstevel@tonic-gate 11147c478bd9Sstevel@tonic-gate if (strcmp(token, "subclass") == 0) { 11157c478bd9Sstevel@tonic-gate if (strcopys(replacement, hdr->subclass)) { 11167c478bd9Sstevel@tonic-gate freestr(replacement); 11177c478bd9Sstevel@tonic-gate return (NULL); 11187c478bd9Sstevel@tonic-gate } 11197c478bd9Sstevel@tonic-gate return (replacement); 11207c478bd9Sstevel@tonic-gate } 11217c478bd9Sstevel@tonic-gate 11227c478bd9Sstevel@tonic-gate if ((strcmp(token, "sequence") == 0) || 11237c478bd9Sstevel@tonic-gate (strcmp(token, "timestamp") == 0)) { 11247c478bd9Sstevel@tonic-gate if (strcmp(token, "sequence") == 0) { 11257c478bd9Sstevel@tonic-gate (void) snprintf(num, sizeof (num), 11267c478bd9Sstevel@tonic-gate "0x%llx", sysevent_get_seq(ev)); 11277c478bd9Sstevel@tonic-gate } else { 11287c478bd9Sstevel@tonic-gate hrtime_t ts; 11297c478bd9Sstevel@tonic-gate sysevent_get_time(ev, &ts); 11307c478bd9Sstevel@tonic-gate (void) snprintf(num, sizeof (num), "0x%llx", ts); 11317c478bd9Sstevel@tonic-gate } 11327c478bd9Sstevel@tonic-gate if (strcopys(replacement, num)) { 11337c478bd9Sstevel@tonic-gate freestr(replacement); 11347c478bd9Sstevel@tonic-gate return (NULL); 11357c478bd9Sstevel@tonic-gate } 11367c478bd9Sstevel@tonic-gate return (replacement); 11377c478bd9Sstevel@tonic-gate } 11387c478bd9Sstevel@tonic-gate 11397c478bd9Sstevel@tonic-gate nmatches = 0; 11407c478bd9Sstevel@tonic-gate 11417c478bd9Sstevel@tonic-gate if (nvlist) { 11427c478bd9Sstevel@tonic-gate nvpair_t *nvp_match; 11437c478bd9Sstevel@tonic-gate nvp = NULL; 11447c478bd9Sstevel@tonic-gate while ((nvp = nvlist_next_nvpair(nvlist, nvp)) != NULL) { 11457c478bd9Sstevel@tonic-gate if (debug_level >= DBG_DETAILED) { 11467c478bd9Sstevel@tonic-gate syseventd_print(DBG_DETAILED, 11477c478bd9Sstevel@tonic-gate " attribute: %s %s\n", nvpair_name(nvp), 11487c478bd9Sstevel@tonic-gate se_attr_type_to_str(nvpair_type(nvp))); 11497c478bd9Sstevel@tonic-gate } 11507c478bd9Sstevel@tonic-gate if (strcmp(token, nvpair_name(nvp)) == 0) { 11517c478bd9Sstevel@tonic-gate nmatches++; 11527c478bd9Sstevel@tonic-gate nvp_match = nvp; 11537c478bd9Sstevel@tonic-gate } 11547c478bd9Sstevel@tonic-gate } 11557c478bd9Sstevel@tonic-gate nvp = nvp_match; 11567c478bd9Sstevel@tonic-gate } 11577c478bd9Sstevel@tonic-gate 11587c478bd9Sstevel@tonic-gate if (nmatches == 0) { 11597c478bd9Sstevel@tonic-gate syslog(LOG_ERR, MACRO_UNDEF_ERR, 11607c478bd9Sstevel@tonic-gate sep->se_conf_file, sep->se_lineno, token); 11617c478bd9Sstevel@tonic-gate freestr(replacement); 11627c478bd9Sstevel@tonic-gate return (NULL); 11637c478bd9Sstevel@tonic-gate } else if (nmatches > 1) { 11647c478bd9Sstevel@tonic-gate syslog(LOG_ERR, MACRO_MULT_DEF_ERR, 11657c478bd9Sstevel@tonic-gate sep->se_conf_file, sep->se_lineno, token); 11667c478bd9Sstevel@tonic-gate freestr(replacement); 11677c478bd9Sstevel@tonic-gate return (NULL); 11687c478bd9Sstevel@tonic-gate } 11697c478bd9Sstevel@tonic-gate 11707c478bd9Sstevel@tonic-gate switch (nvpair_type(nvp)) { 11717c478bd9Sstevel@tonic-gate case DATA_TYPE_BYTE: 11727c478bd9Sstevel@tonic-gate (void) nvpair_value_byte(nvp, &x.x_byte); 11737c478bd9Sstevel@tonic-gate (void) snprintf(num, sizeof (num), "0x%x", x.x_byte); 11747c478bd9Sstevel@tonic-gate if (strcats(replacement, num)) { 11757c478bd9Sstevel@tonic-gate freestr(replacement); 11767c478bd9Sstevel@tonic-gate return (NULL); 11777c478bd9Sstevel@tonic-gate } 11787c478bd9Sstevel@tonic-gate break; 11797c478bd9Sstevel@tonic-gate case DATA_TYPE_INT16: 11807c478bd9Sstevel@tonic-gate (void) nvpair_value_int16(nvp, &x.x_int16); 11817c478bd9Sstevel@tonic-gate (void) snprintf(num, sizeof (num), "%d", x.x_int16); 11827c478bd9Sstevel@tonic-gate if (strcats(replacement, num)) { 11837c478bd9Sstevel@tonic-gate freestr(replacement); 11847c478bd9Sstevel@tonic-gate return (NULL); 11857c478bd9Sstevel@tonic-gate } 11867c478bd9Sstevel@tonic-gate break; 11877c478bd9Sstevel@tonic-gate case DATA_TYPE_UINT16: 11887c478bd9Sstevel@tonic-gate (void) nvpair_value_uint16(nvp, &x.x_uint16); 11897c478bd9Sstevel@tonic-gate (void) snprintf(num, sizeof (num), "0x%x", x.x_uint16); 11907c478bd9Sstevel@tonic-gate if (strcats(replacement, num)) { 11917c478bd9Sstevel@tonic-gate freestr(replacement); 11927c478bd9Sstevel@tonic-gate return (NULL); 11937c478bd9Sstevel@tonic-gate } 11947c478bd9Sstevel@tonic-gate break; 11957c478bd9Sstevel@tonic-gate case DATA_TYPE_INT32: 11967c478bd9Sstevel@tonic-gate (void) nvpair_value_int32(nvp, &x.x_int32); 11977c478bd9Sstevel@tonic-gate (void) snprintf(num, sizeof (num), "%d", x.x_int32); 11987c478bd9Sstevel@tonic-gate if (strcats(replacement, num)) { 11997c478bd9Sstevel@tonic-gate freestr(replacement); 12007c478bd9Sstevel@tonic-gate return (NULL); 12017c478bd9Sstevel@tonic-gate } 12027c478bd9Sstevel@tonic-gate break; 12037c478bd9Sstevel@tonic-gate case DATA_TYPE_UINT32: 12047c478bd9Sstevel@tonic-gate (void) nvpair_value_uint32(nvp, &x.x_uint32); 12057c478bd9Sstevel@tonic-gate (void) snprintf(num, sizeof (num), "0x%x", x.x_uint32); 12067c478bd9Sstevel@tonic-gate if (strcats(replacement, num)) { 12077c478bd9Sstevel@tonic-gate freestr(replacement); 12087c478bd9Sstevel@tonic-gate return (NULL); 12097c478bd9Sstevel@tonic-gate } 12107c478bd9Sstevel@tonic-gate break; 12117c478bd9Sstevel@tonic-gate case DATA_TYPE_INT64: 12127c478bd9Sstevel@tonic-gate (void) nvpair_value_int64(nvp, &x.x_int64); 12137c478bd9Sstevel@tonic-gate (void) snprintf(num, sizeof (num), "%lld", x.x_int64); 12147c478bd9Sstevel@tonic-gate if (strcats(replacement, num)) { 12157c478bd9Sstevel@tonic-gate freestr(replacement); 12167c478bd9Sstevel@tonic-gate return (NULL); 12177c478bd9Sstevel@tonic-gate } 12187c478bd9Sstevel@tonic-gate break; 12197c478bd9Sstevel@tonic-gate case DATA_TYPE_UINT64: 12207c478bd9Sstevel@tonic-gate (void) nvpair_value_uint64(nvp, &x.x_uint64); 12217c478bd9Sstevel@tonic-gate (void) snprintf(num, sizeof (num), "0x%llx", x.x_uint64); 12227c478bd9Sstevel@tonic-gate if (strcats(replacement, num)) { 12237c478bd9Sstevel@tonic-gate freestr(replacement); 12247c478bd9Sstevel@tonic-gate return (NULL); 12257c478bd9Sstevel@tonic-gate } 12267c478bd9Sstevel@tonic-gate break; 12277c478bd9Sstevel@tonic-gate case DATA_TYPE_STRING: 12287c478bd9Sstevel@tonic-gate (void) nvpair_value_string(nvp, &x.x_string); 12297c478bd9Sstevel@tonic-gate if (strcats(replacement, x.x_string)) { 12307c478bd9Sstevel@tonic-gate freestr(replacement); 12317c478bd9Sstevel@tonic-gate return (NULL); 12327c478bd9Sstevel@tonic-gate } 12337c478bd9Sstevel@tonic-gate break; 12347c478bd9Sstevel@tonic-gate case DATA_TYPE_BYTE_ARRAY: { 12357c478bd9Sstevel@tonic-gate uchar_t *p; 12367c478bd9Sstevel@tonic-gate (void) nvpair_value_byte_array(nvp, 12377c478bd9Sstevel@tonic-gate &x.x_byte_array, &nelems); 12387c478bd9Sstevel@tonic-gate p = x.x_byte_array; 12397c478bd9Sstevel@tonic-gate for (i = 0; i < nelems; i++) { 12407c478bd9Sstevel@tonic-gate (void) snprintf(num, sizeof (num), 12417c478bd9Sstevel@tonic-gate "0x%x ", *p++ & 0xff); 12427c478bd9Sstevel@tonic-gate if (strcats(replacement, num)) { 12437c478bd9Sstevel@tonic-gate freestr(replacement); 12447c478bd9Sstevel@tonic-gate return (NULL); 12457c478bd9Sstevel@tonic-gate } 12467c478bd9Sstevel@tonic-gate } 12477c478bd9Sstevel@tonic-gate } 12487c478bd9Sstevel@tonic-gate break; 12497c478bd9Sstevel@tonic-gate case DATA_TYPE_INT16_ARRAY: { 12507c478bd9Sstevel@tonic-gate int16_t *p; 12517c478bd9Sstevel@tonic-gate (void) nvpair_value_int16_array(nvp, 12527c478bd9Sstevel@tonic-gate &x.x_int16_array, &nelems); 12537c478bd9Sstevel@tonic-gate p = x.x_int16_array; 12547c478bd9Sstevel@tonic-gate for (i = 0; i < nelems; i++) { 12557c478bd9Sstevel@tonic-gate (void) snprintf(num, sizeof (num), "%d ", *p++); 12567c478bd9Sstevel@tonic-gate if (strcats(replacement, num)) { 12577c478bd9Sstevel@tonic-gate freestr(replacement); 12587c478bd9Sstevel@tonic-gate return (NULL); 12597c478bd9Sstevel@tonic-gate } 12607c478bd9Sstevel@tonic-gate } 12617c478bd9Sstevel@tonic-gate } 12627c478bd9Sstevel@tonic-gate break; 12637c478bd9Sstevel@tonic-gate 12647c478bd9Sstevel@tonic-gate case DATA_TYPE_UINT16_ARRAY: { 12657c478bd9Sstevel@tonic-gate uint16_t *p; 12667c478bd9Sstevel@tonic-gate (void) nvpair_value_uint16_array(nvp, 12677c478bd9Sstevel@tonic-gate &x.x_uint16_array, &nelems); 12687c478bd9Sstevel@tonic-gate p = x.x_uint16_array; 12697c478bd9Sstevel@tonic-gate for (i = 0; i < nelems; i++) { 12707c478bd9Sstevel@tonic-gate (void) snprintf(num, sizeof (num), 12717c478bd9Sstevel@tonic-gate "0x%x ", *p++); 12727c478bd9Sstevel@tonic-gate if (strcats(replacement, num)) { 12737c478bd9Sstevel@tonic-gate freestr(replacement); 12747c478bd9Sstevel@tonic-gate return (NULL); 12757c478bd9Sstevel@tonic-gate } 12767c478bd9Sstevel@tonic-gate } 12777c478bd9Sstevel@tonic-gate } 12787c478bd9Sstevel@tonic-gate break; 12797c478bd9Sstevel@tonic-gate 12807c478bd9Sstevel@tonic-gate case DATA_TYPE_INT32_ARRAY: { 12817c478bd9Sstevel@tonic-gate int32_t *p; 12827c478bd9Sstevel@tonic-gate (void) nvpair_value_int32_array(nvp, 12837c478bd9Sstevel@tonic-gate &x.x_int32_array, &nelems); 12847c478bd9Sstevel@tonic-gate p = x.x_int32_array; 12857c478bd9Sstevel@tonic-gate for (i = 0; i < nelems; i++) { 12867c478bd9Sstevel@tonic-gate (void) snprintf(num, sizeof (num), "%d ", *p++); 12877c478bd9Sstevel@tonic-gate if (strcats(replacement, num)) { 12887c478bd9Sstevel@tonic-gate freestr(replacement); 12897c478bd9Sstevel@tonic-gate return (NULL); 12907c478bd9Sstevel@tonic-gate } 12917c478bd9Sstevel@tonic-gate } 12927c478bd9Sstevel@tonic-gate } 12937c478bd9Sstevel@tonic-gate break; 12947c478bd9Sstevel@tonic-gate 12957c478bd9Sstevel@tonic-gate case DATA_TYPE_UINT32_ARRAY: { 12967c478bd9Sstevel@tonic-gate uint32_t *p; 12977c478bd9Sstevel@tonic-gate (void) nvpair_value_uint32_array(nvp, 12987c478bd9Sstevel@tonic-gate &x.x_uint32_array, &nelems); 12997c478bd9Sstevel@tonic-gate p = x.x_uint32_array; 13007c478bd9Sstevel@tonic-gate for (i = 0; i < nelems; i++) { 13017c478bd9Sstevel@tonic-gate (void) snprintf(num, sizeof (num), 13027c478bd9Sstevel@tonic-gate "0x%x ", *p++); 13037c478bd9Sstevel@tonic-gate if (strcats(replacement, num)) { 13047c478bd9Sstevel@tonic-gate freestr(replacement); 13057c478bd9Sstevel@tonic-gate return (NULL); 13067c478bd9Sstevel@tonic-gate } 13077c478bd9Sstevel@tonic-gate } 13087c478bd9Sstevel@tonic-gate } 13097c478bd9Sstevel@tonic-gate break; 13107c478bd9Sstevel@tonic-gate 13117c478bd9Sstevel@tonic-gate case DATA_TYPE_INT64_ARRAY: { 13127c478bd9Sstevel@tonic-gate int64_t *p; 13137c478bd9Sstevel@tonic-gate (void) nvpair_value_int64_array(nvp, 13147c478bd9Sstevel@tonic-gate &x.x_int64_array, &nelems); 13157c478bd9Sstevel@tonic-gate p = x.x_int64_array; 13167c478bd9Sstevel@tonic-gate for (i = 0; i < nelems; i++) { 13177c478bd9Sstevel@tonic-gate (void) snprintf(num, sizeof (num), 13187c478bd9Sstevel@tonic-gate "%lld ", *p++); 13197c478bd9Sstevel@tonic-gate if (strcats(replacement, num)) { 13207c478bd9Sstevel@tonic-gate freestr(replacement); 13217c478bd9Sstevel@tonic-gate return (NULL); 13227c478bd9Sstevel@tonic-gate } 13237c478bd9Sstevel@tonic-gate } 13247c478bd9Sstevel@tonic-gate } 13257c478bd9Sstevel@tonic-gate break; 13267c478bd9Sstevel@tonic-gate 13277c478bd9Sstevel@tonic-gate case DATA_TYPE_UINT64_ARRAY: { 13287c478bd9Sstevel@tonic-gate uint64_t *p; 13297c478bd9Sstevel@tonic-gate (void) nvpair_value_uint64_array(nvp, 13307c478bd9Sstevel@tonic-gate &x.x_uint64_array, &nelems); 13317c478bd9Sstevel@tonic-gate p = x.x_uint64_array; 13327c478bd9Sstevel@tonic-gate for (i = 0; i < nelems; i++) { 13337c478bd9Sstevel@tonic-gate (void) snprintf(num, sizeof (num), 13347c478bd9Sstevel@tonic-gate "0x%llx ", *p++); 13357c478bd9Sstevel@tonic-gate if (strcats(replacement, num)) { 13367c478bd9Sstevel@tonic-gate freestr(replacement); 13377c478bd9Sstevel@tonic-gate return (NULL); 13387c478bd9Sstevel@tonic-gate } 13397c478bd9Sstevel@tonic-gate } 13407c478bd9Sstevel@tonic-gate } 13417c478bd9Sstevel@tonic-gate break; 13427c478bd9Sstevel@tonic-gate 13437c478bd9Sstevel@tonic-gate case DATA_TYPE_STRING_ARRAY: { 13447c478bd9Sstevel@tonic-gate char **p; 13457c478bd9Sstevel@tonic-gate (void) nvpair_value_string_array(nvp, 13467c478bd9Sstevel@tonic-gate &x.x_string_array, &nelems); 13477c478bd9Sstevel@tonic-gate p = x.x_string_array; 13487c478bd9Sstevel@tonic-gate for (i = 0; i < nelems; i++) { 13497c478bd9Sstevel@tonic-gate if (strcats(replacement, *p++) || 13507c478bd9Sstevel@tonic-gate strcats(replacement, " ")) { 13517c478bd9Sstevel@tonic-gate freestr(replacement); 13527c478bd9Sstevel@tonic-gate return (NULL); 13537c478bd9Sstevel@tonic-gate } 13547c478bd9Sstevel@tonic-gate } 13557c478bd9Sstevel@tonic-gate } 13567c478bd9Sstevel@tonic-gate break; 13577c478bd9Sstevel@tonic-gate 13587c478bd9Sstevel@tonic-gate case DATA_TYPE_HRTIME: 13597c478bd9Sstevel@tonic-gate (void) nvpair_value_hrtime(nvp, &x.x_time); 13607c478bd9Sstevel@tonic-gate (void) snprintf(num, sizeof (num), "0x%llx", x.x_time); 13617c478bd9Sstevel@tonic-gate if (strcats(replacement, num)) { 13627c478bd9Sstevel@tonic-gate freestr(replacement); 13637c478bd9Sstevel@tonic-gate return (NULL); 13647c478bd9Sstevel@tonic-gate } 13657c478bd9Sstevel@tonic-gate break; 13667c478bd9Sstevel@tonic-gate default: 13677c478bd9Sstevel@tonic-gate syslog(LOG_ERR, ATTR_UNSUPPORTED_ERR, 13687c478bd9Sstevel@tonic-gate sep->se_conf_file, sep->se_lineno, 13697c478bd9Sstevel@tonic-gate nvpair_type(nvp), token); 13707c478bd9Sstevel@tonic-gate freestr(replacement); 13717c478bd9Sstevel@tonic-gate return (NULL); 13727c478bd9Sstevel@tonic-gate } 13737c478bd9Sstevel@tonic-gate 13747c478bd9Sstevel@tonic-gate return (replacement); 13757c478bd9Sstevel@tonic-gate } 13767c478bd9Sstevel@tonic-gate 13777c478bd9Sstevel@tonic-gate /* 13787c478bd9Sstevel@tonic-gate * Expand macros in the command template provided in an event 13797c478bd9Sstevel@tonic-gate * specification with the data from the event or event attributes. 13807c478bd9Sstevel@tonic-gate * 13817c478bd9Sstevel@tonic-gate * Macros are introduced by the '$' character, with the macro 13827c478bd9Sstevel@tonic-gate * name being the following token separated by a SPACE or 13837c478bd9Sstevel@tonic-gate * TAB character. If the macro name is embedded in text, 13847c478bd9Sstevel@tonic-gate * it may be delineated by '${' and "}'. A backslash before 13857c478bd9Sstevel@tonic-gate * the '$' causes macro expansion not to occur. 13867c478bd9Sstevel@tonic-gate * 13877c478bd9Sstevel@tonic-gate * The following predefined macros are defined for each event: 13887c478bd9Sstevel@tonic-gate * 13897c478bd9Sstevel@tonic-gate * $vendor - the vendor string defining the event. 13907c478bd9Sstevel@tonic-gate * 13917c478bd9Sstevel@tonic-gate * $publisher - the publisher string defining the event. 13927c478bd9Sstevel@tonic-gate * 13937c478bd9Sstevel@tonic-gate * $class - the class string defining the event. 13947c478bd9Sstevel@tonic-gate * 13957c478bd9Sstevel@tonic-gate * $subclass - the subclass string defining the event. 13967c478bd9Sstevel@tonic-gate * 13977c478bd9Sstevel@tonic-gate * $sequence - the sequence number of the event. 13987c478bd9Sstevel@tonic-gate * 13997c478bd9Sstevel@tonic-gate * $timestamp - the timestamp of the event. 14007c478bd9Sstevel@tonic-gate * 14017c478bd9Sstevel@tonic-gate * 14027c478bd9Sstevel@tonic-gate * Macro names other than those predefined are compared against 14037c478bd9Sstevel@tonic-gate * the attribute list provided with the event. An attribute 14047c478bd9Sstevel@tonic-gate * with name matching the macro name causes the value of 14057c478bd9Sstevel@tonic-gate * of the attribute to be substituted as ASCII text on the 14067c478bd9Sstevel@tonic-gate * generated command line. 14077c478bd9Sstevel@tonic-gate * 14087c478bd9Sstevel@tonic-gate * Use of a macro for which no attribute with that name 14097c478bd9Sstevel@tonic-gate * is defined, or for which multiple attributes with that 14107c478bd9Sstevel@tonic-gate * name are provided, cause an error and the command is 14117c478bd9Sstevel@tonic-gate * not invoked. 14127c478bd9Sstevel@tonic-gate */ 14137c478bd9Sstevel@tonic-gate static int 14147c478bd9Sstevel@tonic-gate expand_macros(sysevent_t *ev, nvlist_t *nvlist, syseventtab_t *sep, 14157c478bd9Sstevel@tonic-gate str_t *line, sysevent_hdr_info_t *hdr) 14167c478bd9Sstevel@tonic-gate { 14177c478bd9Sstevel@tonic-gate char *p; 14187c478bd9Sstevel@tonic-gate int state; 14197c478bd9Sstevel@tonic-gate char *end; 14207c478bd9Sstevel@tonic-gate str_t *token; 14217c478bd9Sstevel@tonic-gate str_t *remainder; 14227c478bd9Sstevel@tonic-gate str_t *replacement; 14237c478bd9Sstevel@tonic-gate int count; 14247c478bd9Sstevel@tonic-gate int dollar_position; 14257c478bd9Sstevel@tonic-gate 14267c478bd9Sstevel@tonic-gate syseventd_print(DBG_MACRO, " expanding macros: '%s'\n", line->s_str); 14277c478bd9Sstevel@tonic-gate 14287c478bd9Sstevel@tonic-gate reset: 14297c478bd9Sstevel@tonic-gate state = 0; 14307c478bd9Sstevel@tonic-gate count = 0; 14317c478bd9Sstevel@tonic-gate for (p = line->s_str; *p != 0; p++, count++) { 14327c478bd9Sstevel@tonic-gate switch (state) { 14337c478bd9Sstevel@tonic-gate case 0: /* initial state */ 14347c478bd9Sstevel@tonic-gate if (*p == '\\') { 14357c478bd9Sstevel@tonic-gate state = 1; 14367c478bd9Sstevel@tonic-gate } else if (*p == '$') { 14377c478bd9Sstevel@tonic-gate dollar_position = count; 14387c478bd9Sstevel@tonic-gate state = 2; 14397c478bd9Sstevel@tonic-gate } 14407c478bd9Sstevel@tonic-gate break; 14417c478bd9Sstevel@tonic-gate case 1: /* skip characters */ 14427c478bd9Sstevel@tonic-gate state = 0; /* after backslash */ 14437c478bd9Sstevel@tonic-gate break; 14447c478bd9Sstevel@tonic-gate case 2: /* character after $ */ 14457c478bd9Sstevel@tonic-gate if (*p == '{') { 14467c478bd9Sstevel@tonic-gate token = snip_delimited_identifier(p+1, &end); 14477c478bd9Sstevel@tonic-gate } else { 14487c478bd9Sstevel@tonic-gate token = snip_identifier(p, &end); 14497c478bd9Sstevel@tonic-gate } 14507c478bd9Sstevel@tonic-gate if (token == NULL) 14517c478bd9Sstevel@tonic-gate goto failed; 14527c478bd9Sstevel@tonic-gate 14537c478bd9Sstevel@tonic-gate if ((remainder = initstr(128)) == NULL) { 14547c478bd9Sstevel@tonic-gate freestr(token); 14557c478bd9Sstevel@tonic-gate return (1); 14567c478bd9Sstevel@tonic-gate } 14577c478bd9Sstevel@tonic-gate if (strcopys(remainder, end)) { 14587c478bd9Sstevel@tonic-gate freestr(token); 14597c478bd9Sstevel@tonic-gate freestr(remainder); 14607c478bd9Sstevel@tonic-gate return (1); 14617c478bd9Sstevel@tonic-gate } 14627c478bd9Sstevel@tonic-gate replacement = find_macro_definition(ev, nvlist, 14637c478bd9Sstevel@tonic-gate sep, token->s_str, hdr); 14647c478bd9Sstevel@tonic-gate if (replacement == NULL) { 14657c478bd9Sstevel@tonic-gate freestr(token); 14667c478bd9Sstevel@tonic-gate freestr(remainder); 14677c478bd9Sstevel@tonic-gate return (1); 14687c478bd9Sstevel@tonic-gate } 14697c478bd9Sstevel@tonic-gate syseventd_print(DBG_MACRO, 14707c478bd9Sstevel@tonic-gate " '%s' expands to '%s'\n", 14717c478bd9Sstevel@tonic-gate token->s_str, replacement->s_str); 14727c478bd9Sstevel@tonic-gate 14737c478bd9Sstevel@tonic-gate strtrunc(line, dollar_position); 14747c478bd9Sstevel@tonic-gate if (strcats(line, replacement->s_str)) { 14757c478bd9Sstevel@tonic-gate freestr(token); 14767c478bd9Sstevel@tonic-gate freestr(replacement); 14777c478bd9Sstevel@tonic-gate freestr(remainder); 14787c478bd9Sstevel@tonic-gate return (1); 14797c478bd9Sstevel@tonic-gate } 14807c478bd9Sstevel@tonic-gate if (strcats(line, remainder->s_str)) { 14817c478bd9Sstevel@tonic-gate freestr(token); 14827c478bd9Sstevel@tonic-gate freestr(replacement); 14837c478bd9Sstevel@tonic-gate freestr(remainder); 14847c478bd9Sstevel@tonic-gate return (1); 14857c478bd9Sstevel@tonic-gate } 14867c478bd9Sstevel@tonic-gate 14877c478bd9Sstevel@tonic-gate syseventd_print(DBG_MACRO, 14887c478bd9Sstevel@tonic-gate " with macro expanded: '%s'\n", line->s_str); 14897c478bd9Sstevel@tonic-gate 14907c478bd9Sstevel@tonic-gate freestr(token); 14917c478bd9Sstevel@tonic-gate freestr(replacement); 14927c478bd9Sstevel@tonic-gate freestr(remainder); 14937c478bd9Sstevel@tonic-gate goto reset; 14947c478bd9Sstevel@tonic-gate } 14957c478bd9Sstevel@tonic-gate } 14967c478bd9Sstevel@tonic-gate 14977c478bd9Sstevel@tonic-gate failed: 14987c478bd9Sstevel@tonic-gate if (state != 0) { 14997c478bd9Sstevel@tonic-gate syslog(LOG_ERR, SYNTAX_ERR, sep->se_conf_file, sep->se_lineno); 15007c478bd9Sstevel@tonic-gate return (1); 15017c478bd9Sstevel@tonic-gate } 15027c478bd9Sstevel@tonic-gate 15037c478bd9Sstevel@tonic-gate return (0); 15047c478bd9Sstevel@tonic-gate } 15057c478bd9Sstevel@tonic-gate 15067c478bd9Sstevel@tonic-gate 15077c478bd9Sstevel@tonic-gate static void 15087c478bd9Sstevel@tonic-gate start_syseventconfd() 15097c478bd9Sstevel@tonic-gate { 15107c478bd9Sstevel@tonic-gate int err; 15117c478bd9Sstevel@tonic-gate 15127c478bd9Sstevel@tonic-gate err = system1("/usr/lib/sysevent/syseventconfd", 15137c478bd9Sstevel@tonic-gate "/usr/lib/sysevent/syseventconfd"); 15147c478bd9Sstevel@tonic-gate 15157c478bd9Sstevel@tonic-gate if (err != 0 && confd_err_msg_emitted == 0) { 15167c478bd9Sstevel@tonic-gate if (confd_state == CONFD_STATE_NOT_RUNNING) { 15177c478bd9Sstevel@tonic-gate syslog(LOG_ERR, SYSEVENTCONFD_START_ERR, 15187c478bd9Sstevel@tonic-gate strerror(errno)); 15197c478bd9Sstevel@tonic-gate } else { 15207c478bd9Sstevel@tonic-gate syslog(LOG_ERR, SYSEVENTCONFD_RESTART_ERR, 15217c478bd9Sstevel@tonic-gate strerror(errno)); 15227c478bd9Sstevel@tonic-gate } 15237c478bd9Sstevel@tonic-gate } 15247c478bd9Sstevel@tonic-gate } 15257c478bd9Sstevel@tonic-gate 15267c478bd9Sstevel@tonic-gate 15277c478bd9Sstevel@tonic-gate static int 15287c478bd9Sstevel@tonic-gate system1(const char *s_path, const char *s) 15297c478bd9Sstevel@tonic-gate { 15307c478bd9Sstevel@tonic-gate struct sigaction cbuf, ibuf, qbuf, ignore, dfl; 15317c478bd9Sstevel@tonic-gate sigset_t mask; 15327c478bd9Sstevel@tonic-gate sigset_t savemask; 15337c478bd9Sstevel@tonic-gate struct stat st; 15347c478bd9Sstevel@tonic-gate pid_t pid; 15357c478bd9Sstevel@tonic-gate int status, w; 15367c478bd9Sstevel@tonic-gate 15377c478bd9Sstevel@tonic-gate /* Check the requested command */ 15387c478bd9Sstevel@tonic-gate if (s == NULL) { 15397c478bd9Sstevel@tonic-gate errno = EINVAL; 15407c478bd9Sstevel@tonic-gate return (-1); 15417c478bd9Sstevel@tonic-gate } 15427c478bd9Sstevel@tonic-gate 15437c478bd9Sstevel@tonic-gate /* Check the ability to execute devfsadmd from this process */ 15447c478bd9Sstevel@tonic-gate if (stat(s_path, &st) < 0) { 15457c478bd9Sstevel@tonic-gate return (-1); 15467c478bd9Sstevel@tonic-gate } 15477c478bd9Sstevel@tonic-gate if (((geteuid() == st.st_uid) && ((st.st_mode & S_IXUSR) == 0)) || 15487c478bd9Sstevel@tonic-gate ((getegid() == st.st_gid) && ((st.st_mode & S_IXGRP) == 0)) || 15497c478bd9Sstevel@tonic-gate ((st.st_mode & S_IXOTH) == 0)) { 15507c478bd9Sstevel@tonic-gate errno = EPERM; 15517c478bd9Sstevel@tonic-gate return (-1); 15527c478bd9Sstevel@tonic-gate } 15537c478bd9Sstevel@tonic-gate 15547c478bd9Sstevel@tonic-gate /* 15557c478bd9Sstevel@tonic-gate * Block SIGCHLD and set up a default handler for the duration of the 15567c478bd9Sstevel@tonic-gate * system1 call. 15577c478bd9Sstevel@tonic-gate */ 15587c478bd9Sstevel@tonic-gate (void) sigemptyset(&mask); 15597c478bd9Sstevel@tonic-gate (void) sigaddset(&mask, SIGCHLD); 15607c478bd9Sstevel@tonic-gate (void) sigprocmask(SIG_BLOCK, &mask, &savemask); 15617c478bd9Sstevel@tonic-gate (void) memset(&dfl, 0, sizeof (dfl)); 15627c478bd9Sstevel@tonic-gate dfl.sa_handler = SIG_DFL; 15637c478bd9Sstevel@tonic-gate (void) sigaction(SIGCHLD, &dfl, &cbuf); 15647c478bd9Sstevel@tonic-gate 15657c478bd9Sstevel@tonic-gate /* Fork off the child process (using fork1(), because it's MT-safe) */ 15667c478bd9Sstevel@tonic-gate switch (pid = fork1()) { 15677c478bd9Sstevel@tonic-gate case -1: 15687c478bd9Sstevel@tonic-gate /* Error */ 15697c478bd9Sstevel@tonic-gate (void) sigaction(SIGCHLD, &cbuf, NULL); 15707c478bd9Sstevel@tonic-gate (void) sigprocmask(SIG_SETMASK, &savemask, NULL); 15717c478bd9Sstevel@tonic-gate return (-1); 15727c478bd9Sstevel@tonic-gate case 0: 15737c478bd9Sstevel@tonic-gate /* Set-up an initial signal mask for the child */ 15747c478bd9Sstevel@tonic-gate (void) sigemptyset(&mask); 15757c478bd9Sstevel@tonic-gate (void) sigprocmask(SIG_SETMASK, &mask, NULL); 1576bc9ec910Snakanon closefrom(3); 15777c478bd9Sstevel@tonic-gate (void) execl(s_path, s, (char *)0); 15787c478bd9Sstevel@tonic-gate _exit(-1); 15797c478bd9Sstevel@tonic-gate break; 15807c478bd9Sstevel@tonic-gate default: 15817c478bd9Sstevel@tonic-gate /* Parent */ 15827c478bd9Sstevel@tonic-gate break; 15837c478bd9Sstevel@tonic-gate } 15847c478bd9Sstevel@tonic-gate 15857c478bd9Sstevel@tonic-gate (void) memset(&ignore, 0, sizeof (ignore)); 15867c478bd9Sstevel@tonic-gate ignore.sa_handler = SIG_IGN; 15877c478bd9Sstevel@tonic-gate (void) sigaction(SIGINT, &ignore, &ibuf); 15887c478bd9Sstevel@tonic-gate (void) sigaction(SIGQUIT, &ignore, &qbuf); 15897c478bd9Sstevel@tonic-gate 15907c478bd9Sstevel@tonic-gate do { 15917c478bd9Sstevel@tonic-gate w = waitpid(pid, &status, 0); 15927c478bd9Sstevel@tonic-gate } while (w == -1 && errno == EINTR); 15937c478bd9Sstevel@tonic-gate 15947c478bd9Sstevel@tonic-gate (void) sigaction(SIGINT, &ibuf, NULL); 15957c478bd9Sstevel@tonic-gate (void) sigaction(SIGQUIT, &qbuf, NULL); 15967c478bd9Sstevel@tonic-gate 15977c478bd9Sstevel@tonic-gate (void) sigaction(SIGCHLD, &cbuf, NULL); 15987c478bd9Sstevel@tonic-gate (void) sigprocmask(SIG_SETMASK, &savemask, NULL); 15997c478bd9Sstevel@tonic-gate 16007c478bd9Sstevel@tonic-gate return ((w == -1)? w: status); 16017c478bd9Sstevel@tonic-gate } 16027c478bd9Sstevel@tonic-gate 16037c478bd9Sstevel@tonic-gate /* 16047c478bd9Sstevel@tonic-gate * Free all commands on the cmd queue 16057c478bd9Sstevel@tonic-gate */ 16067c478bd9Sstevel@tonic-gate static void 16077c478bd9Sstevel@tonic-gate abort_cmd_queue() 16087c478bd9Sstevel@tonic-gate { 16097c478bd9Sstevel@tonic-gate cmdqueue_t *cmd; 16107c478bd9Sstevel@tonic-gate cmdqueue_t *next; 16117c478bd9Sstevel@tonic-gate int nevents = 0; 16127c478bd9Sstevel@tonic-gate 16137c478bd9Sstevel@tonic-gate while ((cmd = cmdq) != NULL) { 16147c478bd9Sstevel@tonic-gate next = cmd->next; 16157c478bd9Sstevel@tonic-gate cmdq_cnt--; 16167c478bd9Sstevel@tonic-gate sysevent_free(cmd->event); 16177c478bd9Sstevel@tonic-gate sc_free(cmd, sizeof (cmdqueue_t)); 16187c478bd9Sstevel@tonic-gate cmdq = next; 16197c478bd9Sstevel@tonic-gate nevents++; 16207c478bd9Sstevel@tonic-gate } 16217c478bd9Sstevel@tonic-gate cmdq_tail = NULL; 16227c478bd9Sstevel@tonic-gate 16237c478bd9Sstevel@tonic-gate /* 16247c478bd9Sstevel@tonic-gate * Generate error msgs if events were discarded or 16257c478bd9Sstevel@tonic-gate * we are entering the disabled state. 16267c478bd9Sstevel@tonic-gate */ 16277c478bd9Sstevel@tonic-gate if (nevents > 0) { 16287c478bd9Sstevel@tonic-gate syslog(LOG_ERR, N_EVENTS_DISCARDED_ERR, nevents); 16297c478bd9Sstevel@tonic-gate } 16307c478bd9Sstevel@tonic-gate if (want_fini == 0) { 16317c478bd9Sstevel@tonic-gate confd_state = CONFD_STATE_DISABLED; 16327c478bd9Sstevel@tonic-gate syslog(LOG_ERR, SERVICE_DISABLED_MSG); 16337c478bd9Sstevel@tonic-gate } 16347c478bd9Sstevel@tonic-gate } 16357c478bd9Sstevel@tonic-gate 16367c478bd9Sstevel@tonic-gate /* 16377c478bd9Sstevel@tonic-gate * For a matching event specification, build the command to be 16387c478bd9Sstevel@tonic-gate * invoked in response to the event. Building the command involves 16397c478bd9Sstevel@tonic-gate * expanding macros supplied in the event specification command 16407c478bd9Sstevel@tonic-gate * with values from the actual event. These macros can be 16417c478bd9Sstevel@tonic-gate * the class/subclass/vendor/publisher strings, or arbitrary 16427c478bd9Sstevel@tonic-gate * attribute data attached to the event. 16437c478bd9Sstevel@tonic-gate * 16447c478bd9Sstevel@tonic-gate * This module does not invoke (fork/exec) the command itself, 16457c478bd9Sstevel@tonic-gate * since this module is running in the context of the syseventd 16467c478bd9Sstevel@tonic-gate * daemon, and fork/exec's done here interfere with the door 16477c478bd9Sstevel@tonic-gate * upcall delivering events from the kernel to the daemon. 16487c478bd9Sstevel@tonic-gate * Instead, we build a separate event and nvlist with the 16497c478bd9Sstevel@tonic-gate * attributes of the command to be invoked, and pass that on 16507c478bd9Sstevel@tonic-gate * to the syseventconfd daemon, which is basically a fork/exec 16517c478bd9Sstevel@tonic-gate * server on our behalf. 16527c478bd9Sstevel@tonic-gate * 16537c478bd9Sstevel@tonic-gate * Errors queuing the event are returned to syseventd with 16547c478bd9Sstevel@tonic-gate * EAGAIN, allowing syseventd to manage a limited number of 16557c478bd9Sstevel@tonic-gate * retries after a short delay. 16567c478bd9Sstevel@tonic-gate */ 16577c478bd9Sstevel@tonic-gate static int 16587c478bd9Sstevel@tonic-gate queue_event(sysevent_t *ev, syseventtab_t *sep, sysevent_hdr_info_t *hdr) 16597c478bd9Sstevel@tonic-gate { 16607c478bd9Sstevel@tonic-gate str_t *line; 16617c478bd9Sstevel@tonic-gate nvlist_t *nvlist; 1662*c7cb3c8bSToomas Soome char *argv0; 16637c478bd9Sstevel@tonic-gate sysevent_t *cmd_event; 16647c478bd9Sstevel@tonic-gate nvlist_t *cmd_nvlist; 16657c478bd9Sstevel@tonic-gate cmdqueue_t *new_cmd; 16667c478bd9Sstevel@tonic-gate 16677c478bd9Sstevel@tonic-gate if ((line = initstr(128)) == NULL) 16687c478bd9Sstevel@tonic-gate return (1); 16697c478bd9Sstevel@tonic-gate 16707c478bd9Sstevel@tonic-gate if ((argv0 = strrchr(sep->se_path, '/')) == NULL) { 16717c478bd9Sstevel@tonic-gate argv0 = sep->se_path; 16727c478bd9Sstevel@tonic-gate } else { 16737c478bd9Sstevel@tonic-gate argv0++; 16747c478bd9Sstevel@tonic-gate } 16757c478bd9Sstevel@tonic-gate if (strcopys(line, argv0)) { 16767c478bd9Sstevel@tonic-gate freestr(line); 16777c478bd9Sstevel@tonic-gate return (1); 16787c478bd9Sstevel@tonic-gate } 16797c478bd9Sstevel@tonic-gate 16807c478bd9Sstevel@tonic-gate if (sep->se_args) { 16817c478bd9Sstevel@tonic-gate if (strcats(line, " ")) { 16827c478bd9Sstevel@tonic-gate freestr(line); 16837c478bd9Sstevel@tonic-gate return (1); 16847c478bd9Sstevel@tonic-gate } 16857c478bd9Sstevel@tonic-gate if (strcats(line, sep->se_args)) { 16867c478bd9Sstevel@tonic-gate freestr(line); 16877c478bd9Sstevel@tonic-gate return (1); 16887c478bd9Sstevel@tonic-gate } 16897c478bd9Sstevel@tonic-gate 16907c478bd9Sstevel@tonic-gate if (sysevent_get_attr_list(ev, &nvlist) != 0) { 16917c478bd9Sstevel@tonic-gate syslog(LOG_ERR, GET_ATTR_LIST_ERR, 16927c478bd9Sstevel@tonic-gate sep->se_conf_file, sep->se_lineno, 16937c478bd9Sstevel@tonic-gate strerror(errno)); 16947c478bd9Sstevel@tonic-gate freestr(line); 16957c478bd9Sstevel@tonic-gate return (1); 16967c478bd9Sstevel@tonic-gate } 16977c478bd9Sstevel@tonic-gate if (expand_macros(ev, nvlist, sep, line, hdr)) { 16987c478bd9Sstevel@tonic-gate freestr(line); 1699aab83bb8SJosef 'Jeff' Sipek nvlist_free(nvlist); 17007c478bd9Sstevel@tonic-gate return (1); 17017c478bd9Sstevel@tonic-gate } 1702aab83bb8SJosef 'Jeff' Sipek nvlist_free(nvlist); 17037c478bd9Sstevel@tonic-gate } 17047c478bd9Sstevel@tonic-gate 17057c478bd9Sstevel@tonic-gate if (debug_level >= DBG_EXEC) { 17067c478bd9Sstevel@tonic-gate syseventd_print(DBG_EXEC, "%s, line %d: path = %s\n", 17077c478bd9Sstevel@tonic-gate sep->se_conf_file, sep->se_lineno, sep->se_path); 17087c478bd9Sstevel@tonic-gate syseventd_print(DBG_EXEC, " cmd = %s\n", line->s_str); 17097c478bd9Sstevel@tonic-gate } 17107c478bd9Sstevel@tonic-gate 17117c478bd9Sstevel@tonic-gate cmd_nvlist = NULL; 17127c478bd9Sstevel@tonic-gate if ((errno = nvlist_alloc(&cmd_nvlist, NV_UNIQUE_NAME, 0)) != 0) { 17137c478bd9Sstevel@tonic-gate freestr(line); 17147c478bd9Sstevel@tonic-gate syslog(LOG_ERR, NVLIST_ALLOC_ERR, 17157c478bd9Sstevel@tonic-gate sep->se_conf_file, sep->se_lineno, 17167c478bd9Sstevel@tonic-gate strerror(errno)); 17177c478bd9Sstevel@tonic-gate return (1); 17187c478bd9Sstevel@tonic-gate } 17197c478bd9Sstevel@tonic-gate 17207c478bd9Sstevel@tonic-gate if ((errno = nvlist_add_string(cmd_nvlist, "path", sep->se_path)) != 0) 17217c478bd9Sstevel@tonic-gate goto err; 17227c478bd9Sstevel@tonic-gate if ((errno = nvlist_add_string(cmd_nvlist, "cmd", line->s_str)) != 0) 17237c478bd9Sstevel@tonic-gate goto err; 17247c478bd9Sstevel@tonic-gate if ((errno = nvlist_add_string(cmd_nvlist, "file", 17257c478bd9Sstevel@tonic-gate sep->se_conf_file)) != 0) 17267c478bd9Sstevel@tonic-gate goto err; 17277c478bd9Sstevel@tonic-gate if ((errno = nvlist_add_int32(cmd_nvlist, "line", sep->se_lineno)) != 0) 17287c478bd9Sstevel@tonic-gate goto err; 17297c478bd9Sstevel@tonic-gate if ((errno = nvlist_add_string(cmd_nvlist, "user", sep->se_user)) != 0) 17307c478bd9Sstevel@tonic-gate goto err; 17317c478bd9Sstevel@tonic-gate 17327c478bd9Sstevel@tonic-gate if (sep->se_uid != (uid_t)0) { 17337c478bd9Sstevel@tonic-gate if ((errno = nvlist_add_int32(cmd_nvlist, "uid", 17347c478bd9Sstevel@tonic-gate sep->se_uid)) != 0) 17357c478bd9Sstevel@tonic-gate goto err; 17367c478bd9Sstevel@tonic-gate if ((errno = nvlist_add_int32(cmd_nvlist, "gid", 17377c478bd9Sstevel@tonic-gate sep->se_gid)) != 0) 17387c478bd9Sstevel@tonic-gate goto err; 17397c478bd9Sstevel@tonic-gate } 17407c478bd9Sstevel@tonic-gate 17417c478bd9Sstevel@tonic-gate cmd_event = sysevent_alloc_event(hdr->class, hdr->subclass, hdr->vendor, 17427c478bd9Sstevel@tonic-gate hdr->publisher, cmd_nvlist); 17437c478bd9Sstevel@tonic-gate if (cmd_event == NULL) { 17447c478bd9Sstevel@tonic-gate syslog(LOG_ERR, SYSEVENT_ALLOC_ERR, 17457c478bd9Sstevel@tonic-gate sep->se_conf_file, sep->se_lineno, 17467c478bd9Sstevel@tonic-gate strerror(errno)); 17477c478bd9Sstevel@tonic-gate nvlist_free(cmd_nvlist); 17487c478bd9Sstevel@tonic-gate freestr(line); 17497c478bd9Sstevel@tonic-gate return (1); 17507c478bd9Sstevel@tonic-gate } 17517c478bd9Sstevel@tonic-gate 17527c478bd9Sstevel@tonic-gate nvlist_free(cmd_nvlist); 17537c478bd9Sstevel@tonic-gate freestr(line); 17547c478bd9Sstevel@tonic-gate 17557c478bd9Sstevel@tonic-gate /* 17567c478bd9Sstevel@tonic-gate * Place cmd_event on queue to be transported to syseventconfd 17577c478bd9Sstevel@tonic-gate */ 17587c478bd9Sstevel@tonic-gate if ((new_cmd = sc_malloc(sizeof (cmdqueue_t))) == NULL) { 17597c478bd9Sstevel@tonic-gate sysevent_free(cmd_event); 17607c478bd9Sstevel@tonic-gate return (1); 17617c478bd9Sstevel@tonic-gate } 17627c478bd9Sstevel@tonic-gate new_cmd->event = cmd_event; 17637c478bd9Sstevel@tonic-gate new_cmd->next = NULL; 17647c478bd9Sstevel@tonic-gate (void) mutex_lock(&cmdq_lock); 17657c478bd9Sstevel@tonic-gate if (cmdq == NULL) { 17667c478bd9Sstevel@tonic-gate cmdq = new_cmd; 17677c478bd9Sstevel@tonic-gate } else { 17687c478bd9Sstevel@tonic-gate cmdq_tail->next = new_cmd; 17697c478bd9Sstevel@tonic-gate } 17707c478bd9Sstevel@tonic-gate cmdq_cnt++; 17717c478bd9Sstevel@tonic-gate cmdq_tail = new_cmd; 17727c478bd9Sstevel@tonic-gate 17737c478bd9Sstevel@tonic-gate /* 17747c478bd9Sstevel@tonic-gate * signal queue flush thread 17757c478bd9Sstevel@tonic-gate */ 17767c478bd9Sstevel@tonic-gate (void) cond_signal(&cmdq_cv); 17777c478bd9Sstevel@tonic-gate 17787c478bd9Sstevel@tonic-gate (void) mutex_unlock(&cmdq_lock); 17797c478bd9Sstevel@tonic-gate 17807c478bd9Sstevel@tonic-gate return (0); 17817c478bd9Sstevel@tonic-gate 17827c478bd9Sstevel@tonic-gate err: 17837c478bd9Sstevel@tonic-gate syslog(LOG_ERR, NVLIST_BUILD_ERR, 17847c478bd9Sstevel@tonic-gate sep->se_conf_file, sep->se_lineno, strerror(errno)); 17857c478bd9Sstevel@tonic-gate nvlist_free(cmd_nvlist); 17867c478bd9Sstevel@tonic-gate freestr(line); 17877c478bd9Sstevel@tonic-gate return (1); 17887c478bd9Sstevel@tonic-gate } 17897c478bd9Sstevel@tonic-gate 17907c478bd9Sstevel@tonic-gate 17917c478bd9Sstevel@tonic-gate static int 17927c478bd9Sstevel@tonic-gate transport_event(sysevent_t *event) 17937c478bd9Sstevel@tonic-gate { 17947c478bd9Sstevel@tonic-gate int rval; 17957c478bd9Sstevel@tonic-gate 17967c478bd9Sstevel@tonic-gate rval = sysevent_send_event(confd_handle, event); 17977c478bd9Sstevel@tonic-gate if (rval != 0) { 17987c478bd9Sstevel@tonic-gate switch (errno) { 17997c478bd9Sstevel@tonic-gate case EAGAIN: 18007c478bd9Sstevel@tonic-gate case EINTR: 18017c478bd9Sstevel@tonic-gate /* 18027c478bd9Sstevel@tonic-gate * syseventconfd daemon may be forking, stop 18037c478bd9Sstevel@tonic-gate * attempting to empty the queue momentarily. 18047c478bd9Sstevel@tonic-gate */ 18057c478bd9Sstevel@tonic-gate rval = errno; 18067c478bd9Sstevel@tonic-gate break; 18077c478bd9Sstevel@tonic-gate case ENOENT: 18087c478bd9Sstevel@tonic-gate case EBADF: 18097c478bd9Sstevel@tonic-gate /* 18107c478bd9Sstevel@tonic-gate * start/restart the syseventconfd daemon, 18117c478bd9Sstevel@tonic-gate * allowing for some delay when starting 18127c478bd9Sstevel@tonic-gate * up before it begins to reply. 18137c478bd9Sstevel@tonic-gate */ 18147c478bd9Sstevel@tonic-gate if (confd_state == CONFD_STATE_NOT_RUNNING || 18157c478bd9Sstevel@tonic-gate confd_state == CONFD_STATE_OK) { 18167c478bd9Sstevel@tonic-gate confd_state = CONFD_STATE_STARTED; 18177c478bd9Sstevel@tonic-gate start_syseventconfd(); 18187c478bd9Sstevel@tonic-gate confd_retries = 0; 18197c478bd9Sstevel@tonic-gate rval = EAGAIN; 18207c478bd9Sstevel@tonic-gate } else if (confd_state == CONFD_STATE_STARTED && 18217c478bd9Sstevel@tonic-gate confd_retries < 16) { 18227c478bd9Sstevel@tonic-gate if (++confd_retries == 16) { 18237c478bd9Sstevel@tonic-gate confd_state = CONFD_STATE_ERR; 18247c478bd9Sstevel@tonic-gate if (confd_err_msg_emitted == 0) { 18257c478bd9Sstevel@tonic-gate syslog(LOG_ERR, 18267c478bd9Sstevel@tonic-gate SYSEVENTCONFD_ERR); 18277c478bd9Sstevel@tonic-gate confd_err_msg_emitted = 1; 18287c478bd9Sstevel@tonic-gate } 18297c478bd9Sstevel@tonic-gate } 18307c478bd9Sstevel@tonic-gate rval = EAGAIN; 18317c478bd9Sstevel@tonic-gate } else { 18327c478bd9Sstevel@tonic-gate rval = errno; 18337c478bd9Sstevel@tonic-gate } 18347c478bd9Sstevel@tonic-gate break; 18357c478bd9Sstevel@tonic-gate default: 18367c478bd9Sstevel@tonic-gate syslog(LOG_ERR, SYSEVENTCONFD_TRAN_ERR, 18377c478bd9Sstevel@tonic-gate strerror(errno)); 18387c478bd9Sstevel@tonic-gate rval = errno; 18397c478bd9Sstevel@tonic-gate break; 18407c478bd9Sstevel@tonic-gate } 18417c478bd9Sstevel@tonic-gate } else if (confd_state != CONFD_STATE_OK) { 18427c478bd9Sstevel@tonic-gate if (confd_state == CONFD_STATE_ERR) { 18437c478bd9Sstevel@tonic-gate syslog(LOG_ERR, SYSEVENTCONFD_OK); 18447c478bd9Sstevel@tonic-gate confd_err_msg_emitted = 0; 18457c478bd9Sstevel@tonic-gate } 18467c478bd9Sstevel@tonic-gate confd_state = CONFD_STATE_OK; 18477c478bd9Sstevel@tonic-gate confd_retries = 0; 18487c478bd9Sstevel@tonic-gate confd_err_msg_emitted = 0; 18497c478bd9Sstevel@tonic-gate } 18507c478bd9Sstevel@tonic-gate return (rval); 18517c478bd9Sstevel@tonic-gate } 18527c478bd9Sstevel@tonic-gate 18537c478bd9Sstevel@tonic-gate 18547c478bd9Sstevel@tonic-gate /* 18557c478bd9Sstevel@tonic-gate * Send events on queue to syseventconfd daemon. We queue events 18567c478bd9Sstevel@tonic-gate * here since the daemon is unable to handle events during an 18577c478bd9Sstevel@tonic-gate * active fork/exec, returning EAGAIN as a result. It is grossly 18587c478bd9Sstevel@tonic-gate * inefficient to bounce these events back to syseventd, so 18597c478bd9Sstevel@tonic-gate * we queue them here for delivery. 18607c478bd9Sstevel@tonic-gate * 18617c478bd9Sstevel@tonic-gate * EAGAIN/EINTR don't indicate errors with the transport to 18627c478bd9Sstevel@tonic-gate * syseventconfd itself, just the daemon is busy or some 18637c478bd9Sstevel@tonic-gate * other transient difficulty. We retry EBADF and other errors 18647c478bd9Sstevel@tonic-gate * for some time, then eventually give up - something's broken. 18657c478bd9Sstevel@tonic-gate * 18667c478bd9Sstevel@tonic-gate * Error handling strategy: 18677c478bd9Sstevel@tonic-gate * If we're trying to shut down and the syseventconfd daemon isn't 18687c478bd9Sstevel@tonic-gate * responding, abort the queue so we don't cause the fini to hang 18697c478bd9Sstevel@tonic-gate * forever. Otherwise, EAGAIN/EINTR are retried forever, as 18707c478bd9Sstevel@tonic-gate * we presume the daemon is active but either busy or some transient 18717c478bd9Sstevel@tonic-gate * state is preventing the transport. We make considerable effort 18727c478bd9Sstevel@tonic-gate * to retry EBADF since the daemon may take some time to come up when 18737c478bd9Sstevel@tonic-gate * restarted so don't want to give up too easily. Once we enter 18747c478bd9Sstevel@tonic-gate * the DISABLED state, we stop handling events altogther to 18757c478bd9Sstevel@tonic-gate * avoid thrashing the system if the syseventconfd binary is 18767c478bd9Sstevel@tonic-gate * corrupted or missing. This state can be cleared by issuing 18777c478bd9Sstevel@tonic-gate * a HUP signal to the syseventd daemon. For errors other than 18787c478bd9Sstevel@tonic-gate * EAGAIN/EINTR/EBADF, we just drop the event and if we get 18797c478bd9Sstevel@tonic-gate * a certain number of these in a row, we enter the DISABLED 18807c478bd9Sstevel@tonic-gate * state. 18817c478bd9Sstevel@tonic-gate */ 18827c478bd9Sstevel@tonic-gate 18837c478bd9Sstevel@tonic-gate static void 18847c478bd9Sstevel@tonic-gate transport_queued_events() 18857c478bd9Sstevel@tonic-gate { 18867c478bd9Sstevel@tonic-gate int rval; 18877c478bd9Sstevel@tonic-gate cmdqueue_t *cmd; 18887c478bd9Sstevel@tonic-gate 18897c478bd9Sstevel@tonic-gate (void) mutex_lock(&cmdq_lock); 18907c478bd9Sstevel@tonic-gate while (cmdq != NULL) { 18917c478bd9Sstevel@tonic-gate cmd = cmdq; 18927c478bd9Sstevel@tonic-gate (void) mutex_unlock(&cmdq_lock); 18937c478bd9Sstevel@tonic-gate rval = transport_event(cmd->event); 18947c478bd9Sstevel@tonic-gate (void) mutex_lock(&cmdq_lock); 18957c478bd9Sstevel@tonic-gate if (rval != 0) { 18967c478bd9Sstevel@tonic-gate switch (rval) { 18977c478bd9Sstevel@tonic-gate case EAGAIN: 18987c478bd9Sstevel@tonic-gate case EINTR: 18997c478bd9Sstevel@tonic-gate /* 19007c478bd9Sstevel@tonic-gate * Limit retries in the case of fini 19017c478bd9Sstevel@tonic-gate */ 19027c478bd9Sstevel@tonic-gate if (want_fini) { 19037c478bd9Sstevel@tonic-gate if (++transport_retries == 16) { 19047c478bd9Sstevel@tonic-gate abort_cmd_queue(); 19057c478bd9Sstevel@tonic-gate } 19067c478bd9Sstevel@tonic-gate } 19077c478bd9Sstevel@tonic-gate (void) mutex_unlock(&cmdq_lock); 19087c478bd9Sstevel@tonic-gate return; 19097c478bd9Sstevel@tonic-gate case EBADF: 19107c478bd9Sstevel@tonic-gate /* 19117c478bd9Sstevel@tonic-gate * retry up to 16 times 19127c478bd9Sstevel@tonic-gate */ 19137c478bd9Sstevel@tonic-gate if (want_fini || ++transport_retries == 16) { 19147c478bd9Sstevel@tonic-gate abort_cmd_queue(); 19157c478bd9Sstevel@tonic-gate } 19167c478bd9Sstevel@tonic-gate (void) mutex_unlock(&cmdq_lock); 19177c478bd9Sstevel@tonic-gate return; 19187c478bd9Sstevel@tonic-gate default: 19197c478bd9Sstevel@tonic-gate /* 19207c478bd9Sstevel@tonic-gate * After 16 sequential errors, give up 19217c478bd9Sstevel@tonic-gate */ 19227c478bd9Sstevel@tonic-gate if (++transport_retries == 16) { 19237c478bd9Sstevel@tonic-gate abort_cmd_queue(); 19247c478bd9Sstevel@tonic-gate (void) mutex_unlock(&cmdq_lock); 19257c478bd9Sstevel@tonic-gate return; 19267c478bd9Sstevel@tonic-gate } 19277c478bd9Sstevel@tonic-gate /* 19287c478bd9Sstevel@tonic-gate * We don't retry these errors, we 19297c478bd9Sstevel@tonic-gate * fall through to remove this event 19307c478bd9Sstevel@tonic-gate * from the queue. 19317c478bd9Sstevel@tonic-gate */ 19327c478bd9Sstevel@tonic-gate break; 19337c478bd9Sstevel@tonic-gate } 19347c478bd9Sstevel@tonic-gate } else { 19357c478bd9Sstevel@tonic-gate transport_retries = 0; 19367c478bd9Sstevel@tonic-gate } 19377c478bd9Sstevel@tonic-gate 19387c478bd9Sstevel@tonic-gate /* 19397c478bd9Sstevel@tonic-gate * Take completed event off queue 19407c478bd9Sstevel@tonic-gate */ 19417c478bd9Sstevel@tonic-gate cmdq_cnt--; 19427c478bd9Sstevel@tonic-gate cmdq = cmdq->next; 19437c478bd9Sstevel@tonic-gate if (cmdq == NULL) { 19447c478bd9Sstevel@tonic-gate cmdq_tail = NULL; 19457c478bd9Sstevel@tonic-gate } 19467c478bd9Sstevel@tonic-gate (void) mutex_unlock(&cmdq_lock); 19477c478bd9Sstevel@tonic-gate sysevent_free(cmd->event); 19487c478bd9Sstevel@tonic-gate sc_free(cmd, sizeof (cmdqueue_t)); 19497c478bd9Sstevel@tonic-gate (void) mutex_lock(&cmdq_lock); 19507c478bd9Sstevel@tonic-gate } 19517c478bd9Sstevel@tonic-gate 19527c478bd9Sstevel@tonic-gate (void) mutex_unlock(&cmdq_lock); 19537c478bd9Sstevel@tonic-gate } 19547c478bd9Sstevel@tonic-gate 19557c478bd9Sstevel@tonic-gate 19567c478bd9Sstevel@tonic-gate static void 19577c478bd9Sstevel@tonic-gate queue_flush_thr() 19587c478bd9Sstevel@tonic-gate { 19597c478bd9Sstevel@tonic-gate int n; 19607c478bd9Sstevel@tonic-gate 19617c478bd9Sstevel@tonic-gate (void) mutex_lock(&cmdq_lock); 19627c478bd9Sstevel@tonic-gate for (;;) { 19637c478bd9Sstevel@tonic-gate while (cmdq_cnt == 0 && want_fini == 0) { 19647c478bd9Sstevel@tonic-gate (void) cond_wait(&cmdq_cv, &cmdq_lock); 19657c478bd9Sstevel@tonic-gate } 19667c478bd9Sstevel@tonic-gate if (cmdq_cnt == 0 && want_fini) { 19677c478bd9Sstevel@tonic-gate (void) cond_signal(&cmdq_thr_cv); 19687c478bd9Sstevel@tonic-gate (void) mutex_unlock(&cmdq_lock); 19697c478bd9Sstevel@tonic-gate thr_exit(NULL); 19707c478bd9Sstevel@tonic-gate /*NOTREACHED*/ 19717c478bd9Sstevel@tonic-gate } 19727c478bd9Sstevel@tonic-gate (void) mutex_unlock(&cmdq_lock); 19737c478bd9Sstevel@tonic-gate transport_queued_events(); 19747c478bd9Sstevel@tonic-gate (void) mutex_lock(&cmdq_lock); 19757c478bd9Sstevel@tonic-gate if (cmdq_cnt != 0) { 19767c478bd9Sstevel@tonic-gate (void) mutex_unlock(&cmdq_lock); 19777c478bd9Sstevel@tonic-gate if (want_fini == 0 && confd_err_msg_emitted) { 19787c478bd9Sstevel@tonic-gate for (n = 0; n < 60; n++) { 19797c478bd9Sstevel@tonic-gate (void) sleep(1); 19807c478bd9Sstevel@tonic-gate if (want_fini) 19817c478bd9Sstevel@tonic-gate break; 19827c478bd9Sstevel@tonic-gate } 19837c478bd9Sstevel@tonic-gate } else { 19847c478bd9Sstevel@tonic-gate (void) sleep(1); 19857c478bd9Sstevel@tonic-gate } 19867c478bd9Sstevel@tonic-gate (void) mutex_lock(&cmdq_lock); 19877c478bd9Sstevel@tonic-gate } 19887c478bd9Sstevel@tonic-gate } 19897c478bd9Sstevel@tonic-gate } 19907c478bd9Sstevel@tonic-gate 19917c478bd9Sstevel@tonic-gate 19927c478bd9Sstevel@tonic-gate /* 19937c478bd9Sstevel@tonic-gate * syseventd daemon module event handler 19947c478bd9Sstevel@tonic-gate * 19957c478bd9Sstevel@tonic-gate * The syseventd daemon calls this handler with each event 19967c478bd9Sstevel@tonic-gate * for this module to handle the event as appropriate. 19977c478bd9Sstevel@tonic-gate * The task of this module is to compare the event's 19987c478bd9Sstevel@tonic-gate * class/subclass/publisher/vendor against the list of 19997c478bd9Sstevel@tonic-gate * event specifications provided in the installed 20007c478bd9Sstevel@tonic-gate * sysevent.conf files. Build and execute the 20017c478bd9Sstevel@tonic-gate * defined command for that event specification 20027c478bd9Sstevel@tonic-gate * for each match. 20037c478bd9Sstevel@tonic-gate * 20047c478bd9Sstevel@tonic-gate * Events are matched against the class, subclass, vendor 20057c478bd9Sstevel@tonic-gate * and publisher specifications. Any field not to be matched 20067c478bd9Sstevel@tonic-gate * against an event should be set to '-'. A specification 20077c478bd9Sstevel@tonic-gate * of '- - - -' generates a match against every event. 20087c478bd9Sstevel@tonic-gate */ 20097c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 20107c478bd9Sstevel@tonic-gate static int 20117c478bd9Sstevel@tonic-gate sysevent_conf_event(sysevent_t *ev, int flag) 20127c478bd9Sstevel@tonic-gate { 20137c478bd9Sstevel@tonic-gate int ret = 0; 20147c478bd9Sstevel@tonic-gate char *vendor; 20157c478bd9Sstevel@tonic-gate char *publisher; 20167c478bd9Sstevel@tonic-gate char *class; 20177c478bd9Sstevel@tonic-gate char *subclass; 20187c478bd9Sstevel@tonic-gate syseventtab_t *sep; 20197c478bd9Sstevel@tonic-gate sysevent_hdr_info_t hdr; 20207c478bd9Sstevel@tonic-gate uint64_t seq; 20217c478bd9Sstevel@tonic-gate hrtime_t ts; 20227c478bd9Sstevel@tonic-gate 20237c478bd9Sstevel@tonic-gate /* 20247c478bd9Sstevel@tonic-gate * If we've been completely unable to communicate with 20257c478bd9Sstevel@tonic-gate * syseventconfd, there's not much we can do. 20267c478bd9Sstevel@tonic-gate */ 20277c478bd9Sstevel@tonic-gate if (confd_state == CONFD_STATE_DISABLED) { 20287c478bd9Sstevel@tonic-gate return (0); 20297c478bd9Sstevel@tonic-gate } 20307c478bd9Sstevel@tonic-gate 20317c478bd9Sstevel@tonic-gate /* 20327c478bd9Sstevel@tonic-gate * sysevent_get_seq(ev) < ev_seq): 20337c478bd9Sstevel@tonic-gate * an event we have played before, ignore it 20347c478bd9Sstevel@tonic-gate * sysevent_get_seq(ev) == ev_seq): 20357c478bd9Sstevel@tonic-gate * ev_nretries > 0, an event being retried 20367c478bd9Sstevel@tonic-gate * sysevent_get_seq(ev) > ev_seq): 20377c478bd9Sstevel@tonic-gate * a new event 20387c478bd9Sstevel@tonic-gate */ 20397c478bd9Sstevel@tonic-gate if (debug_level >= DBG_EVENTS) { 20407c478bd9Sstevel@tonic-gate if (sysevent_get_seq(ev) == ev_seq && ev_nretries > 0) { 20417c478bd9Sstevel@tonic-gate syseventd_print(DBG_EVENTS, 20427c478bd9Sstevel@tonic-gate "sequence: %lld/%lld, retry %d\n", 20437c478bd9Sstevel@tonic-gate sysevent_get_seq(ev), ev_seq, ev_nretries); 20447c478bd9Sstevel@tonic-gate } else if (sysevent_get_seq(ev) > ev_seq) { 20457c478bd9Sstevel@tonic-gate syseventd_print(DBG_EVENTS, 20467c478bd9Sstevel@tonic-gate "sequence: %lld/%lld\n", 20477c478bd9Sstevel@tonic-gate sysevent_get_seq(ev), ev_seq); 20487c478bd9Sstevel@tonic-gate } 20497c478bd9Sstevel@tonic-gate } 20507c478bd9Sstevel@tonic-gate 20517c478bd9Sstevel@tonic-gate seq = sysevent_get_seq(ev); 20527c478bd9Sstevel@tonic-gate sysevent_get_time(ev, &ts); 20537c478bd9Sstevel@tonic-gate 20547c478bd9Sstevel@tonic-gate if (seq > ev_seq || ts > ev_ts) { 20557c478bd9Sstevel@tonic-gate ev_nretries = 0; 20567c478bd9Sstevel@tonic-gate } else if (first_event == 0 && 20577c478bd9Sstevel@tonic-gate (((seq < ev_seq) || (seq == 0 && ts > ev_ts)) || 20587c478bd9Sstevel@tonic-gate (seq == ev_seq && ev_nretries == 0))) { 20597c478bd9Sstevel@tonic-gate syseventd_print(DBG_TEST, 20607c478bd9Sstevel@tonic-gate "out-of-order sequence: received %lld/0x%llx, " 20617c478bd9Sstevel@tonic-gate "expected %lld/0x%llx\n", seq, ts, ev_seq+1, ev_ts); 20627c478bd9Sstevel@tonic-gate return (ret); 20637c478bd9Sstevel@tonic-gate } 20647c478bd9Sstevel@tonic-gate 20657c478bd9Sstevel@tonic-gate ev_ts = ts; 20667c478bd9Sstevel@tonic-gate ev_seq = seq; 20677c478bd9Sstevel@tonic-gate first_event = 0; 20687c478bd9Sstevel@tonic-gate 20697c478bd9Sstevel@tonic-gate /* 20707c478bd9Sstevel@tonic-gate * sysevent_get_vendor_name() and sysevent_get_pub_name() 20717c478bd9Sstevel@tonic-gate * allocate strings which must be freed. 20727c478bd9Sstevel@tonic-gate */ 20737c478bd9Sstevel@tonic-gate vendor = sysevent_get_vendor_name(ev); 20747c478bd9Sstevel@tonic-gate publisher = sysevent_get_pub_name(ev); 20757c478bd9Sstevel@tonic-gate class = sysevent_get_class_name(ev); 20767c478bd9Sstevel@tonic-gate subclass = sysevent_get_subclass_name(ev); 20777c478bd9Sstevel@tonic-gate 20787c478bd9Sstevel@tonic-gate if (vendor == NULL || publisher == NULL) { 20797c478bd9Sstevel@tonic-gate syseventd_print(DBG_EVENTS, "Short on memory with vendor " 20807c478bd9Sstevel@tonic-gate "and/or publisher string generation\n"); 20817c478bd9Sstevel@tonic-gate /* Temporary short on memory */ 20827c478bd9Sstevel@tonic-gate ev_nretries++; 20837c478bd9Sstevel@tonic-gate free(publisher); 20847c478bd9Sstevel@tonic-gate free(vendor); 20857c478bd9Sstevel@tonic-gate return (EAGAIN); 20867c478bd9Sstevel@tonic-gate } 20877c478bd9Sstevel@tonic-gate 20887c478bd9Sstevel@tonic-gate syseventd_print(DBG_EVENTS, 20897c478bd9Sstevel@tonic-gate "%s event %lld: vendor='%s' publisher='%s' class='%s' " 20907c478bd9Sstevel@tonic-gate "subclass='%s'\n", whoami, sysevent_get_seq(ev), vendor, 20917c478bd9Sstevel@tonic-gate publisher, class, subclass); 20927c478bd9Sstevel@tonic-gate 20937c478bd9Sstevel@tonic-gate for (sep = syseventtab; sep; sep = sep->se_next) { 20947c478bd9Sstevel@tonic-gate if (strcmp(sep->se_vendor, "-") != 0) { 20957c478bd9Sstevel@tonic-gate if (strcmp(sep->se_vendor, vendor) != 0) 20967c478bd9Sstevel@tonic-gate continue; 20977c478bd9Sstevel@tonic-gate } 20987c478bd9Sstevel@tonic-gate if (strcmp(sep->se_publisher, "-") != 0) { 20997c478bd9Sstevel@tonic-gate if (strcmp(sep->se_publisher, publisher) != 0) 21007c478bd9Sstevel@tonic-gate continue; 21017c478bd9Sstevel@tonic-gate } 21027c478bd9Sstevel@tonic-gate if (strcmp(sep->se_class, "-") != 0) { 21037c478bd9Sstevel@tonic-gate if (strcmp(sep->se_class, class) != 0) 21047c478bd9Sstevel@tonic-gate continue; 21057c478bd9Sstevel@tonic-gate } 21067c478bd9Sstevel@tonic-gate if (strcmp(sep->se_subclass, "-") != 0) { 21077c478bd9Sstevel@tonic-gate if (strcmp(sep->se_subclass, subclass) != 0) 21087c478bd9Sstevel@tonic-gate continue; 21097c478bd9Sstevel@tonic-gate } 21107c478bd9Sstevel@tonic-gate syseventd_print(DBG_MATCHES, " event match: %s, line %d\n", 21117c478bd9Sstevel@tonic-gate sep->se_conf_file, sep->se_lineno); 21127c478bd9Sstevel@tonic-gate hdr.class = class; 21137c478bd9Sstevel@tonic-gate hdr.subclass = subclass; 21147c478bd9Sstevel@tonic-gate hdr.vendor = vendor; 21157c478bd9Sstevel@tonic-gate hdr.publisher = publisher; 21167c478bd9Sstevel@tonic-gate if ((ret = queue_event(ev, sep, &hdr)) != 0) 21177c478bd9Sstevel@tonic-gate break; 21187c478bd9Sstevel@tonic-gate } 21197c478bd9Sstevel@tonic-gate 21207c478bd9Sstevel@tonic-gate if (ret == 0) { 21217c478bd9Sstevel@tonic-gate ev_nretries = 0; 21227c478bd9Sstevel@tonic-gate } else { 21237c478bd9Sstevel@tonic-gate /* 21247c478bd9Sstevel@tonic-gate * Ask syseventd to retry any failed event. If we have 21257c478bd9Sstevel@tonic-gate * reached the limit on retries, emit a msg that we're 21267c478bd9Sstevel@tonic-gate * not going to be able to service it. 21277c478bd9Sstevel@tonic-gate */ 21287c478bd9Sstevel@tonic-gate if (ev_nretries == SE_MAX_RETRY_LIMIT) { 21297c478bd9Sstevel@tonic-gate syslog(LOG_ERR, SYSEVENT_SEND_ERR, 21307c478bd9Sstevel@tonic-gate sep->se_conf_file, sep->se_lineno, errno); 21317c478bd9Sstevel@tonic-gate } else { 21327c478bd9Sstevel@tonic-gate syseventd_print(DBG_TEST, "%s event %lld: " 21337c478bd9Sstevel@tonic-gate "'%s' '%s' '%s' '%s - errno %d, retry %d\n", 21347c478bd9Sstevel@tonic-gate whoami, sysevent_get_seq(ev), vendor, 21357c478bd9Sstevel@tonic-gate publisher, class, subclass, errno, ev_nretries); 21367c478bd9Sstevel@tonic-gate } 21377c478bd9Sstevel@tonic-gate ret = EAGAIN; 21387c478bd9Sstevel@tonic-gate ev_nretries++; 21397c478bd9Sstevel@tonic-gate } 21407c478bd9Sstevel@tonic-gate 21417c478bd9Sstevel@tonic-gate free(publisher); 21427c478bd9Sstevel@tonic-gate free(vendor); 21437c478bd9Sstevel@tonic-gate 21447c478bd9Sstevel@tonic-gate return (ret); 21457c478bd9Sstevel@tonic-gate } 21467c478bd9Sstevel@tonic-gate 21477c478bd9Sstevel@tonic-gate /* 21487c478bd9Sstevel@tonic-gate * syseventd daemon module initialization 21497c478bd9Sstevel@tonic-gate */ 21507c478bd9Sstevel@tonic-gate struct slm_mod_ops * 21517c478bd9Sstevel@tonic-gate slm_init() 21527c478bd9Sstevel@tonic-gate { 21537c478bd9Sstevel@tonic-gate char lock_file[PATH_MAX+1]; 21547c478bd9Sstevel@tonic-gate int lock_fd; 21557c478bd9Sstevel@tonic-gate int err; 21567c478bd9Sstevel@tonic-gate 21577c478bd9Sstevel@tonic-gate /* 21587c478bd9Sstevel@tonic-gate * This functionality is not supported in the mini-root 21597c478bd9Sstevel@tonic-gate * environment, ie install. If root_dir is set, implying 21607c478bd9Sstevel@tonic-gate * install, we quietly fail. Return dummy ops rather 21617c478bd9Sstevel@tonic-gate * than NULL to avoid error msgs out of syseventd. 21627c478bd9Sstevel@tonic-gate */ 21637c478bd9Sstevel@tonic-gate if (strcmp(root_dir, "") != 0) { 21647c478bd9Sstevel@tonic-gate return (&sysevent_conf_dummy_mod_ops); 21657c478bd9Sstevel@tonic-gate } 21667c478bd9Sstevel@tonic-gate 21677c478bd9Sstevel@tonic-gate ev_nretries = 0; 21687c478bd9Sstevel@tonic-gate first_event = 1; 21697c478bd9Sstevel@tonic-gate 21707c478bd9Sstevel@tonic-gate /* 21717c478bd9Sstevel@tonic-gate * Initialize the channel to syseventconfd 21727c478bd9Sstevel@tonic-gate */ 21737c478bd9Sstevel@tonic-gate confd_handle = sysevent_open_channel_alt(SYSEVENTCONFD_SERVICE_DOOR); 21747c478bd9Sstevel@tonic-gate if (confd_handle == NULL) { 21757c478bd9Sstevel@tonic-gate syslog(LOG_ERR, CHANNEL_OPEN_ERR); 21767c478bd9Sstevel@tonic-gate return (NULL); 21777c478bd9Sstevel@tonic-gate } 21787c478bd9Sstevel@tonic-gate 21797c478bd9Sstevel@tonic-gate if (sysevent_bind_publisher(confd_handle) != 0) { 21807c478bd9Sstevel@tonic-gate if (errno == EBUSY) { 21817c478bd9Sstevel@tonic-gate sysevent_cleanup_publishers(confd_handle); 21827c478bd9Sstevel@tonic-gate if (sysevent_bind_publisher(confd_handle) != 0) { 21837c478bd9Sstevel@tonic-gate sysevent_close_channel(confd_handle); 21847c478bd9Sstevel@tonic-gate return (NULL); 21857c478bd9Sstevel@tonic-gate } 21867c478bd9Sstevel@tonic-gate } 21877c478bd9Sstevel@tonic-gate } 21887c478bd9Sstevel@tonic-gate 21897c478bd9Sstevel@tonic-gate sysevent_cleanup_subscribers(confd_handle); 21907c478bd9Sstevel@tonic-gate 21917c478bd9Sstevel@tonic-gate cmdq = NULL; 21927c478bd9Sstevel@tonic-gate cmdq_tail = NULL; 21937c478bd9Sstevel@tonic-gate cmdq_cnt = 0; 21947c478bd9Sstevel@tonic-gate want_fini = 0; 21957c478bd9Sstevel@tonic-gate confd_err_msg_emitted = 0; 21967c478bd9Sstevel@tonic-gate if (confd_state != CONFD_STATE_OK) { 21977c478bd9Sstevel@tonic-gate confd_state = CONFD_STATE_NOT_RUNNING; 21987c478bd9Sstevel@tonic-gate } 21997c478bd9Sstevel@tonic-gate 22007c478bd9Sstevel@tonic-gate confd_retries = 0; 22017c478bd9Sstevel@tonic-gate transport_retries = 0; 22027c478bd9Sstevel@tonic-gate 22037c478bd9Sstevel@tonic-gate (void) mutex_init(&cmdq_lock, USYNC_THREAD, NULL); 22047c478bd9Sstevel@tonic-gate (void) cond_init(&cmdq_cv, USYNC_THREAD, NULL); 22057c478bd9Sstevel@tonic-gate (void) cond_init(&cmdq_thr_cv, USYNC_THREAD, NULL); 22067c478bd9Sstevel@tonic-gate 22077c478bd9Sstevel@tonic-gate /* 22087c478bd9Sstevel@tonic-gate * Create thread to flush cmd queue 22097c478bd9Sstevel@tonic-gate */ 2210*c7cb3c8bSToomas Soome if ((err = thr_create(NULL, 0, (void *(*)(void*))queue_flush_thr, 2211*c7cb3c8bSToomas Soome NULL, 0, &cmdq_thr_id)) != 0) { 22127c478bd9Sstevel@tonic-gate syslog(LOG_ERR, THR_CREATE_ERR, strerror(err)); 22137c478bd9Sstevel@tonic-gate sysevent_close_channel(confd_handle); 22147c478bd9Sstevel@tonic-gate confd_handle = NULL; 22157c478bd9Sstevel@tonic-gate (void) mutex_destroy(&cmdq_lock); 22167c478bd9Sstevel@tonic-gate (void) cond_destroy(&cmdq_cv); 22177c478bd9Sstevel@tonic-gate (void) cond_destroy(&cmdq_thr_cv); 22187c478bd9Sstevel@tonic-gate return (NULL); 22197c478bd9Sstevel@tonic-gate } 22207c478bd9Sstevel@tonic-gate 22217c478bd9Sstevel@tonic-gate if ((lock_fd = enter_lock(lock_file)) == -1) { 22227c478bd9Sstevel@tonic-gate (void) thr_join(cmdq_thr_id, NULL, NULL); 22237c478bd9Sstevel@tonic-gate sysevent_close_channel(confd_handle); 22247c478bd9Sstevel@tonic-gate confd_handle = NULL; 22257c478bd9Sstevel@tonic-gate (void) mutex_destroy(&cmdq_lock); 22267c478bd9Sstevel@tonic-gate (void) cond_destroy(&cmdq_cv); 22277c478bd9Sstevel@tonic-gate (void) cond_destroy(&cmdq_thr_cv); 22287c478bd9Sstevel@tonic-gate return (NULL); 22297c478bd9Sstevel@tonic-gate } 22307c478bd9Sstevel@tonic-gate 22317c478bd9Sstevel@tonic-gate build_event_table(); 22327c478bd9Sstevel@tonic-gate exit_lock(lock_fd, lock_file); 22337c478bd9Sstevel@tonic-gate return (&sysevent_conf_mod_ops); 22347c478bd9Sstevel@tonic-gate } 22357c478bd9Sstevel@tonic-gate 22367c478bd9Sstevel@tonic-gate /* 22377c478bd9Sstevel@tonic-gate * syseventd daemon module tear-down 22387c478bd9Sstevel@tonic-gate */ 22397c478bd9Sstevel@tonic-gate void 22407c478bd9Sstevel@tonic-gate slm_fini() 22417c478bd9Sstevel@tonic-gate { 22427c478bd9Sstevel@tonic-gate int err; 22437c478bd9Sstevel@tonic-gate 22447c478bd9Sstevel@tonic-gate /* 22457c478bd9Sstevel@tonic-gate * Nothing to clean up if we're in the install environment 22467c478bd9Sstevel@tonic-gate */ 22477c478bd9Sstevel@tonic-gate if (strcmp(root_dir, "") != 0) { 22487c478bd9Sstevel@tonic-gate return; 22497c478bd9Sstevel@tonic-gate } 22507c478bd9Sstevel@tonic-gate 22517c478bd9Sstevel@tonic-gate /* 22527c478bd9Sstevel@tonic-gate * Wait for the queue to drain 22537c478bd9Sstevel@tonic-gate */ 22547c478bd9Sstevel@tonic-gate (void) mutex_lock(&cmdq_lock); 22557c478bd9Sstevel@tonic-gate want_fini = 1; 22567c478bd9Sstevel@tonic-gate (void) cond_signal(&cmdq_cv); 22577c478bd9Sstevel@tonic-gate (void) cond_wait(&cmdq_thr_cv, &cmdq_lock); 22587c478bd9Sstevel@tonic-gate (void) mutex_unlock(&cmdq_lock); 22597c478bd9Sstevel@tonic-gate 22607c478bd9Sstevel@tonic-gate /* 22617c478bd9Sstevel@tonic-gate * Shut down the the queue flush thread 22627c478bd9Sstevel@tonic-gate */ 22637c478bd9Sstevel@tonic-gate if ((err = thr_join(cmdq_thr_id, NULL, NULL)) != 0) { 22647c478bd9Sstevel@tonic-gate syslog(LOG_ERR, THR_JOIN_ERR, strerror(err)); 22657c478bd9Sstevel@tonic-gate } 22667c478bd9Sstevel@tonic-gate 22677c478bd9Sstevel@tonic-gate sysevent_close_channel(confd_handle); 22687c478bd9Sstevel@tonic-gate confd_handle = NULL; 22697c478bd9Sstevel@tonic-gate (void) mutex_destroy(&cmdq_lock); 22707c478bd9Sstevel@tonic-gate (void) cond_destroy(&cmdq_cv); 22717c478bd9Sstevel@tonic-gate (void) cond_destroy(&cmdq_thr_cv); 22727c478bd9Sstevel@tonic-gate free_event_table(); 22737c478bd9Sstevel@tonic-gate } 22747c478bd9Sstevel@tonic-gate 22757c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 22767c478bd9Sstevel@tonic-gate static int 22777c478bd9Sstevel@tonic-gate sysevent_conf_dummy_event(sysevent_t *ev, int flag) 22787c478bd9Sstevel@tonic-gate { 22797c478bd9Sstevel@tonic-gate return (0); 22807c478bd9Sstevel@tonic-gate } 2281