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 (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ 22 /* All Rights Reserved */ 23 24 25 /* 26 * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 27 * Use is subject to license terms. 28 * Copyright (c) 2016 by Delphix. All rights reserved. 29 */ 30 31 #include "termio.h" 32 #include "dial.h" 33 #include "unistd.h" 34 35 #include "lpsched.h" 36 37 #include <sys/ioccom.h> 38 #include <sys/ecppsys.h> 39 40 static void sigalrm(int); 41 static int push_module(int, char *, char *); 42 43 static int SigAlrm; 44 45 /* 46 * open_dialup() - OPEN A PORT TO A ``DIAL-UP'' PRINTER 47 */ 48 49 int 50 open_dialup(char *ptype, PRINTER *pp) 51 { 52 static char *baud_table[] = { 53 0, 54 "50", 55 "75", 56 "110", 57 "134", 58 "150", 59 "200", 60 "300", 61 "600", 62 "1200", 63 "1800", 64 "2400", 65 "4800", 66 "9600", 67 "19200", 68 "38400", 69 "57600", 70 "76800", 71 "115200", 72 "153600", 73 "230400", 74 "307200", 75 "460800", 76 "921600", 77 "1000000", 78 "1152000", 79 "1500000", 80 "2000000", 81 "2500000", 82 "3000000", 83 "3500000", 84 "4000000" 85 }; 86 87 struct termio tio; 88 struct termios tios; 89 90 CALL call; 91 92 int speed, fd; 93 94 char *sspeed; 95 96 97 if (pp->speed == NULL || (speed = atoi(pp->speed)) <= 0) 98 speed = -1; 99 100 call.attr = 0; 101 call.speed = speed; 102 call.line = 0; 103 call.telno = pp->dial_info; 104 105 if ((fd = dial(call)) < 0) 106 return (EXEC_EXIT_NDIAL | (~EXEC_EXIT_NMASK & abs(fd))); 107 108 /* 109 * "dial()" doesn't guarantee which file descriptor 110 * it uses when it opens the port, so we probably have to 111 * move it. 112 */ 113 if (fd != 1) { 114 dup2(fd, 1); 115 Close(fd); 116 } 117 118 /* 119 * The "printermgmt()" routines move out of ".stty" 120 * anything that looks like a baud rate, and puts it 121 * in ".speed", if the printer port is dialed. Thus 122 * we are saved the task of cleaning out spurious 123 * baud rates from ".stty". 124 * 125 * However, we must determine the baud rate and 126 * concatenate it onto ".stty" so that that we can 127 * override the default in the interface progam. 128 * Putting the override in ".stty" allows the user 129 * to override us (although it would be probably be 130 * silly for them to do so.) 131 */ 132 if (ioctl(1, TCGETS, &tios) < 0) { 133 ioctl(1, TCGETA, &tio); 134 tios.c_cflag = tio.c_cflag; 135 } 136 if ((sspeed = baud_table[cfgetospeed(&tios)]) != NULL) { 137 138 if (pp->stty == NULL) 139 pp->stty = ""; 140 141 { 142 char *new_stty = Malloc( 143 strlen(pp->stty) + 1 + strlen(sspeed) + 1); 144 145 sprintf(new_stty, "%s %s", pp->stty, sspeed); 146 147 /* 148 * We can trash "pp->stty" because 149 * the parent process has the good copy. 150 */ 151 pp->stty = new_stty; 152 } 153 } 154 155 return (0); 156 } 157 158 /* 159 * open_direct() - OPEN A PORT TO A DIRECTLY CONNECTED PRINTER 160 */ 161 162 int 163 open_direct(char *ptype, PRINTER *pp) 164 { 165 short bufsz = -1, cps = -1; 166 int open_mode, fd; 167 register unsigned int oldalarm, newalarm = 0; 168 char *device; 169 170 struct ecpp_transfer_parms ecpp_params; /* for ECPP port checking */ 171 char **modules = NULL; 172 173 struct flock lck; 174 struct stat buf; 175 176 register void (*oldsig)() = signal(SIGALRM, sigalrm); 177 178 179 /* 180 * Set an alarm to wake us from trying to open the port. 181 * We'll try at least 60 seconds, or more if the printer 182 * has a huge buffer that, in the worst case, would take 183 * a long time to drain. 184 */ 185 tidbit(ptype, "bufsz", &bufsz); 186 tidbit(ptype, "cps", &cps); 187 if (bufsz > 0 && cps > 0) 188 newalarm = (((long)bufsz * 1100) / cps) / 1000; 189 if (newalarm < 60) 190 newalarm = 60; 191 oldalarm = alarm(newalarm); 192 193 device = pp->device; 194 if (is_printer_uri(device) == 0) { 195 /* 196 * if it's a device uri and the endpoint contains a valid 197 * path, that path should be opened/locked by lpsched for 198 * the backend. If not, the uri isn't associated with a 199 * local device, so use /dev/null. 200 */ 201 device = strstr(device, "://"); 202 if (device != NULL) 203 device = strchr(device + 3, '/'); 204 205 if ((device == NULL) || (access(device, F_OK) < 0)) 206 device = "/dev/null"; 207 } 208 209 /* 210 * The following open must be interruptable. 211 * O_APPEND is set in case the ``port'' is a file. 212 * O_RDWR is set in case the interface program wants 213 * to get input from the printer. Don't fail, though, 214 * just because we can't get read access. 215 */ 216 217 open_mode = O_WRONLY; 218 if (access(device, R_OK) == 0) 219 open_mode = O_RDWR; 220 open_mode |= O_APPEND; 221 222 SigAlrm = 0; 223 224 while ((fd = open(device, open_mode, 0)) == -1) { 225 if (errno != EINTR) 226 return (EXEC_EXIT_NPORT); 227 else if (SigAlrm) 228 return (EXEC_EXIT_TMOUT); 229 } 230 231 alarm(oldalarm); 232 signal(SIGALRM, oldsig); 233 234 /* 235 * Lock the file in case two "printers" are defined on the 236 * same port. Don't lock /dev/null. 237 */ 238 239 lck.l_type = F_WRLCK; 240 lck.l_whence = 0; 241 lck.l_start = 0L; 242 lck.l_len = 0L; 243 244 if (strcmp(device, "/dev/null") && Fcntl(fd, F_SETLKW, &lck) < 0) { 245 execlog("lock error: %s\n", pp->device); 246 return (EXEC_EXIT_NPORT); 247 } 248 249 /* 250 * We should get the correct channel number (1), but just 251 * in case.... 252 */ 253 if (fd != 1) { 254 dup2(fd, 1); 255 Close(fd); 256 } 257 258 /* 259 * Handle streams modules: 260 */ 261 if (fstat(1, &buf)) 262 buf.st_mode = 0; 263 264 /* 265 * for some unknown reason, lpsched appears to pop the streams 266 * modules off the device and push back some "default" ones, 267 * unless a specific set were specified with the printer configuration. 268 * This behaviour causes problems with the ECPP port, so if we have 269 * an ECPP port, and nobody specified a set of modules to use, we 270 * should leave it alone. Normally, we would not bother to play with 271 * the streams modules, but it is possible that someone has come 272 * to rely on this behaviour for other devices. 273 */ 274 if ((pp->modules != NULL) && (pp->modules[0] != NULL) && 275 (strcmp(pp->modules[0], "default") != 0)) 276 modules = pp->modules; 277 278 if ((modules == NULL) && (ioctl(1, ECPPIOC_GETPARMS, &ecpp_params) < 0)) 279 modules = getlist(DEFMODULES, LP_WS, LP_SEP); 280 281 /* if "nopush" is supplied, leave the modules alone */ 282 if ((modules != NULL) && (modules[0] != NULL) && 283 (strcasecmp(modules[0], "nopush") == 0)) 284 modules = NULL; 285 286 /* 287 * If we have a stream and a list of modules to use, then pop the old 288 * modules and push the new ones. 289 */ 290 if ((modules != NULL) && !S_ISFIFO(buf.st_mode) && isastream(1)) { 291 /* 292 * First, pop all current modules off, unless 293 * instructed not to. 294 */ 295 while (ioctl(1, I_POP, 0) == 0) 296 ; 297 298 /* 299 * Now push either the administrator specified modules 300 * or the standard modules, unless instructed to push 301 * nothing. 302 */ 303 304 if ((modules[1] == NULL) && 305 (strcasecmp(modules[0], "none") == 0)) 306 return (0); 307 308 while (*modules) 309 if (push_module(1, device, *modules++) == -1) 310 return (EXEC_EXIT_NPUSH); 311 } 312 313 return (0); 314 } 315 316 /* 317 * sigalrm() 318 */ 319 static void 320 sigalrm(int ignore) 321 { 322 signal(SIGALRM, SIG_IGN); 323 SigAlrm = 1; 324 } 325 326 327 /* 328 * push_module() 329 */ 330 331 static int 332 push_module(int fd, char *device, char *module) 333 { 334 int ret = ioctl(fd, I_PUSH, module); 335 336 if (ret == -1) 337 note("push (%s) on %s failed (%s)\n", module, device, PERROR); 338 return (ret); 339 } 340