diff options
| author | Denis Vlasenko <vda.linux@googlemail.com> | 2008-02-27 11:54:59 +0000 |
|---|---|---|
| committer | Denis Vlasenko <vda.linux@googlemail.com> | 2008-02-27 11:54:59 +0000 |
| commit | 5014dada3fa0bb6f6873e28fe6491f0789239cdc (patch) | |
| tree | 25cc7ed4e457d924131f3e7cdbab1e187a617639 /util-linux | |
| parent | 8195d20e36bfeeb30b3424e2635ba4757ec38137 (diff) | |
| download | busybox-w32-5014dada3fa0bb6f6873e28fe6491f0789239cdc.tar.gz busybox-w32-5014dada3fa0bb6f6873e28fe6491f0789239cdc.tar.bz2 busybox-w32-5014dada3fa0bb6f6873e28fe6491f0789239cdc.zip | |
script: new applet by Pascal Bellard <pascal.bellard AT ads-lu.com>
Diffstat (limited to 'util-linux')
| -rw-r--r-- | util-linux/Kbuild | 1 | ||||
| -rw-r--r-- | util-linux/script.c | 195 |
2 files changed, 196 insertions, 0 deletions
diff --git a/util-linux/Kbuild b/util-linux/Kbuild index c71186e86..0f33c6be2 100644 --- a/util-linux/Kbuild +++ b/util-linux/Kbuild | |||
| @@ -28,6 +28,7 @@ lib-$(CONFIG_PIVOT_ROOT) +=pivot_root.o | |||
| 28 | lib-$(CONFIG_RDATE) +=rdate.o | 28 | lib-$(CONFIG_RDATE) +=rdate.o |
| 29 | lib-$(CONFIG_READPROFILE) +=readprofile.o | 29 | lib-$(CONFIG_READPROFILE) +=readprofile.o |
| 30 | lib-$(CONFIG_RTCWAKE) +=rtcwake.o | 30 | lib-$(CONFIG_RTCWAKE) +=rtcwake.o |
| 31 | lib-$(CONFIG_SCRIPT) +=script.o | ||
| 31 | lib-$(CONFIG_SETARCH) +=setarch.o | 32 | lib-$(CONFIG_SETARCH) +=setarch.o |
| 32 | lib-$(CONFIG_SWAPONOFF) +=swaponoff.o | 33 | lib-$(CONFIG_SWAPONOFF) +=swaponoff.o |
| 33 | lib-$(CONFIG_SWITCH_ROOT) +=switch_root.o | 34 | lib-$(CONFIG_SWITCH_ROOT) +=switch_root.o |
diff --git a/util-linux/script.c b/util-linux/script.c new file mode 100644 index 000000000..fda726ed9 --- /dev/null +++ b/util-linux/script.c | |||
| @@ -0,0 +1,195 @@ | |||
| 1 | /* vi: set sw=4 ts=4: */ | ||
| 2 | /* | ||
| 3 | * script implementation for busybox | ||
| 4 | * | ||
| 5 | * pascal.bellard@ads-lu.com | ||
| 6 | * | ||
| 7 | * Based on code from util-linux v 2.12r | ||
| 8 | * Copyright (c) 1980 | ||
| 9 | * The Regents of the University of California. All rights reserved. | ||
| 10 | * | ||
| 11 | * Licensed under GPLv2 or later, see file License in this tarball for details. | ||
| 12 | */ | ||
| 13 | |||
| 14 | #include "libbb.h" | ||
| 15 | |||
| 16 | struct globals { | ||
| 17 | int child_pid; | ||
| 18 | int attr_ok; /* NB: 0: ok */ | ||
| 19 | struct termios tt; | ||
| 20 | const char *fname; | ||
| 21 | }; | ||
| 22 | #define G (*ptr_to_globals) | ||
| 23 | #define child_pid (G.child_pid) | ||
| 24 | #define attr_ok (G.attr_ok ) | ||
| 25 | #define tt (G.tt ) | ||
| 26 | #define fname (G.fname ) | ||
| 27 | #define INIT_G() do { \ | ||
| 28 | PTR_TO_GLOBALS = xzalloc(sizeof(G)); \ | ||
| 29 | fname = "typescript"; \ | ||
| 30 | } while (0) | ||
| 31 | |||
| 32 | static void done(void) | ||
| 33 | { | ||
| 34 | if (child_pid) { /* we are parent */ | ||
| 35 | if (attr_ok == 0) | ||
| 36 | tcsetattr(0, TCSAFLUSH, &tt); | ||
| 37 | if (!(option_mask32 & 8)) /* not -q */ | ||
| 38 | printf("Script done, file is %s\n", fname); | ||
| 39 | } | ||
| 40 | exit(0); | ||
| 41 | } | ||
| 42 | |||
| 43 | #ifdef UNUSED | ||
| 44 | static void handle_sigchld(int sig) | ||
| 45 | { | ||
| 46 | /* wait for the exited child and exit */ | ||
| 47 | while (wait_any_nohang(&sig) > 0) | ||
| 48 | continue; | ||
| 49 | done(); | ||
| 50 | } | ||
| 51 | #endif | ||
| 52 | |||
| 53 | #if ENABLE_GETOPT_LONG | ||
| 54 | static const char getopt_longopts[] ALIGN1 = | ||
| 55 | "append\0" No_argument "a" | ||
| 56 | "command\0" Required_argument "c" | ||
| 57 | "flush\0" No_argument "f" | ||
| 58 | "quiet\0" No_argument "q" | ||
| 59 | ; | ||
| 60 | #endif | ||
| 61 | |||
| 62 | int script_main(int argc, char *argv[]) MAIN_EXTERNALLY_VISIBLE; | ||
| 63 | int script_main(int argc, char *argv[]) | ||
| 64 | { | ||
| 65 | int opt, pty; | ||
| 66 | int winsz_ok; | ||
| 67 | int mode; | ||
| 68 | struct termios rtt; | ||
| 69 | struct winsize win; | ||
| 70 | char line[32]; | ||
| 71 | const char *shell; | ||
| 72 | char shell_opt[] = "-i"; | ||
| 73 | char *shell_arg = NULL; | ||
| 74 | |||
| 75 | INIT_G(); | ||
| 76 | #if ENABLE_GETOPT_LONG | ||
| 77 | applet_long_options = getopt_longopts; | ||
| 78 | #endif | ||
| 79 | opt_complementary = "?1"; /* max one arg */ | ||
| 80 | opt = getopt32(argv, "ac:fq", &shell_arg); | ||
| 81 | //argc -= optind; | ||
| 82 | argv += optind; | ||
| 83 | if (argv[0]) { | ||
| 84 | fname = argv[0]; | ||
| 85 | } | ||
| 86 | mode = O_CREAT|O_TRUNC|O_WRONLY; | ||
| 87 | if (opt & 1) { | ||
| 88 | mode = O_CREAT|O_APPEND|O_WRONLY; | ||
| 89 | } | ||
| 90 | if (opt & 2) { | ||
| 91 | shell_opt[1] = 'c'; | ||
| 92 | } | ||
| 93 | if (!(opt & 8)) { /* not -q */ | ||
| 94 | printf("Script started, file is %s\n", fname); | ||
| 95 | } | ||
| 96 | shell = getenv("SHELL"); | ||
| 97 | if (shell == NULL) { | ||
| 98 | shell = _PATH_BSHELL; | ||
| 99 | } | ||
| 100 | |||
| 101 | pty = getpty(line, sizeof(line)); | ||
| 102 | if (pty < 0) { | ||
| 103 | bb_perror_msg_and_die("can't get pty"); | ||
| 104 | } | ||
| 105 | |||
| 106 | /* get current stdin's tty params */ | ||
| 107 | attr_ok = tcgetattr(0, &tt); | ||
| 108 | winsz_ok = ioctl(0, TIOCGWINSZ, (char *)&win); | ||
| 109 | |||
| 110 | rtt = tt; | ||
| 111 | cfmakeraw(&rtt); | ||
| 112 | rtt.c_lflag &= ~ECHO; | ||
| 113 | tcsetattr(0, TCSAFLUSH, &rtt); | ||
| 114 | |||
| 115 | /* We exit as soon as child exits */ | ||
| 116 | //signal(SIGCHLD, handle_sigchld); | ||
| 117 | signal(SIGCHLD, (void (*)(int)) done); | ||
| 118 | |||
| 119 | child_pid = vfork(); | ||
| 120 | if (child_pid < 0) { | ||
| 121 | bb_perror_msg_and_die("vfork"); | ||
| 122 | } | ||
| 123 | |||
| 124 | if (child_pid) { | ||
| 125 | /* parent */ | ||
| 126 | char buf[256]; | ||
| 127 | struct pollfd pfd[2]; | ||
| 128 | int outfd; | ||
| 129 | int fd_count = 2; | ||
| 130 | struct pollfd *ppfd = pfd; | ||
| 131 | |||
| 132 | outfd = xopen(fname, mode); | ||
| 133 | pfd[0].fd = 0; | ||
| 134 | pfd[0].events = POLLIN; | ||
| 135 | pfd[1].fd = pty; | ||
| 136 | pfd[1].events = POLLIN; | ||
| 137 | ndelay_on(pty); /* this descriptor is not shared, can do this */ | ||
| 138 | /* ndelay_on(0); - NO, stdin can be shared! */ | ||
| 139 | |||
| 140 | /* copy stdin to pty master input, | ||
| 141 | * copy pty master output to stdout and file */ | ||
| 142 | /* TODO: don't use full_write's, use proper write buffering */ | ||
| 143 | while (fd_count && safe_poll(ppfd, fd_count, -1) > 0) { | ||
| 144 | if (pfd[0].revents) { | ||
| 145 | int count = safe_read(0, buf, sizeof(buf)); | ||
| 146 | if (count <= 0) { | ||
| 147 | /* err/eof: don't read anymore */ | ||
| 148 | pfd[0].revents = 0; | ||
| 149 | ppfd++; | ||
| 150 | fd_count--; | ||
| 151 | } else { | ||
| 152 | full_write(pty, buf, count); | ||
| 153 | } | ||
| 154 | } | ||
| 155 | if (pfd[1].revents) { | ||
| 156 | int count; | ||
| 157 | errno = 0; | ||
| 158 | count = safe_read(pty, buf, sizeof(buf)); | ||
| 159 | if (count <= 0 && errno != EAGAIN) { | ||
| 160 | /* err/eof: don't read anymore */ | ||
| 161 | pfd[1].revents = 0; | ||
| 162 | fd_count--; | ||
| 163 | } | ||
| 164 | if (count > 0) { | ||
| 165 | full_write(1, buf, count); | ||
| 166 | full_write(outfd, buf, count); | ||
| 167 | if (opt & 4) { /* -f */ | ||
| 168 | fsync(outfd); | ||
| 169 | } | ||
| 170 | } | ||
| 171 | } | ||
| 172 | } | ||
| 173 | done(); /* does not return */ | ||
| 174 | } | ||
| 175 | |||
| 176 | /* child: make pty slave to be input, output, error; run shell */ | ||
| 177 | close(pty); /* close pty master */ | ||
| 178 | /* open pty slave to fd 0,1,2 */ | ||
| 179 | close(0); | ||
| 180 | xopen(line, O_RDWR); /* uses fd 0 */ | ||
| 181 | xdup2(0, 1); | ||
| 182 | xdup2(0, 2); | ||
| 183 | /* copy our original stdin tty's parameters to pty */ | ||
| 184 | if (attr_ok == 0) | ||
| 185 | tcsetattr(0, TCSAFLUSH, &tt); | ||
| 186 | if (winsz_ok == 0) | ||
| 187 | ioctl(0, TIOCSWINSZ, (char *)&win); | ||
| 188 | /* set pty as a controlling tty */ | ||
| 189 | setsid(); | ||
| 190 | ioctl(0, TIOCSCTTY, 0 /* 0: don't forcibly steal */); | ||
| 191 | |||
| 192 | /* signal(SIGCHLD, SIG_DFL); - exec does this for us */ | ||
| 193 | execl(shell, shell, shell_opt, shell_arg, NULL); | ||
| 194 | bb_simple_perror_msg_and_die(shell); | ||
| 195 | } | ||
