Path: utzoo!utgpu!cs.utexas.edu!usc!rpi!bu.edu!stanford.edu!rutgers!cs.widener.edu!brendan From: brendan@CS.WIDENER.EDU (Brendan Kehoe) Newsgroups: alt.hackers Subject: Re: TIOCSTI Message-ID: Date: 15 May 91 12:14:46 GMT References: <1991May13.211622.1452@sbcs.sunysb.edu> <1991May15.050257.5547@solbourne.com> Sender: nobody@rutgers.rutgers.edu Distribution: alt Organization: Widener CS Dept Lines: 226 Approved: nobody@rutgers.rutgers.edu kucharsk@solbourne.com writes: > god@csserv2.ic.sunysb.edu writes: >>The TIOCSTI ioctl lets you simulate keyboard input on other peoples terminals >>.. Whoever made this system call goofed. > >Actually the system call can be quite handy I have to agree .. I've found a good number of uses for it. Here's a quick hack I made to let you have nearly an "interactive" connection with their terminal (tho you can't see any of the output, you can put whole lines onto their stdin). It's been invaluable in helping people do things when I'm not there to physically help them. (Hehe, and to cleanly log people out that've been idle for 18 years or more.) -- cut -- /* * force.c - v1.2 - by Brendan Kehoe * * v1.0 - 10/15/90 - force execution of a command on the user's command line * v1.1 - 11/19/90 - allow a pseudo-interactive session, of sorts * v1.2 - 11/20/90 - made the thing error check itself into oblivion * * Usage: force [ -n ] [ -l /dev/ttyxx ] * -n - use this if you don't want the command to echo * -l /dev/ttyxx - the line to hit; use the full name (e.g. /dev/ttyp0) * * Compiles under SunOS 4.1 and Ultrix 3.1D (that I know of). No promises * are made for other OS's or systems. * It won't work under System V Release anything until an alternative * to the TIOCSTI ioctl comes around. (Or you use SVR4, I'm told.) * * (Yes, this requires you be root to use it.) * * You're welcome to do whatever you want with this, as long as you note * its origin somewhere. (Namely "This Was Written By Brendan Kehoe", for * starters.) (A 19-page writeup would be cool, too, but maybe it's too much.) * * Thanks to Richard Stallman for Emacs .. now that I'm finally really using * it to any extent, I'm discovering it's an absolute dream to work in. If * you aren't using it, GET it. (Write me if you don't know how.) */ #include #ifdef sun # include #endif /* sun */ #include /* for stat(2) */ #include /* for stat(2) */ #include #include #if defined(ultrix) # include # define TCGETS TCGETP # define TCSETS TCSANOW #endif /* ultrix */ void push(), devchk(); extern char *optarg; extern int optind; short no_echo = 0; #define USAGE "usage: %s [-n] [-l /dev/ttyxx]\n",*argv #define COMMAND_LIM 100 int main(argc, argv) int argc; char **argv; { int f, cnt; short true = 1, no_cmd = 0; char *device, *buf, *trail, chr; if (argc > 4) { fprintf(stderr, USAGE); exit(1); } if ((device = (char *)malloc(40)) == (char *)NULL) { perror("malloc 1"); exit(1); } if ((buf = (char *)alloca(COMMAND_LIM)) == (char *)NULL) { perror("alloca 1"); exit(1); } while ((chr = getopt(argc, argv, "nl:")) != -1) switch (chr) { case 'n': no_echo = 1; break; case 'l': (void) devchk(optarg, *argv); device = optarg; break; default: fprintf(stderr, USAGE); exit(1); } if (strlen(device) < 2) { printf("Device [form: /dev/ttyxx]: "); fflush(stdout); fgets(device, 39, stdin); /* cut off the trailing return that fgets leaves on */ if ((*device) && (*(trail=(char *)(device + strlen(device) - 1)) == '\n')) *trail = '\0'; if (strlen(device) > 7) (void) devchk(device, *argv); else { fprintf(stderr, "%s: give full name [e.g. /dev/ttyp0].\n", *argv); exit(1); } } printf("Terminate with '-X-' on a line by itself.\n"); while (true) { no_cmd = cnt = 0; chr = *buf = '\0'; printf("Force> "); rewind(stdin); while (((chr=getchar()) != '\n') && (chr != EOF) && (cnt < COMMAND_LIM)) *(buf + cnt++) = chr; if (cnt == COMMAND_LIM) { printf("Limit of %d characters per command line.\n", COMMAND_LIM); no_cmd = 1; } if (chr == EOF) { putc('\n', stdout); exit(0); } if (!no_cmd) { *(buf + cnt) = '\0'; if (!strcmp(buf, "-X-")) true = 0; else if ((*buf != '\n') && (*buf != '\0')) { if ((f = open(device, O_NDELAY | O_RDWR)) < 0) { perror("open"); exit(1); } push(f, buf); close(f); } } } } void push(f, s) int f; char *s; { register int i; char ret='\n'; struct termios termios; if (no_echo) { if (ioctl(f, TCGETS, &termios) < 0) { perror("ioctl 1"); exit(1); } termios.c_lflag &= ~ECHO; if (ioctl(f, TCSETS, &termios) < 0) { perror("ioctl 2"); exit(1); } } if (ioctl(f, TCFLSH, 0) < 0) { /* flush the input queue */ perror("ioctl 3"); exit(1); } for (i = 0; i < strlen(s); i++) /* give 'em the command */ ioctl(f, TIOCSTI, s + i); ioctl(f, TIOCSTI, &ret); /* including a return */ if (no_echo) { ioctl(f, TCGETS, &termios); termios.c_lflag |= ECHO; ioctl(f, TCSETS, &termios); ioctl(f, TCFLSH, 1); /* flush the output queue */ } } void devchk(device, prg) char *device, *prg; { struct stat sb; if (strncmp(device, "/dev/tt", 7) && strncmp(device, "/dev/co", 7)) { fprintf(stderr, "%s: give full name [e.g. /dev/ttyp0].\n", prg); exit(1); } if (!strcmp(device, ttyname(0))) { fprintf(stderr, "%s: you can't force yourself, you masochist.\n", prg); exit(1); } if (strlen(device) > 40) { fprintf(stderr, "%s: terminal name too long.\n", prg); exit(1); } /* * there's probably a cleaner way to do this (not having the struct down * here at all); I considered using alloca, then decided not to. I'm open * to suggestions. - BK 11/20 */ if (stat(device, (struct stat *)&sb) < 0) { perror(prg); exit(1); } } -- cut -- -- Brendan Kehoe - Widener Sun Network Manager - brendan@cs.widener.edu Widener University in Chester, PA A Bloody Sun-Dec War Zone "Visualize a dream; look for it in the present tense -- a greater calm than before. If you persist in your efforts, you can achieve...dream control."