1/* Coherent tty locking support.  This file was contributed by Bob
2   Hemedinger <bob@dalek.mwc.com> of Mark Williams Corporation and
3   lightly edited by Ian Lance Taylor.  */
4
5/* The bottom part of this file is lock.c.
6 * This is a hacked lock.c. A full lock.c can be found in the libmisc sources
7 * under /usr/src/misc.tar.Z.
8 *
9 * These are for checking for the existence of locks:
10 * lockexist(resource)
11 * lockttyexist(ttyname)
12 */
13
14#include "uucp.h"
15
16#if HAVE_COHERENT_LOCKFILES
17
18/* cohtty.c:	Given a serial device name, read /etc/ttys and determine if
19 *		the device is already enabled. If it is, disable the
20 *		device and return a string so that it can be re-enabled
21 * 		at the completion of the uucico session as part of the
22 *		function that resets the serial device before uucico
23 *		terminates.
24 *
25 */
26
27#include "uudefs.h"
28#include "sysdep.h"
29
30#include <ctype.h>
31#include <access.h>
32
33/* fscoherent_disable_tty() is a COHERENT specific function. It takes the name
34 * of a serial device and then scans /etc/ttys for a match. If it finds one,
35 * it checks the first field of the entry. If it is a '1', then it will disable
36 * the port and set a flag. The flag will be checked later when uucico wants to
37 * reset the serial device to see if the device needs to be re-enabled.
38 */
39
40/* May 10, 1993: This function will always return true for the following
41 * reasons:
42 *  1) lock files have already been dealt with
43 *  2) if someone else already has the port open, uucico should fail anyways
44 *  3) Coherent's disable command return can return '0' or '1', but will
45 *     succeed in any event.
46 *  4) It doesn't matter if there is a ttys entry for the port in question.
47 *     /etc/ttys generally only lists devices that MAY be enabled for logins.
48 *     If a device will never be used for logins, then there may not be a
49 *     ttys entry, in which case, disable won't be called anyways.
50 *	---bob@mwc.com
51 */
52
53boolean
54fscoherent_disable_tty (zdevice, pzenable)
55     const char *zdevice;
56     char **pzenable;
57{
58
59
60struct ttyentry{			/* this is an /etc/ttys entry */
61	char enable_disable[1];
62	char remote_local[1];
63	char baud_rate[1];
64	char tty_device[16];
65};
66
67struct ttyentry sought_tty;
68
69int x,y,z;				/* dummy */
70FILE *	infp;				/* this will point to /etc/ttys */
71char disable_command[66];		/* this will be the disable command
72					 * passed to the system.
73					 */
74char enable_device[16];			/* this will hold our device name
75					 * to enable.
76					 */
77
78	*pzenable = NULL;
79
80	strcpy(enable_device,"");	/* initialize our strings */
81	strcpy(sought_tty.tty_device,"");
82
83	if( (infp = fopen("/etc/ttys","r")) == NULL){
84		ulog(LOG_ERROR,"Error: check_disable_tty: failed to open /etc/ttys\n");
85		return FALSE;
86	}
87
88	while (NULL !=(fgets(&sought_tty, sizeof (sought_tty), infp ))){
89		sought_tty.tty_device[strlen(sought_tty.tty_device) -1] = '\0';
90		strcpy(enable_device,sought_tty.tty_device);
91
92		/* we must strip away the suffix to the com port name or
93		 * we will never find a match. For example, if we are passed
94		 * /dev/com4l to call out with and the port is already enabled,
95		 * 9/10 the port enabled will be com4r. After we strip away the
96		 * suffix of the port found in /etc/ttys, then we can test
97		 * if the base port name appears in the device name string
98		 * passed to us.
99		 */
100
101		for(z = strlen(sought_tty.tty_device) ; z > 0 ; z--){
102			if(isdigit(sought_tty.tty_device[z])){
103				break;
104			}
105		}
106		y = strlen(sought_tty.tty_device);
107		for(x = z+1 ; x <= y; x++){
108			sought_tty.tty_device[x] = '\0';
109		}
110
111
112/*		ulog(LOG_NORMAL,"found device {%s}\n",sought_tty.tty_device); */
113		if(strstr(zdevice, sought_tty.tty_device)){
114			if(sought_tty.enable_disable[0] == '1'){
115				ulog(LOG_NORMAL, "coh_tty: Disabling device %s {%s}\n",
116					zdevice, sought_tty.tty_device);
117					sprintf(disable_command, "/etc/disable %s",enable_device);
118				{
119				  pid_t ipid;
120				  const char *azargs[3];
121				  int aidescs[3];
122
123				  azargs[0] = "/etc/disable";
124				  azargs[1] = enable_device;
125				  azargs[2] = NULL;
126				  aidescs[0] = SPAWN_NULL;
127				  aidescs[1] = SPAWN_NULL;
128				  aidescs[2] = SPAWN_NULL;
129				  ipid = ixsspawn (azargs, aidescs, TRUE,
130						   FALSE,
131						   (const char *) NULL, TRUE,
132						   TRUE,
133						   (const char *) NULL,
134						   (const char *) NULL,
135						   (const char *) NULL);
136				  if (ipid < 0)
137				    x = 1;
138				  else
139				    x = ixswait ((unsigned long) ipid,
140						 (const char *) NULL);
141				}
142				*pzenable = zbufalc (sizeof "/dev/"
143						     + strlen (enable_device));
144				sprintf(*pzenable,"/dev/%s", enable_device);
145/*				ulog(LOG_NORMAL,"Enable string is {%s}",*pzenable); */
146				return TRUE;
147			}else{
148				/* device not enabled */
149				return TRUE;
150			}
151		}
152	}
153	return TRUE;	/* no ttys entry found */
154}
155
156/* The following is COHERENT 4.0 specific. It is used to test for any
157 * existing lockfiles on a port which would have been created by init
158 * when a user logs into a port.
159 */
160
161#define LOCKSIG		9	/* Significant Chars of Lockable Resources.  */
162#define LOKFLEN		64	/* Max Length of UUCP Lock File Name.	     */
163
164#define	LOCKPRE	"LCK.."
165#define PIDLEN	6	/* Maximum length of string representing a pid.  */
166
167#ifndef LOCKDIR
168#define LOCKDIR SPOOLDIR
169#endif
170
171/* There is a special version of DEVMASK for the PE multiport driver
172 * because of the peculiar way it uses the minor device number.  For
173 * all other drivers, the lower 5 bits describe the physical port--
174 * the upper 3 bits give attributes for the port.
175 */
176
177#define PE_DRIVER 21	/* Major device number for the PE driver.  */
178#define PE_DEVMASK 0x3f	/* PE driver minor device mask.  */
179#define DEVMASK 0x1f	/* Minor device mask.  */
180
181/*
182 * Generates a resource name for locking, based on the major number
183 * and the lower 4 bits of the minor number of the tty device.
184 *
185 * Builds the name in buff as two "." separated decimal numbers.
186 * Returns NULL on failure, buff on success.
187 */
188static char *
189gen_res_name(path, buff)
190char *path;
191char *buff;
192{
193	struct stat sbuf;
194	int status;
195
196	if (0 != (status = stat(path, &sbuf))) {
197		/* Can't stat the file.  */
198		return (NULL);
199	}
200
201	if (PE_DRIVER == major(sbuf.st_rdev)) {
202		sprintf(buff, "%d.%d", major(sbuf.st_rdev),
203				       PE_DEVMASK & minor(sbuf.st_rdev));
204	} else {
205		sprintf(buff, "%d.%d", major(sbuf.st_rdev),
206				       DEVMASK & minor(sbuf.st_rdev));
207	}
208
209	return(buff);
210} /* gen_res_name */
211
212/*
213 *  lockexist(resource)  char *resource;
214 *
215 *  Test for existance of a lock on the given resource.
216 *
217 *  Returns:  (1)  Resource is locked.
218 *	      (0)  Resource is not locked.
219 */
220
221static boolean
222lockexist(resource)
223const char	*resource;
224{
225	char lockfn[LOKFLEN];
226
227	if ( resource == NULL )
228		return(0);
229	sprintf(lockfn, "%s/%s%.*s", LOCKDIR, LOCKPRE, LOCKSIG, resource);
230
231	return (!access(lockfn, AEXISTS));
232} /* lockexist() */
233
234/*
235 *  lockttyexist(ttyname)  char *ttyname;
236 *
237 *  Test for existance of a lock on the given tty.
238 *
239 *  Returns:  (1)  Resource is locked.
240 *	      (0)  Resource is not locked.
241 */
242boolean
243lockttyexist(ttyn)
244const char *ttyn;
245{
246	char resource[LOKFLEN];
247	char filename[LOKFLEN];
248
249	sprintf(filename, "/dev/%s", ttyn);
250	if (NULL == gen_res_name(filename, resource)){
251		return(0);	/* Non-existent tty can not be locked :-) */
252	}
253
254	return(lockexist(resource));
255} /* lockttyexist() */
256
257#endif /* HAVE_COHERENT_LOCKFILES */
258