4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
22 * Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved.
36 #include <sys/sunddi.h>
38 #include <libsysevent.h>
40 #include "sysevent_signal.h"
41 #include "../devfsadm/devfsadm.h"
44 * SLM for devfsadmd device configuration daemon
47 extern char *root_dir
;
48 extern void syseventd_print();
50 sysevent_handle_t
*sysevent_hp
;
52 /* Alternate root declarations during install */
53 static int use_alt_root
= 0;
55 static int devfsadmdeliver_event(sysevent_t
*ev
, int flag
);
57 static struct slm_mod_ops devfsadm_mod_ops
= {
58 SE_MAJOR_VERSION
, SE_MINOR_VERSION
, 10, devfsadmdeliver_event
};
60 typedef struct ev_queue
{
61 struct ev_queue
*evq_next
;
65 static mutex_t evq_lock
;
67 static ev_queue_t
*eventq_head
;
68 static ev_queue_t
*eventq_tail
;
70 #define DELIVERY_FAILED \
71 gettext("devfsadmd not responding, /dev may not be current")
73 #define DELIVERY_RESUMED \
74 gettext("devfsadmd now responding again")
77 * Retry error recovery when attempting to send an event to devfsadmd
79 #define RETRY_DAEMON_RESTART 0
80 #define RETRY_MSG_THRESHOLD 60
81 #define RETRY_DAEMON_INTERVAL 60
84 system1(const char *s_path
, const char *s
)
86 struct sigaction cbuf
, ibuf
, qbuf
, ignore
, dfl
;
87 sigset_t mask
, savemask
;
92 /* Check the requested command */
98 /* Check the ability to execute devfsadmd from this process */
99 if (stat(s_path
, &st
) < 0) {
102 if (((geteuid() == st
.st_uid
) && ((st
.st_mode
& S_IXUSR
) == 0)) ||
103 ((getegid() == st
.st_gid
) && ((st
.st_mode
& S_IXGRP
) == 0)) ||
104 ((st
.st_mode
& S_IXOTH
) == 0)) {
110 * Block SIGCHLD and set up a default handler for the duration of the
113 (void) sigemptyset(&mask
);
114 (void) sigaddset(&mask
, SIGCHLD
);
115 (void) sigprocmask(SIG_BLOCK
, &mask
, &savemask
);
116 (void) memset(&dfl
, 0, sizeof (dfl
));
117 dfl
.sa_handler
= SIG_DFL
;
118 (void) sigaction(SIGCHLD
, &dfl
, &cbuf
);
120 /* Fork off the child process (using fork1(), because it's MT-safe) */
121 switch (pid
= fork1()) {
124 (void) sigaction(SIGCHLD
, &cbuf
, NULL
);
125 (void) sigprocmask(SIG_SETMASK
, &savemask
, NULL
);
128 /* Set-up an initial signal mask for the child */
129 (void) sigemptyset(&mask
);
130 (void) sigprocmask(SIG_SETMASK
, &mask
, NULL
);
132 (void) execl(s_path
, s
, (char *)0);
140 (void) memset(&ignore
, 0, sizeof (ignore
));
141 ignore
.sa_handler
= SIG_IGN
;
142 (void) sigaction(SIGINT
, &ignore
, &ibuf
);
143 (void) sigaction(SIGQUIT
, &ignore
, &qbuf
);
146 w
= waitpid(pid
, &status
, 0);
147 } while (w
== -1 && errno
== EINTR
);
149 (void) sigaction(SIGINT
, &ibuf
, NULL
);
150 (void) sigaction(SIGQUIT
, &qbuf
, NULL
);
151 (void) sigaction(SIGCHLD
, &cbuf
, NULL
);
152 (void) sigprocmask(SIG_SETMASK
, &savemask
, NULL
);
154 return ((w
== -1)? w
: status
);
158 * devfsadmdeliver_event - called by syseventd to deliver an event buffer.
159 * The event buffer is subsequently delivered to
160 * devfsadmd. If devfsadmd, is not responding to the
161 * delivery attempt, we will try to startup the
162 * daemon. MT protection is provided by syseventd
163 * and the client lock. This insures sequential
164 * event delivery and protection from re-entrance.
168 devfsadmdeliver_event(sysevent_t
*ev
, int flag
)
173 /* Not initialized */
174 if (sysevent_hp
== NULL
) {
178 /* Quick return for uninteresting events */
179 if (strcmp(sysevent_get_class_name(ev
), EC_DEVFS
) != 0) {
183 /* Queue event for delivery to devfsadmd */
184 new_evq
= (ev_queue_t
*)calloc(1, sizeof (ev_queue_t
));
185 if (new_evq
== NULL
) {
189 ev_size
= sysevent_get_size(ev
);
190 new_evq
->evq_ev
= (sysevent_t
*)malloc(ev_size
);
191 if (new_evq
->evq_ev
== NULL
) {
195 bcopy(ev
, new_evq
->evq_ev
, ev_size
);
197 (void) mutex_lock(&evq_lock
);
198 if (eventq_head
== NULL
) {
199 eventq_head
= new_evq
;
201 eventq_tail
->evq_next
= new_evq
;
203 eventq_tail
= new_evq
;
205 (void) cond_signal(&evq_cv
);
206 (void) mutex_unlock(&evq_lock
);
212 thread_t deliver_thr_id
;
215 devfsadmd_deliver_thr()
221 (void) mutex_lock(&evq_lock
);
223 while (eventq_head
== NULL
) {
224 (void) cond_wait(&evq_cv
, &evq_lock
);
225 if (cleanup
&& eventq_head
== NULL
) {
226 (void) cond_signal(&evq_cv
);
227 (void) mutex_unlock(&evq_lock
);
232 /* Send events on to devfsadmd */
235 (void) mutex_unlock(&evq_lock
);
237 while (sysevent_send_event(sysevent_hp
,
238 evqp
->evq_ev
) != 0) {
240 * Invoke devfsadm to handle node creation
241 * but not for an alternate root.
243 if (use_alt_root
!= 0)
246 * daemon unresponsive -
247 * restart daemon and retry once more
249 if ((errno
== EBADF
|| errno
== ENOENT
) &&
250 (retry
== RETRY_DAEMON_RESTART
) ||
251 ((retry
% RETRY_DAEMON_INTERVAL
) == 0)) {
253 DEVFSADMD_START_PATH
,
256 if (retry
== RETRY_MSG_THRESHOLD
) {
257 syslog(LOG_ERR
, DELIVERY_FAILED
);
266 * Event delivered: remove from queue
267 * and reset delivery retry state.
270 syslog(LOG_ERR
, DELIVERY_RESUMED
);
274 (void) mutex_lock(&evq_lock
);
275 if (eventq_head
!= NULL
) {
276 eventq_head
= eventq_head
->evq_next
;
277 if (eventq_head
== NULL
)
285 (void) cond_signal(&evq_cv
);
286 (void) mutex_unlock(&evq_lock
);
297 char alt_door
[MAXPATHLEN
];
299 if (strcmp(root_dir
, "") == 0) {
300 /* Initialize the private sysevent handle */
301 sysevent_hp
= sysevent_open_channel_alt(DEVFSADM_SERVICE_DOOR
);
304 /* Try alternate door during install time */
305 if (snprintf(alt_door
, MAXPATHLEN
, "%s%s", "/tmp",
306 DEVFSADM_SERVICE_DOOR
) >= MAXPATHLEN
)
309 sysevent_hp
= sysevent_open_channel_alt(alt_door
);
312 if (sysevent_hp
== NULL
) {
313 syseventd_print(0, "Unable to allocate sysevent handle"
314 " for devfsadm module\n");
318 if (sysevent_bind_publisher(sysevent_hp
) != 0) {
319 if (errno
== EBUSY
) {
320 sysevent_cleanup_publishers(sysevent_hp
);
321 if (sysevent_bind_publisher(sysevent_hp
) != 0) {
322 (void) sysevent_close_channel(sysevent_hp
);
328 sysevent_cleanup_subscribers(sysevent_hp
);
333 (void) mutex_init(&evq_lock
, USYNC_THREAD
, NULL
);
334 (void) cond_init(&evq_cv
, USYNC_THREAD
, NULL
);
336 if (thr_create(NULL
, 0, (void *(*)(void *))devfsadmd_deliver_thr
,
337 NULL
, THR_BOUND
, &deliver_thr_id
) != 0) {
338 (void) mutex_destroy(&evq_lock
);
339 (void) cond_destroy(&evq_cv
);
340 sysevent_close_channel(sysevent_hp
);
344 return (&devfsadm_mod_ops
);
350 /* Wait for all events to be flushed out to devfsadmd */
351 (void) mutex_lock(&evq_lock
);
353 (void) cond_signal(&evq_cv
);
354 (void) cond_wait(&evq_cv
, &evq_lock
);
355 (void) mutex_unlock(&evq_lock
);
357 /* Wait for delivery thread to exit */
358 (void) thr_join(deliver_thr_id
, NULL
, NULL
);
360 (void) mutex_destroy(&evq_lock
);
361 (void) cond_destroy(&evq_cv
);
363 sysevent_close_channel(sysevent_hp
);