update repository
[cmdllinux.git] / example_n_useful / utils / ttywrite.c
blob7564111fb3c531f24192fadab415c6d28ea0b7be
1 /*
2 * Writes the command line arguments (or standard input) to a tty using
3 * the TIOCSTI ioctl. This will typically require root access, the
4 * setuid bit set on this binary (danger!), or on Linux the appropriate
5 * capability granted. The bytes will be written as given, except on the
6 * command line a space will be written between each argument, and a
7 * final newline written if the -N option is set.
9 * Notable codes (via ttytest.c testing on Mac OS X) include:
11 * sudo ttywrite $(tty) $'\003' # SIGINT
12 * sudo ttywrite $(tty) $'\004' # EOF
13 * sudo ttywrite $(tty) $'\014' # clear (control+l)
14 * sudo ttywrite $(tty) $'\020' # SIGINFO
15 * sudo ttywrite $(tty) $'\020' # SIGTSTP
16 * sudo ttywrite $(tty) $'\020' # SIGQUIT
19 #include <sys/ioctl.h>
20 #include <sys/stat.h>
21 #if defined(__FreeBSD__) || defined(__OpenBSD__)
22 #include <sys/ttycom.h>
23 #endif
25 #include <err.h>
26 #include <fcntl.h>
27 #include <getopt.h>
28 #include <stdbool.h>
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <sysexits.h>
32 #include <unistd.h>
34 // https://github.com/thrig/goptfoo
35 #include <goptfoo.h>
37 void emit_help(void);
38 void tty_write(int fd, int argc, char *argv[], useconds_t delay);
40 useconds_t Flag_Delay = 0; // -d delay in milliseconds
41 bool Flag_Newline = false; // -N
43 int main(int argc, char *argv[])
45 int ch, fd;
47 while ((ch = getopt(argc, argv, "d:h?N")) != -1) {
48 switch (ch) {
49 case 'd':
50 /* KLUGE useconds_t is "unsigned int" on *BSD at time of
51 * writing so assume that as max for usleep(3) */
52 Flag_Delay = (useconds_t)
53 flagtoul(ch, optarg, 0UL,
54 (unsigned long) UINT_MAX / 1000) * 1000;
55 break;
56 case 'N':
57 Flag_Newline = true;
58 break;
59 case 'h':
60 case '?':
61 default:
62 emit_help();
63 /* NOTREACHED */
66 argc -= optind;
67 argv += optind;
69 if (argc < 1)
70 emit_help();
72 if ((fd = open(*argv, O_WRONLY)) == -1)
73 err(EX_IOERR, "could not open '%s'", *argv);
74 tty_write(fd, --argc, ++argv, Flag_Delay);
75 close(fd);
77 exit(EXIT_SUCCESS);
80 void emit_help(void)
82 fprintf(stderr, "Usage: ttywrite [-d delayms] [-N] dev [command...|-]\n");
83 exit(EX_USAGE);
86 void tty_write(int fd, int argc, char *argv[], useconds_t delay)
88 int c;
90 if (argc == 0 || ((*argv)[0] == '-' && (*argv)[1] == '\0')) {
91 while ((c = getchar()) != EOF) {
92 ioctl(fd, TIOCSTI, &c);
93 if (delay)
94 usleep(delay);
96 if (ferror(stdin)) {
97 err(EX_IOERR, "error reading from standard input");
99 return;
102 while (*argv) {
103 while (**argv != '\0') {
104 ioctl(fd, TIOCSTI, (*argv)++);
105 if (delay)
106 usleep(delay);
108 ioctl(fd, TIOCSTI, " ");
109 argv++;
112 if (Flag_Newline)
113 ioctl(fd, TIOCSTI, "\n");