xref: /illumos-gate/usr/src/cmd/lp/cmd/lpsched/ports.c (revision d9c3e05c)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5de81e71eSTim Marsland  * Common Development and Distribution License (the "License").
6de81e71eSTim Marsland  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
217c478bd9Sstevel@tonic-gate /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
227c478bd9Sstevel@tonic-gate /*	  All Rights Reserved  	*/
237c478bd9Sstevel@tonic-gate 
247c478bd9Sstevel@tonic-gate 
257c478bd9Sstevel@tonic-gate /*
26de81e71eSTim Marsland  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
277c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
2848bbca81SDaniel Hoffman  * Copyright (c) 2016 by Delphix. All rights reserved.
297c478bd9Sstevel@tonic-gate  */
307c478bd9Sstevel@tonic-gate 
317c478bd9Sstevel@tonic-gate #include "termio.h"
327c478bd9Sstevel@tonic-gate #include "dial.h"
337c478bd9Sstevel@tonic-gate #include "unistd.h"
347c478bd9Sstevel@tonic-gate 
357c478bd9Sstevel@tonic-gate #include "lpsched.h"
367c478bd9Sstevel@tonic-gate 
377c478bd9Sstevel@tonic-gate #include <sys/ioccom.h>
387c478bd9Sstevel@tonic-gate #include <sys/ecppsys.h>
397c478bd9Sstevel@tonic-gate 
40de81e71eSTim Marsland static void		sigalrm(int);
41de81e71eSTim Marsland static int		push_module(int, char *, char *);
427c478bd9Sstevel@tonic-gate 
437c478bd9Sstevel@tonic-gate static int		SigAlrm;
447c478bd9Sstevel@tonic-gate 
45de81e71eSTim Marsland /*
46de81e71eSTim Marsland  * open_dialup() - OPEN A PORT TO A ``DIAL-UP'' PRINTER
47de81e71eSTim Marsland  */
487c478bd9Sstevel@tonic-gate 
497c478bd9Sstevel@tonic-gate int
open_dialup(char * ptype,PRINTER * pp)50de81e71eSTim Marsland open_dialup(char *ptype, PRINTER *pp)
517c478bd9Sstevel@tonic-gate {
527c478bd9Sstevel@tonic-gate 	static char		*baud_table[]	= {
53de81e71eSTim Marsland 		0,
54de81e71eSTim Marsland 		"50",
55de81e71eSTim Marsland 		"75",
56de81e71eSTim Marsland 		"110",
57de81e71eSTim Marsland 		"134",
58de81e71eSTim Marsland 		"150",
59de81e71eSTim Marsland 		"200",
60de81e71eSTim Marsland 		"300",
61de81e71eSTim Marsland 		"600",
62de81e71eSTim Marsland 		"1200",
63de81e71eSTim Marsland 		"1800",
64de81e71eSTim Marsland 		"2400",
65de81e71eSTim Marsland 		"4800",
66de81e71eSTim Marsland 		"9600",
677c478bd9Sstevel@tonic-gate 		"19200",
687c478bd9Sstevel@tonic-gate 		"38400",
697c478bd9Sstevel@tonic-gate 		"57600",
707c478bd9Sstevel@tonic-gate 		"76800",
717c478bd9Sstevel@tonic-gate 		"115200",
727c478bd9Sstevel@tonic-gate 		"153600",
737c478bd9Sstevel@tonic-gate 		"230400",
747c478bd9Sstevel@tonic-gate 		"307200",
75de81e71eSTim Marsland 		"460800",
76*d9c3e05cSJoshua M. Clulow 		"921600",
77*d9c3e05cSJoshua M. Clulow 		"1000000",
78*d9c3e05cSJoshua M. Clulow 		"1152000",
79*d9c3e05cSJoshua M. Clulow 		"1500000",
80*d9c3e05cSJoshua M. Clulow 		"2000000",
81*d9c3e05cSJoshua M. Clulow 		"2500000",
82*d9c3e05cSJoshua M. Clulow 		"3000000",
83*d9c3e05cSJoshua M. Clulow 		"3500000",
84*d9c3e05cSJoshua M. Clulow 		"4000000"
857c478bd9Sstevel@tonic-gate 	};
867c478bd9Sstevel@tonic-gate 
877c478bd9Sstevel@tonic-gate 	struct termio		tio;
887c478bd9Sstevel@tonic-gate 	struct termios		tios;
897c478bd9Sstevel@tonic-gate 
907c478bd9Sstevel@tonic-gate 	CALL			call;
917c478bd9Sstevel@tonic-gate 
92de81e71eSTim Marsland 	int			speed, fd;
937c478bd9Sstevel@tonic-gate 
947c478bd9Sstevel@tonic-gate 	char			*sspeed;
957c478bd9Sstevel@tonic-gate 
967c478bd9Sstevel@tonic-gate 
977c478bd9Sstevel@tonic-gate 	if (pp->speed == NULL || (speed = atoi(pp->speed)) <= 0)
987c478bd9Sstevel@tonic-gate 		speed = -1;
997c478bd9Sstevel@tonic-gate 
1007c478bd9Sstevel@tonic-gate 	call.attr = 0;
1017c478bd9Sstevel@tonic-gate 	call.speed = speed;
1027c478bd9Sstevel@tonic-gate 	call.line = 0;
1037c478bd9Sstevel@tonic-gate 	call.telno = pp->dial_info;
1047c478bd9Sstevel@tonic-gate 
1057c478bd9Sstevel@tonic-gate 	if ((fd = dial(call)) < 0)
1067c478bd9Sstevel@tonic-gate 		return (EXEC_EXIT_NDIAL | (~EXEC_EXIT_NMASK & abs(fd)));
1077c478bd9Sstevel@tonic-gate 
1087c478bd9Sstevel@tonic-gate 	/*
1097c478bd9Sstevel@tonic-gate 	 * "dial()" doesn't guarantee which file descriptor
1107c478bd9Sstevel@tonic-gate 	 * it uses when it opens the port, so we probably have to
1117c478bd9Sstevel@tonic-gate 	 * move it.
1127c478bd9Sstevel@tonic-gate 	 */
1137c478bd9Sstevel@tonic-gate 	if (fd != 1) {
114de81e71eSTim Marsland 		dup2(fd, 1);
115de81e71eSTim Marsland 		Close(fd);
1167c478bd9Sstevel@tonic-gate 	}
1177c478bd9Sstevel@tonic-gate 
1187c478bd9Sstevel@tonic-gate 	/*
1197c478bd9Sstevel@tonic-gate 	 * The "printermgmt()" routines move out of ".stty"
1207c478bd9Sstevel@tonic-gate 	 * anything that looks like a baud rate, and puts it
1217c478bd9Sstevel@tonic-gate 	 * in ".speed", if the printer port is dialed. Thus
1227c478bd9Sstevel@tonic-gate 	 * we are saved the task of cleaning out spurious
1237c478bd9Sstevel@tonic-gate 	 * baud rates from ".stty".
1247c478bd9Sstevel@tonic-gate 	 *
1257c478bd9Sstevel@tonic-gate 	 * However, we must determine the baud rate and
1267c478bd9Sstevel@tonic-gate 	 * concatenate it onto ".stty" so that that we can
1277c478bd9Sstevel@tonic-gate 	 * override the default in the interface progam.
1287c478bd9Sstevel@tonic-gate 	 * Putting the override in ".stty" allows the user
1297c478bd9Sstevel@tonic-gate 	 * to override us (although it would be probably be
13048bbca81SDaniel Hoffman 	 * silly for them to do so.)
1317c478bd9Sstevel@tonic-gate 	 */
132de81e71eSTim Marsland 	if (ioctl(1, TCGETS, &tios) < 0) {
133de81e71eSTim Marsland 		ioctl(1, TCGETA, &tio);
1347c478bd9Sstevel@tonic-gate 		tios.c_cflag = tio.c_cflag;
1357c478bd9Sstevel@tonic-gate 	}
1367c478bd9Sstevel@tonic-gate 	if ((sspeed = baud_table[cfgetospeed(&tios)]) != NULL) {
1377c478bd9Sstevel@tonic-gate 
1387c478bd9Sstevel@tonic-gate 		if (pp->stty == NULL)
1397c478bd9Sstevel@tonic-gate 			pp->stty = "";
140de81e71eSTim Marsland 
1417c478bd9Sstevel@tonic-gate 		{
142de81e71eSTim Marsland 			char *new_stty = Malloc(
143de81e71eSTim Marsland 			    strlen(pp->stty) + 1 + strlen(sspeed) + 1);
1447c478bd9Sstevel@tonic-gate 
145de81e71eSTim Marsland 			sprintf(new_stty, "%s %s", pp->stty, sspeed);
1467c478bd9Sstevel@tonic-gate 
147de81e71eSTim Marsland 			/*
148de81e71eSTim Marsland 			 * We can trash "pp->stty" because
149de81e71eSTim Marsland 			 * the parent process has the good copy.
150de81e71eSTim Marsland 			 */
151de81e71eSTim Marsland 			pp->stty = new_stty;
1527c478bd9Sstevel@tonic-gate 		}
1537c478bd9Sstevel@tonic-gate 	}
1547c478bd9Sstevel@tonic-gate 
1557c478bd9Sstevel@tonic-gate 	return (0);
1567c478bd9Sstevel@tonic-gate }
1577c478bd9Sstevel@tonic-gate 
158de81e71eSTim Marsland /*
159de81e71eSTim Marsland  * open_direct() - OPEN A PORT TO A DIRECTLY CONNECTED PRINTER
160de81e71eSTim Marsland  */
1617c478bd9Sstevel@tonic-gate 
1627c478bd9Sstevel@tonic-gate int
open_direct(char * ptype,PRINTER * pp)1637c478bd9Sstevel@tonic-gate open_direct(char *ptype, PRINTER *pp)
1647c478bd9Sstevel@tonic-gate {
165de81e71eSTim Marsland 	short bufsz = -1, cps = -1;
166de81e71eSTim Marsland 	int open_mode, fd;
167de81e71eSTim Marsland 	register unsigned int oldalarm, newalarm = 0;
1687c478bd9Sstevel@tonic-gate 	char *device;
1697c478bd9Sstevel@tonic-gate 
1707c478bd9Sstevel@tonic-gate 	struct ecpp_transfer_parms ecpp_params;	/* for ECPP port checking */
171de81e71eSTim Marsland 	char **modules = NULL;
1727c478bd9Sstevel@tonic-gate 
1737c478bd9Sstevel@tonic-gate 	struct flock		lck;
1747c478bd9Sstevel@tonic-gate 	struct stat		buf;
1757c478bd9Sstevel@tonic-gate 
1767c478bd9Sstevel@tonic-gate 	register void		(*oldsig)() = signal(SIGALRM, sigalrm);
1777c478bd9Sstevel@tonic-gate 
1787c478bd9Sstevel@tonic-gate 
1797c478bd9Sstevel@tonic-gate 	/*
1807c478bd9Sstevel@tonic-gate 	 * Set an alarm to wake us from trying to open the port.
1817c478bd9Sstevel@tonic-gate 	 * We'll try at least 60 seconds, or more if the printer
1827c478bd9Sstevel@tonic-gate 	 * has a huge buffer that, in the worst case, would take
1837c478bd9Sstevel@tonic-gate 	 * a long time to drain.
1847c478bd9Sstevel@tonic-gate 	 */
185de81e71eSTim Marsland 	tidbit(ptype, "bufsz", &bufsz);
186de81e71eSTim Marsland 	tidbit(ptype, "cps", &cps);
1877c478bd9Sstevel@tonic-gate 	if (bufsz > 0 && cps > 0)
1887c478bd9Sstevel@tonic-gate 		newalarm = (((long)bufsz * 1100) / cps) / 1000;
1897c478bd9Sstevel@tonic-gate 	if (newalarm < 60)
1907c478bd9Sstevel@tonic-gate 		newalarm = 60;
1917c478bd9Sstevel@tonic-gate 	oldalarm = alarm(newalarm);
1927c478bd9Sstevel@tonic-gate 
1937c478bd9Sstevel@tonic-gate 	device = pp->device;
1947c478bd9Sstevel@tonic-gate 	if (is_printer_uri(device) == 0) {
1957c478bd9Sstevel@tonic-gate 		/*
1967c478bd9Sstevel@tonic-gate 		 * if it's a device uri and the endpoint contains a valid
1977c478bd9Sstevel@tonic-gate 		 * path, that path should be opened/locked by lpsched for
1987c478bd9Sstevel@tonic-gate 		 * the backend.  If not, the uri isn't associated with a
1997c478bd9Sstevel@tonic-gate 		 * local device, so use /dev/null.
2007c478bd9Sstevel@tonic-gate 		 */
2017c478bd9Sstevel@tonic-gate 		device = strstr(device, "://");
2027c478bd9Sstevel@tonic-gate 		if (device != NULL)
2037c478bd9Sstevel@tonic-gate 			device = strchr(device + 3, '/');
2047c478bd9Sstevel@tonic-gate 
2057c478bd9Sstevel@tonic-gate 		if ((device == NULL) || (access(device, F_OK) < 0))
2067c478bd9Sstevel@tonic-gate 			device = "/dev/null";
2077c478bd9Sstevel@tonic-gate 	}
2087c478bd9Sstevel@tonic-gate 
2097c478bd9Sstevel@tonic-gate 	/*
2107c478bd9Sstevel@tonic-gate 	 * The following open must be interruptable.
2117c478bd9Sstevel@tonic-gate 	 * O_APPEND is set in case the ``port'' is a file.
2127c478bd9Sstevel@tonic-gate 	 * O_RDWR is set in case the interface program wants
2137c478bd9Sstevel@tonic-gate 	 * to get input from the printer. Don't fail, though,
2147c478bd9Sstevel@tonic-gate 	 * just because we can't get read access.
2157c478bd9Sstevel@tonic-gate 	 */
2167c478bd9Sstevel@tonic-gate 
2177c478bd9Sstevel@tonic-gate 	open_mode = O_WRONLY;
2187c478bd9Sstevel@tonic-gate 	if (access(device, R_OK) == 0)
2197c478bd9Sstevel@tonic-gate 		open_mode = O_RDWR;
2207c478bd9Sstevel@tonic-gate 	open_mode |= O_APPEND;
2217c478bd9Sstevel@tonic-gate 
2227c478bd9Sstevel@tonic-gate 	SigAlrm = 0;
2237c478bd9Sstevel@tonic-gate 
2247c478bd9Sstevel@tonic-gate 	while ((fd = open(device, open_mode, 0)) == -1) {
2257c478bd9Sstevel@tonic-gate 		if (errno != EINTR)
2267c478bd9Sstevel@tonic-gate 			return (EXEC_EXIT_NPORT);
2277c478bd9Sstevel@tonic-gate 		else if (SigAlrm)
2287c478bd9Sstevel@tonic-gate 			return (EXEC_EXIT_TMOUT);
2297c478bd9Sstevel@tonic-gate 	}
2307c478bd9Sstevel@tonic-gate 
231de81e71eSTim Marsland 	alarm(oldalarm);
232de81e71eSTim Marsland 	signal(SIGALRM, oldsig);
2337c478bd9Sstevel@tonic-gate 
2347c478bd9Sstevel@tonic-gate 	/*
2357c478bd9Sstevel@tonic-gate 	 * Lock the file in case two "printers" are defined on the
2367c478bd9Sstevel@tonic-gate 	 * same port.  Don't lock /dev/null.
2377c478bd9Sstevel@tonic-gate 	 */
2387c478bd9Sstevel@tonic-gate 
2397c478bd9Sstevel@tonic-gate 	lck.l_type = F_WRLCK;
240de81e71eSTim Marsland 	lck.l_whence = 0;
2417c478bd9Sstevel@tonic-gate 	lck.l_start = 0L;
2427c478bd9Sstevel@tonic-gate 	lck.l_len = 0L;
2437c478bd9Sstevel@tonic-gate 
2447c478bd9Sstevel@tonic-gate 	if (strcmp(device, "/dev/null") && Fcntl(fd, F_SETLKW, &lck) < 0) {
2457c478bd9Sstevel@tonic-gate 		execlog("lock error: %s\n", pp->device);
2467c478bd9Sstevel@tonic-gate 		return (EXEC_EXIT_NPORT);
2477c478bd9Sstevel@tonic-gate 	}
2487c478bd9Sstevel@tonic-gate 
2497c478bd9Sstevel@tonic-gate 	/*
2507c478bd9Sstevel@tonic-gate 	 * We should get the correct channel number (1), but just
2517c478bd9Sstevel@tonic-gate 	 * in case....
2527c478bd9Sstevel@tonic-gate 	 */
2537c478bd9Sstevel@tonic-gate 	if (fd != 1) {
254de81e71eSTim Marsland 		dup2(fd, 1);
255de81e71eSTim Marsland 		Close(fd);
2567c478bd9Sstevel@tonic-gate 	}
2577c478bd9Sstevel@tonic-gate 
2587c478bd9Sstevel@tonic-gate 	/*
2597c478bd9Sstevel@tonic-gate 	 * Handle streams modules:
2607c478bd9Sstevel@tonic-gate 	 */
2617c478bd9Sstevel@tonic-gate 	if (fstat(1, &buf))
2627c478bd9Sstevel@tonic-gate 		buf.st_mode = 0;
2637c478bd9Sstevel@tonic-gate 
2647c478bd9Sstevel@tonic-gate 	/*
2657c478bd9Sstevel@tonic-gate 	 * for some unknown reason, lpsched appears to pop the streams
2667c478bd9Sstevel@tonic-gate 	 * modules off the device and push back some "default" ones,
2677c478bd9Sstevel@tonic-gate 	 * unless a specific set were specified with the printer configuration.
2687c478bd9Sstevel@tonic-gate 	 * This behaviour causes problems with the ECPP port, so if we have
2697c478bd9Sstevel@tonic-gate 	 * an ECPP port, and nobody specified a set of modules to use, we
2707c478bd9Sstevel@tonic-gate 	 * should leave it alone.  Normally, we would not bother to play with
2717c478bd9Sstevel@tonic-gate 	 * the streams modules, but it is possible that someone has come
2727c478bd9Sstevel@tonic-gate 	 * to rely on this behaviour for other devices.
2737c478bd9Sstevel@tonic-gate 	 */
2747c478bd9Sstevel@tonic-gate 	if ((pp->modules != NULL) && (pp->modules[0] != NULL) &&
2757c478bd9Sstevel@tonic-gate 	    (strcmp(pp->modules[0], "default") != 0))
2767c478bd9Sstevel@tonic-gate 		modules = pp->modules;
2777c478bd9Sstevel@tonic-gate 
2787c478bd9Sstevel@tonic-gate 	if ((modules == NULL) && (ioctl(1, ECPPIOC_GETPARMS, &ecpp_params) < 0))
2797c478bd9Sstevel@tonic-gate 		modules = getlist(DEFMODULES, LP_WS, LP_SEP);
2807c478bd9Sstevel@tonic-gate 
2817c478bd9Sstevel@tonic-gate 	/* if "nopush" is supplied, leave the modules alone */
2827c478bd9Sstevel@tonic-gate 	if ((modules != NULL) && (modules[0] != NULL) &&
2837c478bd9Sstevel@tonic-gate 	    (strcasecmp(modules[0], "nopush") == 0))
2847c478bd9Sstevel@tonic-gate 		modules = NULL;
2857c478bd9Sstevel@tonic-gate 
2867c478bd9Sstevel@tonic-gate 	/*
2877c478bd9Sstevel@tonic-gate 	 * If we have a stream and a list of modules to use, then pop the old
2887c478bd9Sstevel@tonic-gate 	 * modules and push the new ones.
2897c478bd9Sstevel@tonic-gate 	 */
2904bc0a2efScasper 	if ((modules != NULL) && !S_ISFIFO(buf.st_mode) && isastream(1)) {
2917c478bd9Sstevel@tonic-gate 		/*
2927c478bd9Sstevel@tonic-gate 		 * First, pop all current modules off, unless
2937c478bd9Sstevel@tonic-gate 		 * instructed not to.
2947c478bd9Sstevel@tonic-gate 		 */
2957c478bd9Sstevel@tonic-gate 		while (ioctl(1, I_POP, 0) == 0)
296de81e71eSTim Marsland 			;
2977c478bd9Sstevel@tonic-gate 
2987c478bd9Sstevel@tonic-gate 		/*
2997c478bd9Sstevel@tonic-gate 		 * Now push either the administrator specified modules
3007c478bd9Sstevel@tonic-gate 		 * or the standard modules, unless instructed to push
3017c478bd9Sstevel@tonic-gate 		 * nothing.
3027c478bd9Sstevel@tonic-gate 		 */
3037c478bd9Sstevel@tonic-gate 
3047c478bd9Sstevel@tonic-gate 		if ((modules[1] == NULL) &&
3057c478bd9Sstevel@tonic-gate 		    (strcasecmp(modules[0], "none") == 0))
3067c478bd9Sstevel@tonic-gate 			return (0);
3077c478bd9Sstevel@tonic-gate 
3087c478bd9Sstevel@tonic-gate 		while (*modules)
3097c478bd9Sstevel@tonic-gate 			if (push_module(1, device, *modules++) == -1)
3107c478bd9Sstevel@tonic-gate 				return (EXEC_EXIT_NPUSH);
3117c478bd9Sstevel@tonic-gate 	}
3127c478bd9Sstevel@tonic-gate 
3137c478bd9Sstevel@tonic-gate 	return (0);
3147c478bd9Sstevel@tonic-gate }
3157c478bd9Sstevel@tonic-gate 
316de81e71eSTim Marsland /*
317de81e71eSTim Marsland  * sigalrm()
318de81e71eSTim Marsland  */
3197c478bd9Sstevel@tonic-gate static void
sigalrm(int ignore)3207c478bd9Sstevel@tonic-gate sigalrm(int ignore)
3217c478bd9Sstevel@tonic-gate {
322de81e71eSTim Marsland 	signal(SIGALRM, SIG_IGN);
3237c478bd9Sstevel@tonic-gate 	SigAlrm = 1;
3247c478bd9Sstevel@tonic-gate }
3257c478bd9Sstevel@tonic-gate 
3267c478bd9Sstevel@tonic-gate 
327de81e71eSTim Marsland /*
328de81e71eSTim Marsland  * push_module()
329de81e71eSTim Marsland  */
3307c478bd9Sstevel@tonic-gate 
3317c478bd9Sstevel@tonic-gate static int
push_module(int fd,char * device,char * module)3327c478bd9Sstevel@tonic-gate push_module(int fd, char *device, char *module)
3337c478bd9Sstevel@tonic-gate {
334de81e71eSTim Marsland 	int ret	= ioctl(fd, I_PUSH, module);
3357c478bd9Sstevel@tonic-gate 
3367c478bd9Sstevel@tonic-gate 	if (ret == -1)
337de81e71eSTim Marsland 		note("push (%s) on %s failed (%s)\n", module, device, PERROR);
3387c478bd9Sstevel@tonic-gate 	return (ret);
3397c478bd9Sstevel@tonic-gate }
340