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
ipp_action_create(const char * modname,const char * aname,nvlist_t ** nvlpp,ipp_flags_t flags)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
ipp_action_destroy(const char * aname,ipp_flags_t flags)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
ipp_action_modify(const char * aname,nvlist_t ** nvlpp,ipp_flags_t flags)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
ipp_action_info(const char * aname,int (* fn)(nvlist_t *,void *),void * arg,ipp_flags_t flags)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
ipp_action_mod(const char * aname,char ** modnamep)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
ipp_list_mods(char *** modname_arrayp,int * neltp)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
ipp_mod_list_actions(const char * modname,char *** aname_arrayp,int * neltp)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
ipp_free(char * buf)522 ipp_free(
523 char *buf)
524 {
525 free(buf);
526 }
527 #undef __FN__
528
529 #define __FN__ "ipp_free_array"
530 void
ipp_free_array(char ** array,int nelt)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
nvlist_callback(nvlist_t * nvlp,void * arg)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
string_callback(nvlist_t * nvlp,void * arg)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
string_array_callback(nvlist_t * nvlp,void * arg)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
dispatch(nvlist_t ** nvlpp,int (* fn)(nvlist_t *,void *),void * arg)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