xref: /titanic_51/usr/src/lib/librcm/librcm.c (revision bf1d7e28fd966a3f7e92b40aa301efdedc81ef7b)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 #pragma ident	"%Z%%M%	%I%	%E% SMI"
27 
28 #include "librcm_impl.h"
29 #include "librcm_event.h"
30 
31 #ifdef	DEBUG
32 static int rcm_debug = 1;
33 #define	dprintf(args) if (rcm_debug) (void) fprintf args
34 #else
35 #define	dprintf(args) /* nothing */
36 #endif	/* DEBUG */
37 
38 static int extract_info(nvlist_t *, rcm_info_t **);
39 static int rcm_daemon_is_alive();
40 static int rcm_common(int, rcm_handle_t *, char **, uint_t, void *,
41     rcm_info_t **);
42 static int rcm_direct_call(int, rcm_handle_t *, char **, uint_t, void *,
43     rcm_info_t **);
44 static int rcm_daemon_call(int, rcm_handle_t *, char **, uint_t, void *,
45     rcm_info_t **);
46 static int rcm_generate_nvlist(int, rcm_handle_t *, char **, uint_t, void *,
47     char **, size_t *);
48 static int rcm_check_permission(void);
49 
50 /*
51  * Allocate a handle structure
52  */
53 /*ARGSUSED2*/
54 int
55 rcm_alloc_handle(char *modname, uint_t flag, void *arg, rcm_handle_t **hdp)
56 {
57 	rcm_handle_t *hd;
58 	void *temp;
59 	char namebuf[MAXPATHLEN];
60 
61 	if ((hdp == NULL) || (flag & ~RCM_ALLOC_HDL_MASK)) {
62 		errno = EINVAL;
63 		return (RCM_FAILURE);
64 	}
65 
66 	if (rcm_check_permission() == 0) {
67 		errno = EPERM;
68 		return (RCM_FAILURE);
69 	}
70 
71 	if ((hd = calloc(1, sizeof (*hd))) == NULL) {
72 		return (RCM_FAILURE);
73 	}
74 
75 	if (modname) {
76 		(void) snprintf(namebuf, MAXPATHLEN, "%s%s", modname,
77 			RCM_MODULE_SUFFIX);
78 
79 		if ((hd->modname = strdup(namebuf)) == NULL) {
80 			free(hd);
81 			return (RCM_FAILURE);
82 		}
83 
84 		if ((temp = rcm_module_open(namebuf)) == NULL) {
85 			free(hd->modname);
86 			free(hd);
87 			errno = EINVAL;
88 			return (RCM_FAILURE);
89 		}
90 
91 		rcm_module_close(temp);
92 	}
93 
94 	if (flag & RCM_NOPID) {
95 		hd->pid = (pid_t)0;
96 	} else {
97 		hd->pid = (pid_t)getpid();
98 	}
99 
100 	*hdp = hd;
101 	return (RCM_SUCCESS);
102 }
103 
104 /* free handle structure */
105 int
106 rcm_free_handle(rcm_handle_t *hd)
107 {
108 	if (hd == NULL) {
109 		errno = EINVAL;
110 		return (RCM_FAILURE);
111 	}
112 
113 	if (hd->modname) {
114 		free(hd->modname);
115 	}
116 
117 	free(hd);
118 	return (RCM_SUCCESS);
119 }
120 
121 
122 /*
123  * Operations which require daemon processing
124  */
125 
126 /* get registration and DR information from rcm_daemon */
127 int
128 rcm_get_info(rcm_handle_t *hd, char *rsrcname, uint_t flag, rcm_info_t **infop)
129 {
130 	char *rsrcnames[2];
131 
132 	if ((flag & ~RCM_GET_INFO_MASK) || (infop == NULL)) {
133 		errno = EINVAL;
134 		return (RCM_FAILURE);
135 	}
136 
137 	/*
138 	 * rsrcname may be NULL if requesting dr operations or modinfo
139 	 */
140 	if ((rsrcname == NULL) &&
141 	    ((flag & RCM_DR_OPERATION|RCM_MOD_INFO) == 0)) {
142 		errno = EINVAL;
143 		return (RCM_FAILURE);
144 	}
145 
146 	rsrcnames[0] = rsrcname;
147 	rsrcnames[1] = NULL;
148 
149 	return (rcm_common(CMD_GETINFO, hd, rsrcnames, flag, NULL, infop));
150 }
151 
152 /* get registration and DR information from rcm_daemon (list version) */
153 int
154 rcm_get_info_list(rcm_handle_t *hd, char **rsrcnames, uint_t flag,
155     rcm_info_t **infop)
156 {
157 	/* Requesting the current DR operations with a *list() is invalid */
158 	if ((flag & RCM_DR_OPERATION) || (flag & RCM_MOD_INFO)) {
159 		errno = EINVAL;
160 		return (RCM_FAILURE);
161 	}
162 
163 	return (rcm_common(CMD_GETINFO, hd, rsrcnames, flag, NULL, infop));
164 }
165 
166 /* request to offline a resource before DR removal */
167 int
168 rcm_request_offline(rcm_handle_t *hd, char *rsrcname, uint_t flag,
169     rcm_info_t **infop)
170 {
171 	char *rsrcnames[2];
172 
173 	rsrcnames[0] = rsrcname;
174 	rsrcnames[1] = NULL;
175 
176 	return (rcm_request_offline_list(hd, rsrcnames, flag, infop));
177 }
178 
179 /* request to offline a resource before DR removal (list version) */
180 int
181 rcm_request_offline_list(rcm_handle_t *hd, char **rsrcnames, uint_t flag,
182     rcm_info_t **infop)
183 {
184 	if (flag & ~RCM_REQUEST_MASK) {
185 		errno = EINVAL;
186 		return (RCM_FAILURE);
187 	}
188 
189 	return (rcm_common(CMD_OFFLINE, hd, rsrcnames, flag, NULL, infop));
190 }
191 
192 /* cancel offline request and allow apps to use rsrcname */
193 int
194 rcm_notify_online(rcm_handle_t *hd, char *rsrcname, uint_t flag,
195     rcm_info_t **infop)
196 {
197 	char *rsrcnames[2];
198 
199 	rsrcnames[0] = rsrcname;
200 	rsrcnames[1] = NULL;
201 
202 	return (rcm_notify_online_list(hd, rsrcnames, flag, infop));
203 }
204 
205 /* cancel offline and allow apps to use resources (list version) */
206 int
207 rcm_notify_online_list(rcm_handle_t *hd, char **rsrcnames, uint_t flag,
208     rcm_info_t **infop)
209 {
210 	if (flag & ~RCM_NOTIFY_MASK) {
211 		errno = EINVAL;
212 		return (RCM_FAILURE);
213 	}
214 
215 	return (rcm_common(CMD_ONLINE, hd, rsrcnames, flag, NULL, infop));
216 }
217 
218 /* notify that rsrcname has been removed */
219 int
220 rcm_notify_remove(rcm_handle_t *hd, char *rsrcname, uint_t flag,
221     rcm_info_t **infop)
222 {
223 	char *rsrcnames[2];
224 
225 	rsrcnames[0] = rsrcname;
226 	rsrcnames[1] = NULL;
227 
228 	return (rcm_notify_remove_list(hd, rsrcnames, flag, infop));
229 }
230 
231 /* notify that resrouces have been removed (list form) */
232 int
233 rcm_notify_remove_list(rcm_handle_t *hd, char **rsrcnames, uint_t flag,
234     rcm_info_t **infop)
235 {
236 	if (flag & ~RCM_NOTIFY_MASK) {
237 		errno = EINVAL;
238 		return (RCM_FAILURE);
239 	}
240 
241 	return (rcm_common(CMD_REMOVE, hd, rsrcnames, flag, NULL, infop));
242 }
243 
244 /* request for permission to suspend resource of interval time */
245 int
246 rcm_request_suspend(rcm_handle_t *hd, char *rsrcname, uint_t flag,
247     timespec_t *interval, rcm_info_t **infop)
248 {
249 	char *rsrcnames[2];
250 
251 	rsrcnames[0] = rsrcname;
252 	rsrcnames[1] = NULL;
253 
254 	return (rcm_request_suspend_list(hd, rsrcnames, flag, interval, infop));
255 }
256 
257 /* request for permission to suspend resource of interval time (list form) */
258 int
259 rcm_request_suspend_list(rcm_handle_t *hd, char **rsrcnames, uint_t flag,
260     timespec_t *interval, rcm_info_t **infop)
261 {
262 	if ((flag & ~RCM_REQUEST_MASK) || (interval == NULL) ||
263 	    (interval->tv_sec < 0) || (interval->tv_nsec < 0)) {
264 		errno = EINVAL;
265 		return (RCM_FAILURE);
266 	}
267 
268 	return (rcm_common(CMD_SUSPEND, hd, rsrcnames, flag, (void *)interval,
269 	    infop));
270 }
271 
272 /* notify apps of the completion of resource suspension */
273 int
274 rcm_notify_resume(rcm_handle_t *hd, char *rsrcname, uint_t flag,
275     rcm_info_t **infop)
276 {
277 	char *rsrcnames[2];
278 
279 	rsrcnames[0] = rsrcname;
280 	rsrcnames[1] = NULL;
281 
282 	return (rcm_notify_resume_list(hd, rsrcnames, flag, infop));
283 }
284 
285 /* notify apps of the completion of resource suspension (list form) */
286 int
287 rcm_notify_resume_list(rcm_handle_t *hd, char **rsrcnames, uint_t flag,
288     rcm_info_t **infop)
289 {
290 	if (flag & ~(RCM_NOTIFY_MASK | RCM_SUSPENDED)) {
291 		errno = EINVAL;
292 		return (RCM_FAILURE);
293 	}
294 
295 	return (rcm_common(CMD_RESUME, hd, rsrcnames, flag, NULL, infop));
296 }
297 
298 /* request a capacity change from apps */
299 int
300 rcm_request_capacity_change(rcm_handle_t *hd, char *rsrcname, uint_t flag,
301     nvlist_t *nvl, rcm_info_t **infop)
302 {
303 	int rv;
304 	char *rsrcnames[2];
305 
306 	if ((nvl == NULL) || (flag & ~RCM_REQUEST_MASK)) {
307 		errno = EINVAL;
308 		return (RCM_FAILURE);
309 	}
310 
311 	rsrcnames[0] = rsrcname;
312 	rsrcnames[1] = NULL;
313 
314 	rv = rcm_common(CMD_REQUEST_CHANGE, hd, rsrcnames, flag, (void *)nvl,
315 	    infop);
316 
317 	return (rv);
318 }
319 
320 /* notify apps of a capacity change */
321 int
322 rcm_notify_capacity_change(rcm_handle_t *hd, char *rsrcname, uint_t flag,
323     nvlist_t *nvl, rcm_info_t **infop)
324 {
325 	int rv;
326 	char *rsrcnames[2];
327 
328 	if ((nvl == NULL) || (flag & ~RCM_REQUEST_MASK)) {
329 		errno = EINVAL;
330 		return (RCM_FAILURE);
331 	}
332 
333 	rsrcnames[0] = rsrcname;
334 	rsrcnames[1] = NULL;
335 
336 	rv = rcm_common(CMD_NOTIFY_CHANGE, hd, rsrcnames, flag, (void *)nvl,
337 	    infop);
338 
339 	return (rv);
340 }
341 
342 /* notify apps of an event */
343 int
344 rcm_notify_event(rcm_handle_t *hd, char *rsrcname, uint_t flag, nvlist_t *nvl,
345     rcm_info_t **infop)
346 {
347 	int rv;
348 	char *rsrcnames[2];
349 
350 	/* No flags are defined yet for rcm_notify_event() */
351 	if ((nvl == NULL) || (flag != 0)) {
352 		errno = EINVAL;
353 		return (RCM_FAILURE);
354 	}
355 
356 	rsrcnames[0] = rsrcname;
357 	rsrcnames[1] = NULL;
358 
359 	rv = rcm_common(CMD_EVENT, hd, rsrcnames, 0, (void *)nvl, infop);
360 
361 	return (rv);
362 }
363 
364 /*
365  * Register to receive capacity changes. This requires a module to exist in
366  * module directory. It should be called prior to using a new resource.
367  */
368 /* ARGSUSED */
369 int
370 rcm_register_capacity(rcm_handle_t *hd, char *rsrcname, uint_t flag,
371     rcm_info_t **infop)
372 {
373 	char *rsrcnames[2];
374 
375 	if (flag & ~RCM_REGISTER_MASK) {
376 		errno = EINVAL;
377 		return (RCM_FAILURE);
378 	}
379 
380 	flag |= RCM_REGISTER_CAPACITY;
381 
382 	rsrcnames[0] = rsrcname;
383 	rsrcnames[1] = NULL;
384 
385 	return (rcm_common(CMD_REGISTER, hd, rsrcnames, flag, NULL, NULL));
386 }
387 
388 /* unregister interest in capacity changes */
389 int
390 rcm_unregister_capacity(rcm_handle_t *hd, char *rsrcname, uint_t flag)
391 {
392 	char *rsrcnames[2];
393 
394 	if (flag & ~RCM_REGISTER_MASK) {
395 		errno = EINVAL;
396 		return (RCM_FAILURE);
397 	}
398 
399 	flag |= RCM_REGISTER_CAPACITY;
400 
401 	rsrcnames[0] = rsrcname;
402 	rsrcnames[1] = NULL;
403 
404 	return (rcm_common(CMD_UNREGISTER, hd, rsrcnames, flag, NULL, NULL));
405 }
406 
407 /*
408  * Register to receive events. This requires a module to exist in module
409  * directory. It should be called prior to using a new resource.
410  */
411 /* ARGSUSED */
412 int
413 rcm_register_event(rcm_handle_t *hd, char *rsrcname, uint_t flag,
414     rcm_info_t **infop)
415 {
416 	char *rsrcnames[2];
417 
418 	if (flag & ~RCM_REGISTER_MASK) {
419 		errno = EINVAL;
420 		return (RCM_FAILURE);
421 	}
422 
423 	flag |= RCM_REGISTER_EVENT;
424 
425 	rsrcnames[0] = rsrcname;
426 	rsrcnames[1] = NULL;
427 
428 	return (rcm_common(CMD_REGISTER, hd, rsrcnames, flag, NULL, NULL));
429 }
430 
431 /* unregister interest in events */
432 int
433 rcm_unregister_event(rcm_handle_t *hd, char *rsrcname, uint_t flag)
434 {
435 	char *rsrcnames[2];
436 
437 	if (flag & ~RCM_REGISTER_MASK) {
438 		errno = EINVAL;
439 		return (RCM_FAILURE);
440 	}
441 
442 	flag |= RCM_REGISTER_EVENT;
443 
444 	rsrcnames[0] = rsrcname;
445 	rsrcnames[1] = NULL;
446 
447 	return (rcm_common(CMD_UNREGISTER, hd, rsrcnames, flag, NULL, NULL));
448 }
449 
450 /*
451  * Register interest in a resource. This requires a module to exist in module
452  * directory. It should be called prior to using a new resource.
453  *
454  * Registration may be denied if it is presently locked by a DR operation.
455  */
456 /* ARGSUSED */
457 int
458 rcm_register_interest(rcm_handle_t *hd, char *rsrcname, uint_t flag,
459     rcm_info_t **infop)
460 {
461 	char *rsrcnames[2];
462 
463 	if (flag & ~RCM_REGISTER_MASK) {
464 		errno = EINVAL;
465 		return (RCM_FAILURE);
466 	}
467 
468 	flag |= RCM_REGISTER_DR;
469 
470 	rsrcnames[0] = rsrcname;
471 	rsrcnames[1] = NULL;
472 
473 	return (rcm_common(CMD_REGISTER, hd, rsrcnames, flag, NULL, NULL));
474 }
475 
476 /* unregister interest in rsrcname */
477 int
478 rcm_unregister_interest(rcm_handle_t *hd, char *rsrcname, uint_t flag)
479 {
480 	char *rsrcnames[2];
481 
482 	if (flag & ~RCM_REGISTER_MASK) {
483 		errno = EINVAL;
484 		return (RCM_FAILURE);
485 	}
486 
487 	flag |= RCM_REGISTER_DR;
488 
489 	rsrcnames[0] = rsrcname;
490 	rsrcnames[1] = NULL;
491 
492 	return (rcm_common(CMD_UNREGISTER, hd, rsrcnames, flag, NULL, NULL));
493 }
494 
495 /* get the current state of a resource */
496 int
497 rcm_get_rsrcstate(rcm_handle_t *hd, char *rsrcname, int *statep)
498 {
499 	int result;
500 	int flag = 0;
501 	rcm_info_t *infop = NULL;
502 	rcm_info_tuple_t *tuple = NULL;
503 	char *rsrcnames[2];
504 
505 	if (statep == NULL) {
506 		errno = EINVAL;
507 		return (RCM_FAILURE);
508 	}
509 
510 	rsrcnames[0] = rsrcname;
511 	rsrcnames[1] = NULL;
512 
513 	result = rcm_common(CMD_GETSTATE, hd, rsrcnames, flag, NULL, &infop);
514 
515 	/*
516 	 * A successful result implies the presence of exactly one RCM info
517 	 * tuple containing the state of this resource (a combination of each
518 	 * client's resources).  If that's not true, change the result to
519 	 * RCM_FAILURE.
520 	 */
521 	if (result == RCM_SUCCESS) {
522 		if ((infop == NULL) ||
523 		    ((tuple = rcm_info_next(infop, NULL)) == NULL) ||
524 		    (rcm_info_next(infop, tuple) != NULL)) {
525 			result = RCM_FAILURE;
526 		} else if (infop && tuple) {
527 			*statep = rcm_info_state(tuple);
528 		}
529 	}
530 
531 	if (infop)
532 		rcm_free_info(infop);
533 
534 	return (result);
535 }
536 
537 /*
538  * RCM helper functions exposed to librcm callers.
539  */
540 
541 /* Free linked list of registration info */
542 void
543 rcm_free_info(rcm_info_t *info)
544 {
545 	while (info) {
546 		rcm_info_t *tmp = info->next;
547 
548 		if (info->info)
549 			nvlist_free(info->info);
550 		free(info);
551 
552 		info = tmp;
553 	}
554 }
555 
556 /* return the next tuple in the info structure */
557 rcm_info_tuple_t *
558 rcm_info_next(rcm_info_t *info, rcm_info_tuple_t *tuple)
559 {
560 	if (info == NULL) {
561 		errno = EINVAL;
562 		return (NULL);
563 	}
564 
565 	if (tuple == NULL) {
566 		return ((rcm_info_tuple_t *)info);
567 	}
568 	return ((rcm_info_tuple_t *)tuple->next);
569 }
570 
571 /* return resource name */
572 const char *
573 rcm_info_rsrc(rcm_info_tuple_t *tuple)
574 {
575 	char *rsrcname = NULL;
576 
577 	if (tuple == NULL || tuple->info == NULL) {
578 		errno = EINVAL;
579 		return (NULL);
580 	}
581 
582 	if (errno = nvlist_lookup_string(tuple->info, RCM_RSRCNAME, &rsrcname))
583 		return (NULL);
584 
585 	return (rsrcname);
586 }
587 
588 const char *
589 rcm_info_info(rcm_info_tuple_t *tuple)
590 {
591 	char *info = NULL;
592 
593 	if (tuple == NULL || tuple->info == NULL) {
594 		errno = EINVAL;
595 		return (NULL);
596 	}
597 
598 	if (errno = nvlist_lookup_string(tuple->info, RCM_CLIENT_INFO, &info))
599 		return (NULL);
600 
601 	return (info);
602 }
603 
604 const char *
605 rcm_info_error(rcm_info_tuple_t *tuple)
606 {
607 	char *errstr = NULL;
608 
609 	if (tuple == NULL || tuple->info == NULL) {
610 		errno = EINVAL;
611 		return (NULL);
612 	}
613 
614 	if (errno = nvlist_lookup_string(tuple->info, RCM_CLIENT_ERROR,
615 	    &errstr))
616 		return (NULL);
617 
618 	return (errstr);
619 }
620 
621 /* return info string in the tuple */
622 const char *
623 rcm_info_modname(rcm_info_tuple_t *tuple)
624 {
625 	char *modname = NULL;
626 
627 	if (tuple == NULL || tuple->info == NULL) {
628 		errno = EINVAL;
629 		return (NULL);
630 	}
631 
632 	if (errno = nvlist_lookup_string(tuple->info, RCM_CLIENT_MODNAME,
633 	    &modname))
634 		return (NULL);
635 
636 	return (modname);
637 }
638 
639 /* return client pid in the tuple */
640 pid_t
641 rcm_info_pid(rcm_info_tuple_t *tuple)
642 {
643 	uint64_t pid64 = (uint64_t)0;
644 
645 	if (tuple == NULL || tuple->info == NULL) {
646 		errno = EINVAL;
647 		return ((pid_t)0);
648 	}
649 
650 	if (errno = nvlist_lookup_uint64(tuple->info, RCM_CLIENT_ID, &pid64))
651 		return ((pid_t)0);
652 
653 	return ((pid_t)pid64);
654 }
655 
656 /* return client state in the tuple */
657 int
658 rcm_info_state(rcm_info_tuple_t *tuple)
659 {
660 	int state;
661 
662 	if (tuple == NULL || tuple->info == NULL) {
663 		errno = EINVAL;
664 		return (RCM_STATE_UNKNOWN);
665 	}
666 
667 	if (errno = nvlist_lookup_int32(tuple->info, RCM_RSRCSTATE, &state))
668 		return (RCM_STATE_UNKNOWN);
669 
670 	return (state);
671 }
672 
673 /* return the generic properties in the tuple */
674 nvlist_t *
675 rcm_info_properties(rcm_info_tuple_t *tuple)
676 {
677 	char *buf;
678 	uint_t buflen;
679 	nvlist_t *nvl;
680 
681 	if (tuple == NULL || tuple->info == NULL) {
682 		errno = EINVAL;
683 		return (NULL);
684 	}
685 
686 	if (errno = nvlist_lookup_byte_array(tuple->info, RCM_CLIENT_PROPERTIES,
687 	    (uchar_t **)&buf, &buflen))
688 		return (NULL);
689 
690 	if (errno = nvlist_unpack(buf, buflen, &nvl, 0)) {
691 		free(buf);
692 		return (NULL);
693 	}
694 
695 	return (nvl);
696 }
697 
698 /*
699  * return operation sequence number
700  *
701  * This is private. Called by rcmctl only for testing purposes.
702  */
703 int
704 rcm_info_seqnum(rcm_info_tuple_t *tuple)
705 {
706 	int seqnum;
707 
708 	if (tuple == NULL || tuple->info == NULL) {
709 		errno = EINVAL;
710 		return (-1);
711 	}
712 
713 	if (errno = nvlist_lookup_int32(tuple->info, RCM_SEQ_NUM, &seqnum))
714 		return (-1);
715 
716 	return (seqnum);
717 }
718 
719 
720 /*
721  * The following interfaces are PRIVATE to the RCM framework. They are not
722  * declared static because they are called by rcm_daemon.
723  */
724 
725 /*
726  * Invoke shell to execute command in MT safe manner.
727  * Returns wait status or -1 on error.
728  */
729 int
730 rcm_exec_cmd(char *cmd)
731 {
732 	pid_t pid;
733 	int status, w;
734 	char *argvec[] = {"sh", "-c", NULL, NULL};
735 
736 	argvec[2] = cmd;
737 	if ((pid = fork1()) == 0) {
738 		(void) execv("/bin/sh", argvec);
739 		_exit(127);
740 	} else if (pid == -1) {
741 		return (-1);
742 	}
743 
744 	do {
745 		w = waitpid(pid, &status, 0);
746 	} while (w == -1 && errno == EINTR);
747 
748 	return ((w == -1) ? w : status);
749 }
750 
751 /* Append info at the very end */
752 int
753 rcm_append_info(rcm_info_t **head, rcm_info_t *info)
754 {
755 	rcm_info_t *tuple;
756 
757 	if (head == NULL) {
758 		errno = EINVAL;
759 		return (RCM_FAILURE);
760 	}
761 
762 	if ((tuple = *head) == NULL) {
763 		*head = info;
764 		return (RCM_SUCCESS);
765 	}
766 
767 	while (tuple->next) {
768 		tuple = tuple->next;
769 	}
770 	tuple->next = info;
771 	return (RCM_SUCCESS);
772 }
773 
774 /* get rcm module and rcm script directory names */
775 
776 #define	N_MODULE_DIR	3	/* search 3 directories for modules */
777 #define	MODULE_DIR_HW	"/usr/platform/%s/lib/rcm/modules/"
778 #define	MODULE_DIR_GEN	"/usr/lib/rcm/modules/"
779 
780 #define	N_SCRIPT_DIR	4	/* search 4 directories for scripts */
781 #define	SCRIPT_DIR_HW	"/usr/platform/%s/lib/rcm/scripts/"
782 #define	SCRIPT_DIR_GEN	"/usr/lib/rcm/scripts/"
783 #define	SCRIPT_DIR_ETC	"/etc/rcm/scripts/"
784 
785 
786 char *
787 rcm_module_dir(uint_t dirnum)
788 {
789 	if (dirnum < N_MODULE_DIR)
790 		return (rcm_dir(dirnum, NULL));
791 	else
792 		return (NULL);
793 }
794 
795 char *
796 rcm_script_dir(uint_t dirnum)
797 {
798 	if (dirnum < N_SCRIPT_DIR)
799 		return (rcm_dir(dirnum + N_MODULE_DIR, NULL));
800 	else
801 		return (NULL);
802 }
803 
804 char *
805 rcm_dir(uint_t dirnum, int *rcm_script)
806 {
807 	static char dir_name[N_MODULE_DIR + N_SCRIPT_DIR][MAXPATHLEN];
808 
809 	char infobuf[MAXPATHLEN];
810 
811 	if (dirnum >= (N_MODULE_DIR + N_SCRIPT_DIR))
812 		return (NULL);
813 
814 	if (dir_name[0][0] == '\0') {
815 		/*
816 		 * construct the module directory names
817 		 */
818 		if (sysinfo(SI_PLATFORM, infobuf, MAXPATHLEN) == -1) {
819 			dprintf((stderr, "sysinfo %s\n", strerror(errno)));
820 			return (NULL);
821 		} else {
822 			if (snprintf(dir_name[0], MAXPATHLEN, MODULE_DIR_HW,
823 			    infobuf) >= MAXPATHLEN ||
824 			    snprintf(dir_name[N_MODULE_DIR + 1], MAXPATHLEN,
825 			    SCRIPT_DIR_HW, infobuf) >= MAXPATHLEN) {
826 				dprintf((stderr,
827 				    "invalid module or script directory for "
828 				    "platform %s\n", infobuf));
829 				return (NULL);
830 			}
831 		}
832 
833 		if (sysinfo(SI_MACHINE, infobuf, MAXPATHLEN) == -1) {
834 			dprintf((stderr, "sysinfo %s\n", strerror(errno)));
835 			return (NULL);
836 		} else {
837 			if (snprintf(dir_name[1], MAXPATHLEN, MODULE_DIR_HW,
838 			    infobuf) >= MAXPATHLEN ||
839 			    snprintf(dir_name[N_MODULE_DIR + 2], MAXPATHLEN,
840 			    SCRIPT_DIR_HW, infobuf) >= MAXPATHLEN) {
841 				dprintf((stderr,
842 				    "invalid module or script directory for "
843 				    "machine type %s\n", infobuf));
844 				return (NULL);
845 			}
846 		}
847 
848 		if (strlcpy(dir_name[2], MODULE_DIR_GEN, MAXPATHLEN) >=
849 		    MAXPATHLEN ||
850 		    strlcpy(dir_name[N_MODULE_DIR + 3], SCRIPT_DIR_GEN,
851 		    MAXPATHLEN) >= MAXPATHLEN ||
852 		    strlcpy(dir_name[N_MODULE_DIR + 0], SCRIPT_DIR_ETC,
853 		    MAXPATHLEN) >= MAXPATHLEN) {
854 			dprintf((stderr,
855 			    "invalid module or script generic directory\n"));
856 			return (NULL);
857 		}
858 	}
859 
860 	if (rcm_script)
861 		*rcm_script = (dirnum < N_MODULE_DIR) ? 0 : 1;
862 
863 	return (dir_name[dirnum]);
864 }
865 
866 /*
867  * Find the directory where the script is located.
868  * If the script is found return a pointer to the directory where the
869  * script was found otherwise return NULL.
870  */
871 char *
872 rcm_get_script_dir(char *script_name)
873 {
874 	uint_t i;
875 	char *dir_name;
876 	char path[MAXPATHLEN];
877 	struct stat stats;
878 
879 	for (i = 0; (dir_name = rcm_script_dir(i)) != NULL; i++) {
880 		if (snprintf(path, MAXPATHLEN, "%s%s", dir_name, script_name)
881 		    >= MAXPATHLEN) {
882 			dprintf((stderr, "invalid script %s skipped\n",
883 			    script_name));
884 			continue;
885 		}
886 		if (stat(path, &stats) == 0)
887 			return (dir_name);
888 	}
889 
890 	return (NULL);
891 }
892 
893 /*
894  * Returns 1 if the filename is an rcm script.
895  * Returns 0 if the filename is an rcm module.
896  */
897 int
898 rcm_is_script(char *filename)
899 {
900 	char *tmp;
901 
902 	if (((tmp = strstr(filename, RCM_MODULE_SUFFIX)) != NULL) &&
903 		(tmp[strlen(RCM_MODULE_SUFFIX)] == '\0'))
904 		return (0);
905 	else
906 		return (1);
907 }
908 
909 /* Locate the module and call dlopen */
910 void *
911 rcm_module_open(char *modname)
912 {
913 	unsigned i;
914 	char *dir_name;
915 	void *dlhandle = NULL;
916 	char modpath[MAXPATHLEN];
917 
918 #ifdef DEBUG
919 	struct stat sbuf;
920 #endif
921 
922 	/*
923 	 * dlopen the module
924 	 */
925 	for (i = 0; (dir_name = rcm_module_dir(i)) != NULL; i++) {
926 		if (snprintf(modpath, MAXPATHLEN, "%s%s", dir_name, modname)
927 		    >= MAXPATHLEN) {
928 			dprintf((stderr, "invalid module %s skipped\n",
929 			    modname));
930 			continue;
931 		}
932 
933 		if ((dlhandle = dlopen(modpath, RTLD_LAZY)) != NULL) {
934 			return (dlhandle);
935 		}
936 
937 		dprintf((stderr, "failure (dlopen=%s)\n", dlerror()));
938 #ifdef DEBUG
939 		if (stat(modpath, &sbuf) == 0) {
940 			(void) fprintf(stderr, "%s is not a valid module\n",
941 			    modpath);
942 		}
943 #endif
944 	}
945 
946 	dprintf((stderr, "module %s not found\n", modname));
947 	return (NULL);
948 }
949 
950 /* dlclose module */
951 void
952 rcm_module_close(void *dlhandle)
953 {
954 	if (dlclose(dlhandle) == 0)
955 		return;
956 
957 	dprintf((stderr, "dlclose: %s\n", dlerror()));
958 }
959 
960 
961 /*
962  * stub implementation of rcm_log_message allows dlopen of rcm modules
963  * to proceed in absence of rcm_daemon.
964  *
965  * This definition is interposed by the definition in rcm_daemon because of the
966  * default search order implemented by the linker and dlsym(). All RCM modules
967  * will see the daemon version when loaded by the rcm_daemon.
968  */
969 /* ARGSUSED */
970 void
971 rcm_log_message(int level, char *message, ...)
972 {
973 	dprintf((stderr, "rcm_log_message stub\n"));
974 }
975 
976 /*
977  * Helper functions
978  */
979 
980 /*
981  * Common routine for all rcm calls which require daemon processing
982  */
983 static int
984 rcm_common(int cmd, rcm_handle_t *hd, char **rsrcnames, uint_t flag, void *arg,
985     rcm_info_t **infop)
986 {
987 	int i;
988 
989 	if (hd == NULL) {
990 		errno = EINVAL;
991 		return (RCM_FAILURE);
992 	}
993 
994 	if (getuid() != 0) {
995 		errno = EPERM;
996 		return (RCM_FAILURE);
997 	}
998 
999 	if ((flag & (RCM_DR_OPERATION | RCM_MOD_INFO)) == 0) {
1000 		if ((rsrcnames == NULL) || (rsrcnames[0] == NULL)) {
1001 			errno = EINVAL;
1002 			return (RCM_FAILURE);
1003 		}
1004 
1005 		for (i = 0; rsrcnames[i] != NULL; i++) {
1006 			if (*rsrcnames[i] == '\0') {
1007 				errno = EINVAL;
1008 				return (RCM_FAILURE);
1009 			}
1010 		}
1011 	}
1012 
1013 	/*
1014 	 * Check if handle is allocated by rcm_daemon. If so, this call came
1015 	 * from an RCM module, so we make a direct call into rcm_daemon.
1016 	 */
1017 	if (hd->lrcm_ops != NULL) {
1018 		return (rcm_direct_call(cmd, hd, rsrcnames, flag, arg, infop));
1019 	}
1020 
1021 	/*
1022 	 * When not called from a RCM module (i.e. no recursion), zero the
1023 	 * pointer just in case caller did not do so. For recursive calls,
1024 	 * we want to append rcm_info_t after infop; zero it may cause
1025 	 * memory leaks.
1026 	 */
1027 	if (infop) {
1028 		*infop = NULL;
1029 	}
1030 
1031 	/*
1032 	 * Now call into the daemon.
1033 	 */
1034 	return (rcm_daemon_call(cmd, hd, rsrcnames, flag, arg, infop));
1035 }
1036 
1037 /*
1038  * Caller is an RCM module, call directly into rcm_daemon.
1039  */
1040 static int
1041 rcm_direct_call(int cmd, rcm_handle_t *hd, char **rsrcnames, uint_t flag,
1042     void *arg, rcm_info_t **infop)
1043 {
1044 	int error;
1045 
1046 	librcm_ops_t *ops = (librcm_ops_t *)hd->lrcm_ops;
1047 	switch (cmd) {
1048 	case CMD_GETINFO:
1049 		error = ops->librcm_getinfo(rsrcnames, flag, hd->seq_num,
1050 		    infop);
1051 		break;
1052 
1053 	case CMD_OFFLINE:
1054 		error = ops->librcm_offline(rsrcnames, hd->pid, flag,
1055 		    hd->seq_num, infop);
1056 		break;
1057 
1058 	case CMD_ONLINE:
1059 		error = ops->librcm_online(rsrcnames, hd->pid, flag,
1060 		    hd->seq_num, infop);
1061 		break;
1062 
1063 	case CMD_REMOVE:
1064 		error = ops->librcm_remove(rsrcnames, hd->pid, flag,
1065 		    hd->seq_num, infop);
1066 		break;
1067 
1068 	case CMD_SUSPEND:
1069 		error = ops->librcm_suspend(rsrcnames, hd->pid, flag,
1070 		    hd->seq_num, (timespec_t *)arg, infop);
1071 		break;
1072 
1073 	case CMD_RESUME:
1074 		error = ops->librcm_resume(rsrcnames, hd->pid, flag,
1075 		    hd->seq_num, infop);
1076 		break;
1077 
1078 	case CMD_REGISTER:
1079 		error = ops->librcm_regis(hd->modname, rsrcnames[0], hd->pid,
1080 		    flag, infop);
1081 		break;
1082 
1083 	case CMD_UNREGISTER:
1084 		error = ops->librcm_unregis(hd->modname, rsrcnames[0], hd->pid,
1085 		    flag);
1086 		break;
1087 
1088 	case CMD_REQUEST_CHANGE:
1089 		error = ops->librcm_request_change(rsrcnames[0], hd->pid, flag,
1090 		    hd->seq_num, (nvlist_t *)arg, infop);
1091 		break;
1092 
1093 	case CMD_NOTIFY_CHANGE:
1094 		error = ops->librcm_notify_change(rsrcnames[0], hd->pid, flag,
1095 		    hd->seq_num, (nvlist_t *)arg, infop);
1096 		break;
1097 
1098 	case CMD_EVENT:
1099 		error = ops->librcm_notify_event(rsrcnames[0], hd->pid, flag,
1100 		    hd->seq_num, (nvlist_t *)arg, infop);
1101 		break;
1102 
1103 	case CMD_GETSTATE:
1104 		error = ops->librcm_getstate(rsrcnames[0], hd->pid, infop);
1105 		break;
1106 
1107 	default:
1108 		dprintf((stderr, "invalid command: %d\n", cmd));
1109 		error = EFAULT;
1110 	}
1111 
1112 	if (error > 0) {
1113 		errno = error;
1114 		error = RCM_FAILURE;
1115 	}
1116 	return (error);
1117 }
1118 
1119 /*
1120  * Call into rcm_daemon door to process the request
1121  */
1122 static int
1123 rcm_daemon_call(int cmd, rcm_handle_t *hd, char **rsrcnames, uint_t flag,
1124     void *arg, rcm_info_t **infop)
1125 {
1126 	int errno_found;
1127 	int daemon_errno = 0;
1128 	int error = RCM_SUCCESS;
1129 	int delay = 300;
1130 	int maxdelay = 10000;	/* 10 seconds */
1131 	char *nvl_packed = NULL;
1132 	size_t nvl_size = 0;
1133 	nvlist_t *ret = NULL;
1134 	nvpair_t *nvp;
1135 	size_t rsize = 0;
1136 	rcm_info_t *info = NULL;
1137 
1138 	errno = 0;
1139 
1140 	/*
1141 	 * Decide whether to start the daemon
1142 	 */
1143 	switch (cmd) {
1144 	case CMD_GETINFO:
1145 	case CMD_OFFLINE:
1146 	case CMD_ONLINE:
1147 	case CMD_REMOVE:
1148 	case CMD_SUSPEND:
1149 	case CMD_RESUME:
1150 	case CMD_REGISTER:
1151 	case CMD_UNREGISTER:
1152 	case CMD_EVENT:
1153 	case CMD_REQUEST_CHANGE:
1154 	case CMD_NOTIFY_CHANGE:
1155 	case CMD_GETSTATE:
1156 		break;
1157 
1158 	default:
1159 		errno = EFAULT;
1160 		return (RCM_FAILURE);
1161 	}
1162 
1163 	if (rcm_daemon_is_alive() != 1) {
1164 		dprintf((stderr, "failed to start rcm_daemon\n"));
1165 		errno = EFAULT;
1166 		return (RCM_FAILURE);
1167 	}
1168 
1169 	/*
1170 	 * Generate a packed nvlist for the request
1171 	 */
1172 	if (rcm_generate_nvlist(cmd, hd, rsrcnames, flag, arg, &nvl_packed,
1173 	    &nvl_size) < 0) {
1174 		dprintf((stderr, "error in nvlist generation\n"));
1175 		errno = EFAULT;
1176 		return (RCM_FAILURE);
1177 	}
1178 
1179 	/*
1180 	 * Make the door call and get a return event. We go into a retry loop
1181 	 * when RCM_ET_EAGAIN is returned.
1182 	 */
1183 retry:
1184 	if (get_event_service(RCM_SERVICE_DOOR, (void *)nvl_packed, nvl_size,
1185 	    (void **)&ret, &rsize) < 0) {
1186 		dprintf((stderr, "rcm_daemon call failed: %s\n",
1187 		    strerror(errno)));
1188 		free(nvl_packed);
1189 		return (RCM_FAILURE);
1190 	}
1191 
1192 	assert(ret != NULL);
1193 
1194 	/*
1195 	 * nvlist_lookup_* routines don't work because the returned nvlist
1196 	 * was nvlist_alloc'ed without the NV_UNIQUE_NAME flag.  Implement
1197 	 * a sequential search manually, which is fine since there is only
1198 	 * one RCM_RESULT value in the nvlist.
1199 	 */
1200 	errno_found = 0;
1201 	nvp = NULL;
1202 	while (nvp = nvlist_next_nvpair(ret, nvp)) {
1203 		if (strcmp(nvpair_name(nvp), RCM_RESULT) == 0) {
1204 			if (errno = nvpair_value_int32(nvp, &daemon_errno)) {
1205 				error = RCM_FAILURE;
1206 				goto out;
1207 			}
1208 			errno_found++;
1209 			break;
1210 		}
1211 	}
1212 	if (errno_found == 0) {
1213 		errno = EFAULT;
1214 		error = RCM_FAILURE;
1215 		goto out;
1216 	}
1217 
1218 	if (daemon_errno == EAGAIN) {
1219 		/*
1220 		 * Wait and retry
1221 		 */
1222 		dprintf((stderr, "retry door_call\n"));
1223 
1224 		if (delay > maxdelay) {
1225 			errno = EAGAIN;
1226 			error = RCM_FAILURE;
1227 			goto out;
1228 		}
1229 
1230 		(void) poll(NULL, 0, delay);
1231 		delay *= 2;		/* exponential back off */
1232 		nvlist_free(ret);
1233 		goto retry;
1234 	}
1235 
1236 	/*
1237 	 * The door call succeeded. Now extract info from returned event.
1238 	 */
1239 	if (extract_info(ret, &info) != 0) {
1240 		dprintf((stderr, "error in extracting event data\n"));
1241 		errno = EFAULT;
1242 		error = RCM_FAILURE;
1243 		goto out;
1244 	}
1245 
1246 	if (infop)
1247 		*infop = info;
1248 	else
1249 		rcm_free_info(info);
1250 
1251 	if (daemon_errno) {
1252 		if (daemon_errno > 0) {
1253 			errno = daemon_errno;
1254 			error = RCM_FAILURE;
1255 		} else {
1256 			error = daemon_errno;
1257 		}
1258 	}
1259 
1260 out:
1261 	if (nvl_packed)
1262 		free(nvl_packed);
1263 	if (ret)
1264 		nvlist_free(ret);
1265 	dprintf((stderr, "daemon call is done. error = %d, errno = %s\n", error,
1266 	    strerror(errno)));
1267 	return (error);
1268 }
1269 
1270 /*
1271  * Extract registration info from event data.
1272  * Return 0 on success and -1 on failure.
1273  */
1274 static int
1275 extract_info(nvlist_t *nvl, rcm_info_t **infop)
1276 {
1277 	rcm_info_t *info = NULL;
1278 	rcm_info_t *prev = NULL;
1279 	rcm_info_t *tmp = NULL;
1280 	char *buf;
1281 	uint_t buflen;
1282 	nvpair_t *nvp = NULL;
1283 
1284 	while (nvp = nvlist_next_nvpair(nvl, nvp)) {
1285 
1286 		buf = NULL;
1287 		buflen = 0;
1288 
1289 		if (strcmp(nvpair_name(nvp), RCM_RESULT_INFO) != 0)
1290 			continue;
1291 
1292 		if ((tmp = calloc(1, sizeof (*tmp))) == NULL) {
1293 			dprintf((stderr, "out of memory\n"));
1294 			goto fail;
1295 		}
1296 
1297 		if (errno = nvpair_value_byte_array(nvp, (uchar_t **)&buf,
1298 		    &buflen)) {
1299 			free(tmp);
1300 			dprintf((stderr, "failed (nvpair_value=%s)\n",
1301 			    strerror(errno)));
1302 			goto fail;
1303 		}
1304 		if (errno = nvlist_unpack(buf, buflen, &(tmp->info), 0)) {
1305 			free(tmp);
1306 			dprintf((stderr, "failed (nvlist_unpack=%s)\n",
1307 			    strerror(errno)));
1308 			goto fail;
1309 		}
1310 
1311 		if (info == NULL) {
1312 			prev = info = tmp;
1313 		} else {
1314 			prev->next = tmp;
1315 			prev = tmp;
1316 		}
1317 	}
1318 
1319 	*infop = info;
1320 	return (0);
1321 
1322 fail:
1323 	rcm_free_info(info);
1324 	*infop = NULL;
1325 	return (-1);
1326 }
1327 
1328 /* Generate a packed nvlist for communicating with RCM daemon */
1329 static int
1330 rcm_generate_nvlist(int cmd, rcm_handle_t *hd, char **rsrcnames, uint_t flag,
1331     void *arg, char **nvl_packed, size_t *nvl_size)
1332 {
1333 	int nrsrcnames;
1334 	char *buf = NULL;
1335 	size_t buflen = 0;
1336 	nvlist_t *nvl = NULL;
1337 
1338 	assert((nvl_packed != NULL) && (nvl_size != NULL));
1339 
1340 	*nvl_size = 0;
1341 	*nvl_packed = NULL;
1342 
1343 	/* Allocate an empty nvlist */
1344 	if ((errno = nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0)) > 0) {
1345 		dprintf((stderr, "failed (nvlist_alloc=%s).\n",
1346 		    strerror(errno)));
1347 		return (-1);
1348 	}
1349 
1350 	/* Stuff in all the arguments for the daemon call */
1351 	if (nvlist_add_int32(nvl, RCM_CMD, cmd) != 0) {
1352 		dprintf((stderr, "failed (nvlist_add(CMD)=%s).\n",
1353 		    strerror(errno)));
1354 		goto fail;
1355 	}
1356 	if (rsrcnames) {
1357 		nrsrcnames = 0;
1358 		while (rsrcnames[nrsrcnames] != NULL)
1359 			nrsrcnames++;
1360 		if (nvlist_add_string_array(nvl, RCM_RSRCNAMES, rsrcnames,
1361 		    nrsrcnames) != 0) {
1362 			dprintf((stderr, "failed (nvlist_add(RSRCNAMES)=%s).\n",
1363 			    strerror(errno)));
1364 			goto fail;
1365 		}
1366 	}
1367 	if (hd->modname) {
1368 		if (nvlist_add_string(nvl, RCM_CLIENT_MODNAME, hd->modname)
1369 		    != 0) {
1370 			dprintf((stderr,
1371 			    "failed (nvlist_add(CLIENT_MODNAME)=%s).\n",
1372 			    strerror(errno)));
1373 			goto fail;
1374 		}
1375 	}
1376 	if (hd->pid) {
1377 		if (nvlist_add_uint64(nvl, RCM_CLIENT_ID, hd->pid) != 0) {
1378 			dprintf((stderr, "failed (nvlist_add(CLIENT_ID)=%s).\n",
1379 			    strerror(errno)));
1380 			goto fail;
1381 		}
1382 	}
1383 	if (flag) {
1384 		if (nvlist_add_uint32(nvl, RCM_REQUEST_FLAG, flag) != 0) {
1385 			dprintf((stderr,
1386 			    "failed (nvlist_add(REQUEST_FLAG)=%s).\n",
1387 			    strerror(errno)));
1388 			goto fail;
1389 		}
1390 	}
1391 	if (arg && cmd == CMD_SUSPEND) {
1392 		if (nvlist_add_byte_array(nvl, RCM_SUSPEND_INTERVAL,
1393 		    (uchar_t *)arg, sizeof (timespec_t)) != 0) {
1394 			dprintf((stderr,
1395 			    "failed (nvlist_add(SUSPEND_INTERVAL)=%s).\n",
1396 			    strerror(errno)));
1397 			goto fail;
1398 		}
1399 	}
1400 	if (arg &&
1401 	    ((cmd == CMD_REQUEST_CHANGE) || (cmd == CMD_NOTIFY_CHANGE))) {
1402 		if (errno = nvlist_pack(arg, &buf, &buflen, NV_ENCODE_NATIVE,
1403 		    0)) {
1404 			dprintf((stderr,
1405 			    "failed (nvlist_pack(CHANGE_DATA)=%s).\n",
1406 			    strerror(errno)));
1407 			goto fail;
1408 		}
1409 		if (nvlist_add_byte_array(nvl, RCM_CHANGE_DATA, (uchar_t *)buf,
1410 		    buflen) != 0) {
1411 			dprintf((stderr,
1412 			    "failed (nvlist_add(CHANGE_DATA)=%s).\n",
1413 			    strerror(errno)));
1414 			goto fail;
1415 		}
1416 	}
1417 	if (arg && cmd == CMD_EVENT) {
1418 		if (errno = nvlist_pack(arg, &buf, &buflen, NV_ENCODE_NATIVE,
1419 		    0)) {
1420 			dprintf((stderr,
1421 			    "failed (nvlist_pack(CHANGE_DATA)=%s).\n",
1422 			    strerror(errno)));
1423 			goto fail;
1424 		}
1425 		if (nvlist_add_byte_array(nvl, RCM_EVENT_DATA, (uchar_t *)buf,
1426 		    buflen) != 0) {
1427 			dprintf((stderr,
1428 			    "failed (nvlist_add(EVENT_DATA)=%s).\n",
1429 			    strerror(errno)));
1430 			goto fail;
1431 		}
1432 	}
1433 
1434 	/* Pack the nvlist */
1435 	if (errno = nvlist_pack(nvl, nvl_packed, nvl_size, NV_ENCODE_NATIVE,
1436 	    0)) {
1437 		dprintf((stderr, "failed (nvlist_pack=%s).\n",
1438 		    strerror(errno)));
1439 		goto fail;
1440 	}
1441 
1442 	/* If an argument was packed intermediately, free the buffer */
1443 	if (buf)
1444 		free(buf);
1445 
1446 	/* Free the unpacked version of the nvlist and return the packed list */
1447 	nvlist_free(nvl);
1448 	return (0);
1449 
1450 fail:
1451 	if (buf)
1452 		free(buf);
1453 	if (nvl)
1454 		nvlist_free(nvl);
1455 	if (*nvl_packed)
1456 		free(*nvl_packed);
1457 	*nvl_packed = NULL;
1458 	*nvl_size = 0;
1459 	return (-1);
1460 }
1461 
1462 /* check if rcm_daemon is up and running */
1463 static int
1464 rcm_daemon_is_alive()
1465 {
1466 	int lasttry;
1467 	struct stat st;
1468 	nvlist_t *nvl;
1469 	char *buf = NULL;
1470 	size_t buflen = 0;
1471 	int delay = 300;
1472 	const int maxdelay = 10000;	/* 10 sec */
1473 
1474 	/* generate a packed nvlist for the door knocking */
1475 	if (errno = nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0)) {
1476 		dprintf((stderr, "nvlist_alloc failed: %s\n", strerror(errno)));
1477 		return (0);
1478 	}
1479 	if (errno = nvlist_add_int32(nvl, RCM_CMD, CMD_KNOCK)) {
1480 		dprintf((stderr, "nvlist_add failed: %s\n", strerror(errno)));
1481 		nvlist_free(nvl);
1482 		return (0);
1483 	}
1484 	if (errno = nvlist_pack(nvl, &buf, &buflen, NV_ENCODE_NATIVE, 0)) {
1485 		dprintf((stderr, "nvlist_pack failed: %s\n", strerror(errno)));
1486 		nvlist_free(nvl);
1487 		return (0);
1488 	}
1489 	nvlist_free(nvl);
1490 
1491 	/*
1492 	 * check the door and knock on it
1493 	 */
1494 	if ((stat(RCM_SERVICE_DOOR, &st) == 0) &&
1495 	    (get_event_service(RCM_SERVICE_DOOR, (void *)buf, buflen, NULL,
1496 	    NULL) == 0)) {
1497 		free(buf);
1498 		return (1);	/* daemon is alive */
1499 	}
1500 
1501 	/*
1502 	 * Attempt to start the daemon.
1503 	 * If caller has SIGCHLD set to SIG_IGN or its SA_NOCLDWAIT
1504 	 * flag set, waitpid(2) (hence rcm_exec_cmd) will fail.
1505 	 * get_event_service will determine if the rcm_daemon started.
1506 	 */
1507 	dprintf((stderr, "exec: %s\n", RCM_DAEMON_START));
1508 	(void) rcm_exec_cmd(RCM_DAEMON_START);
1509 
1510 	/*
1511 	 * Wait for daemon to respond, timeout at 10 sec
1512 	 */
1513 	while (((lasttry = get_event_service(RCM_SERVICE_DOOR, (void *)buf,
1514 	    buflen, NULL, NULL)) != 0) &&
1515 	    ((errno == EBADF) || (errno == ESRCH))) {
1516 		if (delay > maxdelay) {
1517 			break;
1518 		}
1519 		(void) poll(NULL, 0, delay);
1520 		delay *= 2;
1521 	}
1522 
1523 	free(buf);
1524 	if (lasttry == 0)
1525 		return (1);
1526 	return (0);
1527 }
1528 
1529 /*
1530  * Check permission.
1531  *
1532  * The policy is root only for now. Need to relax this when interface level
1533  * is raised.
1534  */
1535 static int
1536 rcm_check_permission(void)
1537 {
1538 	return (getuid() == 0);
1539 }
1540 
1541 /*
1542  * Project private function - for use by RCM MSTC tests
1543  *
1544  * Get the client name (rcm module name or script name) corresponding to
1545  * the given rcm handle.
1546  */
1547 const char *
1548 rcm_get_client_name(rcm_handle_t *hd)
1549 {
1550 	return (hd->modname);
1551 }
1552