1 #ifndef lint
2 static char sccsid[] = "@(#)acucntrl.c	5.15	(Berkeley) 05/04/88";
3 #endif
4 
5 /*  acucntrl - turn around tty line between dialin and dialout
6  *
7  * Usage:	acucntrl {enable,disable} /dev/ttydX
8  *
9  * History:
10  *	First written by Allan Wilkes (fisher!allan)
11  *
12  *	Modified June 8,1983 by W.Sebok (astrovax!wls) to poke kernel rather
13  * 	than use kernel hack to turn on/off modem control, using subroutine
14  *	stolen from program written by Tsutomu Shimomura
15  *	{astrovax,escher}!tsutomu
16  *
17  *	Worked over many times by W.Sebok (i.e. hacked to death)
18  *
19  * Operation:
20  *   disable (i.e. setup for dialing out)
21  *	(1) check input arguments
22  *	(2) look in /etc/utmp to check that the line is not in use by another
23  *	(3) disable modem control on terminal
24  *	(4) check for carrier on device
25  *	(5) change owner of device to real id
26  *	(6) edit /etc/ttys,  changing the first character of the appropriate
27  *	    line to 0
28  *	(7) send a hangup to process 1 to poke init to disable getty
29  *	(8) post uid name in capitals in /etc/utmp to let world know device has
30  *	    been grabbed
31  *	(9) make sure that DTR is on
32  *
33  *   enable (i.e.) restore for dialin
34  *	(1) check input arguments
35  *	(2) look in /etc/utmp to check that the line is not in use by another
36  *	(3) make sure modem control on terminal is disabled
37  *	(4) turn off DTR to make sure line is hung up
38  *	(5) condition line: clear exclusive use and set hangup on close modes
39  *	(6) turn on modem control
40  *	(7) edit /etc/ttys,  changing the first character of the appropriate
41  *	    line to 1
42  *	(8) send a hangup to process 1 to poke init to enable getty
43  *	(9) clear uid name for /etc/utmp
44  */
45 
46 /* #define SENSECARRIER */
47 
48 #include "uucp.h"
49 #ifdef DIALINOUT
50 #include <sys/buf.h>
51 #include <signal.h>
52 #include <sys/conf.h>
53 #ifdef vax
54 #ifdef BSD4_2
55 #include <vaxuba/ubavar.h>
56 #else
57 #include <sys/ubavar.h>
58 #endif
59 #endif /* vax */
60 #include <sys/stat.h>
61 #include <nlist.h>
62 #include <sgtty.h>
63 #include <utmp.h>
64 #include <pwd.h>
65 #include <stdio.h>
66 #include <sys/file.h>
67 
68 #define NDZLINE	8	/* lines/dz */
69 #define NDHLINE	16	/* lines/dh */
70 #define NDMFLINE 8	/* lines/dmf */
71 
72 #define DZ11	1
73 #define DH11	2
74 #define DMF	3
75 
76 #define NLVALUE(val)	(nl[val].n_value)
77 
78 struct nlist nl[] = {
79 #define CDEVSW	0
80 	{ "_cdevsw" },
81 
82 #define DZOPEN	1
83 	{ "_dzopen" },
84 #define DZINFO	2
85 	{ "_dzinfo" },
86 #define NDZ11	3
87 	{ "_dz_cnt" },
88 #define DZSCAR	4
89 	{ "_dzsoftCAR" },
90 
91 #define DHOPEN	5
92 	{ "_dhopen" },
93 #define DHINFO	6
94 	{ "_dhinfo" },
95 #define NDH11	7
96 	{ "_ndh11" },
97 #define DHSCAR	8
98 	{ "_dhsoftCAR" },
99 
100 #define DMFOPEN	9
101 	{ "_dmfopen" },
102 #define DMFINFO	10
103 	{ "_dmfinfo" },
104 #define NDMF	11
105 	{ "_ndmf" },
106 #define DMFSCAR	12
107 	{ "_dmfsoftCAR" },
108 
109 	{ "\0" }
110 };
111 
112 #define ENABLE	1
113 #define DISABLE	0
114 
115 char Etcutmp[] = "/etc/utmp";
116 char Etcttys[] = "/etc/ttys";
117 #ifdef BSD4_3
118 FILE *ttysfile, *nttysfile;
119 char NEtcttys[] = "/etc/ttys.new";
120 extern long ftell();
121 #endif BSD4_3
122 char Devhome[] = "/dev";
123 
124 char usage[] = "Usage: acucntrl {dis|en}able ttydX\n";
125 
126 struct utmp utmp;
127 char resettty, resetmodem;
128 int etcutmp;
129 off_t utmploc;
130 off_t ttyslnbeg;
131 extern int errno;
132 extern char *sys_errlist[];
133 off_t lseek();
134 
135 #define NAMSIZ	sizeof(utmp.ut_name)
136 #define	LINSIZ	sizeof(utmp.ut_line)
137 
138 main(argc, argv)
139 int argc; char *argv[];
140 {
141 	register char *p;
142 	register int i;
143 	char uname[NAMSIZ], Uname[NAMSIZ];
144 	int enable ;
145 	char *device;
146 	int devfile;
147 	int uid, gid;
148 	struct passwd *getpwuid();
149 	char *rindex();
150 
151 	/* check input arguments */
152 	if (argc!=3 && argc != 4) {
153 		fprintf(stderr, usage);
154 		exit(1);
155 	}
156 
157 	/* interpret command type */
158 	if (prefix(argv[1], "disable")  || strcmp(argv[1], "dialout")==0)
159 		enable = 0;
160 	else if (prefix(argv[1], "enable")  || strcmp(argv[1], "dialin")==0)
161 		enable = 1;
162 	else {
163 		fprintf(stderr, usage);
164 		exit(1);
165 	}
166 
167 	device = rindex(argv[2], '/');
168 	device = (device == NULL) ? argv[2]: device+1;
169 
170 	opnttys(device);
171 
172 #ifdef vax
173 	/* Get nlist info */
174 	nlist("/vmunix", nl);
175 #endif vax
176 
177 	/* Chdir to /dev */
178 	if(chdir(Devhome) < 0) {
179 		fprintf(stderr, "Cannot chdir to %s: %s\r\n",
180 			Devhome, sys_errlist[errno]);
181 		exit(1);
182 	}
183 
184 	/* Get uid information */
185 	uid = getuid();
186 	gid = getgid();
187 
188 	p = getpwuid(uid)->pw_name;
189 	if (p==NULL) {
190 		fprintf(stderr, "cannot get uid name\n");
191 		exit(1);
192 	}
193 
194 	if (strcmp(p, "uucp") == 0 && argc == 4)
195 		p = argv[3];
196 
197 	/*  to upper case */
198 	i = 0;
199 	do {
200 		uname[i] = *p;
201 		Uname[i++] = (*p>='a' && *p<='z') ? (*p - ('a'-'A')) : *p;
202 	} while (*p++ && i<NAMSIZ);
203 
204 	/* check to see if line is being used */
205 	if( (etcutmp = open(Etcutmp, 2)) < 0) {
206 		fprintf(stderr, "On open %s open: %s\n",
207 			Etcutmp, sys_errlist[errno]);
208 		exit(1);
209 	}
210 
211 	(void)lseek(etcutmp, utmploc, 0);
212 
213 	i = read(etcutmp, (char *)&utmp, sizeof(struct utmp));
214 
215 	if(
216 		i == sizeof(struct utmp) &&
217 		utmp.ut_line[0] != '\0'  &&
218 		utmp.ut_name[0] != '\0'  &&
219 		(
220 			!upcase(utmp.ut_name, NAMSIZ) ||
221 			(
222 				uid != 0 &&
223 				strncmp(utmp.ut_name, Uname, NAMSIZ) != 0
224 			)
225 		)
226 	) {
227 		fprintf(stderr, "%s in use by %s\n", device, utmp.ut_name);
228 		exit(2);
229 	}
230 
231 #ifndef sequent
232 	/* Disable modem control */
233 	if (setmodem(device, DISABLE) < 0) {
234 		fprintf(stderr, "Unable to disable modem control\n");
235 		exit(1);
236 	}
237 #endif !sequent
238 
239 	if (enable) {
240 #ifdef sequent
241 		if (setmodem(device, ENABLE) < 0) {
242 			fprintf(stderr, "Cannot Enable modem control\n");
243 			(void)setmodem(device, i);
244 			exit(1);
245 		}
246 #endif sequent
247 #ifndef sequent
248 		if((devfile = open(device, 1)) < 0) {
249 			fprintf(stderr, "On open of %s: %s\n",
250 				device, sys_errlist[errno]);
251 			(void)setmodem(device, resetmodem);
252 			exit(1);
253 		}
254 		/* Try one last time to hang up */
255 		if (ioctl(devfile, (int)TIOCCDTR, (char *)0) < 0)
256 			fprintf(stderr, "On TIOCCDTR ioctl: %s\n",
257 				sys_errlist[errno]);
258 
259 		if (ioctl(devfile, (int)TIOCNXCL, (char *)0) < 0)
260 			fprintf(stderr,
261 			    "Cannot clear Exclusive Use on %s: %s\n",
262 				device, sys_errlist[errno]);
263 
264 		if (ioctl(devfile, (int)TIOCHPCL, (char *)0) < 0)
265 			fprintf(stderr,
266 			    "Cannot set hangup on close on %s: %s\n",
267 				device, sys_errlist[errno]);
268 
269 #endif !sequent
270 		i = resetmodem;
271 
272 #ifndef sequent
273 		if (setmodem(device, ENABLE) < 0) {
274 			fprintf(stderr, "Cannot Enable modem control\n");
275 			(void)setmodem(device, i);
276 			exit(1);
277 		}
278 #endif sequent
279 		resetmodem=i;
280 
281 		if (settys(ENABLE)) {
282 			fprintf(stderr, "%s already enabled\n", device);
283 		} else {
284 			pokeinit(device, Uname, enable);
285 		}
286 		post(device, "");
287 
288 	} else {
289 #if defined(TIOCMGET) && defined(SENSECARRIER)
290 		if (uid!=0) {
291 			int linestat = 0;
292 
293 			/* check for presence of carrier */
294 			sleep(2); /* need time after modem control turnoff */
295 
296 			if((devfile = open(device, 1)) < 0) {
297 				fprintf(stderr, "On open of %s: %s\n",
298 					device, sys_errlist[errno]);
299 				(void)setmodem(device, resetmodem);
300 				exit(1);
301 			}
302 
303 			(void)ioctl(devfile, TIOCMGET, &linestat);
304 
305 			if (linestat&TIOCM_CAR) {
306 				fprintf(stderr, "%s is in use (Carrier On)\n",
307 					device);
308 				(void)setmodem(device, resetmodem);
309 				exit(2);
310 			}
311 			(void)close(devfile);
312 		}
313 #endif TIOCMGET
314 		/* chown device */
315 		if(chown(device, uid, gid) < 0)
316 			fprintf(stderr, "Cannot chown %s: %s\n",
317 				device, sys_errlist[errno]);
318 
319 
320 		/* poke init */
321 		if(settys(DISABLE)) {
322 			fprintf(stderr, "%s already disabled\n", device);
323 		} else {
324 			pokeinit(device, Uname, enable);
325 		}
326 		post(device, Uname);
327 #ifdef sequent
328 	/* Disable modem control */
329 	if (setmodem(device, DISABLE) < 0) {
330 		fprintf(stderr, "Unable to disable modem control\n");
331 		exit(1);
332 	}
333 #endif sequent
334 		if((devfile = open(device, O_RDWR|O_NDELAY)) < 0) {
335 			fprintf(stderr, "On %s open: %s\n",
336 				device, sys_errlist[errno]);
337 		} else {
338 			if(ioctl(devfile, (int)TIOCSDTR, (char *)0) < 0)
339 				fprintf(stderr,
340 				    "Cannot set DTR on %s: %s\n",
341 					device, sys_errlist[errno]);
342 		}
343 	}
344 
345 	exit(0);
346 }
347 
348 /* return true if no lower case */
349 upcase(str, len)
350 register char *str;
351 register int len;
352 {
353 	for (; *str, --len >= 0 ; str++)
354 		if (*str>='a' && *str<='z')
355 			return(0);
356 	return(1);
357 }
358 
359 /* Post name to public */
360 post(device, name)
361 char *device, *name;
362 {
363 	(void)time((time_t *)&utmp.ut_time);
364 	strncpy(utmp.ut_line, device, LINSIZ);
365 	strncpy(utmp.ut_name, name,  NAMSIZ);
366 	if (lseek(etcutmp, utmploc, 0) < 0)
367 		fprintf(stderr, "on lseek in /etc/utmp: %s",
368 			sys_errlist[errno]);
369 	if (write(etcutmp, (char *)&utmp, sizeof(utmp)) < 0)
370 		fprintf(stderr, "on write in /etc/utmp: %s",
371 			sys_errlist[errno]);
372 }
373 
374 /* poke process 1 and wait for it to do its thing */
375 pokeinit(device, uname, enable)
376 char *uname, *device; int enable;
377 {
378 	struct utmp utmp;
379 	register int i;
380 
381 	post(device, uname);
382 
383 	/* poke init */
384 	if (kill(1, SIGHUP)) {
385 		fprintf(stderr,
386 		    "Cannot send hangup to init process: %s\n",
387 			sys_errlist[errno]);
388 		(void)settys(resettty);
389 		(void)setmodem(device, resetmodem);
390 		exit(1);
391 	}
392 
393 	if (enable)
394 		return;
395 
396 	/* wait till init has responded, clearing the utmp entry */
397 	i = 100;
398 	do {
399 		sleep(1);
400 		if (lseek(etcutmp, utmploc, 0) < 0)
401 			fprintf(stderr, "On lseek in /etc/utmp: %s",
402 				sys_errlist[errno]);
403 		if (read(etcutmp, (char *)&utmp, sizeof utmp) < 0)
404 			fprintf(stderr, "On read from /etc/utmp: %s",
405 				sys_errlist[errno]);
406 	} while (utmp.ut_name[0] != '\0' && --i > 0);
407 }
408 
409 #ifdef BSD4_3
410 /* identify terminal line in ttys */
411 opnttys(device)
412 char *device;
413 {
414 	register int  ndevice;
415 	register char *p;
416 	char *index();
417 	char linebuf[BUFSIZ];
418 
419 	ttysfile = NULL;
420 	do {
421 		if (ttysfile != NULL) {
422 			fclose(ttysfile);
423 			sleep(5);
424 		}
425 		ttysfile = fopen(Etcttys, "r");
426 		if(ttysfile == NULL) {
427 			fprintf(stderr, "Cannot open %s: %s\n", Etcttys,
428 				sys_errlist[errno]);
429 			exit(1);
430 		}
431 	} while (flock(fileno(ttysfile), LOCK_NB|LOCK_EX) < 0);
432 	nttysfile = fopen(NEtcttys, "w");
433 	if(nttysfile == NULL) {
434 		fprintf(stderr, "Cannot open %s: %s\n", Etcttys,
435 			sys_errlist[errno]);
436 		exit(1);
437 	}
438 
439 	ndevice = strlen(device);
440 #ifndef BRL4_2
441 	utmploc = sizeof(utmp);
442 #else BRL4_2
443 	utmploc = 0;
444 #endif BRL4_2
445 
446 	while(fgets(linebuf, sizeof(linebuf) - 1, ttysfile) != NULL) {
447 		if(strncmp(device, linebuf, ndevice) == 0)
448 			return;
449 		ttyslnbeg += strlen(linebuf);
450 		if (linebuf[0] != '#' && linebuf[0] != '\0')
451 			utmploc += sizeof(utmp);
452 		if (fputs(linebuf, nttysfile) == NULL) {
453 			fprintf(stderr, "On %s write: %s\n",
454 				Etcttys, sys_errlist[errno]);
455 			exit(1);
456 		}
457 
458 	}
459 	fprintf(stderr, "%s not found in %s\n", device, Etcttys);
460 	exit(1);
461 }
462 
463 /* modify appropriate line in /etc/ttys to turn on/off the device */
464 settys(enable)
465 int enable;
466 {
467 	register char *cp, *cp2;
468 	char lbuf[BUFSIZ];
469 	int i;
470 	char c1, c2;
471 
472 	(void) fseek(ttysfile, ttyslnbeg, 0);
473 	if(fgets(lbuf, BUFSIZ, ttysfile) == NULL) {
474 		fprintf(stderr, "On %s read: %s\n",
475 			Etcttys, sys_errlist[errno]);
476 		exit(1);
477 	}
478 	/* format is now */
479 	/* ttyd0 std.100 dialup on secure # comment */
480 	/* except, 2nd item may have embedded spaces inside quotes, Hubert */
481 	cp = lbuf;
482 	for (i=0;*cp && i<3;i++) {
483 		if (*cp == '"') {
484 			cp++;
485 			while (*cp && *cp != '"')
486 				cp++;
487 			if (*cp != '\0')
488 				cp++;
489 		}else {
490 			while (*cp && *cp != ' ' && *cp != '\t')
491 				cp++;
492 		}
493 		while (*cp && (*cp == ' ' || *cp == '\t'))
494 			cp++;
495 	}
496 	if (*cp == '\0') {
497 		fprintf(stderr,"Badly formatted line in /etc/ttys:\n%s", lbuf);
498 		exit(1);
499 	}
500 	c1 = *--cp;
501 	*cp++ = '\0';
502 	cp2 = cp;
503 	while (*cp && *cp != ' ' && *cp != '\t' && *cp != '\n')
504 		cp++;
505 	if (*cp == '\0') {
506 		fprintf(stderr,"Badly formatted line in /etc/ttys:\n%s", lbuf);
507 		exit(1);
508 	}
509 	c2 = *cp;
510 	*cp++ = '\0';
511 	while (*cp && (*cp == ' ' || *cp == '\t'))
512 		cp++;
513 	resettty = strcmp("on", cp2) != 0;
514 	fprintf(nttysfile,"%s%c%s%c%s", lbuf, c1, enable ? "on" : "off", c2, cp);
515 	if (ferror(nttysfile)) {
516 		fprintf(stderr, "On %s fprintf: %s\n",
517 			NEtcttys, sys_errlist[errno]);
518 		exit(1);
519 	}
520 	while(fgets(lbuf, sizeof(lbuf) - 1, ttysfile) != NULL) {
521 		if (fputs(lbuf, nttysfile) == NULL) {
522 			fprintf(stderr, "On %s write: %s\n",
523 				NEtcttys, sys_errlist[errno]);
524 			exit(1);
525 		}
526 	}
527 
528 	if (enable^resettty)
529 		(void) unlink(NEtcttys);
530 	else {
531 		struct stat statb;
532 		if (stat(Etcttys, &statb) == 0) {
533 			fchmod(fileno(nttysfile) ,statb.st_mode);
534 			fchown(fileno(nttysfile), statb.st_uid, statb.st_gid);
535 		}
536 		(void) rename(NEtcttys, Etcttys);
537 	}
538 	(void) fclose(nttysfile);
539 	(void) fclose(ttysfile);
540 	return enable^resettty;
541 }
542 
543 #else !BSD4_3
544 
545 /* identify terminal line in ttys */
546 opnttys(device)
547 char *device;
548 {
549 	register FILE *ttysfile;
550 	register int  ndevice, lnsiz;
551 	register char *p;
552 	char *index();
553 	char linebuf[BUFSIZ];
554 
555 	ttysfile = fopen(Etcttys, "r");
556 	if(ttysfile == NULL) {
557 		fprintf(stderr, "Cannot open %s: %s\n", Etcttys,
558 			sys_errlist[errno]);
559 		exit(1);
560 	}
561 
562 	ndevice = strlen(device);
563 	ttyslnbeg = 0;
564 	utmploc = 0;
565 
566 	while(fgets(linebuf, sizeof(linebuf) - 1, ttysfile) != NULL) {
567 		lnsiz = strlen(linebuf);
568 		if ((p = index(linebuf, '\n')) != NULL)
569 			*p = '\0';
570 		if(strncmp(device, &linebuf[2], ndevice) == 0) {
571 			(void)fclose(ttysfile);
572 #ifdef sequent
573 			/* Why is the sequent off by one? */
574 			utmploc += sizeof(utmp);
575 #endif sequent
576 			return;
577 		}
578 		ttyslnbeg += lnsiz;
579 		utmploc += sizeof(utmp);
580 	}
581 	fprintf(stderr, "%s not found in %s\n", device, Etcttys);
582 	exit(1);
583 }
584 
585 /* modify appropriate line in /etc/ttys to turn on/off the device */
586 settys(enable)
587 int enable;
588 {
589 	int ittysfil;
590 	char out, in;
591 
592 	ittysfil = open(Etcttys, 2);
593 	if(ittysfil < 0) {
594 		fprintf(stderr, "Cannot open %s for output: %s\n",
595 			Etcttys, sys_errlist[errno]);
596 		exit(1);
597 	}
598 	(void)lseek(ittysfil, ttyslnbeg, 0);
599 	if(read(ittysfil, &in, 1)<0) {
600 		fprintf(stderr, "On %s write: %s\n",
601 			Etcttys, sys_errlist[errno]);
602 		exit(1);
603 	}
604 	resettty = (in == '1');
605 	out = enable ? '1' : '0';
606 	(void)lseek(ittysfil, ttyslnbeg, 0);
607 	if(write(ittysfil, &out, 1)<0) {
608 		fprintf(stderr, "On %s write: %s\n",
609 			Etcttys, sys_errlist[errno]);
610 		exit(1);
611 	}
612 	(void)close(ittysfil);
613 	return(in==out);
614 }
615 #endif !BSD4_3
616 
617 #ifdef sequent
618 setmodem(ttyline, enable)
619 char *ttyline; int enable;
620 {
621 	char *sysbuf[BUFSIZ];
622 	sprintf(sysbuf,"/etc/ttyconfig /dev/%s -special %s", ttyline,
623 		enable ? "-carrier" : "-nocarrier");
624 	system(sysbuf);
625 }
626 #endif /* sequent */
627 #ifdef vax
628 /*
629  * Excerpted from (June 8, 1983 W.Sebok)
630  * > ttymodem.c - enable/disable modem control for tty lines.
631  * >
632  * > Knows about DZ11s and DH11/DM11s.
633  * > 23.3.83 - TS
634  * > modified to know about DMF's  (hasn't been tested) Nov 8, 1984 - WLS
635  */
636 
637 
638 setmodem(ttyline, enable)
639 char *ttyline; int enable;
640 {
641 	dev_t dev;
642 	int kmem;
643 	int unit, line, nlines, addr, tflags;
644 	int devtype=0;
645 	char cflags; short sflags;
646 #ifdef BSD4_2
647 	int flags;
648 #else
649 	short flags;
650 #endif
651 	struct uba_device *ubinfo;
652 	struct stat statb;
653 	struct cdevsw cdevsw;
654 
655 	if(nl[CDEVSW].n_type == 0) {
656 		fprintf(stderr, "No namelist.\n");
657 		return(-1);
658 	}
659 
660 	if((kmem = open("/dev/kmem", 2)) < 0) {
661 		fprintf(stderr, "/dev/kmem open: %s\n", sys_errlist[errno]);
662 		return(-1);
663 	}
664 
665 	if(stat(ttyline, &statb) < 0) {
666 		fprintf(stderr, "%s stat: %s\n", ttyline, sys_errlist[errno]);
667 		return(-1);
668 	}
669 
670 	if((statb.st_mode&S_IFMT) != S_IFCHR) {
671 		fprintf(stderr, "%s is not a character device.\n",ttyline);
672 		return(-1);
673 	}
674 
675 	dev = statb.st_rdev;
676 	(void)lseek(kmem,
677 		(off_t) &(((struct cdevsw *)NLVALUE(CDEVSW))[major(dev)]),0);
678 	(void)read(kmem, (char *) &cdevsw, sizeof cdevsw);
679 
680 	if((int)(cdevsw.d_open) == NLVALUE(DZOPEN)) {
681 		devtype = DZ11;
682 		unit = minor(dev) / NDZLINE;
683 		line = minor(dev) % NDZLINE;
684 		addr = (int) &(((int *)NLVALUE(DZINFO))[unit]);
685 		(void)lseek(kmem, (off_t) NLVALUE(NDZ11), 0);
686 	} else if((int)(cdevsw.d_open) == NLVALUE(DHOPEN)) {
687 		devtype = DH11;
688 		unit = minor(dev) / NDHLINE;
689 		line = minor(dev) % NDHLINE;
690 		addr = (int) &(((int *)NLVALUE(DHINFO))[unit]);
691 		(void)lseek(kmem, (off_t) NLVALUE(NDH11), 0);
692 	} else if((int)(cdevsw.d_open) == NLVALUE(DMFOPEN)) {
693 		devtype = DMF;
694 		unit = minor(dev) / NDMFLINE;
695 		line = minor(dev) % NDMFLINE;
696 		addr = (int) &(((int *)NLVALUE(DMFINFO))[unit]);
697 		(void)lseek(kmem, (off_t) NLVALUE(NDMF), 0);
698 	} else {
699 		fprintf(stderr, "Device %s (%d/%d) unknown.\n", ttyline,
700 		    major(dev), minor(dev));
701 		return(-1);
702 	}
703 
704 	(void)read(kmem, (char *) &nlines, sizeof nlines);
705 	if(minor(dev) >= nlines) {
706 		fprintf(stderr, "Sub-device %d does not exist (only %d).\n",
707 		    minor(dev), nlines);
708 		return(-1);
709 	}
710 
711 	(void)lseek(kmem, (off_t)addr, 0);
712 	(void)read(kmem, (char *) &ubinfo, sizeof ubinfo);
713 	(void)lseek(kmem, (off_t) &(ubinfo->ui_flags), 0);
714 	(void)read(kmem, (char *) &flags, sizeof flags);
715 
716 	tflags = 1<<line;
717 	resetmodem = ((flags&tflags) == 0);
718 	flags = enable ? (flags & ~tflags) : (flags | tflags);
719 	(void)lseek(kmem, (off_t) &(ubinfo->ui_flags), 0);
720 	(void)write(kmem, (char *) &flags, sizeof flags);
721 	switch(devtype) {
722 		case DZ11:
723 			if((addr = NLVALUE(DZSCAR)) == 0) {
724 				fprintf(stderr, "No dzsoftCAR.\n");
725 				return(-1);
726 			}
727 			cflags = flags;
728 			(void)lseek(kmem, (off_t) &(((char *)addr)[unit]), 0);
729 			(void)write(kmem, (char *) &cflags, sizeof cflags);
730 			break;
731 		case DH11:
732 			if((addr = NLVALUE(DHSCAR)) == 0) {
733 				fprintf(stderr, "No dhsoftCAR.\n");
734 				return(-1);
735 			}
736 			sflags = flags;
737 			(void)lseek(kmem, (off_t) &(((short *)addr)[unit]), 0);
738 			(void)write(kmem, (char *) &sflags, sizeof sflags);
739 			break;
740 		case DMF:
741 			if((addr = NLVALUE(DMFSCAR)) == 0) {
742 				fprintf(stderr, "No dmfsoftCAR.\n");
743 				return(-1);
744 			}
745 			cflags = flags;
746 			(void)lseek(kmem, (off_t) &(((char *)addr)[unit]), 0);
747 			(void)write(kmem, (char *) &cflags, sizeof cflags);
748 			break;
749 		default:
750 			fprintf(stderr, "Unknown device type\n");
751 			return(-1);
752 	}
753 	return(0);
754 }
755 #endif /* vax */
756 
757 prefix(s1, s2)
758 	register char *s1, *s2;
759 {
760 	register char c;
761 
762 	while ((c = *s1++) == *s2++)
763 		if (c == '\0')
764 			return (1);
765 	return (c == '\0');
766 }
767 #else	/* !DIALINOUT */
768 main()
769 {
770 	fprintf(stderr,"acucntrl is not supported on this system\n");
771 }
772 #endif /* !DIALINOUT */
773