Home | History | Annotate | Download | only in lpsched
      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
     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
    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
    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
    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