252 lines
5.8 KiB
C
252 lines
5.8 KiB
C
|
/* modem - Put modem into DIALIN or DIALOUT mode. Author: F. van Kempen */
|
||
|
|
||
|
/* Exit: 0 OK, suspended/restarted GETTY
|
||
|
* 1 UNIX error
|
||
|
* 2 Process busy
|
||
|
* Version: 1.3 12/30/89
|
||
|
*
|
||
|
* Author: F. van Kempen, MicroWalt Corporation
|
||
|
*
|
||
|
* All fancy stuff removed, see getty.c. Kees J. Bot.
|
||
|
*
|
||
|
*/
|
||
|
|
||
|
#include <stdio.h>
|
||
|
#include <stdlib.h>
|
||
|
#include <sys/types.h>
|
||
|
#include <sys/stat.h>
|
||
|
#include <sys/wait.h>
|
||
|
#include <fcntl.h>
|
||
|
#include <signal.h>
|
||
|
#include <string.h>
|
||
|
#include <unistd.h>
|
||
|
#include <utmp.h>
|
||
|
#include <errno.h>
|
||
|
|
||
|
char PATH_UTMP[] = "/etc/utmp"; /* current logins */
|
||
|
|
||
|
_PROTOTYPE(void usage , (void));
|
||
|
_PROTOTYPE(int main , (int argc , char *argv []));
|
||
|
_PROTOTYPE(void sendcodes , (char *tty, char *codes));
|
||
|
|
||
|
|
||
|
void usage()
|
||
|
{
|
||
|
fprintf(stderr,
|
||
|
"Usage: modem [-sio] [-I in-codes] [-O out-codes] line [command args ...]\n");
|
||
|
exit(1);
|
||
|
}
|
||
|
|
||
|
|
||
|
main(argc, argv)
|
||
|
int argc;
|
||
|
char *argv[];
|
||
|
{
|
||
|
struct utmp entry;
|
||
|
char devtty[1024], *tty;
|
||
|
char **command;
|
||
|
int ex_code = 0;
|
||
|
int fd, i, slot, getty;
|
||
|
struct stat st;
|
||
|
enum { TOGGLE, DIALIN, DIALOUT } mode= TOGGLE;
|
||
|
int silent = 0;
|
||
|
_PROTOTYPE(void (*hsig), (int));
|
||
|
_PROTOTYPE(void (*isig), (int));
|
||
|
_PROTOTYPE(void (*qsig), (int));
|
||
|
_PROTOTYPE(void (*tsig), (int));
|
||
|
pid_t pid;
|
||
|
int r, status;
|
||
|
uid_t uid = getuid();
|
||
|
gid_t gid = getgid();
|
||
|
char *in_codes, *out_codes;
|
||
|
|
||
|
i = 1;
|
||
|
while (i < argc && argv[i][0] == '-') {
|
||
|
char *opt = argv[i++] + 1;
|
||
|
|
||
|
if (opt[0] == '-' && opt[1] == 0) break;
|
||
|
|
||
|
while (*opt != 0) {
|
||
|
switch (*opt++) {
|
||
|
case 's': /* silent mode */
|
||
|
silent = 1;
|
||
|
break;
|
||
|
case 'i': /* DIAL-IN mode: suspend GETTY */
|
||
|
mode = DIALIN;
|
||
|
break;
|
||
|
case 'o': /* DIAL-OUT mode: restart GETTY */
|
||
|
mode = DIALOUT;
|
||
|
break;
|
||
|
case 'I': /* code to switch modem to dial-in */
|
||
|
if (*opt == 0) {
|
||
|
if (i == argc) usage();
|
||
|
opt = argv[i++];
|
||
|
}
|
||
|
in_codes = opt;
|
||
|
opt = "";
|
||
|
break;
|
||
|
case 'O': /* code to switch modem to dial-out */
|
||
|
if (*opt == 0) {
|
||
|
if (i == argc) usage();
|
||
|
opt = argv[i++];
|
||
|
}
|
||
|
out_codes = opt;
|
||
|
opt = "";
|
||
|
break;
|
||
|
default:
|
||
|
usage();
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (i == argc) usage();
|
||
|
tty = argv[i++]; /* Modem line */
|
||
|
|
||
|
if (mode != TOGGLE && i != argc) usage();
|
||
|
command = argv + i; /* Command to execute (if any). */
|
||
|
|
||
|
if (strchr(tty, '/') == NULL) {
|
||
|
strcpy(devtty, "/dev/");
|
||
|
strncat(devtty, tty, 1024 - 6);
|
||
|
tty = devtty;
|
||
|
}
|
||
|
|
||
|
if (stat(tty, &st) < 0) {
|
||
|
fprintf(stderr, "modem: %s: %s\n", tty, strerror(errno));
|
||
|
exit(1);
|
||
|
}
|
||
|
|
||
|
if (!S_ISCHR(st.st_mode)) {
|
||
|
fprintf(stderr, "%s is not a tty\n", tty);
|
||
|
exit(1);
|
||
|
}
|
||
|
|
||
|
/* Find the utmp slot number for the line. */
|
||
|
if ((fd= open(tty, O_RDONLY)) < 0 || (slot= fttyslot(fd)) == 0) {
|
||
|
fprintf(stderr, "modem: %s: %s\n", tty, strerror(errno));
|
||
|
exit(1);
|
||
|
}
|
||
|
close(fd);
|
||
|
|
||
|
/* Read the UTMP file to find out the PID and STATUS of the GETTY. */
|
||
|
entry.ut_type= 0;
|
||
|
if ((fd = open(PATH_UTMP, O_RDONLY)) < 0
|
||
|
|| lseek(fd, (off_t) slot * sizeof(entry), SEEK_SET) < 0
|
||
|
|| read(fd, &entry, sizeof(entry)) < 0
|
||
|
) {
|
||
|
fprintf(stderr, "modem: cannot read UTMP !\n");
|
||
|
exit(1);
|
||
|
}
|
||
|
close(fd);
|
||
|
|
||
|
hsig= signal(SIGHUP, SIG_IGN);
|
||
|
isig= signal(SIGINT, SIG_IGN);
|
||
|
qsig= signal(SIGQUIT, SIG_IGN);
|
||
|
tsig= signal(SIGTERM, SIG_IGN);
|
||
|
|
||
|
/* Process the terminal entry if we got one. */
|
||
|
switch (entry.ut_type) {
|
||
|
case LOGIN_PROCESS: /* getty waiting for a call */
|
||
|
getty = 1;
|
||
|
break;
|
||
|
case USER_PROCESS: /* login or user-shell */
|
||
|
if (!silent) fprintf(stderr, "modem: line is busy.\n");
|
||
|
exit(2);
|
||
|
break;
|
||
|
default:
|
||
|
getty = 0;
|
||
|
}
|
||
|
|
||
|
for (i = (mode == TOGGLE) ? 0 : 1; i < 2; i++) {
|
||
|
/* Now perform the desired action (DIALIN or DIALOUT). */
|
||
|
switch (mode) {
|
||
|
case DIALOUT:
|
||
|
case TOGGLE:
|
||
|
if (getty) kill(entry.ut_pid, SIGUSR1); /* suspend getty */
|
||
|
chown(tty, uid, st.st_gid); /* give line to user */
|
||
|
chmod(tty, 0600);
|
||
|
if (out_codes != NULL) sendcodes(tty, out_codes);
|
||
|
if (!silent) printf("modem on %s set for dialout.\n", tty);
|
||
|
break;
|
||
|
case DIALIN:
|
||
|
if (in_codes != NULL) sendcodes(tty, in_codes);
|
||
|
chown(tty, 0, st.st_gid); /* revoke access */
|
||
|
chmod(tty, 0600);
|
||
|
if (getty) kill(entry.ut_pid, SIGUSR2); /* restart getty */
|
||
|
if (!silent) printf("modem on %s set for dialin.\n", tty);
|
||
|
}
|
||
|
if (mode == TOGGLE) {
|
||
|
/* Start the command to run */
|
||
|
pid_t pid;
|
||
|
int status;
|
||
|
|
||
|
switch ((pid = fork())) {
|
||
|
case -1:
|
||
|
fprintf(stderr, "modem: fork(): %s\n", strerror(errno));
|
||
|
ex_code= 1;
|
||
|
break;
|
||
|
case 0:
|
||
|
setgid(gid);
|
||
|
setuid(uid);
|
||
|
(void) signal(SIGHUP, hsig);
|
||
|
(void) signal(SIGINT, isig);
|
||
|
(void) signal(SIGQUIT, qsig);
|
||
|
(void) signal(SIGTERM, tsig);
|
||
|
execvp(command[0], command);
|
||
|
fprintf(stderr, "modem: %s: %s\n",
|
||
|
command[0], strerror(errno));
|
||
|
_exit(127);
|
||
|
default:
|
||
|
while ((r= wait(&status)) != pid) {
|
||
|
if (r == -1 && errno != EINTR) break;
|
||
|
}
|
||
|
if (r == -1 || status != 0) ex_code = 1;
|
||
|
}
|
||
|
mode = DIALIN;
|
||
|
}
|
||
|
}
|
||
|
exit(ex_code);
|
||
|
}
|
||
|
|
||
|
void sendcodes(tty, codes)
|
||
|
char *tty, *codes;
|
||
|
{
|
||
|
int fd;
|
||
|
int c;
|
||
|
char buf[1024], *bp = buf;
|
||
|
|
||
|
if ((fd = open(tty, O_RDWR|O_NONBLOCK)) < 0) {
|
||
|
fprintf(stderr, "modem: can't send codes to %s: %s\n",
|
||
|
tty, strerror(errno));
|
||
|
return;
|
||
|
}
|
||
|
while ((c = *codes++) != 0) {
|
||
|
fprintf(stderr, "%d\n", __LINE__);
|
||
|
if (c == '\\') {
|
||
|
if ((c = *codes++) == 0) break;
|
||
|
if (c == 'r') c= '\r';
|
||
|
if (c == 'n') c= '\n';
|
||
|
}
|
||
|
*bp++ = c;
|
||
|
if (bp == buf + sizeof(buf) || c == '\r' || c == '\n') {
|
||
|
fprintf(stderr, "%d\n", __LINE__);
|
||
|
write(fd, buf, bp - buf);
|
||
|
fprintf(stderr, "%d\n", __LINE__);
|
||
|
do {sleep(1);
|
||
|
fprintf(stderr, "%d\n", __LINE__);
|
||
|
fprintf(stderr, "%d\n", read(fd, buf, sizeof(buf)));
|
||
|
}while (read(fd, buf, sizeof(buf)) > 0);
|
||
|
fprintf(stderr, "%d\n", __LINE__);
|
||
|
bp = buf;
|
||
|
}
|
||
|
}
|
||
|
if (bp > buf) {
|
||
|
fprintf(stderr, "%d\n", __LINE__);
|
||
|
write(fd, buf, bp - buf);
|
||
|
fprintf(stderr, "%d\n", __LINE__);
|
||
|
do sleep(1); while (read(fd, buf, sizeof(buf)) > 0);
|
||
|
fprintf(stderr, "%d\n", __LINE__);
|
||
|
}
|
||
|
close(fd);
|
||
|
}
|