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