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