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