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 }