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