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 2001-2002 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #include <stdio.h> 28 #include <stdlib.h> 29 #include <sys/types.h> 30 #include <sys/stat.h> 31 #include <unistd.h> 32 #include <errno.h> 33 #include <strings.h> 34 #include <string.h> 35 #include <fcntl.h> 36 #include <assert.h> 37 #include <libipp.h> 38 #include <libnvpair.h> 39 #include <ipp/ippctl.h> 40 41 /* 42 * Debug macros 43 */ 44 45 #if defined(DEBUG) && !defined(lint) 46 uint32_t ipp_debug_flags = 47 /* 48 * DBG_IO | 49 */ 50 DBG_ERR | 51 0; 52 53 #define DBG0(flags, fmt) \ 54 do { \ 55 if (flags & ipp_debug_flags) \ 56 fprintf(stderr, "libipp: " __FN__ ": " fmt); \ 57 } while (0) 58 59 #define DBG1(flags, fmt, a) \ 60 do { \ 61 if (flags & ipp_debug_flags) \ 62 fprintf(stderr, "libipp: " __FN__ ": " fmt, a); \ 63 } while (0) 64 65 #define DBG2(flags, fmt, a, b) \ 66 do { \ 67 if (flags & ipp_debug_flags) \ 68 fprintf(stderr, "libipp: " __FN__ ": " fmt, a, \ 69 b); \ 70 } while (0) 71 72 #define DBG3(flags, fmt, a, b, c) \ 73 do { \ 74 if (flags & ipp_debug_flags) \ 75 fprintf(stderr, "libipp: " __FN__ ": " fmt, a, \ 76 b, c); \ 77 } while (0) 78 79 #else /* defined(DEBUG) && !defined(lint) */ 80 #define DBG0(flags, fmt) 81 #define DBG1(flags, fmt, a) 82 #define DBG2(flags, fmt, a, b) 83 #define DBG3(flags, fmt, a, b, c) 84 #endif /* defined(DEBUG) && !defined(lint) */ 85 86 /* 87 * Control device node 88 */ 89 90 #define IPPCTL_DEVICE "/devices/pseudo/ippctl@0:ctl" 91 92 /* 93 * Structures. 94 */ 95 96 typedef struct array_desc_t { 97 char *name; 98 char **array; 99 int nelt; 100 } array_desc_t; 101 102 /* 103 * Prototypes 104 */ 105 106 static int nvlist_callback(nvlist_t *, void *); 107 static int string_callback(nvlist_t *, void *); 108 static int string_array_callback(nvlist_t *, void *); 109 static int dispatch(nvlist_t **, int (*)(nvlist_t *, void *), void *); 110 111 /* 112 * API functions 113 */ 114 #define __FN__ "ipp_action_create" 115 int 116 ipp_action_create( 117 const char *modname, 118 const char *aname, 119 nvlist_t **nvlpp, 120 ipp_flags_t flags) 121 { 122 nvlist_t *nvlp; 123 int rc; 124 125 /* 126 * Sanity check the arguments. 127 */ 128 129 if (nvlpp == NULL || modname == NULL || aname == NULL) { 130 DBG0(DBG_ERR, "bad argument\n"); 131 errno = EINVAL; 132 return (-1); 133 } 134 135 /* 136 * Add our data to the nvlist. (This information will be removed for 137 * use by ippctl). 138 */ 139 140 nvlp = *nvlpp; 141 if ((rc = nvlist_add_byte(nvlp, IPPCTL_OP, 142 IPPCTL_OP_ACTION_CREATE)) != 0) { 143 DBG1(DBG_ERR, "failed to add '%s' to nvlist\n", IPPCTL_OP); 144 goto failed; 145 } 146 147 if ((rc = nvlist_add_string(nvlp, IPPCTL_MODNAME, 148 (char *)modname)) != 0) { 149 DBG1(DBG_ERR, "failed to add '%s' to nvlist\n", 150 IPPCTL_MODNAME); 151 goto failed; 152 } 153 154 if ((rc = nvlist_add_string(nvlp, IPPCTL_ANAME, (char *)aname)) != 0) { 155 DBG1(DBG_ERR, "failed to add '%s' to nvlist\n", IPPCTL_ANAME); 156 goto failed; 157 } 158 159 if ((rc = nvlist_add_uint32(nvlp, IPPCTL_FLAGS, flags)) != 0) { 160 DBG1(DBG_ERR, "failed to add '%s' to nvlist\n", IPPCTL_FLAGS); 161 goto failed; 162 } 163 164 /* 165 * Talk to the kernel. 166 */ 167 168 return (dispatch(nvlpp, nvlist_callback, (void *)nvlpp)); 169 failed: 170 errno = rc; 171 return (-1); 172 } 173 #undef __FN__ 174 175 #define __FN__ "ipp_action_destroy" 176 int 177 ipp_action_destroy( 178 const char *aname, 179 ipp_flags_t flags) 180 { 181 nvlist_t *nvlp; 182 int rc; 183 184 /* 185 * Sanity check the arguments. 186 */ 187 188 if (aname == NULL) { 189 DBG0(DBG_ERR, "bad argument\n"); 190 errno = EINVAL; 191 return (-1); 192 } 193 194 /* 195 * Create an nvlist for our data as none is passed into the function. 196 */ 197 198 if ((rc = nvlist_alloc(&nvlp, NV_UNIQUE_NAME, 0)) != 0) { 199 DBG0(DBG_ERR, "failed to allocate nvlist\n"); 200 nvlp = NULL; 201 goto failed; 202 } 203 204 if ((rc = nvlist_add_byte(nvlp, IPPCTL_OP, 205 IPPCTL_OP_ACTION_DESTROY)) != 0) { 206 DBG1(DBG_ERR, "failed to add '%s' to nvlist\n", IPPCTL_OP); 207 goto failed; 208 } 209 210 if ((rc = nvlist_add_string(nvlp, IPPCTL_ANAME, (char *)aname)) != 0) { 211 DBG1(DBG_ERR, "failed to add '%s' to nvlist\n", IPPCTL_ANAME); 212 goto failed; 213 } 214 215 if ((rc = nvlist_add_uint32(nvlp, IPPCTL_FLAGS, flags)) != 0) { 216 DBG1(DBG_ERR, "failed to add '%s' to nvlist\n", IPPCTL_FLAGS); 217 goto failed; 218 } 219 220 /* 221 * Talk to the kernel. 222 */ 223 224 return (dispatch(&nvlp, NULL, NULL)); 225 failed: 226 nvlist_free(nvlp); 227 errno = rc; 228 return (-1); 229 } 230 #undef __FN__ 231 232 #define __FN__ "ipp_action_modify" 233 int 234 ipp_action_modify( 235 const char *aname, 236 nvlist_t **nvlpp, 237 ipp_flags_t flags) 238 { 239 nvlist_t *nvlp; 240 int rc; 241 242 /* 243 * Sanity check the arguments. 244 */ 245 246 if (nvlpp == NULL || aname == NULL) { 247 DBG0(DBG_ERR, "bad argument\n"); 248 errno = EINVAL; 249 return (-1); 250 } 251 252 /* 253 * Add our data to the nvlist. 254 */ 255 256 nvlp = *nvlpp; 257 if ((rc = nvlist_add_byte(nvlp, IPPCTL_OP, 258 IPPCTL_OP_ACTION_MODIFY)) != 0) { 259 DBG1(DBG_ERR, "failed to add '%s' to nvlist\n", IPPCTL_OP); 260 goto failed; 261 } 262 263 if ((rc = nvlist_add_string(nvlp, IPPCTL_ANAME, (char *)aname)) != 0) { 264 DBG1(DBG_ERR, "failed to add '%s' to nvlist\n", IPPCTL_ANAME); 265 goto failed; 266 } 267 268 if ((rc = nvlist_add_uint32(nvlp, IPPCTL_FLAGS, flags)) != 0) { 269 DBG1(DBG_ERR, "failed to add '%s' to nvlist\n", IPPCTL_FLAGS); 270 goto failed; 271 } 272 273 /* 274 * Talk to the kernel. 275 */ 276 277 return (dispatch(nvlpp, nvlist_callback, (void *)nvlpp)); 278 failed: 279 errno = rc; 280 return (-1); 281 } 282 #undef __FN__ 283 284 #define __FN__ "ipp_action_info" 285 int 286 ipp_action_info( 287 const char *aname, 288 int (*fn)(nvlist_t *, void *), 289 void *arg, 290 ipp_flags_t flags) 291 { 292 nvlist_t *nvlp; 293 int rc; 294 295 /* 296 * Sanity check the arguments. 297 */ 298 299 if (aname == NULL || fn == NULL) { 300 DBG0(DBG_ERR, "bad argument\n"); 301 errno = EINVAL; 302 return (-1); 303 } 304 305 /* 306 * Create an nvlist for our data. 307 */ 308 309 if ((rc = nvlist_alloc(&nvlp, NV_UNIQUE_NAME, 0)) != 0) { 310 DBG0(DBG_ERR, "failed to allocate nvlist\n"); 311 nvlp = NULL; 312 } 313 314 if ((rc = nvlist_add_byte(nvlp, IPPCTL_OP, 315 IPPCTL_OP_ACTION_INFO)) != 0) { 316 DBG1(DBG_ERR, "failed to add '%s' to nvlist\n", IPPCTL_OP); 317 goto failed; 318 } 319 320 if ((rc = nvlist_add_string(nvlp, IPPCTL_ANAME, (char *)aname)) != 0) { 321 DBG1(DBG_ERR, "failed to add '%s' to nvlist\n", IPPCTL_ANAME); 322 goto failed; 323 } 324 325 if ((rc = nvlist_add_uint32(nvlp, IPPCTL_FLAGS, flags)) != 0) { 326 DBG1(DBG_ERR, "failed to add '%s' to nvlist\n", IPPCTL_FLAGS); 327 goto failed; 328 } 329 330 /* 331 * Talk to the kernel. 332 */ 333 334 return (dispatch(&nvlp, fn, arg)); 335 failed: 336 nvlist_free(nvlp); 337 errno = rc; 338 return (-1); 339 } 340 #undef __FN__ 341 342 #define __FN__ "ipp_action_mod" 343 int 344 ipp_action_mod( 345 const char *aname, 346 char **modnamep) 347 { 348 nvlist_t *nvlp; 349 int rc; 350 351 /* 352 * Sanity check the arguments. 353 */ 354 355 if (aname == NULL || modnamep == NULL) { 356 DBG0(DBG_ERR, "bad argument\n"); 357 errno = EINVAL; 358 return (-1); 359 } 360 361 /* 362 * Create an nvlist for our data. 363 */ 364 365 if ((rc = nvlist_alloc(&nvlp, NV_UNIQUE_NAME, 0)) != 0) { 366 DBG0(DBG_ERR, "failed to allocate nvlist\n"); 367 nvlp = NULL; 368 goto failed; 369 } 370 371 if ((rc = nvlist_add_byte(nvlp, IPPCTL_OP, 372 IPPCTL_OP_ACTION_MOD)) != 0) { 373 DBG1(DBG_ERR, "failed to add '%s' to nvlist\n", IPPCTL_OP); 374 goto failed; 375 } 376 377 if ((rc = nvlist_add_string(nvlp, IPPCTL_ANAME, (char *)aname)) != 0) { 378 DBG1(DBG_ERR, "failed to add '%s' to nvlist\n", IPPCTL_ANAME); 379 goto failed; 380 } 381 382 /* 383 * Talk to the kernel. 384 */ 385 386 return (dispatch(&nvlp, string_callback, (void *)modnamep)); 387 failed: 388 nvlist_free(nvlp); 389 errno = rc; 390 return (-1); 391 } 392 #undef __FN__ 393 394 #define __FN__ "ipp_list_mods" 395 int 396 ipp_list_mods( 397 char ***modname_arrayp, 398 int *neltp) 399 { 400 nvlist_t *nvlp; 401 array_desc_t ad; 402 int rc; 403 404 /* 405 * Sanity check the arguments. 406 */ 407 408 if (modname_arrayp == NULL || neltp == NULL) { 409 DBG0(DBG_ERR, "bad argument"); 410 errno = EINVAL; 411 return (-1); 412 } 413 414 /* 415 * Create an nvlist for our data. 416 */ 417 418 if ((rc = nvlist_alloc(&nvlp, NV_UNIQUE_NAME, 0)) != 0) { 419 DBG0(DBG_ERR, "failed to allocate nvlist\n"); 420 nvlp = NULL; 421 } 422 423 if ((rc = nvlist_add_byte(nvlp, IPPCTL_OP, 424 IPPCTL_OP_LIST_MODS)) != 0) { 425 DBG1(DBG_ERR, "failed to add '%s' to nvlist\n", IPPCTL_OP); 426 goto failed; 427 } 428 429 /* 430 * Talk to the kernel. 431 */ 432 433 ad.name = IPPCTL_MODNAME_ARRAY; 434 ad.array = NULL; 435 ad.nelt = 0; 436 437 if ((rc = dispatch(&nvlp, string_array_callback, (void *)&ad)) == 0) { 438 *modname_arrayp = ad.array; 439 *neltp = ad.nelt; 440 } 441 442 return (rc); 443 failed: 444 nvlist_free(nvlp); 445 errno = rc; 446 return (-1); 447 } 448 #undef __FN__ 449 450 #define __FN__ "ipp_mod_list_actions" 451 int 452 ipp_mod_list_actions( 453 const char *modname, 454 char ***aname_arrayp, 455 int *neltp) 456 { 457 nvlist_t *nvlp; 458 array_desc_t ad; 459 int rc; 460 461 /* 462 * Sanity check the arguments. 463 */ 464 465 if (modname == NULL || aname_arrayp == NULL || neltp == NULL) { 466 DBG0(DBG_ERR, "bad argument"); 467 errno = EINVAL; 468 return (-1); 469 } 470 471 /* 472 * Create an nvlist for our data. 473 */ 474 475 if ((rc = nvlist_alloc(&nvlp, NV_UNIQUE_NAME, 0)) != 0) { 476 DBG0(DBG_ERR, "failed to allocate nvlist\n"); 477 nvlp = NULL; 478 } 479 480 if ((rc = nvlist_add_byte(nvlp, IPPCTL_OP, 481 IPPCTL_OP_MOD_LIST_ACTIONS)) != 0) { 482 DBG1(DBG_ERR, "failed to add '%s' to nvlist\n", IPPCTL_OP); 483 goto failed; 484 } 485 486 if ((rc = nvlist_add_string(nvlp, IPPCTL_MODNAME, 487 (char *)modname)) != 0) { 488 DBG1(DBG_ERR, "failed to add '%s' to nvlist\n", IPPCTL_MODNAME); 489 goto failed; 490 } 491 492 /* 493 * Talk to the kernel. 494 */ 495 496 ad.name = IPPCTL_ANAME_ARRAY; 497 ad.array = NULL; 498 ad.nelt = 0; 499 500 if ((rc = dispatch(&nvlp, string_array_callback, (void *)&ad)) == 0) { 501 *aname_arrayp = ad.array; 502 *neltp = ad.nelt; 503 } 504 505 return (rc); 506 failed: 507 nvlist_free(nvlp); 508 errno = rc; 509 return (-1); 510 } 511 #undef __FN__ 512 513 #define __FN__ "ipp_free" 514 void 515 ipp_free( 516 char *buf) 517 { 518 free(buf); 519 } 520 #undef __FN__ 521 522 #define __FN__ "ipp_free_array" 523 void 524 ipp_free_array( 525 char **array, 526 int nelt) 527 { 528 int i; 529 530 assert(array[nelt] == NULL); 531 532 for (i = 0; i < nelt; i++) 533 free(array[i]); 534 535 free(array); 536 } 537 #undef __FN__ 538 539 #define __FN__ "nvlist_callback" 540 static int 541 nvlist_callback( 542 nvlist_t *nvlp, 543 void *arg) 544 { 545 nvlist_t **nvlpp = (nvlist_t **)arg; 546 int rc; 547 548 /* 549 * Callback function used by ipp_action_create() and 550 * ipp_action_modify() 551 */ 552 553 DBG0(DBG_IO, "called\n"); 554 555 assert(nvlpp != NULL); 556 assert(*nvlpp == NULL); 557 558 /* 559 * Duplicate the nvlist and set the given pointer to point at the new 560 * copy. 561 */ 562 563 if ((rc = nvlist_dup(nvlp, nvlpp, 0)) != 0) { 564 DBG0(DBG_ERR, "failed to dup nvlist\n"); 565 errno = rc; 566 return (-1); 567 } 568 569 return (0); 570 } 571 #undef __FN__ 572 573 #define __FN__ "string_callback" 574 static int 575 string_callback( 576 nvlist_t *nvlp, 577 void *arg) 578 { 579 char **namep = (char **)arg; 580 char *name; 581 char *ptr; 582 int rc; 583 584 /* 585 * Callback function used by ipp_action_mod() 586 */ 587 588 DBG0(DBG_IO, "called\n"); 589 590 assert(namep != NULL); 591 592 /* 593 * Look up the module name from the nvlist. 594 */ 595 596 if ((rc = nvlist_lookup_string(nvlp, IPPCTL_MODNAME, &ptr)) != 0) { 597 DBG0(DBG_ERR, "failed to find string\n"); 598 errno = rc; 599 return (-1); 600 } 601 602 /* 603 * Allocate a duplicate string. 604 */ 605 606 if ((name = strdup(ptr)) == NULL) { 607 DBG0(DBG_ERR, "failed to duplicate string\n"); 608 return (-1); 609 } 610 611 /* 612 * Set the given pointer to point at the string. 613 */ 614 615 *namep = name; 616 return (0); 617 } 618 #undef __FN__ 619 620 #define __FN__ "string_array_callback" 621 static int 622 string_array_callback( 623 nvlist_t *nvlp, 624 void *arg) 625 { 626 array_desc_t *adp = (array_desc_t *)arg; 627 char **dst; 628 char **src; 629 uint_t nelt; 630 int i; 631 int rc; 632 633 /* 634 * Callback function used by ipp_list_mods() 635 */ 636 637 DBG0(DBG_IO, "called\n"); 638 639 assert(adp != NULL); 640 641 /* 642 * Look up the module name from the nvlist. 643 */ 644 645 if ((rc = nvlist_lookup_string_array(nvlp, adp->name, &src, 646 &nelt)) != 0) { 647 DBG0(DBG_ERR, "failed to find array\n"); 648 errno = rc; 649 return (-1); 650 } 651 652 /* 653 * Allocate an array. 654 */ 655 656 if ((dst = malloc((nelt + 1) * sizeof (char *))) == NULL) { 657 DBG0(DBG_ERR, "failed to allocate new array\n"); 658 return (-1); 659 } 660 661 /* 662 * For each string in the array, allocate a new buffer and copy 663 * the string into it. 664 */ 665 666 for (i = 0; i < nelt; i++) { 667 if ((dst[i] = strdup(src[i])) == NULL) { 668 while (--i >= 0) { 669 free(dst[i]); 670 } 671 free(dst); 672 DBG0(DBG_ERR, "failed to duplicate array\n"); 673 return (-1); 674 } 675 } 676 dst[nelt] = NULL; 677 678 /* 679 * Set the information to be passed back. 680 */ 681 682 adp->array = dst; 683 adp->nelt = nelt; 684 685 return (0); 686 } 687 #undef __FN__ 688 689 #define __FN__ "dispatch" 690 static int 691 dispatch( 692 nvlist_t **nvlpp, 693 int (*fn)(nvlist_t *, void *), 694 void *arg) 695 { 696 char *cbuf = NULL; 697 char *dbuf = NULL; 698 size_t cbuflen = 0; 699 size_t dbuflen = 0; 700 size_t thisbuflen = 0; 701 size_t nextbuflen = 0; 702 int rc; 703 ippctl_ioctl_t iioc; 704 int fd; 705 nvlist_t *cnvlp; 706 nvlist_t *dnvlp = NULL; 707 int count; 708 int rval; 709 710 /* 711 * Sanity check the 'command' nvlist. 712 */ 713 714 cnvlp = *nvlpp; 715 if (cnvlp == NULL) { 716 rc = EINVAL; 717 return (-1); 718 } 719 720 /* 721 * Pack the nvlist and then free the original. 722 */ 723 724 if ((rc = nvlist_pack(cnvlp, &cbuf, &cbuflen, NV_ENCODE_NATIVE, 725 0)) != 0) { 726 DBG0(DBG_ERR, "failed to pack nvlist\n"); 727 nvlist_free(cnvlp); 728 errno = rc; 729 return (-1); 730 } 731 nvlist_free(cnvlp); 732 *nvlpp = NULL; 733 734 /* 735 * Open the control device node. 736 */ 737 738 DBG1(DBG_IO, "opening %s\n", IPPCTL_DEVICE); 739 if ((fd = open(IPPCTL_DEVICE, O_RDWR | O_NOCTTY)) == -1) { 740 DBG1(DBG_ERR, "failed to open %s\n", IPPCTL_DEVICE); 741 goto command_failed; 742 } 743 744 /* 745 * Set up an ioctl structure to point at the packed nvlist. 746 */ 747 748 iioc.ii_buf = cbuf; 749 iioc.ii_buflen = cbuflen; 750 751 /* 752 * Issue a command ioctl, passing the ioctl structure. 753 */ 754 755 DBG0(DBG_IO, "command\n"); 756 if ((rc = ioctl(fd, IPPCTL_CMD, &iioc)) < 0) { 757 DBG0(DBG_ERR, "command ioctl failed\n"); 758 goto command_failed; 759 } 760 761 /* 762 * Get back the length of the first data buffer. 763 */ 764 765 if ((nextbuflen = (size_t)rc) == 0) { 766 DBG0(DBG_ERR, "no data buffer\n"); 767 errno = EPROTO; 768 goto command_failed; 769 } 770 771 /* 772 * Try to re-use the command buffer as the first data buffer. 773 */ 774 775 dbuf = cbuf; 776 thisbuflen = cbuflen; 777 778 count = 0; 779 while (nextbuflen != 0) { 780 dbuflen = nextbuflen; 781 782 /* 783 * Check whether the buffer we have is long enough for the 784 * next lot of data. If it isn't, allocate a new one of 785 * the appropriate length. 786 */ 787 788 if (nextbuflen > thisbuflen) { 789 if ((dbuf = realloc(dbuf, nextbuflen)) == NULL) { 790 DBG0(DBG_ERR, 791 "failed to allocate data buffer\n"); 792 goto data_failed; 793 } 794 thisbuflen = nextbuflen; 795 } 796 797 /* 798 * Set up an ioctl structure to point at the data buffer. 799 */ 800 801 iioc.ii_buf = dbuf; 802 iioc.ii_buflen = dbuflen; 803 804 /* 805 * Issue a data ioctl, passing the ioctl structure. 806 */ 807 808 DBG2(DBG_IO, "data[%d]: length = %d\n", count, dbuflen); 809 if ((rc = ioctl(fd, IPPCTL_DATA, &iioc)) < 0) { 810 DBG0(DBG_ERR, "data ioctl failed\n"); 811 goto data_failed; 812 } 813 814 /* 815 * Get the length of the *next* data buffer, if there is 816 * one. 817 */ 818 819 nextbuflen = (size_t)rc; 820 DBG1(DBG_IO, "nextbuflen = %d\n", nextbuflen); 821 822 /* 823 * Unpack the nvlist that the current data buffer should 824 * now contain. 825 */ 826 827 if ((rc = nvlist_unpack(dbuf, dbuflen, &dnvlp, 0)) != 0) { 828 DBG0(DBG_ERR, "failed to unpack nvlist\n"); 829 errno = rc; 830 goto data_failed; 831 } 832 833 /* 834 * The first data buffer should contain the kernel function's 835 * return code. Subsequent buffers contain nvlists which 836 * should be passed to the given callback function. 837 */ 838 839 if (count == 0) { 840 if ((rc = nvlist_lookup_int32(dnvlp, IPPCTL_RC, 841 &rval)) != 0) { 842 DBG0(DBG_ERR, "failed to find return code\n"); 843 nvlist_free(dnvlp); 844 errno = rc; 845 goto data_failed; 846 } 847 } else { 848 if (fn != NULL) 849 if (fn(dnvlp, arg) != 0) { 850 851 /* 852 * The callback function returned 853 * a non-zero value. Abort any further 854 * data collection. 855 */ 856 857 nvlist_free(dnvlp); 858 free(dbuf); 859 } 860 } 861 862 /* 863 * Free the nvlist now that we have extracted the return 864 * code or called the callback function. 865 */ 866 867 nvlist_free(dnvlp); 868 dnvlp = NULL; 869 870 count++; 871 } 872 873 /* 874 * Free the data buffer as data collection is now complete. 875 */ 876 877 free(dbuf); 878 879 /* 880 * Close the control device. 881 */ 882 883 (void) close(fd); 884 885 /* 886 * If the kernel returned an error, we should return an error. 887 * and set errno. 888 */ 889 890 if (rval != 0) { 891 DBG1(DBG_IO, "kernel return code = %d\n", rval); 892 errno = rval; 893 return (-1); 894 } 895 896 return (0); 897 898 command_failed: 899 free(cbuf); 900 if (fd != -1) 901 (void) close(fd); 902 return (-1); 903 904 data_failed: 905 if (dbuf != NULL) 906 free(dbuf); 907 (void) close(fd); 908 return (-1); 909 } 910 #undef __FN__ 911