6811333 Remove prom_printf() message in emlxs driver
[opensolaris.git] / usr / src / lib / libipp / libipp.c
blob94a5dc3a45a155ccf7f57234d7fb258f1e0b22fe
1 /*
2 * CDDL HEADER START
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.
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]
20 * CDDL HEADER END
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"
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>
44 * Debug macros
47 #if defined(DEBUG) && !defined(lint)
48 uint32_t ipp_debug_flags =
50 * DBG_IO |
52 DBG_ERR |
55 #define DBG0(flags, fmt) \
56 do { \
57 if (flags & ipp_debug_flags) \
58 fprintf(stderr, "libipp: " __FN__ ": " fmt); \
59 } while (0)
61 #define DBG1(flags, fmt, a) \
62 do { \
63 if (flags & ipp_debug_flags) \
64 fprintf(stderr, "libipp: " __FN__ ": " fmt, a); \
65 } while (0)
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)
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)
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) */
89 * Control device node
92 #define IPPCTL_DEVICE "/devices/pseudo/ippctl@0:ctl"
95 * Structures.
98 typedef struct array_desc_t {
99 char *name;
100 char **array;
101 int nelt;
102 } array_desc_t;
105 * Prototypes
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 *);
114 * API functions
116 #define __FN__ "ipp_action_create"
118 ipp_action_create(
119 const char *modname,
120 const char *aname,
121 nvlist_t **nvlpp,
122 ipp_flags_t flags)
124 nvlist_t *nvlp;
125 int rc;
128 * Sanity check the arguments.
131 if (nvlpp == NULL || modname == NULL || aname == NULL) {
132 DBG0(DBG_ERR, "bad argument\n");
133 errno = EINVAL;
134 return (-1);
138 * Add our data to the nvlist. (This information will be removed for
139 * use by ippctl).
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;
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;
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;
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;
167 * Talk to the kernel.
170 return (dispatch(nvlpp, nvlist_callback, (void *)nvlpp));
171 failed:
172 errno = rc;
173 return (-1);
175 #undef __FN__
177 #define __FN__ "ipp_action_destroy"
179 ipp_action_destroy(
180 const char *aname,
181 ipp_flags_t flags)
183 nvlist_t *nvlp;
184 int rc;
187 * Sanity check the arguments.
190 if (aname == NULL) {
191 DBG0(DBG_ERR, "bad argument\n");
192 errno = EINVAL;
193 return (-1);
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");
202 nvlp = NULL;
203 goto failed;
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;
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;
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;
223 * Talk to the kernel.
226 return (dispatch(&nvlp, NULL, NULL));
227 failed:
228 if (nvlp != NULL)
229 nvlist_free(nvlp);
230 errno = rc;
231 return (-1);
233 #undef __FN__
235 #define __FN__ "ipp_action_modify"
237 ipp_action_modify(
238 const char *aname,
239 nvlist_t **nvlpp,
240 ipp_flags_t flags)
242 nvlist_t *nvlp;
243 int rc;
246 * Sanity check the arguments.
249 if (nvlpp == NULL || aname == NULL) {
250 DBG0(DBG_ERR, "bad argument\n");
251 errno = EINVAL;
252 return (-1);
256 * Add our data to the nvlist.
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;
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;
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;
277 * Talk to the kernel.
280 return (dispatch(nvlpp, nvlist_callback, (void *)nvlpp));
281 failed:
282 errno = rc;
283 return (-1);
285 #undef __FN__
287 #define __FN__ "ipp_action_info"
289 ipp_action_info(
290 const char *aname,
291 int (*fn)(nvlist_t *, void *),
292 void *arg,
293 ipp_flags_t flags)
295 nvlist_t *nvlp;
296 int rc;
299 * Sanity check the arguments.
302 if (aname == NULL || fn == NULL) {
303 DBG0(DBG_ERR, "bad argument\n");
304 errno = EINVAL;
305 return (-1);
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");
314 nvlp = NULL;
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;
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;
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;
334 * Talk to the kernel.
337 return (dispatch(&nvlp, fn, arg));
338 failed:
339 if (nvlp != NULL)
340 nvlist_free(nvlp);
341 errno = rc;
342 return (-1);
344 #undef __FN__
346 #define __FN__ "ipp_action_mod"
348 ipp_action_mod(
349 const char *aname,
350 char **modnamep)
352 nvlist_t *nvlp;
353 int rc;
356 * Sanity check the arguments.
359 if (aname == NULL || modnamep == NULL) {
360 DBG0(DBG_ERR, "bad argument\n");
361 errno = EINVAL;
362 return (-1);
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");
371 nvlp = NULL;
372 goto failed;
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;
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;
387 * Talk to the kernel.
390 return (dispatch(&nvlp, string_callback, (void *)modnamep));
391 failed:
392 if (nvlp != NULL)
393 nvlist_free(nvlp);
394 errno = rc;
395 return (-1);
397 #undef __FN__
399 #define __FN__ "ipp_list_mods"
401 ipp_list_mods(
402 char ***modname_arrayp,
403 int *neltp)
405 nvlist_t *nvlp;
406 array_desc_t ad;
407 int rc;
410 * Sanity check the arguments.
413 if (modname_arrayp == NULL || neltp == NULL) {
414 DBG0(DBG_ERR, "bad argument");
415 errno = EINVAL;
416 return (-1);
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");
425 nvlp = NULL;
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;
435 * Talk to the kernel.
438 ad.name = IPPCTL_MODNAME_ARRAY;
439 ad.array = NULL;
440 ad.nelt = 0;
442 if ((rc = dispatch(&nvlp, string_array_callback, (void *)&ad)) == 0) {
443 *modname_arrayp = ad.array;
444 *neltp = ad.nelt;
447 return (rc);
448 failed:
449 if (nvlp != NULL)
450 nvlist_free(nvlp);
451 errno = rc;
452 return (-1);
454 #undef __FN__
456 #define __FN__ "ipp_mod_list_actions"
458 ipp_mod_list_actions(
459 const char *modname,
460 char ***aname_arrayp,
461 int *neltp)
463 nvlist_t *nvlp;
464 array_desc_t ad;
465 int rc;
468 * Sanity check the arguments.
471 if (modname == NULL || aname_arrayp == NULL || neltp == NULL) {
472 DBG0(DBG_ERR, "bad argument");
473 errno = EINVAL;
474 return (-1);
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");
483 nvlp = NULL;
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;
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;
499 * Talk to the kernel.
502 ad.name = IPPCTL_ANAME_ARRAY;
503 ad.array = NULL;
504 ad.nelt = 0;
506 if ((rc = dispatch(&nvlp, string_array_callback, (void *)&ad)) == 0) {
507 *aname_arrayp = ad.array;
508 *neltp = ad.nelt;
511 return (rc);
512 failed:
513 if (nvlp != NULL)
514 nvlist_free(nvlp);
515 errno = rc;
516 return (-1);
518 #undef __FN__
520 #define __FN__ "ipp_free"
521 void
522 ipp_free(
523 char *buf)
525 free(buf);
527 #undef __FN__
529 #define __FN__ "ipp_free_array"
530 void
531 ipp_free_array(
532 char **array,
533 int nelt)
535 int i;
537 assert(array[nelt] == NULL);
539 for (i = 0; i < nelt; i++)
540 free(array[i]);
542 free(array);
544 #undef __FN__
546 #define __FN__ "nvlist_callback"
547 static int
548 nvlist_callback(
549 nvlist_t *nvlp,
550 void *arg)
552 nvlist_t **nvlpp = (nvlist_t **)arg;
553 int rc;
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
567 * copy.
570 if ((rc = nvlist_dup(nvlp, nvlpp, 0)) != 0) {
571 DBG0(DBG_ERR, "failed to dup nvlist\n");
572 errno = rc;
573 return (-1);
576 return (0);
578 #undef __FN__
580 #define __FN__ "string_callback"
581 static int
582 string_callback(
583 nvlist_t *nvlp,
584 void *arg)
586 char **namep = (char **)arg;
587 char *name;
588 char *ptr;
589 int rc;
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");
605 errno = rc;
606 return (-1);
610 * Allocate a duplicate string.
613 if ((name = strdup(ptr)) == NULL) {
614 DBG0(DBG_ERR, "failed to duplicate string\n");
615 return (-1);
619 * Set the given pointer to point at the string.
622 *namep = name;
623 return (0);
625 #undef __FN__
627 #define __FN__ "string_array_callback"
628 static int
629 string_array_callback(
630 nvlist_t *nvlp,
631 void *arg)
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;
641 * Callback function used by ipp_list_mods()
644 DBG0(DBG_IO, "called\n");
646 assert(adp != NULL);
649 * Look up the module name from the nvlist.
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);
660 * Allocate an array.
663 if ((dst = malloc((nelt + 1) * sizeof (char *))) == NULL) {
664 DBG0(DBG_ERR, "failed to allocate new array\n");
665 return (-1);
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) {
675 while (--i >= 0) {
676 free(dst[i]);
678 free(dst);
679 DBG0(DBG_ERR, "failed to duplicate array\n");
680 return (-1);
683 dst[nelt] = NULL;
686 * Set the information to be passed back.
689 adp->array = dst;
690 adp->nelt = nelt;
692 return (0);
694 #undef __FN__
696 #define __FN__ "dispatch"
697 static int
698 dispatch(
699 nvlist_t **nvlpp,
700 int (*fn)(nvlist_t *, void *),
701 void *arg)
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;
718 * Sanity check the 'command' nvlist.
721 cnvlp = *nvlpp;
722 if (cnvlp == NULL) {
723 rc = EINVAL;
724 return (-1);
728 * Pack the nvlist and then free the original.
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);
738 nvlist_free(cnvlp);
739 *nvlpp = NULL;
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);
748 goto command_failed;
752 * Set up an ioctl structure to point at the packed nvlist.
755 iioc.ii_buf = cbuf;
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");
765 goto command_failed;
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");
774 errno = EPROTO;
775 goto command_failed;
779 * Try to re-use the command buffer as the first data buffer.
782 dbuf = cbuf;
783 thisbuflen = cbuflen;
785 count = 0;
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) {
797 DBG0(DBG_ERR,
798 "failed to allocate data buffer\n");
799 goto data_failed;
801 thisbuflen = nextbuflen;
805 * Set up an ioctl structure to point at the data buffer.
808 iioc.ii_buf = dbuf;
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");
818 goto data_failed;
822 * Get the length of the *next* data buffer, if there is
823 * one.
826 nextbuflen = (size_t)rc;
827 DBG1(DBG_IO, "nextbuflen = %d\n", nextbuflen);
830 * Unpack the nvlist that the current data buffer should
831 * now contain.
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;
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.
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;
854 } else {
855 if (fn != NULL)
856 if (fn(dnvlp, arg) != 0) {
859 * The callback function returned
860 * a non-zero value. Abort any further
861 * data collection.
864 nvlist_free(dnvlp);
865 free(dbuf);
870 * Free the nvlist now that we have extracted the return
871 * code or called the callback function.
874 nvlist_free(dnvlp);
875 dnvlp = NULL;
877 count++;
881 * Free the data buffer as data collection is now complete.
884 free(dbuf);
887 * Close the control device.
890 (void) close(fd);
893 * If the kernel returned an error, we should return an error.
894 * and set errno.
897 if (rval != 0) {
898 DBG1(DBG_IO, "kernel return code = %d\n", rval);
899 errno = rval;
900 return (-1);
903 return (0);
905 command_failed:
906 free(cbuf);
907 if (fd != -1)
908 (void) close(fd);
909 return (-1);
911 data_failed:
912 if (dbuf != NULL)
913 free(dbuf);
914 (void) close(fd);
915 return (-1);
917 #undef __FN__