From 63d9da322f438a98bb654cc4976874fa89f1fa62 Mon Sep 17 00:00:00 2001 From: Alison Winters Date: Sat, 27 Feb 2021 15:18:45 -0800 Subject: vi: restore 0 offset after :set noXXX command Fixes bug where commands after the first noXXX command are ignored. e.g. :set noic tabstop=4 While at it, stop recognizing "notabstop=NNN". function old new delta colon 2990 2965 -25 Signed-off-by: Alison Winters Signed-off-by: Denys Vlasenko --- editors/vi.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/editors/vi.c b/editors/vi.c index 458ca6293..e77c348fb 100644 --- a/editors/vi.c +++ b/editors/vi.c @@ -2709,7 +2709,6 @@ static void colon(char *buf) # if ENABLE_FEATURE_VI_SETOPTS char *argp; # endif - i = 0; // offset into args // only blank is regarded as args delimiter. What about tab '\t'? if (!args[0] || strcasecmp(args, "all") == 0) { // print out values of all options @@ -2732,15 +2731,16 @@ static void colon(char *buf) # if ENABLE_FEATURE_VI_SETOPTS argp = args; while (*argp) { - if (strncmp(argp, "no", 2) == 0) - i = 2; // ":set noautoindent" + i = 0; + if (argp[0] == 'n' && argp[1] == 'o') // "noXXX" + i = 2; setops(argp, "autoindent ", i, "ai", VI_AUTOINDENT); setops(argp, "flash " , i, "fl", VI_ERR_METHOD); setops(argp, "ignorecase ", i, "ic", VI_IGNORECASE); setops(argp, "showmatch " , i, "sm", VI_SHOWMATCH ); - if (strncmp(argp + i, "tabstop=", 8) == 0) { + if (strncmp(argp, "tabstop=", 8) == 0) { int t = 0; - sscanf(argp + i+8, "%u", &t); + sscanf(argp + 8, "%u", &t); if (t > 0 && t <= MAX_TABSTOP) tabstop = t; } -- cgit v1.2.3-55-g6feb From 70ee23399cb2c77dec0b6ad3b6030f7cf3105b8f Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Mon, 1 Mar 2021 14:41:39 +0100 Subject: vi: code shrink function old new delta setops 85 73 -12 colon 2965 2915 -50 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 0/2 up/down: 0/-62) Total: -62 bytes Signed-off-by: Denys Vlasenko --- editors/vi.c | 32 ++++++++++++++------------------ 1 file changed, 14 insertions(+), 18 deletions(-) diff --git a/editors/vi.c b/editors/vi.c index e77c348fb..abc0aeae8 100644 --- a/editors/vi.c +++ b/editors/vi.c @@ -2258,7 +2258,7 @@ static char *get_one_address(char *p, int *addr) // get colon addr, if present q = begin_line(dot); *addr = count_lines(text, q); } -#if ENABLE_FEATURE_VI_YANKMARK +# if ENABLE_FEATURE_VI_YANKMARK else if (*p == '\'') { // is this a mark addr p++; c = tolower(*p); @@ -2272,8 +2272,8 @@ static char *get_one_address(char *p, int *addr) // get colon addr, if present } } } -#endif -#if ENABLE_FEATURE_VI_SEARCH +# endif +# if ENABLE_FEATURE_VI_SEARCH else if (*p == '/') { // a search pattern q = strchrnul(p + 1, '/'); if (p + 1 != q) { @@ -2290,7 +2290,7 @@ static char *get_one_address(char *p, int *addr) // get colon addr, if present *addr = count_lines(text, q); } } -#endif +# endif else if (*p == '$') { // the last line in file p++; q = begin_line(end - 1); @@ -2333,16 +2333,13 @@ static char *get_address(char *p, int *b, int *e) // get two colon addrs, if pre return p; } -#if ENABLE_FEATURE_VI_SET && ENABLE_FEATURE_VI_SETOPTS -static void setops(const char *args, const char *opname, int flg_no, - const char *short_opname, int opt) +# if ENABLE_FEATURE_VI_SET && ENABLE_FEATURE_VI_SETOPTS +static void setops(const char *args, const char *nm_longname, int flg_no, int opt) { const char *a = args + flg_no; - int l = strlen(opname) - 1; // opname have + ' ' - // maybe strncmp? we had tons of erroneous strncasecmp's... - if (strncasecmp(a, opname, l) == 0 - || strncasecmp(a, short_opname, 2) == 0 + if (strcmp(a, nm_longname) == 0 + || strcmp(a, nm_longname + 3) == 0 ) { if (flg_no) vi_setops &= ~opt; @@ -2350,7 +2347,7 @@ static void setops(const char *args, const char *opname, int flg_no, vi_setops |= opt; } } -#endif +# endif #endif /* FEATURE_VI_COLON */ @@ -2734,13 +2731,12 @@ static void colon(char *buf) i = 0; if (argp[0] == 'n' && argp[1] == 'o') // "noXXX" i = 2; - setops(argp, "autoindent ", i, "ai", VI_AUTOINDENT); - setops(argp, "flash " , i, "fl", VI_ERR_METHOD); - setops(argp, "ignorecase ", i, "ic", VI_IGNORECASE); - setops(argp, "showmatch " , i, "sm", VI_SHOWMATCH ); + setops(argp, "ai""\0""autoindent", i, VI_AUTOINDENT); + setops(argp, "fl""\0""flash" , i, VI_ERR_METHOD); + setops(argp, "ic""\0""ignorecase", i, VI_IGNORECASE); + setops(argp, "sm""\0""showmatch" , i, VI_SHOWMATCH ); if (strncmp(argp, "tabstop=", 8) == 0) { - int t = 0; - sscanf(argp + 8, "%u", &t); + int t = bb_strtou(argp + 8, NULL, 10); if (t > 0 && t <= MAX_TABSTOP) tabstop = t; } -- cgit v1.2.3-55-g6feb From 2d6c175d9b8b0c8eedda2f9bcf1b96a8117ab441 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Tue, 2 Mar 2021 12:07:14 +0100 Subject: ntpd: decrease INITIAL_SAMPLES from 4 to 3 This reduces initial traffic to NTP servers when a lot of devices boot at once. Log inspection tells me we agressively burst-poll servers about 5 times at startup, even though we usually already update clock after second replies. INITIAL_SAMPLES can probably be even lower, e.g. 2, but let's be conservative when changing this stuff. Signed-off-by: Denys Vlasenko --- networking/ntpd.c | 27 ++++++++++++--------------- 1 file changed, 12 insertions(+), 15 deletions(-) diff --git a/networking/ntpd.c b/networking/ntpd.c index 9c15999f3..caf5cc299 100644 --- a/networking/ntpd.c +++ b/networking/ntpd.c @@ -169,7 +169,7 @@ * datapoints after the step. */ -#define INITIAL_SAMPLES 4 /* how many samples do we want for init */ +#define INITIAL_SAMPLES 3 /* how many samples do we want for init */ #define MIN_FREQHOLD 10 /* adjust offset, but not freq in this many first adjustments */ #define BAD_DELAY_GROWTH 4 /* drop packet if its delay grew by more than this factor */ @@ -223,7 +223,16 @@ #define MIN_SELECTED 1 /* minimum intersection survivors */ #define MIN_CLUSTERED 3 /* minimum cluster survivors */ -#define MAXDRIFT 0.000500 /* frequency drift we can correct (500 PPM) */ +/* Correct frequency ourself (0) or let kernel do it (1)? */ +#define USING_KERNEL_PLL_LOOP 1 +// /* frequency drift we can correct (500 PPM) */ +// #define MAXDRIFT 0.000500 +// /* Compromise Allan intercept (sec). doc uses 1500, std ntpd uses 512 */ +// #define ALLAN 512 +// /* PLL loop gain */ +// #define PLL 65536 +// /* FLL loop gain [why it depends on MAXPOLL??] */ +// #define FLL (MAXPOLL + 1) /* Poll-adjust threshold. * When we see that offset is small enough compared to discipline jitter, @@ -239,12 +248,6 @@ */ #define POLLADJ_GATE 4 #define TIMECONST_HACK_GATE 2 -/* Compromise Allan intercept (sec). doc uses 1500, std ntpd uses 512 */ -#define ALLAN 512 -/* PLL loop gain */ -#define PLL 65536 -/* FLL loop gain [why it depends on MAXPOLL??] */ -#define FLL (MAXPOLL + 1) /* Parameter averaging constant */ #define AVG 4 @@ -372,9 +375,6 @@ typedef struct { char p_hostname[1]; } peer_t; - -#define USING_KERNEL_PLL_LOOP 1 - enum { OPT_n = (1 << 0), OPT_q = (1 << 1), @@ -453,7 +453,7 @@ struct globals { */ #define G_precision_exp -9 /* - * G_precision_exp is used only for construction outgoing packets. + * G_precision_exp is used only for constructing outgoing packets. * It's ok to set G_precision_sec to a slightly different value * (One which is "nicer looking" in logs). * Exact value would be (1.0 / (1 << (- G_precision_exp))): @@ -484,7 +484,6 @@ struct globals { }; #define G (*ptr_to_globals) - #define VERB1 if (MAX_VERBOSE && G.verbose) #define VERB2 if (MAX_VERBOSE >= 2 && G.verbose >= 2) #define VERB3 if (MAX_VERBOSE >= 3 && G.verbose >= 3) @@ -989,7 +988,6 @@ send_query_to_peer(peer_t *p) set_next(p, RESPONSE_INTERVAL); } - /* Note that there is no provision to prevent several run_scripts * to be started in quick succession. In fact, it happens rather often * if initial syncronization results in a step. @@ -1767,7 +1765,6 @@ update_local_clock(peer_t *p) return 1; /* "ok to increase poll interval" */ } - /* * We've got a new reply packet from a peer, process it * (helpers first) -- cgit v1.2.3-55-g6feb From 2d48d9b1cca7745a514f8cf770308ceb48edb195 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Tue, 2 Mar 2021 19:54:09 +0100 Subject: ntpd: tweak comments Signed-off-by: Denys Vlasenko --- networking/ntpd.c | 32 +++++++++----------------------- 1 file changed, 9 insertions(+), 23 deletions(-) diff --git a/networking/ntpd.c b/networking/ntpd.c index caf5cc299..0f350fa6f 100644 --- a/networking/ntpd.c +++ b/networking/ntpd.c @@ -127,24 +127,15 @@ */ #define MAX_VERBOSE 3 - /* High-level description of the algorithm: * * We start running with very small poll_exp, BURSTPOLL, * in order to quickly accumulate INITIAL_SAMPLES datapoints * for each peer. Then, time is stepped if the offset is larger - * than STEP_THRESHOLD, otherwise it isn't; anyway, we enlarge - * poll_exp to MINPOLL and enter frequency measurement step: - * we collect new datapoints but ignore them for WATCH_THRESHOLD - * seconds. After WATCH_THRESHOLD seconds we look at accumulated - * offset and estimate frequency drift. - * - * (frequency measurement step seems to not be strictly needed, - * it is conditionally disabled with USING_INITIAL_FREQ_ESTIMATION - * define set to 0) + * than STEP_THRESHOLD, otherwise it isn't stepped. * - * After this, we enter "steady state": we collect a datapoint, - * we select the best peer, if this datapoint is not a new one + * Then poll_exp is set to MINPOLL, and we enter "steady state": we collect + * a datapoint, we select the best peer, if this datapoint is not a new one * (IOW: if this datapoint isn't for selected peer), sleep * and collect another one; otherwise, use its offset to update * frequency drift, if offset is somewhat large, reduce poll_exp, @@ -189,13 +180,10 @@ // ^^^^ used to be 0.125. // Since Linux 2.6.26 (circa 2006), kernel accepts (-0.5s, +0.5s) range -/* Stepout threshold (sec). std ntpd uses 900 (11 mins (!)) */ -//UNUSED: #define WATCH_THRESHOLD 128 -/* NB: set WATCH_THRESHOLD to ~60 when debugging to save time) */ -//UNUSED: #define PANIC_THRESHOLD 1000 /* panic threshold (sec) */ -/* - * If we got |offset| > BIGOFF from a peer, cap next query interval +// #define PANIC_THRESHOLD 1000 /* panic threshold (sec) */ + +/* If we got |offset| > BIGOFF from a peer, cap next query interval * for this peer by this many seconds: */ #define BIGOFF STEP_THRESHOLD @@ -204,18 +192,16 @@ #define FREQ_TOLERANCE 0.000015 /* frequency tolerance (15 PPM) */ #define BURSTPOLL 0 /* initial poll */ #define MINPOLL 5 /* minimum poll interval. std ntpd uses 6 (6: 64 sec) */ -/* - * If offset > discipline_jitter * POLLADJ_GATE, and poll interval is > 2^BIGPOLL, +/* If offset > discipline_jitter * POLLADJ_GATE, and poll interval is > 2^BIGPOLL, * then it is decreased _at once_. (If <= 2^BIGPOLL, it will be decreased _eventually_). */ #define BIGPOLL 9 /* 2^9 sec ~= 8.5 min */ #define MAXPOLL 12 /* maximum poll interval (12: 1.1h, 17: 36.4h). std ntpd uses 17 */ -/* - * Actively lower poll when we see such big offsets. +/* Actively lower poll when we see such big offsets. * With SLEW_THRESHOLD = 0.125, it means we try to sync more aggressively * if offset increases over ~0.04 sec */ -//#define POLLDOWN_OFFSET (SLEW_THRESHOLD / 3) +// #define POLLDOWN_OFFSET (SLEW_THRESHOLD / 3) #define MINDISP 0.01 /* minimum dispersion (sec) */ #define MAXDISP 16 /* maximum dispersion (sec) */ #define MAXSTRAT 16 /* maximum stratum (infinity metric) */ -- cgit v1.2.3-55-g6feb From 307cd26e9893ed0cf6ee88e7fca2d61d3da0e139 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Tue, 9 Mar 2021 01:12:18 +0100 Subject: start-stop-daemon: explain -x + -a test Signed-off-by: Denys Vlasenko --- testsuite/start-stop-daemon.tests | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/testsuite/start-stop-daemon.tests b/testsuite/start-stop-daemon.tests index 2ddb7fefb..0757b1288 100755 --- a/testsuite/start-stop-daemon.tests +++ b/testsuite/start-stop-daemon.tests @@ -21,8 +21,13 @@ testing "start-stop-daemon without -x and -a" \ "1\n" \ "" "" +# This runs /bin/false with argv[0..2] of { "qwerty", "false", NULL }. +# # Unfortunately, this does not actually check argv[0] correctness, # but at least it checks that pathname to exec() is correct +# +# NB: this fails if /bin/false is a busybox symlink: +# busybox looks at argv[0] and says "qwerty: applet not found" testing "start-stop-daemon with both -x and -a" \ 'start-stop-daemon -S -x /bin/false -a qwerty false 2>&1; echo $?' \ "1\n" \ -- cgit v1.2.3-55-g6feb From 0b25e810ed73334d30f99ba7073f21369b33ab18 Mon Sep 17 00:00:00 2001 From: Ron Yorston Date: Mon, 8 Mar 2021 19:30:57 +0000 Subject: bloat-o-meter: avoid double counting Disable 'echo' in the default config, run 'make baseline', then re-enable 'echo' and run 'make bloatcheck': function old new delta .rodata 182521 182622 +101 packed_usage 33714 33792 +78 applet_main 3168 3176 +8 applet_names 2730 2735 +5 applet_suid 99 100 +1 applet_install_loc 198 199 +1 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 6/0 up/down: 194/0) Total: 194 bytes text data bss dec hex filename 955052 4195 1808 961055 eaa1f busybox_old 955153 4195 1808 961156 eaa84 busybox_unstripped The Total bytes value doesn't equal the change in the size of the binary. The packed_usage and applet_* items are in .rodata and are counted twice. With this modified bloat-o-meter the size of named items is deducted from .rodata: function old new delta packed_usage 33714 33792 +78 applet_main 3168 3176 +8 .rodata 105105 105113 +8 applet_names 2730 2735 +5 applet_suid 99 100 +1 applet_install_loc 198 199 +1 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 6/0 up/down: 101/0) Total: 101 bytes text data bss dec hex filename 955052 4195 1808 961055 eaa1f busybox_old 955153 4195 1808 961156 eaa84 busybox_unstripped v2: Sections numbered less than 10 were always being omitted from consideration because splitting "[ 1] .interp" leaves "1]" in x[1] where the section name is expected. This wasn't a problem for .rodata (numbered 15 in my testing) but let's fix it anyway. Signed-off-by: Ron Yorston Signed-off-by: Denys Vlasenko --- scripts/bloat-o-meter | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/scripts/bloat-o-meter b/scripts/bloat-o-meter index cb861b8e9..b4a1d2811 100755 --- a/scripts/bloat-o-meter +++ b/scripts/bloat-o-meter @@ -43,7 +43,15 @@ if f1 is None or f2 is None: sym_args = " ".join(sys.argv[3 + flag_timing + dashes:]) def getsizes(file): - sym, alias, lut = {}, {}, {} + sym, alias, lut, section = {}, {}, {}, {} + for l in os.popen("readelf -W -S " + file).readlines(): + x = l.replace("[ ", "[", 1).split() + if len(x)<6: continue + # Should take these into account too! + #if x[1] not in [".text", ".rodata", ".symtab", ".strtab"]: continue + if x[1] not in [".rodata"]: continue + sym[x[1]] = {"addr" : int(x[3], 16), "size" : int(x[5], 16)} + section[x[0][1:-1]] = {"name" : x[1]} for l in os.popen("readelf -W -s %s %s" % (sym_args, file)).readlines(): l = l.strip() if not (len(l) and l[0].isdigit() and len(l.split()) == 8): @@ -59,6 +67,10 @@ def getsizes(file): else: sym[name] = {"addr" : value, "size": size} lut[(value, size)] = 0 + # If this item is in a known section deduct its size from + # the size of the section + if ndx in section: + sym[section[ndx]["name"]]["size"] -= size for addr, sz in iter(alias.keys()): # If the non-GLOBAL sym has an implementation elsewhere then # it's an alias, disregard it. @@ -66,13 +78,6 @@ def getsizes(file): # If this non-GLOBAL sym does not have an implementation at # another address, then treat it as a normal symbol. sym[alias[(addr, sz)]["name"]] = {"addr" : addr, "size": sz} - for l in os.popen("readelf -W -S " + file).readlines(): - x = l.split() - if len(x)<6: continue - # Should take these into account too! - #if x[1] not in [".text", ".rodata", ".symtab", ".strtab"]: continue - if x[1] not in [".rodata"]: continue - sym[x[1]] = {"addr" : int(x[3], 16), "size" : int(x[5], 16)} return sym if flag_timing: -- cgit v1.2.3-55-g6feb From b6e6c83ab301ac92f649d63f5cfe0fddde3d142e Mon Sep 17 00:00:00 2001 From: Sergey Ponomarev Date: Sun, 17 Jan 2021 20:35:08 +0200 Subject: wget: new option FEATURE_WGET_FTP to enable/disable FTP Introduce a separate option FTPS_SUPPORTED instead of not obvious ENABLE_FEATURE_WGET_HTTPS. function old new delta P_FTP 4 - -4 P_FTPS 5 - -5 reset_beg_range_to_zero 41 - -41 parse_url 431 366 -65 parse_pasv_epsv 154 - -154 .rodata 115566 115408 -158 ftpcmd 204 - -204 spawn_ssl_client 291 - -291 wget_main 2998 2664 -334 ------------------------------------------------------------------------------ (add/remove: 0/7 grow/shrink: 0/3 up/down: 0/-1256) Total: -1256 bytes Signed-off-by: Sergey Ponomarev Signed-off-by: Denys Vlasenko --- networking/wget.c | 50 +++++++++++++++++++++++++++++++++++--------------- 1 file changed, 35 insertions(+), 15 deletions(-) diff --git a/networking/wget.c b/networking/wget.c index e660c279c..3edc5f870 100644 --- a/networking/wget.c +++ b/networking/wget.c @@ -25,6 +25,13 @@ //config: default y //config: depends on WGET //config: +//config:config FEATURE_WGET_FTP +//config: bool "Enable FTP protocol (+1k)" +//config: default y +//config: depends on WGET +//config: help +//config: To support FTPS, enable FEATURE_WGET_HTTPS as well. +//config: //config:config FEATURE_WGET_AUTHENTICATION //config: bool "Enable HTTP authentication" //config: default y @@ -48,12 +55,12 @@ //config: //config:config FEATURE_WGET_HTTPS //config: bool "Support HTTPS using internal TLS code" -//it also enables FTPS support, but it's not well tested yet //config: default y //config: depends on WGET //config: select TLS //config: help //config: wget will use internal TLS code to connect to https:// URLs. +//config: It also enables FTPS support, but it's not well tested yet. //config: Note: //config: On NOMMU machines, ssl_helper applet should be available //config: in the $PATH for this to work. Make sure to select that applet. @@ -173,6 +180,7 @@ #define SSL_SUPPORTED (ENABLE_FEATURE_WGET_OPENSSL || ENABLE_FEATURE_WGET_HTTPS) +#define FTPS_SUPPORTED (ENABLE_FEATURE_WGET_FTP && ENABLE_FEATURE_WGET_HTTPS) struct host_info { char *allocated; @@ -182,14 +190,16 @@ struct host_info { char *host; int port; }; -static const char P_FTP[] ALIGN1 = "ftp"; static const char P_HTTP[] ALIGN1 = "http"; #if SSL_SUPPORTED -# if ENABLE_FEATURE_WGET_HTTPS -static const char P_FTPS[] ALIGN1 = "ftps"; -# endif static const char P_HTTPS[] ALIGN1 = "https"; #endif +#if ENABLE_FEATURE_WGET_FTP +static const char P_FTP[] ALIGN1 = "ftp"; +#endif +#if FTPS_SUPPORTED +static const char P_FTPS[] ALIGN1 = "ftps"; +#endif #if ENABLE_FEATURE_WGET_LONG_OPTIONS /* User-specified headers prevent using our corresponding built-in headers. */ @@ -482,6 +492,7 @@ static char fgets_trim_sanitize(FILE *fp, const char *fmt) return c; } +#if ENABLE_FEATURE_WGET_FTP static int ftpcmd(const char *s1, const char *s2, FILE *fp) { int result; @@ -507,6 +518,7 @@ static int ftpcmd(const char *s1, const char *s2, FILE *fp) G.wget_buf[3] = ' '; return result; } +#endif static void parse_url(const char *src_url, struct host_info *h) { @@ -515,30 +527,31 @@ static void parse_url(const char *src_url, struct host_info *h) free(h->allocated); h->allocated = url = xstrdup(src_url); - h->protocol = P_FTP; + h->protocol = P_HTTP; p = strstr(url, "://"); if (p) { *p = '\0'; h->host = p + 3; +#if ENABLE_FEATURE_WGET_FTP if (strcmp(url, P_FTP) == 0) { h->port = bb_lookup_std_port(P_FTP, "tcp", 21); + h->protocol = P_FTP; } else -#if SSL_SUPPORTED -# if ENABLE_FEATURE_WGET_HTTPS +#endif +#if FTPS_SUPPORTED if (strcmp(url, P_FTPS) == 0) { h->port = bb_lookup_std_port(P_FTPS, "tcp", 990); h->protocol = P_FTPS; } else -# endif +#endif +#if SSL_SUPPORTED if (strcmp(url, P_HTTPS) == 0) { h->port = bb_lookup_std_port(P_HTTPS, "tcp", 443); h->protocol = P_HTTPS; } else #endif if (strcmp(url, P_HTTP) == 0) { - http: - h->port = bb_lookup_std_port(P_HTTP, "tcp", 80); - h->protocol = P_HTTP; + goto http; } else { *p = ':'; bb_error_msg_and_die("not an http or ftp url: %s", url); @@ -546,7 +559,8 @@ static void parse_url(const char *src_url, struct host_info *h) } else { // GNU wget is user-friendly and falls back to http:// h->host = url; - goto http; + http: + h->port = bb_lookup_std_port(P_HTTP, "tcp", 80); } // FYI: @@ -796,6 +810,7 @@ static void spawn_ssl_client(const char *host, int network_fd, int flags) } #endif +#if ENABLE_FEATURE_WGET_FTP static FILE* prepare_ftp_session(FILE **dfpp, struct host_info *target, len_and_sockaddr *lsa) { FILE *sfp; @@ -803,7 +818,7 @@ static FILE* prepare_ftp_session(FILE **dfpp, struct host_info *target, len_and_ int port; sfp = open_socket(lsa); -#if ENABLE_FEATURE_WGET_HTTPS +#if FTPS_SUPPORTED if (target->protocol == P_FTPS) spawn_ssl_client(target->host, fileno(sfp), TLSLOOP_EXIT_ON_LOCAL_EOF); #endif @@ -859,7 +874,7 @@ static FILE* prepare_ftp_session(FILE **dfpp, struct host_info *target, len_and_ *dfpp = open_socket(lsa); -#if ENABLE_FEATURE_WGET_HTTPS +#if FTPS_SUPPORTED if (target->protocol == P_FTPS) { /* "PROT P" enables encryption of data stream. * Without it (or with "PROT C"), data is sent unencrypted. @@ -885,6 +900,7 @@ static FILE* prepare_ftp_session(FILE **dfpp, struct host_info *target, len_and_ return sfp; } +#endif static void NOINLINE retrieve_file_data(FILE *dfp) { @@ -1407,10 +1423,12 @@ However, in real world it was observed that some web servers /* For HTTP, data is pumped over the same connection */ dfp = sfp; } else { +#if ENABLE_FEATURE_WGET_FTP /* * FTP session */ sfp = prepare_ftp_session(&dfp, &target, lsa); +#endif } free(lsa); @@ -1428,6 +1446,7 @@ However, in real world it was observed that some web servers fprintf(stderr, "remote file exists\n"); } +#if ENABLE_FEATURE_WGET_FTP if (dfp != sfp) { /* It's ftp. Close data connection properly */ fclose(dfp); @@ -1435,6 +1454,7 @@ However, in real world it was observed that some web servers bb_error_msg_and_die("ftp error: %s", G.wget_buf); /* ftpcmd("QUIT", NULL, sfp); - why bother? */ } +#endif fclose(sfp); free(server.allocated); -- cgit v1.2.3-55-g6feb From cbfdeba6609b702432886ecf3e2786818a2bc55b Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Wed, 10 Mar 2021 16:31:05 +0100 Subject: hush: make LINENO selectable without BASH-COMPAT Signed-off-by: Denys Vlasenko --- shell/hush.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/shell/hush.c b/shell/hush.c index 5eb6fa396..7cc678f3c 100644 --- a/shell/hush.c +++ b/shell/hush.c @@ -127,11 +127,6 @@ //config: help //config: Enable {abc,def} extension. //config: -//config:config HUSH_LINENO_VAR -//config: bool "$LINENO variable" -//config: default y -//config: depends on HUSH_BASH_COMPAT -//config: //config:config HUSH_BASH_SOURCE_CURDIR //config: bool "'source' and '.' builtins search current directory after $PATH" //config: default n # do not encourage non-standard behavior @@ -139,6 +134,11 @@ //config: help //config: This is not compliant with standards. Avoid if possible. //config: +//config:config HUSH_LINENO_VAR +//config: bool "$LINENO variable (bashism)" +//config: default y +//config: depends on SHELL_HUSH +//config: //config:config HUSH_INTERACTIVE //config: bool "Interactive mode" //config: default y -- cgit v1.2.3-55-g6feb From f25d254dfd4243698c31a4f3153d4ac72aa9e9bd Mon Sep 17 00:00:00 2001 From: Samuel Sapalski Date: Wed, 3 Mar 2021 16:31:22 +0100 Subject: decompress_gunzip: Fix DoS if gzip is corrupt On certain corrupt gzip files, huft_build will set the error bit on the result pointer. If afterwards abort_unzip is called huft_free might run into a segmentation fault or an invalid pointer to free(p). In order to mitigate this, we check in huft_free if the error bit is set and clear it before the linked list is freed. Signed-off-by: Samuel Sapalski Signed-off-by: Peter Kaestle Signed-off-by: Denys Vlasenko --- archival/libarchive/decompress_gunzip.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/archival/libarchive/decompress_gunzip.c b/archival/libarchive/decompress_gunzip.c index eb3b64930..e93cd5005 100644 --- a/archival/libarchive/decompress_gunzip.c +++ b/archival/libarchive/decompress_gunzip.c @@ -220,10 +220,20 @@ static const uint8_t border[] ALIGN1 = { * each table. * t: table to free */ +#define BAD_HUFT(p) ((uintptr_t)(p) & 1) +#define ERR_RET ((huft_t*)(uintptr_t)1) static void huft_free(huft_t *p) { huft_t *q; + /* + * If 'p' has the error bit set we have to clear it, otherwise we might run + * into a segmentation fault or an invalid pointer to free(p) + */ + if (BAD_HUFT(p)) { + p = (huft_t*)((uintptr_t)(p) ^ (uintptr_t)(ERR_RET)); + } + /* Go through linked list, freeing from the malloced (t[-1]) address. */ while (p) { q = (--p)->v.t; @@ -289,8 +299,6 @@ static unsigned fill_bitbuffer(STATE_PARAM unsigned bitbuffer, unsigned *current * or a valid pointer to a Huffman table, ORed with 0x1 if incompete table * is given: "fixed inflate" decoder feeds us such data. */ -#define BAD_HUFT(p) ((uintptr_t)(p) & 1) -#define ERR_RET ((huft_t*)(uintptr_t)1) static huft_t* huft_build(const unsigned *b, const unsigned n, const unsigned s, const struct cp_ext *cp_ext, unsigned *m) -- cgit v1.2.3-55-g6feb From f26e5634b161e58f56b072f6e703f262e723a80d Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Mon, 15 Mar 2021 17:42:25 +0100 Subject: echo: special case "echo --help": it should not show help text While at it, fix "busybox --help echo" and other special applets to still print the help text. function old new delta run_applet_and_exit 732 761 +29 show_usage_if_dash_dash_help 70 78 +8 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 2/0 up/down: 37/0) Total: 37 bytes Signed-off-by: Denys Vlasenko --- libbb/appletlib.c | 30 ++++++++++++++++++++++-------- 1 file changed, 22 insertions(+), 8 deletions(-) diff --git a/libbb/appletlib.c b/libbb/appletlib.c index 67c540abb..2feed64dd 100644 --- a/libbb/appletlib.c +++ b/libbb/appletlib.c @@ -263,9 +263,14 @@ void lbb_prepare(const char *applet && strcmp(argv[1], "--help") == 0 && !is_prefixed_with(applet, "busybox") ) { - /* Special case. POSIX says "test --help" - * should be no different from e.g. "test --foo". */ - if (!ENABLE_TEST || strcmp(applet_name, "test") != 0) + /* Special cases. POSIX says "test --help" + * should be no different from e.g. "test --foo". + */ + if (!(ENABLE_TEST && strcmp(applet_name, "test") == 0) + && !(ENABLE_TRUE && strcmp(applet_name, "true") == 0) + && !(ENABLE_FALSE && strcmp(applet_name, "false") == 0) + && !(ENABLE_ECHO && strcmp(applet_name, "echo") == 0) + ) bb_show_usage(); } #endif @@ -891,15 +896,21 @@ int busybox_main(int argc UNUSED_PARAM, char **argv) if (!argv[2]) goto help; /* convert to " --help" */ - argv[0] = argv[2]; + applet_name = argv[0] = argv[2]; argv[2] = NULL; + if (find_applet_by_name(applet_name) >= 0) { + /* Make "--help foo" exit with 0: */ + xfunc_error_retval = 0; + bb_show_usage(); + } /* else: unknown applet, fall through (causes "applet not found" later) */ } else { /* "busybox arg1 arg2 ..." */ argv++; + /* We support "busybox /a/path/to/applet args..." too. Allows for + * "#!/bin/busybox"-style wrappers + */ + applet_name = bb_get_last_path_component_nostrip(argv[0]); } - /* We support "busybox /a/path/to/applet args..." too. Allows for - * "#!/bin/busybox"-style wrappers */ - applet_name = bb_get_last_path_component_nostrip(argv[0]); run_applet_and_exit(applet_name, argv); } # endif @@ -910,7 +921,7 @@ void FAST_FUNC show_usage_if_dash_dash_help(int applet_no, char **argv) /* Special case. POSIX says "test --help" * should be no different from e.g. "test --foo". * Thus for "test", we skip --help check. - * "true" and "false" are also special. + * "true", "false", "echo" are also special. */ if (1 # if defined APPLET_NO_test @@ -921,6 +932,9 @@ void FAST_FUNC show_usage_if_dash_dash_help(int applet_no, char **argv) # endif # if defined APPLET_NO_false && applet_no != APPLET_NO_false +# endif +# if defined APPLET_NO_echo + && applet_no != APPLET_NO_echo # endif ) { if (argv[1] && !argv[2] && strcmp(argv[1], "--help") == 0) { -- cgit v1.2.3-55-g6feb From 1c461df70ab357dc9e1e064540731c58e7859a45 Mon Sep 17 00:00:00 2001 From: Russell Senior Date: Mon, 15 Mar 2021 22:42:43 -0700 Subject: udhcpc: ignore zero-length DHCP options Discovered that the DHCP server on a TrendNet router (unknown model) provides a zero-length option 12 (Host Name) in the DHCP ACK message. This has the effect of causing udhcpc to drop the rest of the options, including option 51 (IP Address Lease Time), 3 (Router), and 6 (Domain Name Server), most importantly leaving the OpenWrt device with no default gateway. The TrendNet behavior violates RFC 2132, which in Section 3.14 declares that option 12 has a minimum length of 1 octet. It is perhaps not a cosmic coincidence that I found this behavior on Pi Day. This patch allows zero length options without bailing out, by simply skipping them. function old new delta udhcp_scan_options 183 172 -11 Signed-off-by: Russell Senior Signed-off-by: Denys Vlasenko --- networking/udhcp/common.c | 26 ++++++++++++++++++-------- 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/networking/udhcp/common.c b/networking/udhcp/common.c index 4bc719001..99ecb7aa6 100644 --- a/networking/udhcp/common.c +++ b/networking/udhcp/common.c @@ -273,17 +273,27 @@ uint8_t* FAST_FUNC udhcp_scan_options(struct dhcp_packet *packet, struct dhcp_sc break; } - if (scan_state->rem <= OPT_LEN) - goto complain; /* complain and return NULL */ - len = 2 + scan_state->optionptr[OPT_LEN]; + if (scan_state->rem <= OPT_LEN) /* [len] byte exists? */ + goto complain; /* no, complain and return NULL */ + len = scan_state->optionptr[OPT_LEN]; + /* Skip options with zero length. + * Users report that DHCP server on a TrendNet router (unknown model) + * provides a zero-length option 12 (Host Name) + * (this violates RFC 2132 section 3.14). + */ + if (len == 0) { + scan_state->rem -= OPT_LEN; + scan_state->optionptr += OPT_LEN; + continue; + } + len += OPT_LEN; scan_state->rem -= len; - /* So far no valid option with length 0 known. */ - if (scan_state->rem < 0 || scan_state->optionptr[OPT_LEN] == 0) - goto complain; /* complain and return NULL */ + if (scan_state->rem < 0) /* option is longer than options field? */ + goto complain; /* yes, complain and return NULL */ if (scan_state->optionptr[OPT_CODE] == DHCP_OPTION_OVERLOAD) { - if (len >= 3) - scan_state->overload |= scan_state->optionptr[OPT_DATA]; + /* len is known to be >= 3 now, [data] byte exists */ + scan_state->overload |= scan_state->optionptr[OPT_DATA]; } else { uint8_t *return_ptr = scan_state->optionptr; scan_state->optionptr += len; -- cgit v1.2.3-55-g6feb From fe78d70ec6c48f88126f6deffe04d4707a65c9ac Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Tue, 16 Mar 2021 11:42:56 +0100 Subject: udhcpc: ignore zero-length DHCP options, take 2 advance the optionptr by two bytes, not one Signed-off-by: Denys Vlasenko --- networking/udhcp/common.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/networking/udhcp/common.c b/networking/udhcp/common.c index 99ecb7aa6..f2d6907ad 100644 --- a/networking/udhcp/common.c +++ b/networking/udhcp/common.c @@ -282,11 +282,11 @@ uint8_t* FAST_FUNC udhcp_scan_options(struct dhcp_packet *packet, struct dhcp_sc * (this violates RFC 2132 section 3.14). */ if (len == 0) { - scan_state->rem -= OPT_LEN; - scan_state->optionptr += OPT_LEN; + scan_state->rem -= 2; + scan_state->optionptr += 2; continue; } - len += OPT_LEN; + len += 2; scan_state->rem -= len; if (scan_state->rem < 0) /* option is longer than options field? */ goto complain; /* yes, complain and return NULL */ -- cgit v1.2.3-55-g6feb From 2a2ca935309bfacbc7f87de752f869a89748052c Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Fri, 19 Mar 2021 00:27:44 +0100 Subject: login: implement LOGIN_TIMEOUT function old new delta packed_usage 33559 33598 +39 login_main 953 986 +33 .rodata 103161 103175 +14 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 3/0 up/down: 86/0) Total: 86 bytes Signed-off-by: Denys Vlasenko --- loginutils/login.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/loginutils/login.c b/loginutils/login.c index 21c32fc25..66ac7cf4c 100644 --- a/loginutils/login.c +++ b/loginutils/login.c @@ -60,6 +60,11 @@ //usage: "\n -f Don't authenticate (user already authenticated)" //usage: "\n -h HOST Host user came from (for network logins)" //usage: "\n -p Preserve environment" +//usage: "\n" +//usage: "\n$LOGIN_TIMEOUT Seconds (default 60, 0 - disable)" +//usage: IF_LOGIN_SCRIPTS( +//usage: "\n$LOGIN_PRE_SUID_SCRIPT Execute before user ID change" +//usage: ) #include "libbb.h" #include "common_bufsiz.h" @@ -130,7 +135,6 @@ static const struct pam_conv conv = { #endif enum { - TIMEOUT = 60, EMPTY_USERNAME_COUNT = 10, /* Some users found 32 chars limit to be too low: */ USERNAME_SIZE = 64, @@ -139,6 +143,7 @@ enum { struct globals { struct termios tty_attrs; + int timeout; } FIX_ALIASING; #define G (*(struct globals*)bb_common_bufsiz1) #define INIT_G() do { setup_common_bufsiz(); } while (0) @@ -302,7 +307,7 @@ static void alarm_handler(int sig UNUSED_PARAM) * when you are back at shell prompt, echo will be still off. */ tcsetattr_stdin_TCSANOW(&G.tty_attrs); - printf("\r\nLogin timed out after %u seconds\r\n", TIMEOUT); + printf("\r\nLogin timed out after %u seconds\r\n", G.timeout); fflush_all(); /* unix API is brain damaged regarding O_NONBLOCK, * we should undo it, or else we can affect other processes */ @@ -345,6 +350,8 @@ int login_main(int argc UNUSED_PARAM, char **argv) INIT_G(); + G.timeout = xatoi_positive(getenv("LOGIN_TIMEOUT") ? : "60"); + /* More of suid paranoia if called by non-root: */ /* Clear dangerous stuff, set PATH */ run_by_root = !sanitize_env_if_suid(); @@ -376,7 +383,7 @@ int login_main(int argc UNUSED_PARAM, char **argv) /* We install timeout handler only _after_ we saved G.tty_attrs */ signal(SIGALRM, alarm_handler); - alarm(TIMEOUT); + alarm(G.timeout); /* Find out and memorize our tty name */ full_tty = xmalloc_ttyname(STDIN_FILENO); -- cgit v1.2.3-55-g6feb From 14ed4ec8a416a60a214bf40f9185aa227ac44598 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Sat, 20 Mar 2021 14:01:04 +0100 Subject: resume: write offset in /sys/power/resume_offset Doing this the kernel will hibernate and resume successfully from a swap file. Stop writing offset to /sys/power/resume, as this is not a parameter the kernel takes from this input. (Change added by Sven Mueller) function old new delta resume_main 522 561 +39 .rodata 103175 103182 +7 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 2/0 up/down: 46/0) Total: 46 bytes Signed-off-by: Jordi Pujol Palomer Signed-off-by: Sven Mueller Signed-off-by: Denys Vlasenko --- klibc-utils/resume.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/klibc-utils/resume.c b/klibc-utils/resume.c index 2bf50f9b8..8c4ab26c4 100644 --- a/klibc-utils/resume.c +++ b/klibc-utils/resume.c @@ -103,10 +103,17 @@ int resume_main(int argc UNUSED_PARAM, char **argv) if (major(resume_device) == 0) { bb_error_msg_and_die("invalid resume device: %s", argv[0]); } + ofs = (argv[1] ? xstrtoull(argv[1], 0) : 0); + /* Old kernels have no /sys/power/resume_offset, set it only if necessary */ + if (ofs != 0) { + fd = xopen("/sys/power/resume_offset", O_WRONLY); + s = xasprintf("%llu", ofs); + xwrite_str(fd, s); + } fd = xopen("/sys/power/resume", O_WRONLY); - s = xasprintf("%u:%u:%llu", major(resume_device), minor(resume_device), ofs); + s = xasprintf("%u:%u", major(resume_device), minor(resume_device)); xwrite_str(fd, s); /* if write() returns, resume did not succeed */ -- cgit v1.2.3-55-g6feb From c2bd0b680667c7ec4956552f75d9ff7d040ac941 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Tue, 23 Mar 2021 13:50:02 +0100 Subject: timeout,top,watch,ping: parse NN.N fractional duration in locales with other separators Signed-off-by: Denys Vlasenko --- coreutils/printf.c | 1 + coreutils/sleep.c | 4 ---- coreutils/sort.c | 1 + libbb/duration.c | 14 ++++++++++++-- miscutils/dc.c | 1 + networking/brctl.c | 1 + 6 files changed, 16 insertions(+), 6 deletions(-) diff --git a/coreutils/printf.c b/coreutils/printf.c index a20fc3301..dd94c8ade 100644 --- a/coreutils/printf.c +++ b/coreutils/printf.c @@ -122,6 +122,7 @@ static void FAST_FUNC conv_strtod(const char *arg, void *result) char *end; /* Well, this one allows leading whitespace... so what? */ /* What I like much less is that "-" accepted too! :( */ +//TODO: needs setlocale(LC_NUMERIC, "C")? *(double*)result = strtod(arg, &end); if (end[0]) { errno = ERANGE; diff --git a/coreutils/sleep.c b/coreutils/sleep.c index 7bfaab920..2658e84df 100644 --- a/coreutils/sleep.c +++ b/coreutils/sleep.c @@ -74,10 +74,6 @@ int sleep_main(int argc UNUSED_PARAM, char **argv) sleep(INT_MAX); #if ENABLE_FEATURE_FANCY_SLEEP -# if ENABLE_FLOAT_DURATION - /* undo busybox.c setlocale */ - setlocale(LC_NUMERIC, "C"); -# endif duration = 0; do { duration += parse_duration_str(*argv); diff --git a/coreutils/sort.c b/coreutils/sort.c index b194847d1..6c4e3038c 100644 --- a/coreutils/sort.c +++ b/coreutils/sort.c @@ -295,6 +295,7 @@ static int compare_keys(const void *xarg, const void *yarg) #if ENABLE_FEATURE_SORT_BIG case FLAG_g: { char *xx, *yy; +//TODO: needs setlocale(LC_NUMERIC, "C")? double dx = strtod(x, &xx); double dy = strtod(y, &yy); /* not numbers < NaN < -infinity < numbers < +infinity) */ diff --git a/libbb/duration.c b/libbb/duration.c index 086da15fb..a6a29ddae 100644 --- a/libbb/duration.c +++ b/libbb/duration.c @@ -37,8 +37,18 @@ duration_t FAST_FUNC parse_duration_str(char *str) if (strchr(str, '.')) { double d; char *pp; - int len = strspn(str, "0123456789."); - char sv = str[len]; + int len; + char sv; + +# if ENABLE_LOCALE_SUPPORT + /* Undo busybox.c: on input, we want to use dot + * as fractional separator in strtod(), + * regardless of current locale + */ + setlocale(LC_NUMERIC, "C"); +# endif + len = strspn(str, "0123456789."); + sv = str[len]; str[len] = '\0'; errno = 0; d = strtod(str, &pp); diff --git a/miscutils/dc.c b/miscutils/dc.c index e94dc39e0..42baa67ad 100644 --- a/miscutils/dc.c +++ b/miscutils/dc.c @@ -229,6 +229,7 @@ static void stack_machine(const char *argument) const struct op *o; next: +//TODO: needs setlocale(LC_NUMERIC, "C")? number = strtod(argument, &end); if (end != argument) { argument = end; diff --git a/networking/brctl.c b/networking/brctl.c index e1f3e6445..c83aac6e0 100644 --- a/networking/brctl.c +++ b/networking/brctl.c @@ -89,6 +89,7 @@ static unsigned str_to_jiffies(const char *time_str) { double dd; char *endptr; +//TODO: needs setlocale(LC_NUMERIC, "C")? dd = /*bb_*/strtod(time_str, &endptr); if (endptr == time_str || dd < 0) bb_error_msg_and_die(bb_msg_invalid_arg_to, time_str, "timespec"); -- cgit v1.2.3-55-g6feb From 1195782d79d282639f54ef9620a9211c96c572f1 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Fri, 26 Mar 2021 12:02:08 +0100 Subject: ntpd: code shrink (force not-inlining, stop returning structs) function old new delta d_to_sfp - 133 +133 lfp_to_d - 84 +84 sfp_to_d - 78 +78 d_to_lfp 141 137 -4 .rodata 103182 103174 -8 recv_and_process_peer_pkt 2380 2173 -207 recv_and_process_client_pkt 706 493 -213 ------------------------------------------------------------------------------ (add/remove: 3/0 grow/shrink: 0/4 up/down: 295/-432) Total: -137 bytes Signed-off-by: Denys Vlasenko --- networking/ntpd.c | 50 +++++++++++++++++++++++++------------------------- 1 file changed, 25 insertions(+), 25 deletions(-) diff --git a/networking/ntpd.c b/networking/ntpd.c index 0f350fa6f..8cf8830c2 100644 --- a/networking/ntpd.c +++ b/networking/ntpd.c @@ -552,13 +552,13 @@ gettime1900d(void) } static void -d_to_tv(double d, struct timeval *tv) +d_to_tv(struct timeval *tv, double d) { tv->tv_sec = (long)d; tv->tv_usec = (d - tv->tv_sec) * 1000000; } -static double +static NOINLINE double lfp_to_d(l_fixedpt_t lfp) { double ret; @@ -567,7 +567,7 @@ lfp_to_d(l_fixedpt_t lfp) ret = (double)lfp.int_partl + ((double)lfp.fractionl / UINT_MAX); return ret; } -static double +static NOINLINE double sfp_to_d(s_fixedpt_t sfp) { double ret; @@ -577,25 +577,25 @@ sfp_to_d(s_fixedpt_t sfp) return ret; } #if ENABLE_FEATURE_NTPD_SERVER -static l_fixedpt_t -d_to_lfp(double d) +static void +d_to_lfp(l_fixedpt_t *lfp, double d) { - l_fixedpt_t lfp; - lfp.int_partl = (uint32_t)d; - lfp.fractionl = (uint32_t)((d - lfp.int_partl) * UINT_MAX); - lfp.int_partl = htonl(lfp.int_partl); - lfp.fractionl = htonl(lfp.fractionl); - return lfp; + uint32_t intl; + uint32_t frac; + intl = (uint32_t)d; + frac = (uint32_t)((d - intl) * UINT_MAX); + lfp->int_partl = htonl(intl); + lfp->fractionl = htonl(frac); } -static s_fixedpt_t -d_to_sfp(double d) +static NOINLINE void +d_to_sfp(s_fixedpt_t *sfp, double d) { - s_fixedpt_t sfp; - sfp.int_parts = (uint16_t)d; - sfp.fractions = (uint16_t)((d - sfp.int_parts) * USHRT_MAX); - sfp.int_parts = htons(sfp.int_parts); - sfp.fractions = htons(sfp.fractions); - return sfp; + uint16_t ints; + uint16_t frac; + ints = (uint16_t)d; + frac = (uint16_t)((d - ints) * USHRT_MAX); + sfp->int_parts = htons(ints); + sfp->fractions = htons(frac); } #endif @@ -1037,7 +1037,7 @@ step_time(double offset) xgettimeofday(&tvc); dtime = tvc.tv_sec + (1.0e-6 * tvc.tv_usec) + offset; - d_to_tv(dtime, &tvn); + d_to_tv(&tvn, dtime); xsettimeofday(&tvn); VERB2 { @@ -2117,17 +2117,17 @@ recv_and_process_client_pkt(void /*int fd*/) msg.m_ppoll = G.poll_exp; msg.m_precision_exp = G_precision_exp; /* this time was obtained between poll() and recv() */ - msg.m_rectime = d_to_lfp(G.cur_time); - msg.m_xmttime = d_to_lfp(gettime1900d()); /* this instant */ + d_to_lfp(&msg.m_rectime, G.cur_time); + d_to_lfp(&msg.m_xmttime, gettime1900d()); /* this instant */ if (G.peer_cnt == 0) { /* we have no peers: "stratum 1 server" mode. reftime = our own time */ G.reftime = G.cur_time; } - msg.m_reftime = d_to_lfp(G.reftime); + d_to_lfp(&msg.m_reftime, G.reftime); msg.m_orgtime = query_xmttime; - msg.m_rootdelay = d_to_sfp(G.rootdelay); + d_to_sfp(&msg.m_rootdelay, G.rootdelay); //simple code does not do this, fix simple code! - msg.m_rootdisp = d_to_sfp(G.rootdisp); + d_to_sfp(&msg.m_rootdisp, G.rootdisp); //version = (query_status & VERSION_MASK); /* ... >> VERSION_SHIFT - done below instead */ msg.m_refid = G.refid; // (version > (3 << VERSION_SHIFT)) ? G.refid : G.refid3; -- cgit v1.2.3-55-g6feb From 7b4c2276a89fca0dfedf73db07fbe20fff17a0de Mon Sep 17 00:00:00 2001 From: Ron Yorston Date: Thu, 25 Mar 2021 14:20:56 +0000 Subject: vi: fix word operations across line boundaries Commit 4b49422a0 (vi: fix changes to word at end of line. Closes 11796) fixed a problem where an operation on a word at the end of a line followed by a line starting with whitespace incorrectly joined the lines. However it also broke the case where operating on multiple words across a line boundary *should* join the lines. Fix this by detecting when trailing whitepace in a word operation includes a newline. Whitespace beyond the newline is excluded from consideration. function old new delta do_cmd 5083 5088 +5 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 1/0 up/down: 5/0) Total: 5 bytes Signed-off-by: Ron Yorston Signed-off-by: Denys Vlasenko --- editors/vi.c | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/editors/vi.c b/editors/vi.c index abc0aeae8..1bc2d08ad 100644 --- a/editors/vi.c +++ b/editors/vi.c @@ -3774,14 +3774,16 @@ static void do_cmd(int c) place_cursor(0, 0); if (c1 == 27) { // ESC- user changed mind and wants out c = c1 = 27; // Escape- do nothing - } else if (strchr("wW", c1)) { - ml = 0; // multi-line ranges aren't allowed for words - if (c == 'c') { - // don't include trailing WS as part of word - while (isspace(*q) && q > p) { - q--; - } + } else if (c1 == 'w' || c1 == 'W') { + char *q0 = q; + // don't include trailing WS as part of word + while (q > p && isspace(*q)) { + if (*q-- == '\n') + q0 = q; } + // for non-change operations WS after NL is not part of word + if (c != 'c' && q != p && *q != '\n') + q = q0; dot = yank_delete(p, q, ml, yf, ALLOW_UNDO); // delete word } else if (strchr("^0bBeEft%$ lh\b\177", c1)) { // partial line copy text into a register and delete -- cgit v1.2.3-55-g6feb From 776b56d774fec51e0ac3f9714adbdb2375c6bda7 Mon Sep 17 00:00:00 2001 From: Ron Yorston Date: Thu, 25 Mar 2021 14:21:49 +0000 Subject: vi: code shrink I was puzzled by code in find_range() which handles forward word movement. It included a test to see if we're at the start of a word. Since these are forward word movements surely we'd expect to be at the start of a word? In fact, the test was intended to fix a problem with changes to the last word in a file, as discussed in the thread starting here: http://lists.busybox.net/pipermail/busybox/2004-January/044552.html The code can be simplified by testing directly for end of file instead of indirectly for not being at the start of a word. Since trailing whitespace is now handled in do_cmd() the code to back up off a newline is no longer required. function old new delta find_range 619 514 -105 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 0/1 up/down: 0/-105) Total: -105 bytes Signed-off-by: Ron Yorston Signed-off-by: Denys Vlasenko --- editors/vi.c | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/editors/vi.c b/editors/vi.c index 1bc2d08ad..7a7247c10 100644 --- a/editors/vi.c +++ b/editors/vi.c @@ -3021,15 +3021,9 @@ static int find_range(char **start, char **stop, char c) q = dot; } else if (strchr("wW", c)) { do_cmd(c); // execute movement cmd - // if we are at the next word's first char - // step back one char - // but check the possibilities when it is true - if (dot > text && ((isspace(dot[-1]) && !isspace(dot[0])) - || (ispunct(dot[-1]) && !ispunct(dot[0])) - || (isalnum(dot[-1]) && !isalnum(dot[0])))) - dot--; // move back off of next word - if (dot > text && *dot == '\n') - dot--; // stay off NL + // step back one char, but not if we're at end of file + if (dot > p && !((dot == end - 2 && end[-1] == '\n') || dot == end - 1)) + dot--; q = dot; } else if (strchr("H-k{", c) || (c == 'G' && !forward)) { // these operate on multi-lines backwards -- cgit v1.2.3-55-g6feb From 25d259264019e4171eddde570271a82b6dd0f79a Mon Sep 17 00:00:00 2001 From: Ron Yorston Date: Thu, 25 Mar 2021 14:23:36 +0000 Subject: vi: make buffer handling more vi-like Vi places text affected by change/delete/yank operations into a buffer. The contents of such buffers can be restored with the put commands, 'p' or 'P'. These behave differently depending on whether the buffer contains whole lines or partial lines. For whole lines the text is copied into the file on the line before (P) or after (p) the current line. For partial lines the text is copied before or after the current cursor position. Whether an operation results in whole or partial lines depends on the command used. BusyBox vi treats any buffer with a newline as though it contained whole lines. This is incorrect. Deleting multiple words across a line boundary results in a buffer with a newline but not having whole lines. Rework how buffers are handled to behave more like vi. function old new delta static.text_yank 79 99 +20 colon 3092 3097 +5 edit_file 885 887 +2 yank_delete 127 112 -15 .rodata 105139 105101 -38 find_range 514 467 -47 do_cmd 5088 4842 -246 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 3/4 up/down: 27/-346) Total: -319 bytes Signed-off-by: Ron Yorston Signed-off-by: Denys Vlasenko --- editors/vi.c | 162 +++++++++++++++++++++++++++-------------------------------- 1 file changed, 73 insertions(+), 89 deletions(-) diff --git a/editors/vi.c b/editors/vi.c index 7a7247c10..ccf2870ab 100644 --- a/editors/vi.c +++ b/editors/vi.c @@ -254,6 +254,9 @@ enum { BACK = -1, // code depends on "-1" for array index LIMITED = 0, // char_search() only current line FULL = 1, // char_search() to the end/beginning of entire text + PARTIAL = 0, // buffer contains partial line + WHOLE = 1, // buffer contains whole lines + MULTI = 2, // buffer may include newlines S_BEFORE_WS = 1, // used in skip_thing() for moving "dot" S_TO_WS = 2, // used in skip_thing() for moving "dot" @@ -343,6 +346,7 @@ struct globals { smalluint YDreg;//,Ureg;// default delete register and orig line for "U" #define Ureg 27 char *reg[28]; // named register a-z, "D", and "U" 0-25,26,27 + char regtype[28]; // buffer type: WHOLE, MULTI or PARTIAL char *mark[28]; // user marks points somewhere in text[]- a-z and previous context '' char *context_start, *context_end; #endif @@ -452,6 +456,7 @@ struct globals { #define YDreg (G.YDreg ) //#define Ureg (G.Ureg ) +#define regtype (G.regtype ) #define mark (G.mark ) #define context_start (G.context_start ) #define context_end (G.context_end ) @@ -1314,7 +1319,8 @@ static void not_implemented(const char *s) //----- Block insert/delete, undo ops -------------------------- #if ENABLE_FEATURE_VI_YANKMARK -static char *text_yank(char *p, char *q, int dest) // copy text into a register +// copy text into a register +static char *text_yank(char *p, char *q, int dest, int buftype) { int cnt = q - p; if (cnt < 0) { // they are backwards- reverse them @@ -1323,6 +1329,7 @@ static char *text_yank(char *p, char *q, int dest) // copy text into a register } free(reg[dest]); // if already a yank register, free it reg[dest] = xstrndup(p, cnt + 1); + regtype[dest] = buftype; return p; } @@ -1819,12 +1826,11 @@ static void end_cmd_q(void) #endif /* FEATURE_VI_DOT_CMD */ // copy text into register, then delete text. -// if dist <= 0, do not include, or go past, a NewLine // #if !ENABLE_FEATURE_VI_UNDO #define yank_delete(a,b,c,d,e) yank_delete(a,b,c,d) #endif -static char *yank_delete(char *start, char *stop, int dist, int yf, int undo) +static char *yank_delete(char *start, char *stop, int buftype, int yf, int undo) { char *p; @@ -1835,22 +1841,11 @@ static char *yank_delete(char *start, char *stop, int dist, int yf, int undo) start = stop; stop = p; } - if (dist <= 0) { - // we cannot cross NL boundaries - p = start; - if (*p == '\n') - return p; - // dont go past a NewLine - for (; p + 1 <= stop; p++) { - if (p[1] == '\n') { - stop = p; // "stop" just before NewLine - break; - } - } - } + if (buftype == PARTIAL && *start == '\n') + return start; p = start; #if ENABLE_FEATURE_VI_YANKMARK - text_yank(start, stop, YDreg); + text_yank(start, stop, YDreg, buftype); #endif if (yf == YANKDEL) { p = text_hole_delete(start, stop, undo); @@ -2521,7 +2516,7 @@ static void colon(char *buf) q = begin_line(dot); // assume .,. for the range r = end_line(dot); } - dot = yank_delete(q, r, 1, YANKDEL, ALLOW_UNDO); // save, then delete lines + dot = yank_delete(q, r, WHOLE, YANKDEL, ALLOW_UNDO); // save, then delete lines dot_skip_over_ws(); } else if (strncmp(cmd, "edit", i) == 0) { // Edit a file int size; @@ -2874,7 +2869,7 @@ static void colon(char *buf) q = begin_line(dot); // assume .,. for the range r = end_line(dot); } - text_yank(q, r, YDreg); + text_yank(q, r, YDreg, WHOLE); li = count_lines(q, r); status_line("Yank %d lines (%d chars) into [%c]", li, strlen(reg[YDreg]), what_reg()); @@ -3000,74 +2995,65 @@ static void do_cmd(int c); static int find_range(char **start, char **stop, char c) { char *save_dot, *p, *q, *t; - int cnt, multiline = 0, forward; + int buftype = -1; save_dot = dot; p = q = dot; - // will a 'G' command move forwards or backwards? - forward = cmdcnt == 0 || cmdcnt > count_lines(text, dot); - if (strchr("cdy><", c)) { // these cmds operate on whole lines - p = q = begin_line(p); - for (cnt = 1; cnt < cmdcnt; cnt++) { - q = next_line(q); - } - q = end_line(q); + buftype = WHOLE; + if (--cmdcnt > 0) + do_cmd('j'); } else if (strchr("^%$0bBeEfth\b\177", c)) { // These cmds operate on char positions + buftype = PARTIAL; do_cmd(c); // execute movement cmd - q = dot; + if (p == dot) // no movement is an error + buftype = -1; } else if (strchr("wW", c)) { + buftype = MULTI; do_cmd(c); // execute movement cmd // step back one char, but not if we're at end of file if (dot > p && !((dot == end - 2 && end[-1] == '\n') || dot == end - 1)) dot--; - q = dot; - } else if (strchr("H-k{", c) || (c == 'G' && !forward)) { - // these operate on multi-lines backwards - q = end_line(dot); // find NL - do_cmd(c); // execute movement cmd - dot_begin(); - p = dot; - } else if (strchr("L+j}\r\n", c) || (c == 'G' && forward)) { - // these operate on multi-lines forwards - p = begin_line(dot); + } else if (strchr("GHL+-jk{}\r\n", c)) { + // these operate on whole lines + buftype = WHOLE; do_cmd(c); // execute movement cmd - dot_end(); // find NL - q = dot; - } else /* if (c == ' ' || c == 'l') */ { + } else if (c == ' ' || c == 'l') { // forward motion by character int tmpcnt = (cmdcnt ?: 1); + buftype = PARTIAL; do_cmd(c); // execute movement cmd // exclude last char unless range isn't what we expected // this indicates we've hit EOL if (tmpcnt == dot - p) dot--; - q = dot; } + + if (buftype == -1) + return buftype; + + q = dot; if (q < p) { t = q; q = p; p = t; } + if (buftype == WHOLE) { + p = begin_line(p); + q = end_line(q); + } + // backward char movements don't include start position if (q > p && strchr("^0bBh\b\177", c)) q--; - multiline = 0; - for (t = p; t <= q; t++) { - if (*t == '\n') { - multiline = 1; - break; - } - } - *start = p; *stop = q; dot = save_dot; - return multiline; + return buftype; } //--------------------------------------------------------------------- @@ -3132,7 +3118,7 @@ static void do_cmd(int c) } else { if (1 <= c || Isprint(c)) { if (c != 27) - dot = yank_delete(dot, dot, 0, YANKDEL, ALLOW_UNDO); // delete char + dot = yank_delete(dot, dot, PARTIAL, YANKDEL, ALLOW_UNDO); // delete char dot = char_insert(dot, c, ALLOW_UNDO_CHAIN); // insert new char } goto dc1; @@ -3312,7 +3298,7 @@ static void do_cmd(int c) break; } // are we putting whole lines or strings - if (strchr(p, '\n') != NULL) { + if (regtype[YDreg] == WHOLE) { if (c == 'P') { dot_begin(); // putting lines- Put above } @@ -3523,7 +3509,7 @@ static void do_cmd(int c) cnt = count_lines(text, dot); // remember what line we are on c1 = get_one_char(); // get the type of thing to delete find_range(&p, &q, c1); - yank_delete(p, q, 1, YANKONLY, NO_UNDO); // save copy before change + yank_delete(p, q, WHOLE, YANKONLY, NO_UNDO); // save copy before change p = begin_line(p); q = end_line(q); i = count_lines(p, q); // # of lines we are shifting @@ -3576,7 +3562,7 @@ static void do_cmd(int c) save_dot = dot; dot = dollar_line(dot); // move to before NL // copy text into a register and delete - dot = yank_delete(save_dot, dot, 0, YANKDEL, ALLOW_UNDO); // delete to e-o-l + dot = yank_delete(save_dot, dot, PARTIAL, YANKDEL, ALLOW_UNDO); // delete to e-o-l if (c == 'C') goto dc_i; // start inserting #if ENABLE_FEATURE_VI_DOT_CMD @@ -3682,7 +3668,7 @@ static void do_cmd(int c) break; case KEYCODE_DELETE: if (dot < end - 1) - dot = yank_delete(dot, dot, 1, YANKDEL, ALLOW_UNDO); + dot = yank_delete(dot, dot, PARTIAL, YANKDEL, ALLOW_UNDO); break; case 'X': // X- delete char before dot case 'x': // x- delete the current char @@ -3694,7 +3680,7 @@ static void do_cmd(int c) if (dot[dir] != '\n') { if (c == 'X') dot--; // delete prev char - dot = yank_delete(dot, dot, 0, YANKDEL, ALLOW_UNDO); // delete char + dot = yank_delete(dot, dot, PARTIAL, YANKDEL, ALLOW_UNDO); // delete char } } while (--cmdcnt > 0); end_cmd_q(); // stop adding to q @@ -3754,21 +3740,29 @@ static void do_cmd(int c) case 'Y': // Y- Yank a line #endif { - int yf, ml, whole = 0; +#if ENABLE_FEATURE_VI_YANKMARK + char *savereg = reg[YDreg]; +#endif + int yf, buftype = 0; yf = YANKDEL; // assume either "c" or "d" #if ENABLE_FEATURE_VI_YANKMARK if (c == 'y' || c == 'Y') yf = YANKONLY; #endif c1 = 'y'; - if (c != 'Y') + if (c != 'Y') { c1 = get_one_char(); // get the type of thing to delete + if (c1 == 27) // ESC- user changed mind and wants out + goto dc6; + } // determine range, and whether it spans lines - ml = find_range(&p, &q, c1); + buftype = find_range(&p, &q, c1); place_cursor(0, 0); - if (c1 == 27) { // ESC- user changed mind and wants out - c = c1 = 27; // Escape- do nothing - } else if (c1 == 'w' || c1 == 'W') { + if (buftype == -1) { // invalid range + indicate_error(); + goto dc6; + } + if (c1 == 'w' || c1 == 'W') { char *q0 = q; // don't include trailing WS as part of word while (q > p && isspace(*q)) { @@ -3778,25 +3772,13 @@ static void do_cmd(int c) // for non-change operations WS after NL is not part of word if (c != 'c' && q != p && *q != '\n') q = q0; - dot = yank_delete(p, q, ml, yf, ALLOW_UNDO); // delete word - } else if (strchr("^0bBeEft%$ lh\b\177", c1)) { - // partial line copy text into a register and delete - dot = yank_delete(p, q, ml, yf, ALLOW_UNDO); // delete word - } else if (strchr("cdykjGHL+-{}\r\n", c1)) { - // whole line copy text into a register and delete - dot = yank_delete(p, q, ml, yf, ALLOW_UNDO); // delete lines - whole = 1; - } else { - // could not recognize object - c = c1 = 27; // error- - ml = 0; - indicate_error(); } - if (ml && whole) { + dot = yank_delete(p, q, buftype, yf, ALLOW_UNDO); // delete word + if (buftype == WHOLE) { if (c == 'c') { dot = char_insert(dot, '\n', ALLOW_UNDO_CHAIN); // on the last line of file don't move to prev line - if (whole && dot != (end-1)) { + if (dot != (end-1)) { dot_prev(); } } else if (c == 'd') { @@ -3804,16 +3786,17 @@ static void do_cmd(int c) dot_skip_over_ws(); } } - if (c1 != 27) { - // if CHANGING, not deleting, start inserting after the delete - if (c == 'c') { - strcpy(buf, "Change"); - goto dc_i; // start inserting - } + // if CHANGING, not deleting, start inserting after the delete + if (c == 'c') { + //strcpy(buf, "Change"); + goto dc_i; // start inserting + } +#if ENABLE_FEATURE_VI_YANKMARK + // only update status if a yank has actually happened + if (reg[YDreg] != savereg) { if (c == 'd') { strcpy(buf, "Delete"); } -#if ENABLE_FEATURE_VI_YANKMARK if (c == 'y' || c == 'Y') { strcpy(buf, "Yank"); } @@ -3825,9 +3808,10 @@ static void do_cmd(int c) } status_line("%s %u lines (%u chars) using [%c]", buf, cnt, (unsigned)strlen(reg[YDreg]), what_reg()); -#endif - end_cmd_q(); // stop adding to q } +#endif + dc6: + end_cmd_q(); // stop adding to q break; } case 'k': // k- goto prev line, same col @@ -4271,7 +4255,7 @@ static void edit_file(char *fn) // save a copy of the current line- for the 'U" command if (begin_line(dot) != cur_line) { cur_line = begin_line(dot); - text_yank(begin_line(dot), end_line(dot), Ureg); + text_yank(begin_line(dot), end_line(dot), Ureg, PARTIAL); } #endif #if ENABLE_FEATURE_VI_DOT_CMD -- cgit v1.2.3-55-g6feb From 5ae25f40bdc839e3fb24dcb7ddd6067698bf87b0 Mon Sep 17 00:00:00 2001 From: Ron Yorston Date: Sun, 28 Mar 2021 13:18:40 +0100 Subject: vi: don't overwrite existing file If the name of the file being written doesn't match the current filename and the output file already exists vi should issue a warning and not overwrite the file. Because the test only compares the file names it's somewhat over- protective. If the current file name is 'my_text' and the user tries to save to './my_text' they'll be prevented from doing so. function old new delta colon 3092 3151 +59 .rodata 105118 105146 +28 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 2/0 up/down: 87/0) Total: 87 bytes Signed-off-by: Ron Yorston Signed-off-by: Denys Vlasenko --- editors/vi.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/editors/vi.c b/editors/vi.c index ccf2870ab..47b13b3ca 100644 --- a/editors/vi.c +++ b/editors/vi.c @@ -2816,6 +2816,13 @@ static void colon(char *buf) // is there a file name to write to? if (args[0]) { + struct stat statbuf; + + if (!useforce && (fn == NULL || strcmp(fn, args) != 0) && + stat(args, &statbuf) == 0) { + status_line_bold("File exists (:w! overrides)"); + goto ret; + } fn = args; } # if ENABLE_FEATURE_VI_READONLY -- cgit v1.2.3-55-g6feb From 18871c3f2b96e76269f5c5e4bbf102808b69bd42 Mon Sep 17 00:00:00 2001 From: Ron Yorston Date: Sun, 28 Mar 2021 13:19:26 +0100 Subject: vi: 'G'/'M' commands move to first visible character The 'G' command with no target (meaning 'go to last line') should position the cursor on the first visible character of the line, as it already does in other cases. The 'M' command should position the cursor on the first visible character (as 'H' and 'L' already do). function old new delta do_cmd 4842 4853 +11 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 1/0 up/down: 11/0) Total: 11 bytes Signed-off-by: Ron Yorston Signed-off-by: Denys Vlasenko --- editors/vi.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/editors/vi.c b/editors/vi.c index 47b13b3ca..f4da38071 100644 --- a/editors/vi.c +++ b/editors/vi.c @@ -3596,6 +3596,7 @@ static void do_cmd(int c) if (cmdcnt > 0) { dot = find_line(cmdcnt); // what line is #cmdcnt } + dot_begin(); dot_skip_over_ws(); break; case 'H': // H- goto top line on screen @@ -3652,6 +3653,7 @@ static void do_cmd(int c) dot = screenbegin; for (cnt = 0; cnt < (rows-1) / 2; cnt++) dot = next_line(dot); + dot_skip_over_ws(); break; case 'O': // O- open a empty line above // 0i\n ESC -i -- cgit v1.2.3-55-g6feb From 50a2db7dff696c0196fcc9a27db6154983bae149 Mon Sep 17 00:00:00 2001 From: Ron Yorston Date: Sun, 28 Mar 2021 13:20:01 +0100 Subject: vi: remember cursor column during vertical motion When the 'j'/'k' commands or up/down arrow keys are used to move the cursor vertically 'vi' remembers the original cursor column and positions the cursor there if possible. Also, if the '$' command has been used to position the cursor at the end of a line vertical movements keep the cursor at the end of the line. Make BusyBox 'vi' do the same. function old new delta refresh 674 694 +20 do_cmd 4853 4861 +8 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 2/0 up/down: 28/0) Total: 28 bytes Signed-off-by: Ron Yorston Signed-off-by: Denys Vlasenko --- editors/vi.c | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/editors/vi.c b/editors/vi.c index f4da38071..2c724a448 100644 --- a/editors/vi.c +++ b/editors/vi.c @@ -263,6 +263,8 @@ enum { S_OVER_WS = 3, // used in skip_thing() for moving "dot" S_END_PUNCT = 4, // used in skip_thing() for moving "dot" S_END_ALNUM = 5, // used in skip_thing() for moving "dot" + + C_END = -1, // cursor is at end of line due to '$' command }; @@ -354,6 +356,8 @@ struct globals { sigjmp_buf restart; // int_handler() jumps to location remembered here #endif struct termios term_orig; // remember what the cooked mode was + int cindex; // saved character index for up/down motion + smallint keep_index; // retain saved character index #if ENABLE_FEATURE_VI_COLON char *initial_cmds[3]; // currently 2 entries, NULL terminated #endif @@ -462,6 +466,8 @@ struct globals { #define context_end (G.context_end ) #define restart (G.restart ) #define term_orig (G.term_orig ) +#define cindex (G.cindex ) +#define keep_index (G.keep_index ) #define initial_cmds (G.initial_cmds ) #define readbuffer (G.readbuffer ) #define scr_out_buf (G.scr_out_buf ) @@ -992,6 +998,9 @@ static void refresh(int full_screen) place_cursor(crow, ccol); + if (!keep_index) + cindex = ccol + offset; + old_offset = offset; #undef old_offset } @@ -3096,6 +3105,7 @@ static void do_cmd(int c) // cnt = yf = 0; // quiet the compiler // p = q = save_dot = buf; // quiet the compiler memset(buf, '\0', sizeof(buf)); + keep_index = FALSE; show_status_line(); @@ -3220,9 +3230,10 @@ static void do_cmd(int c) case KEYCODE_DOWN: // cursor key Down do { dot_next(); // go to next B-o-l - // try stay in same col - dot = move_to_col(dot, ccol + offset); } while (--cmdcnt > 0); + // try to stay in saved column + dot = cindex == C_END ? end_line(dot) : move_to_col(dot, cindex); + keep_index = TRUE; break; case 12: // ctrl-L force redraw whole screen case 18: // ctrl-R force redraw @@ -3348,6 +3359,8 @@ static void do_cmd(int c) break; dot_next(); } + cindex = C_END; + keep_index = TRUE; break; case '%': // %- find matching char of pair () [] {} for (q = dot; q < end && *q != '\n'; q++) { @@ -3827,8 +3840,10 @@ static void do_cmd(int c) case KEYCODE_UP: // cursor key Up do { dot_prev(); - dot = move_to_col(dot, ccol + offset); // try stay in same col } while (--cmdcnt > 0); + // try to stay in saved column + dot = cindex == C_END ? end_line(dot) : move_to_col(dot, cindex); + keep_index = TRUE; break; case 'r': // r- replace the current char with user input c1 = get_one_char(); // get the replacement char -- cgit v1.2.3-55-g6feb From 15f4ac3ca99bca8811a334f9c7603969ab7ad362 Mon Sep 17 00:00:00 2001 From: Ron Yorston Date: Sun, 28 Mar 2021 17:15:30 +0100 Subject: vi: improvements to character search within line - Use a common routine to handle all commands to search for a character in a line. - When searching for the nth occurrence of a character don't move the cursor if fewer than n occurrences are present. - Add support for the 'T' command, search backwards for character after next occurrence of given character. function old new delta do_cmd 4861 4805 -56 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 0/1 up/down: 0/-56) Total: -56 bytes v2: Add parentheses to avoid searches continuing past end of line. Signed-off-by: Ron Yorston Signed-off-by: Denys Vlasenko --- editors/vi.c | 80 +++++++++++++++++++++++++++++------------------------------- 1 file changed, 39 insertions(+), 41 deletions(-) diff --git a/editors/vi.c b/editors/vi.c index 2c724a448..ec2d64dfb 100644 --- a/editors/vi.c +++ b/editors/vi.c @@ -322,7 +322,8 @@ struct globals { char *screen; // pointer to the virtual screen buffer int screensize; // and its size int tabstop; - int last_forward_char; // last char searched for with 'f' (int because of Unicode) + int last_search_char; // last char searched for (int because of Unicode) + smallint last_search_cmd; // command used to invoke last char search #if ENABLE_FEATURE_VI_CRASHME char last_input_char; // last char read from user #endif @@ -439,7 +440,8 @@ struct globals { #define screensize (G.screensize ) #define screenbegin (G.screenbegin ) #define tabstop (G.tabstop ) -#define last_forward_char (G.last_forward_char ) +#define last_search_char (G.last_search_char ) +#define last_search_cmd (G.last_search_cmd ) #if ENABLE_FEATURE_VI_CRASHME #define last_input_char (G.last_input_char ) #endif @@ -1772,6 +1774,31 @@ static void dot_skip_over_ws(void) dot++; } +static void dot_to_char(int cmd) +{ + char *q = dot; + int dir = islower(cmd) ? FORWARD : BACK; + + if (last_search_char == 0) + return; + + do { + do { + q += dir; + if ((dir == FORWARD ? q > end - 1 : q < text) || *q == '\n') + return; + } while (*q != last_search_char); + } while (--cmdcnt > 0); + + dot = q; + + // place cursor before/after char as required + if (cmd == 't') + dot_left(); + else if (cmd == 'T') + dot_right(); +} + static void dot_scroll(int cnt, int dir) { char *q; @@ -3181,11 +3208,9 @@ static void do_cmd(int c) //case '*': // *- //case '=': // =- //case '@': // @- - //case 'F': // F- //case 'K': // K- //case 'Q': // Q- //case 'S': // S- - //case 'T': // T- //case 'V': // V- //case '[': // [- //case '\\': // \- @@ -3379,36 +3404,16 @@ static void do_cmd(int c) indicate_error(); break; case 'f': // f- forward to a user specified char - last_forward_char = get_one_char(); // get the search char - // - // dont separate these two commands. 'f' depends on ';' - // - //**** fall through to ... ';' - case ';': // ;- look at rest of line for last forward char - do { - if (last_forward_char == 0) - break; - q = dot + 1; - while (q < end - 1 && *q != '\n' && *q != last_forward_char) { - q++; - } - if (*q == last_forward_char) - dot = q; - } while (--cmdcnt > 0); - break; - case ',': // repeat latest 'f' in opposite direction - if (last_forward_char == 0) - break; - do { - q = dot - 1; - while (q >= text && *q != '\n' && *q != last_forward_char) { - q--; - } - if (q >= text && *q == last_forward_char) - dot = q; - } while (--cmdcnt > 0); + case 'F': // F- backward to a user specified char + case 't': // t- move to char prior to next x + case 'T': // T- move to char after previous x + last_search_char = get_one_char(); // get the search char + last_search_cmd = c; + // fall through + case ';': // ;- look at rest of line for last search char + case ',': // ,- repeat latest search in opposite direction + dot_to_char(c != ',' ? last_search_cmd : last_search_cmd ^ 0x20); break; - case '-': // -- goto prev line do { dot_prev(); @@ -3854,13 +3859,6 @@ static void do_cmd(int c) } end_cmd_q(); // stop adding to q break; - case 't': // t- move to char prior to next x - last_forward_char = get_one_char(); - do_cmd(';'); - if (*dot == last_forward_char) - dot_left(); - last_forward_char = 0; - break; case 'w': // w- forward a word do { if (isalnum(*dot) || *dot == '_') { // we are on ALNUM @@ -4204,7 +4202,7 @@ static void edit_file(char *fn) mark[26] = mark[27] = text; // init "previous context" #endif - last_forward_char = '\0'; + last_search_char = '\0'; #if ENABLE_FEATURE_VI_CRASHME last_input_char = '\0'; #endif -- cgit v1.2.3-55-g6feb From d4c46037a6c595c42aab22b6910c56f5ccadb96e Mon Sep 17 00:00:00 2001 From: Ron Yorston Date: Sun, 28 Mar 2021 13:21:08 +0100 Subject: vi: support more commands for range selection Add 'F', 'T' and '|' as commands that can be used to specify a range for change/delete/yank operations. function old new delta .rodata 105129 105135 +6 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 1/0 up/down: 6/0) Total: 6 bytes Signed-off-by: Ron Yorston Signed-off-by: Denys Vlasenko --- editors/vi.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/editors/vi.c b/editors/vi.c index ec2d64dfb..5d96c1575 100644 --- a/editors/vi.c +++ b/editors/vi.c @@ -3048,7 +3048,7 @@ static int find_range(char **start, char **stop, char c) buftype = WHOLE; if (--cmdcnt > 0) do_cmd('j'); - } else if (strchr("^%$0bBeEfth\b\177", c)) { + } else if (strchr("^%$0bBeEfFtTh|\b\177", c)) { // These cmds operate on char positions buftype = PARTIAL; do_cmd(c); // execute movement cmd @@ -3090,8 +3090,8 @@ static int find_range(char **start, char **stop, char c) q = end_line(q); } - // backward char movements don't include start position - if (q > p && strchr("^0bBh\b\177", c)) q--; + // movements which don't include end of range + if (q > p && strchr("^0bBFTh|\b\177", c)) q--; *start = p; *stop = q; -- cgit v1.2.3-55-g6feb From 1e84daf054113b97dad2d1201b8ec7fbebc9aeb3 Mon Sep 17 00:00:00 2001 From: Ron Yorston Date: Sun, 28 Mar 2021 13:21:34 +0100 Subject: vi: allow motion count for change/delete/yank/shift The motion that determines the range of a change, delete, yank or shift operation can have its own count. Thus the commands '5dd' and 'd5d' are equivalent: both delete 5 lines. When the command itself also has a count the two values are multiplied. Thus the command '2d3w' deletes 6 words and '2D3G' deletes from the current line to line 6. (When dealing with structured data it might make sense to think in units of 3 words so '2d3w' is deleting 2 such units. It doesn't seem quite as sensible to express 'delete from current line to line 6' as '2D3G' but vi permits it.) function old new delta get_motion_char - 68 +68 ------------------------------------------------------------------------------ (add/remove: 1/0 grow/shrink: 0/0 up/down: 68/0) Total: 68 bytes Signed-off-by: Ron Yorston Signed-off-by: Denys Vlasenko --- editors/vi.c | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/editors/vi.c b/editors/vi.c index 5d96c1575..4e1a2390f 100644 --- a/editors/vi.c +++ b/editors/vi.c @@ -1102,6 +1102,22 @@ static int get_one_char(void) # define get_one_char() readit() #endif +// Get type of thing to operate on and adjust count +static int get_motion_char(void) +{ + int c, cnt; + + c = get_one_char(); + if (c != '0' && isdigit(c)) { + // get any non-zero motion count + for (cnt = 0; isdigit(c); c = get_one_char()) + cnt = cnt * 10 + (c - '0'); + cmdcnt = (cmdcnt ?: 1) * cnt; + } + + return c; +} + // Get input line (uses "status line" area) static char *get_input_line(const char *prompt) { @@ -3532,7 +3548,7 @@ static void do_cmd(int c) case '<': // <- Left shift something case '>': // >- Right shift something cnt = count_lines(text, dot); // remember what line we are on - c1 = get_one_char(); // get the type of thing to delete + c1 = get_motion_char(); // get the type of thing to operate on find_range(&p, &q, c1); yank_delete(p, q, WHOLE, YANKONLY, NO_UNDO); // save copy before change p = begin_line(p); @@ -3778,7 +3794,7 @@ static void do_cmd(int c) #endif c1 = 'y'; if (c != 'Y') { - c1 = get_one_char(); // get the type of thing to delete + c1 = get_motion_char(); // get the type of thing to operate on if (c1 == 27) // ESC- user changed mind and wants out goto dc6; } -- cgit v1.2.3-55-g6feb From d3b74826c5a0843e9c0ef324944d6e084ae15b46 Mon Sep 17 00:00:00 2001 From: Ron Yorston Date: Sun, 28 Mar 2021 13:22:11 +0100 Subject: vi: allow repetition count for paragraph motion The paragraph motion commands '{' and '}' should accept a count. function old new delta do_cmd 5054 5071 +17 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 1/0 up/down: 17/0) Total: 17 bytes Signed-off-by: Ron Yorston Signed-off-by: Denys Vlasenko --- editors/vi.c | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/editors/vi.c b/editors/vi.c index 4e1a2390f..e3e0f4b44 100644 --- a/editors/vi.c +++ b/editors/vi.c @@ -3513,16 +3513,15 @@ static void do_cmd(int c) } while (--cmdcnt > 0); break; case '{': // {- move backward paragraph - q = char_search(dot, "\n\n", ((unsigned)BACK << 1) | FULL); - if (q != NULL) { // found blank line - dot = next_line(q); // move to next blank line - } - break; case '}': // }- move forward paragraph - q = char_search(dot, "\n\n", (FORWARD << 1) | FULL); - if (q != NULL) { // found blank line - dot = next_line(q); // move to next blank line - } + do { + q = char_search(dot, "\n\n", c == '{' ? + ((unsigned)BACK << 1) | FULL : + (FORWARD << 1) | FULL); + if (q != NULL) { // found blank line + dot = next_line(q); // move to next blank line + } + } while (--cmdcnt > 0); break; #endif /* FEATURE_VI_SEARCH */ case '0': // 0- goto beginning of line -- cgit v1.2.3-55-g6feb From 8b571bd7b507c5dbdf8bb2bd804047ed66ea9809 Mon Sep 17 00:00:00 2001 From: Ron Yorston Date: Sun, 28 Mar 2021 13:22:43 +0100 Subject: vi: improve motion by paragraph When moving by paragraph ('{' and '}'): - Treat multiple empty lines as a single paragraph separator. - When no paragraph separator is found move to the start or end of the file depending on the direction of motion. function old new delta do_cmd 4821 4900 +79 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 1/0 up/down: 79/0) Total: 79 bytes Signed-off-by: Ron Yorston Signed-off-by: Denys Vlasenko --- editors/vi.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/editors/vi.c b/editors/vi.c index e3e0f4b44..5d4b0f20e 100644 --- a/editors/vi.c +++ b/editors/vi.c @@ -3515,12 +3515,20 @@ static void do_cmd(int c) case '{': // {- move backward paragraph case '}': // }- move forward paragraph do { - q = char_search(dot, "\n\n", c == '{' ? - ((unsigned)BACK << 1) | FULL : - (FORWARD << 1) | FULL); + dir = c == '}' ? FORWARD : BACK; + // skip over consecutive empty lines + while ((dir == FORWARD ? dot < end - 1 : dot > text) && + *dot == '\n' && dot[dir] == '\n') { + dot += dir; + } + q = char_search(dot, "\n\n", ((unsigned)dir << 1) | FULL); if (q != NULL) { // found blank line dot = next_line(q); // move to next blank line } + else { // blank line not found, move to end of file + dot = dir == FORWARD ? end - 1 : text; + break; + } } while (--cmdcnt > 0); break; #endif /* FEATURE_VI_SEARCH */ -- cgit v1.2.3-55-g6feb From d56da680577ae5ad43833040a310706e8331c684 Mon Sep 17 00:00:00 2001 From: Ron Yorston Date: Sun, 28 Mar 2021 13:23:12 +0100 Subject: vi: improve operations involving paragraph movement Movement by paragraph doesn't always involve whole lines. If the cursor is positioned in the middle of a line deleting to either end of the paragraph will result in one partial line and zero or more full lines. Adjust the end of ranges delimited by paragraph movement to more closely match what vi does. function old new delta find_range 467 518 +51 at_eof - 49 +49 ------------------------------------------------------------------------------ (add/remove: 1/0 grow/shrink: 1/0 up/down: 100/0) Total: 100 bytes Signed-off-by: Ron Yorston Signed-off-by: Denys Vlasenko --- editors/vi.c | 30 ++++++++++++++++++++++++------ 1 file changed, 24 insertions(+), 6 deletions(-) diff --git a/editors/vi.c b/editors/vi.c index 5d4b0f20e..323ca4427 100644 --- a/editors/vi.c +++ b/editors/vi.c @@ -3051,6 +3051,12 @@ static void int_handler(int sig) static void do_cmd(int c); +static int at_eof(const char *s) +{ + // does 's' point to end of file, even with no terminating newline? + return ((s == end - 2 && s[1] == '\n') || s == end - 1); +} + static int find_range(char **start, char **stop, char c) { char *save_dot, *p, *q, *t; @@ -3064,7 +3070,7 @@ static int find_range(char **start, char **stop, char c) buftype = WHOLE; if (--cmdcnt > 0) do_cmd('j'); - } else if (strchr("^%$0bBeEfFtTh|\b\177", c)) { + } else if (strchr("^%$0bBeEfFtTh|{}\b\177", c)) { // These cmds operate on char positions buftype = PARTIAL; do_cmd(c); // execute movement cmd @@ -3074,9 +3080,9 @@ static int find_range(char **start, char **stop, char c) buftype = MULTI; do_cmd(c); // execute movement cmd // step back one char, but not if we're at end of file - if (dot > p && !((dot == end - 2 && end[-1] == '\n') || dot == end - 1)) + if (dot > p && !at_eof(dot)) dot--; - } else if (strchr("GHL+-jk{}\r\n", c)) { + } else if (strchr("GHL+-jk\r\n", c)) { // these operate on whole lines buftype = WHOLE; do_cmd(c); // execute movement cmd @@ -3101,14 +3107,26 @@ static int find_range(char **start, char **stop, char c) p = t; } + // movements which don't include end of range + if (q > p) { + if (strchr("^0bBFTh|\b\177", c)) { + q--; + } else if (strchr("{}", c)) { + buftype = (p == begin_line(p) && (*q == '\n' || at_eof(q))) ? + WHOLE : MULTI; + if (!at_eof(q)) { + q--; + if (q > p && p != begin_line(p)) + q--; + } + } + } + if (buftype == WHOLE) { p = begin_line(p); q = end_line(q); } - // movements which don't include end of range - if (q > p && strchr("^0bBFTh|\b\177", c)) q--; - *start = p; *stop = q; dot = save_dot; -- cgit v1.2.3-55-g6feb From a25b4c2c4245083411011e5054ba859d7c6b8dd6 Mon Sep 17 00:00:00 2001 From: Ron Yorston Date: Sun, 28 Mar 2021 13:23:51 +0100 Subject: vi: code shrink - In the '+' and '-' commands the call to dot_skip_over_ws() is only needed for the final line processed so it can be moved out of the while loop. - Marking sync_cursor() NOINLINE doesn't seem to offer the same advantages it did in 2009 (commit adf922ec2). function old new delta refresh 694 974 +280 do_cmd 4900 4887 -13 sync_cursor 336 - -336 ------------------------------------------------------------------------------ (add/remove: 0/1 grow/shrink: 1/1 up/down: 280/-349) Total: -69 bytes Signed-off-by: Ron Yorston Signed-off-by: Denys Vlasenko --- editors/vi.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/editors/vi.c b/editors/vi.c index 323ca4427..4fa67a110 100644 --- a/editors/vi.c +++ b/editors/vi.c @@ -757,7 +757,7 @@ static void new_screen(int ro, int co) } //----- Synchronize the cursor to Dot -------------------------- -static NOINLINE void sync_cursor(char *d, int *row, int *col) +static void sync_cursor(char *d, int *row, int *col) { char *beg_cur; // begin and end of "d" line char *tp; @@ -3302,8 +3302,8 @@ static void do_cmd(int c) case '+': // +- goto next line do { dot_next(); - dot_skip_over_ws(); } while (--cmdcnt > 0); + dot_skip_over_ws(); break; case 21: // ctrl-U scroll up half screen dot_scroll((rows - 2) / 2, -1); @@ -3451,8 +3451,8 @@ static void do_cmd(int c) case '-': // -- goto prev line do { dot_prev(); - dot_skip_over_ws(); } while (--cmdcnt > 0); + dot_skip_over_ws(); break; #if ENABLE_FEATURE_VI_DOT_CMD case '.': // .- repeat the last modifying command -- cgit v1.2.3-55-g6feb From 24198f652f10dca5603df7c704263358ca21f5ce Mon Sep 17 00:00:00 2001 From: Ron Yorston Date: Tue, 30 Mar 2021 13:02:32 +0100 Subject: vi: deal with invalid movements in shift commands Since commit 25d259264 (vi: make buffer handling more vi-like) find_range() can return early when an invalid movement is specified. The call to find_range() in the code that handles shift commands ('<' and '>') doesn't check for this condition. Previously this only resulted in the current line being shifted but it can now result in a segfault. Check for an invalid movement and notify the user without taking any further action. function old new delta do_cmd 4890 4898 +8 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 1/0 up/down: 8/0) Total: 8 bytes Signed-off-by: Ron Yorston Signed-off-by: Denys Vlasenko --- editors/vi.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/editors/vi.c b/editors/vi.c index 4fa67a110..04d584fec 100644 --- a/editors/vi.c +++ b/editors/vi.c @@ -7,7 +7,6 @@ */ // //Things To Do: -// EXINIT // $HOME/.exrc and ./.exrc // add magic to search /foo.*bar // add :help command @@ -3574,7 +3573,10 @@ static void do_cmd(int c) case '>': // >- Right shift something cnt = count_lines(text, dot); // remember what line we are on c1 = get_motion_char(); // get the type of thing to operate on - find_range(&p, &q, c1); + if (find_range(&p, &q, c1) == -1) { + indicate_error(); + goto dc6; + } yank_delete(p, q, WHOLE, YANKONLY, NO_UNDO); // save copy before change p = begin_line(p); q = end_line(q); -- cgit v1.2.3-55-g6feb From 9f017d9db0eb5522eb9c140a2d839461c677eb8e Mon Sep 17 00:00:00 2001 From: Ron Yorston Date: Tue, 6 Apr 2021 22:11:21 +0100 Subject: vi: changes to option handling Since commit 70ee23399 (vi: code shrink) the ':set' command is unable to process multiple options on a line. Fix this by temporarily null-terminating each option. Change the default setting for all options to off to match vim. Actually, 'flash' isn't an option in vim, only traditional vi, where it's on by default. In vim the corresponding option is 'visualbell' which defaults to off. POSIX doesn't have either of these. Allow the abbreviation 'ts' for the 'tabstop' option. Issue an error message if: - an option is not implemented - an option that takes a value has no '=' or has a 'no' prefix - a boolean option has a '=' function old new delta colon 2944 3003 +59 .rodata 103171 103189 +18 vi_main 274 270 -4 setops 73 - -73 ------------------------------------------------------------------------------ (add/remove: 0/1 grow/shrink: 2/1 up/down: 77/-77) Total: 0 bytes v2: Try harder to detect invalid options. Thanks to Peter D for pointing this out. Signed-off-by: Ron Yorston Signed-off-by: Denys Vlasenko --- editors/vi.c | 91 +++++++++++++++++++++++++++++++++++++----------------------- 1 file changed, 57 insertions(+), 34 deletions(-) diff --git a/editors/vi.c b/editors/vi.c index 04d584fec..1c5a32bf9 100644 --- a/editors/vi.c +++ b/editors/vi.c @@ -278,16 +278,23 @@ struct globals { int text_size; // size of the allocated buffer // the rest - smallint vi_setops; -#define VI_AUTOINDENT 1 -#define VI_SHOWMATCH 2 -#define VI_IGNORECASE 4 -#define VI_ERR_METHOD 8 + smallint vi_setops; // set by setops() +#define VI_AUTOINDENT (1 << 0) +#define VI_ERR_METHOD (1 << 1) +#define VI_IGNORECASE (1 << 2) +#define VI_SHOWMATCH (1 << 3) +#define VI_TABSTOP (1 << 4) #define autoindent (vi_setops & VI_AUTOINDENT) -#define showmatch (vi_setops & VI_SHOWMATCH ) +#define err_method (vi_setops & VI_ERR_METHOD) // indicate error with beep or flash #define ignorecase (vi_setops & VI_IGNORECASE) -// indicate error with beep or flash -#define err_method (vi_setops & VI_ERR_METHOD) +#define showmatch (vi_setops & VI_SHOWMATCH ) +// order of constants and strings must match +#define OPTS_STR \ + "ai\0""autoindent\0" \ + "fl\0""flash\0" \ + "ic\0""ignorecase\0" \ + "sm\0""showmatch\0" \ + "ts\0""tabstop\0" #if ENABLE_FEATURE_VI_READONLY smallint readonly_mode; @@ -2380,17 +2387,38 @@ static char *get_address(char *p, int *b, int *e) // get two colon addrs, if pre } # if ENABLE_FEATURE_VI_SET && ENABLE_FEATURE_VI_SETOPTS -static void setops(const char *args, const char *nm_longname, int flg_no, int opt) +static void setops(char *args, int flg_no) { - const char *a = args + flg_no; + char *eq; + int index; + + eq = strchr(args, '='); + if (eq) *eq = '\0'; + index = index_in_strings(OPTS_STR, args + flg_no); + if (eq) *eq = '='; + if (index < 0) { + bad: + status_line_bold("bad option: %s", args); + return; + } - if (strcmp(a, nm_longname) == 0 - || strcmp(a, nm_longname + 3) == 0 - ) { - if (flg_no) - vi_setops &= ~opt; - else - vi_setops |= opt; + index = 1 << (index >> 1); // convert to VI_bit + + if (index & VI_TABSTOP) { + int t; + if (!eq || flg_no) // no "=NNN" or it is "notabstop"? + goto bad; + t = bb_strtou(eq + 1, NULL, 10); + if (t <= 0 || t > MAX_TABSTOP) + goto bad; + tabstop = t; + return; + } + if (eq) goto bad; // boolean option has "="? + if (flg_no) { + vi_setops &= ~index; + } else { + vi_setops |= index; } } # endif @@ -2750,10 +2778,10 @@ static void colon(char *buf) # if ENABLE_FEATURE_VI_SET } else if (strncmp(cmd, "set", i) == 0) { // set or clear features # if ENABLE_FEATURE_VI_SETOPTS - char *argp; + char *argp, *argn, oldch; # endif // only blank is regarded as args delimiter. What about tab '\t'? - if (!args[0] || strcasecmp(args, "all") == 0) { + if (!args[0] || strcmp(args, "all") == 0) { // print out values of all options # if ENABLE_FEATURE_VI_SETOPTS status_line_bold( @@ -2777,17 +2805,12 @@ static void colon(char *buf) i = 0; if (argp[0] == 'n' && argp[1] == 'o') // "noXXX" i = 2; - setops(argp, "ai""\0""autoindent", i, VI_AUTOINDENT); - setops(argp, "fl""\0""flash" , i, VI_ERR_METHOD); - setops(argp, "ic""\0""ignorecase", i, VI_IGNORECASE); - setops(argp, "sm""\0""showmatch" , i, VI_SHOWMATCH ); - if (strncmp(argp, "tabstop=", 8) == 0) { - int t = bb_strtou(argp + 8, NULL, 10); - if (t > 0 && t <= MAX_TABSTOP) - tabstop = t; - } - argp = skip_non_whitespace(argp); - argp = skip_whitespace(argp); + argn = skip_non_whitespace(argp); + oldch = *argn; + *argn = '\0'; + setops(argp, i); + *argn = oldch; + argp = skip_whitespace(argn); } # endif /* FEATURE_VI_SETOPTS */ # endif /* FEATURE_VI_SET */ @@ -4383,10 +4406,10 @@ int vi_main(int argc, char **argv) } #endif - // autoindent is not default in vim 7.3 - vi_setops = /*VI_AUTOINDENT |*/ VI_SHOWMATCH | VI_IGNORECASE; - // 1- process $HOME/.exrc file (not inplemented yet) - // 2- process EXINIT variable from environment + // 0: all of our options are disabled by default in vim + //vi_setops = 0; + // 1- process EXINIT variable from environment + // 2- if EXINIT is unset process $HOME/.exrc file (not inplemented yet) // 3- process command line args #if ENABLE_FEATURE_VI_COLON { -- cgit v1.2.3-55-g6feb From 7ce0e75c1f26d9cb3061c64aeab3204f62a5b55c Mon Sep 17 00:00:00 2001 From: Ron Yorston Date: Tue, 6 Apr 2021 13:39:48 +0100 Subject: vi: code shrink search commands Changes to search commands ('/', '?', 'n' and 'N'): - Rewrite to be smaller and (possibly) clearer. - Issue a warning when a repeat search is requested without a previous search having been made. Vim and BusyBox vi support a repetition count for searches though the original vi doesn't. If the count exceeds the number of occurrences of the search string the search may loop through the file multiple times. function old new delta .rodata 105135 105119 -16 do_cmd 4898 4860 -38 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 0/2 up/down: 0/-54) Total: -54 bytes Signed-off-by; Ron Yorston Signed-off-by: Denys Vlasenko --- editors/vi.c | 85 +++++++++++++++++++++++++----------------------------------- 1 file changed, 36 insertions(+), 49 deletions(-) diff --git a/editors/vi.c b/editors/vi.c index 1c5a32bf9..5dc14f1ba 100644 --- a/editors/vi.c +++ b/editors/vi.c @@ -3486,70 +3486,57 @@ static void do_cmd(int c) break; #endif #if ENABLE_FEATURE_VI_SEARCH - case '?': // /- search for a pattern - case '/': // /- search for a pattern + case 'N': // N- backward search for last pattern + dir = last_search_pattern[0] == '/' ? BACK : FORWARD; + goto dc4; // now search for pattern + break; + case '?': // ?- backward search for a pattern + case '/': // /- forward search for a pattern buf[0] = c; buf[1] = '\0'; q = get_input_line(buf); // get input line- use "status line" - if (q[0] && !q[1]) { + if (!q[0]) // user changed mind and erased the "/"- do nothing + break; + if (!q[1]) { // if no pat re-use old pat if (last_search_pattern[0]) last_search_pattern[0] = c; - goto dc3; // if no pat re-use old pat - } - if (q[0]) { // strlen(q) > 1: new pat- save it and find - // there is a new pat + } else { // strlen(q) > 1: new pat- save it and find free(last_search_pattern); last_search_pattern = xstrdup(q); - goto dc3; // now find the pattern } - // user changed mind and erased the "/"- do nothing - break; - case 'N': // N- backward search for last pattern - dir = BACK; // assume BACKWARD search - p = dot - 1; - if (last_search_pattern[0] == '?') { - dir = FORWARD; - p = dot + 1; - } - goto dc4; // now search for pattern - break; + // fall through case 'n': // n- repeat search for last pattern // search rest of text[] starting at next char - // if search fails return orignal "p" not the "p+1" address - do { - const char *msg; - dc3: - dir = FORWARD; // assume FORWARD search - p = dot + 1; - if (last_search_pattern[0] == '?') { - dir = BACK; - p = dot - 1; - } + // if search fails "dot" is unchanged + dir = last_search_pattern[0] == '/' ? FORWARD : BACK; dc4: - q = char_search(p, last_search_pattern + 1, (dir << 1) | FULL); + if (last_search_pattern[1] == '\0') { + status_line_bold("No previous search"); + break; + } + do { + q = char_search(dot + dir, last_search_pattern + 1, + (dir << 1) | FULL); if (q != NULL) { dot = q; // good search, update "dot" - msg = NULL; - goto dc2; - } - // no pattern found between "dot" and "end"- continue at top - p = text; - if (dir == BACK) { - p = end - 1; - } - q = char_search(p, last_search_pattern + 1, (dir << 1) | FULL); - if (q != NULL) { // found something - dot = q; // found new pattern- goto it - msg = "search hit BOTTOM, continuing at TOP"; - if (dir == BACK) { - msg = "search hit TOP, continuing at BOTTOM"; - } } else { - msg = "Pattern not found"; + // no pattern found between "dot" and top/bottom of file + // continue from other end of file + const char *msg; + q = char_search(dir == FORWARD ? text : end - 1, + last_search_pattern + 1, (dir << 1) | FULL); + if (q != NULL) { // found something + dot = q; // found new pattern- goto it + msg = "search hit %s, continuing at %s"; + } else { // pattern is nowhere in file + cmdcnt = 0; // force exit from loop + msg = "Pattern not found"; + } + if (dir == FORWARD) + status_line_bold(msg, "BOTTOM", "TOP"); + else + status_line_bold(msg, "TOP", "BOTTOM"); } - dc2: - if (msg) - status_line_bold("%s", msg); } while (--cmdcnt > 0); break; case '{': // {- move backward paragraph -- cgit v1.2.3-55-g6feb From b7b1119d9f95cc956eb0161a59ee21a1daca8f52 Mon Sep 17 00:00:00 2001 From: Ron Yorston Date: Tue, 6 Apr 2021 13:40:23 +0100 Subject: vi: improvements to range selection Rewrite find_range(), pushing quite a bit of code from do_cmd() down into it. - The commands 'y', 'd', 'c', '<' and '>' can be given twice to specify a whole-line range. BusyBox vi actually accepted any second character from that group, e.g. 'dc' or '' commands followed by ESC incorrectly issued an alert. - Allow search commands and a marker (specified as "y'a", for example) to define a range for those operators that support it. function old new delta find_range 518 707 +189 .rodata 105119 105133 +14 get_motion_char 68 - -68 do_cmd 4860 4695 -165 ------------------------------------------------------------------------------ (add/remove: 0/1 grow/shrink: 2/1 up/down: 203/-233) Total: -30 bytes Signed-off-by: Ron Yorston Signed-off-by: Denys Vlasenko --- editors/vi.c | 83 ++++++++++++++++++++++++++++++------------------------------ 1 file changed, 42 insertions(+), 41 deletions(-) diff --git a/editors/vi.c b/editors/vi.c index 5dc14f1ba..9a17f6527 100644 --- a/editors/vi.c +++ b/editors/vi.c @@ -3079,22 +3079,38 @@ static int at_eof(const char *s) return ((s == end - 2 && s[1] == '\n') || s == end - 1); } -static int find_range(char **start, char **stop, char c) +static int find_range(char **start, char **stop, int cmd) { char *save_dot, *p, *q, *t; int buftype = -1; + int c; save_dot = dot; p = q = dot; - if (strchr("cdy><", c)) { +#if ENABLE_FEATURE_VI_YANKMARK + if (cmd == 'Y') { + c = 'y'; + } else +#endif + { + c = get_motion_char(); + } + +#if ENABLE_FEATURE_VI_YANKMARK + if ((cmd == 'Y' || cmd == c) && strchr("cdy><", c)) { +#else + if (cmd == c && strchr("cd><", c)) { +#endif // these cmds operate on whole lines buftype = WHOLE; if (--cmdcnt > 0) do_cmd('j'); - } else if (strchr("^%$0bBeEfFtTh|{}\b\177", c)) { - // These cmds operate on char positions - buftype = PARTIAL; + } else if (strchr("^%$0bBeEfFtThnN/?|{}\b\177", c)) { + // Most operate on char positions within a line. Of those that + // don't '%' needs no special treatment, search commands are + // marked as MULTI and "{}" are handled below. + buftype = strchr("nN/?", c) ? MULTI : PARTIAL; do_cmd(c); // execute movement cmd if (p == dot) // no movement is an error buftype = -1; @@ -3104,7 +3120,16 @@ static int find_range(char **start, char **stop, char c) // step back one char, but not if we're at end of file if (dot > p && !at_eof(dot)) dot--; - } else if (strchr("GHL+-jk\r\n", c)) { + t = dot; + // don't include trailing WS as part of word + while (dot > p && isspace(*dot)) { + if (*dot-- == '\n') + t = dot; + } + // for non-change operations WS after NL is not part of word + if (cmd != 'c' && dot != p && *dot != '\n') + dot = t; + } else if (strchr("GHL+-jk'\r\n", c)) { // these operate on whole lines buftype = WHOLE; do_cmd(c); // execute movement cmd @@ -3119,8 +3144,11 @@ static int find_range(char **start, char **stop, char c) dot--; } - if (buftype == -1) + if (buftype == -1) { + if (c != 27) + indicate_error(); return buftype; + } q = dot; if (q < p) { @@ -3131,7 +3159,7 @@ static int find_range(char **start, char **stop, char c) // movements which don't include end of range if (q > p) { - if (strchr("^0bBFTh|\b\177", c)) { + if (strchr("^0bBFThnN/?|\b\177", c)) { q--; } else if (strchr("{}", c)) { buftype = (p == begin_line(p) && (*q == '\n' || at_eof(q))) ? @@ -3144,7 +3172,7 @@ static int find_range(char **start, char **stop, char c) } } - if (buftype == WHOLE) { + if (buftype == WHOLE || cmd == '<' || cmd == '>') { p = begin_line(p); q = end_line(q); } @@ -3582,14 +3610,9 @@ static void do_cmd(int c) case '<': // <- Left shift something case '>': // >- Right shift something cnt = count_lines(text, dot); // remember what line we are on - c1 = get_motion_char(); // get the type of thing to operate on - if (find_range(&p, &q, c1) == -1) { - indicate_error(); + if (find_range(&p, &q, c) == -1) goto dc6; - } yank_delete(p, q, WHOLE, YANKONLY, NO_UNDO); // save copy before change - p = begin_line(p); - q = end_line(q); i = count_lines(p, q); // # of lines we are shifting for ( ; i > 0; i--, p = next_line(p)) { if (c == '<') { @@ -3820,39 +3843,17 @@ static void do_cmd(int c) case 'Y': // Y- Yank a line #endif { + int yf = YANKDEL; // assume either "c" or "d" + int buftype; #if ENABLE_FEATURE_VI_YANKMARK char *savereg = reg[YDreg]; -#endif - int yf, buftype = 0; - yf = YANKDEL; // assume either "c" or "d" -#if ENABLE_FEATURE_VI_YANKMARK if (c == 'y' || c == 'Y') yf = YANKONLY; #endif - c1 = 'y'; - if (c != 'Y') { - c1 = get_motion_char(); // get the type of thing to operate on - if (c1 == 27) // ESC- user changed mind and wants out - goto dc6; - } // determine range, and whether it spans lines - buftype = find_range(&p, &q, c1); - place_cursor(0, 0); - if (buftype == -1) { // invalid range - indicate_error(); + buftype = find_range(&p, &q, c); + if (buftype == -1) // invalid range goto dc6; - } - if (c1 == 'w' || c1 == 'W') { - char *q0 = q; - // don't include trailing WS as part of word - while (q > p && isspace(*q)) { - if (*q-- == '\n') - q0 = q; - } - // for non-change operations WS after NL is not part of word - if (c != 'c' && q != p && *q != '\n') - q = q0; - } dot = yank_delete(p, q, buftype, yf, ALLOW_UNDO); // delete word if (buftype == WHOLE) { if (c == 'c') { -- cgit v1.2.3-55-g6feb From e577afca7c94a7827bc216f4d8c95823d0f86489 Mon Sep 17 00:00:00 2001 From: Ron Yorston Date: Tue, 6 Apr 2021 13:41:01 +0100 Subject: vi: more fixes to range selection by word An example in my vi book presents different ways to fix the spelling of the last word in a line: ... anyweigh. With the cursor on the 'e' the command 'cway' should do the job. Since commit 776b56d77, though, 'cw' incorrectly includes the full stop in the range if we're on the last line of the file. (Prior to commit 776b56d77 BusyBox vi got 'cw' right in this case but 'cW' wrong: it *didn't* delete the full stop.) Reinstate some of the bloat removed by the earlier commit to fix this. Also, commit 7b4c2276a (vi: fix word operations across line boundaries) incorrectly ignores whitespace after a single character word. Adjust the condition to avoid this. function old new delta find_range 707 737 +30 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 1/0 up/down: 30/0) Total: 30 bytes Signed-off-by: Ron Yorston Signed-off-by: Denys Vlasenko --- editors/vi.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/editors/vi.c b/editors/vi.c index 9a17f6527..7e89f58da 100644 --- a/editors/vi.c +++ b/editors/vi.c @@ -3117,8 +3117,10 @@ static int find_range(char **start, char **stop, int cmd) } else if (strchr("wW", c)) { buftype = MULTI; do_cmd(c); // execute movement cmd - // step back one char, but not if we're at end of file - if (dot > p && !at_eof(dot)) + // step back one char, but not if we're at end of file, + // or if we are at EOF and search was for 'w' and we're at + // the start of a 'W' word. + if (dot > p && (!at_eof(dot) || (c == 'w' && ispunct(*dot)))) dot--; t = dot; // don't include trailing WS as part of word @@ -3127,7 +3129,7 @@ static int find_range(char **start, char **stop, int cmd) t = dot; } // for non-change operations WS after NL is not part of word - if (cmd != 'c' && dot != p && *dot != '\n') + if (cmd != 'c' && dot != t && *dot != '\n') dot = t; } else if (strchr("GHL+-jk'\r\n", c)) { // these operate on whole lines -- cgit v1.2.3-55-g6feb From b18c7bf702b2d7d967b2baf7d70fd8c408191eb4 Mon Sep 17 00:00:00 2001 From: Ron Yorston Date: Sat, 10 Apr 2021 10:20:31 +0100 Subject: vi: improvements to undo The left shift operator ('<') didn't support undo at all; right shift ('>') required changes to be undone separately for each line. Allow both types of shift to be undone as a single operation. Also, neither traditional vi nor vim yank the lines being shifted by the '<' and '>' commands, so remove that call to yank_delete(); When a repetition count was specified for the '~', 'x', 'X' or 's' commands the changes had to be undone one character at a time. Allow undo as a single operation (though the delete and change parts of the 's' command still have to be undone separately). function old new delta undo_push_insert 37 40 +3 do_cmd 4695 4663 -32 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 1/1 up/down: 3/-32) Total: -29 bytes v2: Don't break build when FEATURE_VI_UNDO is disabled. Don't reset 'undo_del' too early in '~' handling code. Code shrink '~'. Signed-off-by: Ron Yorston Signed-off-by: Denys Vlasenko --- editors/vi.c | 35 ++++++++++++++++++++++------------- 1 file changed, 22 insertions(+), 13 deletions(-) diff --git a/editors/vi.c b/editors/vi.c index 7e89f58da..e752685d8 100644 --- a/editors/vi.c +++ b/editors/vi.c @@ -3213,6 +3213,10 @@ static void do_cmd(int c) int dir; int cnt, i, j; int c1; +#if ENABLE_FEATURE_VI_UNDO + int allow_undo = ALLOW_UNDO; + int undo_del = UNDO_DEL; +#endif // c1 = c; // quiet the compiler // cnt = yf = 0; // quiet the compiler @@ -3614,24 +3618,29 @@ static void do_cmd(int c) cnt = count_lines(text, dot); // remember what line we are on if (find_range(&p, &q, c) == -1) goto dc6; - yank_delete(p, q, WHOLE, YANKONLY, NO_UNDO); // save copy before change i = count_lines(p, q); // # of lines we are shifting for ( ; i > 0; i--, p = next_line(p)) { if (c == '<') { // shift left- remove tab or 8 spaces if (*p == '\t') { // shrink buffer 1 char - text_hole_delete(p, p, NO_UNDO); + text_hole_delete(p, p, allow_undo); } else if (*p == ' ') { // we should be calculating columns, not just SPACE for (j = 0; *p == ' ' && j < tabstop; j++) { - text_hole_delete(p, p, NO_UNDO); + text_hole_delete(p, p, allow_undo); +#if ENABLE_FEATURE_VI_UNDO + allow_undo = ALLOW_UNDO_CHAIN; +#endif } } - } else if (c == '>') { + } else /* if (c == '>') */ { // shift right -- add tab or 8 spaces - char_insert(p, '\t', ALLOW_UNDO); + char_insert(p, '\t', allow_undo); } +#if ENABLE_FEATURE_VI_UNDO + allow_undo = ALLOW_UNDO_CHAIN; +#endif } dot = find_line(cnt); // what line were we on dot_skip_over_ws(); @@ -3785,7 +3794,10 @@ static void do_cmd(int c) if (dot[dir] != '\n') { if (c == 'X') dot--; // delete prev char - dot = yank_delete(dot, dot, PARTIAL, YANKDEL, ALLOW_UNDO); // delete char + dot = yank_delete(dot, dot, PARTIAL, YANKDEL, allow_undo); // delete char +#if ENABLE_FEATURE_VI_UNDO + allow_undo = ALLOW_UNDO_CHAIN; +#endif } } while (--cmdcnt > 0); end_cmd_q(); // stop adding to q @@ -3945,14 +3957,11 @@ static void do_cmd(int c) case '~': // ~- flip the case of letters a-z -> A-Z do { #if ENABLE_FEATURE_VI_UNDO - if (islower(*dot)) { - undo_push(dot, 1, UNDO_DEL); - *dot = toupper(*dot); - undo_push(dot, 1, UNDO_INS_CHAIN); - } else if (isupper(*dot)) { - undo_push(dot, 1, UNDO_DEL); - *dot = tolower(*dot); + if (isalpha(*dot)) { + undo_push(dot, 1, undo_del); + *dot = islower(*dot) ? toupper(*dot) : tolower(*dot); undo_push(dot, 1, UNDO_INS_CHAIN); + undo_del = UNDO_DEL_CHAIN; } #else if (islower(*dot)) { -- cgit v1.2.3-55-g6feb From fe76569daa88429276e72dc0c51c0b58d275aee7 Mon Sep 17 00:00:00 2001 From: Ron Yorston Date: Sat, 10 Apr 2021 11:16:47 +0100 Subject: vi: allow 'r' command to be aborted, repeated Make the 'r' command behave more like vi: - abort the command if ESC is entered after the 'r'; - allow a repeat count to be entered before the 'r'; - if the repeat count exceeds the space available on the line don't change any characters and issue an alert. function old new delta do_cmd 4679 4746 +67 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 1/0 up/down: 67/0) Total: 67 bytes v2: Don't break build when FEATURE_VI_UNDO is disabled. Signed-off-by: Ron Yorston Signed-off-by: Denys Vlasenko --- editors/vi.c | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/editors/vi.c b/editors/vi.c index e752685d8..fad53174e 100644 --- a/editors/vi.c +++ b/editors/vi.c @@ -3920,9 +3920,18 @@ static void do_cmd(int c) break; case 'r': // r- replace the current char with user input c1 = get_one_char(); // get the replacement char - if (*dot != '\n') { - dot = text_hole_delete(dot, dot, ALLOW_UNDO); - dot = char_insert(dot, c1, ALLOW_UNDO_CHAIN); + if (c1 != 27) { + if (end_line(dot) - dot < (cmdcnt ?: 1)) { + indicate_error(); + goto dc6; + } + do { + dot = text_hole_delete(dot, dot, allow_undo); +#if ENABLE_FEATURE_VI_UNDO + allow_undo = ALLOW_UNDO_CHAIN; +#endif + dot = char_insert(dot, c1, allow_undo); + } while (--cmdcnt > 0); dot_left(); } end_cmd_q(); // stop adding to q -- cgit v1.2.3-55-g6feb From a54450248b063afd96530821020872bfc9ec9997 Mon Sep 17 00:00:00 2001 From: Ron Yorston Date: Tue, 6 Apr 2021 16:48:07 +0100 Subject: vi: allow the '.' command to have a repetition count The '.' command repeats the last text change. When it has a repetition count replay the change the number of times requested. Update the stored count if it changes. For example, 3dw deletes 3 words . deletes another 3 words 2. deletes 2 words and changes the stored count . deletes 2 words function old new delta do_cmd 4746 4781 +35 .rodata 105133 105138 +5 edit_file 887 849 -38 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 2/1 up/down: 40/-38) Total: 2 bytes v2: Change implementation to include repetition count in string. Otherwise repeating 'r' doesn't work properly. Signed-off-by: Ron Yorston Signed-off-by: Denys Vlasenko --- editors/vi.c | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/editors/vi.c b/editors/vi.c index fad53174e..9a2d7b0d9 100644 --- a/editors/vi.c +++ b/editors/vi.c @@ -338,6 +338,7 @@ struct globals { smallint adding2q; // are we currently adding user input to q int lmc_len; // length of last_modifying_cmd char *ioq, *ioq_start; // pointer to string for get_one_char to "read" + int dotcnt; // number of times to repeat '.' command #endif #if ENABLE_FEATURE_VI_SEARCH char *last_search_pattern; // last pattern from a '/' or '?' search @@ -460,6 +461,7 @@ struct globals { #define lmc_len (G.lmc_len ) #define ioq (G.ioq ) #define ioq_start (G.ioq_start ) +#define dotcnt (G.dotcnt ) #define last_search_pattern (G.last_search_pattern) #define edit_file__cur_line (G.edit_file__cur_line) @@ -1094,8 +1096,8 @@ static int get_one_char(void) } // we are adding STDIN chars to q. c = readit(); - if (lmc_len >= ARRAY_SIZE(last_modifying_cmd) - 1) { - // last_modifying_cmd[] is too small, can't remeber the cmd + if (lmc_len >= ARRAY_SIZE(last_modifying_cmd) - 2) { + // last_modifying_cmd[] is too small, can't remember the cmd // - drop it adding2q = 0; lmc_len = 0; @@ -1863,13 +1865,9 @@ static char *bound_dot(char *p) // make sure text[0] <= P < "end" static void start_new_cmd_q(char c) { // get buffer for new cmd - // if there is a current cmd count put it in the buffer first - if (cmdcnt > 0) { - lmc_len = sprintf(last_modifying_cmd, "%u%c", cmdcnt, c); - } else { // just save char c onto queue - last_modifying_cmd[0] = c; - lmc_len = 1; - } + dotcnt = cmdcnt ?: 1; + last_modifying_cmd[0] = c; + lmc_len = 1; adding2q = 1; } static void end_cmd_q(void) @@ -3515,7 +3513,10 @@ static void do_cmd(int c) // Stuff the last_modifying_cmd back into stdin // and let it be re-executed. if (lmc_len != 0) { - ioq = ioq_start = xstrndup(last_modifying_cmd, lmc_len); + if (cmdcnt) // update saved count if current count is non-zero + dotcnt = cmdcnt; + last_modifying_cmd[lmc_len] = '\0'; + ioq = ioq_start = xasprintf("%u%s", dotcnt, last_modifying_cmd); } break; #endif -- cgit v1.2.3-55-g6feb From 951c6ded3aa7f0dc414306e27aed8b2785965857 Mon Sep 17 00:00:00 2001 From: Ron Yorston Date: Sat, 10 Apr 2021 11:17:38 +0100 Subject: vi: make put commands more like vi Make the put commands 'p' and 'P' behave more like vi: - allow a repetition count to be specified; - when the text being inserted doesn't include a newline the cursor should be positioned at the end of the inserted text. function old new delta do_cmd 4765 4842 +77 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 1/0 up/down: 77/0) Total: 77 bytes v2: Don't break build when FEATURE_VI_UNDO is disabled. Signed-off-by: Ron Yorston Signed-off-by: Denys Vlasenko --- editors/vi.c | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/editors/vi.c b/editors/vi.c index 9a2d7b0d9..fd4526dda 100644 --- a/editors/vi.c +++ b/editors/vi.c @@ -3429,11 +3429,12 @@ static void do_cmd(int c) break; } // are we putting whole lines or strings + cnt = 0; if (regtype[YDreg] == WHOLE) { if (c == 'P') { dot_begin(); // putting lines- Put above } - if (c == 'p') { + else /* if ( c == 'p') */ { // are we putting after very last line? if (end_line(dot) == (end - 1)) { dot = end; // force dot to end of text[] @@ -3444,8 +3445,18 @@ static void do_cmd(int c) } else { if (c == 'p') dot_right(); // move to right, can move to NL + // how far to move cursor if register doesn't have a NL + if (strchr(p, '\n') == NULL) + cnt = (cmdcnt ?: 1) * strlen(p) - 1; } - string_insert(dot, p, ALLOW_UNDO); // insert the string + do { + // dot is adjusted if text[] is reallocated so we don't have to + string_insert(dot, p, allow_undo); // insert the string +# if ENABLE_FEATURE_VI_UNDO + allow_undo = ALLOW_UNDO_CHAIN; +# endif + } while (--cmdcnt > 0); + dot += cnt; end_cmd_q(); // stop adding to q break; case 'U': // U- Undo; replace current line with original version -- cgit v1.2.3-55-g6feb From 6220b4d531a64825eb9698e98afa6be2d92abd8d Mon Sep 17 00:00:00 2001 From: Ron Yorston Date: Tue, 6 Apr 2021 13:43:32 +0100 Subject: vi: make the substitute command more like vi Make the ':s/find/replace/g' command behave more like vi: - the final delimiter is optional if no flag is specified; - the cursor is moved to the first visible character of the last line where a substitution was made; - a warning is displayed if no substitution was made. function old new delta colon 3156 3212 +56 .rodata 105133 105142 +9 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 2/0 up/down: 65/0) Total: 65 bytes Signed-off-by: Ron Yorston Signed-off-by: Denys Vlasenko --- editors/vi.c | 30 +++++++++++++++++------------- 1 file changed, 17 insertions(+), 13 deletions(-) diff --git a/editors/vi.c b/editors/vi.c index fd4526dda..4fda6aebf 100644 --- a/editors/vi.c +++ b/editors/vi.c @@ -2817,10 +2817,8 @@ static void colon(char *buf) } else if (cmd[0] == 's') { // substitute a pattern with a replacement pattern char *F, *R, *flags; size_t len_F, len_R; - int gflag; // global replace flag -# if ENABLE_FEATURE_VI_UNDO - int dont_chain_first_item = ALLOW_UNDO; -# endif + int gflag = 0; // global replace flag + int subs = 0; // number of substitutions // F points to the "find" pattern // R points to the "replace" pattern @@ -2833,11 +2831,11 @@ static void colon(char *buf) len_F = R - F; *R++ = '\0'; // terminate "find" flags = strchr(R, c); - if (!flags) - goto colon_s_fail; - len_R = flags - R; - *flags++ = '\0'; // terminate "replace" - gflag = *flags; + if (flags) { + *flags++ = '\0'; // terminate "replace" + gflag = *flags; + } + len_R = strlen(R); q = begin_line(q); if (b < 0) { // maybe :s/foo/bar/ @@ -2856,14 +2854,15 @@ static void colon(char *buf) uintptr_t bias; // we found the "find" pattern - delete it // For undo support, the first item should not be chained - text_hole_delete(found, found + len_F - 1, dont_chain_first_item); -# if ENABLE_FEATURE_VI_UNDO - dont_chain_first_item = ALLOW_UNDO_CHAIN; -# endif + text_hole_delete(found, found + len_F - 1, + subs ? ALLOW_UNDO_CHAIN: ALLOW_UNDO); + // can't do this above, no undo => no third argument + subs++; // insert the "replace" patern bias = string_insert(found, R, ALLOW_UNDO_CHAIN); found += bias; ls += bias; + dot = ls; //q += bias; - recalculated anyway // check for "global" :s/foo/bar/g if (gflag == 'g') { @@ -2875,6 +2874,11 @@ static void colon(char *buf) } q = next_line(ls); } + if (subs == 0) { + status_line_bold("No match"); + } else { + dot_skip_over_ws(); + } # endif /* FEATURE_VI_SEARCH */ } else if (strncmp(cmd, "version", i) == 0) { // show software version status_line(BB_VER); -- cgit v1.2.3-55-g6feb From 99fb5f2144fc30337ec2ece3d1f59ba92ebed5fb Mon Sep 17 00:00:00 2001 From: Ron Yorston Date: Tue, 6 Apr 2021 13:44:36 +0100 Subject: vi: issue a warning on failure to find a character When a search for a character within a line fails issue a warning. function old new delta ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 0/0 up/down: 0/0) Total: 0 bytes Signed-off-by: Ron Yorston Signed-off-by: Denys Vlasenko --- editors/vi.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/editors/vi.c b/editors/vi.c index 4fda6aebf..96e6af318 100644 --- a/editors/vi.c +++ b/editors/vi.c @@ -1809,8 +1809,10 @@ static void dot_to_char(int cmd) do { do { q += dir; - if ((dir == FORWARD ? q > end - 1 : q < text) || *q == '\n') + if ((dir == FORWARD ? q > end - 1 : q < text) || *q == '\n') { + indicate_error(); return; + } } while (*q != last_search_char); } while (--cmdcnt > 0); -- cgit v1.2.3-55-g6feb From f4a9908b4c21e5e8f544ab9d2bc3770b35942a6b Mon Sep 17 00:00:00 2001 From: Ron Yorston Date: Tue, 6 Apr 2021 13:44:05 +0100 Subject: vi: improvements to reporting of changes Traditional vi is mostly silent about the results of yank, delete, change, undo or substitution commands. Vim reports some details about undo and substitution. BusyBox vi is positively verbose in comparison. Make some improvements to BusyBox vi: - Add vim-like reporting of changes caused by substitutions, of the form '64 substitutions on 53 lines'. This replaces a fairly useless report of the result of the last change made. - Ensure that the report about put operations correctly reflects the newly introduced repetition count. - Commit 25d2592640 tried to limit status updates for delete and yank operations by detecting whether the register had changed. This didn't always work because the previously allocated memory could be reused for the new register contents. Fix this by delaying freeing the old register until after the new one has been allocated. - Add a configuration option to control verbose status reporting. This is on by default. Turning it off make BusyBox vi as taciturn as traditional vi and saves 435 bytes. function old new delta colon 3212 3292 +80 yank_status - 74 +74 static.text_yank 99 86 -13 string_insert 130 76 -54 do_cmd 4842 4776 -66 ------------------------------------------------------------------------------ (add/remove: 1/0 grow/shrink: 1/3 up/down: 154/-133) Total: 21 bytes Signed-off-by: Ron Yorston Signed-off-by: Denys Vlasenko --- editors/vi.c | 90 +++++++++++++++++++++++++++++++++++++++--------------------- 1 file changed, 59 insertions(+), 31 deletions(-) diff --git a/editors/vi.c b/editors/vi.c index 96e6af318..fb46dc381 100644 --- a/editors/vi.c +++ b/editors/vi.c @@ -159,6 +159,14 @@ //config: and will generally malloc() larger objects and less frequently. //config: Unless you want more (or less) frequent "undo points" while typing, //config: you should probably leave this unchanged. +//config: +//config:config FEATURE_VI_VERBOSE_STATUS +//config: bool "Enable verbose status reporting" +//config: default y +//config: depends on VI +//config: help +//config: Enable more verbose reporting of the results of yank, change, +//config: delete, undo and substitution commands. //applet:IF_VI(APPLET(vi, BB_DIR_BIN, BB_SUID_DROP)) @@ -1357,14 +1365,17 @@ static void not_implemented(const char *s) // copy text into a register static char *text_yank(char *p, char *q, int dest, int buftype) { + char *oldreg = reg[dest]; int cnt = q - p; if (cnt < 0) { // they are backwards- reverse them p = q; cnt = -cnt; } - free(reg[dest]); // if already a yank register, free it + // Don't free register yet. This prevents the memory allocator + // from reusing the free block so we can detect if it's changed. reg[dest] = xstrndup(p, cnt + 1); regtype[dest] = buftype; + free(oldreg); return p; } @@ -1415,6 +1426,22 @@ static char *swap_context(char *p) // goto new context for '' command make this } return p; } + +# if ENABLE_FEATURE_VI_VERBOSE_STATUS +static void yank_status(const char *op, const char *p, int cnt) +{ + int lines, chars; + + lines = chars = 0; + while (*p) { + ++chars; + if (*p++ == '\n') + ++lines; + } + status_line("%s %d lines (%d chars) from [%c]", + op, lines * cnt, chars * cnt, what_reg()); +} +# endif #endif /* FEATURE_VI_YANKMARK */ #if ENABLE_FEATURE_VI_UNDO @@ -1687,10 +1714,12 @@ static void undo_pop(void) u_start = text + undo_entry->start; text_hole_make(u_start, undo_entry->length); memcpy(u_start, undo_entry->undo_text, undo_entry->length); +# if ENABLE_FEATURE_VI_VERBOSE_STATUS status_line("Undo [%d] %s %d chars at position %d", modified_count, "restored", undo_entry->length, undo_entry->start ); +# endif break; case UNDO_INS: case UNDO_INS_CHAIN: @@ -1698,10 +1727,12 @@ static void undo_pop(void) u_start = undo_entry->start + text; u_end = u_start - 1 + undo_entry->length; text_hole_delete(u_start, u_end, NO_UNDO); +# if ENABLE_FEATURE_VI_VERBOSE_STATUS status_line("Undo [%d] %s %d chars at position %d", modified_count, "deleted", undo_entry->length, undo_entry->start ); +# endif break; } repeat = 0; @@ -2150,16 +2181,6 @@ static uintptr_t string_insert(char *p, const char *s, int undo) // insert the s bias = text_hole_make(p, i); p += bias; memcpy(p, s, i); -#if ENABLE_FEATURE_VI_YANKMARK - { - int cnt; - for (cnt = 0; *s != '\0'; s++) { - if (*s == '\n') - cnt++; - } - status_line("Put %d lines (%d chars) from [%c]", cnt, i, what_reg()); - } -#endif return bias; } #endif @@ -2821,6 +2842,9 @@ static void colon(char *buf) size_t len_F, len_R; int gflag = 0; // global replace flag int subs = 0; // number of substitutions +# if ENABLE_FEATURE_VI_VERBOSE_STATUS + int last_line = 0, lines = 0; +# endif // F points to the "find" pattern // R points to the "replace" pattern @@ -2860,6 +2884,12 @@ static void colon(char *buf) subs ? ALLOW_UNDO_CHAIN: ALLOW_UNDO); // can't do this above, no undo => no third argument subs++; +# if ENABLE_FEATURE_VI_VERBOSE_STATUS + if (last_line != i) { + last_line = i; + ++lines; + } +# endif // insert the "replace" patern bias = string_insert(found, R, ALLOW_UNDO_CHAIN); found += bias; @@ -2880,6 +2910,10 @@ static void colon(char *buf) status_line_bold("No match"); } else { dot_skip_over_ws(); +# if ENABLE_FEATURE_VI_VERBOSE_STATUS + if (subs > 1) + status_line("%d substitutions on %d lines", subs, lines); +# endif } # endif /* FEATURE_VI_SEARCH */ } else if (strncmp(cmd, "version", i) == 0) { // show software version @@ -3434,8 +3468,9 @@ static void do_cmd(int c) status_line_bold("Nothing in register %c", what_reg()); break; } - // are we putting whole lines or strings cnt = 0; + i = cmdcnt ?: 1; + // are we putting whole lines or strings if (regtype[YDreg] == WHOLE) { if (c == 'P') { dot_begin(); // putting lines- Put above @@ -3453,7 +3488,7 @@ static void do_cmd(int c) dot_right(); // move to right, can move to NL // how far to move cursor if register doesn't have a NL if (strchr(p, '\n') == NULL) - cnt = (cmdcnt ?: 1) * strlen(p) - 1; + cnt = i * strlen(p) - 1; } do { // dot is adjusted if text[] is reallocated so we don't have to @@ -3463,6 +3498,9 @@ static void do_cmd(int c) # endif } while (--cmdcnt > 0); dot += cnt; +# if ENABLE_FEATURE_VI_YANKMARK && ENABLE_FEATURE_VI_VERBOSE_STATUS + yank_status("Put", p, i); +# endif end_cmd_q(); // stop adding to q break; case 'U': // U- Undo; replace current line with original version @@ -3473,6 +3511,9 @@ static void do_cmd(int c) p += string_insert(p, reg[Ureg], ALLOW_UNDO_CHAIN); // insert orig line dot = p; dot_skip_over_ws(); +# if ENABLE_FEATURE_VI_YANKMARK && ENABLE_FEATURE_VI_VERBOSE_STATUS + yank_status("Undo", reg[Ureg], 1); +# endif } break; #endif /* FEATURE_VI_YANKMARK */ @@ -3878,7 +3919,9 @@ static void do_cmd(int c) int yf = YANKDEL; // assume either "c" or "d" int buftype; #if ENABLE_FEATURE_VI_YANKMARK +# if ENABLE_FEATURE_VI_VERBOSE_STATUS char *savereg = reg[YDreg]; +# endif if (c == 'y' || c == 'Y') yf = YANKONLY; #endif @@ -3901,27 +3944,12 @@ static void do_cmd(int c) } // if CHANGING, not deleting, start inserting after the delete if (c == 'c') { - //strcpy(buf, "Change"); goto dc_i; // start inserting } -#if ENABLE_FEATURE_VI_YANKMARK +#if ENABLE_FEATURE_VI_YANKMARK && ENABLE_FEATURE_VI_VERBOSE_STATUS // only update status if a yank has actually happened - if (reg[YDreg] != savereg) { - if (c == 'd') { - strcpy(buf, "Delete"); - } - if (c == 'y' || c == 'Y') { - strcpy(buf, "Yank"); - } - p = reg[YDreg]; - q = p + strlen(p); - for (cnt = 0; p <= q; p++) { - if (*p == '\n') - cnt++; - } - status_line("%s %u lines (%u chars) using [%c]", - buf, cnt, (unsigned)strlen(reg[YDreg]), what_reg()); - } + if (reg[YDreg] != savereg) + yank_status(c == 'd' ? "Delete" : "Yank", reg[YDreg], 1); #endif dc6: end_cmd_q(); // stop adding to q -- cgit v1.2.3-55-g6feb From 7323bca1b00d96630f52bc3b4182558d6f8cbc92 Mon Sep 17 00:00:00 2001 From: Natanael Copa Date: Fri, 9 Apr 2021 17:02:00 +0200 Subject: lineedit: fix tab completion with equal sign Fix tab completion for the path when equal sign (=) is used. For example: dd if=/dev/ze Signed-off-by: Natanael Copa Signed-off-by: Denys Vlasenko --- libbb/lineedit.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libbb/lineedit.c b/libbb/lineedit.c index b0adcf140..2cae4711a 100644 --- a/libbb/lineedit.c +++ b/libbb/lineedit.c @@ -1071,7 +1071,7 @@ static NOINLINE int build_match_prefix(char *match_buf) continue; for (--i; i >= 0; i--) { int cur = int_buf[i]; - if (cur == ' ' || cur == '<' || cur == '>' || cur == '|' || cur == '&') { + if (cur == ' ' || cur == '<' || cur == '>' || cur == '|' || cur == '&' || cur == '=') { remove_chunk(int_buf, 0, i + 1); break; } -- cgit v1.2.3-55-g6feb From 520bb3eac2627e2f6bda05ceb2e3e7db71b73dd3 Mon Sep 17 00:00:00 2001 From: Xabier Oneca Date: Fri, 9 Apr 2021 23:15:29 +0200 Subject: touch: add SUSv3 options -a and -m Add missing -a and -m options to be fully SUSv3 compliant. function old new delta touch_main 415 510 +95 packed_usage 33824 33865 +41 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 2/0 up/down: 136/0) Total: 136 bytes v2: Ignore -a/-m if not ENABLE_FEATURE_TOUCH_SUSV3. Signed-off-by: Xabier Oneca Signed-off-by: Denys Vlasenko --- coreutils/touch.c | 59 ++++++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 45 insertions(+), 14 deletions(-) diff --git a/coreutils/touch.c b/coreutils/touch.c index b30811157..dff68cb00 100644 --- a/coreutils/touch.c +++ b/coreutils/touch.c @@ -28,7 +28,7 @@ //config: This requires libc support for lutimes() function. //config: //config:config FEATURE_TOUCH_SUSV3 -//config: bool "Add support for SUSV3 features (-d -t -r)" +//config: bool "Add support for SUSV3 features (-a -d -m -t -r)" //config: default y //config: depends on TOUCH //config: help @@ -38,11 +38,10 @@ //kbuild:lib-$(CONFIG_TOUCH) += touch.o -/* BB_AUDIT SUSv3 _NOT_ compliant -- options -a, -m not supported. */ -/* http://www.opengroup.org/onlinepubs/007904975/utilities/touch.html */ - //usage:#define touch_trivial_usage -//usage: "[-c]" IF_FEATURE_TOUCH_SUSV3(" [-d DATE] [-t DATE] [-r FILE]") " FILE..." +//usage: "[-c" IF_FEATURE_TOUCH_SUSV3("am") "]" +//usage: IF_FEATURE_TOUCH_SUSV3(" [-d DATE] [-t DATE] [-r FILE]") +//usage: " FILE..." //usage:#define touch_full_usage "\n\n" //usage: "Update the last-modified date on the given FILE[s]\n" //usage: "\n -c Don't create files" @@ -50,6 +49,8 @@ //usage: "\n -h Don't follow links" //usage: ) //usage: IF_FEATURE_TOUCH_SUSV3( +//usage: "\n -a Change only atime" +//usage: "\n -m Change only mtime" //usage: "\n -d DT Date/time to use" //usage: "\n -t DT Date/time to use" //usage: "\n -r FILE Use FILE's date/time" @@ -92,9 +93,13 @@ int touch_main(int argc UNUSED_PARAM, char **argv) OPT_r = (1 << 1) * ENABLE_FEATURE_TOUCH_SUSV3, OPT_d = (1 << 2) * ENABLE_FEATURE_TOUCH_SUSV3, OPT_t = (1 << 3) * ENABLE_FEATURE_TOUCH_SUSV3, - OPT_h = (1 << 4) * ENABLE_FEATURE_TOUCH_NODEREF, + OPT_a = (1 << 4) * ENABLE_FEATURE_TOUCH_SUSV3, + OPT_m = (1 << 5) * ENABLE_FEATURE_TOUCH_SUSV3, + OPT_h = (1 << 6) * ENABLE_FEATURE_TOUCH_NODEREF, }; #if ENABLE_FEATURE_TOUCH_SUSV3 + /* NULL = use current time */ + const struct timeval *newtime = NULL; # if ENABLE_LONG_OPTS static const char touch_longopts[] ALIGN1 = /* name, has_arg, val */ @@ -111,6 +116,7 @@ int touch_main(int argc UNUSED_PARAM, char **argv) # endif char *reference_file = NULL; char *date_str = NULL; + /* timebuf[0] is atime, timebuf[1] is mtime */ struct timeval timebuf[2]; timebuf[1].tv_usec = timebuf[0].tv_usec = 0; #else @@ -124,9 +130,9 @@ int touch_main(int argc UNUSED_PARAM, char **argv) /* -d and -t both set time. In coreutils, * accepted data format differs a bit between -d and -t. * We accept the same formats for both */ - opts = GETOPT32(argv, "c" IF_FEATURE_TOUCH_SUSV3("r:d:t:") + opts = GETOPT32(argv, "c" IF_FEATURE_TOUCH_SUSV3("r:d:t:am") IF_FEATURE_TOUCH_NODEREF("h") - /*ignored:*/ "fma" + /*ignored:*/ "f" IF_NOT_FEATURE_TOUCH_SUSV3("am") LONGOPTS IF_FEATURE_TOUCH_SUSV3(, &reference_file) IF_FEATURE_TOUCH_SUSV3(, &date_str) @@ -146,6 +152,7 @@ int touch_main(int argc UNUSED_PARAM, char **argv) * (or is it .st_mtimensec?? see date.c) * to set microseconds too. */ + newtime = timebuf; } if (date_str) { @@ -163,15 +170,39 @@ int touch_main(int argc UNUSED_PARAM, char **argv) t = validate_tm_time(date_str, &tm_time); timebuf[1].tv_sec = timebuf[0].tv_sec = t; + newtime = timebuf; + } + + if ((opts & (OPT_a | OPT_m)) && !newtime) { + time(&timebuf[0].tv_sec); + timebuf[1].tv_sec = timebuf[0].tv_sec; + newtime = timebuf; } do { int result; - result = ( -#if ENABLE_FEATURE_TOUCH_NODEREF - (opts & OPT_h) ? lutimes : -#endif - utimes)(*argv, (reference_file || date_str) ? timebuf : NULL); + + if (opts & (OPT_a | OPT_m)) { + /* Save original times */ + struct stat stbuf; + if (stat(*argv, &stbuf) == 0) { + /* As we must set both times, we lose original + * file time microseconds. + * Can use .st_mtim.tv_nsec + * (or is it .st_mtimensec?? see date.c) + * to set microseconds too. + * Also, utimensat(2) allows to omit one of the + * times to be set. But it is SUSv4. + */ + if (!(opts & OPT_a)) + timebuf[0].tv_sec = stbuf.st_atime; + if (!(opts & OPT_m)) + timebuf[1].tv_sec = stbuf.st_mtime; + } + } + + result = (ENABLE_FEATURE_TOUCH_NODEREF && (opts & OPT_h) ? lutimes : utimes)(*argv, newtime); + if (result != 0) { if (errno == ENOENT) { /* no such file? */ if (opts & OPT_c) { @@ -183,7 +214,7 @@ int touch_main(int argc UNUSED_PARAM, char **argv) if (fd >= 0) { xclose(fd); if (reference_file || date_str) - utimes(*argv, timebuf); + utimes(*argv, newtime); continue; } } -- cgit v1.2.3-55-g6feb From de1a49cb419d931a62500eaddb7c888ee011eefe Mon Sep 17 00:00:00 2001 From: Xabier Oneca Date: Thu, 8 Apr 2021 02:05:37 +0200 Subject: touch: fix atime set from reference file When using a file's times as reference, use both atime and mtime for the files to be modified. Signed-off-by: Xabier Oneca Signed-off-by: Denys Vlasenko --- coreutils/touch.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/coreutils/touch.c b/coreutils/touch.c index dff68cb00..68fb625fe 100644 --- a/coreutils/touch.c +++ b/coreutils/touch.c @@ -147,7 +147,8 @@ int touch_main(int argc UNUSED_PARAM, char **argv) if (reference_file) { struct stat stbuf; xstat(reference_file, &stbuf); - timebuf[1].tv_sec = timebuf[0].tv_sec = stbuf.st_mtime; + timebuf[0].tv_sec = stbuf.st_atime; + timebuf[1].tv_sec = stbuf.st_mtime; /* Can use .st_mtim.tv_nsec * (or is it .st_mtimensec?? see date.c) * to set microseconds too. -- cgit v1.2.3-55-g6feb From 7ec254467c58047a8105fa688044e88f04a806d6 Mon Sep 17 00:00:00 2001 From: Xabier Oneca Date: Fri, 9 Apr 2021 23:27:41 +0200 Subject: touch: remove unneeded GETOPT32 defines Long options handling (getopt32 vs getopt32long) is done in libbb.h, no need to care here of the same logic. This cleans the code a bit. Also, --no-create was grouped as a SUSv3 option, where as the short -c was not. Even if it is part of SUS, leave it out as was the short option. v2: Fix for disabled ENABLE_LONG_OPTS. getopt32long does not like IF_FEATURE_xxx() style conditionals... :/ Signed-off-by: Xabier Oneca Signed-off-by: Denys Vlasenko --- coreutils/touch.c | 31 +++++++++++++------------------ 1 file changed, 13 insertions(+), 18 deletions(-) diff --git a/coreutils/touch.c b/coreutils/touch.c index 68fb625fe..92e134168 100644 --- a/coreutils/touch.c +++ b/coreutils/touch.c @@ -97,23 +97,18 @@ int touch_main(int argc UNUSED_PARAM, char **argv) OPT_m = (1 << 5) * ENABLE_FEATURE_TOUCH_SUSV3, OPT_h = (1 << 6) * ENABLE_FEATURE_TOUCH_NODEREF, }; -#if ENABLE_FEATURE_TOUCH_SUSV3 /* NULL = use current time */ const struct timeval *newtime = NULL; -# if ENABLE_LONG_OPTS +#if ENABLE_LONG_OPTS static const char touch_longopts[] ALIGN1 = /* name, has_arg, val */ "no-create\0" No_argument "c" - "reference\0" Required_argument "r" - "date\0" Required_argument "d" + IF_FEATURE_TOUCH_SUSV3("reference\0" Required_argument "r") + IF_FEATURE_TOUCH_SUSV3("date\0" Required_argument "d") IF_FEATURE_TOUCH_NODEREF("no-dereference\0" No_argument "h") ; -# define GETOPT32 getopt32long -# define LONGOPTS ,touch_longopts -# else -# define GETOPT32 getopt32 -# define LONGOPTS -# endif +#endif +#if ENABLE_FEATURE_TOUCH_SUSV3 char *reference_file = NULL; char *date_str = NULL; /* timebuf[0] is atime, timebuf[1] is mtime */ @@ -123,20 +118,20 @@ int touch_main(int argc UNUSED_PARAM, char **argv) # define reference_file NULL # define date_str NULL # define timebuf ((struct timeval*)NULL) -# define GETOPT32 getopt32 -# define LONGOPTS #endif /* -d and -t both set time. In coreutils, * accepted data format differs a bit between -d and -t. * We accept the same formats for both */ - opts = GETOPT32(argv, "c" IF_FEATURE_TOUCH_SUSV3("r:d:t:am") + opts = getopt32long(argv, "c" IF_FEATURE_TOUCH_SUSV3("r:d:t:am") IF_FEATURE_TOUCH_NODEREF("h") - /*ignored:*/ "f" IF_NOT_FEATURE_TOUCH_SUSV3("am") - LONGOPTS - IF_FEATURE_TOUCH_SUSV3(, &reference_file) - IF_FEATURE_TOUCH_SUSV3(, &date_str) - IF_FEATURE_TOUCH_SUSV3(, &date_str) + /*ignored:*/ "f" IF_NOT_FEATURE_TOUCH_SUSV3("am"), + touch_longopts +#if ENABLE_FEATURE_TOUCH_SUSV3 + , &reference_file + , &date_str + , &date_str +#endif ); argv += optind; -- cgit v1.2.3-55-g6feb From 1a181264d51bc3f3a3c66f756da84ab61b6823d4 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Mon, 12 Apr 2021 20:12:56 +0200 Subject: touch: unbreak -h Signed-off-by: Denys Vlasenko --- coreutils/touch.c | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/coreutils/touch.c b/coreutils/touch.c index 92e134168..690517e66 100644 --- a/coreutils/touch.c +++ b/coreutils/touch.c @@ -90,12 +90,12 @@ int touch_main(int argc UNUSED_PARAM, char **argv) int opts; enum { OPT_c = (1 << 0), - OPT_r = (1 << 1) * ENABLE_FEATURE_TOUCH_SUSV3, - OPT_d = (1 << 2) * ENABLE_FEATURE_TOUCH_SUSV3, - OPT_t = (1 << 3) * ENABLE_FEATURE_TOUCH_SUSV3, - OPT_a = (1 << 4) * ENABLE_FEATURE_TOUCH_SUSV3, - OPT_m = (1 << 5) * ENABLE_FEATURE_TOUCH_SUSV3, - OPT_h = (1 << 6) * ENABLE_FEATURE_TOUCH_NODEREF, + OPT_h = (1 << 1) * ENABLE_FEATURE_TOUCH_NODEREF, + OPT_r = (1 << (1+ENABLE_FEATURE_TOUCH_NODEREF)) * ENABLE_FEATURE_TOUCH_SUSV3, + OPT_d = (1 << (2+ENABLE_FEATURE_TOUCH_NODEREF)) * ENABLE_FEATURE_TOUCH_SUSV3, + OPT_t = (1 << (3+ENABLE_FEATURE_TOUCH_NODEREF)) * ENABLE_FEATURE_TOUCH_SUSV3, + OPT_a = (1 << (4+ENABLE_FEATURE_TOUCH_NODEREF)) * ENABLE_FEATURE_TOUCH_SUSV3, + OPT_m = (1 << (5+ENABLE_FEATURE_TOUCH_NODEREF)) * ENABLE_FEATURE_TOUCH_SUSV3, }; /* NULL = use current time */ const struct timeval *newtime = NULL; @@ -122,9 +122,10 @@ int touch_main(int argc UNUSED_PARAM, char **argv) /* -d and -t both set time. In coreutils, * accepted data format differs a bit between -d and -t. - * We accept the same formats for both */ - opts = getopt32long(argv, "c" IF_FEATURE_TOUCH_SUSV3("r:d:t:am") - IF_FEATURE_TOUCH_NODEREF("h") + * We accept the same formats for both + */ + opts = getopt32long(argv, "c" IF_FEATURE_TOUCH_NODEREF("h") + IF_FEATURE_TOUCH_SUSV3("r:d:t:am") /*ignored:*/ "f" IF_NOT_FEATURE_TOUCH_SUSV3("am"), touch_longopts #if ENABLE_FEATURE_TOUCH_SUSV3 -- cgit v1.2.3-55-g6feb From 79c92dbd7028a9782b85fcbbbe123e1c44cbaec1 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Sun, 11 Apr 2021 06:41:31 +0100 Subject: touch: switch to using utimensat() and futimens() This patch changes the functions used to update timestamps in touch. Before, utimes() and lutimes() were used, which had certain disadvantages. They are unable to handle nanosecond timestamps, and implementations of certain features like -a and -m require running stat() in a loop. Almost all implementations of utimes() and lutimes() are wrappers for utimensat(), this is the case for glibc, ulibc and musl libc. function old new delta __futimens_time64 - 24 +24 __lutimes_time64 80 - -80 touch_main 539 456 -83 ------------------------------------------------------------------------------ (add/remove: 2/2 grow/shrink: 0/1 up/down: 24/-163) Total: -139 bytes Signed-off-by: urmum-69 Signed-off-by: Denys Vlasenko --- coreutils/touch.c | 57 ++++++++++++++++--------------------------------------- 1 file changed, 16 insertions(+), 41 deletions(-) diff --git a/coreutils/touch.c b/coreutils/touch.c index 690517e66..8d3f8dbbe 100644 --- a/coreutils/touch.c +++ b/coreutils/touch.c @@ -25,7 +25,6 @@ //config: depends on TOUCH //config: help //config: Enable touch to have the -h option. -//config: This requires libc support for lutimes() function. //config: //config:config FEATURE_TOUCH_SUSV3 //config: bool "Add support for SUSV3 features (-a -d -m -t -r)" @@ -97,8 +96,6 @@ int touch_main(int argc UNUSED_PARAM, char **argv) OPT_a = (1 << (4+ENABLE_FEATURE_TOUCH_NODEREF)) * ENABLE_FEATURE_TOUCH_SUSV3, OPT_m = (1 << (5+ENABLE_FEATURE_TOUCH_NODEREF)) * ENABLE_FEATURE_TOUCH_SUSV3, }; - /* NULL = use current time */ - const struct timeval *newtime = NULL; #if ENABLE_LONG_OPTS static const char touch_longopts[] ALIGN1 = /* name, has_arg, val */ @@ -112,12 +109,11 @@ int touch_main(int argc UNUSED_PARAM, char **argv) char *reference_file = NULL; char *date_str = NULL; /* timebuf[0] is atime, timebuf[1] is mtime */ - struct timeval timebuf[2]; - timebuf[1].tv_usec = timebuf[0].tv_usec = 0; + struct timespec timebuf[2]; #else # define reference_file NULL # define date_str NULL -# define timebuf ((struct timeval*)NULL) +# define timebuf ((struct timespec*)NULL) #endif /* -d and -t both set time. In coreutils, @@ -140,16 +136,15 @@ int touch_main(int argc UNUSED_PARAM, char **argv) bb_show_usage(); } + timebuf[0].tv_nsec = timebuf[1].tv_nsec = UTIME_NOW; + if (reference_file) { struct stat stbuf; xstat(reference_file, &stbuf); timebuf[0].tv_sec = stbuf.st_atime; timebuf[1].tv_sec = stbuf.st_mtime; - /* Can use .st_mtim.tv_nsec - * (or is it .st_mtimensec?? see date.c) - * to set microseconds too. - */ - newtime = timebuf; + timebuf[0].tv_nsec = stbuf.st_atim.tv_nsec; + timebuf[1].tv_nsec = stbuf.st_mtim.tv_nsec; } if (date_str) { @@ -167,39 +162,19 @@ int touch_main(int argc UNUSED_PARAM, char **argv) t = validate_tm_time(date_str, &tm_time); timebuf[1].tv_sec = timebuf[0].tv_sec = t; - newtime = timebuf; + timebuf[1].tv_nsec = timebuf[0].tv_nsec = 0; } - if ((opts & (OPT_a | OPT_m)) && !newtime) { - time(&timebuf[0].tv_sec); - timebuf[1].tv_sec = timebuf[0].tv_sec; - newtime = timebuf; + if (opts & OPT_a) { + timebuf[1].tv_nsec = UTIME_OMIT; + } + if (opts & OPT_m) { + timebuf[0].tv_nsec = UTIME_OMIT; } do { - int result; - - if (opts & (OPT_a | OPT_m)) { - /* Save original times */ - struct stat stbuf; - if (stat(*argv, &stbuf) == 0) { - /* As we must set both times, we lose original - * file time microseconds. - * Can use .st_mtim.tv_nsec - * (or is it .st_mtimensec?? see date.c) - * to set microseconds too. - * Also, utimensat(2) allows to omit one of the - * times to be set. But it is SUSv4. - */ - if (!(opts & OPT_a)) - timebuf[0].tv_sec = stbuf.st_atime; - if (!(opts & OPT_m)) - timebuf[1].tv_sec = stbuf.st_mtime; - } - } - - result = (ENABLE_FEATURE_TOUCH_NODEREF && (opts & OPT_h) ? lutimes : utimes)(*argv, newtime); - + int result = utimensat(AT_FDCWD, *argv, timebuf, + (opts & OPT_h) ? AT_SYMLINK_NOFOLLOW : 0); if (result != 0) { if (errno == ENOENT) { /* no such file? */ if (opts & OPT_c) { @@ -209,9 +184,9 @@ int touch_main(int argc UNUSED_PARAM, char **argv) /* Try to create the file */ fd = open(*argv, O_RDWR | O_CREAT, 0666); if (fd >= 0) { - xclose(fd); if (reference_file || date_str) - utimes(*argv, newtime); + futimens(fd, timebuf); + xclose(fd); continue; } } -- cgit v1.2.3-55-g6feb From e3c6a0973c8a4fe17d2510093738ef5ae052523e Mon Sep 17 00:00:00 2001 From: Xabier Oneca Date: Sat, 10 Apr 2021 00:11:46 +0200 Subject: touch: prevent usage of -r and -t at once coreutils forbids this combination. Signed-off-by: Xabier Oneca Signed-off-by: Denys Vlasenko --- coreutils/touch.c | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/coreutils/touch.c b/coreutils/touch.c index 8d3f8dbbe..189428a79 100644 --- a/coreutils/touch.c +++ b/coreutils/touch.c @@ -120,14 +120,18 @@ int touch_main(int argc UNUSED_PARAM, char **argv) * accepted data format differs a bit between -d and -t. * We accept the same formats for both */ - opts = getopt32long(argv, "c" IF_FEATURE_TOUCH_NODEREF("h") - IF_FEATURE_TOUCH_SUSV3("r:d:t:am") - /*ignored:*/ "f" IF_NOT_FEATURE_TOUCH_SUSV3("am"), - touch_longopts + opts = getopt32long(argv, "^" + "c" IF_FEATURE_TOUCH_NODEREF("h") + IF_FEATURE_TOUCH_SUSV3("r:d:t:am") + /*ignored:*/ "f" IF_NOT_FEATURE_TOUCH_SUSV3("am") + "\0" /* opt_complementary: */ + /* coreutils forbids -r and -t at once: */ IF_FEATURE_TOUCH_SUSV3("r--t:t--r") + /* but allows these combinations: "r--d:d--r:t--d:d--t" */, + touch_longopts #if ENABLE_FEATURE_TOUCH_SUSV3 - , &reference_file - , &date_str - , &date_str + , &reference_file + , &date_str + , &date_str #endif ); -- cgit v1.2.3-55-g6feb From 6f63a2ba0e54f7fc8ec66d470beb0212dd1b4d4f Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Tue, 13 Apr 2021 15:11:47 +0200 Subject: touch: code shrink function old new delta .rodata 103215 103218 +3 touch_main 460 450 -10 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 1/1 up/down: 3/-10) Total: -7 bytes Signed-off-by: Denys Vlasenko --- coreutils/touch.c | 40 +++++++++++++++++----------------------- 1 file changed, 17 insertions(+), 23 deletions(-) diff --git a/coreutils/touch.c b/coreutils/touch.c index 189428a79..43312d22a 100644 --- a/coreutils/touch.c +++ b/coreutils/touch.c @@ -85,8 +85,19 @@ int touch_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int touch_main(int argc UNUSED_PARAM, char **argv) { int fd; - int status = EXIT_SUCCESS; int opts; + smalluint status = EXIT_SUCCESS; +#if ENABLE_FEATURE_TOUCH_SUSV3 + char *reference_file = NULL; + char *date_str = NULL; + /* timebuf[0] is atime, timebuf[1] is mtime */ + struct timespec timebuf[2]; +#else +# define reference_file NULL +# define date_str NULL +# define timebuf ((struct timespec*)NULL) +#endif + enum { OPT_c = (1 << 0), OPT_h = (1 << 1) * ENABLE_FEATURE_TOUCH_NODEREF, @@ -105,17 +116,6 @@ int touch_main(int argc UNUSED_PARAM, char **argv) IF_FEATURE_TOUCH_NODEREF("no-dereference\0" No_argument "h") ; #endif -#if ENABLE_FEATURE_TOUCH_SUSV3 - char *reference_file = NULL; - char *date_str = NULL; - /* timebuf[0] is atime, timebuf[1] is mtime */ - struct timespec timebuf[2]; -#else -# define reference_file NULL -# define date_str NULL -# define timebuf ((struct timespec*)NULL) -#endif - /* -d and -t both set time. In coreutils, * accepted data format differs a bit between -d and -t. * We accept the same formats for both @@ -125,9 +125,10 @@ int touch_main(int argc UNUSED_PARAM, char **argv) IF_FEATURE_TOUCH_SUSV3("r:d:t:am") /*ignored:*/ "f" IF_NOT_FEATURE_TOUCH_SUSV3("am") "\0" /* opt_complementary: */ - /* coreutils forbids -r and -t at once: */ IF_FEATURE_TOUCH_SUSV3("r--t:t--r") - /* but allows these combinations: "r--d:d--r:t--d:d--t" */, - touch_longopts + /* at least one arg: */ "-1" + /* coreutils forbids -r and -t at once: */ IF_FEATURE_TOUCH_SUSV3(":r--t:t--r") + /* but allows these combinations: "r--d:d--r:t--d:d--t" */ + , touch_longopts #if ENABLE_FEATURE_TOUCH_SUSV3 , &reference_file , &date_str @@ -135,13 +136,7 @@ int touch_main(int argc UNUSED_PARAM, char **argv) #endif ); - argv += optind; - if (!*argv) { - bb_show_usage(); - } - timebuf[0].tv_nsec = timebuf[1].tv_nsec = UTIME_NOW; - if (reference_file) { struct stat stbuf; xstat(reference_file, &stbuf); @@ -150,7 +145,6 @@ int touch_main(int argc UNUSED_PARAM, char **argv) timebuf[0].tv_nsec = stbuf.st_atim.tv_nsec; timebuf[1].tv_nsec = stbuf.st_mtim.tv_nsec; } - if (date_str) { struct tm tm_time; time_t t; @@ -168,7 +162,6 @@ int touch_main(int argc UNUSED_PARAM, char **argv) timebuf[1].tv_sec = timebuf[0].tv_sec = t; timebuf[1].tv_nsec = timebuf[0].tv_nsec = 0; } - if (opts & OPT_a) { timebuf[1].tv_nsec = UTIME_OMIT; } @@ -176,6 +169,7 @@ int touch_main(int argc UNUSED_PARAM, char **argv) timebuf[0].tv_nsec = UTIME_OMIT; } + argv += optind; do { int result = utimensat(AT_FDCWD, *argv, timebuf, (opts & OPT_h) ? AT_SYMLINK_NOFOLLOW : 0); -- cgit v1.2.3-55-g6feb From 36300545046a4f33dca90cedf14a6025a313aeac Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Tue, 13 Apr 2021 15:41:57 +0200 Subject: touch: code shrink function old new delta touch_main 450 423 -27 Signed-off-by: Denys Vlasenko --- coreutils/touch.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/coreutils/touch.c b/coreutils/touch.c index 43312d22a..52605fb7c 100644 --- a/coreutils/touch.c +++ b/coreutils/touch.c @@ -88,8 +88,8 @@ int touch_main(int argc UNUSED_PARAM, char **argv) int opts; smalluint status = EXIT_SUCCESS; #if ENABLE_FEATURE_TOUCH_SUSV3 - char *reference_file = NULL; - char *date_str = NULL; + char *reference_file; + char *date_str; /* timebuf[0] is atime, timebuf[1] is mtime */ struct timespec timebuf[2]; #else @@ -137,7 +137,7 @@ int touch_main(int argc UNUSED_PARAM, char **argv) ); timebuf[0].tv_nsec = timebuf[1].tv_nsec = UTIME_NOW; - if (reference_file) { + if (opts & OPT_r) { struct stat stbuf; xstat(reference_file, &stbuf); timebuf[0].tv_sec = stbuf.st_atime; @@ -145,7 +145,7 @@ int touch_main(int argc UNUSED_PARAM, char **argv) timebuf[0].tv_nsec = stbuf.st_atim.tv_nsec; timebuf[1].tv_nsec = stbuf.st_mtim.tv_nsec; } - if (date_str) { + if (opts & (OPT_d|OPT_t)) { struct tm tm_time; time_t t; -- cgit v1.2.3-55-g6feb From 6b6ff80299cd840849532405b4ca758ce44089f5 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Tue, 13 Apr 2021 15:44:13 +0200 Subject: touch: make FEATURE_TOUCH_NODEREF unconditional Signed-off-by: Denys Vlasenko --- coreutils/touch.c | 27 +++++++++------------------ 1 file changed, 9 insertions(+), 18 deletions(-) diff --git a/coreutils/touch.c b/coreutils/touch.c index 52605fb7c..355455363 100644 --- a/coreutils/touch.c +++ b/coreutils/touch.c @@ -19,13 +19,6 @@ //config: touch is used to create or change the access and/or //config: modification timestamp of specified files. //config: -//config:config FEATURE_TOUCH_NODEREF -//config: bool "Add support for -h" -//config: default y -//config: depends on TOUCH -//config: help -//config: Enable touch to have the -h option. -//config: //config:config FEATURE_TOUCH_SUSV3 //config: bool "Add support for SUSV3 features (-a -d -m -t -r)" //config: default y @@ -44,9 +37,7 @@ //usage:#define touch_full_usage "\n\n" //usage: "Update the last-modified date on the given FILE[s]\n" //usage: "\n -c Don't create files" -//usage: IF_FEATURE_TOUCH_NODEREF( //usage: "\n -h Don't follow links" -//usage: ) //usage: IF_FEATURE_TOUCH_SUSV3( //usage: "\n -a Change only atime" //usage: "\n -m Change only mtime" @@ -100,20 +91,20 @@ int touch_main(int argc UNUSED_PARAM, char **argv) enum { OPT_c = (1 << 0), - OPT_h = (1 << 1) * ENABLE_FEATURE_TOUCH_NODEREF, - OPT_r = (1 << (1+ENABLE_FEATURE_TOUCH_NODEREF)) * ENABLE_FEATURE_TOUCH_SUSV3, - OPT_d = (1 << (2+ENABLE_FEATURE_TOUCH_NODEREF)) * ENABLE_FEATURE_TOUCH_SUSV3, - OPT_t = (1 << (3+ENABLE_FEATURE_TOUCH_NODEREF)) * ENABLE_FEATURE_TOUCH_SUSV3, - OPT_a = (1 << (4+ENABLE_FEATURE_TOUCH_NODEREF)) * ENABLE_FEATURE_TOUCH_SUSV3, - OPT_m = (1 << (5+ENABLE_FEATURE_TOUCH_NODEREF)) * ENABLE_FEATURE_TOUCH_SUSV3, + OPT_h = (1 << 1), + OPT_r = (1 << 2) * ENABLE_FEATURE_TOUCH_SUSV3, + OPT_d = (1 << 3) * ENABLE_FEATURE_TOUCH_SUSV3, + OPT_t = (1 << 4) * ENABLE_FEATURE_TOUCH_SUSV3, + OPT_a = (1 << 5) * ENABLE_FEATURE_TOUCH_SUSV3, + OPT_m = (1 << 6) * ENABLE_FEATURE_TOUCH_SUSV3, }; #if ENABLE_LONG_OPTS static const char touch_longopts[] ALIGN1 = /* name, has_arg, val */ - "no-create\0" No_argument "c" + "no-create\0" No_argument "c" + "no-dereference\0" No_argument "h" IF_FEATURE_TOUCH_SUSV3("reference\0" Required_argument "r") IF_FEATURE_TOUCH_SUSV3("date\0" Required_argument "d") - IF_FEATURE_TOUCH_NODEREF("no-dereference\0" No_argument "h") ; #endif /* -d and -t both set time. In coreutils, @@ -121,7 +112,7 @@ int touch_main(int argc UNUSED_PARAM, char **argv) * We accept the same formats for both */ opts = getopt32long(argv, "^" - "c" IF_FEATURE_TOUCH_NODEREF("h") + "ch" IF_FEATURE_TOUCH_SUSV3("r:d:t:am") /*ignored:*/ "f" IF_NOT_FEATURE_TOUCH_SUSV3("am") "\0" /* opt_complementary: */ -- cgit v1.2.3-55-g6feb From 9c210f0efb1959895df237a96210a73253b5b9ed Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Tue, 13 Apr 2021 15:49:06 +0200 Subject: touch: fix previous commit function old new delta touch_main 423 414 -9 Signed-off-by: Denys Vlasenko --- coreutils/touch.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/coreutils/touch.c b/coreutils/touch.c index 355455363..6c0201374 100644 --- a/coreutils/touch.c +++ b/coreutils/touch.c @@ -173,7 +173,7 @@ int touch_main(int argc UNUSED_PARAM, char **argv) /* Try to create the file */ fd = open(*argv, O_RDWR | O_CREAT, 0666); if (fd >= 0) { - if (reference_file || date_str) + if (opts & (OPT_r|OPT_d|OPT_t)) futimens(fd, timebuf); xclose(fd); continue; -- cgit v1.2.3-55-g6feb From 50a37459ff991cab97e7326490d0637ff1106cc8 Mon Sep 17 00:00:00 2001 From: Rasmus Villemoes Date: Tue, 6 Apr 2021 10:14:53 +0200 Subject: watchdog: make open-write-close-open functionality a config knob The behaviour introduced by commit 31c765081dc4 ("watchdog: stop watchdog first on startup") causes warnings in the kernel log when the nowayout feature is enabled: [ 16.212184] watchdog: watchdog0: nowayout prevents watchdog being stopped! [ 16.212196] watchdog: watchdog0: watchdog did not stop! The latter may also appear by itself in case the watchdog is of the type that cannot be stopped once started (e.g. the common always-running gpio_wdt kind). These warnings can be somewhat ominous and distracting, so allow configuring whether to use this open-write-close-open sequence rather than just open. Also saves a bit of .text when disabled: function old new delta shutdown_on_signal 31 58 +27 watchdog_main 339 306 -33 shutdown_watchdog 34 - -34 ------------------------------------------------------------------------------ (add/remove: 0/1 grow/shrink: 1/1 up/down: 27/-67) Total: -40 bytes Make it default n: - It's a workaround for one specific type of watchdog (and that seems to be a defect in the kernel driver) - Even when not enabled in busybox config, it can easily be implemented outside busybox - Code size - Commit 31c765081dc4 should be considered a regression for all the boards that now end up with KERN_CRIT warnings in dmesg. - The author of that commit said "This use case is evidently rare, so if it is indeed causing problems for other people I'd OK then I understand whatever needs to be done." in the v1 thread. Cc: Matt Spinler Cc: deweloper@wp.pl Cc: tito Signed-off-by: Rasmus Villemoes Signed-off-by: Denys Vlasenko --- miscutils/watchdog.c | 26 +++++++++++++++++++++----- 1 file changed, 21 insertions(+), 5 deletions(-) diff --git a/miscutils/watchdog.c b/miscutils/watchdog.c index 0ed10bcf1..44649cae6 100644 --- a/miscutils/watchdog.c +++ b/miscutils/watchdog.c @@ -18,6 +18,21 @@ //config: watchdog applet ever fails to write the magic character within a //config: certain amount of time, the watchdog device assumes the system has //config: hung, and will cause the hardware to reboot. +//config: +//config:config FEATURE_WATCHDOG_OPEN_TWICE +//config: bool "Open watchdog device twice, closing it gracefully in between" +//config: depends on WATCHDOG +//config: default n # this behavior was essentially a hack for a broken driver +//config: help +//config: When enabled, the watchdog device is opened and then immediately +//config: magic-closed, before being opened a second time. This may be necessary +//config: for some watchdog devices, but can cause spurious warnings in the +//config: kernel log if the nowayout feature is enabled. Also, if this workaround +//config: is really needed for you machine to work properly, consider whether +//config: it should be fixed in the kernel driver instead. Even when disabled, +//config: the behaviour is easily emulated with a "printf 'V' > /dev/watchdog" +//config: immediately before starting the busybox watchdog daemon. Say n unless +//config: you know that you absolutely need this. //applet:IF_WATCHDOG(APPLET(watchdog, BB_DIR_SBIN, BB_SUID_DROP)) @@ -50,10 +65,6 @@ # define WDIOS_ENABLECARD 2 #endif -#define OPT_FOREGROUND (1 << 0) -#define OPT_STIMER (1 << 1) -#define OPT_HTIMER (1 << 2) - static void shutdown_watchdog(void) { static const char V = 'V'; @@ -73,6 +84,7 @@ static void watchdog_open(const char* device) /* Use known fd # - avoid needing global 'int fd' */ xmove_fd(xopen(device, O_WRONLY), 3); +#if ENABLE_FEATURE_WATCHDOG_OPEN_TWICE /* If the watchdog driver can do something other than cause a reboot * on a timeout, then it's possible this program may be starting from * a state when the watchdog hadn't been previously stopped with @@ -82,6 +94,7 @@ static void watchdog_open(const char* device) shutdown_watchdog(); xmove_fd(xopen(device, O_WRONLY), 3); +#endif } int watchdog_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; @@ -100,6 +113,9 @@ int watchdog_main(int argc UNUSED_PARAM, char **argv) char *st_arg; char *ht_arg; +#define OPT_FOREGROUND (1 << 0) +#define OPT_STIMER (1 << 1) +#define OPT_HTIMER (1 << 2) opts = getopt32(argv, "^" "Ft:T:" "\0" "=1"/*must have exactly 1 arg*/, &st_arg, &ht_arg ); @@ -132,7 +148,7 @@ int watchdog_main(int argc UNUSED_PARAM, char **argv) #if 0 ioctl_or_warn(3, WDIOC_GETTIMEOUT, &htimer_duration); printf("watchdog: SW timer is %dms, HW timer is %ds\n", - stimer_duration, htimer_duration * 1000); + stimer_duration, htimer_duration); #endif write_pidfile_std_path_and_ext("watchdog"); -- cgit v1.2.3-55-g6feb From f0c0c56e9b67413ef397876e563c14b02a5deb0f Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Tue, 13 Apr 2021 16:42:17 +0200 Subject: hush: beautify ^D handling to match ash / bash function old new delta fgetc_interactive 227 244 +17 Signed-off-by: Denys Vlasenko --- shell/hush.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/shell/hush.c b/shell/hush.c index 7cc678f3c..144ad3edd 100644 --- a/shell/hush.c +++ b/shell/hush.c @@ -2670,6 +2670,8 @@ static int get_user_input(struct in_str *i) } if (r < 0) { /* EOF/error detected */ + /* ^D on interactive input goes to next line before exiting: */ + write(STDOUT_FILENO, "\n", 1); i->p = NULL; i->peek_buf[0] = r = EOF; return r; -- cgit v1.2.3-55-g6feb From 27c1bc8dfb82f1ccab6bd9b4ce4f54e1fbf7bc3d Mon Sep 17 00:00:00 2001 From: Ron Yorston Date: Sat, 3 Apr 2021 08:57:49 +0100 Subject: build system: avoid build failure during bisection Commit 4bdc914ff (build system: fix compiler warnings) added a test on the return value of fgets() in split-include.c. During bisection it's possible to go back to a state where a configuration value didn't exist. This results in an empty include file corresponding to the missing feature. If a subsequent bisection returns to a state where the feature exists split-include treats the empty file as an error and the build fails. Add a call to ferror() to distinguish between fgets() failing due to an error and due to there being no data to read. Signed-off-by: Ron Yorston Signed-off-by: Denys Vlasenko --- scripts/basic/split-include.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/basic/split-include.c b/scripts/basic/split-include.c index 791d142a8..a38ac3427 100644 --- a/scripts/basic/split-include.c +++ b/scripts/basic/split-include.c @@ -131,7 +131,7 @@ int main(int argc, const char * argv []) is_same = 0; if ((fp_target = fopen(ptarget, "r")) != NULL) { - if (!fgets(old_line, buffer_size, fp_target)) + if (!fgets(old_line, buffer_size, fp_target) && ferror(fp_target)) ERROR_EXIT(ptarget); if (fclose(fp_target) != 0) ERROR_EXIT(ptarget); -- cgit v1.2.3-55-g6feb From 7b5cbfd6d624e19ac296089b3d675b20bda429a4 Mon Sep 17 00:00:00 2001 From: Alison Winters Date: Sun, 4 Apr 2021 08:30:16 -0700 Subject: vi: allow writing to another file if this one is readonly Version 2. Same change but rebased after Ron's improvements. Fixes bug where if you open a read only file, you can't save it as a different filename. function old new delta colon 3160 3162 +2 Signed-off-by: Alison Winters Signed-off-by: Denys Vlasenko --- editors/vi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/editors/vi.c b/editors/vi.c index fb46dc381..31b5d3e8a 100644 --- a/editors/vi.c +++ b/editors/vi.c @@ -2938,7 +2938,7 @@ static void colon(char *buf) fn = args; } # if ENABLE_FEATURE_VI_READONLY - if (readonly_mode && !useforce) { + else if (readonly_mode && !useforce) { status_line_bold("'%s' is read only", fn); goto ret; } -- cgit v1.2.3-55-g6feb From 4eb46e1be6d88eaf077252ce93127ebf00aa8ef2 Mon Sep 17 00:00:00 2001 From: Rafał Miłecki Date: Wed, 24 Mar 2021 16:01:42 +0100 Subject: dd: support iflag=count_bytes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It allows passing amount of bytes in the count= function old new delta packed_usage 33599 33617 +18 static.iflag_words 29 41 +12 dd_main 1601 1607 +6 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 3/0 up/down: 36/0) Total: 36 bytes Signed-off-by: Rafał Miłecki Signed-off-by: Denys Vlasenko --- coreutils/dd.c | 50 +++++++++++++++++++++++++++++---------------- testsuite/dd/dd-count-bytes | 1 + 2 files changed, 33 insertions(+), 18 deletions(-) create mode 100644 testsuite/dd/dd-count-bytes diff --git a/coreutils/dd.c b/coreutils/dd.c index 24d7f0b84..a243f718b 100644 --- a/coreutils/dd.c +++ b/coreutils/dd.c @@ -59,7 +59,7 @@ //usage: "[if=FILE] [of=FILE] [" IF_FEATURE_DD_IBS_OBS("ibs=N obs=N/") "bs=N] [count=N] [skip=N] [seek=N]\n" //usage: IF_FEATURE_DD_IBS_OBS( //usage: " [conv=notrunc|noerror|sync|fsync]\n" -//usage: " [iflag=skip_bytes|fullblock|direct] [oflag=seek_bytes|append|direct]" +//usage: " [iflag=skip_bytes|count_bytes|fullblock|direct] [oflag=seek_bytes|append|direct]" //usage: ) //usage:#define dd_full_usage "\n\n" //usage: "Copy a file with converting and formatting\n" @@ -82,6 +82,7 @@ //usage: "\n conv=fsync Physically write data out before finishing" //usage: "\n conv=swab Swap every pair of bytes" //usage: "\n iflag=skip_bytes skip=N is in bytes" +//usage: "\n iflag=count_bytes count=N is in bytes" //usage: "\n oflag=seek_bytes seek=N is in bytes" //usage: "\n iflag=direct O_DIRECT input" //usage: "\n oflag=direct O_DIRECT output" @@ -136,21 +137,22 @@ enum { FLAG_SWAB = (1 << 4) * ENABLE_FEATURE_DD_IBS_OBS, /* end of conv flags */ /* start of input flags */ - FLAG_IFLAG_SHIFT = 5, - FLAG_SKIP_BYTES = (1 << 5) * ENABLE_FEATURE_DD_IBS_OBS, - FLAG_FULLBLOCK = (1 << 6) * ENABLE_FEATURE_DD_IBS_OBS, - FLAG_IDIRECT = (1 << 7) * ENABLE_FEATURE_DD_IBS_OBS, + FLAG_IFLAG_SHIFT = 5, + FLAG_SKIP_BYTES = (1 << 5) * ENABLE_FEATURE_DD_IBS_OBS, + FLAG_COUNT_BYTES = (1 << 6) * ENABLE_FEATURE_DD_IBS_OBS, + FLAG_FULLBLOCK = (1 << 7) * ENABLE_FEATURE_DD_IBS_OBS, + FLAG_IDIRECT = (1 << 8) * ENABLE_FEATURE_DD_IBS_OBS, /* end of input flags */ /* start of output flags */ - FLAG_OFLAG_SHIFT = 8, - FLAG_SEEK_BYTES = (1 << 8) * ENABLE_FEATURE_DD_IBS_OBS, - FLAG_APPEND = (1 << 9) * ENABLE_FEATURE_DD_IBS_OBS, - FLAG_ODIRECT = (1 << 10) * ENABLE_FEATURE_DD_IBS_OBS, + FLAG_OFLAG_SHIFT = 9, + FLAG_SEEK_BYTES = (1 << 9) * ENABLE_FEATURE_DD_IBS_OBS, + FLAG_APPEND = (1 << 10) * ENABLE_FEATURE_DD_IBS_OBS, + FLAG_ODIRECT = (1 << 11) * ENABLE_FEATURE_DD_IBS_OBS, /* end of output flags */ - FLAG_TWOBUFS = (1 << 11) * ENABLE_FEATURE_DD_IBS_OBS, - FLAG_COUNT = 1 << 12, - FLAG_STATUS_NONE = 1 << 13, - FLAG_STATUS_NOXFER = 1 << 14, + FLAG_TWOBUFS = (1 << 12) * ENABLE_FEATURE_DD_IBS_OBS, + FLAG_COUNT = 1 << 13, + FLAG_STATUS_NONE = 1 << 14, + FLAG_STATUS_NOXFER = 1 << 15, }; static void dd_output_status(int UNUSED_PARAM cur_signal) @@ -175,8 +177,9 @@ static void dd_output_status(int UNUSED_PARAM cur_signal) //So far we react to it (we print the stats), //status=none only suppresses final, non-USR1 generated status message. # endif - fprintf(stderr, "%llu bytes (%sB) copied, ", - G.total_bytes, + fprintf(stderr, /*G.total_bytes < 1024 + ? "%llu bytes copied, " : */ "%llu bytes (%sB) copied, " + , G.total_bytes, /* show fractional digit, use suffixes */ make_human_readable_str(G.total_bytes, 1, 0) ); @@ -317,7 +320,7 @@ int dd_main(int argc UNUSED_PARAM, char **argv) static const char conv_words[] ALIGN1 = "notrunc\0""sync\0""noerror\0""fsync\0""swab\0"; static const char iflag_words[] ALIGN1 = - "skip_bytes\0""fullblock\0""direct\0"; + "skip_bytes\0""count_bytes\0""fullblock\0""direct\0"; static const char oflag_words[] ALIGN1 = "seek_bytes\0append\0""direct\0"; #endif @@ -359,6 +362,7 @@ int dd_main(int argc UNUSED_PARAM, char **argv) /* Partially implemented: */ //swab swap every pair of input bytes: will abort on non-even reads OP_iflag_skip_bytes, + OP_iflag_count_bytes, OP_iflag_fullblock, OP_iflag_direct, OP_oflag_seek_bytes, @@ -551,8 +555,17 @@ int dd_main(int argc UNUSED_PARAM, char **argv) goto die_outfile; } - while (!(G.flags & FLAG_COUNT) || (G.in_full + G.in_part != count)) { - ssize_t n = dd_read(ibuf, ibs); + while (1) { + ssize_t n = ibs; + + if (G.flags & FLAG_COUNT) { + if (count == 0) + break; + if ((G.flags & FLAG_COUNT_BYTES) && count < ibs) + n = count; + } + + n = dd_read(ibuf, n); if (n == 0) break; if (n < 0) { @@ -587,6 +600,7 @@ int dd_main(int argc UNUSED_PARAM, char **argv) p16++; } } + count -= (G.flags & FLAG_COUNT_BYTES) ? n : 1; if ((size_t)n == ibs) G.in_full++; else { diff --git a/testsuite/dd/dd-count-bytes b/testsuite/dd/dd-count-bytes new file mode 100644 index 000000000..0730cba5e --- /dev/null +++ b/testsuite/dd/dd-count-bytes @@ -0,0 +1 @@ +test "$(echo I WANT | busybox dd count=3 iflag=count_bytes 2>/dev/null)" = "I W" -- cgit v1.2.3-55-g6feb From fe9507f8c39a23e1d0af49eb2ce9466a011aa156 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Wed, 14 Apr 2021 01:01:20 +0200 Subject: touch: fix -am function old new delta touch_main 414 424 +10 Signed-off-by: Denys Vlasenko --- coreutils/touch.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/coreutils/touch.c b/coreutils/touch.c index 6c0201374..4c7362acd 100644 --- a/coreutils/touch.c +++ b/coreutils/touch.c @@ -153,11 +153,14 @@ int touch_main(int argc UNUSED_PARAM, char **argv) timebuf[1].tv_sec = timebuf[0].tv_sec = t; timebuf[1].tv_nsec = timebuf[0].tv_nsec = 0; } - if (opts & OPT_a) { - timebuf[1].tv_nsec = UTIME_OMIT; - } - if (opts & OPT_m) { - timebuf[0].tv_nsec = UTIME_OMIT; + /* If both -a and -m specified, both times should be set. + * IOW: set OMIT only if one, not both, of them is given! + */ + if ((opts & (OPT_a|OPT_m)) != (OPT_a|OPT_m)) { + if (opts & OPT_a) + timebuf[1].tv_nsec = UTIME_OMIT; + if (opts & OPT_m) + timebuf[0].tv_nsec = UTIME_OMIT; } argv += optind; -- cgit v1.2.3-55-g6feb From d156bcf71eb62f4e240e45cb2b84bb4eeb6a1e64 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Wed, 14 Apr 2021 14:46:35 +0200 Subject: touch: code shrink function old new delta touch_main 424 421 -3 Signed-off-by: Denys Vlasenko --- coreutils/touch.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/coreutils/touch.c b/coreutils/touch.c index 4c7362acd..a7907e2c8 100644 --- a/coreutils/touch.c +++ b/coreutils/touch.c @@ -156,12 +156,10 @@ int touch_main(int argc UNUSED_PARAM, char **argv) /* If both -a and -m specified, both times should be set. * IOW: set OMIT only if one, not both, of them is given! */ - if ((opts & (OPT_a|OPT_m)) != (OPT_a|OPT_m)) { - if (opts & OPT_a) - timebuf[1].tv_nsec = UTIME_OMIT; - if (opts & OPT_m) - timebuf[0].tv_nsec = UTIME_OMIT; - } + if ((opts & (OPT_a|OPT_m)) == OPT_a) + timebuf[1].tv_nsec = UTIME_OMIT; + if ((opts & (OPT_a|OPT_m)) == OPT_m) + timebuf[0].tv_nsec = UTIME_OMIT; argv += optind; do { -- cgit v1.2.3-55-g6feb From 93f1255af28c5fca0e704c6096e25fb3a5c09a67 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Wed, 14 Apr 2021 14:52:09 +0200 Subject: touch: shorten --help text Signed-off-by: Denys Vlasenko --- coreutils/touch.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/coreutils/touch.c b/coreutils/touch.c index a7907e2c8..d8a930f7d 100644 --- a/coreutils/touch.c +++ b/coreutils/touch.c @@ -35,7 +35,7 @@ //usage: IF_FEATURE_TOUCH_SUSV3(" [-d DATE] [-t DATE] [-r FILE]") //usage: " FILE..." //usage:#define touch_full_usage "\n\n" -//usage: "Update the last-modified date on the given FILE[s]\n" +//usage: "Update mtime of FILE\n" //usage: "\n -c Don't create files" //usage: "\n -h Don't follow links" //usage: IF_FEATURE_TOUCH_SUSV3( -- cgit v1.2.3-55-g6feb From ba9f9c2d2c57f6041c6c01ba7c0e8379a5f5d440 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Wed, 14 Apr 2021 15:15:45 +0200 Subject: *: --help text tweaks Signed-off-by: Denys Vlasenko --- coreutils/chgrp.c | 2 +- coreutils/chown.c | 2 +- coreutils/cp.c | 2 +- coreutils/cut.c | 8 ++++---- coreutils/du.c | 2 +- coreutils/fold.c | 2 +- coreutils/head.c | 2 +- coreutils/mv.c | 2 +- coreutils/realpath.c | 2 +- coreutils/tail.c | 2 +- coreutils/touch.c | 2 +- coreutils/truncate.c | 4 ++-- coreutils/wc.c | 2 +- miscutils/bc.c | 4 ++-- miscutils/watchdog.c | 2 +- selinux/chcon.c | 2 +- 16 files changed, 21 insertions(+), 21 deletions(-) diff --git a/coreutils/chgrp.c b/coreutils/chgrp.c index 4da43c45e..0c2060981 100644 --- a/coreutils/chgrp.c +++ b/coreutils/chgrp.c @@ -23,7 +23,7 @@ //usage:#define chgrp_trivial_usage //usage: "[-Rh"IF_DESKTOP("LHPcvf")"]... GROUP FILE..." //usage:#define chgrp_full_usage "\n\n" -//usage: "Change the group membership of each FILE to GROUP\n" +//usage: "Change the group membership of FILEs to GROUP\n" //usage: "\n -R Recurse" //usage: "\n -h Affect symlinks instead of symlink targets" //usage: IF_DESKTOP( diff --git a/coreutils/chown.c b/coreutils/chown.c index ffccc6cce..170507147 100644 --- a/coreutils/chown.c +++ b/coreutils/chown.c @@ -28,7 +28,7 @@ //usage:#define chown_trivial_usage //usage: "[-Rh"IF_DESKTOP("LHPcvf")"]... USER[:[GRP]] FILE..." //usage:#define chown_full_usage "\n\n" -//usage: "Change the owner and/or group of each FILE to USER and/or GRP\n" +//usage: "Change the owner and/or group of FILEs to USER and/or GRP\n" //usage: "\n -R Recurse" //usage: "\n -h Affect symlinks instead of symlink targets" //usage: IF_DESKTOP( diff --git a/coreutils/cp.c b/coreutils/cp.c index 9b9b8f7bf..f92ba6886 100644 --- a/coreutils/cp.c +++ b/coreutils/cp.c @@ -40,7 +40,7 @@ //usage:#define cp_trivial_usage //usage: "[-arPLHpfilsTu] SOURCE... DEST" //usage:#define cp_full_usage "\n\n" -//usage: "Copy SOURCE(s) to DEST\n" +//usage: "Copy SOURCEs to DEST\n" //usage: "\n -a Same as -dpR" //usage: IF_SELINUX( //usage: "\n -c Preserve security context" diff --git a/coreutils/cut.c b/coreutils/cut.c index 16418ff33..5897d82b6 100644 --- a/coreutils/cut.c +++ b/coreutils/cut.c @@ -22,12 +22,12 @@ //usage:#define cut_trivial_usage //usage: "[OPTIONS] [FILE]..." //usage:#define cut_full_usage "\n\n" -//usage: "Print selected fields from each input FILE to stdout\n" +//usage: "Print selected fields from FILEs to stdout\n" //usage: "\n -b LIST Output only bytes from LIST" //usage: "\n -c LIST Output only characters from LIST" -//usage: "\n -d CHAR Use CHAR instead of tab as the field delimiter" -//usage: "\n -s Output only the lines containing delimiter" -//usage: "\n -f N Print only these fields" +//usage: "\n -d CHAR Use CHAR instead of tab as field delimiter" +//usage: "\n -s Output only lines containing delimiter" +//usage: "\n -f LIST Print only these fields" //usage: "\n -n Ignored" //usage: //usage:#define cut_example_usage diff --git a/coreutils/du.c b/coreutils/du.c index d14d9e4ea..c8aedb6ef 100644 --- a/coreutils/du.c +++ b/coreutils/du.c @@ -40,7 +40,7 @@ //usage:#define du_trivial_usage //usage: "[-aHLdclsx" IF_FEATURE_HUMAN_READABLE("hm") "k] [FILE]..." //usage:#define du_full_usage "\n\n" -//usage: "Summarize disk space used for each FILE and/or directory\n" +//usage: "Summarize disk space used for FILEs (or directories)\n" //usage: "\n -a Show file sizes too" //usage: "\n -L Follow all symlinks" //usage: "\n -H Follow symlinks on command line" diff --git a/coreutils/fold.c b/coreutils/fold.c index 1e26dde0c..98c3b1491 100644 --- a/coreutils/fold.c +++ b/coreutils/fold.c @@ -23,7 +23,7 @@ //usage:#define fold_trivial_usage //usage: "[-bs] [-w WIDTH] [FILE]..." //usage:#define fold_full_usage "\n\n" -//usage: "Wrap input lines in each FILE (or stdin), writing to stdout\n" +//usage: "Wrap input lines in FILEs (or stdin), writing to stdout\n" //usage: "\n -b Count bytes rather than columns" //usage: "\n -s Break at spaces" //usage: "\n -w Use WIDTH columns instead of 80" diff --git a/coreutils/head.c b/coreutils/head.c index b6efabbe0..efb023c6f 100644 --- a/coreutils/head.c +++ b/coreutils/head.c @@ -29,7 +29,7 @@ //usage:#define head_trivial_usage //usage: "[OPTIONS] [FILE]..." //usage:#define head_full_usage "\n\n" -//usage: "Print first 10 lines of each FILE (or stdin) to stdout.\n" +//usage: "Print first 10 lines of FILEs (or stdin) to stdout.\n" //usage: "With more than one FILE, precede each with a filename header.\n" //usage: "\n -n N[kbm] Print first N lines" //usage: IF_FEATURE_FANCY_HEAD( diff --git a/coreutils/mv.c b/coreutils/mv.c index b9f8f6982..f5ed9fcfc 100644 --- a/coreutils/mv.c +++ b/coreutils/mv.c @@ -26,7 +26,7 @@ //usage: "[-fin] SOURCE DEST\n" //usage: "or: mv [-fin] SOURCE... DIRECTORY" //usage:#define mv_full_usage "\n\n" -//usage: "Rename SOURCE to DEST, or move SOURCE(s) to DIRECTORY\n" +//usage: "Rename SOURCE to DEST, or move SOURCEs to DIRECTORY\n" //usage: "\n -f Don't prompt before overwriting" //usage: "\n -i Interactive, prompt before overwrite" //usage: "\n -n Don't overwrite an existing file" diff --git a/coreutils/realpath.c b/coreutils/realpath.c index f5f868744..aeeef601c 100644 --- a/coreutils/realpath.c +++ b/coreutils/realpath.c @@ -23,7 +23,7 @@ //usage:#define realpath_trivial_usage //usage: "FILE..." //usage:#define realpath_full_usage "\n\n" -//usage: "Return the absolute pathnames of given FILE" +//usage: "Print absolute pathnames of FILEs" #include "libbb.h" diff --git a/coreutils/tail.c b/coreutils/tail.c index 1f458f9ed..08fde6cdd 100644 --- a/coreutils/tail.c +++ b/coreutils/tail.c @@ -48,7 +48,7 @@ //usage:#define tail_trivial_usage //usage: "[OPTIONS] [FILE]..." //usage:#define tail_full_usage "\n\n" -//usage: "Print last 10 lines of each FILE (or stdin) to stdout.\n" +//usage: "Print last 10 lines of FILEs (or stdin) to stdout.\n" //usage: "With more than one FILE, precede each with a filename header.\n" //usage: "\n -f Print data as file grows" //usage: "\n -c [+]N[kbm] Print last N bytes" diff --git a/coreutils/touch.c b/coreutils/touch.c index d8a930f7d..2b225dd16 100644 --- a/coreutils/touch.c +++ b/coreutils/touch.c @@ -35,7 +35,7 @@ //usage: IF_FEATURE_TOUCH_SUSV3(" [-d DATE] [-t DATE] [-r FILE]") //usage: " FILE..." //usage:#define touch_full_usage "\n\n" -//usage: "Update mtime of FILE\n" +//usage: "Update mtime of FILEs\n" //usage: "\n -c Don't create files" //usage: "\n -h Don't follow links" //usage: IF_FEATURE_TOUCH_SUSV3( diff --git a/coreutils/truncate.c b/coreutils/truncate.c index 233d0f2d1..e26c3e3e1 100644 --- a/coreutils/truncate.c +++ b/coreutils/truncate.c @@ -19,9 +19,9 @@ //usage:#define truncate_trivial_usage //usage: "[-c] -s SIZE FILE..." //usage:#define truncate_full_usage "\n\n" -//usage: "Truncate FILEs to the given size\n" +//usage: "Truncate FILEs to SIZE\n" //usage: "\n -c Do not create files" -//usage: "\n -s SIZE Truncate to SIZE" +//usage: "\n -s SIZE" //usage: //usage:#define truncate_example_usage //usage: "$ truncate -s 1G foo" diff --git a/coreutils/wc.c b/coreutils/wc.c index 99eb9dc87..d5238d3fc 100644 --- a/coreutils/wc.c +++ b/coreutils/wc.c @@ -80,7 +80,7 @@ //usage: "[-c"IF_UNICODE_SUPPORT("m")"lwL] [FILE]..." //usage: //usage:#define wc_full_usage "\n\n" -//usage: "Count lines, words, and bytes for each FILE (or stdin)\n" +//usage: "Count lines, words, and bytes for FILEs (or stdin)\n" //usage: "\n -c Count bytes" //usage: IF_UNICODE_SUPPORT( //usage: "\n -m Count characters" diff --git a/miscutils/bc.c b/miscutils/bc.c index 553d0f472..dd9f4f8f1 100644 --- a/miscutils/bc.c +++ b/miscutils/bc.c @@ -108,14 +108,14 @@ //See www.gnu.org/software/bc/manual/bc.html //usage:#define bc_trivial_usage -//usage: "[-sqlw] FILE..." +//usage: "[-sqlw] [FILE...]" //usage: //usage:#define bc_full_usage "\n" //usage: "\nArbitrary precision calculator" //usage: "\n" ///////: "\n -i Interactive" - has no effect for now //usage: "\n -q Quiet" -//usage: "\n -l Load standard math library" +//usage: "\n -l Load standard library" //usage: "\n -s Be POSIX compatible" //usage: "\n -w Warn if extensions are used" ///////: "\n -v Version" diff --git a/miscutils/watchdog.c b/miscutils/watchdog.c index 44649cae6..d8e9c78f5 100644 --- a/miscutils/watchdog.c +++ b/miscutils/watchdog.c @@ -27,7 +27,7 @@ //config: When enabled, the watchdog device is opened and then immediately //config: magic-closed, before being opened a second time. This may be necessary //config: for some watchdog devices, but can cause spurious warnings in the -//config: kernel log if the nowayout feature is enabled. Also, if this workaround +//config: kernel log if the nowayout feature is enabled. If this workaround //config: is really needed for you machine to work properly, consider whether //config: it should be fixed in the kernel driver instead. Even when disabled, //config: the behaviour is easily emulated with a "printf 'V' > /dev/watchdog" diff --git a/selinux/chcon.c b/selinux/chcon.c index 2e4f94c0f..e1778a36a 100644 --- a/selinux/chcon.c +++ b/selinux/chcon.c @@ -26,7 +26,7 @@ //usage: ) //usage: //usage:#define chcon_full_usage "\n\n" -//usage: "Change the security context of each FILE to CONTEXT\n" +//usage: "Change the security context of FILEs to CONTEXT\n" //usage: "\n -v Verbose" //usage: "\n -c Report changes made" //usage: "\n -h Affect symlinks instead of their targets" -- cgit v1.2.3-55-g6feb From fe2d8065e3e3c251c054a30e9823977e20b5ab7c Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Wed, 14 Apr 2021 17:52:18 +0200 Subject: fix gcc-11.0 warnings Signed-off-by: Denys Vlasenko --- include/libbb.h | 2 +- libbb/lineedit.c | 2 +- libbb/xfuncs_printf.c | 2 +- networking/udhcp/signalpipe.c | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/include/libbb.h b/include/libbb.h index ece03e7d8..37732e14e 100644 --- a/include/libbb.h +++ b/include/libbb.h @@ -623,7 +623,7 @@ uoff_t FAST_FUNC get_volume_size_in_bytes(int fd, unsigned override_units, int extend); -void xpipe(int filedes[2]) FAST_FUNC; +void xpipe(int *filedes) FAST_FUNC; /* In this form code with pipes is much more readable */ struct fd_pair { int rd; int wr; }; #define piped_pair(pair) pipe(&((pair).rd)) diff --git a/libbb/lineedit.c b/libbb/lineedit.c index 2cae4711a..68d19e127 100644 --- a/libbb/lineedit.c +++ b/libbb/lineedit.c @@ -1314,7 +1314,7 @@ static NOINLINE void input_tab(smallint *lastWasTab) strcpy(&command[cursor_mb], chosen_match + match_pfx_len); len = load_string(command); /* add match and tail */ - sprintf(&command[cursor_mb], "%s%s", chosen_match + match_pfx_len, match_buf); + stpcpy(stpcpy(&command[cursor_mb], chosen_match + match_pfx_len), match_buf); command_len = load_string(command); /* write out the matched command */ /* paranoia: load_string can return 0 on conv error, diff --git a/libbb/xfuncs_printf.c b/libbb/xfuncs_printf.c index f0399ca45..d29acebcd 100644 --- a/libbb/xfuncs_printf.c +++ b/libbb/xfuncs_printf.c @@ -224,7 +224,7 @@ int FAST_FUNC rename_or_warn(const char *oldpath, const char *newpath) return n; } -void FAST_FUNC xpipe(int filedes[2]) +void FAST_FUNC xpipe(int *filedes) { if (pipe(filedes)) bb_simple_perror_msg_and_die("can't create pipe"); diff --git a/networking/udhcp/signalpipe.c b/networking/udhcp/signalpipe.c index 7df671245..774c4beee 100644 --- a/networking/udhcp/signalpipe.c +++ b/networking/udhcp/signalpipe.c @@ -65,7 +65,7 @@ void FAST_FUNC udhcp_sp_setup(void) /* Quick little function to setup the pfds. * Limited in that you can only pass one extra fd. */ -void FAST_FUNC udhcp_sp_fd_set(struct pollfd pfds[2], int extra_fd) +void FAST_FUNC udhcp_sp_fd_set(struct pollfd *pfds, int extra_fd) { pfds[0].fd = READ_FD; pfds[0].events = POLLIN; -- cgit v1.2.3-55-g6feb From 7c813fbabfa672e74a387ab457b9fa39ca1a57aa Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Wed, 14 Apr 2021 18:55:30 +0200 Subject: echo: fix !ENABLE_FEATURE_FANCY_ECHO build Signed-off-by: Denys Vlasenko --- coreutils/echo.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/coreutils/echo.c b/coreutils/echo.c index 61ba060ec..aab177cee 100644 --- a/coreutils/echo.c +++ b/coreutils/echo.c @@ -87,6 +87,7 @@ int echo_main(int argc UNUSED_PARAM, char **argv) char *out; char *buffer; unsigned buflen; + int err; #if !ENABLE_FEATURE_FANCY_ECHO enum { eflag = 0, /* 0 -- disable escape sequences */ @@ -97,7 +98,6 @@ int echo_main(int argc UNUSED_PARAM, char **argv) #else char nflag = 1; char eflag = 0; - int err; while ((arg = *++argv) != NULL) { char n, e; -- cgit v1.2.3-55-g6feb From eb1b2902b8b7b7effdba711645288c64884fd3e7 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Wed, 14 Apr 2021 19:01:53 +0200 Subject: Makefile.flags: add a test for -lrt availability Signed-off-by: Denys Vlasenko --- Makefile.flags | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/Makefile.flags b/Makefile.flags index 3b02bfaac..667481983 100644 --- a/Makefile.flags +++ b/Makefile.flags @@ -145,18 +145,21 @@ CFLAGS += --sysroot=$(CONFIG_SYSROOT) export SYSROOT=$(CONFIG_SYSROOT) endif +# libm may be needed for dc, awk, ntpd +LDLIBS += m # Android has no separate crypt library # gcc-4.2.1 fails if we try to feed C source on stdin: # echo 'int main(void){return 0;}' | $(CC) $(CFLAGS) -lcrypt -o /dev/null -xc - # fall back to using a temp file: -CRYPT_AVAILABLE := $(shell echo 'int main(void){return 0;}' >crypttest.c; $(CC) $(CFLAGS) -lcrypt -o /dev/null crypttest.c >/dev/null 2>&1 && echo "y"; rm crypttest.c) +CRYPT_AVAILABLE := $(shell echo 'int main(void){return 0;}' >bb_libtest.c; $(CC) $(CFLAGS) -lcrypt -o /dev/null bb_libtest.c >/dev/null 2>&1 && echo "y"; rm bb_libtest.c) +RT_AVAILABLE := $(shell echo 'int main(void){return 0;}' >bb_libtest.c; $(CC) $(CFLAGS) -lrt -o /dev/null bb_libtest.c >/dev/null 2>&1 && echo "y"; rm bb_libtest.c) ifeq ($(CRYPT_AVAILABLE),y) -LDLIBS += m rt crypt -else -LDLIBS += m rt +LDLIBS += crypt endif -# libm may be needed for dc, awk, ntpd # librt may be needed for clock_gettime() +ifeq ($(RT_AVAILABLE),y) +LDLIBS += rt +endif # libpam may use libpthread, libdl and/or libaudit. # On some platforms that requires an explicit -lpthread, -ldl, -laudit. -- cgit v1.2.3-55-g6feb From 1a45b2ccea94b0fc123798f276a0801413597880 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Wed, 14 Apr 2021 19:12:43 +0200 Subject: fix "warning array subscript has type 'char'" Signed-off-by: Denys Vlasenko --- applets/applet_tables.c | 2 +- scripts/basic/docproc.c | 18 +++++++++--------- scripts/basic/fixdep.c | 12 ++++++------ scripts/basic/split-include.c | 2 +- scripts/kconfig/conf.c | 6 +++--- scripts/kconfig/confdata.c | 2 +- scripts/kconfig/mconf.c | 2 +- 7 files changed, 22 insertions(+), 22 deletions(-) diff --git a/applets/applet_tables.c b/applets/applet_tables.c index 7ba929b12..66ef7e4ac 100644 --- a/applets/applet_tables.c +++ b/applets/applet_tables.c @@ -56,7 +56,7 @@ static int cmp_name(const void *a, const void *b) static int str_isalnum_(const char *s) { while (*s) { - if (!isalnum(*s) && *s != '_') + if (!isalnum((unsigned char)*s) && *s != '_') return 0; s++; } diff --git a/scripts/basic/docproc.c b/scripts/basic/docproc.c index 720098a23..4464e1874 100644 --- a/scripts/basic/docproc.c +++ b/scripts/basic/docproc.c @@ -182,10 +182,10 @@ void find_export_symbols(char * filename) perror(real_filename); } while (fgets(line, MAXLINESZ, fp)) { - char *p; - char *e; - if (((p = strstr(line, "EXPORT_SYMBOL_GPL")) != 0) || - ((p = strstr(line, "EXPORT_SYMBOL")) != 0)) { + unsigned char *p; + unsigned char *e; + if (((p = (unsigned char *)strstr(line, "EXPORT_SYMBOL_GPL")) != 0) || + ((p = (unsigned char *)strstr(line, "EXPORT_SYMBOL")) != 0)) { /* Skip EXPORT_SYMBOL{_GPL} */ while (isalnum(*p) || *p == '_') p++; @@ -202,7 +202,7 @@ void find_export_symbols(char * filename) while (isalnum(*e) || *e == '_') e++; *e = '\0'; - add_new_symbol(sym, p); + add_new_symbol(sym, (char*)p); } } fclose(fp); @@ -266,7 +266,7 @@ void singfunc(char * filename, char * line) /* Split line up in individual parameters preceded by FUNCTION */ for (i=0; line[i]; i++) { - if (isspace(line[i])) { + if (isspace((unsigned char) line[i])) { line[i] = '\0'; startofsym = 1; continue; @@ -293,10 +293,10 @@ void singfunc(char * filename, char * line) void parse_file(FILE *infile) { char line[MAXLINESZ]; - char * s; + unsigned char * s; while (fgets(line, MAXLINESZ, infile)) { if (line[0] == '!') { - s = line + 2; + s = (unsigned char *)line + 2; switch (line[1]) { case 'E': while (*s && !isspace(*s)) s++; @@ -320,7 +320,7 @@ void parse_file(FILE *infile) /* function names */ while (isspace(*s)) s++; - singlefunctions(line +2, s); + singlefunctions(line +2, (char*)s); break; default: defaultline(line); diff --git a/scripts/basic/fixdep.c b/scripts/basic/fixdep.c index 19f82df09..426b4888b 100644 --- a/scripts/basic/fixdep.c +++ b/scripts/basic/fixdep.c @@ -226,10 +226,10 @@ void use_config(char *m, int slen) void parse_config_file(char *map, size_t len) { /* modified for bbox */ - char *end_3 = map + len - 3; /* 3 == length of "IF_" */ - char *end_7 = map + len - 7; - char *p = map; - char *q; + unsigned char *end_3 = (unsigned char *)map + len - 3; /* 3 == length of "IF_" */ + unsigned char *end_7 = (unsigned char *)map + len - 7; + unsigned char *p = (unsigned char *)map; + unsigned char *q; int off; for (; p <= end_3; p++) { @@ -263,7 +263,7 @@ void parse_config_file(char *map, size_t len) break; } if (q != p) { - use_config(p, q-p); + use_config((char*)p, q - p); } } } @@ -335,7 +335,7 @@ void parse_dep_file(void *map, size_t len) p = m; while (p < end && *p != ' ') p++; if (p == end) { - do p--; while (!isalnum(*p)); + do p--; while (!isalnum((unsigned char)*p)); p++; } memcpy(s, m, p-m); s[p-m] = 0; diff --git a/scripts/basic/split-include.c b/scripts/basic/split-include.c index a38ac3427..6ef29195e 100644 --- a/scripts/basic/split-include.c +++ b/scripts/basic/split-include.c @@ -116,7 +116,7 @@ int main(int argc, const char * argv []) /* We found #define CONFIG_foo or #undef CONFIG_foo. * Make the output file name. */ str_config += sizeof(" CONFIG_") - 1; - for (itarget = 0; !isspace(str_config[itarget]); itarget++) + for (itarget = 0; !isspace((unsigned char)str_config[itarget]); itarget++) { int c = (unsigned char) str_config[itarget]; if (isupper(c)) c = tolower(c); diff --git a/scripts/kconfig/conf.c b/scripts/kconfig/conf.c index 866a7c544..39ec1cdb6 100644 --- a/scripts/kconfig/conf.c +++ b/scripts/kconfig/conf.c @@ -44,7 +44,7 @@ static void strip(char *str) char *p = str; int l; - while ((isspace(*p))) + while ((isspace((unsigned char)*p))) p++; l = strlen(p); if (p != str) @@ -52,7 +52,7 @@ static void strip(char *str) if (!l) return; p = str + l - 1; - while ((isspace(*p))) + while ((isspace((unsigned char)*p))) *p-- = 0; } @@ -401,7 +401,7 @@ static int conf_choice(struct menu *menu) } if (!line[0]) cnt = def; - else if (isdigit(line[0])) + else if (isdigit((unsigned char)line[0])) cnt = atoi(line); else continue; diff --git a/scripts/kconfig/confdata.c b/scripts/kconfig/confdata.c index b05b96e45..9976011a9 100644 --- a/scripts/kconfig/confdata.c +++ b/scripts/kconfig/confdata.c @@ -54,7 +54,7 @@ static char *conf_expand_value(const char *in) strncat(res_value, in, src - in); src++; dst = name; - while (isalnum(*src) || *src == '_') + while (isalnum((unsigned char)*src) || *src == '_') *dst++ = *src++; *dst = 0; sym = sym_lookup(name, 0); diff --git a/scripts/kconfig/mconf.c b/scripts/kconfig/mconf.c index c3a837a14..aaf82820e 100644 --- a/scripts/kconfig/mconf.c +++ b/scripts/kconfig/mconf.c @@ -771,7 +771,7 @@ static void conf(struct menu *menu) if (!type) continue; - for (i = 0; input_buf[i] && !isspace(input_buf[i]); i++) + for (i = 0; input_buf[i] && !isspace((unsigned char)input_buf[i]); i++) ; if (i >= sizeof(active_entry)) i = sizeof(active_entry) - 1; -- cgit v1.2.3-55-g6feb From afc766fc12d54670aaed9bbb228efc7a5be561db Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Wed, 14 Apr 2021 21:15:25 +0200 Subject: unzip: fix for .zip archives with >4GB file function old new delta unzip_main 2644 2665 +21 input_tab 926 927 +1 bb_banner 46 47 +1 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 3/0 up/down: 23/0) Total: 23 bytes Signed-off-by: Denys Vlasenko --- archival/unzip.c | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/archival/unzip.c b/archival/unzip.c index d94bbabcf..12db4e579 100644 --- a/archival/unzip.c +++ b/archival/unzip.c @@ -82,11 +82,13 @@ enum { ZIP_FILEHEADER_MAGIC = 0x504b0304, ZIP_CDF_MAGIC = 0x504b0102, /* CDF item */ ZIP_CDE_MAGIC = 0x504b0506, /* End of CDF */ + ZIP64_CDE_MAGIC = 0x504b0606, /* End of Zip64 CDF */ ZIP_DD_MAGIC = 0x504b0708, #else ZIP_FILEHEADER_MAGIC = 0x04034b50, ZIP_CDF_MAGIC = 0x02014b50, ZIP_CDE_MAGIC = 0x06054b50, + ZIP64_CDE_MAGIC = 0x06064b50, ZIP_DD_MAGIC = 0x08074b50, #endif }; @@ -260,6 +262,12 @@ static uint32_t find_cdf_offset(void) continue; /* we found CDE! */ memcpy(cde.raw, p + 1, CDE_LEN); + dbg("cde.this_disk_no:%d", cde.fmt.this_disk_no ); + dbg("cde.disk_with_cdf_no:%d", cde.fmt.disk_with_cdf_no ); + dbg("cde.cdf_entries_on_this_disk:%d", cde.fmt.cdf_entries_on_this_disk); + dbg("cde.cdf_entries_total:%d", cde.fmt.cdf_entries_total ); + dbg("cde.cdf_size:%d", cde.fmt.cdf_size ); + dbg("cde.cdf_offset:%x", cde.fmt.cdf_offset ); FIX_ENDIANNESS_CDE(cde); /* * I've seen .ZIP files with seemingly valid CDEs @@ -302,19 +310,27 @@ static uint32_t read_next_cdf(uint32_t cdf_offset, cdf_header_t *cdf) dbg("got ZIP_CDE_MAGIC"); return 0; /* EOF */ } + if (magic == ZIP64_CDE_MAGIC) { /* seen in .zip with >4GB files */ + dbg("got ZIP64_CDE_MAGIC"); + return 0; /* EOF */ + } xread(zip_fd, cdf->raw, CDF_HEADER_LEN); FIX_ENDIANNESS_CDF(*cdf); - dbg(" filename_len:%u extra_len:%u file_comment_length:%u", + dbg(" magic:%08x filename_len:%u extra_len:%u file_comment_length:%u", + magic, (unsigned)cdf->fmt.filename_len, (unsigned)cdf->fmt.extra_len, (unsigned)cdf->fmt.file_comment_length ); +//TODO: require that magic == ZIP_CDF_MAGIC? + cdf_offset += 4 + CDF_HEADER_LEN + cdf->fmt.filename_len + cdf->fmt.extra_len + cdf->fmt.file_comment_length; + dbg("Next cdf_offset 0x%x", cdf_offset); return cdf_offset; }; #endif @@ -436,7 +452,9 @@ static void unzip_extract(zip_header_t *zip, int dst_fd) } /* Validate decompression - size */ - if (zip->fmt.ucmpsize != xstate.bytes_out) { + if (zip->fmt.ucmpsize != 0xffffffff /* seen on files with >4GB uncompressed data */ + && zip->fmt.ucmpsize != xstate.bytes_out + ) { /* Don't die. Who knows, maybe len calculation * was botched somewhere. After all, crc matched! */ bb_simple_error_msg("bad length"); -- cgit v1.2.3-55-g6feb From cca4c9f4c0878b08fac6dfe014148ddcd5aa7678 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Wed, 14 Apr 2021 21:34:00 +0200 Subject: unzip: add -t function old new delta packed_usage 33584 33598 +14 .rodata 103218 103219 +1 unzip_main 2665 2656 -9 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 2/1 up/down: 15/-9) Total: 6 bytes Signed-off-by: Denys Vlasenko --- archival/unzip.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/archival/unzip.c b/archival/unzip.c index 12db4e579..66005a43e 100644 --- a/archival/unzip.c +++ b/archival/unzip.c @@ -64,6 +64,7 @@ //usage: "\n -o Overwrite" //usage: "\n -j Do not restore paths" //usage: "\n -p Print to stdout" +//usage: "\n -t Test" //usage: "\n -q Quiet" //usage: "\n -x FILE Exclude FILEs" //usage: "\n -d DIR Extract into DIR" @@ -556,7 +557,7 @@ int unzip_main(int argc, char **argv) opts = 0; /* '-' makes getopt return 1 for non-options */ - while ((i = getopt(argc, argv, "-d:lnopqxjv")) != -1) { + while ((i = getopt(argc, argv, "-d:lnotpqxjv")) != -1) { switch (i) { case 'd': /* Extract to base directory */ base_dir = optarg; @@ -574,8 +575,13 @@ int unzip_main(int argc, char **argv) overwrite = O_ALWAYS; break; - case 'p': /* Extract files to stdout and fall through to set verbosity */ + case 't': /* Extract files to /dev/null */ + xmove_fd(xopen("/dev/null", O_WRONLY), STDOUT_FILENO); + /*fallthrough*/ + + case 'p': /* Extract files to stdout */ dst_fd = STDOUT_FILENO; + /*fallthrough*/ case 'q': /* Be quiet */ quiet++; @@ -984,7 +990,6 @@ int unzip_main(int argc, char **argv) /* O_NOFOLLOW defends against symlink attacks */ dst_fd = xopen(dst_fn, O_WRONLY | O_CREAT | O_TRUNC | O_NOFOLLOW); #endif - do_extract: if (!quiet) { printf(/* zip.fmt.method == 0 ? " extracting: %s\n" @@ -992,6 +997,7 @@ int unzip_main(int argc, char **argv) printable_string(dst_fn) ); } + do_extract: #if ENABLE_FEATURE_UNZIP_CDF if (S_ISLNK(file_mode)) { if (dst_fd != STDOUT_FILENO) /* not -p? */ -- cgit v1.2.3-55-g6feb From c0943ac451051b734711b0c95731ae7c515dbb31 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Wed, 14 Apr 2021 22:14:36 +0200 Subject: platform.h: fix for Bionic >= 21 not having wait3() Signed-off-by: Denys Vlasenko --- include/platform.h | 4 ++++ miscutils/time.c | 7 +++++++ 2 files changed, 11 insertions(+) diff --git a/include/platform.h b/include/platform.h index 24efd186b..387b6f537 100644 --- a/include/platform.h +++ b/include/platform.h @@ -424,6 +424,7 @@ typedef unsigned smalluint; #define HAVE_NET_ETHERNET_H 1 #define HAVE_SYS_STATFS_H 1 #define HAVE_PRINTF_PERCENTM 1 +#define HAVE_WAIT3 1 #if defined(__UCLIBC__) # if UCLIBC_VERSION < KERNEL_VERSION(0, 9, 32) @@ -535,6 +536,9 @@ typedef unsigned smalluint; # undef HAVE_STPCPY # undef HAVE_STPNCPY # endif +# if __ANDROID_API__ >= 21 +# undef HAVE_WAIT3 +# endif # undef HAVE_MEMPCPY # undef HAVE_STRCHRNUL # undef HAVE_STRVERSCMP diff --git a/miscutils/time.c b/miscutils/time.c index 0006c59d8..c4bcbcbc9 100644 --- a/miscutils/time.c +++ b/miscutils/time.c @@ -33,6 +33,13 @@ #include "libbb.h" +#ifndef HAVE_WAIT3 +static pid_t wait3(int *status, int options, struct rusage *rusage) +{ + return wait4(-1, status, options, rusage); +} +#endif + /* Information on the resources used by a child process. */ typedef struct { int waitstatus; -- cgit v1.2.3-55-g6feb From 9b2a3895eedb3c46179b1ed923b0f1214da04c5b Mon Sep 17 00:00:00 2001 From: Ron Yorston Date: Thu, 15 Apr 2021 12:00:50 +0100 Subject: vi: correctly record deleted characters The undo queue didn't record deleted characters properly. For example, insert some text, backspace over a couple of characters then exit insert mode. At this point undo will restore two nulls instead of the deleted characters. The fix is in undo_push(): record the state of the UNDO_USE_SPOS flag and clear it before using 'u_type'. Also, update the comments to reflect the fact that UNDO_QUEUED_FLAG isn't actually used. function old new delta undo_push 443 435 -8 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 0/1 up/down: 0/-8) Total: -8 bytes Signed-off-by: Ron Yorston Signed-off-by: Denys Vlasenko --- editors/vi.c | 39 ++++++++++++++++++++++----------------- 1 file changed, 22 insertions(+), 17 deletions(-) diff --git a/editors/vi.c b/editors/vi.c index 31b5d3e8a..fef328117 100644 --- a/editors/vi.c +++ b/editors/vi.c @@ -399,26 +399,31 @@ struct globals { #define UNDO_DEL 1 #define UNDO_INS_CHAIN 2 #define UNDO_DEL_CHAIN 3 -// UNDO_*_QUEUED must be equal to UNDO_xxx ORed with UNDO_QUEUED_FLAG -#define UNDO_QUEUED_FLAG 4 +# if ENABLE_FEATURE_VI_UNDO_QUEUE #define UNDO_INS_QUEUED 4 #define UNDO_DEL_QUEUED 5 -#define UNDO_USE_SPOS 32 -#define UNDO_EMPTY 64 +# endif + // Pass-through flags for functions that can be undone #define NO_UNDO 0 #define ALLOW_UNDO 1 #define ALLOW_UNDO_CHAIN 2 # if ENABLE_FEATURE_VI_UNDO_QUEUE #define ALLOW_UNDO_QUEUED 3 - char undo_queue_state; +# else +// If undo queuing disabled, don't invoke the missing queue logic +#define ALLOW_UNDO_QUEUED ALLOW_UNDO +# endif + +# if ENABLE_FEATURE_VI_UNDO_QUEUE +#define UNDO_USE_SPOS 32 +#define UNDO_EMPTY 64 + char undo_queue_state; // One of UNDO_INS, UNDO_DEL, UNDO_EMPTY int undo_q; char *undo_queue_spos; // Start position of queued operation char undo_queue[CONFIG_FEATURE_VI_UNDO_QUEUE_MAX]; -# else -// If undo queuing disabled, don't invoke the missing queue logic -#define ALLOW_UNDO_QUEUED 1 # endif + struct undo_object { struct undo_object *prev; // Linking back avoids list traversal (LIFO) int start; // Offset where the data should be restored/deleted @@ -1445,7 +1450,7 @@ static void yank_status(const char *op, const char *p, int cnt) #endif /* FEATURE_VI_YANKMARK */ #if ENABLE_FEATURE_VI_UNDO -static void undo_push(char *, unsigned, unsigned char); +static void undo_push(char *, unsigned, int); #endif // open a hole in text[] @@ -1572,9 +1577,12 @@ static void flush_undo_data(void) // Undo functions and hooks added by Jody Bruchon (jody@jodybruchon.com) // Add to the undo stack -static void undo_push(char *src, unsigned length, uint8_t u_type) +static void undo_push(char *src, unsigned length, int u_type) { struct undo_object *undo_entry; +# if ENABLE_FEATURE_VI_UNDO_QUEUE + int use_spos = u_type & UNDO_USE_SPOS; +# endif // "u_type" values // UNDO_INS: insertion, undo will remove from buffer @@ -1583,8 +1591,8 @@ static void undo_push(char *src, unsigned length, uint8_t u_type) // The CHAIN operations are for handling multiple operations that the user // performs with a single action, i.e. REPLACE mode or find-and-replace commands // UNDO_{INS,DEL}_QUEUED: If queuing feature is enabled, allow use of the queue - // for the INS/DEL operation. The raw values should be equal to the values of - // UNDO_{INS,DEL} ORed with UNDO_QUEUED_FLAG + // for the INS/DEL operation. + // UNDO_{INS,DEL} ORed with UNDO_USE_SPOS: commit the undo queue # if ENABLE_FEATURE_VI_UNDO_QUEUE // This undo queuing functionality groups multiple character typing or backspaces @@ -1637,9 +1645,7 @@ static void undo_push(char *src, unsigned length, uint8_t u_type) } break; } -# else - // If undo queuing is disabled, ignore the queuing flag entirely - u_type = u_type & ~UNDO_QUEUED_FLAG; + u_type &= ~UNDO_USE_SPOS; # endif // Allocate a new undo object @@ -1656,12 +1662,11 @@ static void undo_push(char *src, unsigned length, uint8_t u_type) } undo_entry->length = length; # if ENABLE_FEATURE_VI_UNDO_QUEUE - if ((u_type & UNDO_USE_SPOS) != 0) { + if (use_spos) { undo_entry->start = undo_queue_spos - text; // use start position from queue } else { undo_entry->start = src - text; // use offset from start of text buffer } - u_type = (u_type & ~UNDO_USE_SPOS); # else undo_entry->start = src - text; # endif -- cgit v1.2.3-55-g6feb From d9d19896a9be5b5cf35d00cae61c9d5621044ccf Mon Sep 17 00:00:00 2001 From: Ron Yorston Date: Thu, 15 Apr 2021 12:01:34 +0100 Subject: vi: position cursor on last column of tab Vi places the cursor on the last column of a tab character whereas BusyBox vi puts it on the first. This is disconcerting for experienced vi users and makes it impossible to distinguish visually between an empty line and one containing just a tab. It wasn't always this way. Prior to commit e3cbfb91d (vi: introduce FEATURE_VI_8BIT) BusyBox vi also put the cursor on the last column. However there were problems with cursor positioning when text was inserted before a tab. Commit eaabf0675 (vi: multiple fixes by Natanael Copa) includes a partial attempt to fix this. (The code is still present but it's never executed. Clever compilers optimise it away.) Revert the changes of commit e3cbfb91d and fix the insert problem for all tabs, not just the first. To quote Natanael: "Costs a few bytes but its worth it imho". function old new delta refresh 974 1000 +26 move_to_col 81 83 +2 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 2/0 up/down: 28/0) Total: 28 bytes Signed-off-by: Ron Yorston Signed-off-by: Denys Vlasenko --- editors/vi.c | 21 +++++++++------------ 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/editors/vi.c b/editors/vi.c index fef328117..f71897253 100644 --- a/editors/vi.c +++ b/editors/vi.c @@ -826,21 +826,20 @@ static void sync_cursor(char *d, int *row, int *col) // find out what col "d" is on co = 0; - while (tp < d) { // drive "co" to correct column + do { // drive "co" to correct column if (*tp == '\n') //vda || *tp == '\0') break; if (*tp == '\t') { - // handle tabs like real vi - if (d == tp && cmd_mode) { - break; - } co = next_tabstop(co); } else if ((unsigned char)*tp < ' ' || *tp == 0x7f) { co++; // display as ^X, use 2 columns } - co++; - tp++; - } + // inserting text before a tab, don't include its position + if (cmd_mode && tp == d - 1 && *d == '\t') { + co++; + break; + } + } while (tp++ < d && ++co); // "co" is the column where "dot" is. // The screen has "columns" columns. @@ -1801,7 +1800,7 @@ static char *move_to_col(char *p, int l) p = begin_line(p); co = 0; - while (co < l && p < end) { + do { if (*p == '\n') //vda || *p == '\0') break; if (*p == '\t') { @@ -1809,9 +1808,7 @@ static char *move_to_col(char *p, int l) } else if (*p < ' ' || *p == 127) { co++; // display as ^X, use 2 columns } - co++; - p++; - } + } while (++co <= l && p++ < end); return p; } -- cgit v1.2.3-55-g6feb From 033fa3d5c65958a89fee155208ce8ac7f9049fcd Mon Sep 17 00:00:00 2001 From: Ron Yorston Date: Thu, 15 Apr 2021 12:02:11 +0100 Subject: vi: code shrink motion by paragraph Use a hand-coded loop to search for paragraph boundaries instead of calling char_search(). We were using a loop anyway to skip consecutive newlines. function old new delta do_cmd 4792 4752 -40 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 0/1 up/down: 0/-40) Total: -40 bytes Signed-off-by: Ron Yorston Signed-off-by: Denys Vlasenko --- editors/vi.c | 27 +++++++++++++++------------ 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/editors/vi.c b/editors/vi.c index f71897253..d37357edd 100644 --- a/editors/vi.c +++ b/editors/vi.c @@ -3636,21 +3636,24 @@ static void do_cmd(int c) break; case '{': // {- move backward paragraph case '}': // }- move forward paragraph + dir = c == '}' ? FORWARD : BACK; do { - dir = c == '}' ? FORWARD : BACK; - // skip over consecutive empty lines - while ((dir == FORWARD ? dot < end - 1 : dot > text) && - *dot == '\n' && dot[dir] == '\n') { + int skip = TRUE; // initially skip consecutive empty lines + while (dir == FORWARD ? dot < end - 1 : dot > text) { + if (*dot == '\n' && dot[dir] == '\n') { + if (!skip) { + if (dir == FORWARD) + ++dot; // move to next blank line + goto dc2; + } + } + else { + skip = FALSE; + } dot += dir; } - q = char_search(dot, "\n\n", ((unsigned)dir << 1) | FULL); - if (q != NULL) { // found blank line - dot = next_line(q); // move to next blank line - } - else { // blank line not found, move to end of file - dot = dir == FORWARD ? end - 1 : text; - break; - } + goto dc6; // end of file + dc2: continue; } while (--cmdcnt > 0); break; #endif /* FEATURE_VI_SEARCH */ -- cgit v1.2.3-55-g6feb From 38ae0f3e3e9490c5b8cc3b917c2d896404afddbe Mon Sep 17 00:00:00 2001 From: Ron Yorston Date: Thu, 15 Apr 2021 12:02:43 +0100 Subject: vi: reset command count when specifying '0' range Since commit a54450248 (vi: allow the '.' command to have a repetition count) using '0' to specify a range doesn't work with a non-zero repeat count, e.g. '1d0'. Users wouldn't normally try to do that but the '.' command does. Add a special case in get_motion_char() to handle this. function old new delta find_range 737 746 +9 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 1/0 up/down: 9/0) Total: 9 bytes Signed-off-by: Ron Yorston Signed-off-by: Denys Vlasenko --- editors/vi.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/editors/vi.c b/editors/vi.c index d37357edd..d20481fbd 100644 --- a/editors/vi.c +++ b/editors/vi.c @@ -1128,11 +1128,16 @@ static int get_motion_char(void) int c, cnt; c = get_one_char(); - if (c != '0' && isdigit(c)) { - // get any non-zero motion count - for (cnt = 0; isdigit(c); c = get_one_char()) - cnt = cnt * 10 + (c - '0'); - cmdcnt = (cmdcnt ?: 1) * cnt; + if (isdigit(c)) { + if (c != '0') { + // get any non-zero motion count + for (cnt = 0; isdigit(c); c = get_one_char()) + cnt = cnt * 10 + (c - '0'); + cmdcnt = (cmdcnt ?: 1) * cnt; + } else { + // ensure standalone '0' works + cmdcnt = 0; + } } return c; -- cgit v1.2.3-55-g6feb From d6e653d667bc1eb343014508a8bddb3dd4945f78 Mon Sep 17 00:00:00 2001 From: Ron Yorston Date: Thu, 15 Apr 2021 12:03:22 +0100 Subject: vi: don't move cursor when yanking whole lines When whole lines are yanked using 'yy' or 'Y' vi doesn't change the cursor position. Make BusyBox vi do the same. function old new delta do_cmd 4776 4786 +10 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 1/0 up/down: 10/0) Total: 10 bytes Signed-off-by: Ron Yorston Signed-off-by: Denys Vlasenko --- editors/vi.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/editors/vi.c b/editors/vi.c index d20481fbd..780c81234 100644 --- a/editors/vi.c +++ b/editors/vi.c @@ -3934,6 +3934,7 @@ static void do_cmd(int c) # endif if (c == 'y' || c == 'Y') yf = YANKONLY; + save_dot = dot; #endif // determine range, and whether it spans lines buftype = find_range(&p, &q, c); @@ -3951,6 +3952,11 @@ static void do_cmd(int c) dot_begin(); dot_skip_over_ws(); } +#if ENABLE_FEATURE_VI_YANKMARK + else /* (c == 'y' || c == 'Y') */ { + dot = save_dot; + } +#endif } // if CHANGING, not deleting, start inserting after the delete if (c == 'c') { -- cgit v1.2.3-55-g6feb From ac6495f6fbb97cb59ccd0a6744660346fd9b80b3 Mon Sep 17 00:00:00 2001 From: Ron Yorston Date: Thu, 15 Apr 2021 12:03:58 +0100 Subject: vi: allow ctrl-D to reduce indentation When whitespace has been automatically added to a new line due to autoindent entering ctrl-D should reduce the level of indentation. Implement an approximation of this by treating ctrl-D as backspace. For the common case of indentation using tabs this is good enough. My attempt at a full implementation was three times bigger. function old new delta char_insert 476 531 +55 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 1/0 up/down: 55/0) Total: 55 bytes Signed-off-by: Ron Yorston Signed-off-by: Denys Vlasenko --- editors/vi.c | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/editors/vi.c b/editors/vi.c index 780c81234..0a82f9e38 100644 --- a/editors/vi.c +++ b/editors/vi.c @@ -2072,6 +2072,11 @@ static uintptr_t stupid_insert(char *p, char c) // stupidly insert the char c at #endif static char *char_insert(char *p, char c, int undo) // insert the char c at 'p' { +#if ENABLE_FEATURE_VI_SETOPTS + char *q; + size_t len; +#endif + if (c == 22) { // Is this an ctrl-V? p += stupid_insert(p, '^'); // use ^ to indicate literal next refresh(FALSE); // show the ^ @@ -2092,6 +2097,15 @@ static char *char_insert(char *p, char c, int undo) // insert the char c at 'p' if ((p[-1] != '\n') && (dot > text)) { p--; } +#if ENABLE_FEATURE_VI_SETOPTS + } else if (c == 4 && autoindent) { // ctrl-D reduces indentation + q = begin_line(p); + len = strspn(q, " \t"); + if (len && q + len == p) { + p--; + p = text_hole_delete(p, p, ALLOW_UNDO_QUEUED); + } +#endif } else if (c == term_orig.c_cc[VERASE] || c == 8 || c == 127) { // Is this a BS if (p > text) { p--; @@ -2116,8 +2130,6 @@ static char *char_insert(char *p, char c, int undo) // insert the char c at 'p' showmatching(p - 1); } if (autoindent && c == '\n') { // auto indent the new line - char *q; - size_t len; q = prev_line(p); // use prev line as template len = strspn(q, " \t"); // space or tab if (len) { -- cgit v1.2.3-55-g6feb From 47c3eaa22f7bbdc1d397c3d29beae33139beecde Mon Sep 17 00:00:00 2001 From: Ron Yorston Date: Thu, 15 Apr 2021 12:04:22 +0100 Subject: vi: correct autoindent for 'O' command Opening a line above the current line with the 'O' command should use the current, not previous, line to determine how much to autoindent. function old new delta char_insert 531 563 +32 do_cmd 4746 4723 -23 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 1/1 up/down: 32/-23) Total: 9 bytes Signed-off-by: Ron Yorston Signed-off-by: Denys Vlasenko --- editors/vi.c | 41 +++++++++++++++++++++++++++++------------ 1 file changed, 29 insertions(+), 12 deletions(-) diff --git a/editors/vi.c b/editors/vi.c index 0a82f9e38..b77406967 100644 --- a/editors/vi.c +++ b/editors/vi.c @@ -286,6 +286,7 @@ struct globals { int text_size; // size of the allocated buffer // the rest +#if ENABLE_FEATURE_VI_SETOPTS smallint vi_setops; // set by setops() #define VI_AUTOINDENT (1 << 0) #define VI_ERR_METHOD (1 << 1) @@ -296,6 +297,7 @@ struct globals { #define err_method (vi_setops & VI_ERR_METHOD) // indicate error with beep or flash #define ignorecase (vi_setops & VI_IGNORECASE) #define showmatch (vi_setops & VI_SHOWMATCH ) +#define openabove (vi_setops & VI_TABSTOP ) // order of constants and strings must match #define OPTS_STR \ "ai\0""autoindent\0" \ @@ -303,6 +305,15 @@ struct globals { "ic\0""ignorecase\0" \ "sm\0""showmatch\0" \ "ts\0""tabstop\0" +#define set_openabove() (vi_setops |= VI_TABSTOP) +#define clear_openabove() (vi_setops &= ~VI_TABSTOP) +#else +#define autoindent (0) +#define err_method (0) +#define openabove (0) +#define set_openabove() ((void)0) +#define clear_openabove() ((void)0) +#endif #if ENABLE_FEATURE_VI_READONLY smallint readonly_mode; @@ -2130,8 +2141,13 @@ static char *char_insert(char *p, char c, int undo) // insert the char c at 'p' showmatching(p - 1); } if (autoindent && c == '\n') { // auto indent the new line - q = prev_line(p); // use prev line as template + // use current/previous line as template + q = openabove ? p : prev_line(p); len = strspn(q, " \t"); // space or tab + if (openabove) { + p--; // this replaces dot_prev() in do_cmd() + q += len; // template will be shifted by text_hole_make() + } if (len) { uintptr_t bias; bias = text_hole_make(p, len); @@ -2445,6 +2461,7 @@ static void setops(char *args, int flg_no) index = 1 << (index >> 1); // convert to VI_bit if (index & VI_TABSTOP) { + // don't set this bit in vi_setops, it's reused as 'openabove' int t; if (!eq || flg_no) // no "=NNN" or it is "notabstop"? goto bad; @@ -3841,19 +3858,19 @@ static void do_cmd(int c) dot = next_line(dot); dot_skip_over_ws(); break; - case 'O': // O- open a empty line above - // 0i\n ESC -i - p = begin_line(dot); - if (p[-1] == '\n') { + case 'O': // O- open an empty line above + dot_begin(); + set_openabove(); + goto dc3; + case 'o': // o- open an empty line below + dot_end(); + dc3: + dot = char_insert(dot, '\n', ALLOW_UNDO); + if (c == 'O' && !autoindent) { + // done in char_insert() for openabove+autoindent dot_prev(); - case 'o': // o- open a empty line below; Yes, I know it is in the middle of the "if (..." - dot_end(); - dot = char_insert(dot, '\n', ALLOW_UNDO); - } else { - dot_begin(); // 0 - dot = char_insert(dot, '\n', ALLOW_UNDO); // i\n ESC - dot_prev(); // - } + clear_openabove(); goto dc_i; break; case 'R': // R- continuous Replace char -- cgit v1.2.3-55-g6feb From 74d565ff1f3756a6a6646c4f7c27dd46beaee06f Mon Sep 17 00:00:00 2001 From: Ron Yorston Date: Thu, 15 Apr 2021 12:04:45 +0100 Subject: vi: make context marks more like vi The context marks that are automatically updated and can be used with the "''" command didn't behave the same as in vi. Marks were only being set for certain editing commands when they should have been set on successful movement commands. Make BusyBox vi behave more like vi. function old new delta .rodata 105179 105194 +15 do_cmd 4723 4668 -55 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 1/1 up/down: 15/-55) Total: -40 bytes Signed-off-by: Ron Yorston Signed-off-by: Denys Vlasenko --- editors/vi.c | 30 ++++++++++++------------------ 1 file changed, 12 insertions(+), 18 deletions(-) diff --git a/editors/vi.c b/editors/vi.c index b77406967..922d7ea8d 100644 --- a/editors/vi.c +++ b/editors/vi.c @@ -377,7 +377,6 @@ struct globals { char *reg[28]; // named register a-z, "D", and "U" 0-25,26,27 char regtype[28]; // buffer type: WHOLE, MULTI or PARTIAL char *mark[28]; // user marks points somewhere in text[]- a-z and previous context '' - char *context_start, *context_end; #endif #if ENABLE_FEATURE_VI_USE_SIGNALS sigjmp_buf restart; // int_handler() jumps to location remembered here @@ -496,8 +495,6 @@ struct globals { //#define Ureg (G.Ureg ) #define regtype (G.regtype ) #define mark (G.mark ) -#define context_start (G.context_start ) -#define context_end (G.context_end ) #define restart (G.restart ) #define term_orig (G.term_orig ) #define cindex (G.cindex ) @@ -1415,18 +1412,10 @@ static char what_reg(void) static void check_context(char cmd) { - // A context is defined to be "modifying text" - // Any modifying command establishes a new context. - - if (dot < context_start || dot > context_end) { - if (strchr(modifying_cmds, cmd) != NULL) { - // we are trying to modify text[]- make this the current context - mark[27] = mark[26]; // move cur to prev - mark[26] = dot; // move local to cur - context_start = prev_line(prev_line(dot)); - context_end = next_line(next_line(dot)); - //loiter= start_loiter= now; - } + // Certain movement commands update the context. + if (strchr(":%{}'GHLMz/?Nn", cmd) != NULL) { + mark[27] = mark[26]; // move cur to prev + mark[26] = dot; // move local to cur } } @@ -1441,8 +1430,6 @@ static char *swap_context(char *p) // goto new context for '' command make this tmp = mark[27]; mark[27] = p; mark[26] = p = tmp; - context_start = prev_line(prev_line(prev_line(p))); - context_end = next_line(next_line(next_line(p))); } return p; } @@ -3287,6 +3274,9 @@ static void do_cmd(int c) int dir; int cnt, i, j; int c1; +#if ENABLE_FEATURE_VI_YANKMARK + char *orig_dot = dot; +#endif #if ENABLE_FEATURE_VI_UNDO int allow_undo = ALLOW_UNDO; int undo_del = UNDO_DEL; @@ -3480,6 +3470,9 @@ static void do_cmd(int c) dot = swap_context(dot); // swap current and previous context dot_begin(); // go to B-o-l dot_skip_over_ws(); +#if ENABLE_FEATURE_VI_YANKMARK + orig_dot = dot; // this doesn't update stored contexts +#endif } else { indicate_error(); } @@ -4109,7 +4102,8 @@ static void do_cmd(int c) dot = bound_dot(dot); // make sure "dot" is valid } #if ENABLE_FEATURE_VI_YANKMARK - check_context(c); // update the current context + if (dot != orig_dot) + check_context(c); // update the current context #endif if (!isdigit(c)) -- cgit v1.2.3-55-g6feb From 5d1bb58b13d4a805538e231584721e5738932efc Mon Sep 17 00:00:00 2001 From: Ron Yorston Date: Thu, 15 Apr 2021 12:05:14 +0100 Subject: vi: code shrink colon line addresses Remove some unnecessary code in get_one_address() and rewrite get_address(). function old new delta colon 3325 3604 +279 get_one_address 342 - -342 ------------------------------------------------------------------------------ (add/remove: 0/1 grow/shrink: 1/0 up/down: 279/-342) Total: -63 bytes Signed-off-by: Ron Yorston Signed-off-by: Denys Vlasenko --- editors/vi.c | 55 ++++++++++++++++++++++++++++--------------------------- 1 file changed, 28 insertions(+), 27 deletions(-) diff --git a/editors/vi.c b/editors/vi.c index 922d7ea8d..9c32ed836 100644 --- a/editors/vi.c +++ b/editors/vi.c @@ -2345,14 +2345,15 @@ static char *char_search(char *p, const char *pat, int dir_and_range) static char *get_one_address(char *p, int *addr) // get colon addr, if present { int st; +# if ENABLE_FEATURE_VI_YANKMARK || ENABLE_FEATURE_VI_SEARCH char *q; +# endif IF_FEATURE_VI_YANKMARK(char c;) *addr = -1; // assume no addr if (*p == '.') { // the current line p++; - q = begin_line(dot); - *addr = count_lines(text, q); + *addr = count_lines(text, dot); } # if ENABLE_FEATURE_VI_YANKMARK else if (*p == '\'') { // is this a mark addr @@ -2389,43 +2390,43 @@ static char *get_one_address(char *p, int *addr) // get colon addr, if present # endif else if (*p == '$') { // the last line in file p++; - q = begin_line(end - 1); - *addr = count_lines(text, q); + *addr = count_lines(text, end - 1); } else if (isdigit(*p)) { // specific line number sscanf(p, "%d%n", addr, &st); p += st; - } else { - // unrecognized address - assume -1 - *addr = -1; } return p; } +# define GET_FIRST 0 +# define GET_SECOND 1 +# define GOT_FIRST 2 +# define GOT_SECOND 3 +# define GOT 2 + static char *get_address(char *p, int *b, int *e) // get two colon addrs, if present { + int state = GET_FIRST; + //----- get the address' i.e., 1,3 'a,'b ----- - // get FIRST addr, if present - while (isblank(*p)) - p++; // skip over leading spaces - if (*p == '%') { // alias for 1,$ - p++; - *b = 1; - *e = count_lines(text, end-1); - goto ga0; - } - p = get_one_address(p, b); - while (isblank(*p)) - p++; - if (*p == ',') { // is there a address separator - p++; - while (isblank(*p)) + for (;;) { + if (isblank(*p)) { + p++; + } else if (*p == '%' && state == GET_FIRST) { // alias for 1,$ + p++; + *b = 1; + *e = count_lines(text, end-1); + state = GOT_SECOND; + } else if (*p == ',' && state == GOT_FIRST) { p++; - // get SECOND addr, if present - p = get_one_address(p, e); + state = GET_SECOND; + } else if (state == GET_FIRST || state == GET_SECOND) { + p = get_one_address(p, state == GET_FIRST ? b : e); + state |= GOT; + } else { + break; + } } - ga0: - while (isblank(*p)) - p++; // skip over trailing spaces return p; } -- cgit v1.2.3-55-g6feb From d488def0e453781e0471cfb0971ad709a95c7919 Mon Sep 17 00:00:00 2001 From: Ron Yorston Date: Thu, 15 Apr 2021 12:05:45 +0100 Subject: vi: detect and warn about invalid line addresses BusyBox vi didn't have proper handling for invalid markers or unsuccessful searches in colon line addresses. This could result in the wrong lines being affected by a change. Detect when an invalid address is specified, propagate an error indicator up the call chain and issue a warning. function old new delta colon 3604 3661 +57 .rodata 105195 105211 +16 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 2/0 up/down: 73/0) Total: 73 bytes Signed-off-by: Ron Yorston Signed-off-by: Denys Vlasenko --- editors/vi.c | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/editors/vi.c b/editors/vi.c index 9c32ed836..1d326f454 100644 --- a/editors/vi.c +++ b/editors/vi.c @@ -2360,14 +2360,15 @@ static char *get_one_address(char *p, int *addr) // get colon addr, if present p++; c = tolower(*p); p++; + q = NULL; if (c >= 'a' && c <= 'z') { // we have a mark c = c - 'a'; q = mark[(unsigned char) c]; - if (q != NULL) { // is mark valid - *addr = count_lines(text, q); - } } + if (q == NULL) // is mark valid + return NULL; + *addr = count_lines(text, q); } # endif # if ENABLE_FEATURE_VI_SEARCH @@ -2383,9 +2384,9 @@ static char *get_one_address(char *p, int *addr) // get colon addr, if present p++; q = char_search(next_line(dot), last_search_pattern + 1, (FORWARD << 1) | FULL); - if (q != NULL) { - *addr = count_lines(text, q); - } + if (q == NULL) + return NULL; + *addr = count_lines(text, q); } # endif else if (*p == '$') { // the last line in file @@ -2422,6 +2423,8 @@ static char *get_address(char *p, int *b, int *e) // get two colon addrs, if pre state = GET_SECOND; } else if (state == GET_FIRST || state == GET_SECOND) { p = get_one_address(p, state == GET_FIRST ? b : e); + if (p == NULL) + break; state |= GOT; } else { break; @@ -2536,9 +2539,7 @@ static void colon(char *buf) char *fn, cmd[MAX_INPUT_LEN], args[MAX_INPUT_LEN]; int i, l, li, b, e; int useforce; -# if ENABLE_FEATURE_VI_SEARCH || ENABLE_FEATURE_ALLOW_EXEC char *orig_buf; -# endif // :3154 // if (-e line 3154) goto it else stay put // :4,33w! foo // write a portion of buffer to file "foo" @@ -2568,7 +2569,12 @@ static void colon(char *buf) fn = current_filename; // look for optional address(es) :. :1 :1,9 :'q,'a :% + orig_buf = buf; buf = get_address(buf, &b, &e); + if (buf == NULL) { + status_line_bold("Bad address: %s", orig_buf); + goto ret; + } # if ENABLE_FEATURE_VI_SEARCH || ENABLE_FEATURE_ALLOW_EXEC // remember orig command line -- cgit v1.2.3-55-g6feb From 47f78913f7576596d44c602a015735cb9c49f4f0 Mon Sep 17 00:00:00 2001 From: Ron Yorston Date: Thu, 15 Apr 2021 12:06:11 +0100 Subject: vi: allow backward search to specify line address It should be possible to use a backward search as a line address in colon commands. function old new delta colon 3661 3701 +40 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 1/0 up/down: 40/0) Total: 40 bytes Signed-off-by: Ron Yorston Signed-off-by: Denys Vlasenko --- editors/vi.c | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/editors/vi.c b/editors/vi.c index 1d326f454..0866e0fa9 100644 --- a/editors/vi.c +++ b/editors/vi.c @@ -2346,9 +2346,9 @@ static char *get_one_address(char *p, int *addr) // get colon addr, if present { int st; # if ENABLE_FEATURE_VI_YANKMARK || ENABLE_FEATURE_VI_SEARCH - char *q; + char *q, c; # endif - IF_FEATURE_VI_YANKMARK(char c;) + IF_FEATURE_VI_SEARCH(int dir;) *addr = -1; // assume no addr if (*p == '.') { // the current line @@ -2372,18 +2372,25 @@ static char *get_one_address(char *p, int *addr) // get colon addr, if present } # endif # if ENABLE_FEATURE_VI_SEARCH - else if (*p == '/') { // a search pattern - q = strchrnul(p + 1, '/'); + else if (*p == '/' || *p == '?') { // a search pattern + c = *p; + q = strchrnul(p + 1, c); if (p + 1 != q) { // save copy of new pattern free(last_search_pattern); last_search_pattern = xstrndup(p, q - p); } p = q; - if (*p == '/') + if (*p == c) p++; - q = char_search(next_line(dot), last_search_pattern + 1, - (FORWARD << 1) | FULL); + if (c == '/') { + q = next_line(dot); + dir = (FORWARD << 1) | FULL; + } else { + q = begin_line(dot); + dir = ((unsigned)BACK << 1) | FULL; + } + q = char_search(q, last_search_pattern + 1, dir); if (q == NULL) return NULL; *addr = count_lines(text, q); -- cgit v1.2.3-55-g6feb From f2277268384d47fbcaba081f19cebc68de819836 Mon Sep 17 00:00:00 2001 From: Ron Yorston Date: Thu, 15 Apr 2021 12:06:51 +0100 Subject: vi: allow line addresses to have an offset Line addresses in colon commands can be defined using an expression that includes '+' or '-' operators. The implementation follows traditional vi: - The first term in the expression defines an address. It can be an absolute line number, '.', '$', a search or a marker. - The second and subsequent terms must be non-negative integers. - If the first term is missing '.' is assumed. If the operator is missing addition is assumed. If the final term in missing an offset of 1 is assumed. Thus the following are valid addresses: .+1 .+ + .1 .-1 .- - The following are not valid (though they are in vim): .+$ .$ 2+. function old new delta colon 3701 3844 +143 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 1/0 up/down: 143/0) Total: 143 bytes Signed-off-by: Ron Yorston Signed-off-by: Denys Vlasenko --- editors/vi.c | 118 ++++++++++++++++++++++++++++++++++++----------------------- 1 file changed, 72 insertions(+), 46 deletions(-) diff --git a/editors/vi.c b/editors/vi.c index 0866e0fa9..6dd951421 100644 --- a/editors/vi.c +++ b/editors/vi.c @@ -2342,67 +2342,93 @@ static char *char_search(char *p, const char *pat, int dir_and_range) //----- The Colon commands ------------------------------------- #if ENABLE_FEATURE_VI_COLON -static char *get_one_address(char *p, int *addr) // get colon addr, if present +static char *get_one_address(char *p, int *result) // get colon addr, if present { - int st; + int st, num, sign, addr, new_addr; # if ENABLE_FEATURE_VI_YANKMARK || ENABLE_FEATURE_VI_SEARCH char *q, c; # endif IF_FEATURE_VI_SEARCH(int dir;) - *addr = -1; // assume no addr - if (*p == '.') { // the current line - p++; - *addr = count_lines(text, dot); - } + addr = -1; // assume no addr + sign = 0; + for (;;) { + new_addr = -1; + if (isblank(*p)) { + p++; + } else if (*p == '.') { // the current line + p++; + new_addr = count_lines(text, dot); + } # if ENABLE_FEATURE_VI_YANKMARK - else if (*p == '\'') { // is this a mark addr - p++; - c = tolower(*p); - p++; - q = NULL; - if (c >= 'a' && c <= 'z') { - // we have a mark - c = c - 'a'; - q = mark[(unsigned char) c]; + else if (*p == '\'') { // is this a mark addr + p++; + c = tolower(*p); + p++; + q = NULL; + if (c >= 'a' && c <= 'z') { + // we have a mark + c = c - 'a'; + q = mark[(unsigned char) c]; + } + if (q == NULL) // is mark valid + return NULL; + new_addr = count_lines(text, q); } - if (q == NULL) // is mark valid - return NULL; - *addr = count_lines(text, q); - } # endif # if ENABLE_FEATURE_VI_SEARCH - else if (*p == '/' || *p == '?') { // a search pattern - c = *p; - q = strchrnul(p + 1, c); - if (p + 1 != q) { - // save copy of new pattern - free(last_search_pattern); - last_search_pattern = xstrndup(p, q - p); + else if (*p == '/' || *p == '?') { // a search pattern + c = *p; + q = strchrnul(p + 1, c); + if (p + 1 != q) { + // save copy of new pattern + free(last_search_pattern); + last_search_pattern = xstrndup(p, q - p); + } + p = q; + if (*p == c) + p++; + if (c == '/') { + q = next_line(dot); + dir = (FORWARD << 1) | FULL; + } else { + q = begin_line(dot); + dir = ((unsigned)BACK << 1) | FULL; + } + q = char_search(q, last_search_pattern + 1, dir); + if (q == NULL) + return NULL; + new_addr = count_lines(text, q); } - p = q; - if (*p == c) +# endif + else if (*p == '$') { // the last line in file p++; - if (c == '/') { - q = next_line(dot); - dir = (FORWARD << 1) | FULL; + new_addr = count_lines(text, end - 1); + } else if (isdigit(*p)) { + sscanf(p, "%d%n", &num, &st); + p += st; + if (addr < 0) { // specific line number + addr = num; + } else { // offset from current addr + addr += sign >= 0 ? num : -num; + } + sign = 0; + } else if (*p == '-' || *p == '+') { + sign = *p++ == '-' ? -1 : 1; + if (addr < 0) { // default address is dot + addr = count_lines(text, dot); + } } else { - q = begin_line(dot); - dir = ((unsigned)BACK << 1) | FULL; + addr += sign; // consume unused trailing sign + break; + } + if (new_addr >= 0) { + if (addr >= 0) // only one new address per expression + return NULL; + addr = new_addr; } - q = char_search(q, last_search_pattern + 1, dir); - if (q == NULL) - return NULL; - *addr = count_lines(text, q); - } -# endif - else if (*p == '$') { // the last line in file - p++; - *addr = count_lines(text, end - 1); - } else if (isdigit(*p)) { // specific line number - sscanf(p, "%d%n", addr, &st); - p += st; } + *result = addr; return p; } -- cgit v1.2.3-55-g6feb From b65e7f629ef3cd655eb9a2a6f47530e5fd098ae3 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Thu, 15 Apr 2021 23:17:01 +0200 Subject: vi: move undo_queue_state in globals to other byte-sized members function old new delta vi_main 278 275 -3 undo_queue_commit 62 56 -6 undo_push 374 362 -12 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 0/3 up/down: 0/-21) Total: -21 bytes Signed-off-by: Denys Vlasenko --- editors/vi.c | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/editors/vi.c b/editors/vi.c index 6dd951421..09f6eca6d 100644 --- a/editors/vi.c +++ b/editors/vi.c @@ -352,6 +352,9 @@ struct globals { #if ENABLE_FEATURE_VI_CRASHME char last_input_char; // last char read from user #endif +#if ENABLE_FEATURE_VI_UNDO_QUEUE + char undo_queue_state; // One of UNDO_INS, UNDO_DEL, UNDO_EMPTY +#endif #if ENABLE_FEATURE_VI_DOT_CMD smallint adding2q; // are we currently adding user input to q @@ -425,15 +428,6 @@ struct globals { #define ALLOW_UNDO_QUEUED ALLOW_UNDO # endif -# if ENABLE_FEATURE_VI_UNDO_QUEUE -#define UNDO_USE_SPOS 32 -#define UNDO_EMPTY 64 - char undo_queue_state; // One of UNDO_INS, UNDO_DEL, UNDO_EMPTY - int undo_q; - char *undo_queue_spos; // Start position of queued operation - char undo_queue[CONFIG_FEATURE_VI_UNDO_QUEUE_MAX]; -# endif - struct undo_object { struct undo_object *prev; // Linking back avoids list traversal (LIFO) int start; // Offset where the data should be restored/deleted @@ -441,6 +435,13 @@ struct globals { uint8_t u_type; // 0=deleted, 1=inserted, 2=swapped char undo_text[1]; // text that was deleted (if deletion) } *undo_stack_tail; +# if ENABLE_FEATURE_VI_UNDO_QUEUE +#define UNDO_USE_SPOS 32 +#define UNDO_EMPTY 64 + char *undo_queue_spos; // Start position of queued operation + int undo_q; + char undo_queue[CONFIG_FEATURE_VI_UNDO_QUEUE_MAX]; +# endif #endif /* ENABLE_FEATURE_VI_UNDO */ }; #define G (*ptr_to_globals) @@ -2071,8 +2072,8 @@ static uintptr_t stupid_insert(char *p, char c) // stupidly insert the char c at static char *char_insert(char *p, char c, int undo) // insert the char c at 'p' { #if ENABLE_FEATURE_VI_SETOPTS - char *q; - size_t len; + char *q; + size_t len; #endif if (c == 22) { // Is this an ctrl-V? @@ -2140,9 +2141,9 @@ static char *char_insert(char *p, char c, int undo) // insert the char c at 'p' bias = text_hole_make(p, len); p += bias; q += bias; -#if ENABLE_FEATURE_VI_UNDO +# if ENABLE_FEATURE_VI_UNDO undo_push_insert(p, len, undo); -#endif +# endif memcpy(p, q, len); p += len; } -- cgit v1.2.3-55-g6feb From d9136efd7ac5f7655376057e0ba28498a975216b Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Sun, 18 Apr 2021 13:22:26 +0200 Subject: gcc-version.sh: Cygwin fix On Cygwin, "echo __GNUC__ __GNUC_MINOR__ | gcc -E -xc -" can print extra empty trailing line. Signed-off-by: Denys Vlasenko --- scripts/gcc-version.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/gcc-version.sh b/scripts/gcc-version.sh index 34510804f..9376ed4fb 100755 --- a/scripts/gcc-version.sh +++ b/scripts/gcc-version.sh @@ -8,5 +8,5 @@ compiler="$*" -MAJ_MIN=$(echo __GNUC__ __GNUC_MINOR__ | $compiler -E -xc - | tail -n 1) +MAJ_MIN=$(echo __GNUC__ __GNUC_MINOR__ | $compiler -E -xc - | grep . | tail -n 1) printf '%02d%02d\n' $MAJ_MIN -- cgit v1.2.3-55-g6feb From 310ef232809b34a75c120629b7b2c0d4af0dd50f Mon Sep 17 00:00:00 2001 From: Ron Yorston Date: Sat, 17 Apr 2021 09:25:11 +0100 Subject: vi: add expandtab option This implements the vim option expandtab in BusyBox vi. From vim help: In Insert mode: Use the appropriate number of spaces to insert a . Spaces are used in indents with the '>' and '<' commands and when 'autoindent' is on. To insert a real tab when 'expandtab' is on, use CTRL-V. This implementation doesn't change how BusyBox vi handles autoindent: it continues to copy the indentation from a neighbouring line. If that line has tabs in its indentation so too will the new line. function old new delta char_insert 563 679 +116 next_column - 48 +48 .rodata 105211 105236 +25 colon 3844 3855 +11 refresh 1000 982 -18 move_to_col 83 59 -24 ------------------------------------------------------------------------------ (add/remove: 1/0 grow/shrink: 3/2 up/down: 200/-42) Total: 158 bytes Signed-off-by: Peter D Signed-off-by: Ron Yorston Signed-off-by: Denys Vlasenko --- editors/vi.c | 64 ++++++++++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 47 insertions(+), 17 deletions(-) diff --git a/editors/vi.c b/editors/vi.c index 09f6eca6d..de7a43325 100644 --- a/editors/vi.c +++ b/editors/vi.c @@ -289,11 +289,13 @@ struct globals { #if ENABLE_FEATURE_VI_SETOPTS smallint vi_setops; // set by setops() #define VI_AUTOINDENT (1 << 0) -#define VI_ERR_METHOD (1 << 1) -#define VI_IGNORECASE (1 << 2) -#define VI_SHOWMATCH (1 << 3) -#define VI_TABSTOP (1 << 4) +#define VI_EXPANDTAB (1 << 1) +#define VI_ERR_METHOD (1 << 2) +#define VI_IGNORECASE (1 << 3) +#define VI_SHOWMATCH (1 << 4) +#define VI_TABSTOP (1 << 5) #define autoindent (vi_setops & VI_AUTOINDENT) +#define expandtab (vi_setops & VI_EXPANDTAB ) #define err_method (vi_setops & VI_ERR_METHOD) // indicate error with beep or flash #define ignorecase (vi_setops & VI_IGNORECASE) #define showmatch (vi_setops & VI_SHOWMATCH ) @@ -301,6 +303,7 @@ struct globals { // order of constants and strings must match #define OPTS_STR \ "ai\0""autoindent\0" \ + "et\0""expandtab\0" \ "fl\0""flash\0" \ "ic\0""ignorecase\0" \ "sm\0""showmatch\0" \ @@ -309,6 +312,7 @@ struct globals { #define clear_openabove() (vi_setops &= ~VI_TABSTOP) #else #define autoindent (0) +#define expandtab (0) #define err_method (0) #define openabove (0) #define set_openabove() ((void)0) @@ -759,6 +763,27 @@ static int next_tabstop(int col) return col + ((tabstop - 1) - (col % tabstop)); } +static int next_column(char c, int co) +{ + if (c == '\t') + co = next_tabstop(co); + else if ((unsigned char)c < ' ' || c == 0x7f) + co++; // display as ^X, use 2 columns + return co + 1; +} + +#if ENABLE_FEATURE_VI_SETOPTS +static int get_column(char *p) +{ + const char *r; + int co = 0; + + for (r = begin_line(p); r < p; r++) + co = next_column(*r, co); + return co; +} +#endif + //----- Erase the Screen[] memory ------------------------------ static void screen_erase(void) { @@ -838,11 +863,7 @@ static void sync_cursor(char *d, int *row, int *col) do { // drive "co" to correct column if (*tp == '\n') //vda || *tp == '\0') break; - if (*tp == '\t') { - co = next_tabstop(co); - } else if ((unsigned char)*tp < ' ' || *tp == 0x7f) { - co++; // display as ^X, use 2 columns - } + co = next_column(*tp, co) - 1; // inserting text before a tab, don't include its position if (cmd_mode && tp == d - 1 && *d == '\t') { co++; @@ -1807,12 +1828,8 @@ static char *move_to_col(char *p, int l) do { if (*p == '\n') //vda || *p == '\0') break; - if (*p == '\t') { - co = next_tabstop(co); - } else if (*p < ' ' || *p == 127) { - co++; // display as ^X, use 2 columns - } - } while (++co <= l && p++ < end); + co = next_column(*p, co); + } while (co <= l && p++ < end); return p; } @@ -2104,6 +2121,17 @@ static char *char_insert(char *p, char c, int undo) // insert the char c at 'p' p--; p = text_hole_delete(p, p, ALLOW_UNDO_QUEUED); } + } else if (c == '\t' && expandtab) { // expand tab + int col = get_column(p); + col = next_tabstop(col) - col + 1; + while (col--) { +# if ENABLE_FEATURE_VI_UNDO + undo_push_insert(p, 1, undo); +# else + modified_count++; +# endif + p += 1 + stupid_insert(p, ' '); + } #endif } else if (c == term_orig.c_cc[VERASE] || c == 8 || c == 127) { // Is this a BS if (p > text) { @@ -2871,11 +2899,13 @@ static void colon(char *buf) # if ENABLE_FEATURE_VI_SETOPTS status_line_bold( "%sautoindent " + "%sexpandtab " "%sflash " "%signorecase " "%sshowmatch " "tabstop=%u", autoindent ? "" : "no", + expandtab ? "" : "no", err_method ? "" : "no", ignorecase ? "" : "no", showmatch ? "" : "no", @@ -3753,7 +3783,7 @@ static void do_cmd(int c) i = count_lines(p, q); // # of lines we are shifting for ( ; i > 0; i--, p = next_line(p)) { if (c == '<') { - // shift left- remove tab or 8 spaces + // shift left- remove tab or tabstop spaces if (*p == '\t') { // shrink buffer 1 char text_hole_delete(p, p, allow_undo); @@ -3767,7 +3797,7 @@ static void do_cmd(int c) } } } else /* if (c == '>') */ { - // shift right -- add tab or 8 spaces + // shift right -- add tab or tabstop spaces char_insert(p, '\t', allow_undo); } #if ENABLE_FEATURE_VI_UNDO -- cgit v1.2.3-55-g6feb From f277c9eebb91a46cbd795c34aa64ee8b6a2e448c Mon Sep 17 00:00:00 2001 From: Ron Yorston Date: Sat, 17 Apr 2021 09:25:47 +0100 Subject: vi: make de-indentation with ctrl-D more like vim Commit ac6495f6f (vi: allow ctrl-D to reduce indentation) treated ctrl-D during autoindent as a backspace. This was adequate for indentation using tabs but doesn't work well with the expandtab option. In the latter case it's necessary to backspace over all the spaces. Make ctrl-D work correctly when spaces are present in the indent. Also, make it behave more like vim: - ctrl-D is independent of autoindent; - indentation is reduced even when the cursor isn't positioned at the end of the indent. function old new delta char_insert 679 717 +38 get_column - 37 +37 ------------------------------------------------------------------------------ (add/remove: 1/0 grow/shrink: 1/0 up/down: 75/0) Total: 75 bytes Signed-off-by: Ron Yorston Signed-off-by: Denys Vlasenko --- editors/vi.c | 30 +++++++++++++++++++++--------- 1 file changed, 21 insertions(+), 9 deletions(-) diff --git a/editors/vi.c b/editors/vi.c index de7a43325..caf01acd3 100644 --- a/editors/vi.c +++ b/editors/vi.c @@ -763,6 +763,11 @@ static int next_tabstop(int col) return col + ((tabstop - 1) - (col % tabstop)); } +static int prev_tabstop(int col) +{ + return col - ((col % tabstop) ?: tabstop); +} + static int next_column(char c, int co) { if (c == '\t') @@ -772,7 +777,6 @@ static int next_column(char c, int co) return co + 1; } -#if ENABLE_FEATURE_VI_SETOPTS static int get_column(char *p) { const char *r; @@ -782,7 +786,6 @@ static int get_column(char *p) co = next_column(*r, co); return co; } -#endif //----- Erase the Screen[] memory ------------------------------ static void screen_erase(void) @@ -2113,14 +2116,23 @@ static char *char_insert(char *p, char c, int undo) // insert the char c at 'p' if ((p[-1] != '\n') && (dot > text)) { p--; } -#if ENABLE_FEATURE_VI_SETOPTS - } else if (c == 4 && autoindent) { // ctrl-D reduces indentation - q = begin_line(p); - len = strspn(q, " \t"); - if (len && q + len == p) { - p--; - p = text_hole_delete(p, p, ALLOW_UNDO_QUEUED); + } else if (c == 4) { // ctrl-D reduces indentation + int prev; + char *r, *bol; + bol = begin_line(p); + for (r = bol; r < end_line(p); ++r) { + if (!isblank(*r)) + break; } + + prev = prev_tabstop(get_column(r)); + while (r > bol && get_column(r) > prev) { + if (p > bol) + p--; + r--; + r = text_hole_delete(r, r, ALLOW_UNDO_QUEUED); + } +#if ENABLE_FEATURE_VI_SETOPTS } else if (c == '\t' && expandtab) { // expand tab int col = get_column(p); col = next_tabstop(col) - col + 1; -- cgit v1.2.3-55-g6feb From 21367b283909cb71ef74cb0e89f77334e9eb6a61 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Tue, 20 Apr 2021 19:01:43 +0200 Subject: tls: reduce register pressure in i386 assembly (helps Android to compile) function old new delta pstm_montgomery_reduce 440 435 -5 Signed-off-by: Denys Vlasenko --- networking/tls_pstm_montgomery_reduce.c | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/networking/tls_pstm_montgomery_reduce.c b/networking/tls_pstm_montgomery_reduce.c index 20f9c26d5..e8857f394 100644 --- a/networking/tls_pstm_montgomery_reduce.c +++ b/networking/tls_pstm_montgomery_reduce.c @@ -62,6 +62,7 @@ #define LOOP_START \ mu = c[x] * mp +#if 0 #define INNERMUL \ asm( \ "movl %5,%%eax \n\t" \ @@ -74,6 +75,29 @@ asm( \ :"=g"(_c[LO]), "=r"(cy) \ :"0"(_c[LO]), "1"(cy), "g"(mu), "g"(*tmpm++) \ : "%eax", "%edx", "cc") +/* + * The above generated "error: 'asm' operand has impossible constraints" on Android. + * Do they reserve in their ABI a register for something, and there aren't enough left? + */ +#else +/* Let's avoid two explicit "movl" by telling compiler to put input value of *tmpm++ + * into EAX, and to expect cy result in EDX: + */ +#define INNERMUL \ +asm( \ + "mull %4 \n\t" \ + "addl %3,%%eax \n\t" \ + "adcl $0,%%edx \n\t" \ + "addl %%eax,%0 \n\t" \ + "adcl $0,%%edx \n\t" \ +:"=g"(_c[LO]), "=&d"(cy) \ +:"0"(_c[LO]), "g"(cy), "g"(mu), "a"(*tmpm++) \ +:"cc") +/* This doesn't tell compiler that we clobber EAX, but it probably won't need + * the value of *tmpm anyway, thus won't try to reuse EAX contents. + * TODO: fix it with dummy "=a"(clobbered_eax) output? + */ +#endif #define PROPCARRY \ asm( \ -- cgit v1.2.3-55-g6feb From 20b224046c61ccc9a8e847cd0665f9f39e9a8ff9 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Tue, 20 Apr 2021 19:03:15 +0200 Subject: tls: further reduce register pressure in i386 assembly function old new delta pstm_montgomery_reduce 435 431 -4 Signed-off-by: Denys Vlasenko --- networking/tls_pstm_montgomery_reduce.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/networking/tls_pstm_montgomery_reduce.c b/networking/tls_pstm_montgomery_reduce.c index e8857f394..4181a0590 100644 --- a/networking/tls_pstm_montgomery_reduce.c +++ b/networking/tls_pstm_montgomery_reduce.c @@ -102,11 +102,11 @@ asm( \ #define PROPCARRY \ asm( \ "addl %1,%0 \n\t" \ - "setb %%al \n\t" \ - "movzbl %%al,%1 \n\t" \ + "sbb %1,%1 \n\t" \ + "neg %1 \n\t" \ :"=g"(_c[LO]), "=r"(cy) \ :"0"(_c[LO]), "1"(cy) \ -: "%eax", "cc") +:"cc") /******************************************************************************/ #elif defined(PSTM_X86_64) -- cgit v1.2.3-55-g6feb From 6c6470b3847d12b2d7504fa37fbf871c46792d77 Mon Sep 17 00:00:00 2001 From: Chris Renshaw Date: Wed, 21 Apr 2021 14:40:31 -0300 Subject: gcc-version.sh: fix for "invalid number" message during Android NDK builds A CR in the gcc output would cause the following to show throughout build: : invalid numberbox-1.32.1/scripts/gcc-version.sh: line 12: printf: 9 Signed-off-by: Chris Renshaw Signed-off-by: Denys Vlasenko --- scripts/gcc-version.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/gcc-version.sh b/scripts/gcc-version.sh index 9376ed4fb..0eb27c7a6 100755 --- a/scripts/gcc-version.sh +++ b/scripts/gcc-version.sh @@ -7,6 +7,6 @@ # compiler="$*" - -MAJ_MIN=$(echo __GNUC__ __GNUC_MINOR__ | $compiler -E -xc - | grep . | tail -n 1) +# tr -d '\r': fix up msdos-style line endings (Cygwin et al) +MAJ_MIN=$(echo __GNUC__ __GNUC_MINOR__ | $compiler -E -xc - | tr -d '\r' | tail -n 1) printf '%02d%02d\n' $MAJ_MIN -- cgit v1.2.3-55-g6feb From 972e29881a4aecde7987ee4947e609e75894fb8c Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Thu, 22 Apr 2021 10:25:04 +0200 Subject: tls: make constant basepoint9[32] array 8-byte aligned Has no effect on binary size, but likely to be more efficient. Signed-off-by: Denys Vlasenko --- networking/tls.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/networking/tls.c b/networking/tls.c index e34acd69f..bbb1f41dc 100644 --- a/networking/tls.c +++ b/networking/tls.c @@ -1953,7 +1953,7 @@ static void send_client_key_exchange(tls_state_t *tls) premaster_size = sizeof(rsa_premaster); } else { /* ECDHE */ - static const uint8_t basepoint9[CURVE25519_KEYSIZE] ALIGN1 = {9}; + static const uint8_t basepoint9[CURVE25519_KEYSIZE] ALIGN8 = {9}; uint8_t privkey[CURVE25519_KEYSIZE]; //[32] if (!(tls->flags & GOT_EC_KEY)) -- cgit v1.2.3-55-g6feb From d005c9f4c7e6afc812612e98fdd120b9b4051c04 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Sat, 24 Apr 2021 11:54:50 +0200 Subject: libbb.h: inline byteswaps function old new delta recv_and_process_peer_pkt 2173 2245 +72 machtime_dg 97 114 +17 machtime_stream 29 45 +16 fmt_time_bernstein_25 132 139 +7 aesgcm_GHASH 183 184 +1 dumpleases_main 519 516 -3 __bswap_32 3 - -3 udhcp_run_script 743 739 -4 tls_xread_record 634 630 -4 select_lease_time 56 52 -4 rdate_main 260 256 -4 get_prefix 327 323 -4 udhcp_listen_socket 185 180 -5 sha1_process_block64 361 356 -5 sendping6 81 76 -5 sendping4 107 102 -5 read32 27 22 -5 ll_proto_a2n 112 107 -5 bb_lookup_port 102 97 -5 udhcpc_main 2615 2609 -6 tftpd_main 579 573 -6 str2sockaddr 558 552 -6 GMULT 136 130 -6 sha1_end 73 66 -7 ntpd_main 1361 1354 -7 ntohl 7 - -7 inet_addr_match 93 86 -7 htonl 7 - -7 do_iplink 1259 1252 -7 do_add_or_delete 1138 1131 -7 create_and_bind_or_die 117 110 -7 bind_for_passive_mode 124 117 -7 xconnect_ftpdata 98 90 -8 rpm_getint 118 110 -8 read_leases 304 296 -8 read_config 216 208 -8 udhcp_send_kernel_packet 336 327 -9 udhcp_recv_kernel_packet 143 134 -9 sha256_process_block64 451 442 -9 d6_send_kernel_packet_from_client_data_ifindex 275 266 -9 write_leases 215 205 -10 wget_main 2518 2508 -10 udhcpd_main 1528 1518 -10 tftp_protocol 2019 2009 -10 ftpd_main 2159 2149 -10 des_crypt 1318 1308 -10 send_ACK 138 127 -11 ipaddr_modify 1618 1607 -11 udhcp_str2optset 650 638 -12 init_d6_packet 115 103 -12 xwrite_encrypted 512 499 -13 tls_handshake 2060 2047 -13 pscan_main 607 594 -13 perform_d6_release 240 227 -13 ip_port_str 135 122 -13 handle_incoming_and_exit 2230 2217 -13 INET_setroute 751 737 -14 traceroute_init 1153 1137 -16 nc_main 1055 1039 -16 udhcp_init_header 92 75 -17 volume_id_probe_hfs_hfsplus 512 494 -18 send_offer 455 435 -20 do_lzo_decompress 507 487 -20 add_client_options 229 209 -20 ipcalc_main 554 533 -21 dhcprelay_main 966 943 -23 change_listen_mode 345 321 -24 send_packet 188 162 -26 static.xmalloc_optname_optval 709 681 -28 rpm_gettags 447 419 -28 machtime 28 - -28 catcher 299 270 -29 sfp_to_d 78 48 -30 reread_config_file 917 886 -31 lfp_to_d 84 51 -33 udhcp_recv_raw_packet 594 559 -35 nbdclient_main 1182 1145 -37 d_to_lfp 137 100 -37 lzo_compress 567 529 -38 d6_recv_raw_packet 299 254 -45 d_to_sfp 133 85 -48 d6_send_raw_packet_from_client_data_ifindex 427 379 -48 common_ping_main 1935 1887 -48 udhcp_send_raw_packet 467 416 -51 zcip_main 1219 1160 -59 udhcpc6_main 2636 2568 -68 do_lzo_compress 327 258 -69 send_arp_request 201 129 -72 common_traceroute_main 1699 1621 -78 arpping 523 437 -86 arping_main 1597 1481 -116 print_tunnel 678 550 -128 dnsd_main 1304 1164 -140 parse_args 1370 1169 -201 ------------------------------------------------------------------------------ (add/remove: 0/6 grow/shrink: 5/85 up/down: 113/-2246) Total: -2133 bytes Signed-off-by: Denys Vlasenko --- include/libbb.h | 22 ++++++++++++++++++++++ include/platform.h | 1 + networking/ntpd.c | 2 +- 3 files changed, 24 insertions(+), 1 deletion(-) diff --git a/include/libbb.h b/include/libbb.h index 37732e14e..03f9c35f3 100644 --- a/include/libbb.h +++ b/include/libbb.h @@ -192,6 +192,28 @@ int klogctl(int type, char *b, int len); # define BUFSIZ 4096 #endif +#if __GNUC_PREREQ(5,0) +/* Since musl is apparently unable to get it right and would use + * a function call to a single-instruction function of "bswap %eax", + * reroute to gcc builtins: + */ +# undef bswap_16 +# undef bswap_32 +# undef bswap_64 +# define bswap_16(x) __builtin_bswap16(x) +# define bswap_32(x) __builtin_bswap32(x) +# define bswap_64(x) __builtin_bswap64(x) +# if BB_LITTLE_ENDIAN +# undef ntohs +# undef htons +# undef ntohl +# undef htonl +# define ntohs(x) __builtin_bswap16(x) +# define htons(x) __builtin_bswap16(x) +# define ntohl(x) __builtin_bswap32(x) +# define htonl(x) __builtin_bswap32(x) +# endif +#endif /* Busybox does not use threads, we can speed up stdio. */ #ifdef HAVE_UNLOCKED_STDIO diff --git a/include/platform.h b/include/platform.h index 387b6f537..4633b2507 100644 --- a/include/platform.h +++ b/include/platform.h @@ -195,6 +195,7 @@ #endif #if ULONG_MAX > 0xffffffff +/* inline 64-bit bswap only on 64-bit arches */ # define bb_bswap_64(x) bswap_64(x) #endif diff --git a/networking/ntpd.c b/networking/ntpd.c index 8cf8830c2..6bf6c4e07 100644 --- a/networking/ntpd.c +++ b/networking/ntpd.c @@ -577,7 +577,7 @@ sfp_to_d(s_fixedpt_t sfp) return ret; } #if ENABLE_FEATURE_NTPD_SERVER -static void +static NOINLINE void d_to_lfp(l_fixedpt_t *lfp, double d) { uint32_t intl; -- cgit v1.2.3-55-g6feb From 6ca36077ccde12f4b1e4d730b06284d18c20ac0e Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Sat, 24 Apr 2021 11:56:49 +0200 Subject: tls: "server did not provide EC key" is fatal Signed-off-by: Denys Vlasenko --- networking/tls.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/networking/tls.c b/networking/tls.c index bbb1f41dc..8492997ac 100644 --- a/networking/tls.c +++ b/networking/tls.c @@ -1957,7 +1957,7 @@ static void send_client_key_exchange(tls_state_t *tls) uint8_t privkey[CURVE25519_KEYSIZE]; //[32] if (!(tls->flags & GOT_EC_KEY)) - bb_simple_error_msg("server did not provide EC key"); + bb_simple_error_msg_and_die("server did not provide EC key"); /* Generate random private key, see RFC 7748 */ tls_get_random(privkey, sizeof(privkey)); -- cgit v1.2.3-55-g6feb From 121b02d6b6c9f276e7f8da560e5996d3e389cd63 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Sat, 24 Apr 2021 12:06:03 +0200 Subject: inetd: deinline machtime() - gcc gets it wrong function old new delta machtime - 24 +24 machtime_stream 45 29 -16 machtime_dg 114 97 -17 ------------------------------------------------------------------------------ (add/remove: 1/0 grow/shrink: 0/2 up/down: 24/-33) Total: -9 bytes Signed-off-by: Denys Vlasenko --- networking/inetd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/networking/inetd.c b/networking/inetd.c index febfb7b73..e5352a555 100644 --- a/networking/inetd.c +++ b/networking/inetd.c @@ -1697,7 +1697,7 @@ static void FAST_FUNC chargen_dg(int s, servtab_t *sep) * we must add 2208988800 seconds to this figure to make up for * some seventy years Bell Labs was asleep. */ -static uint32_t machtime(void) +static NOINLINE uint32_t machtime(void) { struct timeval tv; -- cgit v1.2.3-55-g6feb From f18a1fd6f368ada05b33cf36483304a5e3c4945d Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Mon, 26 Apr 2021 13:25:56 +0200 Subject: tls: implement secp256r1 elliptic curve (aka P256) function old new delta sp_256_mod_mul_norm_10 - 1439 +1439 sp_256_ecc_mulmod_10 - 1363 +1363 sp_256_proj_point_dbl_10 - 490 +490 p256_base - 244 +244 static.sp_256_mont_sqr_10 - 234 +234 static.sp_256_mont_mul_10 - 214 +214 curve_P256_compute_pubkey_and_premaster - 197 +197 static.sp_256_mont_reduce_10 - 176 +176 static.sp_256_from_bin - 149 +149 sp_256_to_bin - 148 +148 tls_handshake 2046 2146 +100 static.sp_256_mul_add_10 - 82 +82 .rodata 103275 103336 +61 static.sp_256_mont_sub_10 - 52 +52 static.sp_256_mont_dbl_10 - 52 +52 static.sp_256_cmp_10 - 43 +43 p256_mod - 40 +40 static.sp_256_cond_sub_10 - 32 +32 p256_mod_2 - 32 +32 sp_256_norm_10 - 31 +31 sp_256_cmp_equal_10 - 30 +30 sp_256_add_10 - 22 +22 addr_mask - 8 +8 ------------------------------------------------------------------------------ (add/remove: 22/0 grow/shrink: 2/0 up/down: 5239/0) Total: 5239 bytes text data bss dec hex filename 1018192 559 5020 1023771 f9f1b busybox_old 1023431 559 5020 1029010 fb392 busybox_unstripped Signed-off-by: Denys Vlasenko --- networking/tls.c | 101 +++-- networking/tls.h | 8 + networking/tls_fe.h | 1 - networking/tls_sp_c32.c | 1052 +++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 1126 insertions(+), 36 deletions(-) create mode 100644 networking/tls_sp_c32.c diff --git a/networking/tls.c b/networking/tls.c index 8492997ac..cacd2e9ff 100644 --- a/networking/tls.c +++ b/networking/tls.c @@ -18,6 +18,7 @@ //kbuild:lib-$(CONFIG_TLS) += tls_aesgcm.o //kbuild:lib-$(CONFIG_TLS) += tls_rsa.o //kbuild:lib-$(CONFIG_TLS) += tls_fe.o +//kbuild:lib-$(CONFIG_TLS) += tls_sp_c32.o #include "tls.h" @@ -265,8 +266,9 @@ enum { GOT_CERT_RSA_KEY_ALG = 1 << 1, GOT_CERT_ECDSA_KEY_ALG = 1 << 2, // so far unused GOT_EC_KEY = 1 << 3, - ENCRYPTION_AESGCM = 1 << 4, // else AES-SHA (or NULL-SHA if ALLOW_RSA_NULL_SHA256=1) - ENCRYPT_ON_WRITE = 1 << 5, + GOT_EC_CURVE_X25519 = 1 << 4, // else P256 + ENCRYPTION_AESGCM = 1 << 5, // else AES-SHA (or NULL-SHA if ALLOW_RSA_NULL_SHA256=1) + ENCRYPT_ON_WRITE = 1 << 6, }; struct record_hdr { @@ -285,7 +287,11 @@ struct tls_handshake_data { //TODO: store just the DER key here, parse/use/delete it when sending client key //this way it will stay key type agnostic here. psRsaKey_t server_rsa_pub_key; - uint8_t ecc_pub_key32[32]; + + /* peer's elliptic curve key data */ + /* for x25519, it contains one point in first 32 bytes */ + /* for P256, it contains x,y point pair, each 32 bytes long */ + uint8_t ecc_pub_key32[2 * 32]; /* HANDSHAKE HASH: */ //unsigned saved_client_hello_size; @@ -1526,20 +1532,13 @@ static void send_client_hello_and_alloc_hsd(tls_state_t *tls, const char *sni) }; static const uint8_t supported_groups[] = { 0x00,0x0a, //extension_type: "supported_groups" - 0x00,0x04, //ext len - 0x00,0x02, //list len - 0x00,0x1d, //curve_x25519 (RFC 7748) - //0x00,0x1e, //curve_x448 (RFC 7748) - //0x00,0x17, //curve_secp256r1 + 0x00,0x06, //ext len + 0x00,0x04, //list len + 0x00,0x17, //curve_secp256r1 //0x00,0x18, //curve_secp384r1 //0x00,0x19, //curve_secp521r1 -//TODO: implement secp256r1 (at least): dl.fedoraproject.org immediately aborts -//if only x25519/x448 are advertised, seems to support only secpNNNr1 curves: -// openssl s_client -connect dl.fedoraproject.org:443 -debug -tls1_2 -cipher ECDHE-RSA-AES128-GCM-SHA256 -//Peer signing digest: SHA512 -//Peer signature type: RSA -//Server Temp Key: ECDH, P-256, 256 bits -//TLSv1.2, Cipher is ECDHE-RSA-AES128-GCM-SHA256 + 0x00,0x1d, //curve_x25519 (RFC 7748) + //0x00,0x1e, //curve_x448 (RFC 7748) }; //static const uint8_t signature_algorithms[] = { // 000d @@ -1877,12 +1876,32 @@ static void process_server_key(tls_state_t *tls, int len) if (len < (1+2+1+32)) tls_error_die(tls); keybuf += 4; - /* So far we only support curve_x25519 */ +#if BB_BIG_ENDIAN +# define _0x03001741 0x03001741 +# define _0x03001d20 0x03001d20 +#else +# define _0x03001741 0x41170003 +# define _0x03001d20 0x201d0003 +#endif move_from_unaligned32(t32, keybuf); - if (t32 != htonl(0x03001d20)) - bb_simple_error_msg_and_die("elliptic curve is not x25519"); + keybuf += 4; + switch (t32) { + case _0x03001d20: //curve_x25519 + tls->flags |= GOT_EC_CURVE_X25519; + memcpy(tls->hsd->ecc_pub_key32, keybuf, 32); + break; + case _0x03001741: //curve_secp256r1 + /* P256 point can be transmitted odd- or even-compressed + * (first byte is 3 or 2) or uncompressed (4). + */ + if (*keybuf++ != 4) + bb_simple_error_msg_and_die("compressed EC points not supported"); + memcpy(tls->hsd->ecc_pub_key32, keybuf, 2 * 32); + break; + default: + bb_error_msg_and_die("elliptic curve is not x25519 or P256: 0x%08x", t32); + } - memcpy(tls->hsd->ecc_pub_key32, keybuf + 4, 32); tls->flags |= GOT_EC_KEY; dbg("got eccPubKey\n"); } @@ -1918,9 +1937,7 @@ static void send_client_key_exchange(tls_state_t *tls) }; //FIXME: better size estimate struct client_key_exchange *record = tls_get_zeroed_outbuf(tls, sizeof(*record)); - uint8_t rsa_premaster[RSA_PREMASTER_SIZE]; - uint8_t x25519_premaster[CURVE25519_KEYSIZE]; - uint8_t *premaster; + uint8_t premaster[RSA_PREMASTER_SIZE > EC_CURVE_KEYSIZE ? RSA_PREMASTER_SIZE : EC_CURVE_KEYSIZE]; int premaster_size; int len; @@ -1929,19 +1946,19 @@ static void send_client_key_exchange(tls_state_t *tls) if (!(tls->flags & GOT_CERT_RSA_KEY_ALG)) bb_simple_error_msg("server cert is not RSA"); - tls_get_random(rsa_premaster, sizeof(rsa_premaster)); + tls_get_random(premaster, RSA_PREMASTER_SIZE); if (TLS_DEBUG_FIXED_SECRETS) - memset(rsa_premaster, 0x44, sizeof(rsa_premaster)); + memset(premaster, 0x44, RSA_PREMASTER_SIZE); // RFC 5246 // "Note: The version number in the PreMasterSecret is the version // offered by the client in the ClientHello.client_version, not the // version negotiated for the connection." - rsa_premaster[0] = TLS_MAJ; - rsa_premaster[1] = TLS_MIN; - dump_hex("premaster:%s\n", rsa_premaster, sizeof(rsa_premaster)); + premaster[0] = TLS_MAJ; + premaster[1] = TLS_MIN; + dump_hex("premaster:%s\n", premaster, sizeof(premaster)); len = psRsaEncryptPub(/*pool:*/ NULL, /* psRsaKey_t* */ &tls->hsd->server_rsa_pub_key, - rsa_premaster, /*inlen:*/ sizeof(rsa_premaster), + premaster, /*inlen:*/ RSA_PREMASTER_SIZE, record->key + 2, sizeof(record->key) - 2, data_param_ignored ); @@ -1949,10 +1966,10 @@ static void send_client_key_exchange(tls_state_t *tls) record->key[0] = len >> 8; record->key[1] = len & 0xff; len += 2; - premaster = rsa_premaster; - premaster_size = sizeof(rsa_premaster); - } else { - /* ECDHE */ + premaster_size = RSA_PREMASTER_SIZE; + } else /* ECDHE */ + if (tls->flags & GOT_EC_CURVE_X25519) { + /* ECDHE, curve x25519 */ static const uint8_t basepoint9[CURVE25519_KEYSIZE] ALIGN8 = {9}; uint8_t privkey[CURVE25519_KEYSIZE]; //[32] @@ -1969,13 +1986,27 @@ static void send_client_key_exchange(tls_state_t *tls) /* Compute premaster using peer's public key */ dbg("computing x25519_premaster\n"); - curve25519(x25519_premaster, privkey, tls->hsd->ecc_pub_key32); + curve25519(premaster, privkey, tls->hsd->ecc_pub_key32); len = CURVE25519_KEYSIZE; record->key[0] = len; len++; - premaster = x25519_premaster; - premaster_size = sizeof(x25519_premaster); + premaster_size = CURVE25519_KEYSIZE; + } else { + /* ECDHE, curve P256 */ + if (!(tls->flags & GOT_EC_KEY)) + bb_simple_error_msg_and_die("server did not provide EC key"); + + dbg("computing P256_premaster\n"); + curve_P256_compute_pubkey_and_premaster( + record->key + 2, premaster, + /*point:*/ tls->hsd->ecc_pub_key32 + ); + premaster_size = P256_KEYSIZE; + len = 1 + P256_KEYSIZE * 2; + record->key[0] = len; + record->key[1] = 4; + len++; } record->type = HANDSHAKE_CLIENT_KEY_EXCHANGE; diff --git a/networking/tls.h b/networking/tls.h index d4ac1bef8..e1afb7ea8 100644 --- a/networking/tls.h +++ b/networking/tls.h @@ -106,3 +106,11 @@ void xorbuf_aligned_AES_BLOCK_SIZE(void* buf, const void* mask) FAST_FUNC; #include "tls_aesgcm.h" #include "tls_rsa.h" #include "tls_fe.h" + +#define EC_CURVE_KEYSIZE 32 +#define P256_KEYSIZE 32 +#define CURVE25519_KEYSIZE 32 + +void curve_P256_compute_pubkey_and_premaster( + uint8_t *pubkey, uint8_t *premaster, + const uint8_t *peerkey32) FAST_FUNC; diff --git a/networking/tls_fe.h b/networking/tls_fe.h index fe8cff228..2859c9d2d 100644 --- a/networking/tls_fe.h +++ b/networking/tls_fe.h @@ -3,5 +3,4 @@ * * Licensed under GPLv2, see file LICENSE in this source tree. */ -#define CURVE25519_KEYSIZE 32 void curve25519(uint8_t *result, const uint8_t *e, const uint8_t *q) FAST_FUNC; diff --git a/networking/tls_sp_c32.c b/networking/tls_sp_c32.c new file mode 100644 index 000000000..e7667de73 --- /dev/null +++ b/networking/tls_sp_c32.c @@ -0,0 +1,1052 @@ +/* + * Copyright (C) 2021 Denys Vlasenko + * + * Licensed under GPLv2, see file LICENSE in this source tree. + */ +#include "tls.h" + +#define SP_DEBUG 0 +#define FIXED_SECRET 0 +#define FIXED_PEER_PUBKEY 0 + +#if SP_DEBUG +# define dbg(...) fprintf(stderr, __VA_ARGS__) +static void dump_hex(const char *fmt, const void *vp, int len) +{ + char hexbuf[32 * 1024 + 4]; + const uint8_t *p = vp; + + bin2hex(hexbuf, (void*)p, len)[0] = '\0'; + dbg(fmt, hexbuf); +} +#else +# define dbg(...) ((void)0) +# define dump_hex(...) ((void)0) +#endif + +#undef DIGIT_BIT +#define DIGIT_BIT 32 +typedef int32_t sp_digit; + +/* The code below is taken from parts of + * wolfssl-3.15.3/wolfcrypt/src/sp_c32.c + * and heavily modified. + * Header comment is kept intact: + */ + +/* sp.c + * + * Copyright (C) 2006-2018 wolfSSL Inc. + * + * This file is part of wolfSSL. + * + * wolfSSL 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. + * + * wolfSSL 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA + */ + +/* Implementation by Sean Parkinson. */ + +/* Point structure to use. */ +typedef struct sp_point { + sp_digit x[2 * 10]; + sp_digit y[2 * 10]; + sp_digit z[2 * 10]; + int infinity; +} sp_point; + +/* The modulus (prime) of the curve P256. */ +static const sp_digit p256_mod[10] = { + 0x3ffffff,0x3ffffff,0x3ffffff,0x003ffff,0x0000000, + 0x0000000,0x0000000,0x0000400,0x3ff0000,0x03fffff, +}; + +#define p256_mp_mod ((sp_digit)0x000001) + +/* Mask for address to obfuscate which of the two address will be used. */ +static const size_t addr_mask[2] = { 0, (size_t)-1 }; + +/* The base point of curve P256. */ +static const sp_point p256_base = { + /* X ordinate */ + { 0x098c296,0x04e5176,0x33a0f4a,0x204b7ac,0x277037d,0x0e9103c,0x3ce6e56,0x1091fe2,0x1f2e12c,0x01ac5f4 }, + /* Y ordinate */ + { 0x3bf51f5,0x1901a0d,0x1ececbb,0x15dacc5,0x22bce33,0x303e785,0x27eb4a7,0x1fe6e3b,0x2e2fe1a,0x013f8d0 }, + /* Z ordinate */ + { 0x0000001,0x0000000,0x0000000,0x0000000,0x0000000,0x0000000,0x0000000,0x0000000,0x0000000,0x0000000 }, + /* infinity */ + 0 +}; + +/* Write r as big endian to byte aray. + * Fixed length number of bytes written: 32 + * + * r A single precision integer. + * a Byte array. + */ +static void sp_256_to_bin(sp_digit* r, uint8_t* a) +{ + int i, j, s = 0, b; + + for (i = 0; i < 9; i++) { + r[i+1] += r[i] >> 26; + r[i] &= 0x3ffffff; + } + j = 256 / 8 - 1; + a[j] = 0; + for (i=0; i<10 && j>=0; i++) { + b = 0; + a[j--] |= r[i] << s; b += 8 - s; + if (j < 0) + break; + while (b < 26) { + a[j--] = r[i] >> b; b += 8; + if (j < 0) + break; + } + s = 8 - (b - 26); + if (j >= 0) + a[j] = 0; + if (s != 0) + j++; + } +} + +/* Read big endian unsigned byte aray into r. + * + * r A single precision integer. + * a Byte array. + * n Number of bytes in array to read. + */ +static void sp_256_from_bin(sp_digit* r, int max, const uint8_t* a, int n) +{ + int i, j = 0, s = 0; + + r[0] = 0; + for (i = n-1; i >= 0; i--) { + r[j] |= ((sp_digit)a[i]) << s; + if (s >= 18) { + r[j] &= 0x3ffffff; + s = 26 - s; + if (j + 1 >= max) + break; + r[++j] = a[i] >> s; + s = 8 - s; + } + else + s += 8; + } + + for (j++; j < max; j++) + r[j] = 0; +} + +/* Convert a point of big-endian 32-byte x,y pair to type sp_point. */ +static void sp_256_point_from_bin2x32(sp_point* p, const uint8_t *bin2x32) +{ + memset(p, 0, sizeof(*p)); + /*p->infinity = 0;*/ + sp_256_from_bin(p->x, 2 * 10, bin2x32, 32); + sp_256_from_bin(p->y, 2 * 10, bin2x32 + 32, 32); + //static const uint8_t one[1] = { 1 }; + //sp_256_from_bin(p->z, 2 * 10, one, 1); + p->z[0] = 1; +} + +/* Compare a with b in constant time. + * + * a A single precision integer. + * b A single precision integer. + * return -ve, 0 or +ve if a is less than, equal to or greater than b + * respectively. + */ +static sp_digit sp_256_cmp_10(const sp_digit* a, const sp_digit* b) +{ + sp_digit r = 0; + int i; + for (i = 9; i >= 0; i--) + r |= (a[i] - b[i]) & (0 - !r); + return r; +} + +/* Compare two numbers to determine if they are equal. + * + * a First number to compare. + * b Second number to compare. + * return 1 when equal and 0 otherwise. + */ +static int sp_256_cmp_equal_10(const sp_digit* a, const sp_digit* b) +{ +#if 1 + sp_digit r = 0; + int i; + for (i = 0; i < 10; i++) + r |= (a[i] ^ b[i]); + return r == 0; +#else + return sp_256_cmp_10(a, b) == 0; +#endif +} + +/* Normalize the values in each word to 26. + * + * a Array of sp_digit to normalize. + */ +static void sp_256_norm_10(sp_digit* a) +{ + int i; + for (i = 0; i < 9; i++) { + a[i+1] += a[i] >> 26; + a[i] &= 0x3ffffff; + } +} + +/* Add b to a into r. (r = a + b) + * + * r A single precision integer. + * a A single precision integer. + * b A single precision integer. + */ +static void sp_256_add_10(sp_digit* r, const sp_digit* a, const sp_digit* b) +{ + int i; + for (i = 0; i < 10; i++) + r[i] = a[i] + b[i]; +} + +/* Conditionally add a and b using the mask m. + * m is -1 to add and 0 when not. + * + * r A single precision number representing conditional add result. + * a A single precision number to add with. + * b A single precision number to add. + * m Mask value to apply. + */ +static void sp_256_cond_add_10(sp_digit* r, const sp_digit* a, + const sp_digit* b, const sp_digit m) +{ + int i; + for (i = 0; i < 10; i++) + r[i] = a[i] + (b[i] & m); +} + +/* Conditionally subtract b from a using the mask m. + * m is -1 to subtract and 0 when not. + * + * r A single precision number representing condition subtract result. + * a A single precision number to subtract from. + * b A single precision number to subtract. + * m Mask value to apply. + */ +static void sp_256_cond_sub_10(sp_digit* r, const sp_digit* a, + const sp_digit* b, const sp_digit m) +{ + int i; + for (i = 0; i < 10; i++) + r[i] = a[i] - (b[i] & m); +} + +/* Add 1 to a. (a = a + 1) + * + * r A single precision integer. + * a A single precision integer. + */ +static void sp_256_add_one_10(sp_digit* a) +{ + a[0]++; + sp_256_norm_10(a); +} + +/* Shift number left one bit. + * Bottom bit is lost. + * + * r Result of shift. + * a Number to shift. + */ +static void sp_256_rshift1_10(sp_digit* r, sp_digit* a) +{ + int i; + for (i = 0; i < 9; i++) + r[i] = ((a[i] >> 1) | (a[i + 1] << 25)) & 0x3ffffff; + r[9] = a[9] >> 1; +} + +/* Multiply a number by Montogmery normalizer mod modulus (prime). + * + * r The resulting Montgomery form number. + * a The number to convert. + */ +static void sp_256_mod_mul_norm_10(sp_digit* r, const sp_digit* a) +{ + int64_t t[8]; + int64_t a32[8]; + int64_t o; + + a32[0] = a[0]; + a32[0] |= a[1] << 26; + a32[0] &= 0xffffffff; + a32[1] = (sp_digit)(a[1] >> 6); + a32[1] |= a[2] << 20; + a32[1] &= 0xffffffff; + a32[2] = (sp_digit)(a[2] >> 12); + a32[2] |= a[3] << 14; + a32[2] &= 0xffffffff; + a32[3] = (sp_digit)(a[3] >> 18); + a32[3] |= a[4] << 8; + a32[3] &= 0xffffffff; + a32[4] = (sp_digit)(a[4] >> 24); + a32[4] |= a[5] << 2; + a32[4] |= a[6] << 28; + a32[4] &= 0xffffffff; + a32[5] = (sp_digit)(a[6] >> 4); + a32[5] |= a[7] << 22; + a32[5] &= 0xffffffff; + a32[6] = (sp_digit)(a[7] >> 10); + a32[6] |= a[8] << 16; + a32[6] &= 0xffffffff; + a32[7] = (sp_digit)(a[8] >> 16); + a32[7] |= a[9] << 10; + a32[7] &= 0xffffffff; + + /* 1 1 0 -1 -1 -1 -1 0 */ + t[0] = 0 + a32[0] + a32[1] - a32[3] - a32[4] - a32[5] - a32[6]; + /* 0 1 1 0 -1 -1 -1 -1 */ + t[1] = 0 + a32[1] + a32[2] - a32[4] - a32[5] - a32[6] - a32[7]; + /* 0 0 1 1 0 -1 -1 -1 */ + t[2] = 0 + a32[2] + a32[3] - a32[5] - a32[6] - a32[7]; + /* -1 -1 0 2 2 1 0 -1 */ + t[3] = 0 - a32[0] - a32[1] + 2 * a32[3] + 2 * a32[4] + a32[5] - a32[7]; + /* 0 -1 -1 0 2 2 1 0 */ + t[4] = 0 - a32[1] - a32[2] + 2 * a32[4] + 2 * a32[5] + a32[6]; + /* 0 0 -1 -1 0 2 2 1 */ + t[5] = 0 - a32[2] - a32[3] + 2 * a32[5] + 2 * a32[6] + a32[7]; + /* -1 -1 0 0 0 1 3 2 */ + t[6] = 0 - a32[0] - a32[1] + a32[5] + 3 * a32[6] + 2 * a32[7]; + /* 1 0 -1 -1 -1 -1 0 3 */ + t[7] = 0 + a32[0] - a32[2] - a32[3] - a32[4] - a32[5] + 3 * a32[7]; + + t[1] += t[0] >> 32; t[0] &= 0xffffffff; + t[2] += t[1] >> 32; t[1] &= 0xffffffff; + t[3] += t[2] >> 32; t[2] &= 0xffffffff; + t[4] += t[3] >> 32; t[3] &= 0xffffffff; + t[5] += t[4] >> 32; t[4] &= 0xffffffff; + t[6] += t[5] >> 32; t[5] &= 0xffffffff; + t[7] += t[6] >> 32; t[6] &= 0xffffffff; + o = t[7] >> 32; t[7] &= 0xffffffff; + t[0] += o; + t[3] -= o; + t[6] -= o; + t[7] += o; + t[1] += t[0] >> 32; t[0] &= 0xffffffff; + t[2] += t[1] >> 32; t[1] &= 0xffffffff; + t[3] += t[2] >> 32; t[2] &= 0xffffffff; + t[4] += t[3] >> 32; t[3] &= 0xffffffff; + t[5] += t[4] >> 32; t[4] &= 0xffffffff; + t[6] += t[5] >> 32; t[5] &= 0xffffffff; + t[7] += t[6] >> 32; t[6] &= 0xffffffff; + + r[0] = (sp_digit)(t[0]) & 0x3ffffff; + r[1] = (sp_digit)(t[0] >> 26); + r[1] |= t[1] << 6; + r[1] &= 0x3ffffff; + r[2] = (sp_digit)(t[1] >> 20); + r[2] |= t[2] << 12; + r[2] &= 0x3ffffff; + r[3] = (sp_digit)(t[2] >> 14); + r[3] |= t[3] << 18; + r[3] &= 0x3ffffff; + r[4] = (sp_digit)(t[3] >> 8); + r[4] |= t[4] << 24; + r[4] &= 0x3ffffff; + r[5] = (sp_digit)(t[4] >> 2) & 0x3ffffff; + r[6] = (sp_digit)(t[4] >> 28); + r[6] |= t[5] << 4; + r[6] &= 0x3ffffff; + r[7] = (sp_digit)(t[5] >> 22); + r[7] |= t[6] << 10; + r[7] &= 0x3ffffff; + r[8] = (sp_digit)(t[6] >> 16); + r[8] |= t[7] << 16; + r[8] &= 0x3ffffff; + r[9] = (sp_digit)(t[7] >> 10); +} + +/* Mul a by scalar b and add into r. (r += a * b) + * + * r A single precision integer. + * a A single precision integer. + * b A scalar. + */ +static void sp_256_mul_add_10(sp_digit* r, const sp_digit* a, + const sp_digit b) +{ + int64_t tb = b; + int64_t t = 0; + int i; + + for (i = 0; i < 10; i++) { + t += (tb * a[i]) + r[i]; + r[i] = t & 0x3ffffff; + t >>= 26; + } + r[10] += t; +} + +/* Divide the number by 2 mod the modulus (prime). (r = a / 2 % m) + * + * r Result of division by 2. + * a Number to divide. + * m Modulus (prime). + */ +static void sp_256_div2_10(sp_digit* r, const sp_digit* a, const sp_digit* m) +{ + sp_256_cond_add_10(r, a, m, 0 - (a[0] & 1)); + sp_256_norm_10(r); + sp_256_rshift1_10(r, r); +} + +/* Shift the result in the high 256 bits down to the bottom. + * + * r A single precision number. + * a A single precision number. + */ +static void sp_256_mont_shift_10(sp_digit* r, const sp_digit* a) +{ + int i; + sp_digit n, s; + + s = a[10]; + n = a[9] >> 22; + for (i = 0; i < 9; i++) { + n += (s & 0x3ffffff) << 4; + r[i] = n & 0x3ffffff; + n >>= 26; + s = a[11 + i] + (s >> 26); + } + n += s << 4; + r[9] = n; + memset(&r[10], 0, sizeof(*r) * 10); +} + +/* Add two Montgomery form numbers (r = a + b % m). + * + * r Result of addition. + * a First number to add in Montogmery form. + * b Second number to add in Montogmery form. + * m Modulus (prime). + */ +static void sp_256_mont_add_10(sp_digit* r, const sp_digit* a, const sp_digit* b, + const sp_digit* m) +{ + sp_256_add_10(r, a, b); + sp_256_norm_10(r); + sp_256_cond_sub_10(r, r, m, 0 - ((r[9] >> 22) > 0)); + sp_256_norm_10(r); +} + +/* Double a Montgomery form number (r = a + a % m). + * + * r Result of doubling. + * a Number to double in Montogmery form. + * m Modulus (prime). + */ +static void sp_256_mont_dbl_10(sp_digit* r, const sp_digit* a, const sp_digit* m) +{ + sp_256_add_10(r, a, a); + sp_256_norm_10(r); + sp_256_cond_sub_10(r, r, m, 0 - ((r[9] >> 22) > 0)); + sp_256_norm_10(r); +} + +/* Triple a Montgomery form number (r = a + a + a % m). + * + * r Result of Tripling. + * a Number to triple in Montogmery form. + * m Modulus (prime). + */ +static void sp_256_mont_tpl_10(sp_digit* r, const sp_digit* a, const sp_digit* m) +{ + sp_256_add_10(r, a, a); + sp_256_norm_10(r); + sp_256_cond_sub_10(r, r, m, 0 - ((r[9] >> 22) > 0)); + sp_256_norm_10(r); + sp_256_add_10(r, r, a); + sp_256_norm_10(r); + sp_256_cond_sub_10(r, r, m, 0 - ((r[9] >> 22) > 0)); + sp_256_norm_10(r); +} + +/* Sub b from a into r. (r = a - b) + * + * r A single precision integer. + * a A single precision integer. + * b A single precision integer. + */ +static void sp_256_sub_10(sp_digit* r, const sp_digit* a, + const sp_digit* b) +{ + int i; + for (i = 0; i < 10; i++) + r[i] = a[i] - b[i]; +} + +/* Subtract two Montgomery form numbers (r = a - b % m). + * + * r Result of subtration. + * a Number to subtract from in Montogmery form. + * b Number to subtract with in Montogmery form. + * m Modulus (prime). + */ +static void sp_256_mont_sub_10(sp_digit* r, const sp_digit* a, const sp_digit* b, + const sp_digit* m) +{ + sp_256_sub_10(r, a, b); + sp_256_cond_add_10(r, r, m, r[9] >> 22); + sp_256_norm_10(r); +} + +/* Reduce the number back to 256 bits using Montgomery reduction. + * + * a A single precision number to reduce in place. + * m The single precision number representing the modulus. + * mp The digit representing the negative inverse of m mod 2^n. + */ +static void sp_256_mont_reduce_10(sp_digit* a, const sp_digit* m, sp_digit mp) +{ + int i; + sp_digit mu; + + if (mp != 1) { + for (i = 0; i < 9; i++) { + mu = (a[i] * mp) & 0x3ffffff; + sp_256_mul_add_10(a+i, m, mu); + a[i+1] += a[i] >> 26; + } + mu = (a[i] * mp) & 0x3fffffl; + sp_256_mul_add_10(a+i, m, mu); + a[i+1] += a[i] >> 26; + a[i] &= 0x3ffffff; + } + else { + for (i = 0; i < 9; i++) { + mu = a[i] & 0x3ffffff; + sp_256_mul_add_10(a+i, p256_mod, mu); + a[i+1] += a[i] >> 26; + } + mu = a[i] & 0x3fffffl; + sp_256_mul_add_10(a+i, p256_mod, mu); + a[i+1] += a[i] >> 26; + a[i] &= 0x3ffffff; + } + + sp_256_mont_shift_10(a, a); + sp_256_cond_sub_10(a, a, m, 0 - ((a[9] >> 22) > 0)); + sp_256_norm_10(a); +} + +/* Multiply a and b into r. (r = a * b) + * + * r A single precision integer. + * a A single precision integer. + * b A single precision integer. + */ +static void sp_256_mul_10(sp_digit* r, const sp_digit* a, const sp_digit* b) +{ + int i, j, k; + int64_t c; + + c = ((int64_t)a[9]) * b[9]; + r[19] = (sp_digit)(c >> 26); + c = (c & 0x3ffffff) << 26; + for (k = 17; k >= 0; k--) { + for (i = 9; i >= 0; i--) { + j = k - i; + if (j >= 10) + break; + if (j < 0) + continue; + c += ((int64_t)a[i]) * b[j]; + } + r[k + 2] += c >> 52; + r[k + 1] = (c >> 26) & 0x3ffffff; + c = (c & 0x3ffffff) << 26; + } + r[0] = (sp_digit)(c >> 26); +} + +/* Multiply two Montogmery form numbers mod the modulus (prime). + * (r = a * b mod m) + * + * r Result of multiplication. + * a First number to multiply in Montogmery form. + * b Second number to multiply in Montogmery form. + * m Modulus (prime). + * mp Montogmery mulitplier. + */ +static void sp_256_mont_mul_10(sp_digit* r, const sp_digit* a, const sp_digit* b, + const sp_digit* m, sp_digit mp) +{ + sp_256_mul_10(r, a, b); + sp_256_mont_reduce_10(r, m, mp); +} + +/* Square a and put result in r. (r = a * a) + * + * r A single precision integer. + * a A single precision integer. + */ +static void sp_256_sqr_10(sp_digit* r, const sp_digit* a) +{ + int i, j, k; + int64_t c; + + c = ((int64_t)a[9]) * a[9]; + r[19] = (sp_digit)(c >> 26); + c = (c & 0x3ffffff) << 26; + for (k = 17; k >= 0; k--) { + for (i = 9; i >= 0; i--) { + j = k - i; + if (j >= 10 || i <= j) + break; + if (j < 0) + continue; + + c += ((int64_t)a[i]) * a[j] * 2; + } + if (i == j) + c += ((int64_t)a[i]) * a[i]; + + r[k + 2] += c >> 52; + r[k + 1] = (c >> 26) & 0x3ffffff; + c = (c & 0x3ffffff) << 26; + } + r[0] = (sp_digit)(c >> 26); +} + +/* Square the Montgomery form number. (r = a * a mod m) + * + * r Result of squaring. + * a Number to square in Montogmery form. + * m Modulus (prime). + * mp Montogmery mulitplier. + */ +static void sp_256_mont_sqr_10(sp_digit* r, const sp_digit* a, const sp_digit* m, + sp_digit mp) +{ + sp_256_sqr_10(r, a); + sp_256_mont_reduce_10(r, m, mp); +} + +/* Invert the number, in Montgomery form, modulo the modulus (prime) of the + * P256 curve. (r = 1 / a mod m) + * + * r Inverse result. + * a Number to invert. + * td Temporary data. + */ +/* Mod-2 for the P256 curve. */ +static const uint32_t p256_mod_2[8] = { + 0xfffffffd,0xffffffff,0xffffffff,0x00000000, + 0x00000000,0x00000000,0x00000001,0xffffffff, +}; +static void sp_256_mont_inv_10(sp_digit* r, sp_digit* a, sp_digit* td) +{ + sp_digit* t = td; + int i; + + memcpy(t, a, sizeof(sp_digit) * 10); + for (i = 254; i >= 0; i--) { + sp_256_mont_sqr_10(t, t, p256_mod, p256_mp_mod); + if (p256_mod_2[i / 32] & ((sp_digit)1 << (i % 32))) + sp_256_mont_mul_10(t, t, a, p256_mod, p256_mp_mod); + } + memcpy(r, t, sizeof(sp_digit) * 10); +} + +/* Map the Montgomery form projective co-ordinate point to an affine point. + * + * r Resulting affine co-ordinate point. + * p Montgomery form projective co-ordinate point. + * t Temporary ordinate data. + */ +static void sp_256_map_10(sp_point* r, sp_point* p, sp_digit* t) +{ + sp_digit* t1 = t; + sp_digit* t2 = t + 2*10; + int32_t n; + + sp_256_mont_inv_10(t1, p->z, t + 2*10); + + sp_256_mont_sqr_10(t2, t1, p256_mod, p256_mp_mod); + sp_256_mont_mul_10(t1, t2, t1, p256_mod, p256_mp_mod); + + /* x /= z^2 */ + sp_256_mont_mul_10(r->x, p->x, t2, p256_mod, p256_mp_mod); + memset(r->x + 10, 0, sizeof(r->x) / 2); + sp_256_mont_reduce_10(r->x, p256_mod, p256_mp_mod); + /* Reduce x to less than modulus */ + n = sp_256_cmp_10(r->x, p256_mod); + sp_256_cond_sub_10(r->x, r->x, p256_mod, 0 - (n >= 0)); + sp_256_norm_10(r->x); + + /* y /= z^3 */ + sp_256_mont_mul_10(r->y, p->y, t1, p256_mod, p256_mp_mod); + memset(r->y + 10, 0, sizeof(r->y) / 2); + sp_256_mont_reduce_10(r->y, p256_mod, p256_mp_mod); + /* Reduce y to less than modulus */ + n = sp_256_cmp_10(r->y, p256_mod); + sp_256_cond_sub_10(r->y, r->y, p256_mod, 0 - (n >= 0)); + sp_256_norm_10(r->y); + + memset(r->z, 0, sizeof(r->z)); + r->z[0] = 1; +} + +/* Double the Montgomery form projective point p. + * + * r Result of doubling point. + * p Point to double. + * t Temporary ordinate data. + */ +static void sp_256_proj_point_dbl_10(sp_point* r, sp_point* p, sp_digit* t) +{ + sp_point *rp[2]; + sp_point tp; + sp_digit* t1 = t; + sp_digit* t2 = t + 2*10; + sp_digit* x; + sp_digit* y; + sp_digit* z; + int i; + + /* When infinity don't double point passed in - constant time. */ + rp[0] = r; + rp[1] = &tp; + x = rp[p->infinity]->x; + y = rp[p->infinity]->y; + z = rp[p->infinity]->z; + /* Put point to double into result - good for infinity. */ + if (r != p) { + for (i = 0; i < 10; i++) + r->x[i] = p->x[i]; + for (i = 0; i < 10; i++) + r->y[i] = p->y[i]; + for (i = 0; i < 10; i++) + r->z[i] = p->z[i]; + r->infinity = p->infinity; + } + + /* T1 = Z * Z */ + sp_256_mont_sqr_10(t1, z, p256_mod, p256_mp_mod); + /* Z = Y * Z */ + sp_256_mont_mul_10(z, y, z, p256_mod, p256_mp_mod); + /* Z = 2Z */ + sp_256_mont_dbl_10(z, z, p256_mod); + /* T2 = X - T1 */ + sp_256_mont_sub_10(t2, x, t1, p256_mod); + /* T1 = X + T1 */ + sp_256_mont_add_10(t1, x, t1, p256_mod); + /* T2 = T1 * T2 */ + sp_256_mont_mul_10(t2, t1, t2, p256_mod, p256_mp_mod); + /* T1 = 3T2 */ + sp_256_mont_tpl_10(t1, t2, p256_mod); + /* Y = 2Y */ + sp_256_mont_dbl_10(y, y, p256_mod); + /* Y = Y * Y */ + sp_256_mont_sqr_10(y, y, p256_mod, p256_mp_mod); + /* T2 = Y * Y */ + sp_256_mont_sqr_10(t2, y, p256_mod, p256_mp_mod); + /* T2 = T2/2 */ + sp_256_div2_10(t2, t2, p256_mod); + /* Y = Y * X */ + sp_256_mont_mul_10(y, y, x, p256_mod, p256_mp_mod); + /* X = T1 * T1 */ + sp_256_mont_mul_10(x, t1, t1, p256_mod, p256_mp_mod); + /* X = X - Y */ + sp_256_mont_sub_10(x, x, y, p256_mod); + /* X = X - Y */ + sp_256_mont_sub_10(x, x, y, p256_mod); + /* Y = Y - X */ + sp_256_mont_sub_10(y, y, x, p256_mod); + /* Y = Y * T1 */ + sp_256_mont_mul_10(y, y, t1, p256_mod, p256_mp_mod); + /* Y = Y - T2 */ + sp_256_mont_sub_10(y, y, t2, p256_mod); +} + +/* Add two Montgomery form projective points. + * + * r Result of addition. + * p Frist point to add. + * q Second point to add. + * t Temporary ordinate data. + */ +static void sp_256_proj_point_add_10(sp_point* r, sp_point* p, sp_point* q, + sp_digit* t) +{ + sp_point *ap[2]; + sp_point *rp[2]; + sp_point tp; + sp_digit* t1 = t; + sp_digit* t2 = t + 2*10; + sp_digit* t3 = t + 4*10; + sp_digit* t4 = t + 6*10; + sp_digit* t5 = t + 8*10; + sp_digit* x; + sp_digit* y; + sp_digit* z; + int i; + + /* Ensure only the first point is the same as the result. */ + if (q == r) { + sp_point* a = p; + p = q; + q = a; + } + + /* Check double */ + sp_256_sub_10(t1, p256_mod, q->y); + sp_256_norm_10(t1); + if (sp_256_cmp_equal_10(p->x, q->x) + & sp_256_cmp_equal_10(p->z, q->z) + & (sp_256_cmp_equal_10(p->y, q->y) | sp_256_cmp_equal_10(p->y, t1)) + ) { + sp_256_proj_point_dbl_10(r, p, t); + } + else { + rp[0] = r; + rp[1] = &tp; + memset(&tp, 0, sizeof(tp)); + x = rp[p->infinity | q->infinity]->x; + y = rp[p->infinity | q->infinity]->y; + z = rp[p->infinity | q->infinity]->z; + + ap[0] = p; + ap[1] = q; + for (i=0; i<10; i++) + r->x[i] = ap[p->infinity]->x[i]; + for (i=0; i<10; i++) + r->y[i] = ap[p->infinity]->y[i]; + for (i=0; i<10; i++) + r->z[i] = ap[p->infinity]->z[i]; + r->infinity = ap[p->infinity]->infinity; + + /* U1 = X1*Z2^2 */ + sp_256_mont_sqr_10(t1, q->z, p256_mod, p256_mp_mod); + sp_256_mont_mul_10(t3, t1, q->z, p256_mod, p256_mp_mod); + sp_256_mont_mul_10(t1, t1, x, p256_mod, p256_mp_mod); + /* U2 = X2*Z1^2 */ + sp_256_mont_sqr_10(t2, z, p256_mod, p256_mp_mod); + sp_256_mont_mul_10(t4, t2, z, p256_mod, p256_mp_mod); + sp_256_mont_mul_10(t2, t2, q->x, p256_mod, p256_mp_mod); + /* S1 = Y1*Z2^3 */ + sp_256_mont_mul_10(t3, t3, y, p256_mod, p256_mp_mod); + /* S2 = Y2*Z1^3 */ + sp_256_mont_mul_10(t4, t4, q->y, p256_mod, p256_mp_mod); + /* H = U2 - U1 */ + sp_256_mont_sub_10(t2, t2, t1, p256_mod); + /* R = S2 - S1 */ + sp_256_mont_sub_10(t4, t4, t3, p256_mod); + /* Z3 = H*Z1*Z2 */ + sp_256_mont_mul_10(z, z, q->z, p256_mod, p256_mp_mod); + sp_256_mont_mul_10(z, z, t2, p256_mod, p256_mp_mod); + /* X3 = R^2 - H^3 - 2*U1*H^2 */ + sp_256_mont_sqr_10(x, t4, p256_mod, p256_mp_mod); + sp_256_mont_sqr_10(t5, t2, p256_mod, p256_mp_mod); + sp_256_mont_mul_10(y, t1, t5, p256_mod, p256_mp_mod); + sp_256_mont_mul_10(t5, t5, t2, p256_mod, p256_mp_mod); + sp_256_mont_sub_10(x, x, t5, p256_mod); + sp_256_mont_dbl_10(t1, y, p256_mod); + sp_256_mont_sub_10(x, x, t1, p256_mod); + /* Y3 = R*(U1*H^2 - X3) - S1*H^3 */ + sp_256_mont_sub_10(y, y, x, p256_mod); + sp_256_mont_mul_10(y, y, t4, p256_mod, p256_mp_mod); + sp_256_mont_mul_10(t5, t5, t3, p256_mod, p256_mp_mod); + sp_256_mont_sub_10(y, y, t5, p256_mod); + } +} + +/* Multiply the point by the scalar and return the result. + * If map is true then convert result to affine co-ordinates. + * + * r Resulting point. + * g Point to multiply. + * k Scalar to multiply by. + */ +static void sp_256_ecc_mulmod_10(sp_point* r, const sp_point* g, const sp_digit* k /*, int map*/) +{ + enum { map = 1 }; /* we always convert result to affine coordinates */ + sp_point td[3]; + sp_point* t[3]; + sp_digit tmp[2 * 10 * 5]; + sp_digit n; + int i; + int c, y; + + memset(td, 0, sizeof(td)); + + t[0] = &td[0]; + t[1] = &td[1]; + t[2] = &td[2]; + + /* t[0] = {0, 0, 1} * norm */ + t[0]->infinity = 1; + /* t[1] = {g->x, g->y, g->z} * norm */ + sp_256_mod_mul_norm_10(t[1]->x, g->x); + sp_256_mod_mul_norm_10(t[1]->y, g->y); + sp_256_mod_mul_norm_10(t[1]->z, g->z); + + i = 9; + c = 22; + n = k[i--] << (26 - c); + for (; ; c--) { + if (c == 0) { + if (i == -1) + break; + + n = k[i--]; + c = 26; + } + + y = (n >> 25) & 1; + n <<= 1; + + sp_256_proj_point_add_10(t[y^1], t[0], t[1], tmp); +///FIXME type (or rewrite - get rid of t[] array) + memcpy(t[2], (void*)(((size_t)t[0] & addr_mask[y^1]) + + ((size_t)t[1] & addr_mask[y])), + sizeof(sp_point)); + sp_256_proj_point_dbl_10(t[2], t[2], tmp); + memcpy((void*)(((size_t)t[0] & addr_mask[y^1]) + + ((size_t)t[1] & addr_mask[y])), t[2], + sizeof(sp_point)); + } + + if (map) + sp_256_map_10(r, t[0], tmp); + else + memcpy(r, t[0], sizeof(sp_point)); + + memset(tmp, 0, sizeof(tmp)); + memset(td, 0, sizeof(td)); +} + +/* Multiply the base point of P256 by the scalar and return the result. + * If map is true then convert result to affine co-ordinates. + * + * r Resulting point. + * k Scalar to multiply by. + */ +static void sp_256_ecc_mulmod_base_10(sp_point* r, sp_digit* k /*, int map*/) +{ + sp_256_ecc_mulmod_10(r, &p256_base, k /*, map*/); +} + +/* Multiply the point by the scalar and serialize the X ordinate. + * The number is 0 padded to maximum size on output. + * + * priv Scalar to multiply the point by. + * peerkey2x32 Point to multiply. + * out Buffer to hold X ordinate. + */ +static void sp_ecc_secret_gen_256(sp_digit priv[10], const uint8_t *peerkey2x32, uint8_t* out32) +{ + sp_point point[1]; + +#if FIXED_PEER_PUBKEY + memset((void*)peerkey32, 0x55, 64); +#endif + dump_hex("peerkey32 %s\n", peerkey2x32, 32); + dump_hex(" %s\n", peerkey2x32 + 32, 32); + + sp_256_point_from_bin2x32(point, peerkey2x32); + dump_hex("point->x %s\n", point->x, sizeof(point->x)); + dump_hex("point->y %s\n", point->y, sizeof(point->y)); + + sp_256_ecc_mulmod_10(point, point, priv); + + sp_256_to_bin(point->x, out32); + dump_hex("out32: %s\n", out32, 32); +} + +/* Generates a scalar that is in the range 1..order-1. + * + * rng Random number generator. + * k Scalar value. + */ +static void sp_256_ecc_gen_k_10(sp_digit k[10]) +{ +#define SIMPLIFY 1 +#if !SIMPLIFY + /* The order of the curve P256 minus 2. */ + static const sp_digit p256_order2[10] = { + 0x063254f,0x272b0bf,0x1e84f3b,0x2b69c5e,0x3bce6fa, + 0x3ffffff,0x3ffffff,0x00003ff,0x3ff0000,0x03fffff, + }; +#endif + uint8_t buf[32]; + + for (;;) { + tls_get_random(buf, sizeof(buf)); +#if FIXED_SECRET + memset(buf, 0x77, sizeof(buf)); +#endif + sp_256_from_bin(k, 10, buf, sizeof(buf)); +#if !SIMPLIFY + if (sp_256_cmp_10(k, p256_order2) < 0) + break; +#else + /* non-loopy version (and not needing p256_order2[]): + * if most-significant word seems that it can be larger + * than p256_order2, fix it up: + */ + if (k[9] >= 0x03fffff) + k[9] = 0x03ffffe; + break; +#endif + } + sp_256_add_one_10(k); +#undef SIMPLIFY +} + +/* Makes a random EC key pair. + * + * priv Generated private value. + * pubkey Generated public point. + */ +static void sp_ecc_make_key_256(sp_digit k[10], uint8_t *pubkey) +{ + sp_point point[1]; + + sp_256_ecc_gen_k_10(k); + sp_256_ecc_mulmod_base_10(point, k); + sp_256_to_bin(point->x, pubkey); + sp_256_to_bin(point->y, pubkey + 32); + + memset(point, 0, sizeof(point)); //paranoia +} + +void FAST_FUNC curve_P256_compute_pubkey_and_premaster( + uint8_t *pubkey, uint8_t *premaster32, + const uint8_t *peerkey2x32) +{ + sp_digit privkey[10]; + + sp_ecc_make_key_256(privkey, pubkey); + dump_hex("pubkey: %s\n", pubkey, 32); + dump_hex(" %s\n", pubkey + 32, 32); + + /* Combine our privkey and peerkey32 to generate premaster */ + sp_ecc_secret_gen_256(privkey, /*x,y:*/peerkey2x32, premaster32); + dump_hex("premaster: %s\n", premaster32, 32); +} -- cgit v1.2.3-55-g6feb From 6b69ab68b47d0933f8b4a1d7ed8460274a736a5f Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Mon, 26 Apr 2021 13:46:36 +0200 Subject: tls: make x25519 key generation code more similar to P256 function old new delta curve_x25519_compute_pubkey_and_premaster - 74 +74 tls_handshake 2146 2072 -74 ------------------------------------------------------------------------------ (add/remove: 1/0 grow/shrink: 0/1 up/down: 74/-74) Total: 0 bytes Signed-off-by: Denys Vlasenko --- networking/tls.c | 61 ++++++++++++++++++++++------------------------------- networking/tls.h | 5 ++++- networking/tls_fe.c | 23 +++++++++++++++++++- networking/tls_fe.h | 6 ------ 4 files changed, 51 insertions(+), 44 deletions(-) delete mode 100644 networking/tls_fe.h diff --git a/networking/tls.c b/networking/tls.c index cacd2e9ff..5566d7911 100644 --- a/networking/tls.c +++ b/networking/tls.c @@ -1534,7 +1534,7 @@ static void send_client_hello_and_alloc_hsd(tls_state_t *tls, const char *sni) 0x00,0x0a, //extension_type: "supported_groups" 0x00,0x06, //ext len 0x00,0x04, //list len - 0x00,0x17, //curve_secp256r1 + 0x00,0x17, //curve_secp256r1 (aka P256) //0x00,0x18, //curve_secp384r1 //0x00,0x19, //curve_secp521r1 0x00,0x1d, //curve_x25519 (RFC 7748) @@ -1890,7 +1890,7 @@ static void process_server_key(tls_state_t *tls, int len) tls->flags |= GOT_EC_CURVE_X25519; memcpy(tls->hsd->ecc_pub_key32, keybuf, 32); break; - case _0x03001741: //curve_secp256r1 + case _0x03001741: //curve_secp256r1 (aka P256) /* P256 point can be transmitted odd- or even-compressed * (first byte is 3 or 2) or uncompressed (4). */ @@ -1967,46 +1967,35 @@ static void send_client_key_exchange(tls_state_t *tls) record->key[1] = len & 0xff; len += 2; premaster_size = RSA_PREMASTER_SIZE; - } else /* ECDHE */ - if (tls->flags & GOT_EC_CURVE_X25519) { - /* ECDHE, curve x25519 */ - static const uint8_t basepoint9[CURVE25519_KEYSIZE] ALIGN8 = {9}; - uint8_t privkey[CURVE25519_KEYSIZE]; //[32] - - if (!(tls->flags & GOT_EC_KEY)) - bb_simple_error_msg_and_die("server did not provide EC key"); - - /* Generate random private key, see RFC 7748 */ - tls_get_random(privkey, sizeof(privkey)); - privkey[0] &= 0xf8; - privkey[CURVE25519_KEYSIZE-1] = ((privkey[CURVE25519_KEYSIZE-1] & 0x7f) | 0x40); - - /* Compute public key */ - curve25519(record->key + 1, privkey, basepoint9); - - /* Compute premaster using peer's public key */ - dbg("computing x25519_premaster\n"); - curve25519(premaster, privkey, tls->hsd->ecc_pub_key32); - - len = CURVE25519_KEYSIZE; - record->key[0] = len; - len++; - premaster_size = CURVE25519_KEYSIZE; } else { - /* ECDHE, curve P256 */ + /* ECDHE */ if (!(tls->flags & GOT_EC_KEY)) bb_simple_error_msg_and_die("server did not provide EC key"); - dbg("computing P256_premaster\n"); - curve_P256_compute_pubkey_and_premaster( - record->key + 2, premaster, - /*point:*/ tls->hsd->ecc_pub_key32 - ); - premaster_size = P256_KEYSIZE; - len = 1 + P256_KEYSIZE * 2; + if (tls->flags & GOT_EC_CURVE_X25519) { + /* ECDHE, curve x25519 */ + dbg("computing x25519_premaster\n"); + curve_x25519_compute_pubkey_and_premaster( + record->key + 1, premaster, + /*point:*/ tls->hsd->ecc_pub_key32 + ); + len = CURVE25519_KEYSIZE; + //record->key[0] = len; + //len++; + //premaster_size = CURVE25519_KEYSIZE; + } else { + /* ECDHE, curve P256 */ + dbg("computing P256_premaster\n"); + curve_P256_compute_pubkey_and_premaster( + record->key + 2, premaster, + /*point:*/ tls->hsd->ecc_pub_key32 + ); + record->key[1] = 4; /* "uncompressed point" */ + len = 1 + P256_KEYSIZE * 2; + } record->key[0] = len; - record->key[1] = 4; len++; + premaster_size = P256_KEYSIZE; // = CURVE25519_KEYSIZE = 32 } record->type = HANDSHAKE_CLIENT_KEY_EXCHANGE; diff --git a/networking/tls.h b/networking/tls.h index e1afb7ea8..154e9b2fb 100644 --- a/networking/tls.h +++ b/networking/tls.h @@ -105,12 +105,15 @@ void xorbuf_aligned_AES_BLOCK_SIZE(void* buf, const void* mask) FAST_FUNC; #include "tls_aes.h" #include "tls_aesgcm.h" #include "tls_rsa.h" -#include "tls_fe.h" #define EC_CURVE_KEYSIZE 32 #define P256_KEYSIZE 32 #define CURVE25519_KEYSIZE 32 +void curve_x25519_compute_pubkey_and_premaster( + uint8_t *pubkey, uint8_t *premaster, + const uint8_t *peerkey32) FAST_FUNC; + void curve_P256_compute_pubkey_and_premaster( uint8_t *pubkey, uint8_t *premaster, const uint8_t *peerkey32) FAST_FUNC; diff --git a/networking/tls_fe.c b/networking/tls_fe.c index f810e112a..3b3578c0d 100644 --- a/networking/tls_fe.c +++ b/networking/tls_fe.c @@ -544,7 +544,7 @@ static void xc_double(byte *x3, byte *z3, fe_mul_c(z3, x1sq, 4); } -void FAST_FUNC curve25519(byte *result, const byte *e, const byte *q) +static void curve25519(byte *result, const byte *e, const byte *q) { int i; @@ -599,3 +599,24 @@ void FAST_FUNC curve25519(byte *result, const byte *e, const byte *q) fe_mul__distinct(result, zm1, xm); fe_normalize(result); } + +/* interface to bbox's TLS code: */ + +void FAST_FUNC curve_x25519_compute_pubkey_and_premaster( + uint8_t *pubkey, uint8_t *premaster, + const uint8_t *peerkey32) +{ + static const uint8_t basepoint9[CURVE25519_KEYSIZE] ALIGN8 = {9}; + uint8_t privkey[CURVE25519_KEYSIZE]; //[32] + + /* Generate random private key, see RFC 7748 */ + tls_get_random(privkey, sizeof(privkey)); + privkey[0] &= 0xf8; + privkey[CURVE25519_KEYSIZE-1] = ((privkey[CURVE25519_KEYSIZE-1] & 0x7f) | 0x40); + + /* Compute public key */ + curve25519(pubkey, privkey, basepoint9); + + /* Compute premaster using peer's public key */ + curve25519(premaster, privkey, peerkey32); +} diff --git a/networking/tls_fe.h b/networking/tls_fe.h deleted file mode 100644 index 2859c9d2d..000000000 --- a/networking/tls_fe.h +++ /dev/null @@ -1,6 +0,0 @@ -/* - * Copyright (C) 2018 Denys Vlasenko - * - * Licensed under GPLv2, see file LICENSE in this source tree. - */ -void curve25519(uint8_t *result, const uint8_t *e, const uint8_t *q) FAST_FUNC; -- cgit v1.2.3-55-g6feb From 074b33bf16b8dc047a94d615c24f40d2ba9ead46 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Mon, 26 Apr 2021 14:33:38 +0200 Subject: tls: simplify sp_256_ecc_gen_k_10, cosmetic changes Signed-off-by: Denys Vlasenko --- networking/tls.h | 6 +- networking/tls_sp_c32.c | 184 +++++++++++++----------------------------------- 2 files changed, 52 insertions(+), 138 deletions(-) diff --git a/networking/tls.h b/networking/tls.h index 154e9b2fb..215e92b02 100644 --- a/networking/tls.h +++ b/networking/tls.h @@ -111,9 +111,9 @@ void xorbuf_aligned_AES_BLOCK_SIZE(void* buf, const void* mask) FAST_FUNC; #define CURVE25519_KEYSIZE 32 void curve_x25519_compute_pubkey_and_premaster( - uint8_t *pubkey, uint8_t *premaster, + uint8_t *pubkey32, uint8_t *premaster32, const uint8_t *peerkey32) FAST_FUNC; void curve_P256_compute_pubkey_and_premaster( - uint8_t *pubkey, uint8_t *premaster, - const uint8_t *peerkey32) FAST_FUNC; + uint8_t *pubkey2x32, uint8_t *premaster32, + const uint8_t *peerkey2x32) FAST_FUNC; diff --git a/networking/tls_sp_c32.c b/networking/tls_sp_c32.c index e7667de73..b4e14deac 100644 --- a/networking/tls_sp_c32.c +++ b/networking/tls_sp_c32.c @@ -57,7 +57,6 @@ typedef int32_t sp_digit; /* Implementation by Sean Parkinson. */ -/* Point structure to use. */ typedef struct sp_point { sp_digit x[2 * 10]; sp_digit y[2 * 10]; @@ -165,8 +164,6 @@ static void sp_256_point_from_bin2x32(sp_point* p, const uint8_t *bin2x32) /* Compare a with b in constant time. * - * a A single precision integer. - * b A single precision integer. * return -ve, 0 or +ve if a is less than, equal to or greater than b * respectively. */ @@ -181,8 +178,6 @@ static sp_digit sp_256_cmp_10(const sp_digit* a, const sp_digit* b) /* Compare two numbers to determine if they are equal. * - * a First number to compare. - * b Second number to compare. * return 1 when equal and 0 otherwise. */ static int sp_256_cmp_equal_10(const sp_digit* a, const sp_digit* b) @@ -198,10 +193,7 @@ static int sp_256_cmp_equal_10(const sp_digit* a, const sp_digit* b) #endif } -/* Normalize the values in each word to 26. - * - * a Array of sp_digit to normalize. - */ +/* Normalize the values in each word to 26 bits. */ static void sp_256_norm_10(sp_digit* a) { int i; @@ -211,12 +203,7 @@ static void sp_256_norm_10(sp_digit* a) } } -/* Add b to a into r. (r = a + b) - * - * r A single precision integer. - * a A single precision integer. - * b A single precision integer. - */ +/* Add b to a into r. (r = a + b) */ static void sp_256_add_10(sp_digit* r, const sp_digit* a, const sp_digit* b) { int i; @@ -226,11 +213,6 @@ static void sp_256_add_10(sp_digit* r, const sp_digit* a, const sp_digit* b) /* Conditionally add a and b using the mask m. * m is -1 to add and 0 when not. - * - * r A single precision number representing conditional add result. - * a A single precision number to add with. - * b A single precision number to add. - * m Mask value to apply. */ static void sp_256_cond_add_10(sp_digit* r, const sp_digit* a, const sp_digit* b, const sp_digit m) @@ -242,11 +224,6 @@ static void sp_256_cond_add_10(sp_digit* r, const sp_digit* a, /* Conditionally subtract b from a using the mask m. * m is -1 to subtract and 0 when not. - * - * r A single precision number representing condition subtract result. - * a A single precision number to subtract from. - * b A single precision number to subtract. - * m Mask value to apply. */ static void sp_256_cond_sub_10(sp_digit* r, const sp_digit* a, const sp_digit* b, const sp_digit m) @@ -256,23 +233,7 @@ static void sp_256_cond_sub_10(sp_digit* r, const sp_digit* a, r[i] = a[i] - (b[i] & m); } -/* Add 1 to a. (a = a + 1) - * - * r A single precision integer. - * a A single precision integer. - */ -static void sp_256_add_one_10(sp_digit* a) -{ - a[0]++; - sp_256_norm_10(a); -} - -/* Shift number left one bit. - * Bottom bit is lost. - * - * r Result of shift. - * a Number to shift. - */ +/* Shift number left one bit. Bottom bit is lost. */ static void sp_256_rshift1_10(sp_digit* r, sp_digit* a) { int i; @@ -381,14 +342,8 @@ static void sp_256_mod_mul_norm_10(sp_digit* r, const sp_digit* a) r[9] = (sp_digit)(t[7] >> 10); } -/* Mul a by scalar b and add into r. (r += a * b) - * - * r A single precision integer. - * a A single precision integer. - * b A scalar. - */ -static void sp_256_mul_add_10(sp_digit* r, const sp_digit* a, - const sp_digit b) +/* Mul a by scalar b and add into r. (r += a * b) */ +static void sp_256_mul_add_10(sp_digit* r, const sp_digit* a, sp_digit b) { int64_t tb = b; int64_t t = 0; @@ -402,12 +357,7 @@ static void sp_256_mul_add_10(sp_digit* r, const sp_digit* a, r[10] += t; } -/* Divide the number by 2 mod the modulus (prime). (r = a / 2 % m) - * - * r Result of division by 2. - * a Number to divide. - * m Modulus (prime). - */ +/* Divide the number by 2 mod the modulus (prime). (r = a / 2 % m) */ static void sp_256_div2_10(sp_digit* r, const sp_digit* a, const sp_digit* m) { sp_256_cond_add_10(r, a, m, 0 - (a[0] & 1)); @@ -415,11 +365,7 @@ static void sp_256_div2_10(sp_digit* r, const sp_digit* a, const sp_digit* m) sp_256_rshift1_10(r, r); } -/* Shift the result in the high 256 bits down to the bottom. - * - * r A single precision number. - * a A single precision number. - */ +/* Shift the result in the high 256 bits down to the bottom. */ static void sp_256_mont_shift_10(sp_digit* r, const sp_digit* a) { int i; @@ -438,13 +384,7 @@ static void sp_256_mont_shift_10(sp_digit* r, const sp_digit* a) memset(&r[10], 0, sizeof(*r) * 10); } -/* Add two Montgomery form numbers (r = a + b % m). - * - * r Result of addition. - * a First number to add in Montogmery form. - * b Second number to add in Montogmery form. - * m Modulus (prime). - */ +/* Add two Montgomery form numbers (r = a + b % m) */ static void sp_256_mont_add_10(sp_digit* r, const sp_digit* a, const sp_digit* b, const sp_digit* m) { @@ -454,12 +394,7 @@ static void sp_256_mont_add_10(sp_digit* r, const sp_digit* a, const sp_digit* b sp_256_norm_10(r); } -/* Double a Montgomery form number (r = a + a % m). - * - * r Result of doubling. - * a Number to double in Montogmery form. - * m Modulus (prime). - */ +/* Double a Montgomery form number (r = a + a % m) */ static void sp_256_mont_dbl_10(sp_digit* r, const sp_digit* a, const sp_digit* m) { sp_256_add_10(r, a, a); @@ -468,12 +403,7 @@ static void sp_256_mont_dbl_10(sp_digit* r, const sp_digit* a, const sp_digit* m sp_256_norm_10(r); } -/* Triple a Montgomery form number (r = a + a + a % m). - * - * r Result of Tripling. - * a Number to triple in Montogmery form. - * m Modulus (prime). - */ +/* Triple a Montgomery form number (r = a + a + a % m) */ static void sp_256_mont_tpl_10(sp_digit* r, const sp_digit* a, const sp_digit* m) { sp_256_add_10(r, a, a); @@ -486,27 +416,15 @@ static void sp_256_mont_tpl_10(sp_digit* r, const sp_digit* a, const sp_digit* m sp_256_norm_10(r); } -/* Sub b from a into r. (r = a - b) - * - * r A single precision integer. - * a A single precision integer. - * b A single precision integer. - */ -static void sp_256_sub_10(sp_digit* r, const sp_digit* a, - const sp_digit* b) +/* Sub b from a into r. (r = a - b) */ +static void sp_256_sub_10(sp_digit* r, const sp_digit* a, const sp_digit* b) { int i; for (i = 0; i < 10; i++) r[i] = a[i] - b[i]; } -/* Subtract two Montgomery form numbers (r = a - b % m). - * - * r Result of subtration. - * a Number to subtract from in Montogmery form. - * b Number to subtract with in Montogmery form. - * m Modulus (prime). - */ +/* Subtract two Montgomery form numbers (r = a - b % m) */ static void sp_256_mont_sub_10(sp_digit* r, const sp_digit* a, const sp_digit* b, const sp_digit* m) { @@ -554,12 +472,7 @@ static void sp_256_mont_reduce_10(sp_digit* a, const sp_digit* m, sp_digit mp) sp_256_norm_10(a); } -/* Multiply a and b into r. (r = a * b) - * - * r A single precision integer. - * a A single precision integer. - * b A single precision integer. - */ +/* Multiply a and b into r. (r = a * b) */ static void sp_256_mul_10(sp_digit* r, const sp_digit* a, const sp_digit* b) { int i, j, k; @@ -600,11 +513,7 @@ static void sp_256_mont_mul_10(sp_digit* r, const sp_digit* a, const sp_digit* b sp_256_mont_reduce_10(r, m, mp); } -/* Square a and put result in r. (r = a * a) - * - * r A single precision integer. - * a A single precision integer. - */ +/* Square a and put result in r. (r = a * a) */ static void sp_256_sqr_10(sp_digit* r, const sp_digit* a) { int i, j, k; @@ -937,8 +846,8 @@ static void sp_256_ecc_mulmod_10(sp_point* r, const sp_point* g, const sp_digit* else memcpy(r, t[0], sizeof(sp_point)); - memset(tmp, 0, sizeof(tmp)); - memset(td, 0, sizeof(td)); + memset(tmp, 0, sizeof(tmp)); //paranoia + memset(td, 0, sizeof(td)); //paranoia } /* Multiply the base point of P256 by the scalar and return the result. @@ -956,20 +865,20 @@ static void sp_256_ecc_mulmod_base_10(sp_point* r, sp_digit* k /*, int map*/) * The number is 0 padded to maximum size on output. * * priv Scalar to multiply the point by. - * peerkey2x32 Point to multiply. - * out Buffer to hold X ordinate. + * pub2x32 Point to multiply. + * out32 Buffer to hold X ordinate. */ -static void sp_ecc_secret_gen_256(sp_digit priv[10], const uint8_t *peerkey2x32, uint8_t* out32) +static void sp_ecc_secret_gen_256(sp_digit priv[10], const uint8_t *pub2x32, uint8_t* out32) { sp_point point[1]; #if FIXED_PEER_PUBKEY - memset((void*)peerkey32, 0x55, 64); + memset((void*)pub2x32, 0x55, 64); #endif - dump_hex("peerkey32 %s\n", peerkey2x32, 32); - dump_hex(" %s\n", peerkey2x32 + 32, 32); + dump_hex("peerkey %s\n", pub2x32, 32); /* in TLS, this is peer's public key */ + dump_hex(" %s\n", pub2x32 + 32, 32); - sp_256_point_from_bin2x32(point, peerkey2x32); + sp_256_point_from_bin2x32(point, pub2x32); dump_hex("point->x %s\n", point->x, sizeof(point->x)); dump_hex("point->y %s\n", point->y, sizeof(point->y)); @@ -979,14 +888,18 @@ static void sp_ecc_secret_gen_256(sp_digit priv[10], const uint8_t *peerkey2x32, dump_hex("out32: %s\n", out32, 32); } -/* Generates a scalar that is in the range 1..order-1. - * - * rng Random number generator. - * k Scalar value. - */ +/* Generates a scalar that is in the range 1..order-1. */ +#define SIMPLIFY 1 +/* Add 1 to a. (a = a + 1) */ +#if !SIMPLIFY +static void sp_256_add_one_10(sp_digit* a) +{ + a[0]++; + sp_256_norm_10(a); +} +#endif static void sp_256_ecc_gen_k_10(sp_digit k[10]) { -#define SIMPLIFY 1 #if !SIMPLIFY /* The order of the curve P256 minus 2. */ static const sp_digit p256_order2[10] = { @@ -1007,7 +920,7 @@ static void sp_256_ecc_gen_k_10(sp_digit k[10]) break; #else /* non-loopy version (and not needing p256_order2[]): - * if most-significant word seems that it can be larger + * if most-significant word seems that k can be larger * than p256_order2, fix it up: */ if (k[9] >= 0x03fffff) @@ -1015,21 +928,22 @@ static void sp_256_ecc_gen_k_10(sp_digit k[10]) break; #endif } +#if !SIMPLIFY sp_256_add_one_10(k); +#else + if (k[0] == 0) + k[0] = 1; +#endif #undef SIMPLIFY } -/* Makes a random EC key pair. - * - * priv Generated private value. - * pubkey Generated public point. - */ -static void sp_ecc_make_key_256(sp_digit k[10], uint8_t *pubkey) +/* Makes a random EC key pair. */ +static void sp_ecc_make_key_256(sp_digit privkey[10], uint8_t *pubkey) { sp_point point[1]; - sp_256_ecc_gen_k_10(k); - sp_256_ecc_mulmod_base_10(point, k); + sp_256_ecc_gen_k_10(privkey); + sp_256_ecc_mulmod_base_10(point, privkey); sp_256_to_bin(point->x, pubkey); sp_256_to_bin(point->y, pubkey + 32); @@ -1037,16 +951,16 @@ static void sp_ecc_make_key_256(sp_digit k[10], uint8_t *pubkey) } void FAST_FUNC curve_P256_compute_pubkey_and_premaster( - uint8_t *pubkey, uint8_t *premaster32, + uint8_t *pubkey2x32, uint8_t *premaster32, const uint8_t *peerkey2x32) { sp_digit privkey[10]; - sp_ecc_make_key_256(privkey, pubkey); - dump_hex("pubkey: %s\n", pubkey, 32); - dump_hex(" %s\n", pubkey + 32, 32); + sp_ecc_make_key_256(privkey, pubkey2x32); + dump_hex("pubkey: %s\n", pubkey2x32, 32); + dump_hex(" %s\n", pubkey2x32 + 32, 32); - /* Combine our privkey and peerkey32 to generate premaster */ + /* Combine our privkey and peer's public key to generate premaster */ sp_ecc_secret_gen_256(privkey, /*x,y:*/peerkey2x32, premaster32); dump_hex("premaster: %s\n", premaster32, 32); } -- cgit v1.2.3-55-g6feb From 166363f47d74a73a0a3ad1ebbb5aae00752ab8f7 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Mon, 26 Apr 2021 14:40:21 +0200 Subject: tls: get rid of address obfuscation trick in P256 function old new delta addr_mask 8 - -8 sp_256_ecc_mulmod_10 1363 1330 -33 ------------------------------------------------------------------------------ (add/remove: 0/1 grow/shrink: 0/1 up/down: 0/-41) Total: -41 bytes Signed-off-by: Denys Vlasenko --- networking/tls_sp_c32.c | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/networking/tls_sp_c32.c b/networking/tls_sp_c32.c index b4e14deac..87d44d5e0 100644 --- a/networking/tls_sp_c32.c +++ b/networking/tls_sp_c32.c @@ -72,9 +72,6 @@ static const sp_digit p256_mod[10] = { #define p256_mp_mod ((sp_digit)0x000001) -/* Mask for address to obfuscate which of the two address will be used. */ -static const size_t addr_mask[2] = { 0, (size_t)-1 }; - /* The base point of curve P256. */ static const sp_point p256_base = { /* X ordinate */ @@ -831,14 +828,9 @@ static void sp_256_ecc_mulmod_10(sp_point* r, const sp_point* g, const sp_digit* n <<= 1; sp_256_proj_point_add_10(t[y^1], t[0], t[1], tmp); -///FIXME type (or rewrite - get rid of t[] array) - memcpy(t[2], (void*)(((size_t)t[0] & addr_mask[y^1]) + - ((size_t)t[1] & addr_mask[y])), - sizeof(sp_point)); + memcpy(t[2], t[y], sizeof(sp_point)); sp_256_proj_point_dbl_10(t[2], t[2], tmp); - memcpy((void*)(((size_t)t[0] & addr_mask[y^1]) + - ((size_t)t[1] & addr_mask[y])), t[2], - sizeof(sp_point)); + memcpy(t[y], t[2], sizeof(sp_point)); } if (map) -- cgit v1.2.3-55-g6feb From 03ab2a90bbd5970fabe50fcd510730e5e088b923 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Mon, 26 Apr 2021 14:55:46 +0200 Subject: tls: simplify array manipulations in sp_256_ecc_mulmod_10 Signed-off-by: Denys Vlasenko --- networking/tls_sp_c32.c | 35 +++++++++++++++++------------------ 1 file changed, 17 insertions(+), 18 deletions(-) diff --git a/networking/tls_sp_c32.c b/networking/tls_sp_c32.c index 87d44d5e0..d3bb36a39 100644 --- a/networking/tls_sp_c32.c +++ b/networking/tls_sp_c32.c @@ -788,29 +788,25 @@ static void sp_256_proj_point_add_10(sp_point* r, sp_point* p, sp_point* q, * r Resulting point. * g Point to multiply. * k Scalar to multiply by. + * map Indicates whether to convert result to affine. */ static void sp_256_ecc_mulmod_10(sp_point* r, const sp_point* g, const sp_digit* k /*, int map*/) { enum { map = 1 }; /* we always convert result to affine coordinates */ - sp_point td[3]; - sp_point* t[3]; + sp_point t[3]; sp_digit tmp[2 * 10 * 5]; sp_digit n; int i; int c, y; - memset(td, 0, sizeof(td)); - - t[0] = &td[0]; - t[1] = &td[1]; - t[2] = &td[2]; + memset(t, 0, sizeof(t)); /* t[0] = {0, 0, 1} * norm */ - t[0]->infinity = 1; + t[0].infinity = 1; /* t[1] = {g->x, g->y, g->z} * norm */ - sp_256_mod_mul_norm_10(t[1]->x, g->x); - sp_256_mod_mul_norm_10(t[1]->y, g->y); - sp_256_mod_mul_norm_10(t[1]->z, g->z); + sp_256_mod_mul_norm_10(t[1].x, g->x); + sp_256_mod_mul_norm_10(t[1].y, g->y); + sp_256_mod_mul_norm_10(t[1].z, g->z); i = 9; c = 22; @@ -827,19 +823,21 @@ static void sp_256_ecc_mulmod_10(sp_point* r, const sp_point* g, const sp_digit* y = (n >> 25) & 1; n <<= 1; - sp_256_proj_point_add_10(t[y^1], t[0], t[1], tmp); - memcpy(t[2], t[y], sizeof(sp_point)); - sp_256_proj_point_dbl_10(t[2], t[2], tmp); - memcpy(t[y], t[2], sizeof(sp_point)); +//FIXME: what's "tmp" and why do we pass it down? +//is it scratch space for "sensitive" data, to be memset(0) after we are done? + sp_256_proj_point_add_10(&t[y^1], &t[0], &t[1], tmp); + memcpy(&t[2], &t[y], sizeof(sp_point)); + sp_256_proj_point_dbl_10(&t[2], &t[2], tmp); + memcpy(&t[y], &t[2], sizeof(sp_point)); } if (map) - sp_256_map_10(r, t[0], tmp); + sp_256_map_10(r, &t[0], tmp); else - memcpy(r, t[0], sizeof(sp_point)); + memcpy(r, &t[0], sizeof(sp_point)); memset(tmp, 0, sizeof(tmp)); //paranoia - memset(td, 0, sizeof(td)); //paranoia + memset(t, 0, sizeof(t)); //paranoia } /* Multiply the base point of P256 by the scalar and return the result. @@ -847,6 +845,7 @@ static void sp_256_ecc_mulmod_10(sp_point* r, const sp_point* g, const sp_digit* * * r Resulting point. * k Scalar to multiply by. + * map Indicates whether to convert result to affine. */ static void sp_256_ecc_mulmod_base_10(sp_point* r, sp_digit* k /*, int map*/) { -- cgit v1.2.3-55-g6feb From 4d3a5c135cfeab5b462c03b8269a99682d71b4af Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Mon, 26 Apr 2021 15:21:38 +0200 Subject: tls: simplify sp_256_proj_point_dbl_10 function old new delta sp_256_proj_point_dbl_10 490 435 -55 Signed-off-by: Denys Vlasenko --- networking/tls_sp_c32.c | 58 +++++++++++++++++++------------------------------ 1 file changed, 22 insertions(+), 36 deletions(-) diff --git a/networking/tls_sp_c32.c b/networking/tls_sp_c32.c index d3bb36a39..ffcb83dcc 100644 --- a/networking/tls_sp_c32.c +++ b/networking/tls_sp_c32.c @@ -626,68 +626,54 @@ static void sp_256_map_10(sp_point* r, sp_point* p, sp_digit* t) */ static void sp_256_proj_point_dbl_10(sp_point* r, sp_point* p, sp_digit* t) { - sp_point *rp[2]; sp_point tp; sp_digit* t1 = t; sp_digit* t2 = t + 2*10; - sp_digit* x; - sp_digit* y; - sp_digit* z; - int i; - /* When infinity don't double point passed in - constant time. */ - rp[0] = r; - rp[1] = &tp; - x = rp[p->infinity]->x; - y = rp[p->infinity]->y; - z = rp[p->infinity]->z; - /* Put point to double into result - good for infinity. */ - if (r != p) { - for (i = 0; i < 10; i++) - r->x[i] = p->x[i]; - for (i = 0; i < 10; i++) - r->y[i] = p->y[i]; - for (i = 0; i < 10; i++) - r->z[i] = p->z[i]; - r->infinity = p->infinity; - } + /* Put point to double into result */ + if (r != p) + *r = *p; /* struct copy */ + if (r->infinity) { + /* If infinity, don't double (work on dummy value) */ + r = &tp; + } /* T1 = Z * Z */ - sp_256_mont_sqr_10(t1, z, p256_mod, p256_mp_mod); + sp_256_mont_sqr_10(t1, r->z, p256_mod, p256_mp_mod); /* Z = Y * Z */ - sp_256_mont_mul_10(z, y, z, p256_mod, p256_mp_mod); + sp_256_mont_mul_10(r->z, r->y, r->z, p256_mod, p256_mp_mod); /* Z = 2Z */ - sp_256_mont_dbl_10(z, z, p256_mod); + sp_256_mont_dbl_10(r->z, r->z, p256_mod); /* T2 = X - T1 */ - sp_256_mont_sub_10(t2, x, t1, p256_mod); + sp_256_mont_sub_10(t2, r->x, t1, p256_mod); /* T1 = X + T1 */ - sp_256_mont_add_10(t1, x, t1, p256_mod); + sp_256_mont_add_10(t1, r->x, t1, p256_mod); /* T2 = T1 * T2 */ sp_256_mont_mul_10(t2, t1, t2, p256_mod, p256_mp_mod); /* T1 = 3T2 */ sp_256_mont_tpl_10(t1, t2, p256_mod); /* Y = 2Y */ - sp_256_mont_dbl_10(y, y, p256_mod); + sp_256_mont_dbl_10(r->y, r->y, p256_mod); /* Y = Y * Y */ - sp_256_mont_sqr_10(y, y, p256_mod, p256_mp_mod); + sp_256_mont_sqr_10(r->y, r->y, p256_mod, p256_mp_mod); /* T2 = Y * Y */ - sp_256_mont_sqr_10(t2, y, p256_mod, p256_mp_mod); + sp_256_mont_sqr_10(t2, r->y, p256_mod, p256_mp_mod); /* T2 = T2/2 */ sp_256_div2_10(t2, t2, p256_mod); /* Y = Y * X */ - sp_256_mont_mul_10(y, y, x, p256_mod, p256_mp_mod); + sp_256_mont_mul_10(r->y, r->y, r->x, p256_mod, p256_mp_mod); /* X = T1 * T1 */ - sp_256_mont_mul_10(x, t1, t1, p256_mod, p256_mp_mod); + sp_256_mont_mul_10(r->x, t1, t1, p256_mod, p256_mp_mod); /* X = X - Y */ - sp_256_mont_sub_10(x, x, y, p256_mod); + sp_256_mont_sub_10(r->x, r->x, r->y, p256_mod); /* X = X - Y */ - sp_256_mont_sub_10(x, x, y, p256_mod); + sp_256_mont_sub_10(r->x, r->x, r->y, p256_mod); /* Y = Y - X */ - sp_256_mont_sub_10(y, y, x, p256_mod); + sp_256_mont_sub_10(r->y, r->y, r->x, p256_mod); /* Y = Y * T1 */ - sp_256_mont_mul_10(y, y, t1, p256_mod, p256_mp_mod); + sp_256_mont_mul_10(r->y, r->y, t1, p256_mod, p256_mp_mod); /* Y = Y - T2 */ - sp_256_mont_sub_10(y, y, t2, p256_mod); + sp_256_mont_sub_10(r->y, r->y, t2, p256_mod); } /* Add two Montgomery form projective points. -- cgit v1.2.3-55-g6feb From b3b1713a58dab938524e263426004ab0aca112a8 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Mon, 26 Apr 2021 16:53:53 +0200 Subject: tls: in P256 replace constant-time compares with usual ones function old new delta sp_256_cmp_10 - 24 +24 sp_256_ecc_mulmod_10 1332 1329 -3 sp_256_cmp_equal_10 30 - -30 static.sp_256_cmp_10 43 - -43 ------------------------------------------------------------------------------ (add/remove: 1/2 grow/shrink: 0/1 up/down: 24/-76) Total: -52 bytes Signed-off-by: Denys Vlasenko --- networking/tls_sp_c32.c | 23 +++++++++-------------- 1 file changed, 9 insertions(+), 14 deletions(-) diff --git a/networking/tls_sp_c32.c b/networking/tls_sp_c32.c index ffcb83dcc..c151eea27 100644 --- a/networking/tls_sp_c32.c +++ b/networking/tls_sp_c32.c @@ -159,17 +159,20 @@ static void sp_256_point_from_bin2x32(sp_point* p, const uint8_t *bin2x32) p->z[0] = 1; } -/* Compare a with b in constant time. +/* Compare a with b. * * return -ve, 0 or +ve if a is less than, equal to or greater than b * respectively. */ static sp_digit sp_256_cmp_10(const sp_digit* a, const sp_digit* b) { - sp_digit r = 0; + sp_digit r; int i; - for (i = 9; i >= 0; i--) - r |= (a[i] - b[i]) & (0 - !r); + for (i = 9; i >= 0; i--) { + r = a[i] - b[i]; + if (r != 0) + break; + } return r; } @@ -179,15 +182,7 @@ static sp_digit sp_256_cmp_10(const sp_digit* a, const sp_digit* b) */ static int sp_256_cmp_equal_10(const sp_digit* a, const sp_digit* b) { -#if 1 - sp_digit r = 0; - int i; - for (i = 0; i < 10; i++) - r |= (a[i] ^ b[i]); - return r == 0; -#else return sp_256_cmp_10(a, b) == 0; -#endif } /* Normalize the values in each word to 26 bits. */ @@ -710,8 +705,8 @@ static void sp_256_proj_point_add_10(sp_point* r, sp_point* p, sp_point* q, sp_256_sub_10(t1, p256_mod, q->y); sp_256_norm_10(t1); if (sp_256_cmp_equal_10(p->x, q->x) - & sp_256_cmp_equal_10(p->z, q->z) - & (sp_256_cmp_equal_10(p->y, q->y) | sp_256_cmp_equal_10(p->y, t1)) + && sp_256_cmp_equal_10(p->z, q->z) + && (sp_256_cmp_equal_10(p->y, q->y) || sp_256_cmp_equal_10(p->y, t1)) ) { sp_256_proj_point_dbl_10(r, p, t); } -- cgit v1.2.3-55-g6feb From 772e18775e0e1db2392dcbea970d5729018437e8 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Mon, 26 Apr 2021 17:25:27 +0200 Subject: tls: shrink sp_256_proj_point_dbl_10 function old new delta sp_256_ecc_mulmod_10 1329 1300 -29 Signed-off-by: Denys Vlasenko --- networking/tls_sp_c32.c | 61 +++++++++++++++++++------------------------------ 1 file changed, 24 insertions(+), 37 deletions(-) diff --git a/networking/tls_sp_c32.c b/networking/tls_sp_c32.c index c151eea27..70e20aa86 100644 --- a/networking/tls_sp_c32.c +++ b/networking/tls_sp_c32.c @@ -681,18 +681,11 @@ static void sp_256_proj_point_dbl_10(sp_point* r, sp_point* p, sp_digit* t) static void sp_256_proj_point_add_10(sp_point* r, sp_point* p, sp_point* q, sp_digit* t) { - sp_point *ap[2]; - sp_point *rp[2]; - sp_point tp; sp_digit* t1 = t; sp_digit* t2 = t + 2*10; sp_digit* t3 = t + 4*10; sp_digit* t4 = t + 6*10; sp_digit* t5 = t + 8*10; - sp_digit* x; - sp_digit* y; - sp_digit* z; - int i; /* Ensure only the first point is the same as the result. */ if (q == r) { @@ -711,33 +704,27 @@ static void sp_256_proj_point_add_10(sp_point* r, sp_point* p, sp_point* q, sp_256_proj_point_dbl_10(r, p, t); } else { - rp[0] = r; - rp[1] = &tp; - memset(&tp, 0, sizeof(tp)); - x = rp[p->infinity | q->infinity]->x; - y = rp[p->infinity | q->infinity]->y; - z = rp[p->infinity | q->infinity]->z; - - ap[0] = p; - ap[1] = q; - for (i=0; i<10; i++) - r->x[i] = ap[p->infinity]->x[i]; - for (i=0; i<10; i++) - r->y[i] = ap[p->infinity]->y[i]; - for (i=0; i<10; i++) - r->z[i] = ap[p->infinity]->z[i]; - r->infinity = ap[p->infinity]->infinity; + sp_point tp; + sp_point *v; + + v = r; + if (p->infinity | q->infinity) { + memset(&tp, 0, sizeof(tp)); + v = &tp; + } + + *r = p->infinity ? *q : *p; /* struct copy */ /* U1 = X1*Z2^2 */ sp_256_mont_sqr_10(t1, q->z, p256_mod, p256_mp_mod); sp_256_mont_mul_10(t3, t1, q->z, p256_mod, p256_mp_mod); - sp_256_mont_mul_10(t1, t1, x, p256_mod, p256_mp_mod); + sp_256_mont_mul_10(t1, t1, v->x, p256_mod, p256_mp_mod); /* U2 = X2*Z1^2 */ - sp_256_mont_sqr_10(t2, z, p256_mod, p256_mp_mod); - sp_256_mont_mul_10(t4, t2, z, p256_mod, p256_mp_mod); + sp_256_mont_sqr_10(t2, v->z, p256_mod, p256_mp_mod); + sp_256_mont_mul_10(t4, t2, v->z, p256_mod, p256_mp_mod); sp_256_mont_mul_10(t2, t2, q->x, p256_mod, p256_mp_mod); /* S1 = Y1*Z2^3 */ - sp_256_mont_mul_10(t3, t3, y, p256_mod, p256_mp_mod); + sp_256_mont_mul_10(t3, t3, v->y, p256_mod, p256_mp_mod); /* S2 = Y2*Z1^3 */ sp_256_mont_mul_10(t4, t4, q->y, p256_mod, p256_mp_mod); /* H = U2 - U1 */ @@ -745,21 +732,21 @@ static void sp_256_proj_point_add_10(sp_point* r, sp_point* p, sp_point* q, /* R = S2 - S1 */ sp_256_mont_sub_10(t4, t4, t3, p256_mod); /* Z3 = H*Z1*Z2 */ - sp_256_mont_mul_10(z, z, q->z, p256_mod, p256_mp_mod); - sp_256_mont_mul_10(z, z, t2, p256_mod, p256_mp_mod); + sp_256_mont_mul_10(v->z, v->z, q->z, p256_mod, p256_mp_mod); + sp_256_mont_mul_10(v->z, v->z, t2, p256_mod, p256_mp_mod); /* X3 = R^2 - H^3 - 2*U1*H^2 */ - sp_256_mont_sqr_10(x, t4, p256_mod, p256_mp_mod); + sp_256_mont_sqr_10(v->x, t4, p256_mod, p256_mp_mod); sp_256_mont_sqr_10(t5, t2, p256_mod, p256_mp_mod); - sp_256_mont_mul_10(y, t1, t5, p256_mod, p256_mp_mod); + sp_256_mont_mul_10(v->y, t1, t5, p256_mod, p256_mp_mod); sp_256_mont_mul_10(t5, t5, t2, p256_mod, p256_mp_mod); - sp_256_mont_sub_10(x, x, t5, p256_mod); - sp_256_mont_dbl_10(t1, y, p256_mod); - sp_256_mont_sub_10(x, x, t1, p256_mod); + sp_256_mont_sub_10(v->x, v->x, t5, p256_mod); + sp_256_mont_dbl_10(t1, v->y, p256_mod); + sp_256_mont_sub_10(v->x, v->x, t1, p256_mod); /* Y3 = R*(U1*H^2 - X3) - S1*H^3 */ - sp_256_mont_sub_10(y, y, x, p256_mod); - sp_256_mont_mul_10(y, y, t4, p256_mod, p256_mp_mod); + sp_256_mont_sub_10(v->y, v->y, v->x, p256_mod); + sp_256_mont_mul_10(v->y, v->y, t4, p256_mod, p256_mp_mod); sp_256_mont_mul_10(t5, t5, t3, p256_mod, p256_mp_mod); - sp_256_mont_sub_10(y, y, t5, p256_mod); + sp_256_mont_sub_10(v->y, v->y, t5, p256_mod); } } -- cgit v1.2.3-55-g6feb From 6381f3d4f6d9ac111c2be7cfba041e8b7a28f9f9 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Mon, 26 Apr 2021 17:41:43 +0200 Subject: tls: stop passing temporary buffer address in P256 code function old new delta sp_256_proj_point_dbl_10 435 453 +18 sp_256_ecc_mulmod_10 1300 1237 -63 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 1/1 up/down: 18/-63) Total: -45 bytes Signed-off-by: Denys Vlasenko --- networking/tls_sp_c32.c | 61 +++++++++++++++++++++---------------------------- 1 file changed, 26 insertions(+), 35 deletions(-) diff --git a/networking/tls_sp_c32.c b/networking/tls_sp_c32.c index 70e20aa86..c71f716d6 100644 --- a/networking/tls_sp_c32.c +++ b/networking/tls_sp_c32.c @@ -170,8 +170,8 @@ static sp_digit sp_256_cmp_10(const sp_digit* a, const sp_digit* b) int i; for (i = 9; i >= 0; i--) { r = a[i] - b[i]; - if (r != 0) - break; + if (r != 0) + break; } return r; } @@ -553,16 +553,15 @@ static void sp_256_mont_sqr_10(sp_digit* r, const sp_digit* a, const sp_digit* m * * r Inverse result. * a Number to invert. - * td Temporary data. */ /* Mod-2 for the P256 curve. */ static const uint32_t p256_mod_2[8] = { - 0xfffffffd,0xffffffff,0xffffffff,0x00000000, - 0x00000000,0x00000000,0x00000001,0xffffffff, + 0xfffffffd,0xffffffff,0xffffffff,0x00000000, + 0x00000000,0x00000000,0x00000001,0xffffffff, }; -static void sp_256_mont_inv_10(sp_digit* r, sp_digit* a, sp_digit* td) +static void sp_256_mont_inv_10(sp_digit* r, sp_digit* a) { - sp_digit* t = td; + sp_digit t[2*10]; //can be just [10]? int i; memcpy(t, a, sizeof(sp_digit) * 10); @@ -578,15 +577,14 @@ static void sp_256_mont_inv_10(sp_digit* r, sp_digit* a, sp_digit* td) * * r Resulting affine co-ordinate point. * p Montgomery form projective co-ordinate point. - * t Temporary ordinate data. */ -static void sp_256_map_10(sp_point* r, sp_point* p, sp_digit* t) +static void sp_256_map_10(sp_point* r, sp_point* p) { - sp_digit* t1 = t; - sp_digit* t2 = t + 2*10; + sp_digit t1[2*10]; + sp_digit t2[2*10]; int32_t n; - sp_256_mont_inv_10(t1, p->z, t + 2*10); + sp_256_mont_inv_10(t1, p->z); sp_256_mont_sqr_10(t2, t1, p256_mod, p256_mp_mod); sp_256_mont_mul_10(t1, t2, t1, p256_mod, p256_mp_mod); @@ -617,21 +615,20 @@ static void sp_256_map_10(sp_point* r, sp_point* p, sp_digit* t) * * r Result of doubling point. * p Point to double. - * t Temporary ordinate data. */ -static void sp_256_proj_point_dbl_10(sp_point* r, sp_point* p, sp_digit* t) +static void sp_256_proj_point_dbl_10(sp_point* r, sp_point* p) { sp_point tp; - sp_digit* t1 = t; - sp_digit* t2 = t + 2*10; + sp_digit t1[2*10]; + sp_digit t2[2*10]; /* Put point to double into result */ if (r != p) *r = *p; /* struct copy */ if (r->infinity) { - /* If infinity, don't double (work on dummy value) */ - r = &tp; + /* If infinity, don't double (work on dummy value) */ + r = &tp; } /* T1 = Z * Z */ sp_256_mont_sqr_10(t1, r->z, p256_mod, p256_mp_mod); @@ -676,16 +673,14 @@ static void sp_256_proj_point_dbl_10(sp_point* r, sp_point* p, sp_digit* t) * r Result of addition. * p Frist point to add. * q Second point to add. - * t Temporary ordinate data. */ -static void sp_256_proj_point_add_10(sp_point* r, sp_point* p, sp_point* q, - sp_digit* t) +static void sp_256_proj_point_add_10(sp_point* r, sp_point* p, sp_point* q) { - sp_digit* t1 = t; - sp_digit* t2 = t + 2*10; - sp_digit* t3 = t + 4*10; - sp_digit* t4 = t + 6*10; - sp_digit* t5 = t + 8*10; + sp_digit t1[2*10]; + sp_digit t2[2*10]; + sp_digit t3[2*10]; + sp_digit t4[2*10]; + sp_digit t5[2*10]; /* Ensure only the first point is the same as the result. */ if (q == r) { @@ -701,7 +696,7 @@ static void sp_256_proj_point_add_10(sp_point* r, sp_point* p, sp_point* q, && sp_256_cmp_equal_10(p->z, q->z) && (sp_256_cmp_equal_10(p->y, q->y) || sp_256_cmp_equal_10(p->y, t1)) ) { - sp_256_proj_point_dbl_10(r, p, t); + sp_256_proj_point_dbl_10(r, p); } else { sp_point tp; @@ -762,7 +757,6 @@ static void sp_256_ecc_mulmod_10(sp_point* r, const sp_point* g, const sp_digit* { enum { map = 1 }; /* we always convert result to affine coordinates */ sp_point t[3]; - sp_digit tmp[2 * 10 * 5]; sp_digit n; int i; int c, y; @@ -791,20 +785,17 @@ static void sp_256_ecc_mulmod_10(sp_point* r, const sp_point* g, const sp_digit* y = (n >> 25) & 1; n <<= 1; -//FIXME: what's "tmp" and why do we pass it down? -//is it scratch space for "sensitive" data, to be memset(0) after we are done? - sp_256_proj_point_add_10(&t[y^1], &t[0], &t[1], tmp); + sp_256_proj_point_add_10(&t[y^1], &t[0], &t[1]); memcpy(&t[2], &t[y], sizeof(sp_point)); - sp_256_proj_point_dbl_10(&t[2], &t[2], tmp); + sp_256_proj_point_dbl_10(&t[2], &t[2]); memcpy(&t[y], &t[2], sizeof(sp_point)); } if (map) - sp_256_map_10(r, &t[0], tmp); + sp_256_map_10(r, &t[0]); else memcpy(r, &t[0], sizeof(sp_point)); - memset(tmp, 0, sizeof(tmp)); //paranoia memset(t, 0, sizeof(t)); //paranoia } @@ -817,7 +808,7 @@ static void sp_256_ecc_mulmod_10(sp_point* r, const sp_point* g, const sp_digit* */ static void sp_256_ecc_mulmod_base_10(sp_point* r, sp_digit* k /*, int map*/) { - sp_256_ecc_mulmod_10(r, &p256_base, k /*, map*/); + sp_256_ecc_mulmod_10(r, &p256_base, k /*, map*/); } /* Multiply the point by the scalar and serialize the X ordinate. -- cgit v1.2.3-55-g6feb From 93b886f54bf85ca38f372ddd521f7c5bdbdc5d08 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Mon, 26 Apr 2021 18:05:53 +0200 Subject: tls: shrink sp_256_mont_inv_10 function old new delta sp_256_ecc_mulmod_10 1237 1251 +14 p256_mod_2 32 - -32 ------------------------------------------------------------------------------ (add/remove: 0/1 grow/shrink: 1/0 up/down: 14/-32) Total: -18 bytes Signed-off-by: Denys Vlasenko --- networking/tls_sp_c32.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/networking/tls_sp_c32.c b/networking/tls_sp_c32.c index c71f716d6..97b2d3de9 100644 --- a/networking/tls_sp_c32.c +++ b/networking/tls_sp_c32.c @@ -554,11 +554,18 @@ static void sp_256_mont_sqr_10(sp_digit* r, const sp_digit* a, const sp_digit* m * r Inverse result. * a Number to invert. */ +#if 0 /* Mod-2 for the P256 curve. */ static const uint32_t p256_mod_2[8] = { 0xfffffffd,0xffffffff,0xffffffff,0x00000000, 0x00000000,0x00000000,0x00000001,0xffffffff, }; +//Bit pattern: +//2 2 2 2 2 2 2 1...1 +//5 5 4 3 2 1 0 9...0 9...1 +//543210987654321098765432109876543210987654321098765432109876543210...09876543210...09876543210 +//111111111111111111111111111111110000000000000000000000000000000100...00000111111...11111111101 +#endif static void sp_256_mont_inv_10(sp_digit* r, sp_digit* a) { sp_digit t[2*10]; //can be just [10]? @@ -567,7 +574,8 @@ static void sp_256_mont_inv_10(sp_digit* r, sp_digit* a) memcpy(t, a, sizeof(sp_digit) * 10); for (i = 254; i >= 0; i--) { sp_256_mont_sqr_10(t, t, p256_mod, p256_mp_mod); - if (p256_mod_2[i / 32] & ((sp_digit)1 << (i % 32))) + /*if (p256_mod_2[i / 32] & ((sp_digit)1 << (i % 32)))*/ + if (i >= 224 || i == 192 || (i <= 95 && i != 1)) sp_256_mont_mul_10(t, t, a, p256_mod, p256_mp_mod); } memcpy(r, t, sizeof(sp_digit) * 10); -- cgit v1.2.3-55-g6feb From 120401249a37a77cd2d4c71ad20a9a194bfea409 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Mon, 26 Apr 2021 20:24:34 +0200 Subject: tls: fix whitespace in P256 code Signed-off-by: Denys Vlasenko --- networking/tls_sp_c32.c | 1002 +++++++++++++++++++++++------------------------ 1 file changed, 501 insertions(+), 501 deletions(-) diff --git a/networking/tls_sp_c32.c b/networking/tls_sp_c32.c index 97b2d3de9..8527e7864 100644 --- a/networking/tls_sp_c32.c +++ b/networking/tls_sp_c32.c @@ -92,30 +92,30 @@ static const sp_point p256_base = { */ static void sp_256_to_bin(sp_digit* r, uint8_t* a) { - int i, j, s = 0, b; - - for (i = 0; i < 9; i++) { - r[i+1] += r[i] >> 26; - r[i] &= 0x3ffffff; - } - j = 256 / 8 - 1; - a[j] = 0; - for (i=0; i<10 && j>=0; i++) { - b = 0; - a[j--] |= r[i] << s; b += 8 - s; - if (j < 0) - break; - while (b < 26) { - a[j--] = r[i] >> b; b += 8; - if (j < 0) - break; - } - s = 8 - (b - 26); - if (j >= 0) - a[j] = 0; - if (s != 0) - j++; - } + int i, j, s = 0, b; + + for (i = 0; i < 9; i++) { + r[i+1] += r[i] >> 26; + r[i] &= 0x3ffffff; + } + j = 256 / 8 - 1; + a[j] = 0; + for (i = 0; i < 10 && j >= 0; i++) { + b = 0; + a[j--] |= r[i] << s; b += 8 - s; + if (j < 0) + break; + while (b < 26) { + a[j--] = r[i] >> b; b += 8; + if (j < 0) + break; + } + s = 8 - (b - 26); + if (j >= 0) + a[j] = 0; + if (s != 0) + j++; + } } /* Read big endian unsigned byte aray into r. @@ -126,37 +126,37 @@ static void sp_256_to_bin(sp_digit* r, uint8_t* a) */ static void sp_256_from_bin(sp_digit* r, int max, const uint8_t* a, int n) { - int i, j = 0, s = 0; - - r[0] = 0; - for (i = n-1; i >= 0; i--) { - r[j] |= ((sp_digit)a[i]) << s; - if (s >= 18) { - r[j] &= 0x3ffffff; - s = 26 - s; - if (j + 1 >= max) - break; - r[++j] = a[i] >> s; - s = 8 - s; - } - else - s += 8; - } + int i, j = 0, s = 0; + + r[0] = 0; + for (i = n-1; i >= 0; i--) { + r[j] |= ((sp_digit)a[i]) << s; + if (s >= 18) { + r[j] &= 0x3ffffff; + s = 26 - s; + if (j + 1 >= max) + break; + r[++j] = a[i] >> s; + s = 8 - s; + } + else + s += 8; + } - for (j++; j < max; j++) - r[j] = 0; + for (j++; j < max; j++) + r[j] = 0; } /* Convert a point of big-endian 32-byte x,y pair to type sp_point. */ static void sp_256_point_from_bin2x32(sp_point* p, const uint8_t *bin2x32) { - memset(p, 0, sizeof(*p)); - /*p->infinity = 0;*/ - sp_256_from_bin(p->x, 2 * 10, bin2x32, 32); - sp_256_from_bin(p->y, 2 * 10, bin2x32 + 32, 32); - //static const uint8_t one[1] = { 1 }; - //sp_256_from_bin(p->z, 2 * 10, one, 1); - p->z[0] = 1; + memset(p, 0, sizeof(*p)); + /*p->infinity = 0;*/ + sp_256_from_bin(p->x, 2 * 10, bin2x32, 32); + sp_256_from_bin(p->y, 2 * 10, bin2x32 + 32, 32); + //static const uint8_t one[1] = { 1 }; + //sp_256_from_bin(p->z, 2 * 10, one, 1); + p->z[0] = 1; } /* Compare a with b. @@ -166,14 +166,14 @@ static void sp_256_point_from_bin2x32(sp_point* p, const uint8_t *bin2x32) */ static sp_digit sp_256_cmp_10(const sp_digit* a, const sp_digit* b) { - sp_digit r; - int i; - for (i = 9; i >= 0; i--) { - r = a[i] - b[i]; - if (r != 0) - break; - } - return r; + sp_digit r; + int i; + for (i = 9; i >= 0; i--) { + r = a[i] - b[i]; + if (r != 0) + break; + } + return r; } /* Compare two numbers to determine if they are equal. @@ -182,56 +182,56 @@ static sp_digit sp_256_cmp_10(const sp_digit* a, const sp_digit* b) */ static int sp_256_cmp_equal_10(const sp_digit* a, const sp_digit* b) { - return sp_256_cmp_10(a, b) == 0; + return sp_256_cmp_10(a, b) == 0; } /* Normalize the values in each word to 26 bits. */ static void sp_256_norm_10(sp_digit* a) { - int i; - for (i = 0; i < 9; i++) { - a[i+1] += a[i] >> 26; - a[i] &= 0x3ffffff; - } + int i; + for (i = 0; i < 9; i++) { + a[i+1] += a[i] >> 26; + a[i] &= 0x3ffffff; + } } /* Add b to a into r. (r = a + b) */ static void sp_256_add_10(sp_digit* r, const sp_digit* a, const sp_digit* b) { - int i; - for (i = 0; i < 10; i++) - r[i] = a[i] + b[i]; + int i; + for (i = 0; i < 10; i++) + r[i] = a[i] + b[i]; } /* Conditionally add a and b using the mask m. * m is -1 to add and 0 when not. */ static void sp_256_cond_add_10(sp_digit* r, const sp_digit* a, - const sp_digit* b, const sp_digit m) + const sp_digit* b, const sp_digit m) { - int i; - for (i = 0; i < 10; i++) - r[i] = a[i] + (b[i] & m); + int i; + for (i = 0; i < 10; i++) + r[i] = a[i] + (b[i] & m); } /* Conditionally subtract b from a using the mask m. * m is -1 to subtract and 0 when not. */ static void sp_256_cond_sub_10(sp_digit* r, const sp_digit* a, - const sp_digit* b, const sp_digit m) + const sp_digit* b, const sp_digit m) { - int i; - for (i = 0; i < 10; i++) - r[i] = a[i] - (b[i] & m); + int i; + for (i = 0; i < 10; i++) + r[i] = a[i] - (b[i] & m); } /* Shift number left one bit. Bottom bit is lost. */ static void sp_256_rshift1_10(sp_digit* r, sp_digit* a) { - int i; - for (i = 0; i < 9; i++) - r[i] = ((a[i] >> 1) | (a[i + 1] << 25)) & 0x3ffffff; - r[9] = a[9] >> 1; + int i; + for (i = 0; i < 9; i++) + r[i] = ((a[i] >> 1) | (a[i + 1] << 25)) & 0x3ffffff; + r[9] = a[9] >> 1; } /* Multiply a number by Montogmery normalizer mod modulus (prime). @@ -241,188 +241,188 @@ static void sp_256_rshift1_10(sp_digit* r, sp_digit* a) */ static void sp_256_mod_mul_norm_10(sp_digit* r, const sp_digit* a) { - int64_t t[8]; - int64_t a32[8]; - int64_t o; - - a32[0] = a[0]; - a32[0] |= a[1] << 26; - a32[0] &= 0xffffffff; - a32[1] = (sp_digit)(a[1] >> 6); - a32[1] |= a[2] << 20; - a32[1] &= 0xffffffff; - a32[2] = (sp_digit)(a[2] >> 12); - a32[2] |= a[3] << 14; - a32[2] &= 0xffffffff; - a32[3] = (sp_digit)(a[3] >> 18); - a32[3] |= a[4] << 8; - a32[3] &= 0xffffffff; - a32[4] = (sp_digit)(a[4] >> 24); - a32[4] |= a[5] << 2; - a32[4] |= a[6] << 28; - a32[4] &= 0xffffffff; - a32[5] = (sp_digit)(a[6] >> 4); - a32[5] |= a[7] << 22; - a32[5] &= 0xffffffff; - a32[6] = (sp_digit)(a[7] >> 10); - a32[6] |= a[8] << 16; - a32[6] &= 0xffffffff; - a32[7] = (sp_digit)(a[8] >> 16); - a32[7] |= a[9] << 10; - a32[7] &= 0xffffffff; - - /* 1 1 0 -1 -1 -1 -1 0 */ - t[0] = 0 + a32[0] + a32[1] - a32[3] - a32[4] - a32[5] - a32[6]; - /* 0 1 1 0 -1 -1 -1 -1 */ - t[1] = 0 + a32[1] + a32[2] - a32[4] - a32[5] - a32[6] - a32[7]; - /* 0 0 1 1 0 -1 -1 -1 */ - t[2] = 0 + a32[2] + a32[3] - a32[5] - a32[6] - a32[7]; - /* -1 -1 0 2 2 1 0 -1 */ - t[3] = 0 - a32[0] - a32[1] + 2 * a32[3] + 2 * a32[4] + a32[5] - a32[7]; - /* 0 -1 -1 0 2 2 1 0 */ - t[4] = 0 - a32[1] - a32[2] + 2 * a32[4] + 2 * a32[5] + a32[6]; - /* 0 0 -1 -1 0 2 2 1 */ - t[5] = 0 - a32[2] - a32[3] + 2 * a32[5] + 2 * a32[6] + a32[7]; - /* -1 -1 0 0 0 1 3 2 */ - t[6] = 0 - a32[0] - a32[1] + a32[5] + 3 * a32[6] + 2 * a32[7]; - /* 1 0 -1 -1 -1 -1 0 3 */ - t[7] = 0 + a32[0] - a32[2] - a32[3] - a32[4] - a32[5] + 3 * a32[7]; - - t[1] += t[0] >> 32; t[0] &= 0xffffffff; - t[2] += t[1] >> 32; t[1] &= 0xffffffff; - t[3] += t[2] >> 32; t[2] &= 0xffffffff; - t[4] += t[3] >> 32; t[3] &= 0xffffffff; - t[5] += t[4] >> 32; t[4] &= 0xffffffff; - t[6] += t[5] >> 32; t[5] &= 0xffffffff; - t[7] += t[6] >> 32; t[6] &= 0xffffffff; - o = t[7] >> 32; t[7] &= 0xffffffff; - t[0] += o; - t[3] -= o; - t[6] -= o; - t[7] += o; - t[1] += t[0] >> 32; t[0] &= 0xffffffff; - t[2] += t[1] >> 32; t[1] &= 0xffffffff; - t[3] += t[2] >> 32; t[2] &= 0xffffffff; - t[4] += t[3] >> 32; t[3] &= 0xffffffff; - t[5] += t[4] >> 32; t[4] &= 0xffffffff; - t[6] += t[5] >> 32; t[5] &= 0xffffffff; - t[7] += t[6] >> 32; t[6] &= 0xffffffff; - - r[0] = (sp_digit)(t[0]) & 0x3ffffff; - r[1] = (sp_digit)(t[0] >> 26); - r[1] |= t[1] << 6; - r[1] &= 0x3ffffff; - r[2] = (sp_digit)(t[1] >> 20); - r[2] |= t[2] << 12; - r[2] &= 0x3ffffff; - r[3] = (sp_digit)(t[2] >> 14); - r[3] |= t[3] << 18; - r[3] &= 0x3ffffff; - r[4] = (sp_digit)(t[3] >> 8); - r[4] |= t[4] << 24; - r[4] &= 0x3ffffff; - r[5] = (sp_digit)(t[4] >> 2) & 0x3ffffff; - r[6] = (sp_digit)(t[4] >> 28); - r[6] |= t[5] << 4; - r[6] &= 0x3ffffff; - r[7] = (sp_digit)(t[5] >> 22); - r[7] |= t[6] << 10; - r[7] &= 0x3ffffff; - r[8] = (sp_digit)(t[6] >> 16); - r[8] |= t[7] << 16; - r[8] &= 0x3ffffff; - r[9] = (sp_digit)(t[7] >> 10); + int64_t t[8]; + int64_t a32[8]; + int64_t o; + + a32[0] = a[0]; + a32[0] |= a[1] << 26; + a32[0] &= 0xffffffff; + a32[1] = (sp_digit)(a[1] >> 6); + a32[1] |= a[2] << 20; + a32[1] &= 0xffffffff; + a32[2] = (sp_digit)(a[2] >> 12); + a32[2] |= a[3] << 14; + a32[2] &= 0xffffffff; + a32[3] = (sp_digit)(a[3] >> 18); + a32[3] |= a[4] << 8; + a32[3] &= 0xffffffff; + a32[4] = (sp_digit)(a[4] >> 24); + a32[4] |= a[5] << 2; + a32[4] |= a[6] << 28; + a32[4] &= 0xffffffff; + a32[5] = (sp_digit)(a[6] >> 4); + a32[5] |= a[7] << 22; + a32[5] &= 0xffffffff; + a32[6] = (sp_digit)(a[7] >> 10); + a32[6] |= a[8] << 16; + a32[6] &= 0xffffffff; + a32[7] = (sp_digit)(a[8] >> 16); + a32[7] |= a[9] << 10; + a32[7] &= 0xffffffff; + + /* 1 1 0 -1 -1 -1 -1 0 */ + t[0] = 0 + a32[0] + a32[1] - a32[3] - a32[4] - a32[5] - a32[6]; + /* 0 1 1 0 -1 -1 -1 -1 */ + t[1] = 0 + a32[1] + a32[2] - a32[4] - a32[5] - a32[6] - a32[7]; + /* 0 0 1 1 0 -1 -1 -1 */ + t[2] = 0 + a32[2] + a32[3] - a32[5] - a32[6] - a32[7]; + /* -1 -1 0 2 2 1 0 -1 */ + t[3] = 0 - a32[0] - a32[1] + 2 * a32[3] + 2 * a32[4] + a32[5] - a32[7]; + /* 0 -1 -1 0 2 2 1 0 */ + t[4] = 0 - a32[1] - a32[2] + 2 * a32[4] + 2 * a32[5] + a32[6]; + /* 0 0 -1 -1 0 2 2 1 */ + t[5] = 0 - a32[2] - a32[3] + 2 * a32[5] + 2 * a32[6] + a32[7]; + /* -1 -1 0 0 0 1 3 2 */ + t[6] = 0 - a32[0] - a32[1] + a32[5] + 3 * a32[6] + 2 * a32[7]; + /* 1 0 -1 -1 -1 -1 0 3 */ + t[7] = 0 + a32[0] - a32[2] - a32[3] - a32[4] - a32[5] + 3 * a32[7]; + + t[1] += t[0] >> 32; t[0] &= 0xffffffff; + t[2] += t[1] >> 32; t[1] &= 0xffffffff; + t[3] += t[2] >> 32; t[2] &= 0xffffffff; + t[4] += t[3] >> 32; t[3] &= 0xffffffff; + t[5] += t[4] >> 32; t[4] &= 0xffffffff; + t[6] += t[5] >> 32; t[5] &= 0xffffffff; + t[7] += t[6] >> 32; t[6] &= 0xffffffff; + o = t[7] >> 32; t[7] &= 0xffffffff; + t[0] += o; + t[3] -= o; + t[6] -= o; + t[7] += o; + t[1] += t[0] >> 32; t[0] &= 0xffffffff; + t[2] += t[1] >> 32; t[1] &= 0xffffffff; + t[3] += t[2] >> 32; t[2] &= 0xffffffff; + t[4] += t[3] >> 32; t[3] &= 0xffffffff; + t[5] += t[4] >> 32; t[4] &= 0xffffffff; + t[6] += t[5] >> 32; t[5] &= 0xffffffff; + t[7] += t[6] >> 32; t[6] &= 0xffffffff; + + r[0] = (sp_digit)(t[0]) & 0x3ffffff; + r[1] = (sp_digit)(t[0] >> 26); + r[1] |= t[1] << 6; + r[1] &= 0x3ffffff; + r[2] = (sp_digit)(t[1] >> 20); + r[2] |= t[2] << 12; + r[2] &= 0x3ffffff; + r[3] = (sp_digit)(t[2] >> 14); + r[3] |= t[3] << 18; + r[3] &= 0x3ffffff; + r[4] = (sp_digit)(t[3] >> 8); + r[4] |= t[4] << 24; + r[4] &= 0x3ffffff; + r[5] = (sp_digit)(t[4] >> 2) & 0x3ffffff; + r[6] = (sp_digit)(t[4] >> 28); + r[6] |= t[5] << 4; + r[6] &= 0x3ffffff; + r[7] = (sp_digit)(t[5] >> 22); + r[7] |= t[6] << 10; + r[7] &= 0x3ffffff; + r[8] = (sp_digit)(t[6] >> 16); + r[8] |= t[7] << 16; + r[8] &= 0x3ffffff; + r[9] = (sp_digit)(t[7] >> 10); } /* Mul a by scalar b and add into r. (r += a * b) */ static void sp_256_mul_add_10(sp_digit* r, const sp_digit* a, sp_digit b) { - int64_t tb = b; - int64_t t = 0; - int i; + int64_t tb = b; + int64_t t = 0; + int i; - for (i = 0; i < 10; i++) { - t += (tb * a[i]) + r[i]; - r[i] = t & 0x3ffffff; - t >>= 26; - } - r[10] += t; + for (i = 0; i < 10; i++) { + t += (tb * a[i]) + r[i]; + r[i] = t & 0x3ffffff; + t >>= 26; + } + r[10] += t; } /* Divide the number by 2 mod the modulus (prime). (r = a / 2 % m) */ static void sp_256_div2_10(sp_digit* r, const sp_digit* a, const sp_digit* m) { - sp_256_cond_add_10(r, a, m, 0 - (a[0] & 1)); - sp_256_norm_10(r); - sp_256_rshift1_10(r, r); + sp_256_cond_add_10(r, a, m, 0 - (a[0] & 1)); + sp_256_norm_10(r); + sp_256_rshift1_10(r, r); } /* Shift the result in the high 256 bits down to the bottom. */ static void sp_256_mont_shift_10(sp_digit* r, const sp_digit* a) { - int i; - sp_digit n, s; + int i; + sp_digit n, s; - s = a[10]; - n = a[9] >> 22; - for (i = 0; i < 9; i++) { - n += (s & 0x3ffffff) << 4; - r[i] = n & 0x3ffffff; - n >>= 26; - s = a[11 + i] + (s >> 26); - } - n += s << 4; - r[9] = n; - memset(&r[10], 0, sizeof(*r) * 10); + s = a[10]; + n = a[9] >> 22; + for (i = 0; i < 9; i++) { + n += (s & 0x3ffffff) << 4; + r[i] = n & 0x3ffffff; + n >>= 26; + s = a[11 + i] + (s >> 26); + } + n += s << 4; + r[9] = n; + memset(&r[10], 0, sizeof(*r) * 10); } /* Add two Montgomery form numbers (r = a + b % m) */ static void sp_256_mont_add_10(sp_digit* r, const sp_digit* a, const sp_digit* b, - const sp_digit* m) + const sp_digit* m) { - sp_256_add_10(r, a, b); - sp_256_norm_10(r); - sp_256_cond_sub_10(r, r, m, 0 - ((r[9] >> 22) > 0)); - sp_256_norm_10(r); + sp_256_add_10(r, a, b); + sp_256_norm_10(r); + sp_256_cond_sub_10(r, r, m, 0 - ((r[9] >> 22) > 0)); + sp_256_norm_10(r); } /* Double a Montgomery form number (r = a + a % m) */ static void sp_256_mont_dbl_10(sp_digit* r, const sp_digit* a, const sp_digit* m) { - sp_256_add_10(r, a, a); - sp_256_norm_10(r); - sp_256_cond_sub_10(r, r, m, 0 - ((r[9] >> 22) > 0)); - sp_256_norm_10(r); + sp_256_add_10(r, a, a); + sp_256_norm_10(r); + sp_256_cond_sub_10(r, r, m, 0 - ((r[9] >> 22) > 0)); + sp_256_norm_10(r); } /* Triple a Montgomery form number (r = a + a + a % m) */ static void sp_256_mont_tpl_10(sp_digit* r, const sp_digit* a, const sp_digit* m) { - sp_256_add_10(r, a, a); - sp_256_norm_10(r); - sp_256_cond_sub_10(r, r, m, 0 - ((r[9] >> 22) > 0)); - sp_256_norm_10(r); - sp_256_add_10(r, r, a); - sp_256_norm_10(r); - sp_256_cond_sub_10(r, r, m, 0 - ((r[9] >> 22) > 0)); - sp_256_norm_10(r); + sp_256_add_10(r, a, a); + sp_256_norm_10(r); + sp_256_cond_sub_10(r, r, m, 0 - ((r[9] >> 22) > 0)); + sp_256_norm_10(r); + sp_256_add_10(r, r, a); + sp_256_norm_10(r); + sp_256_cond_sub_10(r, r, m, 0 - ((r[9] >> 22) > 0)); + sp_256_norm_10(r); } /* Sub b from a into r. (r = a - b) */ static void sp_256_sub_10(sp_digit* r, const sp_digit* a, const sp_digit* b) { - int i; - for (i = 0; i < 10; i++) - r[i] = a[i] - b[i]; + int i; + for (i = 0; i < 10; i++) + r[i] = a[i] - b[i]; } /* Subtract two Montgomery form numbers (r = a - b % m) */ static void sp_256_mont_sub_10(sp_digit* r, const sp_digit* a, const sp_digit* b, - const sp_digit* m) + const sp_digit* m) { - sp_256_sub_10(r, a, b); - sp_256_cond_add_10(r, r, m, r[9] >> 22); - sp_256_norm_10(r); + sp_256_sub_10(r, a, b); + sp_256_cond_add_10(r, r, m, r[9] >> 22); + sp_256_norm_10(r); } /* Reduce the number back to 256 bits using Montgomery reduction. @@ -433,60 +433,60 @@ static void sp_256_mont_sub_10(sp_digit* r, const sp_digit* a, const sp_digit* b */ static void sp_256_mont_reduce_10(sp_digit* a, const sp_digit* m, sp_digit mp) { - int i; - sp_digit mu; - - if (mp != 1) { - for (i = 0; i < 9; i++) { - mu = (a[i] * mp) & 0x3ffffff; - sp_256_mul_add_10(a+i, m, mu); - a[i+1] += a[i] >> 26; - } - mu = (a[i] * mp) & 0x3fffffl; - sp_256_mul_add_10(a+i, m, mu); - a[i+1] += a[i] >> 26; - a[i] &= 0x3ffffff; - } - else { - for (i = 0; i < 9; i++) { - mu = a[i] & 0x3ffffff; - sp_256_mul_add_10(a+i, p256_mod, mu); - a[i+1] += a[i] >> 26; - } - mu = a[i] & 0x3fffffl; - sp_256_mul_add_10(a+i, p256_mod, mu); - a[i+1] += a[i] >> 26; - a[i] &= 0x3ffffff; - } - - sp_256_mont_shift_10(a, a); - sp_256_cond_sub_10(a, a, m, 0 - ((a[9] >> 22) > 0)); - sp_256_norm_10(a); + int i; + sp_digit mu; + + if (mp != 1) { + for (i = 0; i < 9; i++) { + mu = (a[i] * mp) & 0x3ffffff; + sp_256_mul_add_10(a+i, m, mu); + a[i+1] += a[i] >> 26; + } + mu = (a[i] * mp) & 0x3fffffl; + sp_256_mul_add_10(a+i, m, mu); + a[i+1] += a[i] >> 26; + a[i] &= 0x3ffffff; + } + else { + for (i = 0; i < 9; i++) { + mu = a[i] & 0x3ffffff; + sp_256_mul_add_10(a+i, p256_mod, mu); + a[i+1] += a[i] >> 26; + } + mu = a[i] & 0x3fffffl; + sp_256_mul_add_10(a+i, p256_mod, mu); + a[i+1] += a[i] >> 26; + a[i] &= 0x3ffffff; + } + + sp_256_mont_shift_10(a, a); + sp_256_cond_sub_10(a, a, m, 0 - ((a[9] >> 22) > 0)); + sp_256_norm_10(a); } /* Multiply a and b into r. (r = a * b) */ static void sp_256_mul_10(sp_digit* r, const sp_digit* a, const sp_digit* b) { - int i, j, k; - int64_t c; - - c = ((int64_t)a[9]) * b[9]; - r[19] = (sp_digit)(c >> 26); - c = (c & 0x3ffffff) << 26; - for (k = 17; k >= 0; k--) { - for (i = 9; i >= 0; i--) { - j = k - i; - if (j >= 10) - break; - if (j < 0) - continue; - c += ((int64_t)a[i]) * b[j]; - } - r[k + 2] += c >> 52; - r[k + 1] = (c >> 26) & 0x3ffffff; - c = (c & 0x3ffffff) << 26; - } - r[0] = (sp_digit)(c >> 26); + int i, j, k; + int64_t c; + + c = ((int64_t)a[9]) * b[9]; + r[19] = (sp_digit)(c >> 26); + c = (c & 0x3ffffff) << 26; + for (k = 17; k >= 0; k--) { + for (i = 9; i >= 0; i--) { + j = k - i; + if (j >= 10) + break; + if (j < 0) + continue; + c += ((int64_t)a[i]) * b[j]; + } + r[k + 2] += c >> 52; + r[k + 1] = (c >> 26) & 0x3ffffff; + c = (c & 0x3ffffff) << 26; + } + r[0] = (sp_digit)(c >> 26); } /* Multiply two Montogmery form numbers mod the modulus (prime). @@ -499,39 +499,39 @@ static void sp_256_mul_10(sp_digit* r, const sp_digit* a, const sp_digit* b) * mp Montogmery mulitplier. */ static void sp_256_mont_mul_10(sp_digit* r, const sp_digit* a, const sp_digit* b, - const sp_digit* m, sp_digit mp) + const sp_digit* m, sp_digit mp) { - sp_256_mul_10(r, a, b); - sp_256_mont_reduce_10(r, m, mp); + sp_256_mul_10(r, a, b); + sp_256_mont_reduce_10(r, m, mp); } /* Square a and put result in r. (r = a * a) */ static void sp_256_sqr_10(sp_digit* r, const sp_digit* a) { - int i, j, k; - int64_t c; - - c = ((int64_t)a[9]) * a[9]; - r[19] = (sp_digit)(c >> 26); - c = (c & 0x3ffffff) << 26; - for (k = 17; k >= 0; k--) { - for (i = 9; i >= 0; i--) { - j = k - i; - if (j >= 10 || i <= j) - break; - if (j < 0) - continue; - - c += ((int64_t)a[i]) * a[j] * 2; - } - if (i == j) - c += ((int64_t)a[i]) * a[i]; - - r[k + 2] += c >> 52; - r[k + 1] = (c >> 26) & 0x3ffffff; - c = (c & 0x3ffffff) << 26; - } - r[0] = (sp_digit)(c >> 26); + int i, j, k; + int64_t c; + + c = ((int64_t)a[9]) * a[9]; + r[19] = (sp_digit)(c >> 26); + c = (c & 0x3ffffff) << 26; + for (k = 17; k >= 0; k--) { + for (i = 9; i >= 0; i--) { + j = k - i; + if (j >= 10 || i <= j) + break; + if (j < 0) + continue; + + c += ((int64_t)a[i]) * a[j] * 2; + } + if (i == j) + c += ((int64_t)a[i]) * a[i]; + + r[k + 2] += c >> 52; + r[k + 1] = (c >> 26) & 0x3ffffff; + c = (c & 0x3ffffff) << 26; + } + r[0] = (sp_digit)(c >> 26); } /* Square the Montgomery form number. (r = a * a mod m) @@ -542,10 +542,10 @@ static void sp_256_sqr_10(sp_digit* r, const sp_digit* a) * mp Montogmery mulitplier. */ static void sp_256_mont_sqr_10(sp_digit* r, const sp_digit* a, const sp_digit* m, - sp_digit mp) + sp_digit mp) { - sp_256_sqr_10(r, a); - sp_256_mont_reduce_10(r, m, mp); + sp_256_sqr_10(r, a); + sp_256_mont_reduce_10(r, m, mp); } /* Invert the number, in Montgomery form, modulo the modulus (prime) of the @@ -557,8 +557,8 @@ static void sp_256_mont_sqr_10(sp_digit* r, const sp_digit* a, const sp_digit* m #if 0 /* Mod-2 for the P256 curve. */ static const uint32_t p256_mod_2[8] = { - 0xfffffffd,0xffffffff,0xffffffff,0x00000000, - 0x00000000,0x00000000,0x00000001,0xffffffff, + 0xfffffffd,0xffffffff,0xffffffff,0x00000000, + 0x00000000,0x00000000,0x00000001,0xffffffff, }; //Bit pattern: //2 2 2 2 2 2 2 1...1 @@ -568,17 +568,17 @@ static const uint32_t p256_mod_2[8] = { #endif static void sp_256_mont_inv_10(sp_digit* r, sp_digit* a) { - sp_digit t[2*10]; //can be just [10]? - int i; + sp_digit t[2*10]; //can be just [10]? + int i; - memcpy(t, a, sizeof(sp_digit) * 10); - for (i = 254; i >= 0; i--) { - sp_256_mont_sqr_10(t, t, p256_mod, p256_mp_mod); - /*if (p256_mod_2[i / 32] & ((sp_digit)1 << (i % 32)))*/ - if (i >= 224 || i == 192 || (i <= 95 && i != 1)) - sp_256_mont_mul_10(t, t, a, p256_mod, p256_mp_mod); - } - memcpy(r, t, sizeof(sp_digit) * 10); + memcpy(t, a, sizeof(sp_digit) * 10); + for (i = 254; i >= 0; i--) { + sp_256_mont_sqr_10(t, t, p256_mod, p256_mp_mod); + /*if (p256_mod_2[i / 32] & ((sp_digit)1 << (i % 32)))*/ + if (i >= 224 || i == 192 || (i <= 95 && i != 1)) + sp_256_mont_mul_10(t, t, a, p256_mod, p256_mp_mod); + } + memcpy(r, t, sizeof(sp_digit) * 10); } /* Map the Montgomery form projective co-ordinate point to an affine point. @@ -588,35 +588,35 @@ static void sp_256_mont_inv_10(sp_digit* r, sp_digit* a) */ static void sp_256_map_10(sp_point* r, sp_point* p) { - sp_digit t1[2*10]; - sp_digit t2[2*10]; - int32_t n; + sp_digit t1[2*10]; + sp_digit t2[2*10]; + int32_t n; - sp_256_mont_inv_10(t1, p->z); + sp_256_mont_inv_10(t1, p->z); - sp_256_mont_sqr_10(t2, t1, p256_mod, p256_mp_mod); - sp_256_mont_mul_10(t1, t2, t1, p256_mod, p256_mp_mod); + sp_256_mont_sqr_10(t2, t1, p256_mod, p256_mp_mod); + sp_256_mont_mul_10(t1, t2, t1, p256_mod, p256_mp_mod); - /* x /= z^2 */ - sp_256_mont_mul_10(r->x, p->x, t2, p256_mod, p256_mp_mod); - memset(r->x + 10, 0, sizeof(r->x) / 2); - sp_256_mont_reduce_10(r->x, p256_mod, p256_mp_mod); - /* Reduce x to less than modulus */ - n = sp_256_cmp_10(r->x, p256_mod); - sp_256_cond_sub_10(r->x, r->x, p256_mod, 0 - (n >= 0)); - sp_256_norm_10(r->x); + /* x /= z^2 */ + sp_256_mont_mul_10(r->x, p->x, t2, p256_mod, p256_mp_mod); + memset(r->x + 10, 0, sizeof(r->x) / 2); + sp_256_mont_reduce_10(r->x, p256_mod, p256_mp_mod); + /* Reduce x to less than modulus */ + n = sp_256_cmp_10(r->x, p256_mod); + sp_256_cond_sub_10(r->x, r->x, p256_mod, 0 - (n >= 0)); + sp_256_norm_10(r->x); - /* y /= z^3 */ - sp_256_mont_mul_10(r->y, p->y, t1, p256_mod, p256_mp_mod); - memset(r->y + 10, 0, sizeof(r->y) / 2); - sp_256_mont_reduce_10(r->y, p256_mod, p256_mp_mod); - /* Reduce y to less than modulus */ - n = sp_256_cmp_10(r->y, p256_mod); - sp_256_cond_sub_10(r->y, r->y, p256_mod, 0 - (n >= 0)); - sp_256_norm_10(r->y); + /* y /= z^3 */ + sp_256_mont_mul_10(r->y, p->y, t1, p256_mod, p256_mp_mod); + memset(r->y + 10, 0, sizeof(r->y) / 2); + sp_256_mont_reduce_10(r->y, p256_mod, p256_mp_mod); + /* Reduce y to less than modulus */ + n = sp_256_cmp_10(r->y, p256_mod); + sp_256_cond_sub_10(r->y, r->y, p256_mod, 0 - (n >= 0)); + sp_256_norm_10(r->y); - memset(r->z, 0, sizeof(r->z)); - r->z[0] = 1; + memset(r->z, 0, sizeof(r->z)); + r->z[0] = 1; } /* Double the Montgomery form projective point p. @@ -626,54 +626,54 @@ static void sp_256_map_10(sp_point* r, sp_point* p) */ static void sp_256_proj_point_dbl_10(sp_point* r, sp_point* p) { - sp_point tp; - sp_digit t1[2*10]; - sp_digit t2[2*10]; - - /* Put point to double into result */ - if (r != p) - *r = *p; /* struct copy */ - - if (r->infinity) { - /* If infinity, don't double (work on dummy value) */ - r = &tp; - } - /* T1 = Z * Z */ - sp_256_mont_sqr_10(t1, r->z, p256_mod, p256_mp_mod); - /* Z = Y * Z */ - sp_256_mont_mul_10(r->z, r->y, r->z, p256_mod, p256_mp_mod); - /* Z = 2Z */ - sp_256_mont_dbl_10(r->z, r->z, p256_mod); - /* T2 = X - T1 */ - sp_256_mont_sub_10(t2, r->x, t1, p256_mod); - /* T1 = X + T1 */ - sp_256_mont_add_10(t1, r->x, t1, p256_mod); - /* T2 = T1 * T2 */ - sp_256_mont_mul_10(t2, t1, t2, p256_mod, p256_mp_mod); - /* T1 = 3T2 */ - sp_256_mont_tpl_10(t1, t2, p256_mod); - /* Y = 2Y */ - sp_256_mont_dbl_10(r->y, r->y, p256_mod); - /* Y = Y * Y */ - sp_256_mont_sqr_10(r->y, r->y, p256_mod, p256_mp_mod); - /* T2 = Y * Y */ - sp_256_mont_sqr_10(t2, r->y, p256_mod, p256_mp_mod); - /* T2 = T2/2 */ - sp_256_div2_10(t2, t2, p256_mod); - /* Y = Y * X */ - sp_256_mont_mul_10(r->y, r->y, r->x, p256_mod, p256_mp_mod); - /* X = T1 * T1 */ - sp_256_mont_mul_10(r->x, t1, t1, p256_mod, p256_mp_mod); - /* X = X - Y */ - sp_256_mont_sub_10(r->x, r->x, r->y, p256_mod); - /* X = X - Y */ - sp_256_mont_sub_10(r->x, r->x, r->y, p256_mod); - /* Y = Y - X */ - sp_256_mont_sub_10(r->y, r->y, r->x, p256_mod); - /* Y = Y * T1 */ - sp_256_mont_mul_10(r->y, r->y, t1, p256_mod, p256_mp_mod); - /* Y = Y - T2 */ - sp_256_mont_sub_10(r->y, r->y, t2, p256_mod); + sp_point tp; + sp_digit t1[2*10]; + sp_digit t2[2*10]; + + /* Put point to double into result */ + if (r != p) + *r = *p; /* struct copy */ + + if (r->infinity) { + /* If infinity, don't double (work on dummy value) */ + r = &tp; + } + /* T1 = Z * Z */ + sp_256_mont_sqr_10(t1, r->z, p256_mod, p256_mp_mod); + /* Z = Y * Z */ + sp_256_mont_mul_10(r->z, r->y, r->z, p256_mod, p256_mp_mod); + /* Z = 2Z */ + sp_256_mont_dbl_10(r->z, r->z, p256_mod); + /* T2 = X - T1 */ + sp_256_mont_sub_10(t2, r->x, t1, p256_mod); + /* T1 = X + T1 */ + sp_256_mont_add_10(t1, r->x, t1, p256_mod); + /* T2 = T1 * T2 */ + sp_256_mont_mul_10(t2, t1, t2, p256_mod, p256_mp_mod); + /* T1 = 3T2 */ + sp_256_mont_tpl_10(t1, t2, p256_mod); + /* Y = 2Y */ + sp_256_mont_dbl_10(r->y, r->y, p256_mod); + /* Y = Y * Y */ + sp_256_mont_sqr_10(r->y, r->y, p256_mod, p256_mp_mod); + /* T2 = Y * Y */ + sp_256_mont_sqr_10(t2, r->y, p256_mod, p256_mp_mod); + /* T2 = T2/2 */ + sp_256_div2_10(t2, t2, p256_mod); + /* Y = Y * X */ + sp_256_mont_mul_10(r->y, r->y, r->x, p256_mod, p256_mp_mod); + /* X = T1 * T1 */ + sp_256_mont_mul_10(r->x, t1, t1, p256_mod, p256_mp_mod); + /* X = X - Y */ + sp_256_mont_sub_10(r->x, r->x, r->y, p256_mod); + /* X = X - Y */ + sp_256_mont_sub_10(r->x, r->x, r->y, p256_mod); + /* Y = Y - X */ + sp_256_mont_sub_10(r->y, r->y, r->x, p256_mod); + /* Y = Y * T1 */ + sp_256_mont_mul_10(r->y, r->y, t1, p256_mod, p256_mp_mod); + /* Y = Y - T2 */ + sp_256_mont_sub_10(r->y, r->y, t2, p256_mod); } /* Add two Montgomery form projective points. @@ -684,73 +684,73 @@ static void sp_256_proj_point_dbl_10(sp_point* r, sp_point* p) */ static void sp_256_proj_point_add_10(sp_point* r, sp_point* p, sp_point* q) { - sp_digit t1[2*10]; - sp_digit t2[2*10]; - sp_digit t3[2*10]; - sp_digit t4[2*10]; - sp_digit t5[2*10]; - - /* Ensure only the first point is the same as the result. */ - if (q == r) { - sp_point* a = p; - p = q; - q = a; - } - - /* Check double */ - sp_256_sub_10(t1, p256_mod, q->y); - sp_256_norm_10(t1); - if (sp_256_cmp_equal_10(p->x, q->x) - && sp_256_cmp_equal_10(p->z, q->z) - && (sp_256_cmp_equal_10(p->y, q->y) || sp_256_cmp_equal_10(p->y, t1)) - ) { - sp_256_proj_point_dbl_10(r, p); - } - else { - sp_point tp; - sp_point *v; - - v = r; - if (p->infinity | q->infinity) { - memset(&tp, 0, sizeof(tp)); - v = &tp; - } - - *r = p->infinity ? *q : *p; /* struct copy */ - - /* U1 = X1*Z2^2 */ - sp_256_mont_sqr_10(t1, q->z, p256_mod, p256_mp_mod); - sp_256_mont_mul_10(t3, t1, q->z, p256_mod, p256_mp_mod); - sp_256_mont_mul_10(t1, t1, v->x, p256_mod, p256_mp_mod); - /* U2 = X2*Z1^2 */ - sp_256_mont_sqr_10(t2, v->z, p256_mod, p256_mp_mod); - sp_256_mont_mul_10(t4, t2, v->z, p256_mod, p256_mp_mod); - sp_256_mont_mul_10(t2, t2, q->x, p256_mod, p256_mp_mod); - /* S1 = Y1*Z2^3 */ - sp_256_mont_mul_10(t3, t3, v->y, p256_mod, p256_mp_mod); - /* S2 = Y2*Z1^3 */ - sp_256_mont_mul_10(t4, t4, q->y, p256_mod, p256_mp_mod); - /* H = U2 - U1 */ - sp_256_mont_sub_10(t2, t2, t1, p256_mod); - /* R = S2 - S1 */ - sp_256_mont_sub_10(t4, t4, t3, p256_mod); - /* Z3 = H*Z1*Z2 */ - sp_256_mont_mul_10(v->z, v->z, q->z, p256_mod, p256_mp_mod); - sp_256_mont_mul_10(v->z, v->z, t2, p256_mod, p256_mp_mod); - /* X3 = R^2 - H^3 - 2*U1*H^2 */ - sp_256_mont_sqr_10(v->x, t4, p256_mod, p256_mp_mod); - sp_256_mont_sqr_10(t5, t2, p256_mod, p256_mp_mod); - sp_256_mont_mul_10(v->y, t1, t5, p256_mod, p256_mp_mod); - sp_256_mont_mul_10(t5, t5, t2, p256_mod, p256_mp_mod); - sp_256_mont_sub_10(v->x, v->x, t5, p256_mod); - sp_256_mont_dbl_10(t1, v->y, p256_mod); - sp_256_mont_sub_10(v->x, v->x, t1, p256_mod); - /* Y3 = R*(U1*H^2 - X3) - S1*H^3 */ - sp_256_mont_sub_10(v->y, v->y, v->x, p256_mod); - sp_256_mont_mul_10(v->y, v->y, t4, p256_mod, p256_mp_mod); - sp_256_mont_mul_10(t5, t5, t3, p256_mod, p256_mp_mod); - sp_256_mont_sub_10(v->y, v->y, t5, p256_mod); - } + sp_digit t1[2*10]; + sp_digit t2[2*10]; + sp_digit t3[2*10]; + sp_digit t4[2*10]; + sp_digit t5[2*10]; + + /* Ensure only the first point is the same as the result. */ + if (q == r) { + sp_point* a = p; + p = q; + q = a; + } + + /* Check double */ + sp_256_sub_10(t1, p256_mod, q->y); + sp_256_norm_10(t1); + if (sp_256_cmp_equal_10(p->x, q->x) + && sp_256_cmp_equal_10(p->z, q->z) + && (sp_256_cmp_equal_10(p->y, q->y) || sp_256_cmp_equal_10(p->y, t1)) + ) { + sp_256_proj_point_dbl_10(r, p); + } + else { + sp_point tp; + sp_point *v; + + v = r; + if (p->infinity | q->infinity) { + memset(&tp, 0, sizeof(tp)); + v = &tp; + } + + *r = p->infinity ? *q : *p; /* struct copy */ + + /* U1 = X1*Z2^2 */ + sp_256_mont_sqr_10(t1, q->z, p256_mod, p256_mp_mod); + sp_256_mont_mul_10(t3, t1, q->z, p256_mod, p256_mp_mod); + sp_256_mont_mul_10(t1, t1, v->x, p256_mod, p256_mp_mod); + /* U2 = X2*Z1^2 */ + sp_256_mont_sqr_10(t2, v->z, p256_mod, p256_mp_mod); + sp_256_mont_mul_10(t4, t2, v->z, p256_mod, p256_mp_mod); + sp_256_mont_mul_10(t2, t2, q->x, p256_mod, p256_mp_mod); + /* S1 = Y1*Z2^3 */ + sp_256_mont_mul_10(t3, t3, v->y, p256_mod, p256_mp_mod); + /* S2 = Y2*Z1^3 */ + sp_256_mont_mul_10(t4, t4, q->y, p256_mod, p256_mp_mod); + /* H = U2 - U1 */ + sp_256_mont_sub_10(t2, t2, t1, p256_mod); + /* R = S2 - S1 */ + sp_256_mont_sub_10(t4, t4, t3, p256_mod); + /* Z3 = H*Z1*Z2 */ + sp_256_mont_mul_10(v->z, v->z, q->z, p256_mod, p256_mp_mod); + sp_256_mont_mul_10(v->z, v->z, t2, p256_mod, p256_mp_mod); + /* X3 = R^2 - H^3 - 2*U1*H^2 */ + sp_256_mont_sqr_10(v->x, t4, p256_mod, p256_mp_mod); + sp_256_mont_sqr_10(t5, t2, p256_mod, p256_mp_mod); + sp_256_mont_mul_10(v->y, t1, t5, p256_mod, p256_mp_mod); + sp_256_mont_mul_10(t5, t5, t2, p256_mod, p256_mp_mod); + sp_256_mont_sub_10(v->x, v->x, t5, p256_mod); + sp_256_mont_dbl_10(t1, v->y, p256_mod); + sp_256_mont_sub_10(v->x, v->x, t1, p256_mod); + /* Y3 = R*(U1*H^2 - X3) - S1*H^3 */ + sp_256_mont_sub_10(v->y, v->y, v->x, p256_mod); + sp_256_mont_mul_10(v->y, v->y, t4, p256_mod, p256_mp_mod); + sp_256_mont_mul_10(t5, t5, t3, p256_mod, p256_mp_mod); + sp_256_mont_sub_10(v->y, v->y, t5, p256_mod); + } } /* Multiply the point by the scalar and return the result. @@ -763,48 +763,48 @@ static void sp_256_proj_point_add_10(sp_point* r, sp_point* p, sp_point* q) */ static void sp_256_ecc_mulmod_10(sp_point* r, const sp_point* g, const sp_digit* k /*, int map*/) { - enum { map = 1 }; /* we always convert result to affine coordinates */ - sp_point t[3]; - sp_digit n; - int i; - int c, y; - - memset(t, 0, sizeof(t)); - - /* t[0] = {0, 0, 1} * norm */ - t[0].infinity = 1; - /* t[1] = {g->x, g->y, g->z} * norm */ - sp_256_mod_mul_norm_10(t[1].x, g->x); - sp_256_mod_mul_norm_10(t[1].y, g->y); - sp_256_mod_mul_norm_10(t[1].z, g->z); - - i = 9; - c = 22; - n = k[i--] << (26 - c); - for (; ; c--) { - if (c == 0) { - if (i == -1) - break; - - n = k[i--]; - c = 26; - } - - y = (n >> 25) & 1; - n <<= 1; - - sp_256_proj_point_add_10(&t[y^1], &t[0], &t[1]); - memcpy(&t[2], &t[y], sizeof(sp_point)); - sp_256_proj_point_dbl_10(&t[2], &t[2]); - memcpy(&t[y], &t[2], sizeof(sp_point)); - } + enum { map = 1 }; /* we always convert result to affine coordinates */ + sp_point t[3]; + sp_digit n; + int i; + int c, y; + + memset(t, 0, sizeof(t)); + + /* t[0] = {0, 0, 1} * norm */ + t[0].infinity = 1; + /* t[1] = {g->x, g->y, g->z} * norm */ + sp_256_mod_mul_norm_10(t[1].x, g->x); + sp_256_mod_mul_norm_10(t[1].y, g->y); + sp_256_mod_mul_norm_10(t[1].z, g->z); + + i = 9; + c = 22; + n = k[i--] << (26 - c); + for (; ; c--) { + if (c == 0) { + if (i == -1) + break; + + n = k[i--]; + c = 26; + } + + y = (n >> 25) & 1; + n <<= 1; + + sp_256_proj_point_add_10(&t[y^1], &t[0], &t[1]); + memcpy(&t[2], &t[y], sizeof(sp_point)); + sp_256_proj_point_dbl_10(&t[2], &t[2]); + memcpy(&t[y], &t[2], sizeof(sp_point)); + } - if (map) - sp_256_map_10(r, &t[0]); - else - memcpy(r, &t[0], sizeof(sp_point)); + if (map) + sp_256_map_10(r, &t[0]); + else + memcpy(r, &t[0], sizeof(sp_point)); - memset(t, 0, sizeof(t)); //paranoia + memset(t, 0, sizeof(t)); //paranoia } /* Multiply the base point of P256 by the scalar and return the result. @@ -816,7 +816,7 @@ static void sp_256_ecc_mulmod_10(sp_point* r, const sp_point* g, const sp_digit* */ static void sp_256_ecc_mulmod_base_10(sp_point* r, sp_digit* k /*, int map*/) { - sp_256_ecc_mulmod_10(r, &p256_base, k /*, map*/); + sp_256_ecc_mulmod_10(r, &p256_base, k /*, map*/); } /* Multiply the point by the scalar and serialize the X ordinate. @@ -828,22 +828,22 @@ static void sp_256_ecc_mulmod_base_10(sp_point* r, sp_digit* k /*, int map*/) */ static void sp_ecc_secret_gen_256(sp_digit priv[10], const uint8_t *pub2x32, uint8_t* out32) { - sp_point point[1]; + sp_point point[1]; #if FIXED_PEER_PUBKEY - memset((void*)pub2x32, 0x55, 64); + memset((void*)pub2x32, 0x55, 64); #endif - dump_hex("peerkey %s\n", pub2x32, 32); /* in TLS, this is peer's public key */ - dump_hex(" %s\n", pub2x32 + 32, 32); + dump_hex("peerkey %s\n", pub2x32, 32); /* in TLS, this is peer's public key */ + dump_hex(" %s\n", pub2x32 + 32, 32); - sp_256_point_from_bin2x32(point, pub2x32); - dump_hex("point->x %s\n", point->x, sizeof(point->x)); - dump_hex("point->y %s\n", point->y, sizeof(point->y)); + sp_256_point_from_bin2x32(point, pub2x32); + dump_hex("point->x %s\n", point->x, sizeof(point->x)); + dump_hex("point->y %s\n", point->y, sizeof(point->y)); - sp_256_ecc_mulmod_10(point, point, priv); + sp_256_ecc_mulmod_10(point, point, priv); - sp_256_to_bin(point->x, out32); - dump_hex("out32: %s\n", out32, 32); + sp_256_to_bin(point->x, out32); + dump_hex("out32: %s\n", out32, 32); } /* Generates a scalar that is in the range 1..order-1. */ @@ -852,8 +852,8 @@ static void sp_ecc_secret_gen_256(sp_digit priv[10], const uint8_t *pub2x32, uin #if !SIMPLIFY static void sp_256_add_one_10(sp_digit* a) { - a[0]++; - sp_256_norm_10(a); + a[0]++; + sp_256_norm_10(a); } #endif static void sp_256_ecc_gen_k_10(sp_digit k[10]) -- cgit v1.2.3-55-g6feb From 9a40be433de31b8a7fea20b7ebce3dafbedaf504 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Mon, 26 Apr 2021 21:58:04 +0200 Subject: tls: get rid of constant-time add/sub operations function old new delta sp_256_sub_10 - 22 +22 static.sp_256_mont_reduce_10 176 178 +2 sp_256_mod_mul_norm_10 1440 1439 -1 sp_256_proj_point_dbl_10 453 446 -7 sp_256_ecc_mulmod_10 1229 1216 -13 static.sp_256_mont_sub_10 52 30 -22 static.sp_256_cond_sub_10 32 - -32 ------------------------------------------------------------------------------ (add/remove: 1/1 grow/shrink: 1/4 up/down: 24/-75) Total: -51 bytes Signed-off-by: Denys Vlasenko --- networking/tls_sp_c32.c | 58 ++++++++++++++++++------------------------------- 1 file changed, 21 insertions(+), 37 deletions(-) diff --git a/networking/tls_sp_c32.c b/networking/tls_sp_c32.c index 8527e7864..72a3be537 100644 --- a/networking/tls_sp_c32.c +++ b/networking/tls_sp_c32.c @@ -203,26 +203,12 @@ static void sp_256_add_10(sp_digit* r, const sp_digit* a, const sp_digit* b) r[i] = a[i] + b[i]; } -/* Conditionally add a and b using the mask m. - * m is -1 to add and 0 when not. - */ -static void sp_256_cond_add_10(sp_digit* r, const sp_digit* a, - const sp_digit* b, const sp_digit m) -{ - int i; - for (i = 0; i < 10; i++) - r[i] = a[i] + (b[i] & m); -} - -/* Conditionally subtract b from a using the mask m. - * m is -1 to subtract and 0 when not. - */ -static void sp_256_cond_sub_10(sp_digit* r, const sp_digit* a, - const sp_digit* b, const sp_digit m) +/* Sub b from a into r. (r = a - b) */ +static void sp_256_sub_10(sp_digit* r, const sp_digit* a, const sp_digit* b) { int i; for (i = 0; i < 10; i++) - r[i] = a[i] - (b[i] & m); + r[i] = a[i] - b[i]; } /* Shift number left one bit. Bottom bit is lost. */ @@ -352,7 +338,8 @@ static void sp_256_mul_add_10(sp_digit* r, const sp_digit* a, sp_digit b) /* Divide the number by 2 mod the modulus (prime). (r = a / 2 % m) */ static void sp_256_div2_10(sp_digit* r, const sp_digit* a, const sp_digit* m) { - sp_256_cond_add_10(r, a, m, 0 - (a[0] & 1)); + if (a[0] & 1) + sp_256_add_10(r, a, m); sp_256_norm_10(r); sp_256_rshift1_10(r, r); } @@ -382,7 +369,8 @@ static void sp_256_mont_add_10(sp_digit* r, const sp_digit* a, const sp_digit* b { sp_256_add_10(r, a, b); sp_256_norm_10(r); - sp_256_cond_sub_10(r, r, m, 0 - ((r[9] >> 22) > 0)); + if ((r[9] >> 22) > 0) + sp_256_sub_10(r, r, m); sp_256_norm_10(r); } @@ -391,7 +379,8 @@ static void sp_256_mont_dbl_10(sp_digit* r, const sp_digit* a, const sp_digit* m { sp_256_add_10(r, a, a); sp_256_norm_10(r); - sp_256_cond_sub_10(r, r, m, 0 - ((r[9] >> 22) > 0)); + if ((r[9] >> 22) > 0) + sp_256_sub_10(r, r, m); sp_256_norm_10(r); } @@ -400,28 +389,23 @@ static void sp_256_mont_tpl_10(sp_digit* r, const sp_digit* a, const sp_digit* m { sp_256_add_10(r, a, a); sp_256_norm_10(r); - sp_256_cond_sub_10(r, r, m, 0 - ((r[9] >> 22) > 0)); + if ((r[9] >> 22) > 0) + sp_256_sub_10(r, r, m); sp_256_norm_10(r); sp_256_add_10(r, r, a); sp_256_norm_10(r); - sp_256_cond_sub_10(r, r, m, 0 - ((r[9] >> 22) > 0)); + if ((r[9] >> 22) > 0) + sp_256_sub_10(r, r, m); sp_256_norm_10(r); } -/* Sub b from a into r. (r = a - b) */ -static void sp_256_sub_10(sp_digit* r, const sp_digit* a, const sp_digit* b) -{ - int i; - for (i = 0; i < 10; i++) - r[i] = a[i] - b[i]; -} - /* Subtract two Montgomery form numbers (r = a - b % m) */ static void sp_256_mont_sub_10(sp_digit* r, const sp_digit* a, const sp_digit* b, const sp_digit* m) { sp_256_sub_10(r, a, b); - sp_256_cond_add_10(r, r, m, r[9] >> 22); + if (r[9] >> 22) + sp_256_add_10(r, r, m); sp_256_norm_10(r); } @@ -460,7 +444,8 @@ static void sp_256_mont_reduce_10(sp_digit* a, const sp_digit* m, sp_digit mp) } sp_256_mont_shift_10(a, a); - sp_256_cond_sub_10(a, a, m, 0 - ((a[9] >> 22) > 0)); + if ((a[9] >> 22) > 0) + sp_256_sub_10(a, a, m); sp_256_norm_10(a); } @@ -590,7 +575,6 @@ static void sp_256_map_10(sp_point* r, sp_point* p) { sp_digit t1[2*10]; sp_digit t2[2*10]; - int32_t n; sp_256_mont_inv_10(t1, p->z); @@ -602,8 +586,8 @@ static void sp_256_map_10(sp_point* r, sp_point* p) memset(r->x + 10, 0, sizeof(r->x) / 2); sp_256_mont_reduce_10(r->x, p256_mod, p256_mp_mod); /* Reduce x to less than modulus */ - n = sp_256_cmp_10(r->x, p256_mod); - sp_256_cond_sub_10(r->x, r->x, p256_mod, 0 - (n >= 0)); + if (sp_256_cmp_10(r->x, p256_mod) >= 0) + sp_256_sub_10(r->x, r->x, p256_mod); sp_256_norm_10(r->x); /* y /= z^3 */ @@ -611,8 +595,8 @@ static void sp_256_map_10(sp_point* r, sp_point* p) memset(r->y + 10, 0, sizeof(r->y) / 2); sp_256_mont_reduce_10(r->y, p256_mod, p256_mp_mod); /* Reduce y to less than modulus */ - n = sp_256_cmp_10(r->y, p256_mod); - sp_256_cond_sub_10(r->y, r->y, p256_mod, 0 - (n >= 0)); + if (sp_256_cmp_10(r->y, p256_mod) >= 0) + sp_256_sub_10(r->y, r->y, p256_mod); sp_256_norm_10(r->y); memset(r->z, 0, sizeof(r->z)); -- cgit v1.2.3-55-g6feb From d728a30c211c2df6adccd64c6e2fc23387b341f2 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Mon, 26 Apr 2021 23:07:32 +0200 Subject: tls: add a patch with optimization which _should_ give better code ...but does not. Signed-off-by: Denys Vlasenko --- networking/tls_sp_c32.patch | 142 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 142 insertions(+) create mode 100644 networking/tls_sp_c32.patch diff --git a/networking/tls_sp_c32.patch b/networking/tls_sp_c32.patch new file mode 100644 index 000000000..7559586c9 --- /dev/null +++ b/networking/tls_sp_c32.patch @@ -0,0 +1,142 @@ +Somehow, gcc 6+ does this optimization same or better than the below +hand-written optimized code (gcc seem to eliminate a32[] array, uses 32-bit +registers/memory for "lower halves" of a32[i] elements). + +But there can be arches where gcc won't be this good? + +diff --git a/networking/tls_sp_c32.c b/networking/tls_sp_c32.c +index 72a3be537..e8a011ad1 100644 +--- a/networking/tls_sp_c32.c ++++ b/networking/tls_sp_c32.c +@@ -228,51 +228,96 @@ static void sp_256_rshift1_10(sp_digit* r, sp_digit* a) + static void sp_256_mod_mul_norm_10(sp_digit* r, const sp_digit* a) + { + int64_t t[8]; +- int64_t a32[8]; ++ uint32_t a32; + int64_t o; + +- a32[0] = a[0]; +- a32[0] |= a[1] << 26; +- a32[0] &= 0xffffffff; +- a32[1] = (sp_digit)(a[1] >> 6); +- a32[1] |= a[2] << 20; +- a32[1] &= 0xffffffff; +- a32[2] = (sp_digit)(a[2] >> 12); +- a32[2] |= a[3] << 14; +- a32[2] &= 0xffffffff; +- a32[3] = (sp_digit)(a[3] >> 18); +- a32[3] |= a[4] << 8; +- a32[3] &= 0xffffffff; +- a32[4] = (sp_digit)(a[4] >> 24); +- a32[4] |= a[5] << 2; +- a32[4] |= a[6] << 28; +- a32[4] &= 0xffffffff; +- a32[5] = (sp_digit)(a[6] >> 4); +- a32[5] |= a[7] << 22; +- a32[5] &= 0xffffffff; +- a32[6] = (sp_digit)(a[7] >> 10); +- a32[6] |= a[8] << 16; +- a32[6] &= 0xffffffff; +- a32[7] = (sp_digit)(a[8] >> 16); +- a32[7] |= a[9] << 10; +- a32[7] &= 0xffffffff; +- + /* 1 1 0 -1 -1 -1 -1 0 */ +- t[0] = 0 + a32[0] + a32[1] - a32[3] - a32[4] - a32[5] - a32[6]; + /* 0 1 1 0 -1 -1 -1 -1 */ +- t[1] = 0 + a32[1] + a32[2] - a32[4] - a32[5] - a32[6] - a32[7]; + /* 0 0 1 1 0 -1 -1 -1 */ +- t[2] = 0 + a32[2] + a32[3] - a32[5] - a32[6] - a32[7]; + /* -1 -1 0 2 2 1 0 -1 */ +- t[3] = 0 - a32[0] - a32[1] + 2 * a32[3] + 2 * a32[4] + a32[5] - a32[7]; + /* 0 -1 -1 0 2 2 1 0 */ +- t[4] = 0 - a32[1] - a32[2] + 2 * a32[4] + 2 * a32[5] + a32[6]; + /* 0 0 -1 -1 0 2 2 1 */ +- t[5] = 0 - a32[2] - a32[3] + 2 * a32[5] + 2 * a32[6] + a32[7]; + /* -1 -1 0 0 0 1 3 2 */ +- t[6] = 0 - a32[0] - a32[1] + a32[5] + 3 * a32[6] + 2 * a32[7]; + /* 1 0 -1 -1 -1 -1 0 3 */ +- t[7] = 0 + a32[0] - a32[2] - a32[3] - a32[4] - a32[5] + 3 * a32[7]; ++ //t[0] = 0 + a32[0] + a32[1] - a32[3] - a32[4] - a32[5] - a32[6] ; ++ //t[1] = 0 + a32[1] + a32[2] - a32[4] - a32[5] - a32[6] - a32[7] ; ++ //t[2] = 0 + a32[2] + a32[3] - a32[5] - a32[6] - a32[7] ; ++ //t[3] = 0 - a32[0] - a32[1] + 2*a32[3] + 2*a32[4] + a32[5] - a32[7] ; ++ //t[4] = 0 - a32[1] - a32[2] + 2*a32[4] + 2*a32[5] + a32[6] ; ++ //t[5] = 0 - a32[2] - a32[3] + 2*a32[5] + 2*a32[6] + a32[7] ; ++ //t[6] = 0 - a32[0] - a32[1] + a32[5] + 3*a32[6] + 2*a32[7]; ++ //t[7] = 0 + a32[0] - a32[2] - a32[3] - a32[4] - a32[5] + 3*a32[7]; ++ ++#define A32 (int64_t)a32 ++ a32 = a[0]; ++ a32 |= a[1] << 26; ++ t[0] = 0 + A32; ++ t[3] = 0 - A32; ++ t[6] = 0 - A32; ++ t[7] = 0 + A32; ++ ++ a32 = (sp_digit)(a[1] >> 6); ++ a32 |= a[2] << 20; ++ t[0] += A32 ; ++ t[1] = 0 + A32; ++ t[3] -= A32 ; ++ t[4] = 0 - A32; ++ t[6] -= A32 ; ++ ++ a32 = (sp_digit)(a[2] >> 12); ++ a32 |= a[3] << 14; ++ t[1] += A32 ; ++ t[2] = 0 + A32; ++ t[4] -= A32 ; ++ t[5] = 0 - A32; ++ t[7] -= A32 ; ++ ++ a32 = (sp_digit)(a[3] >> 18); ++ a32 |= a[4] << 8; ++ t[0] -= A32 ; ++ t[2] += A32 ; ++ t[3] += 2*A32; ++ t[5] -= A32 ; ++ t[7] -= A32 ; ++ ++ a32 = (sp_digit)(a[4] >> 24); ++ a32 |= a[5] << 2; ++ a32 |= a[6] << 28; ++ t[0] -= A32 ; ++ t[1] -= A32 ; ++ t[3] += 2*A32; ++ t[4] += 2*A32; ++ t[7] -= A32 ; ++ ++ a32 = (sp_digit)(a[6] >> 4); ++ a32 |= a[7] << 22; ++ t[0] -= A32 ; ++ t[1] -= A32 ; ++ t[2] -= A32 ; ++ t[3] += A32 ; ++ t[4] += 2*A32; ++ t[5] += 2*A32; ++ t[6] += A32 ; ++ t[7] -= A32 ; ++ ++ a32 = (sp_digit)(a[7] >> 10); ++ a32 |= a[8] << 16; ++ t[0] -= A32 ; ++ t[1] -= A32 ; ++ t[2] -= A32 ; ++ t[4] += A32 ; ++ t[5] += 2*A32; ++ t[6] += 3*A32; ++ ++ a32 = (sp_digit)(a[8] >> 16); ++ a32 |= a[9] << 10; ++ t[1] -= A32 ; ++ t[2] -= A32 ; ++ t[3] -= A32 ; ++ t[5] += A32 ; ++ t[6] += 2*A32; ++ t[7] += 3*A32; ++#undef A32 + + t[1] += t[0] >> 32; t[0] &= 0xffffffff; + t[2] += t[1] >> 32; t[1] &= 0xffffffff; -- cgit v1.2.3-55-g6feb From e52e43c72f9dce8bc524a8e6770e6abe3e97db09 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Tue, 27 Apr 2021 00:40:40 +0200 Subject: tls: whitespace fixes Signed-off-by: Denys Vlasenko --- networking/tls_fe.c | 24 ++++++++++++------------ networking/tls_pstm.c | 8 ++++---- networking/tls_rsa.c | 4 ++-- networking/tls_sp_c32.c | 4 +--- 4 files changed, 19 insertions(+), 21 deletions(-) diff --git a/networking/tls_fe.c b/networking/tls_fe.c index 3b3578c0d..e96b33225 100644 --- a/networking/tls_fe.c +++ b/networking/tls_fe.c @@ -64,8 +64,8 @@ static void fprime_select(byte *dst, const byte *zero, const byte *one, byte con #endif static void fe_select(byte *dst, - const byte *zero, const byte *one, - byte condition) + const byte *zero, const byte *one, + byte condition) { const byte mask = -condition; int i; @@ -163,11 +163,11 @@ static void fprime_mul(byte *r, const byte *a, const byte *b, const byte bit = (b[i >> 3] >> (i & 7)) & 1; byte plusa[F25519_SIZE]; - for (j = 0; j < F25519_SIZE; j++) { - c |= ((word16)r[j]) << 1; - r[j] = (byte)c; - c >>= 8; - } + for (j = 0; j < F25519_SIZE; j++) { + c |= ((word16)r[j]) << 1; + r[j] = (byte)c; + c >>= 8; + } raw_try_sub(r, modulus); fprime_copy(plusa, r); @@ -315,7 +315,7 @@ static void fe_mul__distinct(byte *r, const byte *a, const byte *b) for (; j < F25519_SIZE; j++) c += ((word32)a[j]) * - ((word32)b[i + F25519_SIZE - j]) * 38; + ((word32)b[i + F25519_SIZE - j]) * 38; r[i] = c; } @@ -474,9 +474,9 @@ static void fe_sqrt(byte *r, const byte *a) /* Differential addition */ static void xc_diffadd(byte *x5, byte *z5, - const byte *x1, const byte *z1, - const byte *x2, const byte *z2, - const byte *x3, const byte *z3) + const byte *x1, const byte *z1, + const byte *x2, const byte *z2, + const byte *x3, const byte *z3) { /* Explicit formulas database: dbl-1987-m3 * @@ -516,7 +516,7 @@ static void xc_diffadd(byte *x5, byte *z5, /* Double an X-coordinate */ static void xc_double(byte *x3, byte *z3, - const byte *x1, const byte *z1) + const byte *x1, const byte *z1) { /* Explicit formulas database: dbl-1987-m * diff --git a/networking/tls_pstm.c b/networking/tls_pstm.c index e5544ab11..99929031d 100644 --- a/networking/tls_pstm.c +++ b/networking/tls_pstm.c @@ -438,9 +438,9 @@ int32 FAST_FUNC pstm_read_unsigned_bin(pstm_int *a, unsigned char *b, int32 c) int32 idx = (c - 1) & ~3; switch (c % 4) { case 0: do { pd[idx+0] = *b++; - case 3: pd[idx+1] = *b++; - case 2: pd[idx+2] = *b++; - case 1: pd[idx+3] = *b++; + case 3: pd[idx+1] = *b++; + case 2: pd[idx+2] = *b++; + case 1: pd[idx+3] = *b++; idx -= 4; } while ((c -= 4) > 0); } @@ -1427,7 +1427,7 @@ static int32 pstm_div(psPool_t *pool, pstm_int *a, pstm_int *b, pstm_int *c, } /* while (q{i-t-1} * (yt * b + y{t-1})) > - xi * b**2 + xi-1 * b + xi-2 + xi * b**2 + xi-1 * b + xi-2 do q{i-t-1} -= 1; */ diff --git a/networking/tls_rsa.c b/networking/tls_rsa.c index 5fda1cb49..2dd5a02f4 100644 --- a/networking/tls_rsa.c +++ b/networking/tls_rsa.c @@ -15,7 +15,7 @@ pkcs1Pad(in, inlen, out, outlen, cryptType) static //bbox int32 pkcs1Pad(unsigned char *in, uint32 inlen, unsigned char *out, - uint32 outlen, int32 cryptType, void *userPtr) + uint32 outlen, int32 cryptType, void *userPtr) { unsigned char *c; int32 randomLen; @@ -60,7 +60,7 @@ int32 pkcs1Pad(unsigned char *in, uint32 inlen, unsigned char *out, psRsaCrypt( in, inlen, out, outlen, key, type) static //bbox int32 psRsaCrypt(psPool_t *pool, const unsigned char *in, uint32 inlen, - unsigned char *out, uint32 *outlen, psRsaKey_t *key, int32 type, + unsigned char *out, uint32 *outlen, psRsaKey_t *key, int32 type, void *data) { pstm_int tmp, tmpa, tmpb; diff --git a/networking/tls_sp_c32.c b/networking/tls_sp_c32.c index 72a3be537..1f140315e 100644 --- a/networking/tls_sp_c32.c +++ b/networking/tls_sp_c32.c @@ -506,12 +506,10 @@ static void sp_256_sqr_10(sp_digit* r, const sp_digit* a) break; if (j < 0) continue; - c += ((int64_t)a[i]) * a[j] * 2; } if (i == j) - c += ((int64_t)a[i]) * a[i]; - + c += ((int64_t)a[i]) * a[i]; r[k + 2] += c >> 52; r[k + 1] = (c >> 26) & 0x3ffffff; c = (c & 0x3ffffff) << 26; -- cgit v1.2.3-55-g6feb From a2bc52dd447816a887e508c6a1210ec43b38b03d Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Tue, 27 Apr 2021 01:21:26 +0200 Subject: tls: reorder P256 functions to make more sense Signed-off-by: Denys Vlasenko --- networking/tls_sp_c32.c | 358 ++++++++++++++++++++++++------------------------ 1 file changed, 179 insertions(+), 179 deletions(-) diff --git a/networking/tls_sp_c32.c b/networking/tls_sp_c32.c index 1f140315e..8059f6e10 100644 --- a/networking/tls_sp_c32.c +++ b/networking/tls_sp_c32.c @@ -220,106 +220,6 @@ static void sp_256_rshift1_10(sp_digit* r, sp_digit* a) r[9] = a[9] >> 1; } -/* Multiply a number by Montogmery normalizer mod modulus (prime). - * - * r The resulting Montgomery form number. - * a The number to convert. - */ -static void sp_256_mod_mul_norm_10(sp_digit* r, const sp_digit* a) -{ - int64_t t[8]; - int64_t a32[8]; - int64_t o; - - a32[0] = a[0]; - a32[0] |= a[1] << 26; - a32[0] &= 0xffffffff; - a32[1] = (sp_digit)(a[1] >> 6); - a32[1] |= a[2] << 20; - a32[1] &= 0xffffffff; - a32[2] = (sp_digit)(a[2] >> 12); - a32[2] |= a[3] << 14; - a32[2] &= 0xffffffff; - a32[3] = (sp_digit)(a[3] >> 18); - a32[3] |= a[4] << 8; - a32[3] &= 0xffffffff; - a32[4] = (sp_digit)(a[4] >> 24); - a32[4] |= a[5] << 2; - a32[4] |= a[6] << 28; - a32[4] &= 0xffffffff; - a32[5] = (sp_digit)(a[6] >> 4); - a32[5] |= a[7] << 22; - a32[5] &= 0xffffffff; - a32[6] = (sp_digit)(a[7] >> 10); - a32[6] |= a[8] << 16; - a32[6] &= 0xffffffff; - a32[7] = (sp_digit)(a[8] >> 16); - a32[7] |= a[9] << 10; - a32[7] &= 0xffffffff; - - /* 1 1 0 -1 -1 -1 -1 0 */ - t[0] = 0 + a32[0] + a32[1] - a32[3] - a32[4] - a32[5] - a32[6]; - /* 0 1 1 0 -1 -1 -1 -1 */ - t[1] = 0 + a32[1] + a32[2] - a32[4] - a32[5] - a32[6] - a32[7]; - /* 0 0 1 1 0 -1 -1 -1 */ - t[2] = 0 + a32[2] + a32[3] - a32[5] - a32[6] - a32[7]; - /* -1 -1 0 2 2 1 0 -1 */ - t[3] = 0 - a32[0] - a32[1] + 2 * a32[3] + 2 * a32[4] + a32[5] - a32[7]; - /* 0 -1 -1 0 2 2 1 0 */ - t[4] = 0 - a32[1] - a32[2] + 2 * a32[4] + 2 * a32[5] + a32[6]; - /* 0 0 -1 -1 0 2 2 1 */ - t[5] = 0 - a32[2] - a32[3] + 2 * a32[5] + 2 * a32[6] + a32[7]; - /* -1 -1 0 0 0 1 3 2 */ - t[6] = 0 - a32[0] - a32[1] + a32[5] + 3 * a32[6] + 2 * a32[7]; - /* 1 0 -1 -1 -1 -1 0 3 */ - t[7] = 0 + a32[0] - a32[2] - a32[3] - a32[4] - a32[5] + 3 * a32[7]; - - t[1] += t[0] >> 32; t[0] &= 0xffffffff; - t[2] += t[1] >> 32; t[1] &= 0xffffffff; - t[3] += t[2] >> 32; t[2] &= 0xffffffff; - t[4] += t[3] >> 32; t[3] &= 0xffffffff; - t[5] += t[4] >> 32; t[4] &= 0xffffffff; - t[6] += t[5] >> 32; t[5] &= 0xffffffff; - t[7] += t[6] >> 32; t[6] &= 0xffffffff; - o = t[7] >> 32; t[7] &= 0xffffffff; - t[0] += o; - t[3] -= o; - t[6] -= o; - t[7] += o; - t[1] += t[0] >> 32; t[0] &= 0xffffffff; - t[2] += t[1] >> 32; t[1] &= 0xffffffff; - t[3] += t[2] >> 32; t[2] &= 0xffffffff; - t[4] += t[3] >> 32; t[3] &= 0xffffffff; - t[5] += t[4] >> 32; t[4] &= 0xffffffff; - t[6] += t[5] >> 32; t[5] &= 0xffffffff; - t[7] += t[6] >> 32; t[6] &= 0xffffffff; - - r[0] = (sp_digit)(t[0]) & 0x3ffffff; - r[1] = (sp_digit)(t[0] >> 26); - r[1] |= t[1] << 6; - r[1] &= 0x3ffffff; - r[2] = (sp_digit)(t[1] >> 20); - r[2] |= t[2] << 12; - r[2] &= 0x3ffffff; - r[3] = (sp_digit)(t[2] >> 14); - r[3] |= t[3] << 18; - r[3] &= 0x3ffffff; - r[4] = (sp_digit)(t[3] >> 8); - r[4] |= t[4] << 24; - r[4] &= 0x3ffffff; - r[5] = (sp_digit)(t[4] >> 2) & 0x3ffffff; - r[6] = (sp_digit)(t[4] >> 28); - r[6] |= t[5] << 4; - r[6] &= 0x3ffffff; - r[7] = (sp_digit)(t[5] >> 22); - r[7] |= t[6] << 10; - r[7] &= 0x3ffffff; - r[8] = (sp_digit)(t[6] >> 16); - r[8] |= t[7] << 16; - r[8] &= 0x3ffffff; - r[9] = (sp_digit)(t[7] >> 10); -} - /* Mul a by scalar b and add into r. (r += a * b) */ static void sp_256_mul_add_10(sp_digit* r, const sp_digit* a, sp_digit b) { @@ -335,6 +235,58 @@ static void sp_256_mul_add_10(sp_digit* r, const sp_digit* a, sp_digit b) r[10] += t; } +/* Multiply a and b into r. (r = a * b) */ +static void sp_256_mul_10(sp_digit* r, const sp_digit* a, const sp_digit* b) +{ + int i, j, k; + int64_t c; + + c = ((int64_t)a[9]) * b[9]; + r[19] = (sp_digit)(c >> 26); + c = (c & 0x3ffffff) << 26; + for (k = 17; k >= 0; k--) { + for (i = 9; i >= 0; i--) { + j = k - i; + if (j >= 10) + break; + if (j < 0) + continue; + c += ((int64_t)a[i]) * b[j]; + } + r[k + 2] += c >> 52; + r[k + 1] = (c >> 26) & 0x3ffffff; + c = (c & 0x3ffffff) << 26; + } + r[0] = (sp_digit)(c >> 26); +} + +/* Square a and put result in r. (r = a * a) */ +static void sp_256_sqr_10(sp_digit* r, const sp_digit* a) +{ + int i, j, k; + int64_t c; + + c = ((int64_t)a[9]) * a[9]; + r[19] = (sp_digit)(c >> 26); + c = (c & 0x3ffffff) << 26; + for (k = 17; k >= 0; k--) { + for (i = 9; i >= 0; i--) { + j = k - i; + if (j >= 10 || i <= j) + break; + if (j < 0) + continue; + c += ((int64_t)a[i]) * a[j] * 2; + } + if (i == j) + c += ((int64_t)a[i]) * a[i]; + r[k + 2] += c >> 52; + r[k + 1] = (c >> 26) & 0x3ffffff; + c = (c & 0x3ffffff) << 26; + } + r[0] = (sp_digit)(c >> 26); +} + /* Divide the number by 2 mod the modulus (prime). (r = a / 2 % m) */ static void sp_256_div2_10(sp_digit* r, const sp_digit* a, const sp_digit* m) { @@ -344,25 +296,6 @@ static void sp_256_div2_10(sp_digit* r, const sp_digit* a, const sp_digit* m) sp_256_rshift1_10(r, r); } -/* Shift the result in the high 256 bits down to the bottom. */ -static void sp_256_mont_shift_10(sp_digit* r, const sp_digit* a) -{ - int i; - sp_digit n, s; - - s = a[10]; - n = a[9] >> 22; - for (i = 0; i < 9; i++) { - n += (s & 0x3ffffff) << 4; - r[i] = n & 0x3ffffff; - n >>= 26; - s = a[11 + i] + (s >> 26); - } - n += s << 4; - r[9] = n; - memset(&r[10], 0, sizeof(*r) * 10); -} - /* Add two Montgomery form numbers (r = a + b % m) */ static void sp_256_mont_add_10(sp_digit* r, const sp_digit* a, const sp_digit* b, const sp_digit* m) @@ -374,6 +307,16 @@ static void sp_256_mont_add_10(sp_digit* r, const sp_digit* a, const sp_digit* b sp_256_norm_10(r); } +/* Subtract two Montgomery form numbers (r = a - b % m) */ +static void sp_256_mont_sub_10(sp_digit* r, const sp_digit* a, const sp_digit* b, + const sp_digit* m) +{ + sp_256_sub_10(r, a, b); + if (r[9] >> 22) + sp_256_add_10(r, r, m); + sp_256_norm_10(r); +} + /* Double a Montgomery form number (r = a + a % m) */ static void sp_256_mont_dbl_10(sp_digit* r, const sp_digit* a, const sp_digit* m) { @@ -399,14 +342,23 @@ static void sp_256_mont_tpl_10(sp_digit* r, const sp_digit* a, const sp_digit* m sp_256_norm_10(r); } -/* Subtract two Montgomery form numbers (r = a - b % m) */ -static void sp_256_mont_sub_10(sp_digit* r, const sp_digit* a, const sp_digit* b, - const sp_digit* m) +/* Shift the result in the high 256 bits down to the bottom. */ +static void sp_256_mont_shift_10(sp_digit* r, const sp_digit* a) { - sp_256_sub_10(r, a, b); - if (r[9] >> 22) - sp_256_add_10(r, r, m); - sp_256_norm_10(r); + int i; + sp_digit n, s; + + s = a[10]; + n = a[9] >> 22; + for (i = 0; i < 9; i++) { + n += (s & 0x3ffffff) << 4; + r[i] = n & 0x3ffffff; + n >>= 26; + s = a[11 + i] + (s >> 26); + } + n += s << 4; + r[9] = n; + memset(&r[10], 0, sizeof(*r) * 10); } /* Reduce the number back to 256 bits using Montgomery reduction. @@ -449,31 +401,6 @@ static void sp_256_mont_reduce_10(sp_digit* a, const sp_digit* m, sp_digit mp) sp_256_norm_10(a); } -/* Multiply a and b into r. (r = a * b) */ -static void sp_256_mul_10(sp_digit* r, const sp_digit* a, const sp_digit* b) -{ - int i, j, k; - int64_t c; - - c = ((int64_t)a[9]) * b[9]; - r[19] = (sp_digit)(c >> 26); - c = (c & 0x3ffffff) << 26; - for (k = 17; k >= 0; k--) { - for (i = 9; i >= 0; i--) { - j = k - i; - if (j >= 10) - break; - if (j < 0) - continue; - c += ((int64_t)a[i]) * b[j]; - } - r[k + 2] += c >> 52; - r[k + 1] = (c >> 26) & 0x3ffffff; - c = (c & 0x3ffffff) << 26; - } - r[0] = (sp_digit)(c >> 26); -} - /* Multiply two Montogmery form numbers mod the modulus (prime). * (r = a * b mod m) * @@ -490,33 +417,6 @@ static void sp_256_mont_mul_10(sp_digit* r, const sp_digit* a, const sp_digit* b sp_256_mont_reduce_10(r, m, mp); } -/* Square a and put result in r. (r = a * a) */ -static void sp_256_sqr_10(sp_digit* r, const sp_digit* a) -{ - int i, j, k; - int64_t c; - - c = ((int64_t)a[9]) * a[9]; - r[19] = (sp_digit)(c >> 26); - c = (c & 0x3ffffff) << 26; - for (k = 17; k >= 0; k--) { - for (i = 9; i >= 0; i--) { - j = k - i; - if (j >= 10 || i <= j) - break; - if (j < 0) - continue; - c += ((int64_t)a[i]) * a[j] * 2; - } - if (i == j) - c += ((int64_t)a[i]) * a[i]; - r[k + 2] += c >> 52; - r[k + 1] = (c >> 26) & 0x3ffffff; - c = (c & 0x3ffffff) << 26; - } - r[0] = (sp_digit)(c >> 26); -} - /* Square the Montgomery form number. (r = a * a mod m) * * r Result of squaring. @@ -564,6 +464,106 @@ static void sp_256_mont_inv_10(sp_digit* r, sp_digit* a) memcpy(r, t, sizeof(sp_digit) * 10); } +/* Multiply a number by Montogmery normalizer mod modulus (prime). + * + * r The resulting Montgomery form number. + * a The number to convert. + */ +static void sp_256_mod_mul_norm_10(sp_digit* r, const sp_digit* a) +{ + int64_t t[8]; + int64_t a32[8]; + int64_t o; + + a32[0] = a[0]; + a32[0] |= a[1] << 26; + a32[0] &= 0xffffffff; + a32[1] = (sp_digit)(a[1] >> 6); + a32[1] |= a[2] << 20; + a32[1] &= 0xffffffff; + a32[2] = (sp_digit)(a[2] >> 12); + a32[2] |= a[3] << 14; + a32[2] &= 0xffffffff; + a32[3] = (sp_digit)(a[3] >> 18); + a32[3] |= a[4] << 8; + a32[3] &= 0xffffffff; + a32[4] = (sp_digit)(a[4] >> 24); + a32[4] |= a[5] << 2; + a32[4] |= a[6] << 28; + a32[4] &= 0xffffffff; + a32[5] = (sp_digit)(a[6] >> 4); + a32[5] |= a[7] << 22; + a32[5] &= 0xffffffff; + a32[6] = (sp_digit)(a[7] >> 10); + a32[6] |= a[8] << 16; + a32[6] &= 0xffffffff; + a32[7] = (sp_digit)(a[8] >> 16); + a32[7] |= a[9] << 10; + a32[7] &= 0xffffffff; + + /* 1 1 0 -1 -1 -1 -1 0 */ + t[0] = 0 + a32[0] + a32[1] - a32[3] - a32[4] - a32[5] - a32[6]; + /* 0 1 1 0 -1 -1 -1 -1 */ + t[1] = 0 + a32[1] + a32[2] - a32[4] - a32[5] - a32[6] - a32[7]; + /* 0 0 1 1 0 -1 -1 -1 */ + t[2] = 0 + a32[2] + a32[3] - a32[5] - a32[6] - a32[7]; + /* -1 -1 0 2 2 1 0 -1 */ + t[3] = 0 - a32[0] - a32[1] + 2 * a32[3] + 2 * a32[4] + a32[5] - a32[7]; + /* 0 -1 -1 0 2 2 1 0 */ + t[4] = 0 - a32[1] - a32[2] + 2 * a32[4] + 2 * a32[5] + a32[6]; + /* 0 0 -1 -1 0 2 2 1 */ + t[5] = 0 - a32[2] - a32[3] + 2 * a32[5] + 2 * a32[6] + a32[7]; + /* -1 -1 0 0 0 1 3 2 */ + t[6] = 0 - a32[0] - a32[1] + a32[5] + 3 * a32[6] + 2 * a32[7]; + /* 1 0 -1 -1 -1 -1 0 3 */ + t[7] = 0 + a32[0] - a32[2] - a32[3] - a32[4] - a32[5] + 3 * a32[7]; + + t[1] += t[0] >> 32; t[0] &= 0xffffffff; + t[2] += t[1] >> 32; t[1] &= 0xffffffff; + t[3] += t[2] >> 32; t[2] &= 0xffffffff; + t[4] += t[3] >> 32; t[3] &= 0xffffffff; + t[5] += t[4] >> 32; t[4] &= 0xffffffff; + t[6] += t[5] >> 32; t[5] &= 0xffffffff; + t[7] += t[6] >> 32; t[6] &= 0xffffffff; + o = t[7] >> 32; t[7] &= 0xffffffff; + t[0] += o; + t[3] -= o; + t[6] -= o; + t[7] += o; + t[1] += t[0] >> 32; t[0] &= 0xffffffff; + t[2] += t[1] >> 32; t[1] &= 0xffffffff; + t[3] += t[2] >> 32; t[2] &= 0xffffffff; + t[4] += t[3] >> 32; t[3] &= 0xffffffff; + t[5] += t[4] >> 32; t[4] &= 0xffffffff; + t[6] += t[5] >> 32; t[5] &= 0xffffffff; + t[7] += t[6] >> 32; t[6] &= 0xffffffff; + + r[0] = (sp_digit)(t[0]) & 0x3ffffff; + r[1] = (sp_digit)(t[0] >> 26); + r[1] |= t[1] << 6; + r[1] &= 0x3ffffff; + r[2] = (sp_digit)(t[1] >> 20); + r[2] |= t[2] << 12; + r[2] &= 0x3ffffff; + r[3] = (sp_digit)(t[2] >> 14); + r[3] |= t[3] << 18; + r[3] &= 0x3ffffff; + r[4] = (sp_digit)(t[3] >> 8); + r[4] |= t[4] << 24; + r[4] &= 0x3ffffff; + r[5] = (sp_digit)(t[4] >> 2) & 0x3ffffff; + r[6] = (sp_digit)(t[4] >> 28); + r[6] |= t[5] << 4; + r[6] &= 0x3ffffff; + r[7] = (sp_digit)(t[5] >> 22); + r[7] |= t[6] << 10; + r[7] &= 0x3ffffff; + r[8] = (sp_digit)(t[6] >> 16); + r[8] |= t[7] << 16; + r[8] &= 0x3ffffff; + r[9] = (sp_digit)(t[7] >> 10); +} + /* Map the Montgomery form projective co-ordinate point to an affine point. * * r Resulting affine co-ordinate point. @@ -808,7 +808,7 @@ static void sp_256_ecc_mulmod_base_10(sp_point* r, sp_digit* k /*, int map*/) * pub2x32 Point to multiply. * out32 Buffer to hold X ordinate. */ -static void sp_ecc_secret_gen_256(sp_digit priv[10], const uint8_t *pub2x32, uint8_t* out32) +static void sp_ecc_secret_gen_256(const sp_digit priv[10], const uint8_t *pub2x32, uint8_t* out32) { sp_point point[1]; -- cgit v1.2.3-55-g6feb From 39a3ef51b54272dea4018002080a104c21c6bb97 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Tue, 27 Apr 2021 01:31:51 +0200 Subject: tls: shrink p256_base function old new delta curve_P256_compute_pubkey_and_premaster 196 291 +95 static.base_y - 40 +40 static.base_x - 40 +40 p256_base 244 - -244 ------------------------------------------------------------------------------ (add/remove: 2/1 grow/shrink: 1/0 up/down: 175/-244) Total: -69 bytes Signed-off-by: Denys Vlasenko --- networking/tls_sp_c32.c | 30 ++++++++++++++++++------------ 1 file changed, 18 insertions(+), 12 deletions(-) diff --git a/networking/tls_sp_c32.c b/networking/tls_sp_c32.c index 8059f6e10..64c53b006 100644 --- a/networking/tls_sp_c32.c +++ b/networking/tls_sp_c32.c @@ -72,18 +72,6 @@ static const sp_digit p256_mod[10] = { #define p256_mp_mod ((sp_digit)0x000001) -/* The base point of curve P256. */ -static const sp_point p256_base = { - /* X ordinate */ - { 0x098c296,0x04e5176,0x33a0f4a,0x204b7ac,0x277037d,0x0e9103c,0x3ce6e56,0x1091fe2,0x1f2e12c,0x01ac5f4 }, - /* Y ordinate */ - { 0x3bf51f5,0x1901a0d,0x1ececbb,0x15dacc5,0x22bce33,0x303e785,0x27eb4a7,0x1fe6e3b,0x2e2fe1a,0x013f8d0 }, - /* Z ordinate */ - { 0x0000001,0x0000000,0x0000000,0x0000000,0x0000000,0x0000000,0x0000000,0x0000000,0x0000000,0x0000000 }, - /* infinity */ - 0 -}; - /* Write r as big endian to byte aray. * Fixed length number of bytes written: 32 * @@ -798,6 +786,24 @@ static void sp_256_ecc_mulmod_10(sp_point* r, const sp_point* g, const sp_digit* */ static void sp_256_ecc_mulmod_base_10(sp_point* r, sp_digit* k /*, int map*/) { + /* Since this function is called only once, save space: + * don't have "static const sp_point p256_base = {...}", + * it would have more zeros than data. + */ + static const sp_digit base_x[] = { + 0x098c296,0x04e5176,0x33a0f4a,0x204b7ac,0x277037d,0x0e9103c,0x3ce6e56,0x1091fe2,0x1f2e12c,0x01ac5f4 + }; + static const sp_digit base_y[] = { + 0x3bf51f5,0x1901a0d,0x1ececbb,0x15dacc5,0x22bce33,0x303e785,0x27eb4a7,0x1fe6e3b,0x2e2fe1a,0x013f8d0 + }; + sp_point p256_base; + + memset(&p256_base, 0, sizeof(p256_base)); + memcpy(p256_base.x, base_x, sizeof(base_x)); + memcpy(p256_base.y, base_y, sizeof(base_y)); + p256_base.z[0] = 1; + /*p256_base.infinity = 0;*/ + sp_256_ecc_mulmod_10(r, &p256_base, k /*, map*/); } -- cgit v1.2.3-55-g6feb From 48a18d15dfbfa41d137802e811a3abdfef012ac8 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Tue, 27 Apr 2021 12:24:21 +0200 Subject: tls: shrink p256_base more function old new delta static.p256_base_bin - 64 +64 sp_256_point_from_bin2x32 - 62 +62 static.base_y 40 - -40 static.base_x 40 - -40 curve_P256_compute_pubkey_and_premaster 291 194 -97 ------------------------------------------------------------------------------ (add/remove: 2/2 grow/shrink: 0/1 up/down: 126/-177) Total: -51 bytes Signed-off-by: Denys Vlasenko --- networking/tls_sp_c32.c | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/networking/tls_sp_c32.c b/networking/tls_sp_c32.c index 64c53b006..f9c66b186 100644 --- a/networking/tls_sp_c32.c +++ b/networking/tls_sp_c32.c @@ -790,19 +790,16 @@ static void sp_256_ecc_mulmod_base_10(sp_point* r, sp_digit* k /*, int map*/) * don't have "static const sp_point p256_base = {...}", * it would have more zeros than data. */ - static const sp_digit base_x[] = { - 0x098c296,0x04e5176,0x33a0f4a,0x204b7ac,0x277037d,0x0e9103c,0x3ce6e56,0x1091fe2,0x1f2e12c,0x01ac5f4 - }; - static const sp_digit base_y[] = { - 0x3bf51f5,0x1901a0d,0x1ececbb,0x15dacc5,0x22bce33,0x303e785,0x27eb4a7,0x1fe6e3b,0x2e2fe1a,0x013f8d0 + static const uint8_t p256_base_bin[] = { + /* x (big-endian) */ + 0x6b,0x17,0xd1,0xf2,0xe1,0x2c,0x42,0x47,0xf8,0xbc,0xe6,0xe5,0x63,0xa4,0x40,0xf2,0x77,0x03,0x7d,0x81,0x2d,0xeb,0x33,0xa0,0xf4,0xa1,0x39,0x45,0xd8,0x98,0xc2,0x96, + /* y */ + 0x4f,0xe3,0x42,0xe2,0xfe,0x1a,0x7f,0x9b,0x8e,0xe7,0xeb,0x4a,0x7c,0x0f,0x9e,0x16,0x2b,0xce,0x33,0x57,0x6b,0x31,0x5e,0xce,0xcb,0xb6,0x40,0x68,0x37,0xbf,0x51,0xf5, + /* z will be set to 0, infinity flag to "false" */ }; sp_point p256_base; - memset(&p256_base, 0, sizeof(p256_base)); - memcpy(p256_base.x, base_x, sizeof(base_x)); - memcpy(p256_base.y, base_y, sizeof(base_y)); - p256_base.z[0] = 1; - /*p256_base.infinity = 0;*/ + sp_256_point_from_bin2x32(&p256_base, p256_base_bin); sp_256_ecc_mulmod_10(r, &p256_base, k /*, map*/); } -- cgit v1.2.3-55-g6feb From 646e85629497ee364e97101de4402d7141919144 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Tue, 27 Apr 2021 13:09:44 +0200 Subject: tls: shrink sp_256_mod_mul_norm_10 function old new delta sp_256_mod_mul_norm_10 1439 1405 -34 Signed-off-by: Denys Vlasenko --- networking/tls_sp_c32.c | 145 ++++++++++++++++++++++++++------------------ networking/tls_sp_c32.patch | 142 ------------------------------------------- 2 files changed, 85 insertions(+), 202 deletions(-) delete mode 100644 networking/tls_sp_c32.patch diff --git a/networking/tls_sp_c32.c b/networking/tls_sp_c32.c index f9c66b186..c5e887aad 100644 --- a/networking/tls_sp_c32.c +++ b/networking/tls_sp_c32.c @@ -460,51 +460,90 @@ static void sp_256_mont_inv_10(sp_digit* r, sp_digit* a) static void sp_256_mod_mul_norm_10(sp_digit* r, const sp_digit* a) { int64_t t[8]; - int64_t a32[8]; int64_t o; - - a32[0] = a[0]; - a32[0] |= a[1] << 26; - a32[0] &= 0xffffffff; - a32[1] = (sp_digit)(a[1] >> 6); - a32[1] |= a[2] << 20; - a32[1] &= 0xffffffff; - a32[2] = (sp_digit)(a[2] >> 12); - a32[2] |= a[3] << 14; - a32[2] &= 0xffffffff; - a32[3] = (sp_digit)(a[3] >> 18); - a32[3] |= a[4] << 8; - a32[3] &= 0xffffffff; - a32[4] = (sp_digit)(a[4] >> 24); - a32[4] |= a[5] << 2; - a32[4] |= a[6] << 28; - a32[4] &= 0xffffffff; - a32[5] = (sp_digit)(a[6] >> 4); - a32[5] |= a[7] << 22; - a32[5] &= 0xffffffff; - a32[6] = (sp_digit)(a[7] >> 10); - a32[6] |= a[8] << 16; - a32[6] &= 0xffffffff; - a32[7] = (sp_digit)(a[8] >> 16); - a32[7] |= a[9] << 10; - a32[7] &= 0xffffffff; + uint32_t a32; /* 1 1 0 -1 -1 -1 -1 0 */ - t[0] = 0 + a32[0] + a32[1] - a32[3] - a32[4] - a32[5] - a32[6]; /* 0 1 1 0 -1 -1 -1 -1 */ - t[1] = 0 + a32[1] + a32[2] - a32[4] - a32[5] - a32[6] - a32[7]; /* 0 0 1 1 0 -1 -1 -1 */ - t[2] = 0 + a32[2] + a32[3] - a32[5] - a32[6] - a32[7]; /* -1 -1 0 2 2 1 0 -1 */ - t[3] = 0 - a32[0] - a32[1] + 2 * a32[3] + 2 * a32[4] + a32[5] - a32[7]; /* 0 -1 -1 0 2 2 1 0 */ - t[4] = 0 - a32[1] - a32[2] + 2 * a32[4] + 2 * a32[5] + a32[6]; /* 0 0 -1 -1 0 2 2 1 */ - t[5] = 0 - a32[2] - a32[3] + 2 * a32[5] + 2 * a32[6] + a32[7]; /* -1 -1 0 0 0 1 3 2 */ - t[6] = 0 - a32[0] - a32[1] + a32[5] + 3 * a32[6] + 2 * a32[7]; /* 1 0 -1 -1 -1 -1 0 3 */ - t[7] = 0 + a32[0] - a32[2] - a32[3] - a32[4] - a32[5] + 3 * a32[7]; + // t[] should be calculated from "a" (converted from 26-bit to 32-bit vector a32[8]) + // according to the above matrix: + //t[0] = 0 + a32[0] + a32[1] - a32[3] - a32[4] - a32[5] - a32[6] ; + //t[1] = 0 + a32[1] + a32[2] - a32[4] - a32[5] - a32[6] - a32[7] ; + //t[2] = 0 + a32[2] + a32[3] - a32[5] - a32[6] - a32[7] ; + //t[3] = 0 - a32[0] - a32[1] + 2*a32[3] + 2*a32[4] + a32[5] - a32[7] ; + //t[4] = 0 - a32[1] - a32[2] + 2*a32[4] + 2*a32[5] + a32[6] ; + //t[5] = 0 - a32[2] - a32[3] + 2*a32[5] + 2*a32[6] + a32[7] ; + //t[6] = 0 - a32[0] - a32[1] + a32[5] + 3*a32[6] + 2*a32[7]; + //t[7] = 0 + a32[0] - a32[2] - a32[3] - a32[4] - a32[5] + 3*a32[7]; + // We can do it "piecemeal" after each a32[i] is known, no need to store entire a32[8] vector: + +#define A32 (int64_t)a32 + a32 = a[0] | (a[1] << 26); + t[0] = 0 + A32; + t[3] = 0 - A32; + t[6] = 0 - A32; + t[7] = 0 + A32; + + a32 = (a[1] >> 6) | (a[2] << 20); + t[0] += A32 ; + t[1] = 0 + A32; + t[3] -= A32 ; + t[4] = 0 - A32; + t[6] -= A32 ; + + a32 = (a[2] >> 12) | (a[3] << 14); + t[1] += A32 ; + t[2] = 0 + A32; + t[4] -= A32 ; + t[5] = 0 - A32; + t[7] -= A32 ; + + a32 = (a[3] >> 18) | (a[4] << 8); + t[0] -= A32 ; + t[2] += A32 ; + t[3] += 2*A32; + t[5] -= A32 ; + t[7] -= A32 ; + + a32 = (a[4] >> 24) | (a[5] << 2) | (a[6] << 28); + t[0] -= A32 ; + t[1] -= A32 ; + t[3] += 2*A32; + t[4] += 2*A32; + t[7] -= A32 ; + + a32 = (a[6] >> 4) | (a[7] << 22); + t[0] -= A32 ; + t[1] -= A32 ; + t[2] -= A32 ; + t[3] += A32 ; + t[4] += 2*A32; + t[5] += 2*A32; + t[6] += A32 ; + t[7] -= A32 ; + + a32 = (a[7] >> 10) | (a[8] << 16); + t[0] -= A32 ; + t[1] -= A32 ; + t[2] -= A32 ; + t[4] += A32 ; + t[5] += 2*A32; + t[6] += 3*A32; + + a32 = (a[8] >> 16) | (a[9] << 10); + t[1] -= A32 ; + t[2] -= A32 ; + t[3] -= A32 ; + t[5] += A32 ; + t[6] += 2*A32; + t[7] += 3*A32; +#undef A32 t[1] += t[0] >> 32; t[0] &= 0xffffffff; t[2] += t[1] >> 32; t[1] &= 0xffffffff; @@ -526,30 +565,16 @@ static void sp_256_mod_mul_norm_10(sp_digit* r, const sp_digit* a) t[6] += t[5] >> 32; t[5] &= 0xffffffff; t[7] += t[6] >> 32; t[6] &= 0xffffffff; - r[0] = (sp_digit)(t[0]) & 0x3ffffff; - r[1] = (sp_digit)(t[0] >> 26); - r[1] |= t[1] << 6; - r[1] &= 0x3ffffff; - r[2] = (sp_digit)(t[1] >> 20); - r[2] |= t[2] << 12; - r[2] &= 0x3ffffff; - r[3] = (sp_digit)(t[2] >> 14); - r[3] |= t[3] << 18; - r[3] &= 0x3ffffff; - r[4] = (sp_digit)(t[3] >> 8); - r[4] |= t[4] << 24; - r[4] &= 0x3ffffff; - r[5] = (sp_digit)(t[4] >> 2) & 0x3ffffff; - r[6] = (sp_digit)(t[4] >> 28); - r[6] |= t[5] << 4; - r[6] &= 0x3ffffff; - r[7] = (sp_digit)(t[5] >> 22); - r[7] |= t[6] << 10; - r[7] &= 0x3ffffff; - r[8] = (sp_digit)(t[6] >> 16); - r[8] |= t[7] << 16; - r[8] &= 0x3ffffff; - r[9] = (sp_digit)(t[7] >> 10); + r[0] = 0x3ffffff & ((sp_digit)(t[0])); + r[1] = 0x3ffffff & ((sp_digit)(t[0] >> 26) | ((sp_digit)t[1] << 6)); + r[2] = 0x3ffffff & ((sp_digit)(t[1] >> 20) | ((sp_digit)t[2] << 12)); + r[3] = 0x3ffffff & ((sp_digit)(t[2] >> 14) | ((sp_digit)t[3] << 18)); + r[4] = 0x3ffffff & ((sp_digit)(t[3] >> 8) | ((sp_digit)t[4] << 24)); + r[5] = 0x3ffffff & ((sp_digit)t[4] >> 2); /* small shift, ok to cast t[4] to narrower type */ + r[6] = 0x3ffffff & ((sp_digit)(t[4] >> 28) | ((sp_digit)t[5] << 4)); + r[7] = 0x3ffffff & ((sp_digit)(t[5] >> 22) | ((sp_digit)t[6] << 10)); + r[8] = 0x3ffffff & ((sp_digit)(t[6] >> 16) | ((sp_digit)t[7] << 16)); + r[9] = ((sp_digit)(t[7] >> 10)); } /* Map the Montgomery form projective co-ordinate point to an affine point. @@ -795,7 +820,7 @@ static void sp_256_ecc_mulmod_base_10(sp_point* r, sp_digit* k /*, int map*/) 0x6b,0x17,0xd1,0xf2,0xe1,0x2c,0x42,0x47,0xf8,0xbc,0xe6,0xe5,0x63,0xa4,0x40,0xf2,0x77,0x03,0x7d,0x81,0x2d,0xeb,0x33,0xa0,0xf4,0xa1,0x39,0x45,0xd8,0x98,0xc2,0x96, /* y */ 0x4f,0xe3,0x42,0xe2,0xfe,0x1a,0x7f,0x9b,0x8e,0xe7,0xeb,0x4a,0x7c,0x0f,0x9e,0x16,0x2b,0xce,0x33,0x57,0x6b,0x31,0x5e,0xce,0xcb,0xb6,0x40,0x68,0x37,0xbf,0x51,0xf5, - /* z will be set to 0, infinity flag to "false" */ + /* z will be set to 1, infinity flag to "false" */ }; sp_point p256_base; diff --git a/networking/tls_sp_c32.patch b/networking/tls_sp_c32.patch deleted file mode 100644 index 7559586c9..000000000 --- a/networking/tls_sp_c32.patch +++ /dev/null @@ -1,142 +0,0 @@ -Somehow, gcc 6+ does this optimization same or better than the below -hand-written optimized code (gcc seem to eliminate a32[] array, uses 32-bit -registers/memory for "lower halves" of a32[i] elements). - -But there can be arches where gcc won't be this good? - -diff --git a/networking/tls_sp_c32.c b/networking/tls_sp_c32.c -index 72a3be537..e8a011ad1 100644 ---- a/networking/tls_sp_c32.c -+++ b/networking/tls_sp_c32.c -@@ -228,51 +228,96 @@ static void sp_256_rshift1_10(sp_digit* r, sp_digit* a) - static void sp_256_mod_mul_norm_10(sp_digit* r, const sp_digit* a) - { - int64_t t[8]; -- int64_t a32[8]; -+ uint32_t a32; - int64_t o; - -- a32[0] = a[0]; -- a32[0] |= a[1] << 26; -- a32[0] &= 0xffffffff; -- a32[1] = (sp_digit)(a[1] >> 6); -- a32[1] |= a[2] << 20; -- a32[1] &= 0xffffffff; -- a32[2] = (sp_digit)(a[2] >> 12); -- a32[2] |= a[3] << 14; -- a32[2] &= 0xffffffff; -- a32[3] = (sp_digit)(a[3] >> 18); -- a32[3] |= a[4] << 8; -- a32[3] &= 0xffffffff; -- a32[4] = (sp_digit)(a[4] >> 24); -- a32[4] |= a[5] << 2; -- a32[4] |= a[6] << 28; -- a32[4] &= 0xffffffff; -- a32[5] = (sp_digit)(a[6] >> 4); -- a32[5] |= a[7] << 22; -- a32[5] &= 0xffffffff; -- a32[6] = (sp_digit)(a[7] >> 10); -- a32[6] |= a[8] << 16; -- a32[6] &= 0xffffffff; -- a32[7] = (sp_digit)(a[8] >> 16); -- a32[7] |= a[9] << 10; -- a32[7] &= 0xffffffff; -- - /* 1 1 0 -1 -1 -1 -1 0 */ -- t[0] = 0 + a32[0] + a32[1] - a32[3] - a32[4] - a32[5] - a32[6]; - /* 0 1 1 0 -1 -1 -1 -1 */ -- t[1] = 0 + a32[1] + a32[2] - a32[4] - a32[5] - a32[6] - a32[7]; - /* 0 0 1 1 0 -1 -1 -1 */ -- t[2] = 0 + a32[2] + a32[3] - a32[5] - a32[6] - a32[7]; - /* -1 -1 0 2 2 1 0 -1 */ -- t[3] = 0 - a32[0] - a32[1] + 2 * a32[3] + 2 * a32[4] + a32[5] - a32[7]; - /* 0 -1 -1 0 2 2 1 0 */ -- t[4] = 0 - a32[1] - a32[2] + 2 * a32[4] + 2 * a32[5] + a32[6]; - /* 0 0 -1 -1 0 2 2 1 */ -- t[5] = 0 - a32[2] - a32[3] + 2 * a32[5] + 2 * a32[6] + a32[7]; - /* -1 -1 0 0 0 1 3 2 */ -- t[6] = 0 - a32[0] - a32[1] + a32[5] + 3 * a32[6] + 2 * a32[7]; - /* 1 0 -1 -1 -1 -1 0 3 */ -- t[7] = 0 + a32[0] - a32[2] - a32[3] - a32[4] - a32[5] + 3 * a32[7]; -+ //t[0] = 0 + a32[0] + a32[1] - a32[3] - a32[4] - a32[5] - a32[6] ; -+ //t[1] = 0 + a32[1] + a32[2] - a32[4] - a32[5] - a32[6] - a32[7] ; -+ //t[2] = 0 + a32[2] + a32[3] - a32[5] - a32[6] - a32[7] ; -+ //t[3] = 0 - a32[0] - a32[1] + 2*a32[3] + 2*a32[4] + a32[5] - a32[7] ; -+ //t[4] = 0 - a32[1] - a32[2] + 2*a32[4] + 2*a32[5] + a32[6] ; -+ //t[5] = 0 - a32[2] - a32[3] + 2*a32[5] + 2*a32[6] + a32[7] ; -+ //t[6] = 0 - a32[0] - a32[1] + a32[5] + 3*a32[6] + 2*a32[7]; -+ //t[7] = 0 + a32[0] - a32[2] - a32[3] - a32[4] - a32[5] + 3*a32[7]; -+ -+#define A32 (int64_t)a32 -+ a32 = a[0]; -+ a32 |= a[1] << 26; -+ t[0] = 0 + A32; -+ t[3] = 0 - A32; -+ t[6] = 0 - A32; -+ t[7] = 0 + A32; -+ -+ a32 = (sp_digit)(a[1] >> 6); -+ a32 |= a[2] << 20; -+ t[0] += A32 ; -+ t[1] = 0 + A32; -+ t[3] -= A32 ; -+ t[4] = 0 - A32; -+ t[6] -= A32 ; -+ -+ a32 = (sp_digit)(a[2] >> 12); -+ a32 |= a[3] << 14; -+ t[1] += A32 ; -+ t[2] = 0 + A32; -+ t[4] -= A32 ; -+ t[5] = 0 - A32; -+ t[7] -= A32 ; -+ -+ a32 = (sp_digit)(a[3] >> 18); -+ a32 |= a[4] << 8; -+ t[0] -= A32 ; -+ t[2] += A32 ; -+ t[3] += 2*A32; -+ t[5] -= A32 ; -+ t[7] -= A32 ; -+ -+ a32 = (sp_digit)(a[4] >> 24); -+ a32 |= a[5] << 2; -+ a32 |= a[6] << 28; -+ t[0] -= A32 ; -+ t[1] -= A32 ; -+ t[3] += 2*A32; -+ t[4] += 2*A32; -+ t[7] -= A32 ; -+ -+ a32 = (sp_digit)(a[6] >> 4); -+ a32 |= a[7] << 22; -+ t[0] -= A32 ; -+ t[1] -= A32 ; -+ t[2] -= A32 ; -+ t[3] += A32 ; -+ t[4] += 2*A32; -+ t[5] += 2*A32; -+ t[6] += A32 ; -+ t[7] -= A32 ; -+ -+ a32 = (sp_digit)(a[7] >> 10); -+ a32 |= a[8] << 16; -+ t[0] -= A32 ; -+ t[1] -= A32 ; -+ t[2] -= A32 ; -+ t[4] += A32 ; -+ t[5] += 2*A32; -+ t[6] += 3*A32; -+ -+ a32 = (sp_digit)(a[8] >> 16); -+ a32 |= a[9] << 10; -+ t[1] -= A32 ; -+ t[2] -= A32 ; -+ t[3] -= A32 ; -+ t[5] += A32 ; -+ t[6] += 2*A32; -+ t[7] += 3*A32; -+#undef A32 - - t[1] += t[0] >> 32; t[0] &= 0xffffffff; - t[2] += t[1] >> 32; t[1] &= 0xffffffff; -- cgit v1.2.3-55-g6feb From 840ae696157ae271417953916de861e48a800e2b Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Tue, 27 Apr 2021 13:31:26 +0200 Subject: tls: shrink sp_256_mod_mul_norm_10 more function old new delta sp_256_mod_mul_norm_10 1439 1305 -134 Signed-off-by: Denys Vlasenko --- networking/tls_sp_c32.c | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/networking/tls_sp_c32.c b/networking/tls_sp_c32.c index c5e887aad..2b1ae1496 100644 --- a/networking/tls_sp_c32.c +++ b/networking/tls_sp_c32.c @@ -557,24 +557,24 @@ static void sp_256_mod_mul_norm_10(sp_digit* r, const sp_digit* a) t[3] -= o; t[6] -= o; t[7] += o; - t[1] += t[0] >> 32; t[0] &= 0xffffffff; - t[2] += t[1] >> 32; t[1] &= 0xffffffff; - t[3] += t[2] >> 32; t[2] &= 0xffffffff; - t[4] += t[3] >> 32; t[3] &= 0xffffffff; - t[5] += t[4] >> 32; t[4] &= 0xffffffff; - t[6] += t[5] >> 32; t[5] &= 0xffffffff; - t[7] += t[6] >> 32; t[6] &= 0xffffffff; - - r[0] = 0x3ffffff & ((sp_digit)(t[0])); - r[1] = 0x3ffffff & ((sp_digit)(t[0] >> 26) | ((sp_digit)t[1] << 6)); - r[2] = 0x3ffffff & ((sp_digit)(t[1] >> 20) | ((sp_digit)t[2] << 12)); - r[3] = 0x3ffffff & ((sp_digit)(t[2] >> 14) | ((sp_digit)t[3] << 18)); - r[4] = 0x3ffffff & ((sp_digit)(t[3] >> 8) | ((sp_digit)t[4] << 24)); - r[5] = 0x3ffffff & ((sp_digit)t[4] >> 2); /* small shift, ok to cast t[4] to narrower type */ - r[6] = 0x3ffffff & ((sp_digit)(t[4] >> 28) | ((sp_digit)t[5] << 4)); - r[7] = 0x3ffffff & ((sp_digit)(t[5] >> 22) | ((sp_digit)t[6] << 10)); - r[8] = 0x3ffffff & ((sp_digit)(t[6] >> 16) | ((sp_digit)t[7] << 16)); - r[9] = ((sp_digit)(t[7] >> 10)); + t[1] += t[0] >> 32; //t[0] &= 0xffffffff; + t[2] += t[1] >> 32; //t[1] &= 0xffffffff; + t[3] += t[2] >> 32; //t[2] &= 0xffffffff; + t[4] += t[3] >> 32; //t[3] &= 0xffffffff; + t[5] += t[4] >> 32; //t[4] &= 0xffffffff; + t[6] += t[5] >> 32; //t[5] &= 0xffffffff; + t[7] += t[6] >> 32; //t[6] &= 0xffffffff; - (uint32_t)t[i] casts below accomplish masking + + r[0] = 0x3ffffff & ((sp_digit)((uint32_t)t[0])); + r[1] = 0x3ffffff & ((sp_digit)((uint32_t)t[0] >> 26) | ((sp_digit)t[1] << 6)); + r[2] = 0x3ffffff & ((sp_digit)((uint32_t)t[1] >> 20) | ((sp_digit)t[2] << 12)); + r[3] = 0x3ffffff & ((sp_digit)((uint32_t)t[2] >> 14) | ((sp_digit)t[3] << 18)); + r[4] = 0x3ffffff & ((sp_digit)((uint32_t)t[3] >> 8) | ((sp_digit)t[4] << 24)); + r[5] = 0x3ffffff & ((sp_digit)((uint32_t)t[4] >> 2)); + r[6] = 0x3ffffff & ((sp_digit)((uint32_t)t[4] >> 28) | ((sp_digit)t[5] << 4)); + r[7] = 0x3ffffff & ((sp_digit)((uint32_t)t[5] >> 22) | ((sp_digit)t[6] << 10)); + r[8] = 0x3ffffff & ((sp_digit)((uint32_t)t[6] >> 16) | ((sp_digit)t[7] << 16)); + r[9] = ((sp_digit)((uint32_t)t[7] >> 10)); } /* Map the Montgomery form projective co-ordinate point to an affine point. -- cgit v1.2.3-55-g6feb From 81f9a0035b857206ac03afb729be3c8438f218b9 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Tue, 27 Apr 2021 18:48:43 +0200 Subject: tls: tweak sp_256_ecc_gen_k_10 for smaller code function old new delta curve_P256_compute_pubkey_and_premaster 194 191 -3 Signed-off-by: Denys Vlasenko --- networking/tls_sp_c32.c | 7 ------- 1 file changed, 7 deletions(-) diff --git a/networking/tls_sp_c32.c b/networking/tls_sp_c32.c index 2b1ae1496..5a84852a5 100644 --- a/networking/tls_sp_c32.c +++ b/networking/tls_sp_c32.c @@ -859,13 +859,11 @@ static void sp_ecc_secret_gen_256(const sp_digit priv[10], const uint8_t *pub2x3 /* Generates a scalar that is in the range 1..order-1. */ #define SIMPLIFY 1 /* Add 1 to a. (a = a + 1) */ -#if !SIMPLIFY static void sp_256_add_one_10(sp_digit* a) { a[0]++; sp_256_norm_10(a); } -#endif static void sp_256_ecc_gen_k_10(sp_digit k[10]) { #if !SIMPLIFY @@ -896,12 +894,7 @@ static void sp_256_ecc_gen_k_10(sp_digit k[10]) break; #endif } -#if !SIMPLIFY sp_256_add_one_10(k); -#else - if (k[0] == 0) - k[0] = 1; -#endif #undef SIMPLIFY } -- cgit v1.2.3-55-g6feb From 7a8ceb4eb25f1b136bf9a79b04d46dc4d7f440a7 Mon Sep 17 00:00:00 2001 From: Ron Yorston Date: Sun, 25 Apr 2021 11:51:55 +0100 Subject: vi: changes to line addresses for colon commands Make line addresses behave more like vi: - Vi allows the user to enter an arbitrary number of addresses, though only the last two are used. This simplifies get_address() by reducing the amount of state that needs to be carried. - When a command requires a single address the last one entered is used. - If addresses are separated by a ';' instead of a ',' the current line is updated to the left address. This may be useful when a search is used to specify a range, e.g. ':/first/;/last/d'. - When the last address is empty it should refer to the current line. function old new delta colon 3855 3834 -21 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 0/1 up/down: 0/-21) Total: -21 bytes Signed-off-by: Ron Yorston Signed-off-by: Denys Vlasenko --- editors/vi.c | 110 ++++++++++++++++++++++++++++++++--------------------------- 1 file changed, 60 insertions(+), 50 deletions(-) diff --git a/editors/vi.c b/editors/vi.c index caf01acd3..77c42641e 100644 --- a/editors/vi.c +++ b/editors/vi.c @@ -2473,37 +2473,43 @@ static char *get_one_address(char *p, int *result) // get colon addr, if present return p; } -# define GET_FIRST 0 -# define GET_SECOND 1 -# define GOT_FIRST 2 -# define GOT_SECOND 3 -# define GOT 2 +# define GET_ADDRESS 0 +# define GET_SEPARATOR 1 -static char *get_address(char *p, int *b, int *e) // get two colon addrs, if present +// Read line addresses for a colon command. The user can enter as +// many as they like but only the last two will be used. +static char *get_address(char *p, int *b, int *e) { - int state = GET_FIRST; + int state = GET_ADDRESS; + char *save_dot = dot; //----- get the address' i.e., 1,3 'a,'b ----- for (;;) { if (isblank(*p)) { p++; - } else if (*p == '%' && state == GET_FIRST) { // alias for 1,$ + } else if (*p == '%' && state == GET_ADDRESS) { // alias for 1,$ p++; *b = 1; *e = count_lines(text, end-1); - state = GOT_SECOND; - } else if (*p == ',' && state == GOT_FIRST) { + state = GET_SEPARATOR; + } else if (state == GET_SEPARATOR && (*p == ',' || *p == ';')) { + if (*p == ';') + dot = find_line(*e); p++; - state = GET_SECOND; - } else if (state == GET_FIRST || state == GET_SECOND) { - p = get_one_address(p, state == GET_FIRST ? b : e); + *b = *e; + state = GET_ADDRESS; + } else if (state == GET_ADDRESS) { + p = get_one_address(p, e); if (p == NULL) break; - state |= GOT; + state = GET_SEPARATOR; } else { + if (state == GET_SEPARATOR && *e < 0) + *e = count_lines(text, dot); break; } } + dot = save_dot; return p; } @@ -2637,8 +2643,6 @@ static void colon(char *buf) li = i = 0; b = e = -1; - q = text; // assume 1,$ for the range - r = end - 1; li = count_lines(text, end - 1); fn = current_filename; @@ -2673,27 +2677,33 @@ static void colon(char *buf) useforce = TRUE; *buf1 = '\0'; // get rid of ! } - if (b >= 0) { - // if there is only one addr, then the addr - // is the line number of the single line the - // user wants. So, reset the end - // pointer to point at end of the "b" line - q = find_line(b); // what line is #b - r = end_line(q); - li = 1; - } - if (e >= 0) { - // we were given two addrs. change the - // end pointer to the addr given by user. - r = find_line(e); // what line is #e - r = end_line(r); - li = e - b + 1; + // assume the command will want a range, certain commands + // (read, substitute) need to adjust these assumptions + if (e < 0) { + q = text; // no addr, use 1,$ for the range + r = end - 1; + } else { + // at least one addr was given, get its details + q = r = find_line(e); + if (b < 0) { + // if there is only one addr, then it's the line + // number of the single line the user wants. + // Reset the end pointer to the end of that line. + r = end_line(q); + li = 1; + } else { + // we were given two addrs. change the + // start pointer to the addr given by user. + q = find_line(b); // what line is #b + r = end_line(r); + li = e - b + 1; + } } // ------------ now look for the command ------------ i = strlen(cmd); if (i == 0) { // :123CR goto line #123 - if (b >= 0) { - dot = find_line(b); // what line is #b + if (e >= 0) { + dot = find_line(e); // what line is #e dot_skip_over_ws(); } } @@ -2711,12 +2721,12 @@ static void colon(char *buf) } # endif else if (cmd[0] == '=' && !cmd[1]) { // where is the address - if (b < 0) { // no addr given- use defaults - b = e = count_lines(text, dot); + if (e < 0) { // no addr given- use defaults + e = count_lines(text, dot); } - status_line("%d", b); + status_line("%d", e); } else if (strncmp(cmd, "delete", i) == 0) { // delete lines - if (b < 0) { // no addr given- use defaults + if (e < 0) { // no addr given- use defaults q = begin_line(dot); // assume .,. for the range r = end_line(dot); } @@ -2767,7 +2777,7 @@ static void colon(char *buf) li, (int)(end - text) ); } else if (strncmp(cmd, "file", i) == 0) { // what File is this - if (b != -1 || e != -1) { + if (e >= 0) { status_line_bold("No address allowed on this command"); goto ret; } @@ -2787,7 +2797,7 @@ static void colon(char *buf) rawmode(); Hit_Return(); } else if (strncmp(cmd, "list", i) == 0) { // literal print line - if (b < 0) { // no addr given- use defaults + if (e < 0) { // no addr given- use defaults q = begin_line(dot); // assume .,. for the range r = end_line(dot); } @@ -2861,12 +2871,12 @@ static void colon(char *buf) status_line_bold("No filename given"); goto ret; } - if (b < 0) { // no addr given- use defaults - q = begin_line(dot); // assume "dot" - } - // read after current line- unless user said ":0r foo" - if (b != 0) { - q = next_line(q); + if (e < 0) { // no addr given- read after current line + q = begin_line(dot); + } else if (e == 0) { // user said ":0r foo" + q = text; + } else { // addr given- read after that line + q = next_line(find_line(e)); // read after last line if (q == end-1) ++q; @@ -2969,13 +2979,13 @@ static void colon(char *buf) } len_R = strlen(R); - q = begin_line(q); - if (b < 0) { // maybe :s/foo/bar/ + if (e < 0) { // no addr given q = begin_line(dot); // start with cur line - b = count_lines(text, q); // cur line number + r = end_line(dot); + b = e = count_lines(text, q); // cur line number + } else if (b < 0) { // one addr given + b = e; } - if (e < 0) - e = b; // maybe :.s/foo/bar/ for (i = b; i <= e; i++) { // so, :20,23 s \0 find \0 replace \0 char *ls = q; // orig line start -- cgit v1.2.3-55-g6feb From 3b9233f05fc82029529f74fdce0e453d7fb73997 Mon Sep 17 00:00:00 2001 From: Ron Yorston Date: Sun, 25 Apr 2021 11:52:25 +0100 Subject: vi: adjust conditional compilation of modifying_cmds Since commit 74d565ff1 (vi: make context marks more like vi) the list of commands that modify the text is no longer required when FEATURE_VI_YANKMARK is enabled, only FEATURE_VI_DOT_CMD. Signed-off-by: Ron Yorston Signed-off-by: Denys Vlasenko --- editors/vi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/editors/vi.c b/editors/vi.c index 77c42641e..d818127e2 100644 --- a/editors/vi.c +++ b/editors/vi.c @@ -249,7 +249,7 @@ enum { //#define ESC_CURSOR_UP ESC"[A" //#define ESC_CURSOR_DOWN "\n" -#if ENABLE_FEATURE_VI_DOT_CMD || ENABLE_FEATURE_VI_YANKMARK +#if ENABLE_FEATURE_VI_DOT_CMD // cmds modifying text[] static const char modifying_cmds[] ALIGN1 = "aAcCdDiIJoOpPrRs""xX<>~"; #endif -- cgit v1.2.3-55-g6feb From 09172582daa98f575a711de2f0e3cf3bf88b8346 Mon Sep 17 00:00:00 2001 From: Ron Yorston Date: Sun, 25 Apr 2021 11:52:55 +0100 Subject: vi: saving unnamed file in readonly mode Suppose vi is started with the command 'vi -R', that is, in readonly mode with no filename. Attempting to save the file with 'ZZ' or ':w' results in the message: '(null)' is read only Skip the code which prints this if no filename was provided, thus falling through to file_write() which gives the more helpful message 'No current filename'. function old new delta colon 3867 3874 +7 do_cmd 4668 4673 +5 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 2/0 up/down: 12/0) Total: 12 bytes Signed-off-by: Ron Yorston Signed-off-by: Denys Vlasenko --- editors/vi.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/editors/vi.c b/editors/vi.c index d818127e2..a38f2189d 100644 --- a/editors/vi.c +++ b/editors/vi.c @@ -3054,7 +3054,7 @@ static void colon(char *buf) fn = args; } # if ENABLE_FEATURE_VI_READONLY - else if (readonly_mode && !useforce) { + else if (readonly_mode && !useforce && fn) { status_line_bold("'%s' is read only", fn); goto ret; } @@ -3996,7 +3996,7 @@ static void do_cmd(int c) break; } if (modified_count) { - if (ENABLE_FEATURE_VI_READONLY && readonly_mode) { + if (ENABLE_FEATURE_VI_READONLY && readonly_mode && current_filename) { status_line_bold("'%s' is read only", current_filename); break; } -- cgit v1.2.3-55-g6feb From b9aaa375a3acd83eeca8721d925bca67398bd3af Mon Sep 17 00:00:00 2001 From: Ron Yorston Date: Sun, 25 Apr 2021 11:53:23 +0100 Subject: vi: 'ZZ' should warn if there are more files to edit When 'ZZ' was used to save the current file and more files were available to edit BusyBox vi immediately moved on to the next file. The correct behaviour is to issue a warning. function old new delta do_cmd 4673 4724 +51 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 1/0 up/down: 51/0) Total: 51 bytes Signed-off-by: Ron Yorston Signed-off-by: Denys Vlasenko --- editors/vi.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/editors/vi.c b/editors/vi.c index a38f2189d..7de55d1e6 100644 --- a/editors/vi.c +++ b/editors/vi.c @@ -4010,6 +4010,14 @@ static void do_cmd(int c) } else { editing = 0; } + // are there other files to edit? + j = cmdline_filecnt - optind - 1; + if (editing == 0 && j > 0) { + editing = 1; + modified_count = 0; + last_modified_count = -1; + status_line_bold("%u more file(s) to edit", j); + } break; case '^': // ^- move to first non-blank on line dot_begin(); -- cgit v1.2.3-55-g6feb From e6bc8a29a9f5e679f5c2f8e1ab3541dc99752350 Mon Sep 17 00:00:00 2001 From: Ron Yorston Date: Sun, 25 Apr 2021 11:53:54 +0100 Subject: vi: preserve state when switching file When a new file is opened from an existing editing session the following details should be preserved: - the last command used; - the last character searched for on a line. function old new delta edit_file 849 835 -14 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 0/1 up/down: 0/-14) Total: -14 bytes Signed-off-by: Ron Yorston Signed-off-by: Denys Vlasenko --- editors/vi.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/editors/vi.c b/editors/vi.c index 7de55d1e6..8d9d04a88 100644 --- a/editors/vi.c +++ b/editors/vi.c @@ -4462,7 +4462,6 @@ static void edit_file(char *fn) mark[26] = mark[27] = text; // init "previous context" #endif - last_search_char = '\0'; #if ENABLE_FEATURE_VI_CRASHME last_input_char = '\0'; #endif @@ -4489,7 +4488,6 @@ static void edit_file(char *fn) #if ENABLE_FEATURE_VI_DOT_CMD free(ioq_start); ioq_start = NULL; - lmc_len = 0; adding2q = 0; #endif -- cgit v1.2.3-55-g6feb From dadd90974639c0b8cb0561eb946746ca2678b5fb Mon Sep 17 00:00:00 2001 From: Ron Yorston Date: Sun, 25 Apr 2021 11:54:24 +0100 Subject: vi: improvements to ':read' command Improvements to ':read': - When a file is read into the current buffer the cursor should be placed on the first line read. - If invoked without supplying a filename the current filename should be used. This is similar to how ':edit' works. - The code for ':edit' included an explicit check that the current filename was non-empty. Both vim and traditional vi accept non-empty filenames, only issuing an error message when an attempt to use such a name fails. - Allow undo of a file read. function old new delta file_insert 367 382 +15 colon 3841 3848 +7 .rodata 105236 105218 -18 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 2/1 up/down: 22/-18) Total: 4 bytes Signed-off-by: Ron Yorston Signed-off-by: Denys Vlasenko --- editors/vi.c | 30 +++++++++++++++++------------- 1 file changed, 17 insertions(+), 13 deletions(-) diff --git a/editors/vi.c b/editors/vi.c index 8d9d04a88..dd22eb45b 100644 --- a/editors/vi.c +++ b/editors/vi.c @@ -2007,6 +2007,11 @@ static int file_insert(const char *fn, char *p, int initial) p = text_hole_delete(p + cnt, p + size - 1, NO_UNDO); status_line_bold("can't read '%s'", fn); } +# if ENABLE_FEATURE_VI_UNDO + else { + undo_push_insert(p, size, ALLOW_UNDO); + } +# endif fi: close(fd); @@ -2743,10 +2748,7 @@ static void colon(char *buf) if (args[0]) { // the user supplied a file name fn = args; - } else if (current_filename && current_filename[0]) { - // no user supplied name- use the current filename - // fn = current_filename; was set by default - } else { + } else if (current_filename == NULL) { // no user file name, no current name- punt status_line_bold("No current filename"); goto ret; @@ -2864,11 +2866,14 @@ static void colon(char *buf) } editing = 0; } else if (strncmp(cmd, "read", i) == 0) { // read file into text[] - int size; + int size, num; - fn = args; - if (!fn[0]) { - status_line_bold("No filename given"); + if (args[0]) { + // the user supplied a file name + fn = args; + } else if (current_filename == NULL) { + // no user file name, no current name- punt + status_line_bold("No current filename"); goto ret; } if (e < 0) { // no addr given- read after current line @@ -2881,6 +2886,9 @@ static void colon(char *buf) if (q == end-1) ++q; } + num = count_lines(text, q); + if (q == end) + num++; { // dance around potentially-reallocated text[] uintptr_t ofs = q - text; size = file_insert(fn, q, 0); @@ -2897,11 +2905,7 @@ static void colon(char *buf) IF_FEATURE_VI_READONLY((readonly_mode ? " [Readonly]" : ""),) li, size ); - if (size > 0) { - // if the insert is before "dot" then we need to update - if (q <= dot) - dot += size; - } + dot = find_line(num); } else if (strncmp(cmd, "rewind", i) == 0) { // rewind cmd line args if (modified_count && !useforce) { status_line_bold("No write since last change (:%s! overrides)", cmd); -- cgit v1.2.3-55-g6feb From 852ffbee341ccbcdb6400ad5cb4688b410e236b5 Mon Sep 17 00:00:00 2001 From: Ron Yorston Date: Sun, 25 Apr 2021 11:55:01 +0100 Subject: vi: fix buffer overrun; code shrink It was possible for get_input_line() to store its NUL terminator one character beyond the end of its buffer. Code shrink in colon(): - Certain colon commands can be matched exactly, as any shorter string would be matched earlier, e.g. ':wq' versus ':write'. - Command matching is now case sensitive so there's no need to check for 'N' or 'Q' suffixes. - Rewrite how commands and arguments are split. function old new delta colon 3848 3751 -97 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 0/1 up/down: 0/-97) Total: -97 bytes Signed-off-by: Ron Yorston Signed-off-by: Denys Vlasenko --- editors/vi.c | 53 ++++++++++++++++++++++------------------------------- 1 file changed, 22 insertions(+), 31 deletions(-) diff --git a/editors/vi.c b/editors/vi.c index dd22eb45b..715961019 100644 --- a/editors/vi.c +++ b/editors/vi.c @@ -1191,7 +1191,7 @@ static char *get_input_line(const char *prompt) write1(prompt); // write out the :, /, or ? prompt i = strlen(buf); - while (i < MAX_INPUT_LEN) { + while (i < MAX_INPUT_LEN - 1) { c = get_one_char(); if (c == '\n' || c == '\r' || c == 27) break; // this is end of input @@ -2572,7 +2572,7 @@ static void colon(char *buf) if (cnt == 0) return; if (strncmp(p, "quit", cnt) == 0 - || strncmp(p, "q!", cnt) == 0 + || strcmp(p, "q!") == 0 ) { if (modified_count && p[1] != '!') { status_line_bold("No write since last change (:%s! overrides)", p); @@ -2582,8 +2582,8 @@ static void colon(char *buf) return; } if (strncmp(p, "write", cnt) == 0 - || strncmp(p, "wq", cnt) == 0 - || strncmp(p, "wn", cnt) == 0 + || strcmp(p, "wq") == 0 + || strcmp(p, "wn") == 0 || (p[0] == 'x' && !p[1]) ) { if (modified_count != 0 || p[0] != 'x') { @@ -2601,7 +2601,6 @@ static void colon(char *buf) ); if (p[0] == 'x' || p[1] == 'q' || p[1] == 'n' - || p[1] == 'Q' || p[1] == 'N' ) { editing = 0; } @@ -2621,10 +2620,9 @@ static void colon(char *buf) #else char c, *buf1, *q, *r; - char *fn, cmd[MAX_INPUT_LEN], args[MAX_INPUT_LEN]; + char *fn, cmd[MAX_INPUT_LEN], *cmdend, *args; int i, l, li, b, e; int useforce; - char *orig_buf; // :3154 // if (-e line 3154) goto it else stay put // :4,33w! foo // write a portion of buffer to file "foo" @@ -2652,35 +2650,29 @@ static void colon(char *buf) fn = current_filename; // look for optional address(es) :. :1 :1,9 :'q,'a :% - orig_buf = buf; + buf1 = buf; buf = get_address(buf, &b, &e); if (buf == NULL) { - status_line_bold("Bad address: %s", orig_buf); + status_line_bold("Bad address: %s", buf1); goto ret; } -# if ENABLE_FEATURE_VI_SEARCH || ENABLE_FEATURE_ALLOW_EXEC - // remember orig command line - orig_buf = buf; -# endif - // get the COMMAND into cmd[] + strcpy(cmd, buf); buf1 = cmd; - while (*buf != '\0') { - if (isspace(*buf)) - break; - *buf1++ = *buf++; + while (!isspace(*buf1) && *buf1 != '\0') { + buf1++; } - *buf1 = '\0'; + cmdend = buf1; // get any ARGuments - while (isblank(*buf)) - buf++; - strcpy(args, buf); + while (isblank(*buf1)) + buf1++; + args = buf1; + *cmdend = '\0'; useforce = FALSE; - buf1 = last_char_is(cmd, '!'); - if (buf1) { + if (cmdend > cmd && cmdend[-1] == '!') { useforce = TRUE; - *buf1 = '\0'; // get rid of ! + cmdend[-1] = '\0'; // get rid of ! } // assume the command will want a range, certain commands // (read, substitute) need to adjust these assumptions @@ -2718,7 +2710,7 @@ static void colon(char *buf) // :!ls run the go_bottom_and_clear_to_eol(); cookmode(); - retcode = system(orig_buf + 1); // run the cmd + retcode = system(buf + 1); // run the cmd if (retcode) printf("\nshell returned %i\n\n", retcode); rawmode(); @@ -2969,8 +2961,8 @@ static void colon(char *buf) // F points to the "find" pattern // R points to the "replace" pattern // replace the cmd line delimiters "/" with NULs - c = orig_buf[1]; // what is the delimiter - F = orig_buf + 2; // start of "find" + c = buf[1]; // what is the delimiter + F = buf + 2; // start of "find" R = strchr(F, c); // middle delimiter if (!R) goto colon_s_fail; @@ -3039,8 +3031,8 @@ static void colon(char *buf) } else if (strncmp(cmd, "version", i) == 0) { // show software version status_line(BB_VER); } else if (strncmp(cmd, "write", i) == 0 // write text to file - || strncmp(cmd, "wq", i) == 0 - || strncmp(cmd, "wn", i) == 0 + || strcmp(cmd, "wq") == 0 + || strcmp(cmd, "wn") == 0 || (cmd[0] == 'x' && !cmd[1]) ) { int size; @@ -3096,7 +3088,6 @@ static void colon(char *buf) } if (cmd[0] == 'x' || cmd[1] == 'q' || cmd[1] == 'n' - || cmd[1] == 'Q' || cmd[1] == 'N' ) { editing = 0; } -- cgit v1.2.3-55-g6feb From acd3079fd1be1b350ab3f75338de67ad1e933024 Mon Sep 17 00:00:00 2001 From: Ron Yorston Date: Sun, 25 Apr 2021 11:55:42 +0100 Subject: vi: expand '%' and '#' in colon commands Track the current and alternate filenames. The placeholders '%' and '#' can be used in arguments to colon commands to represent the current and alternate filenames respectively. Backslash can be used to allow literal '%' and '#' characters to be entered. This feature is controlled by the configuration option FEATURE_VI_COLON_EXPAND. function old new delta expand_args - 198 +198 colon 3751 3927 +176 update_filename - 70 +70 init_filename - 48 +48 .rodata 105218 105239 +21 get_one_char 115 124 +9 edit_file 835 838 +3 do_cmd 4724 4727 +3 init_text_buffer 190 172 -18 ------------------------------------------------------------------------------ (add/remove: 3/0 grow/shrink: 5/1 up/down: 528/-18) Total: 510 bytes Signed-off-by: Ron Yorston Signed-off-by: Denys Vlasenko --- editors/vi.c | 126 ++++++++++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 112 insertions(+), 14 deletions(-) diff --git a/editors/vi.c b/editors/vi.c index 715961019..6a879fa8a 100644 --- a/editors/vi.c +++ b/editors/vi.c @@ -53,6 +53,14 @@ //config: Enable a limited set of colon commands. This does not //config: provide an "ex" mode. //config: +//config:config FEATURE_VI_COLON_EXPAND +//config: bool "Expand \"%\" and \"#\" in colon commands" +//config: default y +//config: depends on FEATURE_VI_COLON +//config: help +//config: Expand the special characters \"%\" (current filename) +//config: and \"#\" (alternate filename) in colon commands. +//config: //config:config FEATURE_VI_YANKMARK //config: bool "Enable yank/put commands and mark cmds" //config: default y @@ -347,6 +355,9 @@ struct globals { // [don't make smallint!] int last_status_cksum; // hash of current status line char *current_filename; +#if ENABLE_FEATURE_VI_COLON_EXPAND + char *alt_filename; +#endif char *screenbegin; // index into text[], of top line on the screen char *screen; // pointer to the virtual screen buffer int screensize; // and its size @@ -471,6 +482,7 @@ struct globals { #define have_status_msg (G.have_status_msg ) #define last_status_cksum (G.last_status_cksum ) #define current_filename (G.current_filename ) +#define alt_filename (G.alt_filename ) #define screen (G.screen ) #define screensize (G.screensize ) #define screenbegin (G.screenbegin ) @@ -2198,6 +2210,41 @@ static char *char_insert(char *p, char c, int undo) // insert the char c at 'p' return p; } +#if ENABLE_FEATURE_VI_COLON_EXPAND +static void init_filename(char *fn) +{ + char *copy = xstrdup(fn); + + if (current_filename == NULL) { + current_filename = copy; + } else { + free(alt_filename); + alt_filename = copy; + } +} +#else +# define init_filename(f) ((void)(0)) +#endif + +static void update_filename(char *fn) +{ +#if ENABLE_FEATURE_VI_COLON_EXPAND + if (fn == NULL) + return; + + if (current_filename == NULL || strcmp(fn, current_filename) != 0) { + free(alt_filename); + alt_filename = current_filename; + current_filename = xstrdup(fn); + } +#else + if (fn != current_filename) { + free(current_filename); + current_filename = xstrdup(fn); + } +#endif +} + // read text from file or create an empty buf // will also update current_filename static int init_text_buffer(char *fn) @@ -2209,10 +2256,7 @@ static int init_text_buffer(char *fn) text_size = 10240; screenbegin = dot = end = text = xzalloc(text_size); - if (fn != current_filename) { - free(current_filename); - current_filename = xstrdup(fn); - } + update_filename(fn); rc = file_insert(fn, text, 1); if (rc < 0) { // file doesnt exist. Start empty buf with dummy line @@ -2556,6 +2600,43 @@ static void setops(char *args, int flg_no) } # endif +# if ENABLE_FEATURE_VI_COLON_EXPAND +static char *expand_args(char *args) +{ + char *s, *t; + const char *replace; + + args = xstrdup(args); + for (s = args; *s; s++) { + if (*s == '%') { + replace = current_filename; + } else if (*s == '#') { + replace = alt_filename; + } else { + if (*s == '\\' && s[1] != '\0') { + for (t = s++; *t; t++) + *t = t[1]; + } + continue; + } + + if (replace == NULL) { + free(args); + status_line_bold("No previous filename"); + return NULL; + } + + *s = '\0'; + t = xasprintf("%s%s%s", args, replace, s+1); + s = t + (s - args) + strlen(replace); + free(args); + args = t; + } + return args; +} +# else +# define expand_args(a) (a) +# endif #endif /* FEATURE_VI_COLON */ // buf must be no longer than MAX_INPUT_LEN! @@ -2620,7 +2701,7 @@ static void colon(char *buf) #else char c, *buf1, *q, *r; - char *fn, cmd[MAX_INPUT_LEN], *cmdend, *args; + char *fn, cmd[MAX_INPUT_LEN], *cmdend, *args, *exp = NULL; int i, l, li, b, e; int useforce; @@ -2708,9 +2789,12 @@ static void colon(char *buf) else if (cmd[0] == '!') { // run a cmd int retcode; // :!ls run the + exp = expand_args(buf + 1); + if (exp == NULL) + goto ret; go_bottom_and_clear_to_eol(); cookmode(); - retcode = system(buf + 1); // run the cmd + retcode = system(exp); // run the cmd if (retcode) printf("\nshell returned %i\n\n", retcode); rawmode(); @@ -2739,7 +2823,9 @@ static void colon(char *buf) } if (args[0]) { // the user supplied a file name - fn = args; + fn = exp = expand_args(args); + if (exp == NULL) + goto ret; } else if (current_filename == NULL) { // no user file name, no current name- punt status_line_bold("No current filename"); @@ -2763,7 +2849,7 @@ static void colon(char *buf) status_line("'%s'%s" IF_FEATURE_VI_READONLY("%s") " %uL, %uC", - current_filename, + fn, (size < 0 ? " [New file]" : ""), IF_FEATURE_VI_READONLY( ((readonly_mode) ? " [Readonly]" : ""), @@ -2777,8 +2863,10 @@ static void colon(char *buf) } if (args[0]) { // user wants a new filename - free(current_filename); - current_filename = xstrdup(args); + exp = expand_args(args); + if (exp == NULL) + goto ret; + update_filename(exp); } else { // user wants file status info last_status_cksum = 0; // force status update @@ -2862,7 +2950,10 @@ static void colon(char *buf) if (args[0]) { // the user supplied a file name - fn = args; + fn = exp = expand_args(args); + if (exp == NULL) + goto ret; + init_filename(fn); } else if (current_filename == NULL) { // no user file name, no current name- punt status_line_bold("No current filename"); @@ -3042,12 +3133,16 @@ static void colon(char *buf) if (args[0]) { struct stat statbuf; - if (!useforce && (fn == NULL || strcmp(fn, args) != 0) && - stat(args, &statbuf) == 0) { + exp = expand_args(args); + if (exp == NULL) + goto ret; + if (!useforce && (fn == NULL || strcmp(fn, exp) != 0) && + stat(exp, &statbuf) == 0) { status_line_bold("File exists (:w! overrides)"); goto ret; } - fn = args; + fn = exp; + init_filename(fn); } # if ENABLE_FEATURE_VI_READONLY else if (readonly_mode && !useforce && fn) { @@ -3109,6 +3204,9 @@ static void colon(char *buf) not_implemented(cmd); } ret: +# if ENABLE_FEATURE_VI_COLON_EXPAND + free(exp); +# endif dot = bound_dot(dot); // make sure "dot" is valid return; # if ENABLE_FEATURE_VI_SEARCH -- cgit v1.2.3-55-g6feb From b35eef5383a4e7a6fb60fcf3833654a0bb2245e0 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Wed, 28 Apr 2021 12:19:24 +0200 Subject: tls: code shrink in curve 25519 function old new delta curve25519 832 849 +17 curve_x25519_compute_pubkey_and_premaster 74 71 -3 static.basepoint9 32 - -32 ------------------------------------------------------------------------------ (add/remove: 0/1 grow/shrink: 1/1 up/down: 17/-35) Total: -18 bytes Signed-off-by: Denys Vlasenko --- networking/tls_fe.c | 46 +++++++++++++++++++++++++++------------------- 1 file changed, 27 insertions(+), 19 deletions(-) diff --git a/networking/tls_fe.c b/networking/tls_fe.c index e96b33225..ecb410281 100644 --- a/networking/tls_fe.c +++ b/networking/tls_fe.c @@ -108,26 +108,26 @@ static void raw_try_sub(byte *x, const byte *p) #if 0 //UNUSED static int prime_msb(const byte *p) { - int i; - byte x; - int shift = 1; - int z = F25519_SIZE - 1; - - /* - Test for any hot bits. - As soon as one instance is encountered set shift to 0. - */ + int i; + byte x; + int shift = 1; + int z = F25519_SIZE - 1; + + /* + Test for any hot bits. + As soon as one instance is encountered set shift to 0. + */ for (i = F25519_SIZE - 1; i >= 0; i--) { - shift &= ((shift ^ ((-p[i] | p[i]) >> 7)) & 1); - z -= shift; - } + shift &= ((shift ^ ((-p[i] | p[i]) >> 7)) & 1); + z -= shift; + } x = p[z]; z <<= 3; - shift = 1; - for (i = 0; i < 8; i++) { - shift &= ((-(x >> i) | (x >> i)) >> (7 - i) & 1); - z += shift; - } + shift = 1; + for (i = 0; i < 8; i++) { + shift &= ((-(x >> i) | (x >> i)) >> (7 - i) & 1); + z += shift; + } return z - 1; } @@ -549,6 +549,9 @@ static void curve25519(byte *result, const byte *e, const byte *q) int i; struct { + /* for bbox's special case of q == NULL meaning "use basepoint" */ + /*static const*/ uint8_t basepoint9[CURVE25519_KEYSIZE]; // = {9}; + /* from wolfssl-3.15.3/wolfssl/wolfcrypt/fe_operations.h */ /*static const*/ byte f25519_one[F25519_SIZE]; // = {1}; @@ -559,6 +562,7 @@ static void curve25519(byte *result, const byte *e, const byte *q) byte xm1[F25519_SIZE]; // = {1}; byte zm1[F25519_SIZE]; // = {0}; } z; +#define basepoint9 z.basepoint9 #define f25519_one z.f25519_one #define xm z.xm #define zm z.zm @@ -569,6 +573,11 @@ static void curve25519(byte *result, const byte *e, const byte *q) zm[0] = 1; xm1[0] = 1; + if (!q) { + basepoint9[0] = 9; + q = basepoint9; + } + /* Note: bit 254 is assumed to be 1 */ lm_copy(xm, q); @@ -606,7 +615,6 @@ void FAST_FUNC curve_x25519_compute_pubkey_and_premaster( uint8_t *pubkey, uint8_t *premaster, const uint8_t *peerkey32) { - static const uint8_t basepoint9[CURVE25519_KEYSIZE] ALIGN8 = {9}; uint8_t privkey[CURVE25519_KEYSIZE]; //[32] /* Generate random private key, see RFC 7748 */ @@ -615,7 +623,7 @@ void FAST_FUNC curve_x25519_compute_pubkey_and_premaster( privkey[CURVE25519_KEYSIZE-1] = ((privkey[CURVE25519_KEYSIZE-1] & 0x7f) | 0x40); /* Compute public key */ - curve25519(pubkey, privkey, basepoint9); + curve25519(pubkey, privkey, NULL /* "use base point of x25519" */); /* Compute premaster using peer's public key */ curve25519(premaster, privkey, peerkey32); -- cgit v1.2.3-55-g6feb From 0c42a6b072b48ff615e3960ad5829a2a117cc417 Mon Sep 17 00:00:00 2001 From: Ron Yorston Date: Thu, 29 Apr 2021 08:36:21 +0100 Subject: vi: fix empty line range regression Commit 7a8ceb4eb (vi: changes to line addresses for colon commands) was supposed to address the issue: When the last address is empty it should refer to the current line. This was intended to allow ranges of the form '1,' with an empty last address. It should have been expressed as: When the last address is empty *and the second last isn't* it should refer to the current line. Otherwise a command like ':w' only writes the current line resulting in serious loss of data. function old new delta colon 3906 3911 +5 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 1/0 up/down: 5/0) Total: 5 bytes Signed-off-by: Ron Yorston Signed-off-by: Denys Vlasenko --- editors/vi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/editors/vi.c b/editors/vi.c index 6a879fa8a..edcf84240 100644 --- a/editors/vi.c +++ b/editors/vi.c @@ -2553,7 +2553,7 @@ static char *get_address(char *p, int *b, int *e) break; state = GET_SEPARATOR; } else { - if (state == GET_SEPARATOR && *e < 0) + if (state == GET_SEPARATOR && *b >= 0 && *e < 0) *e = count_lines(text, dot); break; } -- cgit v1.2.3-55-g6feb From e71ea6c1f84318d8655a5783736288695174f596 Mon Sep 17 00:00:00 2001 From: Jeremy Lin Date: Wed, 28 Apr 2021 20:34:24 -0700 Subject: wget: allow HTTP 307/308 redirects This resolves failures like wget: server returned error: HTTP/1.1 307 Temporary Redirect Signed-off-by: Jeremy Lin Signed-off-by: Denys Vlasenko --- networking/wget.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/networking/wget.c b/networking/wget.c index 3edc5f870..6a9604421 100644 --- a/networking/wget.c +++ b/networking/wget.c @@ -1346,6 +1346,8 @@ However, in real world it was observed that some web servers case 301: case 302: case 303: + case 307: + case 308: break; case 206: /* Partial Content */ -- cgit v1.2.3-55-g6feb From a1a77ad5eae7384dd6b1ccaa436a1df48c3c9cd7 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Sat, 1 May 2021 11:54:08 +0200 Subject: udhcpc[6]: untangle "timeout" and "remaining lease"; reduce min lease to 30 seconds This allows to fix a problem that we wait for renew replies for up to half the lease (!!!) if they never come. Make it so that lease of 60 seconds is not "rounded up" to 120 seconds - set lower "sanity limit" to 30 seconds. After 3 failed renew attempts, switch to rebind. After this change, we can have more flexible choice of when to do the first renew - does not need to be equal to lease / 2. function old new delta udhcpc6_main 2568 2576 +8 .rodata 103339 103294 -45 udhcpc_main 2609 2550 -59 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 1/2 up/down: 8/-104) Total: -96 bytes Signed-off-by: Denys Vlasenko --- networking/udhcp/d6_dhcpc.c | 80 ++++++++++++---------------- networking/udhcp/dhcpc.c | 127 +++++++++++++++++++------------------------- 2 files changed, 89 insertions(+), 118 deletions(-) diff --git a/networking/udhcp/d6_dhcpc.c b/networking/udhcp/d6_dhcpc.c index 76b087b92..592f5b127 100644 --- a/networking/udhcp/d6_dhcpc.c +++ b/networking/udhcp/d6_dhcpc.c @@ -1220,7 +1220,7 @@ int udhcpc6_main(int argc UNUSED_PARAM, char **argv) uint32_t xid = 0; int packet_num; int timeout; /* must be signed */ - unsigned already_waited_sec; + int lease_remaining; /* must be signed */ unsigned opt; int retval; @@ -1348,19 +1348,16 @@ int udhcpc6_main(int argc UNUSED_PARAM, char **argv) change_listen_mode(LISTEN_RAW); packet_num = 0; timeout = 0; - already_waited_sec = 0; + lease_remaining = 0; /* Main event loop. select() waits on signal pipe and possibly * on sockfd. * "continue" statements in code below jump to the top of the loop. */ for (;;) { - int tv; struct pollfd pfds[2]; struct d6_packet packet; uint8_t *packet_end; - /* silence "uninitialized!" warning */ - unsigned timestamp_before_wait = timestamp_before_wait; //bb_error_msg("sockfd:%d, listen_mode:%d", client_data.sockfd, client_data.listen_mode); @@ -1373,17 +1370,24 @@ int udhcpc6_main(int argc UNUSED_PARAM, char **argv) udhcp_sp_fd_set(pfds, client_data.sockfd); - tv = timeout - already_waited_sec; retval = 0; /* If we already timed out, fall through with retval = 0, else... */ - if (tv > 0) { - log1("waiting %u seconds", tv); - timestamp_before_wait = (unsigned)monotonic_sec(); - retval = poll(pfds, 2, tv < INT_MAX/1000 ? tv * 1000 : INT_MAX); + if (timeout > 0) { + unsigned diff; + + if (timeout > INT_MAX/1000) + timeout = INT_MAX/1000; + log1("waiting %u seconds", timeout); + diff = (unsigned)monotonic_sec(); + retval = poll(pfds, 2, timeout * 1000); if (retval < 0) { /* EINTR? A signal was caught, don't panic */ if (errno == EINTR) { - already_waited_sec += (unsigned)monotonic_sec() - timestamp_before_wait; + diff = (unsigned)monotonic_sec() - diff; + lease_remaining -= diff; + if (lease_remaining < 0) + lease_remaining = 0; + timeout -= diff; continue; } /* Else: an error occured, panic! */ @@ -1410,9 +1414,6 @@ int udhcpc6_main(int argc UNUSED_PARAM, char **argv) memcpy(clientid_mac_ptr, client_data.client_mac, 6); - /* We will restart the wait in any case */ - already_waited_sec = 0; - switch (client_data.state) { case INIT_SELECTING: if (!discover_retries || packet_num < discover_retries) { @@ -1477,7 +1478,8 @@ int udhcpc6_main(int argc UNUSED_PARAM, char **argv) case RENEW_REQUESTED: /* manual (SIGUSR1) renew */ case_RENEW_REQUESTED: case RENEWING: - if (timeout >= 60) { + if (packet_num < 3) { + packet_num++; /* send an unicast renew request */ /* Sometimes observed to fail (EADDRNOTAVAIL) to bind * a new UDP socket for sending inside send_renew. @@ -1491,7 +1493,8 @@ int udhcpc6_main(int argc UNUSED_PARAM, char **argv) send_d6_info_request(xid); else send_d6_renew(xid, &srv6_buf, requested_ipv6); - timeout >>= 1; + timeout = discover_timeout; + /* ^^^ used to be = lease_remaining / 2 - WAY too long */ continue; } /* Timed out, enter rebinding state */ @@ -1503,12 +1506,12 @@ int udhcpc6_main(int argc UNUSED_PARAM, char **argv) change_listen_mode(LISTEN_RAW); /* Lease is *really* about to run out, * try to find DHCP server using broadcast */ - if (timeout > 0) { + if (lease_remaining > 0) { if (opt & OPT_l) send_d6_info_request(xid); else /* send a broadcast renew request */ send_d6_renew(xid, /*server_ipv6:*/ NULL, requested_ipv6); - timeout >>= 1; + timeout = discover_timeout; continue; } /* Timed out, enter init state */ @@ -1516,7 +1519,7 @@ int udhcpc6_main(int argc UNUSED_PARAM, char **argv) d6_run_script_no_option("deconfig"); client_data.state = INIT_SELECTING; client_data.first_secs = 0; /* make secs field count from 0 */ - /*timeout = 0; - already is */ + timeout = 0; packet_num = 0; continue; /* case RELEASED: */ @@ -1532,21 +1535,9 @@ int udhcpc6_main(int argc UNUSED_PARAM, char **argv) switch (udhcp_sp_read()) { case SIGUSR1: client_data.first_secs = 0; /* make secs field count from 0 */ - already_waited_sec = 0; perform_renew(); - if (client_data.state == RENEW_REQUESTED) { - /* We might be either on the same network - * (in which case renew might work), - * or we might be on a completely different one - * (in which case renew won't ever succeed). - * For the second case, must make sure timeout - * is not too big, or else we can send - * futile renew requests for hours. - */ - if (timeout > 60) - timeout = 60; + if (client_data.state == RENEW_REQUESTED) goto case_RENEW_REQUESTED; - } /* Start things over */ packet_num = 0; /* Kill any timeouts, user wants this to hurry along */ @@ -1579,10 +1570,6 @@ int udhcpc6_main(int argc UNUSED_PARAM, char **argv) sleep(discover_timeout); /* 3 seconds by default */ change_listen_mode(client_data.listen_mode); /* just close and reopen */ } - /* If this packet will turn out to be unrelated/bogus, - * we will go back and wait for next one. - * Be sure timeout is properly decreased. */ - already_waited_sec += (unsigned)monotonic_sec() - timestamp_before_wait; if (len < 0) continue; packet_end = (uint8_t*)&packet + len; @@ -1609,6 +1596,7 @@ int udhcpc6_main(int argc UNUSED_PARAM, char **argv) case RENEW_REQUESTED: case REBINDING: if (packet.d6_msg_type == D6_MSG_REPLY) { + unsigned start; uint32_t lease_seconds; struct d6_option *option; unsigned address_timeout; @@ -1631,7 +1619,6 @@ int udhcpc6_main(int argc UNUSED_PARAM, char **argv) requested_ipv6 = NULL; timeout = 0; packet_num = 0; - already_waited_sec = 0; continue; } option = d6_copy_option(packet.d6_options, packet_end, D6_OPT_SERVERID); @@ -1650,7 +1637,6 @@ int udhcpc6_main(int argc UNUSED_PARAM, char **argv) client_data.state = REQUESTING; timeout = 0; packet_num = 0; - already_waited_sec = 0; continue; } /* It's a D6_MSG_REPLY */ @@ -1814,21 +1800,26 @@ int udhcpc6_main(int argc UNUSED_PARAM, char **argv) address_timeout = prefix_timeout; if (!prefix_timeout) prefix_timeout = address_timeout; - /* note: "int timeout" will not overflow even with 0xffffffff inputs here: */ - timeout = (prefix_timeout < address_timeout ? prefix_timeout : address_timeout) / 2; + lease_remaining = (prefix_timeout < address_timeout ? prefix_timeout : address_timeout); + if (lease_remaining < 0) /* signed overflow? */ + lease_remaining = INT_MAX; if (opt & OPT_l) { /* TODO: request OPTION_INFORMATION_REFRESH_TIME (32) * and use its value instead of the default 1 day. */ - timeout = 24 * 60 * 60; + lease_remaining = 24 * 60 * 60; } /* paranoia: must not be too small */ - /* timeout > 60 - ensures at least one unicast renew attempt */ - if (timeout < 61) - timeout = 61; + if (lease_remaining < 30) + lease_remaining = 30; + /* enter bound state */ + start = monotonic_sec(); d6_run_script(packet.d6_options, packet_end, (client_data.state == REQUESTING ? "bound" : "renew")); + timeout = (unsigned)lease_remaining / 2; + timeout -= (unsigned)monotonic_sec() - start; + packet_num = 0; client_data.state = BOUND; change_listen_mode(LISTEN_NONE); @@ -1844,7 +1835,6 @@ int udhcpc6_main(int argc UNUSED_PARAM, char **argv) opt = ((opt & ~OPT_b) | OPT_f); } #endif - already_waited_sec = 0; continue; /* back to main loop */ } continue; diff --git a/networking/udhcp/dhcpc.c b/networking/udhcp/dhcpc.c index bbcbd1fca..a818c1875 100644 --- a/networking/udhcp/dhcpc.c +++ b/networking/udhcp/dhcpc.c @@ -1266,7 +1266,7 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv) uint32_t xid = xid; /* for compiler */ int packet_num; int timeout; /* must be signed */ - unsigned already_waited_sec; + int lease_remaining; /* must be signed */ unsigned opt; IF_FEATURE_UDHCPC_ARPING(unsigned arpping_ms;) int retval; @@ -1411,18 +1411,15 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv) change_listen_mode(LISTEN_RAW); packet_num = 0; timeout = 0; - already_waited_sec = 0; + lease_remaining = 0; /* Main event loop. select() waits on signal pipe and possibly * on sockfd. * "continue" statements in code below jump to the top of the loop. */ for (;;) { - int tv; struct pollfd pfds[2]; struct dhcp_packet packet; - /* silence "uninitialized!" warning */ - unsigned timestamp_before_wait = timestamp_before_wait; //bb_error_msg("sockfd:%d, listen_mode:%d", client_data.sockfd, client_data.listen_mode); @@ -1435,17 +1432,24 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv) udhcp_sp_fd_set(pfds, client_data.sockfd); - tv = timeout - already_waited_sec; retval = 0; /* If we already timed out, fall through with retval = 0, else... */ - if (tv > 0) { - log1("waiting %u seconds", tv); - timestamp_before_wait = (unsigned)monotonic_sec(); - retval = poll(pfds, 2, tv < INT_MAX/1000 ? tv * 1000 : INT_MAX); + if (timeout > 0) { + unsigned diff; + + if (timeout > INT_MAX/1000) + timeout = INT_MAX/1000; + log1("waiting %u seconds", timeout); + diff = (unsigned)monotonic_sec(); + retval = poll(pfds, 2, timeout * 1000); if (retval < 0) { /* EINTR? A signal was caught, don't panic */ if (errno == EINTR) { - already_waited_sec += (unsigned)monotonic_sec() - timestamp_before_wait; + diff = (unsigned)monotonic_sec() - diff; + lease_remaining -= diff; + if (lease_remaining < 0) + lease_remaining = 0; + timeout -= diff; continue; } /* Else: an error occurred, panic! */ @@ -1472,9 +1476,6 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv) if (clientid_mac_ptr) memcpy(clientid_mac_ptr, client_data.client_mac, 6); - /* We will restart the wait in any case */ - already_waited_sec = 0; - switch (client_data.state) { case INIT_SELECTING: if (!discover_retries || packet_num < discover_retries) { @@ -1536,7 +1537,8 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv) case RENEW_REQUESTED: /* manual (SIGUSR1) renew */ case_RENEW_REQUESTED: case RENEWING: - if (timeout >= 60) { + if (packet_num < 3) { + packet_num++; /* send an unicast renew request */ /* Sometimes observed to fail (EADDRNOTAVAIL) to bind * a new UDP socket for sending inside send_renew. @@ -1547,14 +1549,8 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv) * into INIT_SELECTING state. */ if (send_renew(xid, server_addr, requested_ip) >= 0) { - timeout >>= 1; -//TODO: the timeout to receive an answer for our renew should not be selected -//with "timeout = lease_seconds / 2; ...; timeout = timeout / 2": it is often huge. -//Waiting e.g. 4*3600 seconds for a reply does not make sense -//(if reply isn't coming, we keep an open socket for hours), -//it should be something like 10 seconds. -//Also, it's probably best to try sending renew in kernel mode a few (3-5) times -//and fall back to raw mode if it does not work. + timeout = discover_timeout; + /* ^^^ used to be = lease_remaining / 2 - WAY too long */ continue; } /* else: error sending. @@ -1563,6 +1559,8 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv) * which wasn't reachable (and probably did not exist). */ } +//TODO: if 3 renew's failed (no reply) but remaining lease is large, +//it might make sense to make a large pause (~1 hour?) and try later? /* Timed out or error, enter rebinding state */ log1s("entering rebinding state"); client_data.state = REBINDING; @@ -1572,10 +1570,10 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv) change_listen_mode(LISTEN_RAW); /* Lease is *really* about to run out, * try to find DHCP server using broadcast */ - if (timeout > 0) { + if (lease_remaining > 0) { /* send a broadcast renew request */ send_renew(xid, 0 /*INADDR_ANY*/, requested_ip); - timeout >>= 1; + timeout = discover_timeout; continue; } /* Timed out, enter init state */ @@ -1583,7 +1581,7 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv) udhcp_run_script(NULL, "deconfig"); client_data.state = INIT_SELECTING; client_data.first_secs = 0; /* make secs field count from 0 */ - /*timeout = 0; - already is */ + timeout = 0; packet_num = 0; continue; /* case RELEASED: */ @@ -1599,21 +1597,9 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv) switch (udhcp_sp_read()) { case SIGUSR1: client_data.first_secs = 0; /* make secs field count from 0 */ - already_waited_sec = 0; perform_renew(); - if (client_data.state == RENEW_REQUESTED) { - /* We might be either on the same network - * (in which case renew might work), - * or we might be on a completely different one - * (in which case renew won't ever succeed). - * For the second case, must make sure timeout - * is not too big, or else we can send - * futile renew requests for hours. - */ - if (timeout > 60) - timeout = 60; + if (client_data.state == RENEW_REQUESTED) goto case_RENEW_REQUESTED; - } /* Start things over */ packet_num = 0; /* Kill any timeouts, user wants this to hurry along */ @@ -1646,10 +1632,6 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv) sleep(discover_timeout); /* 3 seconds by default */ change_listen_mode(client_data.listen_mode); /* just close and reopen */ } - /* If this packet will turn out to be unrelated/bogus, - * we will go back and wait for next one. - * Be sure timeout is properly decreased. */ - already_waited_sec += (unsigned)monotonic_sec() - timestamp_before_wait; if (len < 0) continue; } @@ -1722,7 +1704,6 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv) client_data.state = REQUESTING; timeout = 0; packet_num = 0; - already_waited_sec = 0; } continue; case REQUESTING: @@ -1731,28 +1712,38 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv) case REBINDING: if (*message == DHCPACK) { unsigned start; - uint32_t lease_seconds; struct in_addr temp_addr; char server_str[sizeof("255.255.255.255")]; uint8_t *temp; + temp_addr.s_addr = server_addr; + strcpy(server_str, inet_ntoa(temp_addr)); + temp_addr.s_addr = packet.yiaddr; + temp = udhcp_get_option32(&packet, DHCP_LEASE_TIME); if (!temp) { - bb_simple_info_msg("no lease time with ACK, using 1 hour lease"); - lease_seconds = 60 * 60; + lease_remaining = 60 * 60; } else { + uint32_t lease; /* it IS unaligned sometimes, don't "optimize" */ - move_from_unaligned32(lease_seconds, temp); - lease_seconds = ntohl(lease_seconds); - /* paranoia: must not be too small and not prone to overflows */ - /* timeout > 60 - ensures at least one unicast renew attempt */ - if (lease_seconds < 2 * 61) - lease_seconds = 2 * 61; - //if (lease_seconds > 0x7fffffff) - // lease_seconds = 0x7fffffff; - //^^^not necessary since "timeout = lease_seconds / 2" - //does not overflow even for 0xffffffff. + move_from_unaligned32(lease, temp); + lease_remaining = ntohl(lease); } + /* Log message _before_ we sanitize lease */ + bb_info_msg("lease of %s obtained from %s, lease time %u%s", + inet_ntoa(temp_addr), server_str, (unsigned)lease_remaining, + temp ? "" : " (default)" + ); + /* paranoia: must not be too small and not prone to overflows */ + /* NB: 60s leases _are_ used in real world + * (temporary IPs while ISP modem initializes) + * do not break this case by bumplit it up. + */ + if (lease_remaining < 0) /* signed overflow? */ + lease_remaining = INT_MAX; + if (lease_remaining < 30) + lease_remaining = 30; + requested_ip = packet.yiaddr; #if ENABLE_FEATURE_UDHCPC_ARPING if (opt & OPT_a) { /* RFC 2131 3.1 paragraph 5: @@ -1764,7 +1755,7 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv) * address is already in use (e.g., through the use of ARP), * the client MUST send a DHCPDECLINE message to the server and restarts * the configuration process..." */ - if (!arpping(packet.yiaddr, + if (!arpping(requested_ip, NULL, (uint32_t) 0, client_data.client_mac, @@ -1783,27 +1774,18 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv) requested_ip = 0; timeout = tryagain_timeout; packet_num = 0; - already_waited_sec = 0; continue; /* back to main loop */ } } #endif - /* enter bound state */ - temp_addr.s_addr = server_addr; - strcpy(server_str, inet_ntoa(temp_addr)); - temp_addr.s_addr = packet.yiaddr; - bb_info_msg("lease of %s obtained from %s, lease time %u", - inet_ntoa(temp_addr), server_str, (unsigned)lease_seconds); - requested_ip = packet.yiaddr; + /* enter bound state */ start = monotonic_sec(); udhcp_run_script(&packet, client_data.state == REQUESTING ? "bound" : "renew"); - already_waited_sec = (unsigned)monotonic_sec() - start; - timeout = lease_seconds / 2; - if ((unsigned)timeout < already_waited_sec) { - /* Something went wrong. Back to discover state */ - timeout = already_waited_sec = 0; - } + timeout = (unsigned)lease_remaining / 2; +//TODO: why / 2? + timeout -= (unsigned)monotonic_sec() - start; + packet_num = 0; client_data.state = BOUND; change_listen_mode(LISTEN_NONE); @@ -1856,7 +1838,6 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv) requested_ip = 0; timeout = 0; packet_num = 0; - already_waited_sec = 0; } continue; /* case BOUND: - ignore all packets */ -- cgit v1.2.3-55-g6feb From e6007c4911c3ea26925f9473b9f156a692585f30 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Sat, 1 May 2021 13:48:50 +0200 Subject: udhcpc[6]: fold perform_renew() into its only caller function old new delta udhcpc_main 2550 2541 -9 udhcpc6_main 2576 2567 -9 change_listen_mode 321 299 -22 .rodata 103294 103225 -69 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 0/4 up/down: 0/-109) Total: -109 bytes Signed-off-by: Denys Vlasenko --- networking/udhcp/d6_dhcpc.c | 44 +++++++++++++++++------------------------- networking/udhcp/dhcpc.c | 47 ++++++++++++++++++--------------------------- 2 files changed, 37 insertions(+), 54 deletions(-) diff --git a/networking/udhcp/d6_dhcpc.c b/networking/udhcp/d6_dhcpc.c index 592f5b127..0a5cae310 100644 --- a/networking/udhcp/d6_dhcpc.c +++ b/networking/udhcp/d6_dhcpc.c @@ -1040,7 +1040,6 @@ static int d6_raw_socket(int ifindex) log2("opening raw socket on ifindex %d", ifindex); fd = xsocket(PF_PACKET, SOCK_DGRAM, htons(ETH_P_IPV6)); - log3("got raw socket fd %d", fd); memset(&sock, 0, sizeof(sock)); /* let's be deterministic */ sock.sll_family = AF_PACKET; @@ -1087,29 +1086,6 @@ static void change_listen_mode(int new_mode) /* else LISTEN_NONE: client_data.sockfd stays closed */ } -/* Called only on SIGUSR1 */ -static void perform_renew(void) -{ - bb_simple_info_msg("performing DHCP renew"); - switch (client_data.state) { - case BOUND: - change_listen_mode(LISTEN_KERNEL); - case RENEWING: - case REBINDING: - client_data.state = RENEW_REQUESTED; - break; - case RENEW_REQUESTED: /* impatient are we? fine, square 1 */ - d6_run_script_no_option("deconfig"); - case REQUESTING: - case RELEASED: - change_listen_mode(LISTEN_RAW); - client_data.state = INIT_SELECTING; - break; - case INIT_SELECTING: - break; - } -} - static void perform_d6_release(struct in6_addr *server_ipv6, struct in6_addr *our_cur_ipv6) { /* send release packet */ @@ -1535,10 +1511,26 @@ int udhcpc6_main(int argc UNUSED_PARAM, char **argv) switch (udhcp_sp_read()) { case SIGUSR1: client_data.first_secs = 0; /* make secs field count from 0 */ - perform_renew(); - if (client_data.state == RENEW_REQUESTED) + bb_simple_info_msg("performing DHCP renew"); + + switch (client_data.state) { + /* Try to renew/rebind */ + case BOUND: + case RENEWING: + case REBINDING: + change_listen_mode(LISTEN_KERNEL); + client_data.state = RENEW_REQUESTED; goto case_RENEW_REQUESTED; + /* Start things over */ + case RENEW_REQUESTED: /* two or more SIGUSR1 received */ + d6_run_script_no_option("deconfig"); + /* case REQUESTING: break; */ + /* case RELEASED: break; */ + /* case INIT_SELECTING: break; */ + } + change_listen_mode(LISTEN_RAW); + client_data.state = INIT_SELECTING; packet_num = 0; /* Kill any timeouts, user wants this to hurry along */ timeout = 0; diff --git a/networking/udhcp/dhcpc.c b/networking/udhcp/dhcpc.c index a818c1875..6666cbce6 100644 --- a/networking/udhcp/dhcpc.c +++ b/networking/udhcp/dhcpc.c @@ -1027,7 +1027,6 @@ static int udhcp_raw_socket(int ifindex) * SOCK_DGRAM: remove link-layer headers on input (SOCK_RAW keeps them) * ETH_P_IP: want to receive only packets with IPv4 eth type */ - log3("got raw socket fd %d", fd); memset(&sock, 0, sizeof(sock)); /* let's be deterministic */ sock.sll_family = AF_PACKET; @@ -1122,29 +1121,6 @@ static void change_listen_mode(int new_mode) /* else LISTEN_NONE: client_data.sockfd stays closed */ } -/* Called only on SIGUSR1 */ -static void perform_renew(void) -{ - bb_simple_info_msg("performing DHCP renew"); - switch (client_data.state) { - case BOUND: - change_listen_mode(LISTEN_KERNEL); - case RENEWING: - case REBINDING: - client_data.state = RENEW_REQUESTED; - break; - case RENEW_REQUESTED: /* impatient are we? fine, square 1 */ - udhcp_run_script(NULL, "deconfig"); - case REQUESTING: - case RELEASED: - change_listen_mode(LISTEN_RAW); - client_data.state = INIT_SELECTING; - break; - case INIT_SELECTING: - break; - } -} - static void perform_release(uint32_t server_addr, uint32_t requested_ip) { char buffer[sizeof("255.255.255.255")]; @@ -1247,7 +1223,6 @@ static void client_background(void) //usage: "\n USR1 Renew lease" //usage: "\n USR2 Release lease" - int udhcpc_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int udhcpc_main(int argc UNUSED_PARAM, char **argv) { @@ -1597,10 +1572,26 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv) switch (udhcp_sp_read()) { case SIGUSR1: client_data.first_secs = 0; /* make secs field count from 0 */ - perform_renew(); - if (client_data.state == RENEW_REQUESTED) + bb_simple_info_msg("performing DHCP renew"); + + switch (client_data.state) { + /* Try to renew/rebind */ + case BOUND: + case RENEWING: + case REBINDING: + change_listen_mode(LISTEN_KERNEL); + client_data.state = RENEW_REQUESTED; goto case_RENEW_REQUESTED; + /* Start things over */ + case RENEW_REQUESTED: /* two or more SIGUSR1 received */ + udhcp_run_script(NULL, "deconfig"); + /* case REQUESTING: break; */ + /* case RELEASED: break; */ + /* case INIT_SELECTING: break; */ + } + change_listen_mode(LISTEN_RAW); + client_data.state = INIT_SELECTING; packet_num = 0; /* Kill any timeouts, user wants this to hurry along */ timeout = 0; @@ -1737,7 +1728,7 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv) /* paranoia: must not be too small and not prone to overflows */ /* NB: 60s leases _are_ used in real world * (temporary IPs while ISP modem initializes) - * do not break this case by bumplit it up. + * do not break this case by bumping it up. */ if (lease_remaining < 0) /* signed overflow? */ lease_remaining = INT_MAX; -- cgit v1.2.3-55-g6feb From 74e1f321c147753573e4b6bcd34e98708b5ece52 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Sat, 1 May 2021 14:00:09 +0200 Subject: vi: trivial code shrink function old new delta get_input_line 178 176 -2 Signed-off-by: Denys Vlasenko --- editors/vi.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/editors/vi.c b/editors/vi.c index edcf84240..99babccbb 100644 --- a/editors/vi.c +++ b/editors/vi.c @@ -1200,7 +1200,7 @@ static char *get_input_line(const char *prompt) strcpy(buf, prompt); last_status_cksum = 0; // force status update go_bottom_and_clear_to_eol(); - write1(prompt); // write out the :, /, or ? prompt + write1(buf); // write out the :, /, or ? prompt i = strlen(buf); while (i < MAX_INPUT_LEN - 1) { @@ -1209,8 +1209,8 @@ static char *get_input_line(const char *prompt) break; // this is end of input if (c == term_orig.c_cc[VERASE] || c == 8 || c == 127) { // user wants to erase prev char - buf[--i] = '\0'; write1("\b \b"); // erase char on screen + buf[--i] = '\0'; if (i <= 0) // user backs up before b-o-l, exit break; } else if (c > 0 && c < 256) { // exclude Unicode -- cgit v1.2.3-55-g6feb From 147ac93a065e215545488337efbaa6dceebc04d0 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Mon, 3 May 2021 14:57:27 +0200 Subject: decompress_gunzip: simplify ERR_RET bit clearing My gcc is in fact clever enough to do it itself, but let's be explicit Signed-off-by: Denys Vlasenko --- archival/libarchive/decompress_gunzip.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/archival/libarchive/decompress_gunzip.c b/archival/libarchive/decompress_gunzip.c index e93cd5005..d051ecb81 100644 --- a/archival/libarchive/decompress_gunzip.c +++ b/archival/libarchive/decompress_gunzip.c @@ -230,9 +230,8 @@ static void huft_free(huft_t *p) * If 'p' has the error bit set we have to clear it, otherwise we might run * into a segmentation fault or an invalid pointer to free(p) */ - if (BAD_HUFT(p)) { - p = (huft_t*)((uintptr_t)(p) ^ (uintptr_t)(ERR_RET)); - } + //if (BAD_HUFT(p)) // commented out, since bit clearing has effect only if condition is true + p = (huft_t*)((uintptr_t)p & ~(uintptr_t)ERR_RET); /* Go through linked list, freeing from the malloced (t[-1]) address. */ while (p) { -- cgit v1.2.3-55-g6feb From 24effc7a3f32b3d4e78779473ddc683848ac3cb0 Mon Sep 17 00:00:00 2001 From: Ron Yorston Date: Fri, 30 Apr 2021 12:56:12 +0100 Subject: vi: cursor positioning after whole-line 'y' The 'y' command to yank text should leave the cursor at the start of the range. This mostly works correctly in BusyBox vi but not for whole-line yanks with backward motion, e.g. '2yk' to yank two lines backwards. In this case the cursor is left at the end of the range. Fix this by returning the actual range from find_range(). Cursor positioning following whole-line deletion is inconsistent between vim and traditional vi. For BusyBox vi chose the option that uses least code without being exactly compatible with either. Also, find_range() preserved the value of 'dot', the current cursor position. Since this isn't used by either caller of find_range() we can save a few bytes by not bothering. function old new delta do_cmd 4730 4759 +29 find_range 749 686 -63 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 1/1 up/down: 29/-63) Total: -34 bytes Signed-off-by: Ron Yorston Signed-off-by: Denys Vlasenko --- editors/vi.c | 25 ++++++++----------------- 1 file changed, 8 insertions(+), 17 deletions(-) diff --git a/editors/vi.c b/editors/vi.c index 99babccbb..c7e7c67d5 100644 --- a/editors/vi.c +++ b/editors/vi.c @@ -3328,11 +3328,10 @@ static int at_eof(const char *s) static int find_range(char **start, char **stop, int cmd) { - char *save_dot, *p, *q, *t; + char *p, *q, *t; int buftype = -1; int c; - save_dot = dot; p = q = dot; #if ENABLE_FEATURE_VI_YANKMARK @@ -3421,14 +3420,8 @@ static int find_range(char **start, char **stop, int cmd) } } - if (buftype == WHOLE || cmd == '<' || cmd == '>') { - p = begin_line(p); - q = end_line(q); - } - *start = p; *stop = q; - dot = save_dot; return buftype; } @@ -3896,7 +3889,7 @@ static void do_cmd(int c) if (find_range(&p, &q, c) == -1) goto dc6; i = count_lines(p, q); // # of lines we are shifting - for ( ; i > 0; i--, p = next_line(p)) { + for (p = begin_line(p); i > 0; i--, p = next_line(p)) { if (c == '<') { // shift left- remove tab or tabstop spaces if (*p == '\t') { @@ -4150,12 +4143,16 @@ static void do_cmd(int c) # endif if (c == 'y' || c == 'Y') yf = YANKONLY; - save_dot = dot; #endif // determine range, and whether it spans lines buftype = find_range(&p, &q, c); if (buftype == -1) // invalid range goto dc6; + if (buftype == WHOLE) { + save_dot = p; // final cursor position is start of range + p = begin_line(p); + q = end_line(q); + } dot = yank_delete(p, q, buftype, yf, ALLOW_UNDO); // delete word if (buftype == WHOLE) { if (c == 'c') { @@ -4164,15 +4161,9 @@ static void do_cmd(int c) if (dot != (end-1)) { dot_prev(); } - } else if (c == 'd') { - dot_begin(); - dot_skip_over_ws(); - } -#if ENABLE_FEATURE_VI_YANKMARK - else /* (c == 'y' || c == 'Y') */ { + } else { dot = save_dot; } -#endif } // if CHANGING, not deleting, start inserting after the delete if (c == 'c') { -- cgit v1.2.3-55-g6feb From 8e71f2aab8f9f893be7741af21a7c689cf165c66 Mon Sep 17 00:00:00 2001 From: Ron Yorston Date: Sat, 1 May 2021 13:15:30 +0100 Subject: vi: :wq/:x should warn if there are more files to edit ':wq' or ':x' should issue a warning if there are more files to edit, unless they're followed by '!'. function old new delta colon 3911 3960 +49 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 1/0 up/down: 49/0) Total: 49 bytes Signed-off-by: Ron Yorston Signed-off-by: Denys Vlasenko --- editors/vi.c | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/editors/vi.c b/editors/vi.c index c7e7c67d5..4a7f8c3c2 100644 --- a/editors/vi.c +++ b/editors/vi.c @@ -3181,9 +3181,20 @@ static void colon(char *buf) modified_count = 0; last_modified_count = -1; } - if (cmd[0] == 'x' - || cmd[1] == 'q' || cmd[1] == 'n' - ) { + if (cmd[1] == 'n') { + editing = 0; + } else if (cmd[0] == 'x' || cmd[1] == 'q') { + // are there other files to edit? + int n = cmdline_filecnt - optind - 1; + if (n > 0) { + if (useforce) { + // force end of argv list + optind = cmdline_filecnt; + } else { + status_line_bold("%u more file(s) to edit", n); + goto ret; + } + } editing = 0; } } -- cgit v1.2.3-55-g6feb From 36e932abdfd79f55fdded4142d10319ba843839e Mon Sep 17 00:00:00 2001 From: Alexander Sack Date: Tue, 4 May 2021 07:41:50 +0000 Subject: httpd: cgi-bin support for DELETE, PUT, OPTIONS etc methods function old new delta handle_incoming_and_exit 2217 2240 +23 static.request_POST - 5 +5 ------------------------------------------------------------------------------ (add/remove: 1/0 grow/shrink: 1/0 up/down: 28/0) Total: 28 bytes Signed-off-by: Alexander Sack Signed-off-by: Denys Vlasenko --- networking/httpd.c | 85 +++++++++++++++++++++++++----------------------------- 1 file changed, 40 insertions(+), 45 deletions(-) diff --git a/networking/httpd.c b/networking/httpd.c index e6757d943..09e19dc29 100644 --- a/networking/httpd.c +++ b/networking/httpd.c @@ -344,13 +344,6 @@ typedef struct Htaccess_Proxy { char *url_to; } Htaccess_Proxy; -typedef enum CGI_type { - CGI_NONE = 0, - CGI_NORMAL, - CGI_INDEX, - CGI_INTERPRETER, -} CGI_type; - enum { HTTP_OK = 200, HTTP_PARTIAL_CONTENT = 206, @@ -2174,7 +2167,6 @@ static void send_REQUEST_TIMEOUT_and_exit(int sig UNUSED_PARAM) static void handle_incoming_and_exit(const len_and_sockaddr *fromAddr) NORETURN; static void handle_incoming_and_exit(const len_and_sockaddr *fromAddr) { - static const char request_GET[] ALIGN1 = "GET"; struct stat sb; char *urlcopy; char *urlp; @@ -2186,13 +2178,17 @@ static void handle_incoming_and_exit(const len_and_sockaddr *fromAddr) unsigned total_headers_len; #endif #if ENABLE_FEATURE_HTTPD_CGI + static const char request_GET[] ALIGN1 = "GET"; static const char request_HEAD[] ALIGN1 = "HEAD"; + static const char request_POST[] ALIGN1 = "POST"; const char *prequest; - unsigned long length = 0; - enum CGI_type cgi_type = CGI_NONE; -#elif ENABLE_FEATURE_HTTPD_PROXY -#define prequest request_GET - unsigned long length = 0; + unsigned long POST_length; + enum CGI_type { + CGI_NONE = 0, + CGI_NORMAL, + CGI_INDEX, + CGI_INTERPRETER, + } cgi_type = CGI_NONE; #endif #if ENABLE_FEATURE_HTTPD_BASIC_AUTH smallint authorized = -1; @@ -2235,7 +2231,7 @@ static void handle_incoming_and_exit(const len_and_sockaddr *fromAddr) if (!get_line()) /* EOF or error or empty line */ send_headers_and_exit(HTTP_BAD_REQUEST); - /* Determine type of request (GET/POST) */ + /* Determine type of request (GET/POST/...) */ // rfc2616: method and URI is separated by exactly one space //urlp = strpbrk(iobuf, " \t"); - no, tab isn't allowed urlp = strchr(iobuf, ' '); @@ -2244,16 +2240,20 @@ static void handle_incoming_and_exit(const len_and_sockaddr *fromAddr) *urlp++ = '\0'; #if ENABLE_FEATURE_HTTPD_CGI prequest = request_GET; - if (strcasecmp(iobuf, prequest) != 0) { - prequest = request_HEAD; - if (strcasecmp(iobuf, prequest) != 0) { - prequest = "POST"; - if (strcasecmp(iobuf, prequest) != 0) - send_headers_and_exit(HTTP_NOT_IMPLEMENTED); - } - } + if (strcasecmp(iobuf, prequest) == 0) + goto found; + prequest = request_HEAD; + if (strcasecmp(iobuf, prequest) == 0) + goto found; + prequest = request_POST; + if (strcasecmp(iobuf, prequest) == 0) + goto found; + /* For CGI, allow other requests too (DELETE, PUT, OPTIONS, etc) */ + prequest = alloca(16); + safe_strncpy((char*)prequest, iobuf, 16); + found: #else - if (strcasecmp(iobuf, request_GET) != 0) + if (strcasecmp(iobuf, "GET") != 0) send_headers_and_exit(HTTP_NOT_IMPLEMENTED); #endif // rfc2616: method and URI is separated by exactly one space @@ -2300,7 +2300,7 @@ static void handle_incoming_and_exit(const len_and_sockaddr *fromAddr) * to http://hostname[:port]/new/pathSFX */ fdprintf(proxy_fd, "%s %s%s %s\r\n", - prequest, /* "GET" or "POST" */ + iobuf, /* "GET" / "POST" / etc */ proxy_entry->url_to, /* "/new/path" */ urlcopy + strlen(proxy_entry->url_from), /* "SFX" */ HTTP_slash /* "HTTP/xyz" */ @@ -2328,7 +2328,7 @@ static void handle_incoming_and_exit(const len_and_sockaddr *fromAddr) /* Algorithm stolen from libbb bb_simplify_path(), * but don't strdup, retain trailing slash, protect root */ urlp = tptr = urlcopy; - for (;;) { + while (1) { if (*urlp == '/') { /* skip duplicate (or initial) slash */ if (*tptr == '/') { @@ -2435,6 +2435,7 @@ static void handle_incoming_and_exit(const len_and_sockaddr *fromAddr) #if ENABLE_FEATURE_HTTPD_CGI total_headers_len = 0; + POST_length = 0; #endif /* Read until blank line */ @@ -2450,24 +2451,17 @@ static void handle_incoming_and_exit(const len_and_sockaddr *fromAddr) #endif if (DEBUG) bb_error_msg("header: '%s'", iobuf); -#if ENABLE_FEATURE_HTTPD_CGI || ENABLE_FEATURE_HTTPD_PROXY - /* Try and do our best to parse more lines */ - if (STRNCASECMP(iobuf, "Content-Length:") == 0) { - /* extra read only for POST */ - if (prequest != request_GET -# if ENABLE_FEATURE_HTTPD_CGI - && prequest != request_HEAD -# endif - ) { - tptr = skip_whitespace(iobuf + sizeof("Content-Length:") - 1); - if (!tptr[0]) - send_headers_and_exit(HTTP_BAD_REQUEST); - /* not using strtoul: it ignores leading minus! */ - length = bb_strtou(tptr, NULL, 10); - /* length is "ulong", but we need to pass it to int later */ - if (errno || length > INT_MAX) - send_headers_and_exit(HTTP_BAD_REQUEST); - } +#if ENABLE_FEATURE_HTTPD_CGI + /* Only POST needs to know POST_length */ + if (prequest == request_POST && STRNCASECMP(iobuf, "Content-Length:") == 0) { + tptr = skip_whitespace(iobuf + sizeof("Content-Length:") - 1); + if (!tptr[0]) + send_headers_and_exit(HTTP_BAD_REQUEST); + /* not using strtoul: it ignores leading minus! */ + POST_length = bb_strtou(tptr, NULL, 10); + /* length is "ulong", but we need to pass it to int later */ + if (errno || POST_length > INT_MAX) + send_headers_and_exit(HTTP_BAD_REQUEST); continue; } #endif @@ -2588,7 +2582,7 @@ static void handle_incoming_and_exit(const len_and_sockaddr *fromAddr) send_cgi_and_exit( (cgi_type == CGI_INDEX) ? "/cgi-bin/index.cgi" /*CGI_NORMAL or CGI_INTERPRETER*/ : urlcopy, - urlcopy, prequest, length + urlcopy, prequest, POST_length ); } #endif @@ -2599,13 +2593,14 @@ static void handle_incoming_and_exit(const len_and_sockaddr *fromAddr) #if ENABLE_FEATURE_HTTPD_CGI if (prequest != request_GET && prequest != request_HEAD) { - /* POST for files does not make sense */ + /* POST / DELETE / PUT / OPTIONS for files do not make sense */ send_headers_and_exit(HTTP_NOT_IMPLEMENTED); } send_file_and_exit(tptr, (prequest != request_HEAD ? SEND_HEADERS_AND_BODY : SEND_HEADERS) ); #else + /* It was verified earlier that it is a "GET" */ send_file_and_exit(tptr, SEND_HEADERS_AND_BODY); #endif } -- cgit v1.2.3-55-g6feb From ff4d898fe6a0f082baff929087df7eb38d4e890c Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Tue, 4 May 2021 19:51:39 +0200 Subject: httpd: move proxy check before URL duplication and request type check This makes proxy work for any type of requests. function old new delta handle_incoming_and_exit 2240 2172 -68 Signed-off-by: Denys Vlasenko --- networking/httpd.c | 108 ++++++++++++++++++++++++++--------------------------- 1 file changed, 52 insertions(+), 56 deletions(-) diff --git a/networking/httpd.c b/networking/httpd.c index 09e19dc29..951213ec5 100644 --- a/networking/httpd.c +++ b/networking/httpd.c @@ -2190,6 +2190,9 @@ static void handle_incoming_and_exit(const len_and_sockaddr *fromAddr) CGI_INTERPRETER, } cgi_type = CGI_NONE; #endif +#if ENABLE_FEATURE_HTTPD_PROXY + Htaccess_Proxy *proxy_entry; +#endif #if ENABLE_FEATURE_HTTPD_BASIC_AUTH smallint authorized = -1; #endif @@ -2231,13 +2234,57 @@ static void handle_incoming_and_exit(const len_and_sockaddr *fromAddr) if (!get_line()) /* EOF or error or empty line */ send_headers_and_exit(HTTP_BAD_REQUEST); - /* Determine type of request (GET/POST/...) */ + /* Find URL */ // rfc2616: method and URI is separated by exactly one space //urlp = strpbrk(iobuf, " \t"); - no, tab isn't allowed urlp = strchr(iobuf, ' '); if (urlp == NULL) send_headers_and_exit(HTTP_BAD_REQUEST); *urlp++ = '\0'; + //urlp = skip_whitespace(urlp); - should not be necessary + if (urlp[0] != '/') + send_headers_and_exit(HTTP_BAD_REQUEST); + /* Find end of URL */ + HTTP_slash = strchr(urlp, ' '); + /* Is it " HTTP/"? */ + if (!HTTP_slash || strncmp(HTTP_slash + 1, HTTP_200, 5) != 0) + send_headers_and_exit(HTTP_BAD_REQUEST); + *HTTP_slash++ = '\0'; + +#if ENABLE_FEATURE_HTTPD_PROXY + proxy_entry = find_proxy_entry(urlp); + if (proxy_entry) { + int proxy_fd; + len_and_sockaddr *lsa; + + if (verbose > 1) + bb_error_msg("proxy:%s", urlp); + lsa = host2sockaddr(proxy_entry->host_port, 80); + if (!lsa) + send_headers_and_exit(HTTP_INTERNAL_SERVER_ERROR); + proxy_fd = socket(lsa->u.sa.sa_family, SOCK_STREAM, 0); + if (proxy_fd < 0) + send_headers_and_exit(HTTP_INTERNAL_SERVER_ERROR); + if (connect(proxy_fd, &lsa->u.sa, lsa->len) < 0) + send_headers_and_exit(HTTP_INTERNAL_SERVER_ERROR); + /* Disable peer header reading timeout */ + alarm(0); + /* Config directive was of the form: + * P:/url:[http://]hostname[:port]/new/path + * When /urlSFX is requested, reverse proxy it + * to http://hostname[:port]/new/pathSFX + */ + fdprintf(proxy_fd, "%s %s%s %s\r\n", + iobuf, /* "GET" / "POST" / etc */ + proxy_entry->url_to, /* "/new/path" */ + urlp + strlen(proxy_entry->url_from), /* "SFX" */ + HTTP_slash /* "HTTP/xyz" */ + ); + cgi_io_loop_and_exit(proxy_fd, proxy_fd, /*max POST length:*/ INT_MAX); + } +#endif + + /* Determine type of request (GET/POST/...) */ #if ENABLE_FEATURE_HTTPD_CGI prequest = request_GET; if (strcasecmp(iobuf, prequest) == 0) @@ -2248,7 +2295,7 @@ static void handle_incoming_and_exit(const len_and_sockaddr *fromAddr) prequest = request_POST; if (strcasecmp(iobuf, prequest) == 0) goto found; - /* For CGI, allow other requests too (DELETE, PUT, OPTIONS, etc) */ + /* For CGI, allow DELETE, PUT, OPTIONS, etc too */ prequest = alloca(16); safe_strncpy((char*)prequest, iobuf, 16); found: @@ -2256,60 +2303,11 @@ static void handle_incoming_and_exit(const len_and_sockaddr *fromAddr) if (strcasecmp(iobuf, "GET") != 0) send_headers_and_exit(HTTP_NOT_IMPLEMENTED); #endif - // rfc2616: method and URI is separated by exactly one space - //urlp = skip_whitespace(urlp); - should not be necessary - if (urlp[0] != '/') - send_headers_and_exit(HTTP_BAD_REQUEST); - - /* Find end of URL */ - HTTP_slash = strchr(urlp, ' '); - /* Is it " HTTP/"? */ - if (!HTTP_slash || strncmp(HTTP_slash + 1, HTTP_200, 5) != 0) - send_headers_and_exit(HTTP_BAD_REQUEST); - *HTTP_slash++ = '\0'; - - /* Copy URL from after "GET "/"POST " to stack-allocated char[] */ + /* Copy URL to stack-allocated char[] */ urlcopy = alloca((HTTP_slash - urlp) + 2 + strlen(index_page)); - /*if (urlcopy == NULL) - * send_headers_and_exit(HTTP_INTERNAL_SERVER_ERROR);*/ strcpy(urlcopy, urlp); /* NB: urlcopy ptr is never changed after this */ -#if ENABLE_FEATURE_HTTPD_PROXY - { - int proxy_fd; - len_and_sockaddr *lsa; - Htaccess_Proxy *proxy_entry = find_proxy_entry(urlcopy); - - if (proxy_entry) { - if (verbose > 1) - bb_error_msg("proxy:%s", urlcopy); - lsa = host2sockaddr(proxy_entry->host_port, 80); - if (!lsa) - send_headers_and_exit(HTTP_INTERNAL_SERVER_ERROR); - proxy_fd = socket(lsa->u.sa.sa_family, SOCK_STREAM, 0); - if (proxy_fd < 0) - send_headers_and_exit(HTTP_INTERNAL_SERVER_ERROR); - if (connect(proxy_fd, &lsa->u.sa, lsa->len) < 0) - send_headers_and_exit(HTTP_INTERNAL_SERVER_ERROR); - /* Disable peer header reading timeout */ - alarm(0); - /* Config directive was of the form: - * P:/url:[http://]hostname[:port]/new/path - * When /urlSFX is requested, reverse proxy it - * to http://hostname[:port]/new/pathSFX - */ - fdprintf(proxy_fd, "%s %s%s %s\r\n", - iobuf, /* "GET" / "POST" / etc */ - proxy_entry->url_to, /* "/new/path" */ - urlcopy + strlen(proxy_entry->url_from), /* "SFX" */ - HTTP_slash /* "HTTP/xyz" */ - ); - cgi_io_loop_and_exit(proxy_fd, proxy_fd, /*max POST length:*/ INT_MAX); - } - } -#endif - /* Extract url args if present */ g_query = strchr(urlcopy, '?'); if (g_query) @@ -2571,9 +2569,8 @@ static void handle_incoming_and_exit(const len_and_sockaddr *fromAddr) send_headers_and_exit(HTTP_UNAUTHORIZED); #endif - if (found_moved_temporarily) { + if (found_moved_temporarily) send_headers_and_exit(HTTP_MOVED_TEMPORARILY); - } tptr = urlcopy + 1; /* skip first '/' */ @@ -2587,9 +2584,8 @@ static void handle_incoming_and_exit(const len_and_sockaddr *fromAddr) } #endif - if (urlp[-1] == '/') { + if (urlp[-1] == '/') strcpy(urlp, index_page); - } #if ENABLE_FEATURE_HTTPD_CGI if (prequest != request_GET && prequest != request_HEAD) { -- cgit v1.2.3-55-g6feb From 32a8258be78371154dd66b931a9628aad0efd337 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Tue, 4 May 2021 20:15:24 +0200 Subject: httpd: support HEAD requests even in !CGI config Signed-off-by: Denys Vlasenko --- networking/httpd.c | 23 ++++++++++------------- 1 file changed, 10 insertions(+), 13 deletions(-) diff --git a/networking/httpd.c b/networking/httpd.c index 951213ec5..958b3c300 100644 --- a/networking/httpd.c +++ b/networking/httpd.c @@ -548,7 +548,6 @@ enum { enum { SEND_HEADERS = (1 << 0), SEND_BODY = (1 << 1), - SEND_HEADERS_AND_BODY = SEND_HEADERS + SEND_BODY, }; static void send_file_and_exit(const char *url, int what) NORETURN; @@ -2177,11 +2176,11 @@ static void handle_incoming_and_exit(const len_and_sockaddr *fromAddr) #if ENABLE_FEATURE_HTTPD_CGI unsigned total_headers_len; #endif -#if ENABLE_FEATURE_HTTPD_CGI + const char *prequest; static const char request_GET[] ALIGN1 = "GET"; static const char request_HEAD[] ALIGN1 = "HEAD"; +#if ENABLE_FEATURE_HTTPD_CGI static const char request_POST[] ALIGN1 = "POST"; - const char *prequest; unsigned long POST_length; enum CGI_type { CGI_NONE = 0, @@ -2285,24 +2284,23 @@ static void handle_incoming_and_exit(const len_and_sockaddr *fromAddr) #endif /* Determine type of request (GET/POST/...) */ -#if ENABLE_FEATURE_HTTPD_CGI prequest = request_GET; if (strcasecmp(iobuf, prequest) == 0) goto found; prequest = request_HEAD; if (strcasecmp(iobuf, prequest) == 0) goto found; +#if !ENABLE_FEATURE_HTTPD_CGI + send_headers_and_exit(HTTP_NOT_IMPLEMENTED); +#else prequest = request_POST; if (strcasecmp(iobuf, prequest) == 0) goto found; /* For CGI, allow DELETE, PUT, OPTIONS, etc too */ prequest = alloca(16); safe_strncpy((char*)prequest, iobuf, 16); - found: -#else - if (strcasecmp(iobuf, "GET") != 0) - send_headers_and_exit(HTTP_NOT_IMPLEMENTED); #endif + found: /* Copy URL to stack-allocated char[] */ urlcopy = alloca((HTTP_slash - urlp) + 2 + strlen(index_page)); strcpy(urlcopy, urlp); @@ -2592,13 +2590,12 @@ static void handle_incoming_and_exit(const len_and_sockaddr *fromAddr) /* POST / DELETE / PUT / OPTIONS for files do not make sense */ send_headers_and_exit(HTTP_NOT_IMPLEMENTED); } - send_file_and_exit(tptr, - (prequest != request_HEAD ? SEND_HEADERS_AND_BODY : SEND_HEADERS) - ); #else - /* It was verified earlier that it is a "GET" */ - send_file_and_exit(tptr, SEND_HEADERS_AND_BODY); + /* !CGI: it can be only GET or HEAD */ #endif + send_file_and_exit(tptr, + (prequest != request_HEAD ? (SEND_HEADERS + SEND_BODY) : SEND_HEADERS) + ); } /* -- cgit v1.2.3-55-g6feb From 1c698178858ac2b332849a2e24283e6060f9b179 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Tue, 4 May 2021 21:11:03 +0200 Subject: httpd: avoid one stat() call for "GET /dirname" case function old new delta handle_incoming_and_exit 2172 2173 +1 Signed-off-by: Denys Vlasenko --- networking/httpd.c | 30 ++++++++++++++---------------- 1 file changed, 14 insertions(+), 16 deletions(-) diff --git a/networking/httpd.c b/networking/httpd.c index 958b3c300..fc52fafea 100644 --- a/networking/httpd.c +++ b/networking/httpd.c @@ -2355,13 +2355,6 @@ static void handle_incoming_and_exit(const len_and_sockaddr *fromAddr) tptr++; } - /* If URL is a directory, add '/' */ - if (urlp[-1] != '/') { - if (is_directory(urlcopy + 1, /*followlinks:*/ 1)) { - found_moved_temporarily = urlcopy; - } - } - /* Log it */ if (verbose > 1) bb_error_msg("url:%s", urlcopy); @@ -2370,6 +2363,7 @@ static void handle_incoming_and_exit(const len_and_sockaddr *fromAddr) while ((tptr = strchr(tptr + 1, '/')) != NULL) { /* have path1/path2 */ *tptr = '\0'; +//TODO: can we avoid is_directory() test here? if (is_directory(urlcopy + 1, /*followlinks:*/ 1)) { /* may have subdir config */ parse_conf(urlcopy + 1, SUBDIR_PARSE); @@ -2401,19 +2395,23 @@ static void handle_incoming_and_exit(const len_and_sockaddr *fromAddr) strcpy(urlp, index_page); } if (stat(tptr, &sb) == 0) { + /* If URL is a directory with no slash, set up + * "HTTP/1.1 302 Found" "Location: /dir/" reply */ + if (urlp[-1] != '/' && S_ISDIR(sb.st_mode)) { + found_moved_temporarily = urlcopy; + } else { #if ENABLE_FEATURE_HTTPD_CONFIG_WITH_SCRIPT_INTERPR - char *suffix = strrchr(tptr, '.'); - if (suffix) { - Htaccess *cur; - for (cur = script_i; cur; cur = cur->next) { - if (strcmp(cur->before_colon + 1, suffix) == 0) { - cgi_type = CGI_INTERPRETER; - break; + char *suffix = strrchr(tptr, '.'); + if (suffix) { + Htaccess *cur; + for (cur = script_i; cur; cur = cur->next) { + if (strcmp(cur->before_colon + 1, suffix) == 0) { + cgi_type = CGI_INTERPRETER; + break; + } } } - } #endif - if (!found_moved_temporarily) { file_size = sb.st_size; last_mod = sb.st_mtime; } -- cgit v1.2.3-55-g6feb From 5b34a5594c6fc40b6183c50a42e3f86e4b441688 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Tue, 4 May 2021 21:25:16 +0200 Subject: httpd: avoid extra stat() calls for "GET /dirname/" case function old new delta parse_conf 1325 1332 +7 handle_incoming_and_exit 2173 2161 -12 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 1/1 up/down: 7/-12) Total: -5 bytes Signed-off-by: Denys Vlasenko --- networking/httpd.c | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/networking/httpd.c b/networking/httpd.c index fc52fafea..e48574e4f 100644 --- a/networking/httpd.c +++ b/networking/httpd.c @@ -679,7 +679,7 @@ enum { SIGNALED_PARSE = 1, /* path will be "/etc" */ SUBDIR_PARSE = 2, /* path will be derived from URL */ }; -static void parse_conf(const char *path, int flag) +static int parse_conf(const char *path, int flag) { /* internally used extra flag state */ enum { TRY_CURDIR_PARSE = 3 }; @@ -713,7 +713,7 @@ static void parse_conf(const char *path, int flag) while ((f = fopen_for_read(filename)) == NULL) { if (flag >= SUBDIR_PARSE) { /* SUBDIR or TRY_CURDIR */ /* config file not found, no changes to config */ - return; + return -1; } if (flag == FIRST_PARSE) { /* -c CONFFILE given, but CONFFILE doesn't exist? */ @@ -971,6 +971,7 @@ static void parse_conf(const char *path, int flag) } /* while (fgets) */ fclose(f); + return 0; } #if ENABLE_FEATURE_HTTPD_ENCODE_URL_STR @@ -2363,12 +2364,9 @@ static void handle_incoming_and_exit(const len_and_sockaddr *fromAddr) while ((tptr = strchr(tptr + 1, '/')) != NULL) { /* have path1/path2 */ *tptr = '\0'; -//TODO: can we avoid is_directory() test here? - if (is_directory(urlcopy + 1, /*followlinks:*/ 1)) { - /* may have subdir config */ - parse_conf(urlcopy + 1, SUBDIR_PARSE); + /* may have subdir config */ + if (parse_conf(urlcopy + 1, SUBDIR_PARSE) == 0) if_ip_denied_send_HTTP_FORBIDDEN_and_exit(remote_ip); - } *tptr = '/'; } @@ -2420,9 +2418,9 @@ static void handle_incoming_and_exit(const len_and_sockaddr *fromAddr) else if (urlp[-1] == '/') { /* It's a dir URL and there is no index.html * Try cgi-bin/index.cgi */ - if (access("/cgi-bin/index.cgi"+1, X_OK) == 0) { - cgi_type = CGI_INDEX; - } + if (access("/cgi-bin/index.cgi"+1, X_OK) != 0) + send_headers_and_exit(HTTP_NOT_FOUND); + cgi_type = CGI_INDEX; } #endif urlp[0] = '\0'; -- cgit v1.2.3-55-g6feb From 91a58b207ea04e6078f44cecae6c3356e059da8a Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Wed, 5 May 2021 09:40:59 +0200 Subject: httpd: no need to strcpy() when we only need to copy one byte function old new delta handle_incoming_and_exit 2161 2172 +11 Signed-off-by: Denys Vlasenko --- networking/httpd.c | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/networking/httpd.c b/networking/httpd.c index e48574e4f..6bc58995b 100644 --- a/networking/httpd.c +++ b/networking/httpd.c @@ -2416,14 +2416,18 @@ static void handle_incoming_and_exit(const len_and_sockaddr *fromAddr) } #if ENABLE_FEATURE_HTTPD_CGI else if (urlp[-1] == '/') { - /* It's a dir URL and there is no index.html - * Try cgi-bin/index.cgi */ + /* It's a dir URL and there is no index.html */ + /* Is there cgi-bin/index.cgi? */ if (access("/cgi-bin/index.cgi"+1, X_OK) != 0) - send_headers_and_exit(HTTP_NOT_FOUND); + send_headers_and_exit(HTTP_NOT_FOUND); /* no */ cgi_type = CGI_INDEX; } #endif + +#if ENABLE_FEATURE_HTTPD_BASIC_AUTH || ENABLE_FEATURE_HTTPD_CGI + /* check_user_passwd() would be confused by added .../index.html, truncate it */ urlp[0] = '\0'; +#endif #if ENABLE_FEATURE_HTTPD_CGI total_headers_len = 0; @@ -2566,8 +2570,6 @@ static void handle_incoming_and_exit(const len_and_sockaddr *fromAddr) if (found_moved_temporarily) send_headers_and_exit(HTTP_MOVED_TEMPORARILY); - tptr = urlcopy + 1; /* skip first '/' */ - #if ENABLE_FEATURE_HTTPD_CGI if (cgi_type != CGI_NONE) { send_cgi_and_exit( @@ -2578,9 +2580,6 @@ static void handle_incoming_and_exit(const len_and_sockaddr *fromAddr) } #endif - if (urlp[-1] == '/') - strcpy(urlp, index_page); - #if ENABLE_FEATURE_HTTPD_CGI if (prequest != request_GET && prequest != request_HEAD) { /* POST / DELETE / PUT / OPTIONS for files do not make sense */ @@ -2589,7 +2588,13 @@ static void handle_incoming_and_exit(const len_and_sockaddr *fromAddr) #else /* !CGI: it can be only GET or HEAD */ #endif - send_file_and_exit(tptr, + +#if ENABLE_FEATURE_HTTPD_BASIC_AUTH + /* Restore truncated .../index.html */ + if (urlp[-1] == '/') + urlp[0] = index_page[0]; +#endif + send_file_and_exit(urlcopy + 1, (prequest != request_HEAD ? (SEND_HEADERS + SEND_BODY) : SEND_HEADERS) ); } -- cgit v1.2.3-55-g6feb From ad16f89547a5e335f3c45506eb5b43bcc1bf505e Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Wed, 5 May 2021 15:00:09 +0200 Subject: httpd: if no request was given at all, close the socket without generating error page For one, an attacker can try to overload us by just opening and immediately closing tons of connections - reduce our work to the minimum for this case. function old new delta handle_incoming_and_exit 2172 2200 +28 .rodata 103225 103246 +21 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 2/0 up/down: 49/0) Total: 49 bytes Signed-off-by: Denys Vlasenko --- networking/httpd.c | 51 ++++++++++++++++++++++++++++++--------------------- 1 file changed, 30 insertions(+), 21 deletions(-) diff --git a/networking/httpd.c b/networking/httpd.c index 6bc58995b..fb6ffe542 100644 --- a/networking/httpd.c +++ b/networking/httpd.c @@ -305,6 +305,12 @@ #define DEBUG 0 +#if DEBUG +# define dbg(...) fprintf(stderr, __VA_ARGS__) +#else +# define dbg(...) ((void)0) +#endif + #define IOBUF_SIZE 8192 #define MAX_HTTP_HEADERS_SIZE (32*1024) @@ -1158,8 +1164,7 @@ static void send_headers(unsigned responseNum) fprintf(stderr, "headers: '%s'\n", iobuf); } full_write(STDOUT_FILENO, iobuf, len); - if (DEBUG) - fprintf(stderr, "writing error page: '%s'\n", error_page); + dbg("writing error page: '%s'\n", error_page); return send_file_and_exit(error_page, SEND_BODY); } #endif @@ -1500,8 +1505,7 @@ static NOINLINE void cgi_io_loop_and_exit(int fromCgi_rd, int toCgi_wr, int post } if (full_write(STDOUT_FILENO, rbuf, count) != count) break; - if (DEBUG) - fprintf(stderr, "cgi read %d bytes: '%.*s'\n", count, count, rbuf); + dbg("cgi read %d bytes: '%.*s'\n", count, count, rbuf); } /* if (pfd[FROM_CGI].revents) */ } /* while (1) */ log_and_exit(); @@ -1747,8 +1751,7 @@ static NOINLINE void send_file_and_exit(const char *url, int what) /* file_size and last_mod are already populated */ } if (fd < 0) { - if (DEBUG) - bb_perror_msg("can't open '%s'", url); + dbg("can't open '%s'\n", url); /* Error pages are sent by using send_file_and_exit(SEND_BODY). * IOW: it is unsafe to call send_headers_and_exit * if what is SEND_BODY! Can recurse! */ @@ -1761,8 +1764,7 @@ static NOINLINE void send_file_and_exit(const char *url, int what) sprintf(G.etag, "\"%llx-%llx\"", (unsigned long long)last_mod, (unsigned long long)file_size); if (G.if_none_match) { - if (DEBUG) - bb_perror_msg("If-None-Match and file's ETag are: '%s' '%s'\n", G.if_none_match, G.etag); + dbg("If-None-Match:'%s' file's ETag:'%s'\n", G.if_none_match, G.etag); /* Weak ETag comparision. * If-None-Match may have many ETags but they are quoted so we can use simple substring search */ if (strstr(G.if_none_match, G.etag)) @@ -1838,9 +1840,7 @@ static NOINLINE void send_file_and_exit(const char *url, int what) } } - if (DEBUG) - bb_error_msg("sending file '%s' content-type: %s", - url, found_mime_type); + dbg("sending file '%s' content-type:%s\n", url, found_mime_type); #if ENABLE_FEATURE_HTTPD_RANGES if (what == SEND_BODY /* err pages and ranges don't mix */ @@ -1910,9 +1910,7 @@ static void if_ip_denied_send_HTTP_FORBIDDEN_and_exit(unsigned remote_ip) Htaccess_IP *cur; for (cur = G.ip_a_d; cur; cur = cur->next) { -#if DEBUG - fprintf(stderr, - "checkPermIP: '%s' ? '%u.%u.%u.%u/%u.%u.%u.%u'\n", + dbg("checkPermIP: '%s' ? '%u.%u.%u.%u/%u.%u.%u.%u'\n", rmt_ip_str, (unsigned char)(cur->ip >> 24), (unsigned char)(cur->ip >> 16), @@ -1923,7 +1921,6 @@ static void if_ip_denied_send_HTTP_FORBIDDEN_and_exit(unsigned remote_ip) (unsigned char)(cur->mask >> 8), (unsigned char)(cur->mask) ); -#endif if ((remote_ip & cur->mask) == cur->ip) { if (cur->allow_deny == 'A') return; @@ -2015,8 +2012,7 @@ static int check_user_passwd(const char *path, char *user_and_passwd) if (prev && strcmp(prev, dir_prefix) != 0) continue; - if (DEBUG) - fprintf(stderr, "checkPerm: '%s' ? '%s'\n", dir_prefix, user_and_passwd); + dbg("checkPerm: '%s' ? '%s'\n", dir_prefix, user_and_passwd); /* If it's not a prefix match, continue searching */ len = strlen(dir_prefix); @@ -2231,8 +2227,22 @@ static void handle_incoming_and_exit(const len_and_sockaddr *fromAddr) /* Install timeout handler. get_line() needs it. */ signal(SIGALRM, send_REQUEST_TIMEOUT_and_exit); - if (!get_line()) /* EOF or error or empty line */ - send_headers_and_exit(HTTP_BAD_REQUEST); + if (!get_line()) { /* EOF or error or empty line */ + /* Observed Firefox to "speculatively" open + * extra connections to a new site on first access, + * they are closed in ~5 seconds with nothing + * being sent at all. + * (Presumably it's a method to decrease latency?) + */ + if (verbose > 2) + bb_simple_error_msg("eof on read, closing"); + /* Don't bother generating error page in this case, + * just close the socket. + */ + //send_headers_and_exit(HTTP_BAD_REQUEST); + _exit(xfunc_error_retval); + } + dbg("Request:'%s'\n", iobuf); /* Find URL */ // rfc2616: method and URI is separated by exactly one space @@ -2445,8 +2455,7 @@ static void handle_incoming_and_exit(const len_and_sockaddr *fromAddr) if (total_headers_len >= MAX_HTTP_HEADERS_SIZE) send_headers_and_exit(HTTP_ENTITY_TOO_LARGE); #endif - if (DEBUG) - bb_error_msg("header: '%s'", iobuf); + dbg("header:'%s'\n", iobuf); #if ENABLE_FEATURE_HTTPD_CGI /* Only POST needs to know POST_length */ if (prequest == request_POST && STRNCASECMP(iobuf, "Content-Length:") == 0) { -- cgit v1.2.3-55-g6feb From ac4a0b3be77f2b4280fd95849a0259e1351eeb43 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Wed, 5 May 2021 15:31:18 +0200 Subject: httpd: add comment about faster rejection of denied IPs Signed-off-by: Denys Vlasenko --- networking/httpd.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/networking/httpd.c b/networking/httpd.c index fb6ffe542..56ab85b82 100644 --- a/networking/httpd.c +++ b/networking/httpd.c @@ -2632,6 +2632,13 @@ static void mini_httpd(int server_socket) n = accept(server_socket, &fromAddr.u.sa, &fromAddr.len); if (n < 0) continue; +//TODO: we can reject connects from denied IPs right away; +//also, we might want to do one MSG_DONTWAIT'ed recv() here +//to detect immediate EOF, +//to avoid forking a whole new process for attackers +//who open and close lots of connections. +//(OTOH, the real mitigtion for this sort of thing is +//to ratelimit connects in iptables) /* set the KEEPALIVE option to cull dead connections */ setsockopt_keepalive(n); -- cgit v1.2.3-55-g6feb From 7de0ab21d939a5a304157f75918d0318a95261a3 Mon Sep 17 00:00:00 2001 From: Mario Abajo Date: Thu, 6 May 2021 02:10:47 +0200 Subject: login: permit change expired password wit PAM Signed-off-by: Mario Abajo Signed-off-by: Denys Vlasenko --- loginutils/login.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/loginutils/login.c b/loginutils/login.c index 66ac7cf4c..ce87e318a 100644 --- a/loginutils/login.c +++ b/loginutils/login.c @@ -442,6 +442,9 @@ int login_main(int argc UNUSED_PARAM, char **argv) } /* check that the account is healthy */ pamret = pam_acct_mgmt(pamh, 0); + if (pamret == PAM_NEW_AUTHTOK_REQD) { + pamret = pam_chauthtok(pamh, PAM_CHANGE_EXPIRED_AUTHTOK); + } if (pamret != PAM_SUCCESS) { failed_msg = "acct_mgmt"; goto pam_auth_failed; -- cgit v1.2.3-55-g6feb