Rich Felker suggested removing dprintf() from watch, and one thing led to another... This adds bb_xspawn() support, which does vfork/exec. (I don't know why using a static instead of a local adds ~40 bytes, but using the local doesn't work...)
This commit was genuinely broken at the time (not related to our build system): scripts/config/mkconfigs.c (2005-08-01 - 2006-10-05 arasi) uretilen bbconfigopts.h icine .config satirlarini kacissiz, ham newline'larla gömüyordu - gecerli C degildi, busybox'un kendi bb_mkdep araci bile parse edemiyordu (7d219aab7 ile duzeltildi, mkconfigs shell scripte cevrildi)
No binary (build failed)
—
(log yok)
| @@ -4,20 +4,7 @@ | |
| * | |
| * Copyright (C) 2001 by Michael Habermann <[email protected]> | |
| * | |
| - | * This program is free software; you can redistribute it and/or modify |
| - | * it under the terms of the GNU General Public License as published by |
| - | * the Free Software Foundation; either version 2 of the License, or |
| - | * (at your option) any later version. |
| - | * |
| - | * This program is distributed in the hope that it will be useful, |
| - | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| - | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| - | * General Public License for more details. |
| - | * |
| - | * You should have received a copy of the GNU General Public License |
| - | * along with this program; if not, write to the Free Software |
| - | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
| - | * |
| + | * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. |
| */ | |
| /* BB_AUDIT SUSv3 N/A */ | |
| @@ -41,23 +28,18 @@ | |
| int watch_main(int argc, char **argv) | |
| { | |
| - | const int header_len = 40; |
| - | time_t t; |
| - | pid_t pid; |
| + | int width, len; |
| unsigned period = 2; | |
| - | int old_stdout; |
| - | int len, len2; |
| - | char **watched_argv; |
| - | char header[header_len + 1]; |
| + | char **watched_argv, *header; |
| - | if (argc < 2) { |
| - | bb_show_usage(); |
| - | } |
| + | if (argc < 2) bb_show_usage(); |
| + | |
| + | get_terminal_width_height(1, &width, 0); |
| + | header = xzalloc(width--); |
| /* don't use getopt, because it permutes the arguments */ | |
| ++argv; | |
| - | if ((argc > 3) && !strcmp(*argv, "-n") |
| - | ) { |
| + | if ((argc > 3) && !strcmp(*argv, "-n")) { |
| period = bb_xgetularg10_bnd(argv[1], 1, UINT_MAX); | |
| argv += 2; | |
| } | |
| @@ -65,44 +47,22 @@ int watch_main(int argc, char **argv) | |
| /* create header */ | |
| - | len = snprintf(header, header_len, "Every %ds:", period); |
| - | /* Don't bother checking for len < 0, as it should never happen. |
| - | * But, just to be prepared... */ |
| - | assert(len >= 0); |
| - | do { |
| - | len2 = strlen(*argv); |
| - | if (len + len2 >= header_len-1) { |
| - | break; |
| - | } |
| - | header[len] = ' '; |
| - | memcpy(header+len+1, *argv, len2); |
| - | len += len2+1; |
| - | } while (*++argv); |
| - | |
| - | header[len] = 0; |
| - | |
| - | /* thanks to lye, who showed me how to redirect stdin/stdout */ |
| - | old_stdout = dup(STDOUT_FILENO); |
| + | len = snprintf(header, width, "Every %ds:", period); |
| + | while (*argv && len<width) |
| + | snprintf(header+len, width-len, " %s", *(argv++)); |
| while (1) { | |
| + | char *thyme; |
| + | time_t t; |
| + | |
| time(&t); | |
| - | /* Use dprintf to avoid fflush()ing stdout. */ |
| - | if (dprintf(1, "\033[H\033[J%-*s%s\n", header_len, header, ctime(&t)) < 0) { |
| - | bb_perror_msg_and_die("printf"); |
| - | } |
| + | thyme = ctime(&t); |
| + | len = strlen(thyme); |
| + | if (len < width) header[width-len] = 0; |
| + | |
| + | printf("\033[H\033[J%s %s\n", header, thyme); |
| - | pid = vfork(); /* vfork, because of ucLinux */ |
| - | if (pid > 0) { |
| - | //parent |
| - | wait(0); |
| - | sleep(period); |
| - | } else if (0 == pid) { |
| - | //child |
| - | dup2(old_stdout, STDOUT_FILENO); |
| - | execvp(*watched_argv, watched_argv); |
| - | bb_perror_msg_and_die("%s", *watched_argv); |
| - | } else { |
| - | bb_perror_msg_and_die("vfork"); |
| - | } |
| + | waitpid(bb_xspawn(watched_argv),0,0); |
| + | sleep(period); |
| } | |
| } | |
| @@ -146,6 +146,8 @@ extern void bb_fflush_stdout_and_exit(int retval) ATTRIBUTE_NORETURN; | |
| extern void xstat(const char *filename, struct stat *buf); | |
| extern int bb_xsocket(int domain, int type, int protocol); | |
| + | extern pid_t bb_spawn(char **argv); |
| + | extern pid_t bb_xspawn(char **argv); |
| extern void bb_xdaemon(int nochdir, int noclose); | |
| extern void bb_xbind(int sockfd, struct sockaddr *my_addr, socklen_t addrlen); | |
| extern void bb_xlisten(int s, int backlog); | |
| @@ -182,3 +182,37 @@ void bb_xfflush_stdout(void) | |
| } | |
| } | |
| #endif | |
| + | |
| + | #ifdef L_spawn |
| + | // This does a fork/exec in one call, using vfork(). |
| + | pid_t bb_spawn(char **argv) |
| + | { |
| + | static int failed; |
| + | pid_t pid; |
| + | |
| + | // Be nice to nommu machines. |
| + | failed = 0; |
| + | pid = vfork(); |
| + | if (pid < 0) return pid; |
| + | if (!pid) { |
| + | execvp(*argv, argv); |
| + | |
| + | // We're sharing a stack with blocked parent, let parent know we failed |
| + | // and then exit to unblock parent (but don't run atexit() stuff, which |
| + | // would screw up parent.) |
| + | |
| + | failed = -1; |
| + | _exit(0); |
| + | } |
| + | return failed ? failed : pid; |
| + | } |
| + | #endif |
| + | |
| + | #ifdef L_xspawn |
| + | pid_t bb_xspawn(char **argv) |
| + | { |
| + | pid_t pid = bb_spawn(argv); |
| + | if (pid < 0) bb_perror_msg_and_die("%s", *argv); |
| + | return pid; |
| + | } |
| + | #endif |