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