aboutsummaryrefslogtreecommitdiff
path: root/libbb
diff options
context:
space:
mode:
authorRon Yorston <rmy@pobox.com>2016-10-19 17:01:55 +0100
committerRon Yorston <rmy@pobox.com>2016-10-19 17:01:55 +0100
commit075814c60a316cfd088c88f26f75ab21b5850b98 (patch)
treef6e33ac693630827deb309faa5fa4931588db57d /libbb
parent977d65c1bbc57f5cdd0c8bfd67c8b5bb1cd390dd (diff)
parentf37e1155aabde6bd95d267a8aec347cedccb8bc3 (diff)
downloadbusybox-w32-075814c60a316cfd088c88f26f75ab21b5850b98.tar.gz
busybox-w32-075814c60a316cfd088c88f26f75ab21b5850b98.tar.bz2
busybox-w32-075814c60a316cfd088c88f26f75ab21b5850b98.zip
Merge branch busybox (up to "ash: comment out free(p) just before...")
Diffstat (limited to 'libbb')
-rw-r--r--libbb/appletlib.c12
-rw-r--r--libbb/copy_file.c16
-rw-r--r--libbb/dump.c51
-rw-r--r--libbb/hash_md5_sha.c55
-rw-r--r--libbb/lineedit.c22
-rw-r--r--libbb/login.c40
-rw-r--r--libbb/speed_table.c81
-rw-r--r--libbb/udp_io.c10
-rw-r--r--libbb/vfork_daemon_rexec.c5
-rw-r--r--libbb/xconnect.c7
-rw-r--r--libbb/xfuncs_printf.c12
11 files changed, 238 insertions, 73 deletions
diff --git a/libbb/appletlib.c b/libbb/appletlib.c
index 28adf2740..4aa40454f 100644
--- a/libbb/appletlib.c
+++ b/libbb/appletlib.c
@@ -930,7 +930,9 @@ void FAST_FUNC run_applet_no_and_exit(int applet_no, char **argv)
930 } 930 }
931 if (ENABLE_FEATURE_SUID) 931 if (ENABLE_FEATURE_SUID)
932 check_suid(applet_no); 932 check_suid(applet_no);
933 exit(applet_main[applet_no](argc, argv)); 933 xfunc_error_retval = applet_main[applet_no](argc, argv);
934 /* Note: applet_main() may also not return (die on a xfunc or such) */
935 xfunc_die();
934} 936}
935# endif /* NUM_APPLETS > 0 */ 937# endif /* NUM_APPLETS > 0 */
936 938
@@ -993,6 +995,14 @@ int main(int argc UNUSED_PARAM, char **argv)
993 */ 995 */
994 mallopt(M_MMAP_THRESHOLD, 32 * 1024 - 256); 996 mallopt(M_MMAP_THRESHOLD, 32 * 1024 - 256);
995#endif 997#endif
998#if 0 /*def M_TOP_PAD*/
999 /* When the program break is increased, then M_TOP_PAD bytes are added
1000 * to the sbrk(2) request. When the heap is trimmed because of free(3),
1001 * this much free space is preserved at the top of the heap.
1002 * glibc default seems to be way too big: 128k, but need to verify.
1003 */
1004 mallopt(M_TOP_PAD, 8 * 1024);
1005#endif
996 1006
997#if !BB_MMU 1007#if !BB_MMU
998 /* NOMMU re-exec trick sets high-order bit in first byte of name */ 1008 /* NOMMU re-exec trick sets high-order bit in first byte of name */
diff --git a/libbb/copy_file.c b/libbb/copy_file.c
index c52297376..cb6d12359 100644
--- a/libbb/copy_file.c
+++ b/libbb/copy_file.c
@@ -299,11 +299,16 @@ int FAST_FUNC copy_file(const char *source, const char *dest, int flags)
299 if (!S_ISREG(source_stat.st_mode)) 299 if (!S_ISREG(source_stat.st_mode))
300 new_mode = 0666; 300 new_mode = 0666;
301 301
302 // POSIX way is a security problem versus (sym)link attacks 302 if (ENABLE_FEATURE_NON_POSIX_CP || (flags & FILEUTILS_INTERACTIVE)) {
303 if (!ENABLE_FEATURE_NON_POSIX_CP) { 303 /*
304 dst_fd = open(dest, O_WRONLY|O_CREAT|O_TRUNC, new_mode); 304 * O_CREAT|O_EXCL: require that file did not exist before creation
305 } else { /* safe way: */ 305 */
306 dst_fd = open(dest, O_WRONLY|O_CREAT|O_EXCL, new_mode); 306 dst_fd = open(dest, O_WRONLY|O_CREAT|O_EXCL, new_mode);
307 } else { /* POSIX, and not "cp -i" */
308 /*
309 * O_CREAT|O_TRUNC: create, or truncate (security problem versus (sym)link attacks)
310 */
311 dst_fd = open(dest, O_WRONLY|O_CREAT|O_TRUNC, new_mode);
307 } 312 }
308 if (dst_fd == -1) { 313 if (dst_fd == -1) {
309 ovr = ask_and_unlink(dest, flags); 314 ovr = ask_and_unlink(dest, flags);
@@ -378,7 +383,7 @@ int FAST_FUNC copy_file(const char *source, const char *dest, int flags)
378 } 383 }
379 /* _Not_ jumping to preserve_mode_ugid_time: 384 /* _Not_ jumping to preserve_mode_ugid_time:
380 * symlinks don't have those */ 385 * symlinks don't have those */
381 return 0; 386 goto verb_and_exit;
382 } 387 }
383 if (S_ISBLK(source_stat.st_mode) || S_ISCHR(source_stat.st_mode) 388 if (S_ISBLK(source_stat.st_mode) || S_ISCHR(source_stat.st_mode)
384 || S_ISSOCK(source_stat.st_mode) || S_ISFIFO(source_stat.st_mode) 389 || S_ISSOCK(source_stat.st_mode) || S_ISFIFO(source_stat.st_mode)
@@ -413,6 +418,7 @@ int FAST_FUNC copy_file(const char *source, const char *dest, int flags)
413 bb_perror_msg("can't preserve %s of '%s'", "permissions", dest); 418 bb_perror_msg("can't preserve %s of '%s'", "permissions", dest);
414 } 419 }
415 420
421 verb_and_exit:
416 if (flags & FILEUTILS_VERBOSE) { 422 if (flags & FILEUTILS_VERBOSE) {
417 printf("'%s' -> '%s'\n", source, dest); 423 printf("'%s' -> '%s'\n", source, dest);
418 } 424 }
diff --git a/libbb/dump.c b/libbb/dump.c
index 566881a78..154be5d80 100644
--- a/libbb/dump.c
+++ b/libbb/dump.c
@@ -157,7 +157,7 @@ static NOINLINE void rewrite(priv_dumper_t *dumper, FS *fs)
157 /* 157 /*
158 * figure out the byte count for each conversion; 158 * figure out the byte count for each conversion;
159 * rewrite the format as necessary, set up blank- 159 * rewrite the format as necessary, set up blank-
160 * pbb_dump_adding for end of data. 160 * padding for end of data.
161 */ 161 */
162 if (*p1 == 'c') { 162 if (*p1 == 'c') {
163 pr->flags = F_CHAR; 163 pr->flags = F_CHAR;
@@ -466,14 +466,14 @@ static void bpad(PR *pr)
466} 466}
467 467
468static const char conv_str[] ALIGN1 = 468static const char conv_str[] ALIGN1 =
469 "\0\\0\0" 469 "\0" "\\""0""\0"
470 "\007\\a\0" /* \a */ 470 "\007""\\""a""\0" /* \a */
471 "\b\\b\0" 471 "\b" "\\""b""\0"
472 "\f\\b\0" 472 "\f" "\\""f""\0"
473 "\n\\n\0" 473 "\n" "\\""n""\0"
474 "\r\\r\0" 474 "\r" "\\""r""\0"
475 "\t\\t\0" 475 "\t" "\\""t""\0"
476 "\v\\v\0" 476 "\v" "\\""v""\0"
477 ; 477 ;
478 478
479 479
@@ -485,7 +485,7 @@ static void conv_c(PR *pr, unsigned char *p)
485 do { 485 do {
486 if (*p == *str) { 486 if (*p == *str) {
487 ++str; 487 ++str;
488 goto strpr; 488 goto strpr; /* map e.g. '\n' to "\\n" */
489 } 489 }
490 str += 4; 490 str += 4;
491 } while (*str); 491 } while (*str);
@@ -702,8 +702,6 @@ int FAST_FUNC bb_dump_dump(dumper_t *pub_dumper, char **argv)
702void FAST_FUNC bb_dump_add(dumper_t* pub_dumper, const char *fmt) 702void FAST_FUNC bb_dump_add(dumper_t* pub_dumper, const char *fmt)
703{ 703{
704 const char *p; 704 const char *p;
705 char *p1;
706 char *p2;
707 FS *tfs; 705 FS *tfs;
708 FU *tfu, **nextfupp; 706 FU *tfu, **nextfupp;
709 const char *savep; 707 const char *savep;
@@ -779,29 +777,42 @@ void FAST_FUNC bb_dump_add(dumper_t* pub_dumper, const char *fmt)
779 } 777 }
780 } 778 }
781 tfu->fmt = xstrndup(savep, p - savep); 779 tfu->fmt = xstrndup(savep, p - savep);
782/* escape(tfu->fmt); */
783
784 p1 = tfu->fmt;
785 780
786 /* alphabetic escape sequences have to be done in place */ 781 /* alphabetic escape sequences have to be done in place */
782 strcpy_and_process_escape_sequences(tfu->fmt, tfu->fmt);
783 /* unknown mappings are not changed: "\z" -> '\\' 'z' */
784 /* trailing backslash, if any, is preserved */
785#if 0
786 char *p1;
787 char *p2;
788 p1 = tfu->fmt;
787 for (p2 = p1;; ++p1, ++p2) { 789 for (p2 = p1;; ++p1, ++p2) {
788 if (*p1 == '\0') { 790 *p2 = *p1;
789 *p2 = *p1; 791 if (*p1 == '\0')
790 break; 792 break;
791 } 793
792 if (*p1 == '\\') { 794 if (*p1 == '\\') {
793 const char *cs = conv_str + 4; 795 const char *cs;
794 ++p1; 796
797 p1++;
795 *p2 = *p1; 798 *p2 = *p1;
799 if (*p1 == '\0') {
800 /* "...\" trailing backslash. Eaten. */
801 break;
802 }
803 cs = conv_str + 4; /* skip NUL element */
796 do { 804 do {
805 /* map e.g. "\n" -> '\n' */
797 if (*p1 == cs[2]) { 806 if (*p1 == cs[2]) {
798 *p2 = cs[0]; 807 *p2 = cs[0];
799 break; 808 break;
800 } 809 }
801 cs += 4; 810 cs += 4;
802 } while (*cs); 811 } while (*cs);
812 /* unknown mappings remove bkslash: "\z" -> 'z' */
803 } 813 }
804 } 814 }
815#endif
805 816
806 p++; 817 p++;
807 } 818 }
diff --git a/libbb/hash_md5_sha.c b/libbb/hash_md5_sha.c
index d08c6b2f7..7e7d8da2f 100644
--- a/libbb/hash_md5_sha.c
+++ b/libbb/hash_md5_sha.c
@@ -941,10 +941,6 @@ void FAST_FUNC sha512_end(sha512_ctx_t *ctx, void *resbuf)
941# define OPTIMIZE_SHA3_FOR_32 1 941# define OPTIMIZE_SHA3_FOR_32 1
942#endif 942#endif
943 943
944enum {
945 SHA3_IBLK_BYTES = 72, /* 576 bits / 8 */
946};
947
948#if OPTIMIZE_SHA3_FOR_32 944#if OPTIMIZE_SHA3_FOR_32
949/* This splits every 64-bit word into a pair of 32-bit words, 945/* This splits every 64-bit word into a pair of 32-bit words,
950 * even bits go into first word, odd bits go to second one. 946 * even bits go into first word, odd bits go to second one.
@@ -1352,6 +1348,8 @@ static void sha3_process_block72(uint64_t *state)
1352void FAST_FUNC sha3_begin(sha3_ctx_t *ctx) 1348void FAST_FUNC sha3_begin(sha3_ctx_t *ctx)
1353{ 1349{
1354 memset(ctx, 0, sizeof(*ctx)); 1350 memset(ctx, 0, sizeof(*ctx));
1351 /* SHA3-512, user can override */
1352 ctx->input_block_bytes = (1600 - 512*2) / 8; /* 72 bytes */
1355} 1353}
1356 1354
1357void FAST_FUNC sha3_hash(sha3_ctx_t *ctx, const void *buffer, size_t len) 1355void FAST_FUNC sha3_hash(sha3_ctx_t *ctx, const void *buffer, size_t len)
@@ -1361,7 +1359,7 @@ void FAST_FUNC sha3_hash(sha3_ctx_t *ctx, const void *buffer, size_t len)
1361 unsigned bufpos = ctx->bytes_queued; 1359 unsigned bufpos = ctx->bytes_queued;
1362 1360
1363 while (1) { 1361 while (1) {
1364 unsigned remaining = SHA3_IBLK_BYTES - bufpos; 1362 unsigned remaining = ctx->input_block_bytes - bufpos;
1365 if (remaining > len) 1363 if (remaining > len)
1366 remaining = len; 1364 remaining = len;
1367 len -= remaining; 1365 len -= remaining;
@@ -1373,38 +1371,41 @@ void FAST_FUNC sha3_hash(sha3_ctx_t *ctx, const void *buffer, size_t len)
1373 remaining--; 1371 remaining--;
1374 } 1372 }
1375 /* Clever way to do "if (bufpos != N) break; ... ; bufpos = 0;" */ 1373 /* Clever way to do "if (bufpos != N) break; ... ; bufpos = 0;" */
1376 bufpos -= SHA3_IBLK_BYTES; 1374 bufpos -= ctx->input_block_bytes;
1377 if (bufpos != 0) 1375 if (bufpos != 0)
1378 break; 1376 break;
1379 /* Buffer is filled up, process it */ 1377 /* Buffer is filled up, process it */
1380 sha3_process_block72(ctx->state); 1378 sha3_process_block72(ctx->state);
1381 /*bufpos = 0; - already is */ 1379 /*bufpos = 0; - already is */
1382 } 1380 }
1383 ctx->bytes_queued = bufpos + SHA3_IBLK_BYTES; 1381 ctx->bytes_queued = bufpos + ctx->input_block_bytes;
1384#else 1382#else
1385 /* +50 bytes code size, but a bit faster because of long-sized XORs */ 1383 /* +50 bytes code size, but a bit faster because of long-sized XORs */
1386 const uint8_t *data = buffer; 1384 const uint8_t *data = buffer;
1387 unsigned bufpos = ctx->bytes_queued; 1385 unsigned bufpos = ctx->bytes_queued;
1386 unsigned iblk_bytes = ctx->input_block_bytes;
1388 1387
1389 /* If already data in queue, continue queuing first */ 1388 /* If already data in queue, continue queuing first */
1390 while (len != 0 && bufpos != 0) { 1389 if (bufpos != 0) {
1391 uint8_t *buf = (uint8_t*)ctx->state; 1390 while (len != 0) {
1392 buf[bufpos] ^= *data++; 1391 uint8_t *buf = (uint8_t*)ctx->state;
1393 len--; 1392 buf[bufpos] ^= *data++;
1394 bufpos++; 1393 len--;
1395 if (bufpos == SHA3_IBLK_BYTES) { 1394 bufpos++;
1396 bufpos = 0; 1395 if (bufpos == iblk_bytes) {
1397 goto do_block; 1396 bufpos = 0;
1397 goto do_block;
1398 }
1398 } 1399 }
1399 } 1400 }
1400 1401
1401 /* Absorb complete blocks */ 1402 /* Absorb complete blocks */
1402 while (len >= SHA3_IBLK_BYTES) { 1403 while (len >= iblk_bytes) {
1403 /* XOR data onto beginning of state[]. 1404 /* XOR data onto beginning of state[].
1404 * We try to be efficient - operate one word at a time, not byte. 1405 * We try to be efficient - operate one word at a time, not byte.
1405 * Careful wrt unaligned access: can't just use "*(long*)data"! 1406 * Careful wrt unaligned access: can't just use "*(long*)data"!
1406 */ 1407 */
1407 unsigned count = SHA3_IBLK_BYTES / sizeof(long); 1408 unsigned count = iblk_bytes / sizeof(long);
1408 long *buf = (long*)ctx->state; 1409 long *buf = (long*)ctx->state;
1409 do { 1410 do {
1410 long v; 1411 long v;
@@ -1412,7 +1413,7 @@ void FAST_FUNC sha3_hash(sha3_ctx_t *ctx, const void *buffer, size_t len)
1412 *buf++ ^= v; 1413 *buf++ ^= v;
1413 data += sizeof(long); 1414 data += sizeof(long);
1414 } while (--count); 1415 } while (--count);
1415 len -= SHA3_IBLK_BYTES; 1416 len -= iblk_bytes;
1416 do_block: 1417 do_block:
1417 sha3_process_block72(ctx->state); 1418 sha3_process_block72(ctx->state);
1418 } 1419 }
@@ -1433,8 +1434,22 @@ void FAST_FUNC sha3_end(sha3_ctx_t *ctx, void *resbuf)
1433{ 1434{
1434 /* Padding */ 1435 /* Padding */
1435 uint8_t *buf = (uint8_t*)ctx->state; 1436 uint8_t *buf = (uint8_t*)ctx->state;
1436 buf[ctx->bytes_queued] ^= 1; 1437 /*
1437 buf[SHA3_IBLK_BYTES - 1] ^= 0x80; 1438 * Keccak block padding is: add 1 bit after last bit of input,
1439 * then add zero bits until the end of block, and add the last 1 bit
1440 * (the last bit in the block) - the "10*1" pattern.
1441 * SHA3 standard appends additional two bits, 01, before that padding:
1442 *
1443 * SHA3-224(M) = KECCAK[448](M||01, 224)
1444 * SHA3-256(M) = KECCAK[512](M||01, 256)
1445 * SHA3-384(M) = KECCAK[768](M||01, 384)
1446 * SHA3-512(M) = KECCAK[1024](M||01, 512)
1447 * (M is the input, || is bit concatenation)
1448 *
1449 * The 6 below contains 01 "SHA3" bits and the first 1 "Keccak" bit:
1450 */
1451 buf[ctx->bytes_queued] ^= 6; /* bit pattern 00000110 */
1452 buf[ctx->input_block_bytes - 1] ^= 0x80;
1438 1453
1439 sha3_process_block72(ctx->state); 1454 sha3_process_block72(ctx->state);
1440 1455
diff --git a/libbb/lineedit.c b/libbb/lineedit.c
index 2566abd38..34eb16e6b 100644
--- a/libbb/lineedit.c
+++ b/libbb/lineedit.c
@@ -81,7 +81,9 @@
81# define CHAR_T wchar_t 81# define CHAR_T wchar_t
82static bool BB_isspace(CHAR_T c) { return ((unsigned)c < 256 && isspace(c)); } 82static bool BB_isspace(CHAR_T c) { return ((unsigned)c < 256 && isspace(c)); }
83# if ENABLE_FEATURE_EDITING_VI 83# if ENABLE_FEATURE_EDITING_VI
84static bool BB_isalnum(CHAR_T c) { return ((unsigned)c < 256 && isalnum(c)); } 84static bool BB_isalnum_or_underscore(CHAR_T c) {
85 return ((unsigned)c < 256 && isalnum(c)) || c == '_';
86}
85# endif 87# endif
86static bool BB_ispunct(CHAR_T c) { return ((unsigned)c < 256 && ispunct(c)); } 88static bool BB_ispunct(CHAR_T c) { return ((unsigned)c < 256 && ispunct(c)); }
87# undef isspace 89# undef isspace
@@ -96,7 +98,11 @@ static bool BB_ispunct(CHAR_T c) { return ((unsigned)c < 256 && ispunct(c)); }
96# define BB_NUL '\0' 98# define BB_NUL '\0'
97# define CHAR_T char 99# define CHAR_T char
98# define BB_isspace(c) isspace(c) 100# define BB_isspace(c) isspace(c)
99# define BB_isalnum(c) isalnum(c) 101# if ENABLE_FEATURE_EDITING_VI
102static bool BB_isalnum_or_underscore(CHAR_T c) {
103 return ((unsigned)c < 256 && isalnum(c)) || c == '_';
104}
105# endif
100# define BB_ispunct(c) ispunct(c) 106# define BB_ispunct(c) ispunct(c)
101#endif 107#endif
102#if ENABLE_UNICODE_PRESERVE_BROKEN 108#if ENABLE_UNICODE_PRESERVE_BROKEN
@@ -1647,9 +1653,9 @@ vi_word_motion(int eat)
1647{ 1653{
1648 CHAR_T *command = command_ps; 1654 CHAR_T *command = command_ps;
1649 1655
1650 if (BB_isalnum(command[cursor]) || command[cursor] == '_') { 1656 if (BB_isalnum_or_underscore(command[cursor])) {
1651 while (cursor < command_len 1657 while (cursor < command_len
1652 && (BB_isalnum(command[cursor+1]) || command[cursor+1] == '_') 1658 && (BB_isalnum_or_underscore(command[cursor+1]))
1653 ) { 1659 ) {
1654 input_forward(); 1660 input_forward();
1655 } 1661 }
@@ -1691,9 +1697,9 @@ vi_end_motion(void)
1691 input_forward(); 1697 input_forward();
1692 if (cursor >= command_len-1) 1698 if (cursor >= command_len-1)
1693 return; 1699 return;
1694 if (BB_isalnum(command[cursor]) || command[cursor] == '_') { 1700 if (BB_isalnum_or_underscore(command[cursor])) {
1695 while (cursor < command_len-1 1701 while (cursor < command_len-1
1696 && (BB_isalnum(command[cursor+1]) || command[cursor+1] == '_') 1702 && (BB_isalnum_or_underscore(command[cursor+1]))
1697 ) { 1703 ) {
1698 input_forward(); 1704 input_forward();
1699 } 1705 }
@@ -1726,9 +1732,9 @@ vi_back_motion(void)
1726 input_backward(1); 1732 input_backward(1);
1727 if (cursor <= 0) 1733 if (cursor <= 0)
1728 return; 1734 return;
1729 if (BB_isalnum(command[cursor]) || command[cursor] == '_') { 1735 if (BB_isalnum_or_underscore(command[cursor])) {
1730 while (cursor > 0 1736 while (cursor > 0
1731 && (BB_isalnum(command[cursor-1]) || command[cursor-1] == '_') 1737 && (BB_isalnum_or_underscore(command[cursor-1]))
1732 ) { 1738 ) {
1733 input_backward(1); 1739 input_backward(1);
1734 } 1740 }
diff --git a/libbb/login.c b/libbb/login.c
index 8f080b775..5a7acfcf0 100644
--- a/libbb/login.c
+++ b/libbb/login.c
@@ -45,6 +45,45 @@ void FAST_FUNC print_login_issue(const char *issue_file, const char *tty)
45 if (c == '\\' || c == '%') { 45 if (c == '\\' || c == '%') {
46 c = fgetc(fp); 46 c = fgetc(fp);
47 switch (c) { 47 switch (c) {
48//From getty manpage (* - supported by us)
49//========================================
50//4 or 4{interface}
51// Insert the IPv4 address of the network interface (example: \4{eth0}).
52// If the interface argument is not specified, then select the first
53// fully configured (UP, non-LOOPBACK, RUNNING) interface.
54//6 or 6{interface} -- The same as \4 but for IPv6.
55//b -- Insert the baudrate of the current line.
56//*d -- Insert the current date.
57//*t -- Insert the current time.
58//e or e{name}
59// Translate the human-readable name to an escape sequence and insert it
60// (for example: \e{red}Alert text.\e{reset}). If the name argument
61// is not specified, then insert \033. The currently supported names are:
62// black, blink, blue, bold, brown, cyan, darkgray, gray, green, halfbright,
63// lightblue, lightcyan, lightgray, lightgreen, lightmagenta, lightred,
64// magenta, red, reset, reverse, and yellow. Unknown names are ignored.
65//*s
66// Insert the system name (the name of the operating system - `uname -s`)
67//*S or S{VARIABLE}
68// Insert the VARIABLE data from /etc/os-release.
69// If the VARIABLE argument is not specified, use PRETTY_NAME.
70// If PRETTY_NAME is not in /etc/os-release, \S is the same as \s.
71//*l -- Insert the name of the current tty line.
72//*m -- Insert the architecture identifier of the machine: `uname -m`.
73//*n -- Insert the nodename of the machine: `uname -n`.
74//*o -- Insert the NIS domainname of the machine. Same as `hostname -d'.
75//*O -- Insert the DNS domainname of the machine.
76//*r -- Insert the release number of the OS: `uname -r`.
77//u -- Insert the number of current users logged in.
78//U -- Insert the string "1 user" or "N users" (current users logged in).
79//*v -- Insert the version of the OS, e.g. the build-date etc: `uname -v`.
80//We also implement:
81//*D -- same as \O "DNS domainname"
82//*h -- same as \n "nodename"
83
84 case 'S':
85 /* minimal implementation, not reading /etc/os-release */
86 /*FALLTHROUGH*/
48 case 's': 87 case 's':
49 outbuf = uts.sysname; 88 outbuf = uts.sysname;
50 break; 89 break;
@@ -65,6 +104,7 @@ void FAST_FUNC print_login_issue(const char *issue_file, const char *tty)
65#if defined(__linux__) 104#if defined(__linux__)
66 case 'D': 105 case 'D':
67 case 'o': 106 case 'o':
107 case 'O':
68 outbuf = uts.domainname; 108 outbuf = uts.domainname;
69 break; 109 break;
70#endif 110#endif
diff --git a/libbb/speed_table.c b/libbb/speed_table.c
index 174d531b2..11ced01d0 100644
--- a/libbb/speed_table.c
+++ b/libbb/speed_table.c
@@ -10,7 +10,16 @@
10#include "libbb.h" 10#include "libbb.h"
11 11
12struct speed_map { 12struct speed_map {
13#if defined __FreeBSD__ 13#if defined __FreeBSD__ \
14 || (defined B115200 && B115200 > 0xffff) \
15 || (defined B230400 && B230400 > 0xffff) \
16 || (defined B460800 && B460800 > 0xffff) \
17 || (defined B921600 && B921600 > 0xffff) \
18 || (defined B1152000 && B1152000 > 0xffff) \
19 || (defined B1000000 && B1000000 > 0xffff) \
20 || (defined B2000000 && B2000000 > 0xffff) \
21 || (defined B3000000 && B3000000 > 0xffff) \
22 || (defined B4000000 && B4000000 > 0xffff)
14 /* On FreeBSD, B<num> constants don't fit into a short */ 23 /* On FreeBSD, B<num> constants don't fit into a short */
15 unsigned speed; 24 unsigned speed;
16#else 25#else
@@ -19,6 +28,7 @@ struct speed_map {
19 unsigned short value; 28 unsigned short value;
20}; 29};
21 30
31/* On Linux, Bxx constants are 0..15 (up to B38400) and 0x1001..0x100f */
22static const struct speed_map speeds[] = { 32static const struct speed_map speeds[] = {
23 {B0, 0}, 33 {B0, 0},
24 {B50, 50}, 34 {B50, 50},
@@ -37,30 +47,79 @@ static const struct speed_map speeds[] = {
37#ifdef B19200 47#ifdef B19200
38 {B19200, 19200}, 48 {B19200, 19200},
39#elif defined(EXTA) 49#elif defined(EXTA)
40 {EXTA, 19200}, 50 {EXTA, 19200},
41#endif 51#endif
52/* 19200 = 0x4b00 */
53/* 38400 = 0x9600, this value would use bit#15 if not "/200" encoded: */
42#ifdef B38400 54#ifdef B38400
43 {B38400, 38400/256 + 0x8000U}, 55 {B38400, 38400/200 + 0x8000u},
44#elif defined(EXTB) 56#elif defined(EXTB)
45 {EXTB, 38400/256 + 0x8000U}, 57 {EXTB, 38400/200 + 0x8000u},
46#endif 58#endif
47#ifdef B57600 59#ifdef B57600
48 {B57600, 57600/256 + 0x8000U}, 60 {B57600, 57600/200 + 0x8000u},
49#endif 61#endif
50#ifdef B115200 62#ifdef B115200
51 {B115200, 115200/256 + 0x8000U}, 63 {B115200, 115200/200 + 0x8000u},
52#endif 64#endif
53#ifdef B230400 65#ifdef B230400
54 {B230400, 230400/256 + 0x8000U}, 66 {B230400, 230400/200 + 0x8000u},
55#endif 67#endif
56#ifdef B460800 68#ifdef B460800
57 {B460800, 460800/256 + 0x8000U}, 69 {B460800, 460800/200 + 0x8000u},
70#endif
71#ifdef B576000
72 {B576000, 576000/200 + 0x8000u},
58#endif 73#endif
59#ifdef B921600 74#ifdef B921600
60 {B921600, 921600/256 + 0x8000U}, 75 {B921600, 921600/200 + 0x8000u},
76#endif
77#ifdef B1152000
78 {B1152000, 1152000/200 + 0x8000u},
79#endif
80
81#ifdef B500000
82 {B500000, 500000/200 + 0x8000u},
83#endif
84#ifdef B1000000
85 {B1000000, 1000000/200 + 0x8000u},
86#endif
87#ifdef B1500000
88 {B1500000, 1500000/200 + 0x8000u},
89#endif
90#ifdef B2000000
91 {B2000000, 2000000/200 + 0x8000u},
92#endif
93#ifdef B2500000
94 {B2500000, 2500000/200 + 0x8000u},
61#endif 95#endif
96#ifdef B3000000
97 {B3000000, 3000000/200 + 0x8000u},
98#endif
99#ifdef B3500000
100 {B3500000, 3500000/200 + 0x8000u},
101#endif
102#ifdef B4000000
103 {B4000000, 4000000/200 + 0x8000u},
104#endif
105/* 4000000/200 = 0x4e20, bit#15 still does not interfere with the value */
106/* (can use /800 if higher speeds would appear, /1600 won't work for B500000) */
62}; 107};
63 108
109/*
110 * TODO: maybe we can just bite the bullet, ditch the table and use termios2
111 * Linux API (supports arbitrary baud rates, no Bxxxx mess needed)? Example:
112 *
113 * #include <asm/termios.h>
114 * #include <asm/ioctls.h>
115 * struct termios2 t;
116 * ioctl(fd, TCGETS2, &t);
117 * t.c_ospeed = t.c_ispeed = 543210;
118 * t.c_cflag &= ~CBAUD;
119 * t.c_cflag |= BOTHER;
120 * ioctl(fd, TCSETS2, &t);
121 */
122
64enum { NUM_SPEEDS = ARRAY_SIZE(speeds) }; 123enum { NUM_SPEEDS = ARRAY_SIZE(speeds) };
65 124
66unsigned FAST_FUNC tty_baud_to_value(speed_t speed) 125unsigned FAST_FUNC tty_baud_to_value(speed_t speed)
@@ -69,8 +128,8 @@ unsigned FAST_FUNC tty_baud_to_value(speed_t speed)
69 128
70 do { 129 do {
71 if (speed == speeds[i].speed) { 130 if (speed == speeds[i].speed) {
72 if (speeds[i].value & 0x8000U) { 131 if (speeds[i].value & 0x8000u) {
73 return ((unsigned long) (speeds[i].value) & 0x7fffU) * 256; 132 return ((unsigned)(speeds[i].value) & 0x7fffU) * 200;
74 } 133 }
75 return speeds[i].value; 134 return speeds[i].value;
76 } 135 }
diff --git a/libbb/udp_io.c b/libbb/udp_io.c
index a32af9bd2..6e3ef484e 100644
--- a/libbb/udp_io.c
+++ b/libbb/udp_io.c
@@ -70,7 +70,13 @@ send_to_from(int fd, void *buf, size_t len, int flags,
70 msg.msg_flags = flags; 70 msg.msg_flags = flags;
71 71
72 cmsgptr = CMSG_FIRSTHDR(&msg); 72 cmsgptr = CMSG_FIRSTHDR(&msg);
73 if (to->sa_family == AF_INET && from->sa_family == AF_INET) { 73 /*
74 * Users report that to->sa_family can be AF_INET6 too,
75 * if "to" was acquired by recv_from_to(). IOW: recv_from_to()
76 * was seen showing IPv6 "from" even when the destination
77 * of received packet (our local address) was IPv4.
78 */
79 if (/* to->sa_family == AF_INET && */ from->sa_family == AF_INET) {
74 struct in_pktinfo *pktptr; 80 struct in_pktinfo *pktptr;
75 cmsgptr->cmsg_level = IPPROTO_IP; 81 cmsgptr->cmsg_level = IPPROTO_IP;
76 cmsgptr->cmsg_type = IP_PKTINFO; 82 cmsgptr->cmsg_type = IP_PKTINFO;
@@ -86,7 +92,7 @@ send_to_from(int fd, void *buf, size_t len, int flags,
86 pktptr->ipi_spec_dst = ((struct sockaddr_in*)from)->sin_addr; 92 pktptr->ipi_spec_dst = ((struct sockaddr_in*)from)->sin_addr;
87 } 93 }
88# if ENABLE_FEATURE_IPV6 && defined(IPV6_PKTINFO) 94# if ENABLE_FEATURE_IPV6 && defined(IPV6_PKTINFO)
89 else if (to->sa_family == AF_INET6 && from->sa_family == AF_INET6) { 95 else if (/* to->sa_family == AF_INET6 && */ from->sa_family == AF_INET6) {
90 struct in6_pktinfo *pktptr; 96 struct in6_pktinfo *pktptr;
91 cmsgptr->cmsg_level = IPPROTO_IPV6; 97 cmsgptr->cmsg_level = IPPROTO_IPV6;
92 cmsgptr->cmsg_type = IPV6_PKTINFO; 98 cmsgptr->cmsg_type = IPV6_PKTINFO;
diff --git a/libbb/vfork_daemon_rexec.c b/libbb/vfork_daemon_rexec.c
index f488f8e0c..766a89e5f 100644
--- a/libbb/vfork_daemon_rexec.c
+++ b/libbb/vfork_daemon_rexec.c
@@ -70,7 +70,8 @@ pid_t FAST_FUNC xspawn(char **argv)
70 return pid; 70 return pid;
71} 71}
72 72
73#if ENABLE_FEATURE_PREFER_APPLETS 73#if ENABLE_FEATURE_PREFER_APPLETS \
74 || ENABLE_FEATURE_SH_NOFORK
74static jmp_buf die_jmp; 75static jmp_buf die_jmp;
75static void jump(void) 76static void jump(void)
76{ 77{
@@ -176,7 +177,7 @@ int FAST_FUNC run_nofork_applet(int applet_no, char **argv)
176 177
177 return rc & 0xff; /* don't confuse people with "exitcodes" >255 */ 178 return rc & 0xff; /* don't confuse people with "exitcodes" >255 */
178} 179}
179#endif /* FEATURE_PREFER_APPLETS */ 180#endif /* FEATURE_PREFER_APPLETS || FEATURE_SH_NOFORK */
180 181
181int FAST_FUNC spawn_and_wait(char **argv) 182int FAST_FUNC spawn_and_wait(char **argv)
182{ 183{
diff --git a/libbb/xconnect.c b/libbb/xconnect.c
index c318af419..ee54898e3 100644
--- a/libbb/xconnect.c
+++ b/libbb/xconnect.c
@@ -500,12 +500,15 @@ char* FAST_FUNC xmalloc_sockaddr2hostonly_noport(const struct sockaddr *sa)
500{ 500{
501 return sockaddr2str(sa, NI_NAMEREQD | IGNORE_PORT); 501 return sockaddr2str(sa, NI_NAMEREQD | IGNORE_PORT);
502} 502}
503#ifndef NI_NUMERICSCOPE
504# define NI_NUMERICSCOPE 0
505#endif
503char* FAST_FUNC xmalloc_sockaddr2dotted(const struct sockaddr *sa) 506char* FAST_FUNC xmalloc_sockaddr2dotted(const struct sockaddr *sa)
504{ 507{
505 return sockaddr2str(sa, NI_NUMERICHOST); 508 return sockaddr2str(sa, NI_NUMERICHOST | NI_NUMERICSCOPE);
506} 509}
507 510
508char* FAST_FUNC xmalloc_sockaddr2dotted_noport(const struct sockaddr *sa) 511char* FAST_FUNC xmalloc_sockaddr2dotted_noport(const struct sockaddr *sa)
509{ 512{
510 return sockaddr2str(sa, NI_NUMERICHOST | IGNORE_PORT); 513 return sockaddr2str(sa, NI_NUMERICHOST | NI_NUMERICSCOPE | IGNORE_PORT);
511} 514}
diff --git a/libbb/xfuncs_printf.c b/libbb/xfuncs_printf.c
index e9222f690..1b11caf6b 100644
--- a/libbb/xfuncs_printf.c
+++ b/libbb/xfuncs_printf.c
@@ -235,8 +235,16 @@ void FAST_FUNC xwrite(int fd, const void *buf, size_t count)
235{ 235{
236 if (count) { 236 if (count) {
237 ssize_t size = full_write(fd, buf, count); 237 ssize_t size = full_write(fd, buf, count);
238 if ((size_t)size != count) 238 if ((size_t)size != count) {
239 bb_error_msg_and_die("short write"); 239 /*
240 * Two cases: write error immediately;
241 * or some writes succeeded, then we hit an error.
242 * In either case, errno is set.
243 */
244 bb_perror_msg_and_die(
245 size >= 0 ? "short write" : "write error"
246 );
247 }
240 } 248 }
241} 249}
242void FAST_FUNC xwrite_str(int fd, const char *str) 250void FAST_FUNC xwrite_str(int fd, const char *str)