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.
29 #include <sys/types.h>
38 #include <libnvpair.h>
39 #include <ipp/ippctl.h>
45 #if defined(DEBUG) && !defined(lint)
46 uint32_t ipp_debug_flags
=
53 #define DBG0(flags, fmt) \
55 if (flags & ipp_debug_flags) \
56 fprintf(stderr, "libipp: " __FN__ ": " fmt); \
59 #define DBG1(flags, fmt, a) \
61 if (flags & ipp_debug_flags) \
62 fprintf(stderr, "libipp: " __FN__ ": " fmt, a); \
65 #define DBG2(flags, fmt, a, b) \
67 if (flags & ipp_debug_flags) \
68 fprintf(stderr, "libipp: " __FN__ ": " fmt, a, \
72 #define DBG3(flags, fmt, a, b, c) \
74 if (flags & ipp_debug_flags) \
75 fprintf(stderr, "libipp: " __FN__ ": " fmt, a, \
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) */
90 #define IPPCTL_DEVICE "/devices/pseudo/ippctl@0:ctl"
96 typedef struct array_desc_t
{
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 *);
114 #define __FN__ "ipp_action_create"
126 * Sanity check the arguments.
129 if (nvlpp
== NULL
|| modname
== NULL
|| aname
== NULL
) {
130 DBG0(DBG_ERR
, "bad argument\n");
136 * Add our data to the nvlist. (This information will be removed for
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
);
147 if ((rc
= nvlist_add_string(nvlp
, IPPCTL_MODNAME
,
148 (char *)modname
)) != 0) {
149 DBG1(DBG_ERR
, "failed to add '%s' to nvlist\n",
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
);
159 if ((rc
= nvlist_add_uint32(nvlp
, IPPCTL_FLAGS
, flags
)) != 0) {
160 DBG1(DBG_ERR
, "failed to add '%s' to nvlist\n", IPPCTL_FLAGS
);
165 * Talk to the kernel.
168 return (dispatch(nvlpp
, nvlist_callback
, (void *)nvlpp
));
175 #define __FN__ "ipp_action_destroy"
185 * Sanity check the arguments.
189 DBG0(DBG_ERR
, "bad argument\n");
195 * Create an nvlist for our data as none is passed into the function.
198 if ((rc
= nvlist_alloc(&nvlp
, NV_UNIQUE_NAME
, 0)) != 0) {
199 DBG0(DBG_ERR
, "failed to allocate nvlist\n");
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
);
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
);
215 if ((rc
= nvlist_add_uint32(nvlp
, IPPCTL_FLAGS
, flags
)) != 0) {
216 DBG1(DBG_ERR
, "failed to add '%s' to nvlist\n", IPPCTL_FLAGS
);
221 * Talk to the kernel.
224 return (dispatch(&nvlp
, NULL
, NULL
));
232 #define __FN__ "ipp_action_modify"
243 * Sanity check the arguments.
246 if (nvlpp
== NULL
|| aname
== NULL
) {
247 DBG0(DBG_ERR
, "bad argument\n");
253 * Add our data to the nvlist.
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
);
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
);
268 if ((rc
= nvlist_add_uint32(nvlp
, IPPCTL_FLAGS
, flags
)) != 0) {
269 DBG1(DBG_ERR
, "failed to add '%s' to nvlist\n", IPPCTL_FLAGS
);
274 * Talk to the kernel.
277 return (dispatch(nvlpp
, nvlist_callback
, (void *)nvlpp
));
284 #define __FN__ "ipp_action_info"
288 int (*fn
)(nvlist_t
*, void *),
296 * Sanity check the arguments.
299 if (aname
== NULL
|| fn
== NULL
) {
300 DBG0(DBG_ERR
, "bad argument\n");
306 * Create an nvlist for our data.
309 if ((rc
= nvlist_alloc(&nvlp
, NV_UNIQUE_NAME
, 0)) != 0) {
310 DBG0(DBG_ERR
, "failed to allocate nvlist\n");
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
);
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
);
325 if ((rc
= nvlist_add_uint32(nvlp
, IPPCTL_FLAGS
, flags
)) != 0) {
326 DBG1(DBG_ERR
, "failed to add '%s' to nvlist\n", IPPCTL_FLAGS
);
331 * Talk to the kernel.
334 return (dispatch(&nvlp
, fn
, arg
));
342 #define __FN__ "ipp_action_mod"
352 * Sanity check the arguments.
355 if (aname
== NULL
|| modnamep
== NULL
) {
356 DBG0(DBG_ERR
, "bad argument\n");
362 * Create an nvlist for our data.
365 if ((rc
= nvlist_alloc(&nvlp
, NV_UNIQUE_NAME
, 0)) != 0) {
366 DBG0(DBG_ERR
, "failed to allocate nvlist\n");
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
);
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
);
383 * Talk to the kernel.
386 return (dispatch(&nvlp
, string_callback
, (void *)modnamep
));
394 #define __FN__ "ipp_list_mods"
397 char ***modname_arrayp
,
405 * Sanity check the arguments.
408 if (modname_arrayp
== NULL
|| neltp
== NULL
) {
409 DBG0(DBG_ERR
, "bad argument");
415 * Create an nvlist for our data.
418 if ((rc
= nvlist_alloc(&nvlp
, NV_UNIQUE_NAME
, 0)) != 0) {
419 DBG0(DBG_ERR
, "failed to allocate nvlist\n");
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
);
430 * Talk to the kernel.
433 ad
.name
= IPPCTL_MODNAME_ARRAY
;
437 if ((rc
= dispatch(&nvlp
, string_array_callback
, (void *)&ad
)) == 0) {
438 *modname_arrayp
= ad
.array
;
450 #define __FN__ "ipp_mod_list_actions"
452 ipp_mod_list_actions(
454 char ***aname_arrayp
,
462 * Sanity check the arguments.
465 if (modname
== NULL
|| aname_arrayp
== NULL
|| neltp
== NULL
) {
466 DBG0(DBG_ERR
, "bad argument");
472 * Create an nvlist for our data.
475 if ((rc
= nvlist_alloc(&nvlp
, NV_UNIQUE_NAME
, 0)) != 0) {
476 DBG0(DBG_ERR
, "failed to allocate nvlist\n");
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
);
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
);
493 * Talk to the kernel.
496 ad
.name
= IPPCTL_ANAME_ARRAY
;
500 if ((rc
= dispatch(&nvlp
, string_array_callback
, (void *)&ad
)) == 0) {
501 *aname_arrayp
= ad
.array
;
513 #define __FN__ "ipp_free"
522 #define __FN__ "ipp_free_array"
530 assert(array
[nelt
] == NULL
);
532 for (i
= 0; i
< nelt
; i
++)
539 #define __FN__ "nvlist_callback"
545 nvlist_t
**nvlpp
= (nvlist_t
**)arg
;
549 * Callback function used by ipp_action_create() and
550 * ipp_action_modify()
553 DBG0(DBG_IO
, "called\n");
555 assert(nvlpp
!= NULL
);
556 assert(*nvlpp
== NULL
);
559 * Duplicate the nvlist and set the given pointer to point at the new
563 if ((rc
= nvlist_dup(nvlp
, nvlpp
, 0)) != 0) {
564 DBG0(DBG_ERR
, "failed to dup nvlist\n");
573 #define __FN__ "string_callback"
579 char **namep
= (char **)arg
;
585 * Callback function used by ipp_action_mod()
588 DBG0(DBG_IO
, "called\n");
590 assert(namep
!= NULL
);
593 * Look up the module name from the nvlist.
596 if ((rc
= nvlist_lookup_string(nvlp
, IPPCTL_MODNAME
, &ptr
)) != 0) {
597 DBG0(DBG_ERR
, "failed to find string\n");
603 * Allocate a duplicate string.
606 if ((name
= strdup(ptr
)) == NULL
) {
607 DBG0(DBG_ERR
, "failed to duplicate string\n");
612 * Set the given pointer to point at the string.
620 #define __FN__ "string_array_callback"
622 string_array_callback(
626 array_desc_t
*adp
= (array_desc_t
*)arg
;
634 * Callback function used by ipp_list_mods()
637 DBG0(DBG_IO
, "called\n");
642 * Look up the module name from the nvlist.
645 if ((rc
= nvlist_lookup_string_array(nvlp
, adp
->name
, &src
,
647 DBG0(DBG_ERR
, "failed to find array\n");
656 if ((dst
= malloc((nelt
+ 1) * sizeof (char *))) == NULL
) {
657 DBG0(DBG_ERR
, "failed to allocate new array\n");
662 * For each string in the array, allocate a new buffer and copy
663 * the string into it.
666 for (i
= 0; i
< nelt
; i
++) {
667 if ((dst
[i
] = strdup(src
[i
])) == NULL
) {
672 DBG0(DBG_ERR
, "failed to duplicate array\n");
679 * Set the information to be passed back.
689 #define __FN__ "dispatch"
693 int (*fn
)(nvlist_t
*, void *),
700 size_t thisbuflen
= 0;
701 size_t nextbuflen
= 0;
706 nvlist_t
*dnvlp
= NULL
;
711 * Sanity check the 'command' nvlist.
721 * Pack the nvlist and then free the original.
724 if ((rc
= nvlist_pack(cnvlp
, &cbuf
, &cbuflen
, NV_ENCODE_NATIVE
,
726 DBG0(DBG_ERR
, "failed to pack nvlist\n");
735 * Open the control device node.
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
);
745 * Set up an ioctl structure to point at the packed nvlist.
749 iioc
.ii_buflen
= cbuflen
;
752 * Issue a command ioctl, passing the ioctl structure.
755 DBG0(DBG_IO
, "command\n");
756 if ((rc
= ioctl(fd
, IPPCTL_CMD
, &iioc
)) < 0) {
757 DBG0(DBG_ERR
, "command ioctl failed\n");
762 * Get back the length of the first data buffer.
765 if ((nextbuflen
= (size_t)rc
) == 0) {
766 DBG0(DBG_ERR
, "no data buffer\n");
772 * Try to re-use the command buffer as the first data buffer.
776 thisbuflen
= cbuflen
;
779 while (nextbuflen
!= 0) {
780 dbuflen
= nextbuflen
;
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.
788 if (nextbuflen
> thisbuflen
) {
789 if ((dbuf
= realloc(dbuf
, nextbuflen
)) == NULL
) {
791 "failed to allocate data buffer\n");
794 thisbuflen
= nextbuflen
;
798 * Set up an ioctl structure to point at the data buffer.
802 iioc
.ii_buflen
= dbuflen
;
805 * Issue a data ioctl, passing the ioctl structure.
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");
815 * Get the length of the *next* data buffer, if there is
819 nextbuflen
= (size_t)rc
;
820 DBG1(DBG_IO
, "nextbuflen = %d\n", nextbuflen
);
823 * Unpack the nvlist that the current data buffer should
827 if ((rc
= nvlist_unpack(dbuf
, dbuflen
, &dnvlp
, 0)) != 0) {
828 DBG0(DBG_ERR
, "failed to unpack nvlist\n");
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.
840 if ((rc
= nvlist_lookup_int32(dnvlp
, IPPCTL_RC
,
842 DBG0(DBG_ERR
, "failed to find return code\n");
849 if (fn(dnvlp
, arg
) != 0) {
852 * The callback function returned
853 * a non-zero value. Abort any further
863 * Free the nvlist now that we have extracted the return
864 * code or called the callback function.
874 * Free the data buffer as data collection is now complete.
880 * Close the control device.
886 * If the kernel returned an error, we should return an error.
891 DBG1(DBG_IO
, "kernel return code = %d\n", rval
);