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
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.
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]
23 * Copyright 2001-2002 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
27 #pragma ident "%Z%%M% %I% %E% SMI"
31 #include <sys/types.h>
40 #include <libnvpair.h>
41 #include <ipp/ippctl.h>
47 #if defined(DEBUG) && !defined(lint)
48 uint32_t ipp_debug_flags
=
55 #define DBG0(flags, fmt) \
57 if (flags & ipp_debug_flags) \
58 fprintf(stderr, "libipp: " __FN__ ": " fmt); \
61 #define DBG1(flags, fmt, a) \
63 if (flags & ipp_debug_flags) \
64 fprintf(stderr, "libipp: " __FN__ ": " fmt, a); \
67 #define DBG2(flags, fmt, a, b) \
69 if (flags & ipp_debug_flags) \
70 fprintf(stderr, "libipp: " __FN__ ": " fmt, a, \
74 #define DBG3(flags, fmt, a, b, c) \
76 if (flags & ipp_debug_flags) \
77 fprintf(stderr, "libipp: " __FN__ ": " fmt, a, \
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) */
92 #define IPPCTL_DEVICE "/devices/pseudo/ippctl@0:ctl"
98 typedef struct array_desc_t
{
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 *);
116 #define __FN__ "ipp_action_create"
128 * Sanity check the arguments.
131 if (nvlpp
== NULL
|| modname
== NULL
|| aname
== NULL
) {
132 DBG0(DBG_ERR
, "bad argument\n");
138 * Add our data to the nvlist. (This information will be removed for
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
);
149 if ((rc
= nvlist_add_string(nvlp
, IPPCTL_MODNAME
,
150 (char *)modname
)) != 0) {
151 DBG1(DBG_ERR
, "failed to add '%s' to nvlist\n",
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
);
161 if ((rc
= nvlist_add_uint32(nvlp
, IPPCTL_FLAGS
, flags
)) != 0) {
162 DBG1(DBG_ERR
, "failed to add '%s' to nvlist\n", IPPCTL_FLAGS
);
167 * Talk to the kernel.
170 return (dispatch(nvlpp
, nvlist_callback
, (void *)nvlpp
));
177 #define __FN__ "ipp_action_destroy"
187 * Sanity check the arguments.
191 DBG0(DBG_ERR
, "bad argument\n");
197 * Create an nvlist for our data as none is passed into the function.
200 if ((rc
= nvlist_alloc(&nvlp
, NV_UNIQUE_NAME
, 0)) != 0) {
201 DBG0(DBG_ERR
, "failed to allocate nvlist\n");
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
);
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
);
217 if ((rc
= nvlist_add_uint32(nvlp
, IPPCTL_FLAGS
, flags
)) != 0) {
218 DBG1(DBG_ERR
, "failed to add '%s' to nvlist\n", IPPCTL_FLAGS
);
223 * Talk to the kernel.
226 return (dispatch(&nvlp
, NULL
, NULL
));
235 #define __FN__ "ipp_action_modify"
246 * Sanity check the arguments.
249 if (nvlpp
== NULL
|| aname
== NULL
) {
250 DBG0(DBG_ERR
, "bad argument\n");
256 * Add our data to the nvlist.
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
);
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
);
271 if ((rc
= nvlist_add_uint32(nvlp
, IPPCTL_FLAGS
, flags
)) != 0) {
272 DBG1(DBG_ERR
, "failed to add '%s' to nvlist\n", IPPCTL_FLAGS
);
277 * Talk to the kernel.
280 return (dispatch(nvlpp
, nvlist_callback
, (void *)nvlpp
));
287 #define __FN__ "ipp_action_info"
291 int (*fn
)(nvlist_t
*, void *),
299 * Sanity check the arguments.
302 if (aname
== NULL
|| fn
== NULL
) {
303 DBG0(DBG_ERR
, "bad argument\n");
309 * Create an nvlist for our data.
312 if ((rc
= nvlist_alloc(&nvlp
, NV_UNIQUE_NAME
, 0)) != 0) {
313 DBG0(DBG_ERR
, "failed to allocate nvlist\n");
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
);
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
);
328 if ((rc
= nvlist_add_uint32(nvlp
, IPPCTL_FLAGS
, flags
)) != 0) {
329 DBG1(DBG_ERR
, "failed to add '%s' to nvlist\n", IPPCTL_FLAGS
);
334 * Talk to the kernel.
337 return (dispatch(&nvlp
, fn
, arg
));
346 #define __FN__ "ipp_action_mod"
356 * Sanity check the arguments.
359 if (aname
== NULL
|| modnamep
== NULL
) {
360 DBG0(DBG_ERR
, "bad argument\n");
366 * Create an nvlist for our data.
369 if ((rc
= nvlist_alloc(&nvlp
, NV_UNIQUE_NAME
, 0)) != 0) {
370 DBG0(DBG_ERR
, "failed to allocate nvlist\n");
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
);
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
);
387 * Talk to the kernel.
390 return (dispatch(&nvlp
, string_callback
, (void *)modnamep
));
399 #define __FN__ "ipp_list_mods"
402 char ***modname_arrayp
,
410 * Sanity check the arguments.
413 if (modname_arrayp
== NULL
|| neltp
== NULL
) {
414 DBG0(DBG_ERR
, "bad argument");
420 * Create an nvlist for our data.
423 if ((rc
= nvlist_alloc(&nvlp
, NV_UNIQUE_NAME
, 0)) != 0) {
424 DBG0(DBG_ERR
, "failed to allocate nvlist\n");
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
);
435 * Talk to the kernel.
438 ad
.name
= IPPCTL_MODNAME_ARRAY
;
442 if ((rc
= dispatch(&nvlp
, string_array_callback
, (void *)&ad
)) == 0) {
443 *modname_arrayp
= ad
.array
;
456 #define __FN__ "ipp_mod_list_actions"
458 ipp_mod_list_actions(
460 char ***aname_arrayp
,
468 * Sanity check the arguments.
471 if (modname
== NULL
|| aname_arrayp
== NULL
|| neltp
== NULL
) {
472 DBG0(DBG_ERR
, "bad argument");
478 * Create an nvlist for our data.
481 if ((rc
= nvlist_alloc(&nvlp
, NV_UNIQUE_NAME
, 0)) != 0) {
482 DBG0(DBG_ERR
, "failed to allocate nvlist\n");
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
);
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
);
499 * Talk to the kernel.
502 ad
.name
= IPPCTL_ANAME_ARRAY
;
506 if ((rc
= dispatch(&nvlp
, string_array_callback
, (void *)&ad
)) == 0) {
507 *aname_arrayp
= ad
.array
;
520 #define __FN__ "ipp_free"
529 #define __FN__ "ipp_free_array"
537 assert(array
[nelt
] == NULL
);
539 for (i
= 0; i
< nelt
; i
++)
546 #define __FN__ "nvlist_callback"
552 nvlist_t
**nvlpp
= (nvlist_t
**)arg
;
556 * Callback function used by ipp_action_create() and
557 * ipp_action_modify()
560 DBG0(DBG_IO
, "called\n");
562 assert(nvlpp
!= NULL
);
563 assert(*nvlpp
== NULL
);
566 * Duplicate the nvlist and set the given pointer to point at the new
570 if ((rc
= nvlist_dup(nvlp
, nvlpp
, 0)) != 0) {
571 DBG0(DBG_ERR
, "failed to dup nvlist\n");
580 #define __FN__ "string_callback"
586 char **namep
= (char **)arg
;
592 * Callback function used by ipp_action_mod()
595 DBG0(DBG_IO
, "called\n");
597 assert(namep
!= NULL
);
600 * Look up the module name from the nvlist.
603 if ((rc
= nvlist_lookup_string(nvlp
, IPPCTL_MODNAME
, &ptr
)) != 0) {
604 DBG0(DBG_ERR
, "failed to find string\n");
610 * Allocate a duplicate string.
613 if ((name
= strdup(ptr
)) == NULL
) {
614 DBG0(DBG_ERR
, "failed to duplicate string\n");
619 * Set the given pointer to point at the string.
627 #define __FN__ "string_array_callback"
629 string_array_callback(
633 array_desc_t
*adp
= (array_desc_t
*)arg
;
641 * Callback function used by ipp_list_mods()
644 DBG0(DBG_IO
, "called\n");
649 * Look up the module name from the nvlist.
652 if ((rc
= nvlist_lookup_string_array(nvlp
, adp
->name
, &src
,
654 DBG0(DBG_ERR
, "failed to find array\n");
663 if ((dst
= malloc((nelt
+ 1) * sizeof (char *))) == NULL
) {
664 DBG0(DBG_ERR
, "failed to allocate new array\n");
669 * For each string in the array, allocate a new buffer and copy
670 * the string into it.
673 for (i
= 0; i
< nelt
; i
++) {
674 if ((dst
[i
] = strdup(src
[i
])) == NULL
) {
679 DBG0(DBG_ERR
, "failed to duplicate array\n");
686 * Set the information to be passed back.
696 #define __FN__ "dispatch"
700 int (*fn
)(nvlist_t
*, void *),
707 size_t thisbuflen
= 0;
708 size_t nextbuflen
= 0;
713 nvlist_t
*dnvlp
= NULL
;
718 * Sanity check the 'command' nvlist.
728 * Pack the nvlist and then free the original.
731 if ((rc
= nvlist_pack(cnvlp
, &cbuf
, &cbuflen
, NV_ENCODE_NATIVE
,
733 DBG0(DBG_ERR
, "failed to pack nvlist\n");
742 * Open the control device node.
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
);
752 * Set up an ioctl structure to point at the packed nvlist.
756 iioc
.ii_buflen
= cbuflen
;
759 * Issue a command ioctl, passing the ioctl structure.
762 DBG0(DBG_IO
, "command\n");
763 if ((rc
= ioctl(fd
, IPPCTL_CMD
, &iioc
)) < 0) {
764 DBG0(DBG_ERR
, "command ioctl failed\n");
769 * Get back the length of the first data buffer.
772 if ((nextbuflen
= (size_t)rc
) == 0) {
773 DBG0(DBG_ERR
, "no data buffer\n");
779 * Try to re-use the command buffer as the first data buffer.
783 thisbuflen
= cbuflen
;
786 while (nextbuflen
!= 0) {
787 dbuflen
= nextbuflen
;
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.
795 if (nextbuflen
> thisbuflen
) {
796 if ((dbuf
= realloc(dbuf
, nextbuflen
)) == NULL
) {
798 "failed to allocate data buffer\n");
801 thisbuflen
= nextbuflen
;
805 * Set up an ioctl structure to point at the data buffer.
809 iioc
.ii_buflen
= dbuflen
;
812 * Issue a data ioctl, passing the ioctl structure.
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");
822 * Get the length of the *next* data buffer, if there is
826 nextbuflen
= (size_t)rc
;
827 DBG1(DBG_IO
, "nextbuflen = %d\n", nextbuflen
);
830 * Unpack the nvlist that the current data buffer should
834 if ((rc
= nvlist_unpack(dbuf
, dbuflen
, &dnvlp
, 0)) != 0) {
835 DBG0(DBG_ERR
, "failed to unpack nvlist\n");
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.
847 if ((rc
= nvlist_lookup_int32(dnvlp
, IPPCTL_RC
,
849 DBG0(DBG_ERR
, "failed to find return code\n");
856 if (fn(dnvlp
, arg
) != 0) {
859 * The callback function returned
860 * a non-zero value. Abort any further
870 * Free the nvlist now that we have extracted the return
871 * code or called the callback function.
881 * Free the data buffer as data collection is now complete.
887 * Close the control device.
893 * If the kernel returned an error, we should return an error.
898 DBG1(DBG_IO
, "kernel return code = %d\n", rval
);