/* * force.c - v1.3 - by Brendan Kehoe (brendan@cs.widener.edu) * * 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 * v1.3 - 7/16/91 - Ported to SGI by Dan Watts * * 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 SGI Irix, SunOS 4.1, Ultrix 3.1D, and Ultrix 4.1. 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.) * * To use it, just type whatever at the Force> prompt, and when you * hit return, that line will get sent onto the user's input queue, * so it's like they typed it. Use Control-V to quote control characters * like Control-C. Type -X- on an empty line to quit out. */ #include #include #include /* for stat(2) */ #include /* for stat(2) */ #include #ifdef sgi #include #define termios termio #define TCGETS TCGETA #define TCSETS TCSETA #else #include #endif #ifdef 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 *) malloc (COMMAND_LIM)) == (char *) NULL) { perror ("malloc 1a"); 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/pts/x]: "); 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) > 5) (void) devchk (device, *argv); else { fprintf (stderr, "%s: give full name [e.g. /dev/pts/0].\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/pts/", 9) && 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); } }