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
rcm_alloc_handle(char * modname,uint_t flag,void * arg,rcm_handle_t ** hdp)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
rcm_free_handle(rcm_handle_t * hd)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
rcm_get_info(rcm_handle_t * hd,char * rsrcname,uint_t flag,rcm_info_t ** infop)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
rcm_get_info_list(rcm_handle_t * hd,char ** rsrcnames,uint_t flag,rcm_info_t ** infop)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
rcm_request_offline(rcm_handle_t * hd,char * rsrcname,uint_t flag,rcm_info_t ** infop)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
rcm_request_offline_list(rcm_handle_t * hd,char ** rsrcnames,uint_t flag,rcm_info_t ** infop)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
rcm_notify_online(rcm_handle_t * hd,char * rsrcname,uint_t flag,rcm_info_t ** infop)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
rcm_notify_online_list(rcm_handle_t * hd,char ** rsrcnames,uint_t flag,rcm_info_t ** infop)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
rcm_notify_remove(rcm_handle_t * hd,char * rsrcname,uint_t flag,rcm_info_t ** infop)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
rcm_notify_remove_list(rcm_handle_t * hd,char ** rsrcnames,uint_t flag,rcm_info_t ** infop)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
rcm_request_suspend(rcm_handle_t * hd,char * rsrcname,uint_t flag,timespec_t * interval,rcm_info_t ** infop)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
rcm_request_suspend_list(rcm_handle_t * hd,char ** rsrcnames,uint_t flag,timespec_t * interval,rcm_info_t ** infop)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
rcm_notify_resume(rcm_handle_t * hd,char * rsrcname,uint_t flag,rcm_info_t ** infop)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
rcm_notify_resume_list(rcm_handle_t * hd,char ** rsrcnames,uint_t flag,rcm_info_t ** infop)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
rcm_request_capacity_change(rcm_handle_t * hd,char * rsrcname,uint_t flag,nvlist_t * nvl,rcm_info_t ** infop)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
rcm_notify_capacity_change(rcm_handle_t * hd,char * rsrcname,uint_t flag,nvlist_t * nvl,rcm_info_t ** infop)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
rcm_notify_event(rcm_handle_t * hd,char * rsrcname,uint_t flag,nvlist_t * nvl,rcm_info_t ** infop)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
rcm_register_capacity(rcm_handle_t * hd,char * rsrcname,uint_t flag,rcm_info_t ** infop)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
rcm_unregister_capacity(rcm_handle_t * hd,char * rsrcname,uint_t flag)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
rcm_register_event(rcm_handle_t * hd,char * rsrcname,uint_t flag,rcm_info_t ** infop)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
rcm_unregister_event(rcm_handle_t * hd,char * rsrcname,uint_t flag)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
rcm_register_interest(rcm_handle_t * hd,char * rsrcname,uint_t flag,rcm_info_t ** infop)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
rcm_unregister_interest(rcm_handle_t * hd,char * rsrcname,uint_t flag)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
rcm_get_rsrcstate(rcm_handle_t * hd,char * rsrcname,int * statep)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
rcm_free_info(rcm_info_t * info)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 *
rcm_info_next(rcm_info_t * info,rcm_info_tuple_t * tuple)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 *
rcm_info_rsrc(rcm_info_tuple_t * tuple)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 *
rcm_info_info(rcm_info_tuple_t * tuple)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 *
rcm_info_error(rcm_info_tuple_t * tuple)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 *
rcm_info_modname(rcm_info_tuple_t * tuple)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
rcm_info_pid(rcm_info_tuple_t * tuple)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
rcm_info_state(rcm_info_tuple_t * tuple)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 *
rcm_info_properties(rcm_info_tuple_t * tuple)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
rcm_info_seqnum(rcm_info_tuple_t * tuple)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
rcm_exec_cmd(char * cmd)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
rcm_append_info(rcm_info_t ** head,rcm_info_t * info)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 *
rcm_module_dir(uint_t dirnum)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 *
rcm_script_dir(uint_t dirnum)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 *
rcm_dir(uint_t dirnum,int * rcm_script)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 *
rcm_get_script_dir(char * script_name)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
rcm_is_script(char * filename)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 *
rcm_module_open(char * modname)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
rcm_module_close(void * dlhandle)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
rcm_log_message(int level,char * message,...)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
rcm_common(int cmd,rcm_handle_t * hd,char ** rsrcnames,uint_t flag,void * arg,rcm_info_t ** infop)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
rcm_direct_call(int cmd,rcm_handle_t * hd,char ** rsrcnames,uint_t flag,void * arg,rcm_info_t ** infop)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
rcm_daemon_call(int cmd,rcm_handle_t * hd,char ** rsrcnames,uint_t flag,void * arg,rcm_info_t ** infop)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
extract_info(nvlist_t * nvl,rcm_info_t ** infop)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
rcm_generate_nvlist(int cmd,rcm_handle_t * hd,char ** rsrcnames,uint_t flag,void * arg,char ** nvl_packed,size_t * nvl_size)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
rcm_daemon_is_alive()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
rcm_check_permission(void)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 *
rcm_get_client_name(rcm_handle_t * hd)1548 rcm_get_client_name(rcm_handle_t *hd)
1549 {
1550 return (hd->modname);
1551 }
1552