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