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