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 2005 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 */
26
27 /*
28 * Copyright (c) 2018, Joyent, Inc.
29 */
30
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <unistd.h>
34 #include <string.h>
35 #include <sys/ioctl.h>
36 #include <sys/prnio.h>
37 #include <fcntl.h>
38
39 #define COMMAND_SET_MAX 16 /* more than 16 command sets is not likely */
40 #define NP(x) (x ? x : "")
41
42 typedef struct {
43 char *manufacturer;
44 char *model;
45 char *description;
46 char *class;
47 char *command_set[COMMAND_SET_MAX];
48 } printer_description_t;
49
50 int
51 get_printer_description(char *path, printer_description_t *info)
52 {
53 int fd, rc;
54 struct prn_1284_device_id id;
55 char buf[BUFSIZ];
56 char *s, *iter = NULL;
57
58 /* open the device */
59 if ((fd = open(path, O_RDWR)) < 0)
60 return (fd);
61
62 /* get the 1284 device id */
63 memset(&id, 0, sizeof (id));
64 memset(&buf, 0, sizeof (buf));
65 id.id_len = sizeof (buf);
66 id.id_data = buf;
67
68 rc = ioctl(fd, PRNIOC_GET_1284_DEVID, &id);
69 /* close(fd); */
70 if (rc < 0)
71 return (rc);
72
73 memset(info, 0, sizeof (*info));
74
75 /* parse the 1284 device id string */
76 for (s = (char *)strtok_r(buf, ";\n", &iter); s != NULL;
77 s = (char *)strtok_r(NULL, ";\n", &iter)) {
78 char *t, *u, *iter2 = NULL;
79
80 if ((t = (char *)strtok_r(s, ":\n", &iter2)) == NULL)
81 continue;
82
83 if ((u = (char *)strtok_r(NULL, ":\n", &iter2)) == NULL)
84 continue;
85
86 if ((strcasecmp(t, "MFG") == 0) ||
87 (strcasecmp(t, "MANUFACTURER") == 0))
88 info->manufacturer = strdup(u);
89 else if ((strcasecmp(t, "MDL") == 0) ||
90 (strcasecmp(t, "MODEL") == 0))
91 info->model = strdup(u);
92 else if ((strcasecmp(t, "DES") == 0) ||
93 (strcasecmp(t, "DESCRIPTION") == 0))
94 info->description = strdup(u);
95 else if ((strcasecmp(t, "CLS") == 0) ||
96 (strcasecmp(t, "CLASS") == 0))
97 info->class = strdup(u);
98 else if ((strcasecmp(t, "CMD") == 0) ||
99 (strcasecmp(t, "COMMAND SET") == 0)) {
100 /* this should be more dynamic, I got lazy */
101 char *v, *iter3 = NULL;
102 int i = 0;
103
104 for (v = (char *)strtok_r(u, ",\n", &iter3);
105 ((v != NULL) && (i < COMMAND_SET_MAX));
106 v = (char *)strtok_r(NULL, ",\n", &iter3))
107 info->command_set[i++] = strdup(v);
108 }
109 }
110
111 return (0);
112 }
113
114 static void
115 usage(char *name)
116 {
117 char *program;
118
119 if ((program = strrchr(name, '/')) == NULL)
120 program = name;
121 else
122 program++;
123
124 printf("Usage: %s [-aMmdCc] (path) ...\n", program);
125 }
126
127 int
128 main(int ac, char *av[])
129 {
130 int rc;
131 int manufacturer = 0, model = 0, description = 0, command_set = 0,
132 class = 0;
133
134 while ((rc = getopt(ac, av, "aMmdCc")) != EOF)
135 switch (rc) {
136 case 'a':
137 manufacturer++;
138 model++;
139 description++;
140 command_set++;
141 class++;
142 break;
143 case 'M':
144 manufacturer++;
145 break;
146 case 'm':
147 model++;
148 break;
149 case 'd':
150 description++;
151 break;
152 case 'C':
153 command_set++;
154 break;
155 case 'c':
156 class++;
157 break;
158 default:
159 usage(av[0]);
160 exit(1);
161 }
162
163 if (optind >= ac) {
164 usage(av[0]);
165 exit(1);
166 }
167
168 while (optind < ac) {
169 char *path = av[optind++];
170 printer_description_t info;
171
172 rc = get_printer_description(path, &info);
173 if (rc == 0) {
174 printf("%s:\n", path);
175 if (manufacturer != 0)
176 printf("\tManufacturer: %s\n",
177 NP(info.manufacturer));
178 if (model != 0)
179 printf("\tModel: %s\n",
180 NP(info.model));
181 if (description != 0)
182 printf("\tDescription: %s\n",
183 NP(info.description));
184 if (class != 0)
185 printf("\tClass: %s\n",
186 NP(info.class));
187 if (command_set != 0) {
188 int i;
189
190 printf("\tCommand set:\n");
191 for (i = 0; info.command_set[i] != NULL; i++)
192 printf("\t\tcmd[%d]: %s\n", i,
193 info.command_set[i]);
194 }
195 } else
196 perror(path);
197 }
198 return (rc);
199 }