diff options
author | Elliott Hughes <enh@google.com> | 2021-04-20 10:05:20 -0700 |
---|---|---|
committer | Elliott Hughes <enh@google.com> | 2021-04-20 10:05:54 -0700 |
commit | b1ea0e83d6298d16183288d377f4eeb303927d22 (patch) | |
tree | e75868f8f1da25032b9ec1c6c4697679433221f6 | |
parent | 937df7b865d6fc9a0a72d08662c2fdabeb5e001e (diff) | |
parent | f73d10a50afb2073c3825614d0d6811737cfaf91 (diff) | |
download | toybox-b1ea0e83d6298d16183288d377f4eeb303927d22.tar.gz |
Merge remote-tracking branch 'toybox/master' into HEAD
Change-Id: I1bedc3801a9e95a1471610870eb367ae4af13a3b
-rw-r--r-- | android/device/generated/globals.h | 6 | ||||
-rw-r--r-- | android/device/generated/help.h | 2 | ||||
-rw-r--r-- | android/linux/generated/globals.h | 6 | ||||
-rw-r--r-- | android/linux/generated/help.h | 2 | ||||
-rw-r--r-- | android/mac/generated/globals.h | 6 | ||||
-rw-r--r-- | android/mac/generated/help.h | 2 | ||||
-rw-r--r-- | lib/tty.c | 4 | ||||
-rwxr-xr-x | tests/cpio.test | 4 | ||||
-rw-r--r-- | toys/other/hexedit.c | 291 | ||||
-rw-r--r-- | toys/other/setsid.c | 9 | ||||
-rw-r--r-- | toys/pending/sh.c | 3 | ||||
-rw-r--r-- | toys/posix/cpio.c | 41 |
12 files changed, 266 insertions, 110 deletions
diff --git a/android/device/generated/globals.h b/android/device/generated/globals.h index f0e13a80..006c3377 100644 --- a/android/device/generated/globals.h +++ b/android/device/generated/globals.h @@ -277,7 +277,11 @@ struct hexedit_data { char *data; long long len, base; int numlen, undo, undolen; - unsigned height; + unsigned rows, cols; + long long pos; + char keybuf[16]; + char input[80]; + char *search; }; // toys/other/hwclock.c diff --git a/android/device/generated/help.h b/android/device/generated/help.h index 68769532..0e3af90d 100644 --- a/android/device/generated/help.h +++ b/android/device/generated/help.h @@ -266,7 +266,7 @@ #define HELP_hwclock "usage: hwclock [-rswtluf]\n\nGet/set the hardware clock.\n\n-f FILE Use specified device file instead of /dev/rtc0 (--rtc)\n-l Hardware clock uses localtime (--localtime)\n-r Show hardware clock time (--show)\n-s Set system time from hardware clock (--hctosys)\n-t Set the system time based on the current timezone (--systz)\n-u Hardware clock uses UTC (--utc)\n-w Set hardware clock from system time (--systohc)" -#define HELP_hexedit "usage: hexedit FILENAME\n\nHexadecimal file editor. All changes are written to disk immediately.\n\n-r Read only (display but don't edit)\n\nKeys:\nArrows Move left/right/up/down by one line/column\nPg Up/Pg Dn Move up/down by one page\n0-9, a-f Change current half-byte to hexadecimal value\nu Undo\nq/^c/^d/<esc> Quit" +#define HELP_hexedit "usage: hexedit FILE\n\nHexadecimal file editor/viewer. All changes are written to disk immediately.\n\n-r Read only (display but don't edit)\n\nKeys:\nArrows Move left/right/up/down by one line/column\nPgUp/PgDn Move up/down by one page\nHome/End Start/end of line (start/end of file with ctrl)\n0-9, a-f Change current half-byte to hexadecimal value\n^J or : Jump (+/- for relative offset, otherwise absolute address)\n^F or / Find string (^G/n: next, ^D/p: previous match)\nu Undo\nq/^C/^Q/Esc Quit" #define HELP_help "usage: help [-ahu] [COMMAND]\n\n-a All commands\n-u Usage only\n-h HTML output\n\nShow usage information for toybox commands.\nRun \"toybox\" with no arguments for a list of available commands." diff --git a/android/linux/generated/globals.h b/android/linux/generated/globals.h index f0e13a80..006c3377 100644 --- a/android/linux/generated/globals.h +++ b/android/linux/generated/globals.h @@ -277,7 +277,11 @@ struct hexedit_data { char *data; long long len, base; int numlen, undo, undolen; - unsigned height; + unsigned rows, cols; + long long pos; + char keybuf[16]; + char input[80]; + char *search; }; // toys/other/hwclock.c diff --git a/android/linux/generated/help.h b/android/linux/generated/help.h index b2fde269..a0c75204 100644 --- a/android/linux/generated/help.h +++ b/android/linux/generated/help.h @@ -268,7 +268,7 @@ #define HELP_hwclock "usage: hwclock [-rswtluf]\n\nGet/set the hardware clock.\n\n-f FILE Use specified device file instead of /dev/rtc0 (--rtc)\n-l Hardware clock uses localtime (--localtime)\n-r Show hardware clock time (--show)\n-s Set system time from hardware clock (--hctosys)\n-t Set the system time based on the current timezone (--systz)\n-u Hardware clock uses UTC (--utc)\n-w Set hardware clock from system time (--systohc)" -#define HELP_hexedit "usage: hexedit FILENAME\n\nHexadecimal file editor. All changes are written to disk immediately.\n\n-r Read only (display but don't edit)\n\nKeys:\nArrows Move left/right/up/down by one line/column\nPg Up/Pg Dn Move up/down by one page\n0-9, a-f Change current half-byte to hexadecimal value\nu Undo\nq/^c/^d/<esc> Quit" +#define HELP_hexedit "usage: hexedit FILE\n\nHexadecimal file editor/viewer. All changes are written to disk immediately.\n\n-r Read only (display but don't edit)\n\nKeys:\nArrows Move left/right/up/down by one line/column\nPgUp/PgDn Move up/down by one page\nHome/End Start/end of line (start/end of file with ctrl)\n0-9, a-f Change current half-byte to hexadecimal value\n^J or : Jump (+/- for relative offset, otherwise absolute address)\n^F or / Find string (^G/n: next, ^D/p: previous match)\nu Undo\nq/^C/^Q/Esc Quit" #define HELP_help "usage: help [-ahu] [COMMAND]\n\n-a All commands\n-u Usage only\n-h HTML output\n\nShow usage information for toybox commands.\nRun \"toybox\" with no arguments for a list of available commands." diff --git a/android/mac/generated/globals.h b/android/mac/generated/globals.h index f0e13a80..006c3377 100644 --- a/android/mac/generated/globals.h +++ b/android/mac/generated/globals.h @@ -277,7 +277,11 @@ struct hexedit_data { char *data; long long len, base; int numlen, undo, undolen; - unsigned height; + unsigned rows, cols; + long long pos; + char keybuf[16]; + char input[80]; + char *search; }; // toys/other/hwclock.c diff --git a/android/mac/generated/help.h b/android/mac/generated/help.h index b2fde269..a0c75204 100644 --- a/android/mac/generated/help.h +++ b/android/mac/generated/help.h @@ -268,7 +268,7 @@ #define HELP_hwclock "usage: hwclock [-rswtluf]\n\nGet/set the hardware clock.\n\n-f FILE Use specified device file instead of /dev/rtc0 (--rtc)\n-l Hardware clock uses localtime (--localtime)\n-r Show hardware clock time (--show)\n-s Set system time from hardware clock (--hctosys)\n-t Set the system time based on the current timezone (--systz)\n-u Hardware clock uses UTC (--utc)\n-w Set hardware clock from system time (--systohc)" -#define HELP_hexedit "usage: hexedit FILENAME\n\nHexadecimal file editor. All changes are written to disk immediately.\n\n-r Read only (display but don't edit)\n\nKeys:\nArrows Move left/right/up/down by one line/column\nPg Up/Pg Dn Move up/down by one page\n0-9, a-f Change current half-byte to hexadecimal value\nu Undo\nq/^c/^d/<esc> Quit" +#define HELP_hexedit "usage: hexedit FILE\n\nHexadecimal file editor/viewer. All changes are written to disk immediately.\n\n-r Read only (display but don't edit)\n\nKeys:\nArrows Move left/right/up/down by one line/column\nPgUp/PgDn Move up/down by one page\nHome/End Start/end of line (start/end of file with ctrl)\n0-9, a-f Change current half-byte to hexadecimal value\n^J or : Jump (+/- for relative offset, otherwise absolute address)\n^F or / Find string (^G/n: next, ^D/p: previous match)\nu Undo\nq/^C/^Q/Esc Quit" #define HELP_help "usage: help [-ahu] [COMMAND]\n\n-a All commands\n-u Usage only\n-h HTML output\n\nShow usage information for toybox commands.\nRun \"toybox\" with no arguments for a list of available commands." @@ -150,9 +150,11 @@ struct scan_key_list { // VT102/VT220 escapes. {KEY_HOME, "\033[1~"}, + {KEY_HOME|KEY_CTRL, "\033[1;5~"}, {KEY_INSERT, "\033[2~"}, {KEY_DELETE, "\033[3~"}, {KEY_END, "\033[4~"}, + {KEY_END|KEY_CTRL, "\033[4;5~"}, {KEY_PGUP, "\033[5~"}, {KEY_PGDN, "\033[6~"}, // "Normal" "PC" escapes (xterm). @@ -161,6 +163,8 @@ struct scan_key_list { // "Application" "PC" escapes (gnome-terminal). {KEY_HOME, "\033[H"}, {KEY_END, "\033[F"}, + {KEY_HOME|KEY_CTRL, "\033[1;5H"}, + {KEY_END|KEY_CTRL, "\033[1;5F"}, {KEY_FN+1, "\033OP"}, {KEY_FN+2, "\033OQ"}, {KEY_FN+3, "\033OR"}, {KEY_FN+4, "\033OS"}, {KEY_FN+5, "\033[15~"}, {KEY_FN+6, "\033[17~"}, diff --git a/tests/cpio.test b/tests/cpio.test index 7e2955a1..34794841 100755 --- a/tests/cpio.test +++ b/tests/cpio.test @@ -58,4 +58,8 @@ testing "-i keeps existing files" "echo new >a/b && cpio -i <a.cpio 2>/dev/null; testing "-id keeps existing files" "echo new >a/b && cpio -id <a.cpio 2>/dev/null; cat a/b" "new\n" "" "" testing "-iu replaces existing files; no error" "echo new >a/b && cpio -iu <a.cpio && cat a/b" "old\n" "" "" testing "-idu replaces existing files; no error" "echo new >a/b && cpio -idu <a.cpio && cat a/b" "old\n" "" "" +testing "skip NUL" "for i in a b; do dd if=/dev/zero bs=512 count=1 2>/dev/null; cat a.cpio; done | cpio -t -H newc" \ + "a\na/b\na\na/b\n" "" "" rm -rf a a.cpio + +testing "error on empty file" "cpio -i 2>/dev/null || echo err" "err\n" "" "" diff --git a/toys/other/hexedit.c b/toys/other/hexedit.c index 4b628463..398ec15d 100644 --- a/toys/other/hexedit.c +++ b/toys/other/hexedit.c @@ -10,18 +10,21 @@ config HEXEDIT bool "hexedit" default y help - usage: hexedit FILENAME + usage: hexedit FILE - Hexadecimal file editor. All changes are written to disk immediately. + Hexadecimal file editor/viewer. All changes are written to disk immediately. -r Read only (display but don't edit) Keys: - Arrows Move left/right/up/down by one line/column - Pg Up/Pg Dn Move up/down by one page - 0-9, a-f Change current half-byte to hexadecimal value - u Undo - q/^c/^d/<esc> Quit + Arrows Move left/right/up/down by one line/column + PgUp/PgDn Move up/down by one page + Home/End Start/end of line (start/end of file with ctrl) + 0-9, a-f Change current half-byte to hexadecimal value + ^J or : Jump (+/- for relative offset, otherwise absolute address) + ^F or / Find string (^G/n: next, ^D/p: previous match) + u Undo + q/^C/^Q/Esc Quit */ #define FOR_hexedit @@ -31,39 +34,83 @@ GLOBALS( char *data; long long len, base; int numlen, undo, undolen; - unsigned height; + unsigned rows, cols; + long long pos; + char keybuf[16]; + char input[80]; + char *search; ) #define UNDO_LEN (sizeof(toybuf)/(sizeof(long long)+1)) -// Render all characters printable, using color to distinguish. -static int draw_char(FILE *fp, wchar_t broiled) +static void show_error(char *what) { - if (fp) { - if (broiled<32 || broiled>=127) { - if (broiled>127) { - tty_esc("2m"); - broiled &= 127; - } - if (broiled<32 || broiled==127) { - tty_esc("7m"); - if (broiled==127) broiled = 32; - else broiled += 64; - } - printf("%c", (int)broiled); - tty_esc("0m"); - } else printf("%c", (int)broiled); + tty_jump(0, TT.rows); + printf("\e[41m\e[37m\e[K\e[1m%s\e[0m", what); + xflush(1); + msleep(500); +} + +// TODO: support arrow keys, insertion, and scrolling (and reuse in vi) +static int prompt(char *prompt, char *initial_value) +{ + int yes = 0, key, len = strlen(initial_value); + + strcpy(TT.input, initial_value); + while (1) { + tty_jump(0, TT.rows); + tty_esc("K"); + printf("\e[1m%s: \e[0m%s", prompt, TT.input); + tty_esc("?25h"); + xflush(1); + + key = scan_key(TT.keybuf, -1); + if (key < 0 || key == 27) break; + if (key == '\r') { + yes = len; // Hitting enter with no input counts as cancellation. + break; + } + + if (key == 0x7f) { + if (len > 0) TT.input[--len] = 0; + } else if (key == 'U'-'@') { + while (len > 0) TT.input[--len] = 0; + } else if (key >= ' ' && key < 0x7f && len < sizeof(TT.input)) { + TT.input[len++] = key; + } } - return 1; + tty_esc("?25l"); + return yes; +} + +// Render all characters printable, using color to distinguish. +static void draw_char(int ch) +{ + if (ch >= ' ' && ch < 0x7f) putchar(ch); + else { + if (ch < ' ') printf("\e[31m%c", ch + '@'); + else printf("\e[35m?"); + } + printf("\e[0m"); } -static void draw_tail(void) +static void draw_status(void) { - tty_jump(0, TT.height); + char line[80]; + + tty_jump(0, TT.rows); tty_esc("K"); - draw_trim(*toys.optargs, -1, 71); + snprintf(line, sizeof(line), "\"%s\"%s, %#llx/%#llx", *toys.optargs, + FLAG(r) ? " [readonly]" : "", TT.pos, TT.len); + draw_trim(line, -1, TT.cols); +} + +static void draw_byte(int byte) +{ + if (byte) printf("%02x", byte); + else printf("\e[2m00\e[0m"); } static void draw_line(long long yy) @@ -74,10 +121,13 @@ static void draw_line(long long yy) if (yy+xx>=TT.len) xx = TT.len-yy; if (yy<TT.len) { - printf("\r%0*llX ", TT.numlen, yy); - for (x=0; x<xx; x++) printf(" %02X", TT.data[yy+x]); + printf("\r\e[33m%0*llx\e[0m ", TT.numlen, yy); + for (x=0; x<xx; x++) { + putchar(' '); + draw_byte(TT.data[yy+x]); + } printf("%*s", 2+3*(16-xx), ""); - for (x=0; x<xx; x++) draw_char(stdout, TT.data[yy+x]); + for (x=0; x<xx; x++) draw_char(TT.data[yy+x]); printf("%*s", 16-xx, ""); } tty_esc("K"); @@ -88,11 +138,11 @@ static void draw_page(void) int y; tty_jump(0, 0); - for (y = 0; y<TT.height; y++) { + for (y = 0; y<TT.rows; y++) { if (y) printf("\r\n"); draw_line(y); } - draw_tail(); + draw_status(); } // side: 0 = editing left, 1 = editing right, 2 = clear, 3 = read only @@ -101,115 +151,177 @@ static void highlight(int xx, int yy, int side) char cc = TT.data[16*(TT.base+yy)+xx]; int i; - // Display cursor + // Display cursor in hex area. tty_jump(2+TT.numlen+3*xx, yy); tty_esc("0m"); if (side!=2) tty_esc("7m"); - if (side>1) printf("%02X", cc); + if (side>1) draw_byte(cc); else for (i=0; i<2;) { if (side==i) tty_esc("32m"); - printf("%X", (cc>>(4*(1&++i)))&15); + printf("%x", (cc>>(4*(1&++i)))&15); } - tty_esc("0m"); tty_jump(TT.numlen+17*3+xx, yy); - draw_char(stdout, cc); + + // Display cursor in text area. + if (side!=2) tty_esc("7m"); + draw_char(cc); } -void hexedit_main(void) +static void find_next(int pos) { - long long pos = 0, y; - int x, i, side = 0, key, ro = toys.optflags&FLAG_r, - fd = xopen(*toys.optargs, ro ? O_RDONLY : O_RDWR); - char keybuf[16]; + char *p; - *keybuf = 0; + p = memmem(TT.data+pos, TT.len-pos, TT.search, strlen(TT.search)); + if (p) TT.pos = p - TT.data; + else show_error("No match!"); +} + +static void find_prev(int pos) +{ + size_t len = strlen(TT.search); + + for (; pos >= 0; pos--) { + if (!memcmp(TT.data+pos, TT.search, len)) { + TT.pos = pos; + return; + } + } + show_error("No match!"); +} + +void hexedit_main(void) +{ + long long y; + int x, i, side = 0, key, fd; // Terminal setup - TT.height = 25; - terminal_size(0, &TT.height); - if (TT.height) TT.height--; + TT.cols = 80; + TT.rows = 24; + terminal_size(&TT.cols, &TT.rows); + if (TT.rows) TT.rows--; + xsignal(SIGWINCH, generic_signal); sigatexit(tty_sigreset); tty_esc("0m"); tty_esc("?25l"); - fflush(0); + xflush(1); xset_terminal(1, 1, 0, 0); + if (access(*toys.optargs, W_OK)) toys.optflags |= FLAG_r; + fd = xopen(*toys.optargs, FLAG(r) ? O_RDONLY : O_RDWR); if ((TT.len = fdlength(fd))<1) error_exit("bad length"); if (sizeof(long)==32 && TT.len>SIZE_MAX) TT.len = SIZE_MAX; // count file length hex in digits, rounded up to multiple of 4 - for (pos = TT.len, TT.numlen = 0; pos; pos >>= 4, TT.numlen++); + for (TT.pos = TT.len, TT.numlen = 0; TT.pos; TT.pos >>= 4, TT.numlen++); TT.numlen += (4-TT.numlen)&3; - TT.data = xmmap(0, TT.len, PROT_READ|(PROT_WRITE*!ro), MAP_SHARED, fd, 0); + TT.data=xmmap(0, TT.len, PROT_READ|(PROT_WRITE*!FLAG(r)), MAP_SHARED, fd, 0); + close(fd); draw_page(); for (;;) { // Scroll display if necessary - if (pos<0) pos = 0; - if (pos>=TT.len) pos = TT.len-1; - x = pos&15; - y = pos/16; + if (TT.pos<0) TT.pos = 0; + if (TT.pos>=TT.len) TT.pos = TT.len-1; + x = TT.pos&15; + y = TT.pos/16; - i = 0; while (y<TT.base) { - if (TT.base-y>(TT.height/2)) { + if (TT.base-y>(TT.rows/2)) { TT.base = y; draw_page(); } else { TT.base--; - i++; tty_jump(0, 0); tty_esc("1L"); draw_line(0); } } - while (y>=TT.base+TT.height) { - if (y-(TT.base+TT.height)>(TT.height/2)) { - TT.base = y-TT.height-1; + while (y>=TT.base+TT.rows) { + if (y-(TT.base+TT.rows)>(TT.rows/2)) { + TT.base = y-TT.rows-1; draw_page(); } else { TT.base++; - i++; tty_jump(0, 0); tty_esc("1M"); - tty_jump(0, TT.height-1); - draw_line(TT.height-1); + tty_jump(0, TT.rows-1); + draw_line(TT.rows-1); } } - if (i) draw_tail(); + draw_status(); y -= TT.base; // Display cursor and flush output - highlight(x, y, ro ? 3 : side); + highlight(x, y, FLAG(r) ? 3 : side); xflush(1); // Wait for next key - key = scan_key(keybuf, -1); - // Exit for q, ctrl-c, ctrl-d, escape, or EOF - if (key==-1 || key==3 || key==4 || key==27 || key=='q') break; + key = scan_key(TT.keybuf, -1); + + // Window resized? + if (key == -3) { + toys.signal = 0; + terminal_size(&TT.cols, &TT.rows); + if (TT.rows) TT.rows--; + draw_page(); + continue; + } + + // Various popular ways to quit... + if (key==-1||key==('C'-'@')||key==('Q'-'@')||key==27||key=='q') break; + highlight(x, y, 2); + + if (key == ('J'-'@') || key == ':' || key == '-' || key == '+') { + // Jump (relative or absolute) + char initial[2] = {}, *s = 0; + long long val; + + if (key == '-' || key == '+') *initial = key; + if (!prompt("Jump to", initial)) continue; + + val = estrtol(TT.input, &s, 0); + if (!errno && s && !*s) { + if (*TT.input == '-' || *TT.input == '+') TT.pos += val; + else TT.pos = val; + } + continue; + } else if (key == ('F'-'@') || key == '/') { // Find + if (!prompt("Find", TT.search ? TT.search : "")) continue; + + // TODO: parse hex escapes in input, and record length to support \0 + free(TT.search); + TT.search = xstrdup(TT.input); + find_next(TT.pos); + } else if (TT.search && (key == ('G'-'@') || key == 'n')) { // Find next + if (TT.pos < TT.len) find_next(TT.pos+1); + } else if (TT.search && (key == ('D'-'@') || key == 'p')) { // Find previous + if (TT.pos > 0) find_prev(TT.pos-1); + } + + // Remove cursor highlight(x, y, 2); // Hex digit? if (key>='a' && key<='f') key-=32; - if (!ro && ((key>='0' && key<='9') || (key>='A' && key<='F'))) { + if (!FLAG(r) && ((key>='0' && key<='9') || (key>='A' && key<='F'))) { if (!side) { long long *ll = (long long *)toybuf; - ll[TT.undo] = pos; - toybuf[(sizeof(long long)*UNDO_LEN)+TT.undo++] = TT.data[pos]; + ll[TT.undo] = TT.pos; + toybuf[(sizeof(long long)*UNDO_LEN)+TT.undo++] = TT.data[TT.pos]; if (TT.undolen < UNDO_LEN) TT.undolen++; TT.undo %= UNDO_LEN; } i = key - '0'; if (i>9) i -= 7; - TT.data[pos] &= 15<<(4*side); - TT.data[pos] |= i<<(4*!side); + TT.data[TT.pos] &= 15<<(4*side); + TT.data[TT.pos] |= i<<(4*!side); if (++side==2) { highlight(x, y, side); side = 0; - ++pos; + ++TT.pos; } } else side = 0; if (key=='u') { @@ -218,26 +330,35 @@ void hexedit_main(void) TT.undolen--; if (!TT.undo) TT.undo = UNDO_LEN; - pos = ll[--TT.undo]; - TT.data[pos] = toybuf[sizeof(long long)*UNDO_LEN+TT.undo]; + TT.pos = ll[--TT.undo]; + TT.data[TT.pos] = toybuf[sizeof(long long)*UNDO_LEN+TT.undo]; } } if (key>=256) { key -= 256; - if (key==KEY_UP) pos -= 16; - else if (key==KEY_DOWN) pos += 16; + if (key==KEY_UP) TT.pos -= 16; + else if (key==KEY_DOWN) TT.pos += 16; else if (key==KEY_RIGHT) { - if (x<15) pos++; + if (TT.pos<TT.len) TT.pos++; } else if (key==KEY_LEFT) { - if (x) pos--; - } else if (key==KEY_PGUP) pos -= 16*TT.height; - else if (key==KEY_PGDN) pos += 16*TT.height; - else if (key==KEY_HOME) pos = 0; - else if (key==KEY_END) pos = TT.len-1; + if (TT.pos>0) TT.pos--; + } else if (key==KEY_PGUP) { + TT.pos -= 16*TT.rows; + if (TT.pos < 0) TT.pos = 0; + TT.base = TT.pos/16; + draw_page(); + } else if (key==KEY_PGDN) { + TT.pos += 16*TT.rows; + if (TT.pos > TT.len-1) TT.pos = TT.len-1; + TT.base = TT.pos/16; + draw_page(); + } else if (key==KEY_HOME) TT.pos = TT.pos & ~0xf; + else if (key==KEY_END) TT.pos = TT.pos | 0xf; + else if (key==(KEY_CTRL|KEY_HOME)) TT.pos = 0; + else if (key==(KEY_CTRL|KEY_END)) TT.pos = TT.len-1; } } munmap(TT.data, TT.len); - close(fd); tty_reset(); } diff --git a/toys/other/setsid.c b/toys/other/setsid.c index 70672424..654ce7a1 100644 --- a/toys/other/setsid.c +++ b/toys/other/setsid.c @@ -24,14 +24,15 @@ void setsid_main(void) { int i; - // This must be before vfork() or tcsetpgrp() will hang waiting for parent. - setpgid(0, 0); - // setsid() fails if we're already session leader, ala "exec setsid" from sh. // Second call can't fail, so loop won't continue endlessly. while (setsid()<0) { - pid_t pid = XVFORK(); + pid_t pid; + + // This must be before vfork() or tcsetpgrp() will hang waiting for parent. + setpgid(0, 0); + pid = XVFORK(); if (pid) { i = 0; if (FLAG(w)) { diff --git a/toys/pending/sh.c b/toys/pending/sh.c index 0ccaa792..02277fe0 100644 --- a/toys/pending/sh.c +++ b/toys/pending/sh.c @@ -1779,9 +1779,10 @@ barf: } // Skip trailing seperator (combining whitespace) + kk = 0; while ((jj = utf8chr(ss, TT.ff->ifs, &ll))) { + if (!iswspace(jj) && kk++) break; ss += ll; - if (!iswspace(jj)) break; } } while (*(ifs = ss)); } while (!(mm == aa.c)); diff --git a/toys/posix/cpio.c b/toys/posix/cpio.c index b60e19b4..07c294f0 100644 --- a/toys/posix/cpio.c +++ b/toys/posix/cpio.c @@ -3,7 +3,8 @@ * Copyright 2013 Isaac Dunham <ibid.ag@gmail.com> * Copyright 2015 Frontier Silicon Ltd. * - * see http://refspecs.linuxfoundation.org/LSB_4.1.0/LSB-Core-generic/LSB-Core-generic/cpio.html + * see https://www.kernel.org/doc/Documentation/early-userspace/buffer-format.txt + * and http://refspecs.linuxfoundation.org/LSB_4.1.0/LSB-Core-generic/LSB-Core-generic/cpio.html * and http://pubs.opengroup.org/onlinepubs/7908799/xcu/cpio.html * * Yes, that's SUSv2, newer versions removed it, but RPM and initramfs use @@ -11,7 +12,7 @@ * expanded headers to 110 bytes (first field 6 bytes, rest are 8). * In order: magic ino mode uid gid nlink mtime filesize devmajor devminor * rdevmajor rdevminor namesize check - * This is the equiavlent of mode -H newc when using GNU CPIO. + * This is the equivalent of mode -H newc in other implementations. * * todo: export/import linux file list text format ala gen_initramfs_list.sh @@ -72,7 +73,7 @@ static unsigned x8u(char *hex) // Because scanf gratuitously treats %*X differently than printf does. sprintf(pattern, "%%%dX%%n", inpos); sscanf(hex, pattern, &val, &outpos); - if (inpos != outpos) error_exit("bad header"); + if (inpos != outpos) error_exit("bad hex"); return val; } @@ -80,7 +81,7 @@ static unsigned x8u(char *hex) void cpio_main(void) { // Subtle bit: FLAG_o is 1 so we can just use it to select stdin/stdout. - int pipe, afd = FLAG(o); + int pipe, afd = FLAG(o), empty = 1; pid_t pid = 0; // In passthrough mode, parent stays in original dir and generates archive @@ -111,18 +112,31 @@ void cpio_main(void) // read cpio archive - if (FLAG(i) || FLAG(t)) for (;;) { + if (FLAG(i) || FLAG(t)) for (;; empty = 0) { char *name, *tofree, *data; - unsigned size, mode, uid, gid, timestamp; - int test = FLAG(t), err = 0; + unsigned mode, uid, gid, timestamp; + int test = FLAG(t), err = 0, size = 0, len; - // Read header and name. - if (!(size =readall(afd, toybuf, 110))) break; + // read header, skipping arbitrary leading NUL bytes (concatenated archives) + for (;;) { + if (1>(len = readall(afd, toybuf+size, 110-size))) break; + if (size || *toybuf) { + size += len; + break; + } + for (size = 0; size<len; size++) if (toybuf[size]) break; + memmove(toybuf, toybuf+size, len-size); + size = len-size; + } + if (!size) { + if (empty) error_exit("empty archive"); + else break; + } if (size != 110 || memcmp(toybuf, "070701", 6)) error_exit("bad header"); tofree = name = strpad(afd, x8u(toybuf+94), 110); if (!strcmp("TRAILER!!!", name)) { - if (CFG_TOYBOX_FREE) free(tofree); - break; + free(tofree); + continue; } // If you want to extract absolute paths, "cd /" and run cpio. @@ -283,9 +297,8 @@ void cpio_main(void) } if (CFG_TOYBOX_FREE) free(name); - memset(toybuf, 0, sizeof(toybuf)); - xwrite(afd, toybuf, - sprintf(toybuf, "070701%040X%056X%08XTRAILER!!!", 1, 0x0b, 0)+4); + // nlink=1, namesize=11, with padding + dprintf(afd, "070701%040X%056X%08XTRAILER!!!%c%c%c%c", 1, 11, 0, 0, 0, 0,0); } if (TT.F) xclose(afd); |