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