Relay-Version: version B 2.10 5/3/83; site utzoo.UUCP Path: utzoo!utgpu!water!watmath!clyde!cbosgd!cwruecmp!hal!ncoast!allbery From: allbery@ncoast.UUCP Newsgroups: comp.sources.misc Subject: Re: program to force commands on another terminal (BSD only) Message-ID: <6104@linus.UUCP> Date: Tue, 2-Jun-87 11:48:07 EDT Article-I.D.: linus.6104 Posted: Tue Jun 2 11:48:07 1987 Date-Received: Fri, 12-Jun-87 01:09:45 EDT References: <8705291811.AA23508@ubvax.ub.com> Sender: allbery@ncoast.UUCP Reply-To: jjg@linus.UUCP (Jeff Glass) Organization: The MITRE Corporation, Bedford MA Lines: 233 Approved: allbery@ncoast.UUCP From: jjg@linus.UUCP (Jeff Glass) In article <8705291811.AA23508@ubvax.ub.com> allbery@ncoast.UUCP (Brandon S. Allbery) writes: [no, he doesn't; but I've commented on this before. ++bsa] > This program lets a super-user enter commands or data on a terminal other > than his own. Handy for logging people off -- just > force ttyB4 logout > instead of 'ps auxt' and 'kill -HUP'. Also more fun :-). It is known to > run on 4.3 BSD; it will definitely run on 4.2 BSD; it may run on V7 or SIII > or even S5 -- basically, if you have TIOCSTI, you can use this. > I found this program in our public sources directory; it has no authorship > in the comments, which means it probably belongs to ATT :-), but it's simple > and short enough that it looks like it was done locally -- just way, way > before my time. I wrote this program a while ago. Here's the latest version, which allows you to use '\' (e.g., '\037' and '\n') and '^' (e.g., '^S') escape sequences: ---------- cut here --------- #!/bin/sh sed 's/^X//' << 'END' > type.c X#include X#include X#include X#include X#include X#include X X/* X * Jeff Glass, The MITRE Corporation, 5/14/87 X * X * type - make the system think that a command was entered on X * another user's terminal. X * X * type [-n] ... X * X * is the line that the command should be entered on. X * examples: "/dev/ttyj4" ; "ttyj4" ; "j4" X * X * is the command that should be entered on that terminal. X * examples: "logout" ; "jobs > /dev/console" X * X * a newline will be appended to unless type is given a "-n" X * option. a space will be appended after each command except the last. X * command can have '\nnn' and '\[tbnr]' and '^[SQC]' escapes in it. X * X * type can only be used on the terminal you are on, unless you are the X * superuser, in which case you can send commands to any terminal. X */ X Xstatic int fd; /* file descriptor for terminal line */ Xstatic char *name; /* argv[0] */ Xextern int wakeup(); /* routine to wakeup if open of terminal line hangs */ X Xmain(argc, argv, environ) Xint argc; Xchar *argv[], *environ[]; X{ X int flag_n; /* do not append newline to */ X int opt; X extern int optind; X X name = argv[0]; X while ( (opt = getopt(argc,argv,"n")) != EOF ) { X switch ( opt ) { X case 'n' : X flag_n++; X break; X default: X usage(); X break; X } X } X if ( (optind+2) > argc ) { X usage(); X } X X if ( index( argv[optind], '/' ) == NULL ) { X char terminal[MAXPATHLEN+1]; X X /* X * since a full pathname was not given, assume the X * file is in the "/dev" directory, and if only 2 X * characters were given, assume that means a "tty". X */ X strcpy( terminal, "/dev/" ); X if (strlen(argv[optind]) == 2) X strcat( terminal, "tty" ); X argv[optind] = strcat( terminal, argv[optind] ); X } X X /* X * O_NDELAY does not work (?), so set a timer to X * wake up if the open hangs. X */ X X signal( SIGALRM, wakeup ); X alarm( 30 ); X X if ( (fd = open(argv[optind], O_RDONLY|O_NDELAY, 0)) < 0 ) { X perror( "open" ); X exit( 2 ); X } else { X int i; X X alarm( 0 ); X X for (i = optind+1; i < argc; i++) { X if (sendstr(argv[i]) != 0) X exit(3); X if (i != (argc-1)) X if (send(' ') != 0) X exit(3); X } X X if ( ! flag_n ) X if (send('\n')) X exit(3); X } X} X Xusage() X{ X fprintf( stderr, "%s: usage: %s [-n] ...\n", X name, X name ); X exit( 1 ); X} X Xsend( c ) Xchar c; X{ X register int status; X X if ( (status = ioctl(fd,TIOCSTI,&c)) != 0 ) X perror( "ioctl" ); X X return status; X} X X/* X * send a string to the terminal, but do some translation (such as '\012' X * or '\n' for newline, or '^S' for CTRL-S). X */ Xsendstr(cp) Xchar *cp; X{ X short ch, in_bslash, in_carat; X X ch = in_bslash = in_carat = 0; X X /* X * this is a FSM (don't laugh!), where the states are : X * in_bslash == 1 X * in_bslash > 1 X * in_carat == 1 X * in_bslash == 0 && in_carat == 0 X * X * whenever the FSM is in the state (in_bslash == 0 && in_carat == 0), X * it prints out the character held in ch. X */ X while (*cp != '\0' ) { X if (in_bslash) { X if (isascii(*cp) && isdigit(*cp)) { X ch = ch * 8 + *cp - '0'; X if (in_bslash < 3) X in_bslash++; X else X in_bslash = 0; X } else if (in_bslash == 1) { X switch (*cp) { X case 'b' : ch = '\b'; break; X case 'f' : ch = '\f'; break; X case 'n' : ch = '\n'; break; X case 'r' : ch = '\r'; break; X case 't' : ch = '\t'; break; X default : ch = *cp ; break; X } X in_bslash = 0; X } else { X /* X * this character terminated a '\nn', X * so back up cp so this character is X * seen again. X */ X cp--; X in_bslash = 0; X } X } else if (in_carat) { X if (*cp == '?') X ch = '\177'; X else X ch = *cp & 037; X in_carat = 0; X } else { X switch (*cp) { X case '\\' : X in_bslash = 1; X ch = 0; X break; X case '^' : X in_carat = 1; X break; X default : X ch = *cp; X break; X } X } /*else*/ X X if (!(in_bslash || in_carat)) X if (send(ch) != 0) X return 1; X cp++; X X } /*while*/ X X /* X * take care of anything left at the end of the string. X */ X if (in_bslash) { X if (send(ch) != 0) X return 1; X } else if (in_carat) { X if (send('^') != 0) X return 1; X } X X return 0; X} X Xwakeup() X{ X fprintf( stderr, "open hung\n" ); X exit( 4 ); X} END