static char sccsid
[] = "@(#)acucntrl.c 5.15 (Berkeley) %G%";
/* acucntrl - turn around tty line between dialin and dialout
* Usage: acucntrl {enable,disable} /dev/ttydX
* First written by Allan Wilkes (fisher!allan)
* Modified June 8,1983 by W.Sebok (astrovax!wls) to poke kernel rather
* than use kernel hack to turn on/off modem control, using subroutine
* stolen from program written by Tsutomu Shimomura
* {astrovax,escher}!tsutomu
* Worked over many times by W.Sebok (i.e. hacked to death)
* disable (i.e. setup for dialing out)
* (1) check input arguments
* (2) look in /etc/utmp to check that the line is not in use by another
* (3) disable modem control on terminal
* (4) check for carrier on device
* (5) change owner of device to real id
* (6) edit /etc/ttys, changing the first character of the appropriate
* (7) send a hangup to process 1 to poke init to disable getty
* (8) post uid name in capitals in /etc/utmp to let world know device has
* (9) make sure that DTR is on
* enable (i.e.) restore for dialin
* (1) check input arguments
* (2) look in /etc/utmp to check that the line is not in use by another
* (3) make sure modem control on terminal is disabled
* (4) turn off DTR to make sure line is hung up
* (5) condition line: clear exclusive use and set hangup on close modes
* (6) turn on modem control
* (7) edit /etc/ttys, changing the first character of the appropriate
* (8) send a hangup to process 1 to poke init to enable getty
* (9) clear uid name for /etc/utmp
/* #define SENSECARRIER */
#include <vaxuba/ubavar.h>
#define NDZLINE 8 /* lines/dz */
#define NDHLINE 16 /* lines/dh */
#define NDMFLINE 8 /* lines/dmf */
#define NLVALUE(val) (nl[val].n_value)
char Etcutmp
[] = "/etc/utmp";
char Etcttys
[] = "/etc/ttys";
FILE *ttysfile
, *nttysfile
;
char NEtcttys
[] = "/etc/ttys.new";
char usage
[] = "Usage: acucntrl {dis|en}able ttydX\n";
char resettty
, resetmodem
;
extern char *sys_errlist
[];
#define NAMSIZ sizeof(utmp.ut_name)
#define LINSIZ sizeof(utmp.ut_line)
char uname
[NAMSIZ
], Uname
[NAMSIZ
];
struct passwd
*getpwuid();
/* check input arguments */
if (argc
!=3 && argc
!= 4) {
/* interpret command type */
if (prefix(argv
[1], "disable") || strcmp(argv
[1], "dialout")==0)
else if (prefix(argv
[1], "enable") || strcmp(argv
[1], "dialin")==0)
device
= rindex(argv
[2], '/');
device
= (device
== NULL
) ? argv
[2]: device
+1;
fprintf(stderr
, "Cannot chdir to %s: %s\r\n",
Devhome
, sys_errlist
[errno
]);
/* Get uid information */
p
= getpwuid(uid
)->pw_name
;
fprintf(stderr
, "cannot get uid name\n");
if (strcmp(p
, "uucp") == 0 && argc
== 4)
Uname
[i
++] = (*p
>='a' && *p
<='z') ? (*p
- ('a'-'A')) : *p
;
} while (*p
++ && i
<NAMSIZ
);
/* check to see if line is being used */
if( (etcutmp
= open(Etcutmp
, 2)) < 0) {
fprintf(stderr
, "On open %s open: %s\n",
Etcutmp
, sys_errlist
[errno
]);
(void)lseek(etcutmp
, utmploc
, 0);
i
= read(etcutmp
, (char *)&utmp
, sizeof(struct utmp
));
i
== sizeof(struct utmp
) &&
utmp
.ut_line
[0] != '\0' &&
utmp
.ut_name
[0] != '\0' &&
!upcase(utmp
.ut_name
, NAMSIZ
) ||
strncmp(utmp
.ut_name
, Uname
, NAMSIZ
) != 0
fprintf(stderr
, "%s in use by %s\n", device
, utmp
.ut_name
);
/* Disable modem control */
if (setmodem(device
, DISABLE
) < 0) {
fprintf(stderr
, "Unable to disable modem control\n");
if (setmodem(device
, ENABLE
) < 0) {
fprintf(stderr
, "Cannot Enable modem control\n");
(void)setmodem(device
, i
);
if((devfile
= open(device
, 1)) < 0) {
fprintf(stderr
, "On open of %s: %s\n",
device
, sys_errlist
[errno
]);
(void)setmodem(device
, resetmodem
);
/* Try one last time to hang up */
if (ioctl(devfile
, (int)TIOCCDTR
, (char *)0) < 0)
fprintf(stderr
, "On TIOCCDTR ioctl: %s\n",
if (ioctl(devfile
, (int)TIOCNXCL
, (char *)0) < 0)
"Cannot clear Exclusive Use on %s: %s\n",
device
, sys_errlist
[errno
]);
if (ioctl(devfile
, (int)TIOCHPCL
, (char *)0) < 0)
"Cannot set hangup on close on %s: %s\n",
device
, sys_errlist
[errno
]);
if (setmodem(device
, ENABLE
) < 0) {
fprintf(stderr
, "Cannot Enable modem control\n");
(void)setmodem(device
, i
);
fprintf(stderr
, "%s already enabled\n", device
);
pokeinit(device
, Uname
, enable
);
#if defined(TIOCMGET) && defined(SENSECARRIER)
/* check for presence of carrier */
sleep(2); /* need time after modem control turnoff */
if((devfile
= open(device
, 1)) < 0) {
fprintf(stderr
, "On open of %s: %s\n",
device
, sys_errlist
[errno
]);
(void)setmodem(device
, resetmodem
);
(void)ioctl(devfile
, TIOCMGET
, &linestat
);
if (linestat
&TIOCM_CAR
) {
fprintf(stderr
, "%s is in use (Carrier On)\n",
(void)setmodem(device
, resetmodem
);
if(chown(device
, uid
, gid
) < 0)
fprintf(stderr
, "Cannot chown %s: %s\n",
device
, sys_errlist
[errno
]);
fprintf(stderr
, "%s already disabled\n", device
);
pokeinit(device
, Uname
, enable
);
/* Disable modem control */
if (setmodem(device
, DISABLE
) < 0) {
fprintf(stderr
, "Unable to disable modem control\n");
if((devfile
= open(device
, O_RDWR
|O_NDELAY
)) < 0) {
fprintf(stderr
, "On %s open: %s\n",
device
, sys_errlist
[errno
]);
if(ioctl(devfile
, (int)TIOCSDTR
, (char *)0) < 0)
"Cannot set DTR on %s: %s\n",
device
, sys_errlist
[errno
]);
/* return true if no lower case */
for (; *str
, --len
>= 0 ; str
++)
if (*str
>='a' && *str
<='z')
/* Post name to public */
(void)time((time_t *)&utmp
.ut_time
);
strncpy(utmp
.ut_line
, device
, LINSIZ
);
strncpy(utmp
.ut_name
, name
, NAMSIZ
);
if (lseek(etcutmp
, utmploc
, 0) < 0)
fprintf(stderr
, "on lseek in /etc/utmp: %s",
if (write(etcutmp
, (char *)&utmp
, sizeof(utmp
)) < 0)
fprintf(stderr
, "on write in /etc/utmp: %s",
/* poke process 1 and wait for it to do its thing */
pokeinit(device
, uname
, enable
)
char *uname
, *device
; int enable
;
"Cannot send hangup to init process: %s\n",
(void)setmodem(device
, resetmodem
);
/* wait till init has responded, clearing the utmp entry */
if (lseek(etcutmp
, utmploc
, 0) < 0)
fprintf(stderr
, "On lseek in /etc/utmp: %s",
if (read(etcutmp
, (char *)&utmp
, sizeof utmp
) < 0)
fprintf(stderr
, "On read from /etc/utmp: %s",
} while (utmp
.ut_name
[0] != '\0' && --i
> 0);
/* identify terminal line in ttys */
ttysfile
= fopen(Etcttys
, "r");
fprintf(stderr
, "Cannot open %s: %s\n", Etcttys
,
} while (flock(fileno(ttysfile
), LOCK_NB
|LOCK_EX
) < 0);
nttysfile
= fopen(NEtcttys
, "w");
fprintf(stderr
, "Cannot open %s: %s\n", Etcttys
,
ndevice
= strlen(device
);
while(fgets(linebuf
, sizeof(linebuf
) - 1, ttysfile
) != NULL
) {
if(strncmp(device
, linebuf
, ndevice
) == 0)
ttyslnbeg
+= strlen(linebuf
);
if (linebuf
[0] != '#' && linebuf
[0] != '\0')
if (fputs(linebuf
, nttysfile
) == NULL
) {
fprintf(stderr
, "On %s write: %s\n",
Etcttys
, sys_errlist
[errno
]);
fprintf(stderr
, "%s not found in %s\n", device
, Etcttys
);
/* modify appropriate line in /etc/ttys to turn on/off the device */
(void) fseek(ttysfile
, ttyslnbeg
, 0);
if(fgets(lbuf
, BUFSIZ
, ttysfile
) == NULL
) {
fprintf(stderr
, "On %s read: %s\n",
Etcttys
, sys_errlist
[errno
]);
/* ttyd0 std.100 dialup on secure # comment */
/* except, 2nd item may have embedded spaces inside quotes, Hubert */
for (i
=0;*cp
&& i
<3;i
++) {
while (*cp
&& *cp
!= '"')
while (*cp
&& *cp
!= ' ' && *cp
!= '\t')
while (*cp
&& (*cp
== ' ' || *cp
== '\t'))
fprintf(stderr
,"Badly formatted line in /etc/ttys:\n%s", lbuf
);
while (*cp
&& *cp
!= ' ' && *cp
!= '\t' && *cp
!= '\n')
fprintf(stderr
,"Badly formatted line in /etc/ttys:\n%s", lbuf
);
while (*cp
&& (*cp
== ' ' || *cp
== '\t'))
resettty
= strcmp("on", cp2
) != 0;
fprintf(nttysfile
,"%s%c%s%c%s", lbuf
, c1
, enable
? "on" : "off", c2
, cp
);
fprintf(stderr
, "On %s fprintf: %s\n",
NEtcttys
, sys_errlist
[errno
]);
while(fgets(lbuf
, sizeof(lbuf
) - 1, ttysfile
) != NULL
) {
if (fputs(lbuf
, nttysfile
) == NULL
) {
fprintf(stderr
, "On %s write: %s\n",
NEtcttys
, sys_errlist
[errno
]);
if (stat(Etcttys
, &statb
) == 0) {
fchmod(fileno(nttysfile
) ,statb
.st_mode
);
fchown(fileno(nttysfile
), statb
.st_uid
, statb
.st_gid
);
(void) rename(NEtcttys
, Etcttys
);
(void) fclose(nttysfile
);
/* identify terminal line in ttys */
register int ndevice
, lnsiz
;
ttysfile
= fopen(Etcttys
, "r");
fprintf(stderr
, "Cannot open %s: %s\n", Etcttys
,
ndevice
= strlen(device
);
while(fgets(linebuf
, sizeof(linebuf
) - 1, ttysfile
) != NULL
) {
if ((p
= index(linebuf
, '\n')) != NULL
)
if(strncmp(device
, &linebuf
[2], ndevice
) == 0) {
/* Why is the sequent off by one? */
fprintf(stderr
, "%s not found in %s\n", device
, Etcttys
);
/* modify appropriate line in /etc/ttys to turn on/off the device */
ittysfil
= open(Etcttys
, 2);
fprintf(stderr
, "Cannot open %s for output: %s\n",
Etcttys
, sys_errlist
[errno
]);
(void)lseek(ittysfil
, ttyslnbeg
, 0);
if(read(ittysfil
, &in
, 1)<0) {
fprintf(stderr
, "On %s write: %s\n",
Etcttys
, sys_errlist
[errno
]);
out
= enable
? '1' : '0';
(void)lseek(ittysfil
, ttyslnbeg
, 0);
if(write(ittysfil
, &out
, 1)<0) {
fprintf(stderr
, "On %s write: %s\n",
Etcttys
, sys_errlist
[errno
]);
setmodem(ttyline
, enable
)
char *ttyline
; int enable
;
sprintf(sysbuf
,"/etc/ttyconfig /dev/%s -special %s", ttyline
,
enable
? "-carrier" : "-nocarrier");
* Excerpted from (June 8, 1983 W.Sebok)
* > ttymodem.c - enable/disable modem control for tty lines.
* > Knows about DZ11s and DH11/DM11s.
* > modified to know about DMF's (hasn't been tested) Nov 8, 1984 - WLS
setmodem(ttyline
, enable
)
char *ttyline
; int enable
;
int unit
, line
, nlines
, addr
, tflags
;
char cflags
; short sflags
;
struct uba_device
*ubinfo
;
if(nl
[CDEVSW
].n_type
== 0) {
fprintf(stderr
, "No namelist.\n");
if((kmem
= open("/dev/kmem", 2)) < 0) {
fprintf(stderr
, "/dev/kmem open: %s\n", sys_errlist
[errno
]);
if(stat(ttyline
, &statb
) < 0) {
fprintf(stderr
, "%s stat: %s\n", ttyline
, sys_errlist
[errno
]);
if((statb
.st_mode
&S_IFMT
) != S_IFCHR
) {
fprintf(stderr
, "%s is not a character device.\n",ttyline
);
(off_t
) &(((struct cdevsw
*)NLVALUE(CDEVSW
))[major(dev
)]),0);
(void)read(kmem
, (char *) &cdevsw
, sizeof cdevsw
);
if((int)(cdevsw
.d_open
) == NLVALUE(DZOPEN
)) {
unit
= minor(dev
) / NDZLINE
;
line
= minor(dev
) % NDZLINE
;
addr
= (int) &(((int *)NLVALUE(DZINFO
))[unit
]);
(void)lseek(kmem
, (off_t
) NLVALUE(NDZ11
), 0);
} else if((int)(cdevsw
.d_open
) == NLVALUE(DHOPEN
)) {
unit
= minor(dev
) / NDHLINE
;
line
= minor(dev
) % NDHLINE
;
addr
= (int) &(((int *)NLVALUE(DHINFO
))[unit
]);
(void)lseek(kmem
, (off_t
) NLVALUE(NDH11
), 0);
} else if((int)(cdevsw
.d_open
) == NLVALUE(DMFOPEN
)) {
unit
= minor(dev
) / NDMFLINE
;
line
= minor(dev
) % NDMFLINE
;
addr
= (int) &(((int *)NLVALUE(DMFINFO
))[unit
]);
(void)lseek(kmem
, (off_t
) NLVALUE(NDMF
), 0);
fprintf(stderr
, "Device %s (%d/%d) unknown.\n", ttyline
,
(void)read(kmem
, (char *) &nlines
, sizeof nlines
);
if(minor(dev
) >= nlines
) {
fprintf(stderr
, "Sub-device %d does not exist (only %d).\n",
(void)lseek(kmem
, (off_t
)addr
, 0);
(void)read(kmem
, (char *) &ubinfo
, sizeof ubinfo
);
(void)lseek(kmem
, (off_t
) &(ubinfo
->ui_flags
), 0);
(void)read(kmem
, (char *) &flags
, sizeof flags
);
resetmodem
= ((flags
&tflags
) == 0);
flags
= enable
? (flags
& ~tflags
) : (flags
| tflags
);
(void)lseek(kmem
, (off_t
) &(ubinfo
->ui_flags
), 0);
(void)write(kmem
, (char *) &flags
, sizeof flags
);
if((addr
= NLVALUE(DZSCAR
)) == 0) {
fprintf(stderr
, "No dzsoftCAR.\n");
(void)lseek(kmem
, (off_t
) &(((char *)addr
)[unit
]), 0);
(void)write(kmem
, (char *) &cflags
, sizeof cflags
);
if((addr
= NLVALUE(DHSCAR
)) == 0) {
fprintf(stderr
, "No dhsoftCAR.\n");
(void)lseek(kmem
, (off_t
) &(((short *)addr
)[unit
]), 0);
(void)write(kmem
, (char *) &sflags
, sizeof sflags
);
if((addr
= NLVALUE(DMFSCAR
)) == 0) {
fprintf(stderr
, "No dmfsoftCAR.\n");
(void)lseek(kmem
, (off_t
) &(((char *)addr
)[unit
]), 0);
(void)write(kmem
, (char *) &cflags
, sizeof cflags
);
fprintf(stderr
, "Unknown device type\n");
while ((c
= *s1
++) == *s2
++)
fprintf(stderr
,"acucntrl is not supported on this system\n");