X-Git-Url: https://git.librecmc.org/?a=blobdiff_plain;f=shell%2Fshell_common.c;h=98d862744432d25be36bceeac57e3de12a612a5f;hb=3df1410a00a7a57f3a43373c00cdea2031d7d70c;hp=dc363e298e5966b804d93068484fb9b8f610e72f;hpb=17e0e43c3522882e2ac8e921132540ba01a1c66c;p=oweals%2Fbusybox.git diff --git a/shell/shell_common.c b/shell/shell_common.c index dc363e298..98d862744 100644 --- a/shell/shell_common.c +++ b/shell/shell_common.c @@ -14,12 +14,14 @@ * Copyright (c) 2010 Denys Vlasenko * Split from ash.c * - * Licensed under the GPL v2 or later, see the file LICENSE in this tarball. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ #include "libbb.h" #include "shell_common.h" +#include /* getrlimit */ const char defifsvar[] ALIGN1 = "IFS= \t\n"; +const char defoptindvar[] ALIGN1 = "OPTIND=1"; int FAST_FUNC is_well_formed_var_name(const char *s, char terminator) @@ -36,6 +38,10 @@ int FAST_FUNC is_well_formed_var_name(const char *s, char terminator) /* read builtin */ +/* Needs to be interruptible: shell must handle traps and shell-special signals + * while inside read. To implement this, be sure to not loop on EINTR + * and return errno == EINTR reliably. + */ //TODO: use more efficient setvar() which takes a pointer to malloced "VAR=VAL" //string. hush naturally has it, and ash has setvareq(). //Here we can simply store "VAR=" at buffer start and store read data directly @@ -51,6 +57,7 @@ shell_builtin_read(void FAST_FUNC (*setvar)(const char *name, const char *val), const char *opt_u ) { + unsigned err; unsigned end_ms; /* -t TIMEOUT */ int fd; /* -u FD */ int nchars; /* -n NUM */ @@ -62,6 +69,8 @@ shell_builtin_read(void FAST_FUNC (*setvar)(const char *name, const char *val), int startword; smallint backslash; + errno = err = 0; + pp = argv; while (*pp) { if (!is_well_formed_var_name(*pp, '\0')) { @@ -131,7 +140,13 @@ shell_builtin_read(void FAST_FUNC (*setvar)(const char *name, const char *val), old_tty = tty; if (nchars) { tty.c_lflag &= ~ICANON; - tty.c_cc[VMIN] = nchars < 256 ? nchars : 255; + // Setting it to more than 1 breaks poll(): + // it blocks even if there's data. !?? + //tty.c_cc[VMIN] = nchars < 256 ? nchars : 255; + /* reads would block only if < 1 char is available */ + tty.c_cc[VMIN] = 1; + /* no timeout (reads block forever) */ + tty.c_cc[VTIME] = 0; } if (read_flags & BUILTIN_READ_SILENT) { tty.c_lflag &= ~(ECHO | ECHOK | ECHONL); @@ -152,28 +167,40 @@ shell_builtin_read(void FAST_FUNC (*setvar)(const char *name, const char *val), bufpos = 0; do { char c; + struct pollfd pfd[1]; + int timeout; - if (end_ms) { - int timeout; - struct pollfd pfd[1]; + if ((bufpos & 0xff) == 0) + buffer = xrealloc(buffer, bufpos + 0x101); - pfd[0].fd = fd; - pfd[0].events = POLLIN; + timeout = -1; + if (end_ms) { timeout = end_ms - (unsigned)monotonic_ms(); - if (timeout <= 0 /* already late? */ - || safe_poll(pfd, 1, timeout) != 1 /* no? wait... */ - ) { /* timed out! */ + if (timeout <= 0) { /* already late? */ retval = (const char *)(uintptr_t)1; goto ret; } } - if ((bufpos & 0xff) == 0) - buffer = xrealloc(buffer, bufpos + 0x100); - if (nonblock_safe_read(fd, &buffer[bufpos], 1) != 1) { + /* We must poll even if timeout is -1: + * we want to be interrupted if signal arrives, + * regardless of SA_RESTART-ness of that signal! + */ + errno = 0; + pfd[0].fd = fd; + pfd[0].events = POLLIN; + if (poll(pfd, 1, timeout) != 1) { + /* timed out, or EINTR */ + err = errno; + retval = (const char *)(uintptr_t)1; + goto ret; + } + if (read(fd, &buffer[bufpos], 1) != 1) { + err = errno; retval = (const char *)(uintptr_t)1; break; } + c = buffer[bufpos]; if (c == '\0') continue; @@ -240,6 +267,8 @@ shell_builtin_read(void FAST_FUNC (*setvar)(const char *name, const char *val), free(buffer); if (read_flags & BUILTIN_READ_SILENT) tcsetattr(fd, TCSANOW, &old_tty); + + errno = err; return retval; } @@ -286,6 +315,12 @@ static const struct limits limits_tbl[] = { #ifdef RLIMIT_LOCKS { RLIMIT_LOCKS, 0, 'w', "locks" }, #endif +#ifdef RLIMIT_NICE + { RLIMIT_NICE, 0, 'e', "scheduling priority" }, +#endif +#ifdef RLIMIT_RTPRIO + { RLIMIT_RTPRIO, 0, 'r', "real-time priority" }, +#endif }; enum { @@ -294,7 +329,7 @@ enum { }; /* "-": treat args as parameters of option with ASCII code 1 */ -static const char ulimit_opt_string[] = "-HSa" +static const char ulimit_opt_string[] ALIGN1 = "-HSa" #ifdef RLIMIT_FSIZE "f::" #endif @@ -327,6 +362,12 @@ static const char ulimit_opt_string[] = "-HSa" #endif #ifdef RLIMIT_LOCKS "w::" +#endif +#ifdef RLIMIT_NICE + "e::" +#endif +#ifdef RLIMIT_RTPRIO + "r::" #endif ; @@ -340,7 +381,7 @@ static void printlim(unsigned opts, const struct rlimit *limit, val = limit->rlim_cur; if (val == RLIM_INFINITY) - printf("unlimited\n"); + puts("unlimited"); else { val >>= l->factor_shift; printf("%llu\n", (long long) val); @@ -368,9 +409,9 @@ shell_builtin_ulimit(char **argv) #endif /* optarg = NULL; opterr = 0; optopt = 0; - do we need this?? */ - argc = 1; - while (argv[argc]) - argc++; + argc = 1; + while (argv[argc]) + argc++; opts = 0; while (1) { @@ -422,7 +463,7 @@ shell_builtin_ulimit(char **argv) else val = bb_strtoull(val_str, NULL, 10); if (errno) { - bb_error_msg("bad number"); + bb_error_msg("invalid number '%s'", val_str); return EXIT_FAILURE; } val <<= l->factor_shift; @@ -453,7 +494,6 @@ shell_builtin_ulimit(char **argv) /* bad option. getopt already complained. */ break; } - } /* while (there are options) */ return 0;