1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 #include <unistd.h> 30 #include <stdlib.h> 31 #include <string.h> 32 #include <strings.h> 33 #include <limits.h> 34 #include <thread.h> 35 #include <wait.h> 36 #include <synch.h> 37 #include <syslog.h> 38 #include <libintl.h> 39 #include <sys/stat.h> 40 #include <sys/sunddi.h> 41 42 #include <libsysevent.h> 43 44 #include "sysevent_signal.h" 45 #include "../devfsadm/devfsadm.h" 46 47 /* 48 * SLM for devfsadmd device configuration daemon 49 */ 50 51 extern char *root_dir; 52 extern void syseventd_print(); 53 54 sysevent_handle_t *sysevent_hp; 55 56 /* Alternate root declarations during install */ 57 static int use_alt_root = 0; 58 59 static int devfsadmdeliver_event(sysevent_t *ev, int flag); 60 61 static struct slm_mod_ops devfsadm_mod_ops = { 62 SE_MAJOR_VERSION, SE_MINOR_VERSION, 10, devfsadmdeliver_event}; 63 64 typedef struct ev_queue { 65 struct ev_queue *evq_next; 66 sysevent_t *evq_ev; 67 } ev_queue_t; 68 69 static mutex_t evq_lock; 70 static cond_t evq_cv; 71 static ev_queue_t *eventq_head; 72 static ev_queue_t *eventq_tail; 73 74 #define DELIVER_FAILED gettext("/devices or /dev may not be current \ 75 (devfsadmd not responding) Run devfsadm") 76 #define RETRY_MAX 3 77 78 static int 79 system1(const char *s_path, const char *s) 80 { 81 struct sigaction cbuf, ibuf, qbuf, ignore, dfl; 82 sigset_t mask, savemask; 83 struct stat st; 84 pid_t pid; 85 int status, w; 86 87 /* Check the requested command */ 88 if (s == NULL) { 89 errno = EINVAL; 90 return (-1); 91 } 92 93 /* Check the ability to execute devfsadmd from this process */ 94 if (stat(s_path, &st) < 0) { 95 return (-1); 96 } 97 if (((geteuid() == st.st_uid) && ((st.st_mode & S_IXUSR) == 0)) || 98 ((getegid() == st.st_gid) && ((st.st_mode & S_IXGRP) == 0)) || 99 ((st.st_mode & S_IXOTH) == 0)) { 100 errno = EPERM; 101 return (-1); 102 } 103 104 /* 105 * Block SIGCHLD and set up a default handler for the duration of the 106 * system1 call. 107 */ 108 (void) sigemptyset(&mask); 109 (void) sigaddset(&mask, SIGCHLD); 110 (void) sigprocmask(SIG_BLOCK, &mask, &savemask); 111 (void) memset(&dfl, 0, sizeof (dfl)); 112 dfl.sa_handler = SIG_DFL; 113 (void) sigaction(SIGCHLD, &dfl, &cbuf); 114 115 /* Fork off the child process (using fork1(), because it's MT-safe) */ 116 switch (pid = fork1()) { 117 case -1: 118 /* Error */ 119 (void) sigaction(SIGCHLD, &cbuf, NULL); 120 (void) sigprocmask(SIG_SETMASK, &savemask, NULL); 121 return (-1); 122 case 0: 123 /* Set-up an initial signal mask for the child */ 124 (void) sigemptyset(&mask); 125 (void) sigprocmask(SIG_SETMASK, &mask, NULL); 126 (void) execl(s_path, s, (char *)0); 127 _exit(-1); 128 break; 129 default: 130 /* Parent */ 131 break; 132 } 133 134 (void) memset(&ignore, 0, sizeof (ignore)); 135 ignore.sa_handler = SIG_IGN; 136 (void) sigaction(SIGINT, &ignore, &ibuf); 137 (void) sigaction(SIGQUIT, &ignore, &qbuf); 138 139 do { 140 w = waitpid(pid, &status, 0); 141 } while (w == -1 && errno == EINTR); 142 143 (void) sigaction(SIGINT, &ibuf, NULL); 144 (void) sigaction(SIGQUIT, &qbuf, NULL); 145 (void) sigaction(SIGCHLD, &cbuf, NULL); 146 (void) sigprocmask(SIG_SETMASK, &savemask, NULL); 147 148 return ((w == -1)? w: status); 149 } 150 151 /* 152 * devfsadmdeliver_event - called by syseventd to deliver an event buffer. 153 * The event buffer is subsequently delivered to 154 * devfsadmd. If devfsadmd, is not responding to the 155 * delivery attempt, we will try to startup the 156 * daemon. MT protection is provided by syseventd 157 * and the client lock. This insures sequential 158 * event delivery and protection from re-entrance. 159 */ 160 /*ARGSUSED*/ 161 static int 162 devfsadmdeliver_event(sysevent_t *ev, int flag) 163 { 164 int ev_size; 165 ev_queue_t *new_evq; 166 167 /* Not initialized */ 168 if (sysevent_hp == NULL) { 169 return (0); 170 } 171 172 /* Quick return for uninteresting events */ 173 if (strcmp(sysevent_get_class_name(ev), EC_DEVFS) != 0) { 174 return (0); 175 } 176 177 /* Queue event for delivery to devfsadmd */ 178 new_evq = (ev_queue_t *)calloc(1, sizeof (ev_queue_t)); 179 if (new_evq == NULL) { 180 return (EAGAIN); 181 } 182 183 ev_size = sysevent_get_size(ev); 184 new_evq->evq_ev = (sysevent_t *)malloc(ev_size); 185 if (new_evq->evq_ev == NULL) { 186 free(new_evq); 187 return (EAGAIN); 188 } 189 bcopy(ev, new_evq->evq_ev, ev_size); 190 191 (void) mutex_lock(&evq_lock); 192 if (eventq_head == NULL) { 193 eventq_head = new_evq; 194 } else { 195 eventq_tail->evq_next = new_evq; 196 } 197 eventq_tail = new_evq; 198 199 (void) cond_signal(&evq_cv); 200 (void) mutex_unlock(&evq_lock); 201 202 return (0); 203 } 204 205 static int cleanup; 206 thread_t deliver_thr_id; 207 208 void 209 devfsadmd_deliver_thr() 210 { 211 int retry; 212 ev_queue_t *evqp; 213 214 (void) mutex_lock(&evq_lock); 215 for (;;) { 216 while (eventq_head == NULL) { 217 (void) cond_wait(&evq_cv, &evq_lock); 218 if (cleanup && eventq_head == NULL) { 219 (void) cond_signal(&evq_cv); 220 (void) mutex_unlock(&evq_lock); 221 return; 222 } 223 } 224 225 /* Send events on to devfsadmd */ 226 evqp = eventq_head; 227 while (evqp) { 228 (void) mutex_unlock(&evq_lock); 229 retry = 0; 230 while (sysevent_send_event(sysevent_hp, 231 evqp->evq_ev) != 0) { 232 /* 233 * If we are using an alternate root, devfsadm 234 * is run to handle node creation. 235 */ 236 if (use_alt_root == 0) { 237 /* 238 * daemon unresponsive - 239 * restart daemon and retry once more 240 * if not installing 241 */ 242 if (errno == EBADF || errno == ENOENT) { 243 if (system1( 244 DEVFSADMD_START_PATH, 245 DEVFSADMD_START) != -1) { 246 (void) sleep(1); 247 } 248 } 249 ++retry; 250 if (retry < RETRY_MAX) { 251 continue; 252 } else { 253 syslog(LOG_ERR, DELIVER_FAILED); 254 break; 255 } 256 } else { 257 break; 258 } 259 } 260 (void) mutex_lock(&evq_lock); 261 if (eventq_head != NULL) { 262 eventq_head = eventq_head->evq_next; 263 if (eventq_head == NULL) 264 eventq_tail = NULL; 265 } 266 free(evqp->evq_ev); 267 free(evqp); 268 evqp = eventq_head; 269 } 270 if (cleanup) { 271 (void) cond_signal(&evq_cv); 272 (void) mutex_unlock(&evq_lock); 273 return; 274 } 275 } 276 277 /* NOTREACHED */ 278 } 279 280 struct slm_mod_ops * 281 slm_init() 282 { 283 char alt_door[MAXPATHLEN]; 284 285 if (strcmp(root_dir, "") == 0) { 286 /* Initialize the private sysevent handle */ 287 sysevent_hp = sysevent_open_channel_alt(DEVFSADM_SERVICE_DOOR); 288 } else { 289 290 /* Try alternate door during install time */ 291 if (snprintf(alt_door, MAXPATHLEN, "%s%s", "/tmp", 292 DEVFSADM_SERVICE_DOOR) >= MAXPATHLEN) 293 return (NULL); 294 295 sysevent_hp = sysevent_open_channel_alt(alt_door); 296 use_alt_root = 1; 297 } 298 if (sysevent_hp == NULL) { 299 syseventd_print(0, "Unable to allocate sysevent handle" 300 " for devfsadm module\n"); 301 return (NULL); 302 } 303 304 if (sysevent_bind_publisher(sysevent_hp) != 0) { 305 if (errno == EBUSY) { 306 sysevent_cleanup_publishers(sysevent_hp); 307 if (sysevent_bind_publisher(sysevent_hp) != 0) { 308 (void) sysevent_close_channel(sysevent_hp); 309 return (NULL); 310 } 311 } 312 } 313 314 sysevent_cleanup_subscribers(sysevent_hp); 315 cleanup = 0; 316 eventq_head = NULL; 317 eventq_tail = NULL; 318 319 (void) mutex_init(&evq_lock, USYNC_THREAD, NULL); 320 (void) cond_init(&evq_cv, USYNC_THREAD, NULL); 321 322 if (thr_create(NULL, NULL, (void *(*)(void *))devfsadmd_deliver_thr, 323 NULL, THR_BOUND, &deliver_thr_id) != 0) { 324 (void) mutex_destroy(&evq_lock); 325 (void) cond_destroy(&evq_cv); 326 sysevent_close_channel(sysevent_hp); 327 return (NULL); 328 } 329 330 return (&devfsadm_mod_ops); 331 } 332 333 void 334 slm_fini() 335 { 336 /* Wait for all events to be flushed out to devfsadmd */ 337 (void) mutex_lock(&evq_lock); 338 cleanup = 1; 339 (void) cond_signal(&evq_cv); 340 (void) cond_wait(&evq_cv, &evq_lock); 341 (void) mutex_unlock(&evq_lock); 342 343 /* Wait for delivery thread to exit */ 344 (void) thr_join(deliver_thr_id, NULL, NULL); 345 346 (void) mutex_destroy(&evq_lock); 347 (void) cond_destroy(&evq_cv); 348 349 sysevent_close_channel(sysevent_hp); 350 sysevent_hp = NULL; 351 } 352