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 }; 78 79 struct termio tio; 80 struct termios tios; 81 82 CALL call; 83 84 int speed, fd; 85 86 char *sspeed; 87 88 89 if (pp->speed == NULL || (speed = atoi(pp->speed)) <= 0) 90 speed = -1; 91 92 call.attr = 0; 93 call.speed = speed; 94 call.line = 0; 95 call.telno = pp->dial_info; 96 97 if ((fd = dial(call)) < 0) 98 return (EXEC_EXIT_NDIAL | (~EXEC_EXIT_NMASK & abs(fd))); 99 100 /* 101 * "dial()" doesn't guarantee which file descriptor 102 * it uses when it opens the port, so we probably have to 103 * move it. 104 */ 105 if (fd != 1) { 106 dup2(fd, 1); 107 Close(fd); 108 } 109 110 /* 111 * The "printermgmt()" routines move out of ".stty" 112 * anything that looks like a baud rate, and puts it 113 * in ".speed", if the printer port is dialed. Thus 114 * we are saved the task of cleaning out spurious 115 * baud rates from ".stty". 116 * 117 * However, we must determine the baud rate and 118 * concatenate it onto ".stty" so that that we can 119 * override the default in the interface progam. 120 * Putting the override in ".stty" allows the user 121 * to override us (although it would be probably be 122 * silly for them to do so.) 123 */ 124 if (ioctl(1, TCGETS, &tios) < 0) { 125 ioctl(1, TCGETA, &tio); 126 tios.c_cflag = tio.c_cflag; 127 } 128 if ((sspeed = baud_table[cfgetospeed(&tios)]) != NULL) { 129 130 if (pp->stty == NULL) 131 pp->stty = ""; 132 133 { 134 char *new_stty = Malloc( 135 strlen(pp->stty) + 1 + strlen(sspeed) + 1); 136 137 sprintf(new_stty, "%s %s", pp->stty, sspeed); 138 139 /* 140 * We can trash "pp->stty" because 141 * the parent process has the good copy. 142 */ 143 pp->stty = new_stty; 144 } 145 } 146 147 return (0); 148 } 149 150 /* 151 * open_direct() - OPEN A PORT TO A DIRECTLY CONNECTED PRINTER 152 */ 153 154 int 155 open_direct(char *ptype, PRINTER *pp) 156 { 157 short bufsz = -1, cps = -1; 158 int open_mode, fd; 159 register unsigned int oldalarm, newalarm = 0; 160 char *device; 161 162 struct ecpp_transfer_parms ecpp_params; /* for ECPP port checking */ 163 char **modules = NULL; 164 165 struct flock lck; 166 struct stat buf; 167 168 register void (*oldsig)() = signal(SIGALRM, sigalrm); 169 170 171 /* 172 * Set an alarm to wake us from trying to open the port. 173 * We'll try at least 60 seconds, or more if the printer 174 * has a huge buffer that, in the worst case, would take 175 * a long time to drain. 176 */ 177 tidbit(ptype, "bufsz", &bufsz); 178 tidbit(ptype, "cps", &cps); 179 if (bufsz > 0 && cps > 0) 180 newalarm = (((long)bufsz * 1100) / cps) / 1000; 181 if (newalarm < 60) 182 newalarm = 60; 183 oldalarm = alarm(newalarm); 184 185 device = pp->device; 186 if (is_printer_uri(device) == 0) { 187 /* 188 * if it's a device uri and the endpoint contains a valid 189 * path, that path should be opened/locked by lpsched for 190 * the backend. If not, the uri isn't associated with a 191 * local device, so use /dev/null. 192 */ 193 device = strstr(device, "://"); 194 if (device != NULL) 195 device = strchr(device + 3, '/'); 196 197 if ((device == NULL) || (access(device, F_OK) < 0)) 198 device = "/dev/null"; 199 } 200 201 /* 202 * The following open must be interruptable. 203 * O_APPEND is set in case the ``port'' is a file. 204 * O_RDWR is set in case the interface program wants 205 * to get input from the printer. Don't fail, though, 206 * just because we can't get read access. 207 */ 208 209 open_mode = O_WRONLY; 210 if (access(device, R_OK) == 0) 211 open_mode = O_RDWR; 212 open_mode |= O_APPEND; 213 214 SigAlrm = 0; 215 216 while ((fd = open(device, open_mode, 0)) == -1) { 217 if (errno != EINTR) 218 return (EXEC_EXIT_NPORT); 219 else if (SigAlrm) 220 return (EXEC_EXIT_TMOUT); 221 } 222 223 alarm(oldalarm); 224 signal(SIGALRM, oldsig); 225 226 /* 227 * Lock the file in case two "printers" are defined on the 228 * same port. Don't lock /dev/null. 229 */ 230 231 lck.l_type = F_WRLCK; 232 lck.l_whence = 0; 233 lck.l_start = 0L; 234 lck.l_len = 0L; 235 236 if (strcmp(device, "/dev/null") && Fcntl(fd, F_SETLKW, &lck) < 0) { 237 execlog("lock error: %s\n", pp->device); 238 return (EXEC_EXIT_NPORT); 239 } 240 241 /* 242 * We should get the correct channel number (1), but just 243 * in case.... 244 */ 245 if (fd != 1) { 246 dup2(fd, 1); 247 Close(fd); 248 } 249 250 /* 251 * Handle streams modules: 252 */ 253 if (fstat(1, &buf)) 254 buf.st_mode = 0; 255 256 /* 257 * for some unknown reason, lpsched appears to pop the streams 258 * modules off the device and push back some "default" ones, 259 * unless a specific set were specified with the printer configuration. 260 * This behaviour causes problems with the ECPP port, so if we have 261 * an ECPP port, and nobody specified a set of modules to use, we 262 * should leave it alone. Normally, we would not bother to play with 263 * the streams modules, but it is possible that someone has come 264 * to rely on this behaviour for other devices. 265 */ 266 if ((pp->modules != NULL) && (pp->modules[0] != NULL) && 267 (strcmp(pp->modules[0], "default") != 0)) 268 modules = pp->modules; 269 270 if ((modules == NULL) && (ioctl(1, ECPPIOC_GETPARMS, &ecpp_params) < 0)) 271 modules = getlist(DEFMODULES, LP_WS, LP_SEP); 272 273 /* if "nopush" is supplied, leave the modules alone */ 274 if ((modules != NULL) && (modules[0] != NULL) && 275 (strcasecmp(modules[0], "nopush") == 0)) 276 modules = NULL; 277 278 /* 279 * If we have a stream and a list of modules to use, then pop the old 280 * modules and push the new ones. 281 */ 282 if ((modules != NULL) && !S_ISFIFO(buf.st_mode) && isastream(1)) { 283 /* 284 * First, pop all current modules off, unless 285 * instructed not to. 286 */ 287 while (ioctl(1, I_POP, 0) == 0) 288 ; 289 290 /* 291 * Now push either the administrator specified modules 292 * or the standard modules, unless instructed to push 293 * nothing. 294 */ 295 296 if ((modules[1] == NULL) && 297 (strcasecmp(modules[0], "none") == 0)) 298 return (0); 299 300 while (*modules) 301 if (push_module(1, device, *modules++) == -1) 302 return (EXEC_EXIT_NPUSH); 303 } 304 305 return (0); 306 } 307 308 /* 309 * sigalrm() 310 */ 311 static void 312 sigalrm(int ignore) 313 { 314 signal(SIGALRM, SIG_IGN); 315 SigAlrm = 1; 316 } 317 318 319 /* 320 * push_module() 321 */ 322 323 static int 324 push_module(int fd, char *device, char *module) 325 { 326 int ret = ioctl(fd, I_PUSH, module); 327 328 if (ret == -1) 329 note("push (%s) on %s failed (%s)\n", module, device, PERROR); 330 return (ret); 331 } 332