Print this page
6139 help gcc figure out variable initialization
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/lib/libhotplug/common/libhotplug.c
+++ new/usr/src/lib/libhotplug/common/libhotplug.c
1 1 /*
2 2 * CDDL HEADER START
3 3 *
4 4 * The contents of this file are subject to the terms of the
5 5 * Common Development and Distribution License (the "License").
6 6 * You may not use this file except in compliance with the License.
7 7 *
8 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 9 * or http://www.opensolaris.org/os/licensing.
10 10 * See the License for the specific language governing permissions
11 11 * and limitations under the License.
12 12 *
13 13 * When distributing Covered Code, include this CDDL HEADER in each
14 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 15 * If applicable, add the following below this CDDL HEADER, with the
16 16 * fields enclosed by brackets "[]" replaced with your own identifying
17 17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 18 *
19 19 * CDDL HEADER END
20 20 */
21 21 /*
22 22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
23 23 * Use is subject to license terms.
24 24 */
25 25
26 26 #include <stdio.h>
27 27 #include <stdlib.h>
28 28 #include <stdarg.h>
29 29 #include <unistd.h>
30 30 #include <fcntl.h>
31 31 #include <errno.h>
32 32 #include <string.h>
33 33 #include <door.h>
34 34 #include <libnvpair.h>
35 35 #include <libhotplug.h>
36 36 #include <libhotplug_impl.h>
37 37 #include <sys/sunddi.h>
38 38 #include <sys/ddi_hp.h>
39 39
40 40 static void i_hp_dprintf(const char *fmt, ...);
41 41 static int i_hp_pack_branch(hp_node_t, char **, size_t *);
42 42 static int i_hp_pack_node(hp_node_t, char **, size_t *);
43 43 static int i_hp_unpack_node(char *, size_t, hp_node_t, hp_node_t *);
44 44 static int i_hp_unpack_branch(char *, size_t, hp_node_t, hp_node_t *);
45 45 static int i_hp_call_hotplugd(nvlist_t *, nvlist_t **);
46 46 static nvlist_t *i_hp_set_args(hp_cmd_t, const char *, const char *, uint_t,
47 47 const char *, int);
48 48 static int i_hp_parse_results(nvlist_t *, hp_node_t *, char **);
49 49
50 50 /*
51 51 * Global flag to enable debug features.
52 52 */
53 53 int libhotplug_debug = 0;
54 54
55 55 /*
56 56 * hp_init()
57 57 *
58 58 * Initialize a hotplug information snapshot.
59 59 */
60 60 hp_node_t
61 61 hp_init(const char *path, const char *connection, uint_t flags)
62 62 {
63 63 nvlist_t *args;
64 64 nvlist_t *results;
65 65 hp_node_t root = NULL;
66 66 int rv;
67 67
68 68 i_hp_dprintf("hp_init: path=%p, connection=%p, flags=0x%x\n",
69 69 (void *)path, (void *)connection, flags);
70 70
71 71 /* Check arguments */
72 72 if ((path == NULL) || !HP_INIT_FLAGS_VALID(flags)) {
73 73 i_hp_dprintf("hp_init: invalid arguments.\n");
74 74 errno = EINVAL;
75 75 return (NULL);
76 76 }
77 77
78 78 /* Build arguments for door call */
79 79 if ((args = i_hp_set_args(HP_CMD_GETINFO, path, connection, flags,
80 80 NULL, 0)) == NULL) {
81 81 i_hp_dprintf("hp_init: cannot build arguments nvlist.\n");
82 82 errno = ENOMEM;
83 83 return (NULL);
84 84 }
85 85
86 86 /* Make the door call to hotplugd */
87 87 rv = i_hp_call_hotplugd(args, &results);
88 88
89 89 /* Arguments no longer needed */
90 90 nvlist_free(args);
91 91
92 92 /* Parse additional results, if any */
93 93 if ((rv == 0) && (results != NULL)) {
94 94 rv = i_hp_parse_results(results, &root, NULL);
95 95 nvlist_free(results);
96 96 }
97 97
98 98 /* Check for errors */
99 99 if (rv != 0) {
100 100 i_hp_dprintf("hp_init: failure (%s).\n", strerror(rv));
101 101 if (root)
102 102 hp_fini(root);
103 103 errno = rv;
104 104 return (NULL);
105 105 }
106 106
107 107 /* Success requires an info snapshot */
108 108 if (root == NULL) {
109 109 i_hp_dprintf("hp_init: missing info snapshot.\n");
110 110 errno = EFAULT;
111 111 return (NULL);
112 112 }
113 113
114 114 /* Success */
115 115 return (root);
116 116 }
117 117
118 118 /*
119 119 * hp_fini()
120 120 *
121 121 * Terminate and clean-up a hotplug information snapshot.
122 122 */
123 123 void
124 124 hp_fini(hp_node_t root)
125 125 {
126 126 hp_node_t node;
127 127 hp_node_t sibling;
128 128 char *basepath;
129 129
130 130 i_hp_dprintf("hp_fini: root=%p\n", (void *)root);
131 131
132 132 if (root == NULL) {
133 133 i_hp_dprintf("hp_fini: invalid arguments.\n");
134 134 return;
135 135 }
136 136
137 137 /* Extract and free base path */
138 138 if (root->hp_basepath) {
139 139 basepath = root->hp_basepath;
140 140 for (node = root; node != NULL; node = node->hp_sibling)
141 141 node->hp_basepath = NULL;
142 142 free(basepath);
143 143 }
144 144
145 145 /* Destroy the nodes */
146 146 node = root;
147 147 while (node) {
148 148 sibling = node->hp_sibling;
149 149 if (node->hp_child)
150 150 hp_fini(node->hp_child);
151 151 if (node->hp_name)
152 152 free(node->hp_name);
153 153 if (node->hp_usage)
154 154 free(node->hp_usage);
155 155 if (node->hp_description)
156 156 free(node->hp_description);
157 157 free(node);
158 158 node = sibling;
159 159 }
160 160 }
161 161
162 162 /*
163 163 * hp_traverse()
164 164 *
165 165 * Walk a graph of hotplug nodes, executing a callback on each node.
166 166 */
167 167 int
168 168 hp_traverse(hp_node_t root, void *arg, int (*hp_callback)(hp_node_t, void *arg))
169 169 {
170 170 int rv;
171 171 hp_node_t node;
172 172
173 173 i_hp_dprintf("hp_traverse: root=%p, arg=%p, hp_callback=%p\n",
174 174 (void *)root, arg, (void *)hp_callback);
175 175
176 176 /* Check arguments */
177 177 if ((root == NULL) || (hp_callback == NULL)) {
178 178 i_hp_dprintf("hp_traverse: invalid arguments.\n");
179 179 errno = EINVAL;
180 180 return (-1);
181 181 }
182 182
183 183 for (node = root; node; node = node->hp_sibling) {
184 184 rv = hp_callback(node, arg);
185 185
186 186 if (rv == HP_WALK_TERMINATE) {
187 187 i_hp_dprintf("hp_traverse: walk terminated.\n");
188 188 return (HP_WALK_TERMINATE);
189 189 }
190 190
191 191 if (node->hp_child && (rv != HP_WALK_PRUNECHILD))
192 192 if (hp_traverse(node->hp_child, arg, hp_callback) ==
193 193 HP_WALK_TERMINATE) {
194 194 i_hp_dprintf("hp_traverse: walk terminated.\n");
195 195 return (HP_WALK_TERMINATE);
196 196 }
197 197
198 198 if (rv == HP_WALK_PRUNESIBLING)
199 199 break;
200 200 }
201 201
202 202 return (0);
203 203 }
204 204
205 205 /*
206 206 * hp_type()
207 207 *
208 208 * Return a node's type.
209 209 */
210 210 int
211 211 hp_type(hp_node_t node)
212 212 {
213 213 i_hp_dprintf("hp_type: node=%p\n", (void *)node);
214 214
215 215 if (node == NULL) {
216 216 i_hp_dprintf("hp_type: invalid arguments.\n");
217 217 errno = EINVAL;
218 218 return (-1);
219 219 }
220 220
221 221 return (node->hp_type);
222 222 }
223 223
224 224 /*
225 225 * hp_name()
226 226 *
227 227 * Return a node's name.
228 228 */
229 229 char *
230 230 hp_name(hp_node_t node)
231 231 {
232 232 i_hp_dprintf("hp_name: node=%p\n", (void *)node);
233 233
234 234 if (node == NULL) {
235 235 i_hp_dprintf("hp_name: invalid arguments.\n");
236 236 errno = EINVAL;
237 237 return (NULL);
238 238 }
239 239
240 240 if (node->hp_name == NULL) {
241 241 i_hp_dprintf("hp_name: missing name value.\n");
242 242 errno = EFAULT;
243 243 }
244 244
245 245 return (node->hp_name);
246 246 }
247 247
248 248 /*
249 249 * hp_state()
250 250 *
251 251 * Return a node's current state.
252 252 */
253 253 int
254 254 hp_state(hp_node_t node)
255 255 {
256 256 i_hp_dprintf("hp_state: node=%p\n", (void *)node);
257 257
258 258 if (node == NULL) {
259 259 i_hp_dprintf("hp_state: invalid arguments.\n");
260 260 errno = EINVAL;
261 261 return (-1);
262 262 }
263 263
264 264 if ((node->hp_type != HP_NODE_CONNECTOR) &&
265 265 (node->hp_type != HP_NODE_PORT)) {
266 266 i_hp_dprintf("hp_state: operation not supported.\n");
267 267 errno = ENOTSUP;
268 268 return (-1);
269 269 }
270 270
271 271 return (node->hp_state);
272 272 }
273 273
274 274 /*
275 275 * hp_usage()
276 276 *
277 277 * Return a usage description for usage nodes.
278 278 */
279 279 char *
280 280 hp_usage(hp_node_t node)
281 281 {
282 282 i_hp_dprintf("hp_usage: node=%p\n", (void *)node);
283 283
284 284 if (node == NULL) {
285 285 i_hp_dprintf("hp_usage: invalid arguments.\n");
286 286 errno = EINVAL;
287 287 return (NULL);
288 288 }
289 289
290 290 if (node->hp_type != HP_NODE_USAGE) {
291 291 i_hp_dprintf("hp_usage: operation not supported.\n");
292 292 errno = ENOTSUP;
293 293 return (NULL);
294 294 }
295 295
296 296 if (node->hp_usage == NULL) {
297 297 i_hp_dprintf("hp_usage: missing usage value.\n");
298 298 errno = EFAULT;
299 299 }
300 300
301 301 return (node->hp_usage);
302 302 }
303 303
304 304 /*
305 305 * hp_description()
306 306 *
307 307 * Return a type description (e.g. "PCI slot") for connection nodes.
308 308 */
309 309 char *
310 310 hp_description(hp_node_t node)
311 311 {
312 312 i_hp_dprintf("hp_description: node=%p\n", (void *)node);
313 313
314 314 if (node == NULL) {
315 315 i_hp_dprintf("hp_description: invalid arguments.\n");
316 316 errno = EINVAL;
317 317 return (NULL);
318 318 }
319 319
320 320 if ((node->hp_type != HP_NODE_CONNECTOR) &&
321 321 (node->hp_type != HP_NODE_PORT)) {
322 322 i_hp_dprintf("hp_description: operation not supported.\n");
323 323 errno = ENOTSUP;
324 324 return (NULL);
325 325 }
326 326
327 327 if (node->hp_description == NULL) {
328 328 i_hp_dprintf("hp_description: missing description value.\n");
329 329 errno = EFAULT;
330 330 }
331 331
332 332 return (node->hp_description);
333 333 }
334 334
335 335 /*
336 336 * hp_last_change()
337 337 *
338 338 * Return when the state of a connection was last changed.
339 339 */
340 340 time_t
341 341 hp_last_change(hp_node_t node)
342 342 {
343 343 i_hp_dprintf("hp_last_change: node=%p\n", (void *)node);
344 344
345 345 if (node == NULL) {
346 346 i_hp_dprintf("hp_last_change: invalid arguments.\n");
347 347 errno = EINVAL;
348 348 return (NULL);
349 349 }
350 350
351 351 if ((node->hp_type != HP_NODE_CONNECTOR) &&
352 352 (node->hp_type != HP_NODE_PORT)) {
353 353 i_hp_dprintf("hp_last_change: operation not supported.\n");
354 354 errno = ENOTSUP;
355 355 return (NULL);
356 356 }
357 357
358 358 return (node->hp_last_change);
359 359 }
360 360
361 361 /*
362 362 * hp_parent()
363 363 *
364 364 * Return a node's parent node.
365 365 */
366 366 hp_node_t
367 367 hp_parent(hp_node_t node)
368 368 {
369 369 i_hp_dprintf("hp_parent: node=%p\n", (void *)node);
370 370
371 371 if (node == NULL) {
372 372 i_hp_dprintf("hp_parent: invalid arguments.\n");
373 373 errno = EINVAL;
374 374 return (NULL);
375 375 }
376 376
377 377 if (node->hp_parent == NULL) {
378 378 i_hp_dprintf("hp_parent: node has no parent.\n");
379 379 errno = ENXIO;
380 380 }
381 381
382 382 return (node->hp_parent);
383 383 }
384 384
385 385 /*
386 386 * hp_child()
387 387 *
388 388 * Return a node's first child node.
389 389 */
390 390 hp_node_t
391 391 hp_child(hp_node_t node)
392 392 {
393 393 i_hp_dprintf("hp_child: node=%p\n", (void *)node);
394 394
395 395 if (node == NULL) {
396 396 i_hp_dprintf("hp_child: invalid arguments.\n");
397 397 errno = EINVAL;
398 398 return (NULL);
399 399 }
400 400
401 401 if (node->hp_child == NULL) {
402 402 i_hp_dprintf("hp_child: node has no child.\n");
403 403 errno = ENXIO;
404 404 }
405 405
406 406 return (node->hp_child);
407 407 }
408 408
409 409 /*
410 410 * hp_sibling()
411 411 *
412 412 * Return a node's next sibling node.
413 413 */
414 414 hp_node_t
415 415 hp_sibling(hp_node_t node)
416 416 {
417 417 i_hp_dprintf("hp_sibling: node=%p\n", (void *)node);
418 418
419 419 if (node == NULL) {
420 420 i_hp_dprintf("hp_sibling: invalid arguments.\n");
421 421 errno = EINVAL;
422 422 return (NULL);
423 423 }
424 424
425 425 if (node->hp_sibling == NULL) {
426 426 i_hp_dprintf("hp_sibling: node has no sibling.\n");
427 427 errno = ENXIO;
428 428 }
429 429
430 430 return (node->hp_sibling);
431 431 }
432 432
433 433 /*
434 434 * hp_path()
435 435 *
436 436 * Return the path (and maybe connection name) of a node.
437 437 * The caller must supply two buffers, each MAXPATHLEN size.
438 438 */
439 439 int
440 440 hp_path(hp_node_t node, char *path, char *connection)
441 441 {
442 442 hp_node_t root;
443 443 hp_node_t parent;
444 444 int i;
445 445 char *s;
446 446 char components[MAXPATHLEN];
447 447
448 448 i_hp_dprintf("hp_path: node=%p, path=%p, connection=%p\n", (void *)node,
449 449 (void *)path, (void *)connection);
450 450
451 451 if ((node == NULL) || (path == NULL) || (connection == NULL)) {
452 452 i_hp_dprintf("hp_path: invalid arguments.\n");
453 453 return (EINVAL);
454 454 }
455 455
↓ open down ↓ |
455 lines elided |
↑ open up ↑ |
456 456 (void) memset(path, 0, MAXPATHLEN);
457 457 (void) memset(connection, 0, MAXPATHLEN);
458 458 (void) memset(components, 0, MAXPATHLEN);
459 459
460 460 /* Set 'connection' only for connectors and ports */
461 461 if ((node->hp_type == HP_NODE_CONNECTOR) ||
462 462 (node->hp_type == HP_NODE_PORT))
463 463 (void) strlcpy(connection, node->hp_name, MAXPATHLEN);
464 464
465 465 /* Trace back to the root node, accumulating components */
466 - for (parent = node; parent != NULL; parent = parent->hp_parent) {
466 + for (parent = node, root = parent; parent != NULL;
467 + root = parent, parent = parent->hp_parent) {
467 468 if (parent->hp_type == HP_NODE_DEVICE) {
468 469 (void) strlcat(components, "/", MAXPATHLEN);
469 470 (void) strlcat(components, parent->hp_name, MAXPATHLEN);
470 471 }
471 - if (parent->hp_parent == NULL)
472 - root = parent;
473 472 }
474 473
475 474 /* Ensure the snapshot actually contains a base path */
476 475 if (root->hp_basepath == NULL) {
477 476 i_hp_dprintf("hp_path: missing base pathname.\n");
478 477 return (EFAULT);
479 478 }
480 479
481 480 /*
482 481 * Construct the path. Start with the base path from the root
483 482 * node, then append the accumulated components in reverse order.
484 483 */
485 484 if (strcmp(root->hp_basepath, "/") != 0) {
486 485 (void) strlcat(path, root->hp_basepath, MAXPATHLEN);
487 486 if ((root->hp_type == HP_NODE_DEVICE) &&
488 487 ((s = strrchr(path, '/')) != NULL))
489 488 *s = '\0';
490 489 }
491 490 for (i = strlen(components) - 1; i >= 0; i--) {
492 491 if (components[i] == '/') {
493 492 (void) strlcat(path, &components[i], MAXPATHLEN);
494 493 components[i] = '\0';
495 494 }
496 495 }
497 496
498 497 return (0);
499 498 }
500 499
501 500 /*
502 501 * hp_set_state()
503 502 *
504 503 * Initiate a state change operation on a node.
505 504 */
506 505 int
507 506 hp_set_state(hp_node_t node, uint_t flags, int state, hp_node_t *resultsp)
508 507 {
509 508 hp_node_t root = NULL;
510 509 nvlist_t *args;
511 510 nvlist_t *results;
512 511 int rv;
513 512 char path[MAXPATHLEN];
514 513 char connection[MAXPATHLEN];
515 514
516 515 i_hp_dprintf("hp_set_state: node=%p, flags=0x%x, state=0x%x, "
517 516 "resultsp=%p\n", (void *)node, flags, state, (void *)resultsp);
518 517
519 518 /* Check arguments */
520 519 if ((node == NULL) || (resultsp == NULL) ||
521 520 !HP_SET_STATE_FLAGS_VALID(flags)) {
522 521 i_hp_dprintf("hp_set_state: invalid arguments.\n");
523 522 return (EINVAL);
524 523 }
525 524
526 525 /* Check node type */
527 526 if ((node->hp_type != HP_NODE_CONNECTOR) &&
528 527 (node->hp_type != HP_NODE_PORT)) {
529 528 i_hp_dprintf("hp_set_state: operation not supported.\n");
530 529 return (ENOTSUP);
531 530 }
532 531
533 532 /* Check that target state is valid */
534 533 switch (state) {
535 534 case DDI_HP_CN_STATE_PRESENT:
536 535 case DDI_HP_CN_STATE_POWERED:
537 536 case DDI_HP_CN_STATE_ENABLED:
538 537 if (node->hp_type != HP_NODE_CONNECTOR) {
539 538 i_hp_dprintf("hp_set_state: mismatched target.\n");
540 539 return (ENOTSUP);
541 540 }
542 541 break;
543 542 case DDI_HP_CN_STATE_PORT_PRESENT:
544 543 case DDI_HP_CN_STATE_OFFLINE:
545 544 case DDI_HP_CN_STATE_ONLINE:
546 545 if (node->hp_type != HP_NODE_PORT) {
547 546 i_hp_dprintf("hp_set_state: mismatched target.\n");
548 547 return (ENOTSUP);
549 548 }
550 549 break;
551 550 default:
552 551 i_hp_dprintf("hp_set_state: invalid target state.\n");
553 552 return (EINVAL);
554 553 }
555 554
556 555 /* Get path and connection of specified node */
557 556 if ((rv = hp_path(node, path, connection)) != 0)
558 557 return (rv);
559 558
560 559 /* Build arguments for door call */
561 560 if ((args = i_hp_set_args(HP_CMD_CHANGESTATE, path, connection, flags,
562 561 NULL, state)) == NULL)
563 562 return (ENOMEM);
564 563
565 564 /* Make the door call to hotplugd */
566 565 rv = i_hp_call_hotplugd(args, &results);
567 566
568 567 /* Arguments no longer needed */
569 568 nvlist_free(args);
570 569
571 570 /* Parse additional results, if any */
572 571 if ((rv == 0) && (results != NULL)) {
573 572 rv = i_hp_parse_results(results, &root, NULL);
574 573 nvlist_free(results);
575 574 *resultsp = root;
576 575 }
577 576
578 577 /* Done */
579 578 return (rv);
580 579 }
581 580
582 581 /*
583 582 * hp_set_private()
584 583 *
585 584 * Set bus private options on the hotplug connection
586 585 * indicated by the given hotplug information node.
587 586 */
588 587 int
589 588 hp_set_private(hp_node_t node, const char *options, char **resultsp)
590 589 {
591 590 int rv;
592 591 nvlist_t *args;
593 592 nvlist_t *results;
594 593 char *values = NULL;
595 594 char path[MAXPATHLEN];
596 595 char connection[MAXPATHLEN];
597 596
598 597 i_hp_dprintf("hp_set_private: node=%p, options=%p, resultsp=%p\n",
599 598 (void *)node, (void *)options, (void *)resultsp);
600 599
601 600 /* Check arguments */
602 601 if ((node == NULL) || (options == NULL) || (resultsp == NULL)) {
603 602 i_hp_dprintf("hp_set_private: invalid arguments.\n");
604 603 return (EINVAL);
605 604 }
606 605
607 606 /* Check node type */
608 607 if (node->hp_type != HP_NODE_CONNECTOR) {
609 608 i_hp_dprintf("hp_set_private: operation not supported.\n");
610 609 return (ENOTSUP);
611 610 }
612 611
613 612 /* Initialize results */
614 613 *resultsp = NULL;
615 614
616 615 /* Get path and connection of specified node */
617 616 if ((rv = hp_path(node, path, connection)) != 0)
618 617 return (rv);
619 618
620 619 /* Build arguments for door call */
621 620 if ((args = i_hp_set_args(HP_CMD_SETPRIVATE, path, connection, 0,
622 621 options, 0)) == NULL)
623 622 return (ENOMEM);
624 623
625 624 /* Make the door call to hotplugd */
626 625 rv = i_hp_call_hotplugd(args, &results);
627 626
628 627 /* Arguments no longer needed */
629 628 nvlist_free(args);
630 629
631 630 /* Parse additional results, if any */
632 631 if ((rv == 0) && (results != NULL)) {
633 632 rv = i_hp_parse_results(results, NULL, &values);
634 633 nvlist_free(results);
635 634 *resultsp = values;
636 635 }
637 636
638 637 /* Done */
639 638 return (rv);
640 639 }
641 640
642 641 /*
643 642 * hp_get_private()
644 643 *
645 644 * Get bus private options on the hotplug connection
646 645 * indicated by the given hotplug information node.
647 646 */
648 647 int
649 648 hp_get_private(hp_node_t node, const char *options, char **resultsp)
650 649 {
651 650 int rv;
652 651 nvlist_t *args;
653 652 nvlist_t *results;
654 653 char *values = NULL;
655 654 char path[MAXPATHLEN];
656 655 char connection[MAXPATHLEN];
657 656
658 657 i_hp_dprintf("hp_get_private: node=%p, options=%p, resultsp=%p\n",
659 658 (void *)node, (void *)options, (void *)resultsp);
660 659
661 660 /* Check arguments */
662 661 if ((node == NULL) || (options == NULL) || (resultsp == NULL)) {
663 662 i_hp_dprintf("hp_get_private: invalid arguments.\n");
664 663 return (EINVAL);
665 664 }
666 665
667 666 /* Check node type */
668 667 if (node->hp_type != HP_NODE_CONNECTOR) {
669 668 i_hp_dprintf("hp_get_private: operation not supported.\n");
670 669 return (ENOTSUP);
671 670 }
672 671
673 672 /* Initialize results */
674 673 *resultsp = NULL;
675 674
676 675 /* Get path and connection of specified node */
677 676 if ((rv = hp_path(node, path, connection)) != 0)
678 677 return (rv);
679 678
680 679 /* Build arguments for door call */
681 680 if ((args = i_hp_set_args(HP_CMD_GETPRIVATE, path, connection, 0,
682 681 options, 0)) == NULL)
683 682 return (ENOMEM);
684 683
685 684 /* Make the door call to hotplugd */
686 685 rv = i_hp_call_hotplugd(args, &results);
687 686
688 687 /* Arguments no longer needed */
689 688 nvlist_free(args);
690 689
691 690 /* Parse additional results, if any */
692 691 if ((rv == 0) && (results != NULL)) {
693 692 rv = i_hp_parse_results(results, NULL, &values);
694 693 nvlist_free(results);
695 694 *resultsp = values;
696 695 }
697 696
698 697 /* Done */
699 698 return (rv);
700 699 }
701 700
702 701 /*
703 702 * hp_pack()
704 703 *
705 704 * Given the root of a hotplug information snapshot, pack
706 705 * it into a contiguous byte array so that it is suitable
707 706 * for network transport.
708 707 */
709 708 int
710 709 hp_pack(hp_node_t root, char **bufp, size_t *lenp)
711 710 {
712 711 hp_node_t node;
713 712 nvlist_t *nvl;
714 713 char *buf;
715 714 size_t len;
716 715 int rv;
717 716
718 717 i_hp_dprintf("hp_pack: root=%p, bufp=%p, lenp=%p\n", (void *)root,
719 718 (void *)bufp, (void *)lenp);
720 719
721 720 if ((root == NULL) || (bufp == NULL) || (lenp == NULL)) {
722 721 i_hp_dprintf("hp_pack: invalid arguments.\n");
723 722 return (EINVAL);
724 723 }
725 724
726 725 *lenp = 0;
727 726 *bufp = NULL;
728 727
729 728 if (nvlist_alloc(&nvl, 0, 0) != 0) {
730 729 i_hp_dprintf("hp_pack: nvlist_alloc() failed (%s).\n",
731 730 strerror(errno));
732 731 return (ENOMEM);
733 732 }
734 733
735 734 if (root->hp_basepath != NULL) {
736 735 rv = nvlist_add_string(nvl, HP_INFO_BASE, root->hp_basepath);
737 736 if (rv != 0) {
738 737 nvlist_free(nvl);
739 738 return (rv);
740 739 }
741 740 }
742 741
743 742 for (node = root; node != NULL; node = node->hp_sibling) {
744 743 if ((rv = i_hp_pack_branch(node, &buf, &len)) == 0) {
745 744 rv = nvlist_add_byte_array(nvl, HP_INFO_BRANCH,
746 745 (uchar_t *)buf, len);
747 746 free(buf);
748 747 }
749 748 if (rv != 0) {
750 749 nvlist_free(nvl);
751 750 return (rv);
752 751 }
753 752 }
754 753
755 754 len = 0;
756 755 buf = NULL;
757 756 if ((rv = nvlist_pack(nvl, &buf, &len, NV_ENCODE_NATIVE, 0)) == 0) {
758 757 *lenp = len;
759 758 *bufp = buf;
760 759 }
761 760
762 761 nvlist_free(nvl);
763 762
764 763 return (rv);
765 764 }
766 765
767 766 /*
768 767 * hp_unpack()
769 768 *
770 769 * Unpack a hotplug information snapshot for normal usage.
771 770 */
772 771 int
773 772 hp_unpack(char *packed_buf, size_t packed_len, hp_node_t *retp)
774 773 {
775 774 hp_node_t root;
776 775 hp_node_t root_list = NULL;
777 776 hp_node_t prev_root = NULL;
778 777 nvlist_t *nvl = NULL;
779 778 nvpair_t *nvp;
780 779 char *basepath = NULL;
781 780 int rv;
782 781
783 782 i_hp_dprintf("hp_unpack: packed_buf=%p, packed_len=%u, retp=%p\n",
784 783 (void *)packed_buf, (uint32_t)packed_len, (void *)retp);
785 784
786 785 if ((packed_buf == NULL) || (packed_len == 0) || (retp == NULL)) {
787 786 i_hp_dprintf("hp_unpack: invalid arguments.\n");
788 787 return (EINVAL);
789 788 }
790 789
791 790 if ((rv = nvlist_unpack(packed_buf, packed_len, &nvl, 0)) != 0)
792 791 return (rv);
793 792
794 793 if (nvlist_next_nvpair(nvl, NULL) == NULL) {
795 794 nvlist_free(nvl);
796 795 errno = EINVAL;
797 796 return (NULL);
798 797 }
799 798
800 799 for (nvp = NULL; nvp = nvlist_next_nvpair(nvl, nvp); ) {
801 800
802 801 rv = EINVAL;
803 802
804 803 if (strcmp(nvpair_name(nvp), HP_INFO_BASE) == 0) {
805 804 char *val_string;
806 805
807 806 if ((rv = nvpair_value_string(nvp, &val_string)) == 0) {
808 807 if ((basepath = strdup(val_string)) == NULL)
809 808 rv = ENOMEM;
810 809 }
811 810
812 811 } else if (strcmp(nvpair_name(nvp), HP_INFO_BRANCH) == 0) {
813 812 size_t len = 0;
814 813 char *buf = NULL;
815 814
816 815 if ((rv = nvpair_value_byte_array(nvp,
817 816 (uchar_t **)&buf, (uint_t *)&len)) == 0) {
818 817 rv = i_hp_unpack_branch(buf, len, NULL, &root);
819 818 }
820 819
821 820 if (rv == 0) {
822 821 if (prev_root) {
823 822 prev_root->hp_sibling = root;
824 823 } else {
825 824 root_list = root;
826 825 }
827 826 prev_root = root;
828 827 }
829 828 }
830 829
831 830 if (rv != 0) {
832 831 if (basepath)
833 832 free(basepath);
834 833 nvlist_free(nvl);
835 834 hp_fini(root_list);
836 835 *retp = NULL;
837 836 return (rv);
838 837 }
839 838 }
840 839
841 840 /* Store the base path in each root node */
842 841 if (basepath) {
843 842 for (root = root_list; root; root = root->hp_sibling)
844 843 root->hp_basepath = basepath;
845 844 }
846 845
847 846 nvlist_free(nvl);
848 847 *retp = root_list;
849 848 return (0);
850 849 }
851 850
852 851 /*
853 852 * i_hp_dprintf()
854 853 *
855 854 * Print debug messages to stderr, but only when the debug flag
856 855 * (libhotplug_debug) is set.
857 856 */
858 857 /*PRINTFLIKE1*/
859 858 static void
860 859 i_hp_dprintf(const char *fmt, ...)
861 860 {
862 861 va_list ap;
863 862
864 863 if (libhotplug_debug) {
865 864 va_start(ap, fmt);
866 865 (void) vfprintf(stderr, fmt, ap);
867 866 va_end(ap);
868 867 }
869 868 }
870 869
871 870 /*
872 871 * i_hp_pack_branch()
873 872 *
874 873 * Pack an individual branch of a hotplug information snapshot.
875 874 */
876 875 static int
877 876 i_hp_pack_branch(hp_node_t root, char **bufp, size_t *lenp)
878 877 {
879 878 hp_node_t child;
880 879 nvlist_t *nvl;
881 880 char *buf;
882 881 size_t len;
883 882 int rv;
884 883
885 884 *lenp = 0;
886 885 *bufp = NULL;
887 886
888 887 /* Allocate an nvlist for this branch */
889 888 if (nvlist_alloc(&nvl, 0, 0) != 0)
890 889 return (ENOMEM);
891 890
892 891 /* Pack the root of the branch and add it to the nvlist */
893 892 if ((rv = i_hp_pack_node(root, &buf, &len)) == 0) {
894 893 rv = nvlist_add_byte_array(nvl, HP_INFO_NODE,
895 894 (uchar_t *)buf, len);
896 895 free(buf);
897 896 }
898 897 if (rv != 0) {
899 898 nvlist_free(nvl);
900 899 return (rv);
901 900 }
902 901
903 902 /* Pack each subordinate branch, and add it to the nvlist */
904 903 for (child = root->hp_child; child != NULL; child = child->hp_sibling) {
905 904 if ((rv = i_hp_pack_branch(child, &buf, &len)) == 0) {
906 905 rv = nvlist_add_byte_array(nvl, HP_INFO_BRANCH,
907 906 (uchar_t *)buf, len);
908 907 free(buf);
909 908 }
910 909 if (rv != 0) {
911 910 nvlist_free(nvl);
912 911 return (rv);
913 912 }
914 913 }
915 914
916 915 /* Pack the resulting nvlist into a single buffer */
917 916 len = 0;
918 917 buf = NULL;
919 918 if ((rv = nvlist_pack(nvl, &buf, &len, NV_ENCODE_NATIVE, 0)) == 0) {
920 919 *lenp = len;
921 920 *bufp = buf;
922 921 }
923 922
924 923 /* Free the nvlist */
925 924 nvlist_free(nvl);
926 925
927 926 return (rv);
928 927 }
929 928
930 929 /*
931 930 * i_hp_pack_node()
932 931 *
933 932 * Pack an individual node of a hotplug information snapshot.
934 933 */
935 934 static int
936 935 i_hp_pack_node(hp_node_t node, char **bufp, size_t *lenp)
937 936 {
938 937 nvlist_t *nvl;
939 938 char *buf = NULL;
940 939 size_t len = 0;
941 940 int rv;
942 941
943 942 if (nvlist_alloc(&nvl, 0, 0) != 0)
944 943 return (ENOMEM);
945 944
946 945 if ((rv = nvlist_add_uint32(nvl, HP_INFO_TYPE,
947 946 (uint32_t)node->hp_type)) != 0)
948 947 goto fail;
949 948
950 949 if ((node->hp_name) &&
951 950 ((rv = nvlist_add_string(nvl, HP_INFO_NAME, node->hp_name)) != 0))
952 951 goto fail;
953 952
954 953 if ((node->hp_usage) &&
955 954 ((rv = nvlist_add_string(nvl, HP_INFO_USAGE, node->hp_usage)) != 0))
956 955 goto fail;
957 956
958 957 if ((node->hp_description) &&
959 958 ((rv = nvlist_add_string(nvl, HP_INFO_DESC,
960 959 node->hp_description)) != 0))
961 960 goto fail;
962 961
963 962 if ((rv = nvlist_add_uint32(nvl, HP_INFO_STATE, node->hp_state)) != 0)
964 963 goto fail;
965 964
966 965 if ((node->hp_last_change != 0) &&
967 966 ((rv = nvlist_add_uint32(nvl, HP_INFO_TIME,
968 967 node->hp_last_change)) != 0))
969 968 goto fail;
970 969
971 970 if ((rv = nvlist_pack(nvl, &buf, &len, NV_ENCODE_NATIVE, 0)) != 0)
972 971 goto fail;
973 972
974 973 *bufp = buf;
975 974 *lenp = len;
976 975 nvlist_free(nvl);
977 976 return (0);
978 977
979 978 fail:
980 979 *bufp = NULL;
981 980 *lenp = 0;
982 981 nvlist_free(nvl);
983 982 return (rv);
984 983 }
985 984
986 985 /*
987 986 * i_hp_unpack_branch()
988 987 *
989 988 * Unpack a branch of hotplug information nodes.
990 989 */
991 990 static int
992 991 i_hp_unpack_branch(char *packed_buf, size_t packed_len, hp_node_t parent,
993 992 hp_node_t *retp)
994 993 {
995 994 hp_node_t node = NULL;
996 995 hp_node_t child;
997 996 hp_node_t prev_child = NULL;
998 997 nvlist_t *nvl = NULL;
999 998 nvpair_t *nvp;
1000 999 char *buf;
1001 1000 size_t len;
1002 1001 int rv;
1003 1002
1004 1003 /* Initialize results */
1005 1004 *retp = NULL;
1006 1005
1007 1006 /* Unpack the nvlist for this branch */
1008 1007 if ((rv = nvlist_unpack(packed_buf, packed_len, &nvl, 0)) != 0)
1009 1008 return (rv);
1010 1009
1011 1010 /*
1012 1011 * Unpack the branch. The first item in the nvlist is
1013 1012 * always the root node. And zero or more subordinate
1014 1013 * branches may be packed afterward.
1015 1014 */
1016 1015 for (nvp = NULL; nvp = nvlist_next_nvpair(nvl, nvp); ) {
1017 1016
1018 1017 len = 0;
1019 1018 buf = NULL;
1020 1019
1021 1020 if (strcmp(nvpair_name(nvp), HP_INFO_NODE) == 0) {
1022 1021
1023 1022 /* Check that there is only one root node */
1024 1023 if (node != NULL) {
1025 1024 hp_fini(node);
1026 1025 nvlist_free(nvl);
1027 1026 return (EFAULT);
1028 1027 }
1029 1028
1030 1029 if ((rv = nvpair_value_byte_array(nvp, (uchar_t **)&buf,
1031 1030 (uint_t *)&len)) == 0)
1032 1031 rv = i_hp_unpack_node(buf, len, parent, &node);
1033 1032
1034 1033 if (rv != 0) {
1035 1034 nvlist_free(nvl);
1036 1035 return (rv);
1037 1036 }
1038 1037
1039 1038 } else if (strcmp(nvpair_name(nvp), HP_INFO_BRANCH) == 0) {
1040 1039
1041 1040 if ((rv = nvpair_value_byte_array(nvp, (uchar_t **)&buf,
1042 1041 (uint_t *)&len)) == 0)
1043 1042 rv = i_hp_unpack_branch(buf, len, node, &child);
1044 1043
1045 1044 if (rv != 0) {
1046 1045 hp_fini(node);
1047 1046 nvlist_free(nvl);
1048 1047 return (rv);
1049 1048 }
1050 1049
1051 1050 if (prev_child) {
1052 1051 prev_child->hp_sibling = child;
1053 1052 } else {
1054 1053 node->hp_child = child;
1055 1054 }
1056 1055 prev_child = child;
1057 1056 }
1058 1057 }
1059 1058
1060 1059 nvlist_free(nvl);
1061 1060 *retp = node;
1062 1061 return (0);
1063 1062 }
1064 1063
1065 1064 /*
1066 1065 * i_hp_unpack_node()
1067 1066 *
1068 1067 * Unpack an individual hotplug information node.
1069 1068 */
1070 1069 static int
1071 1070 i_hp_unpack_node(char *buf, size_t len, hp_node_t parent, hp_node_t *retp)
1072 1071 {
1073 1072 hp_node_t node;
1074 1073 nvlist_t *nvl;
1075 1074 nvpair_t *nvp;
1076 1075 uint32_t val_uint32;
1077 1076 char *val_string;
1078 1077 int rv = 0;
1079 1078
1080 1079 /* Initialize results */
1081 1080 *retp = NULL;
1082 1081
1083 1082 /* Unpack node into an nvlist */
1084 1083 if ((nvlist_unpack(buf, len, &nvl, 0) != 0))
1085 1084 return (EINVAL);
1086 1085
1087 1086 /* Allocate the new node */
1088 1087 if ((node = (hp_node_t)calloc(1, sizeof (struct hp_node))) == NULL) {
1089 1088 nvlist_free(nvl);
1090 1089 return (ENOMEM);
1091 1090 }
1092 1091
1093 1092 /* Iterate through nvlist, unpacking each field */
1094 1093 for (nvp = NULL; nvp = nvlist_next_nvpair(nvl, nvp); ) {
1095 1094
1096 1095 if ((strcmp(nvpair_name(nvp), HP_INFO_TYPE) == 0) &&
1097 1096 (nvpair_type(nvp) == DATA_TYPE_UINT32)) {
1098 1097
1099 1098 (void) nvpair_value_uint32(nvp, &val_uint32);
1100 1099 node->hp_type = val_uint32;
1101 1100
1102 1101 } else if ((strcmp(nvpair_name(nvp), HP_INFO_NAME) == 0) &&
1103 1102 (nvpair_type(nvp) == DATA_TYPE_STRING)) {
1104 1103
1105 1104 (void) nvpair_value_string(nvp, &val_string);
1106 1105 if ((node->hp_name = strdup(val_string)) == NULL) {
1107 1106 rv = ENOMEM;
1108 1107 break;
1109 1108 }
1110 1109
1111 1110 } else if ((strcmp(nvpair_name(nvp), HP_INFO_STATE) == 0) &&
1112 1111 (nvpair_type(nvp) == DATA_TYPE_UINT32)) {
1113 1112
1114 1113 (void) nvpair_value_uint32(nvp, &val_uint32);
1115 1114 node->hp_state = val_uint32;
1116 1115
1117 1116 } else if ((strcmp(nvpair_name(nvp), HP_INFO_USAGE) == 0) &&
1118 1117 (nvpair_type(nvp) == DATA_TYPE_STRING)) {
1119 1118
1120 1119 (void) nvpair_value_string(nvp, &val_string);
1121 1120 if ((node->hp_usage = strdup(val_string)) == NULL) {
1122 1121 rv = ENOMEM;
1123 1122 break;
1124 1123 }
1125 1124
1126 1125 } else if ((strcmp(nvpair_name(nvp), HP_INFO_DESC) == 0) &&
1127 1126 (nvpair_type(nvp) == DATA_TYPE_STRING)) {
1128 1127
1129 1128 (void) nvpair_value_string(nvp, &val_string);
1130 1129 if ((node->hp_description = strdup(val_string))
1131 1130 == NULL) {
1132 1131 rv = ENOMEM;
1133 1132 break;
1134 1133 }
1135 1134
1136 1135 } else if ((strcmp(nvpair_name(nvp), HP_INFO_TIME) == 0) &&
1137 1136 (nvpair_type(nvp) == DATA_TYPE_UINT32)) {
1138 1137
1139 1138 (void) nvpair_value_uint32(nvp, &val_uint32);
1140 1139 node->hp_last_change = (time_t)val_uint32;
1141 1140
1142 1141 } else {
1143 1142 i_hp_dprintf("i_hp_unpack_node: unrecognized: '%s'\n",
1144 1143 nvpair_name(nvp));
1145 1144 }
1146 1145 }
1147 1146
1148 1147 /* Unpacked nvlist no longer needed */
1149 1148 nvlist_free(nvl);
1150 1149
1151 1150 /* Check for errors */
1152 1151 if (rv != 0) {
1153 1152 hp_fini(node);
1154 1153 return (rv);
1155 1154 }
1156 1155
1157 1156 /* Success */
1158 1157 node->hp_parent = parent;
1159 1158 *retp = node;
1160 1159 return (0);
1161 1160 }
1162 1161
1163 1162 /*
1164 1163 * i_hp_call_hotplugd()
1165 1164 *
1166 1165 * Perform a door call to the hotplug daemon.
1167 1166 */
1168 1167 static int
1169 1168 i_hp_call_hotplugd(nvlist_t *args, nvlist_t **resultsp)
1170 1169 {
1171 1170 door_arg_t door_arg;
1172 1171 nvlist_t *results = NULL;
1173 1172 char *buf = NULL;
1174 1173 size_t len = 0;
1175 1174 uint64_t seqnum;
1176 1175 int door_fd;
1177 1176 int rv;
1178 1177
1179 1178 /* Initialize results */
1180 1179 *resultsp = NULL;
1181 1180
1182 1181 /* Open door */
1183 1182 if ((door_fd = open(HOTPLUGD_DOOR, O_RDONLY)) < 0) {
1184 1183 i_hp_dprintf("i_hp_call_hotplugd: cannot open door (%s)\n",
1185 1184 strerror(errno));
1186 1185 return (EBADF);
1187 1186 }
1188 1187
1189 1188 /* Pack the nvlist of arguments */
1190 1189 if ((rv = nvlist_pack(args, &buf, &len, NV_ENCODE_NATIVE, 0)) != 0) {
1191 1190 i_hp_dprintf("i_hp_call_hotplugd: cannot pack arguments (%s)\n",
1192 1191 strerror(rv));
1193 1192 return (rv);
1194 1193 }
1195 1194
1196 1195 /* Set the door argument using the packed arguments */
1197 1196 door_arg.data_ptr = buf;
1198 1197 door_arg.data_size = len;
1199 1198 door_arg.desc_ptr = NULL;
1200 1199 door_arg.desc_num = 0;
1201 1200 door_arg.rbuf = (char *)(uintptr_t)&rv;
1202 1201 door_arg.rsize = sizeof (rv);
1203 1202
1204 1203 /* Attempt the door call */
1205 1204 if (door_call(door_fd, &door_arg) != 0) {
1206 1205 rv = errno;
1207 1206 i_hp_dprintf("i_hp_call_hotplugd: door call failed (%s)\n",
1208 1207 strerror(rv));
1209 1208 (void) close(door_fd);
1210 1209 free(buf);
1211 1210 return (rv);
1212 1211 }
1213 1212
1214 1213 /* The arguments are no longer needed */
1215 1214 free(buf);
1216 1215
1217 1216 /*
1218 1217 * If results are not in the original buffer provided,
1219 1218 * then check and process the new results buffer.
1220 1219 */
1221 1220 if (door_arg.rbuf != (char *)(uintptr_t)&rv) {
1222 1221
1223 1222 /*
1224 1223 * First check that the buffer is valid. Then check for
1225 1224 * the simple case where a short result code was sent.
1226 1225 * The last case is a packed nvlist was returned, which
1227 1226 * needs to be unpacked.
1228 1227 */
1229 1228 if ((door_arg.rbuf == NULL) ||
1230 1229 (door_arg.data_size < sizeof (rv))) {
1231 1230 i_hp_dprintf("i_hp_call_hotplugd: invalid results.\n");
1232 1231 rv = EFAULT;
1233 1232
1234 1233 } else if (door_arg.data_size == sizeof (rv)) {
1235 1234 rv = *(int *)(uintptr_t)door_arg.rbuf;
1236 1235
1237 1236 } else if ((rv = nvlist_unpack(door_arg.rbuf,
1238 1237 door_arg.data_size, &results, 0)) != 0) {
1239 1238 i_hp_dprintf("i_hp_call_hotplugd: "
1240 1239 "cannot unpack results (%s).\n", strerror(rv));
1241 1240 results = NULL;
1242 1241 rv = EFAULT;
1243 1242 }
1244 1243
1245 1244 /* Unmap the results buffer */
1246 1245 if (door_arg.rbuf != NULL)
1247 1246 (void) munmap(door_arg.rbuf, door_arg.rsize);
1248 1247
1249 1248 /*
1250 1249 * In the case of a packed nvlist, notify the daemon
1251 1250 * that it can free the result buffer from its heap.
1252 1251 */
1253 1252 if ((results != NULL) &&
1254 1253 (nvlist_lookup_uint64(results, HPD_SEQNUM, &seqnum) == 0)) {
1255 1254 door_arg.data_ptr = (char *)(uintptr_t)&seqnum;
1256 1255 door_arg.data_size = sizeof (seqnum);
1257 1256 door_arg.desc_ptr = NULL;
1258 1257 door_arg.desc_num = 0;
1259 1258 door_arg.rbuf = NULL;
1260 1259 door_arg.rsize = 0;
1261 1260 (void) door_call(door_fd, &door_arg);
1262 1261 if (door_arg.rbuf != NULL)
1263 1262 (void) munmap(door_arg.rbuf, door_arg.rsize);
1264 1263 }
1265 1264
1266 1265 *resultsp = results;
1267 1266 }
1268 1267
1269 1268 (void) close(door_fd);
1270 1269 return (rv);
1271 1270 }
1272 1271
1273 1272 /*
1274 1273 * i_hp_set_args()
1275 1274 *
1276 1275 * Construct an nvlist of arguments for a hotplugd door call.
1277 1276 */
1278 1277 static nvlist_t *
1279 1278 i_hp_set_args(hp_cmd_t cmd, const char *path, const char *connection,
1280 1279 uint_t flags, const char *options, int state)
1281 1280 {
1282 1281 nvlist_t *args;
1283 1282
1284 1283 /* Allocate a new nvlist */
1285 1284 if (nvlist_alloc(&args, NV_UNIQUE_NAME_TYPE, 0) != 0)
1286 1285 return (NULL);
1287 1286
1288 1287 /* Add common arguments */
1289 1288 if ((nvlist_add_int32(args, HPD_CMD, cmd) != 0) ||
1290 1289 (nvlist_add_string(args, HPD_PATH, path) != 0)) {
1291 1290 nvlist_free(args);
1292 1291 return (NULL);
1293 1292 }
1294 1293
1295 1294 /* Add connection, but only if defined */
1296 1295 if ((connection != NULL) && (connection[0] != '\0') &&
1297 1296 (nvlist_add_string(args, HPD_CONNECTION, connection) != 0)) {
1298 1297 nvlist_free(args);
1299 1298 return (NULL);
1300 1299 }
1301 1300
1302 1301 /* Add flags, but only if defined */
1303 1302 if ((flags != 0) && (nvlist_add_uint32(args, HPD_FLAGS, flags) != 0)) {
1304 1303 nvlist_free(args);
1305 1304 return (NULL);
1306 1305 }
1307 1306
1308 1307 /* Add options, but only if defined */
1309 1308 if ((options != NULL) &&
1310 1309 (nvlist_add_string(args, HPD_OPTIONS, options) != 0)) {
1311 1310 nvlist_free(args);
1312 1311 return (NULL);
1313 1312 }
1314 1313
1315 1314 /* Add state, but only for CHANGESTATE command */
1316 1315 if ((cmd == HP_CMD_CHANGESTATE) &&
1317 1316 (nvlist_add_int32(args, HPD_STATE, state) != 0)) {
1318 1317 nvlist_free(args);
1319 1318 return (NULL);
1320 1319 }
1321 1320
1322 1321 return (args);
1323 1322 }
1324 1323
1325 1324 /*
1326 1325 * i_hp_parse_results()
1327 1326 *
1328 1327 * Parse out individual fields of an nvlist of results from
1329 1328 * a hotplugd door call.
1330 1329 */
1331 1330 static int
1332 1331 i_hp_parse_results(nvlist_t *results, hp_node_t *rootp, char **optionsp)
1333 1332 {
1334 1333 int rv;
1335 1334
1336 1335 /* Parse an information snapshot */
1337 1336 if (rootp) {
1338 1337 char *buf = NULL;
1339 1338 size_t len = 0;
1340 1339
1341 1340 *rootp = NULL;
1342 1341 if (nvlist_lookup_byte_array(results, HPD_INFO,
1343 1342 (uchar_t **)&buf, (uint_t *)&len) == 0) {
1344 1343 if ((rv = hp_unpack(buf, len, rootp)) != 0)
1345 1344 return (rv);
1346 1345 }
1347 1346 }
1348 1347
1349 1348 /* Parse a bus private option string */
1350 1349 if (optionsp) {
1351 1350 char *str;
1352 1351
1353 1352 *optionsp = NULL;
1354 1353 if ((nvlist_lookup_string(results, HPD_OPTIONS, &str) == 0) &&
1355 1354 ((*optionsp = strdup(str)) == NULL)) {
1356 1355 return (ENOMEM);
1357 1356 }
1358 1357 }
1359 1358
1360 1359 /* Parse result code of the operation */
1361 1360 if (nvlist_lookup_int32(results, HPD_STATUS, &rv) != 0) {
1362 1361 i_hp_dprintf("i_hp_call_hotplugd: missing status.\n");
1363 1362 return (EFAULT);
1364 1363 }
1365 1364
1366 1365 return (rv);
1367 1366 }
↓ open down ↓ |
885 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX