aboutsummaryrefslogtreecommitdiff
path: root/coreutils
diff options
context:
space:
mode:
Diffstat (limited to 'coreutils')
-rw-r--r--coreutils/dd.c78
-rw-r--r--coreutils/du.c2
-rw-r--r--coreutils/expr.c2
-rw-r--r--coreutils/factor.c4
-rw-r--r--coreutils/id.c20
-rw-r--r--coreutils/ls.c85
-rw-r--r--coreutils/nproc.c17
-rw-r--r--coreutils/od_bloaty.c7
-rw-r--r--coreutils/printf.c68
-rw-r--r--coreutils/shred.c10
-rw-r--r--coreutils/shuf.c2
-rw-r--r--coreutils/sort.c5
-rw-r--r--coreutils/split.c8
-rw-r--r--coreutils/stat.c5
-rw-r--r--coreutils/sum.c4
-rw-r--r--coreutils/test.c4
-rw-r--r--coreutils/timeout.c73
17 files changed, 373 insertions, 21 deletions
diff --git a/coreutils/dd.c b/coreutils/dd.c
index 8bb782781..e6b88acf5 100644
--- a/coreutils/dd.c
+++ b/coreutils/dd.c
@@ -59,8 +59,13 @@
59//usage: "[if=FILE] [of=FILE] [" IF_FEATURE_DD_IBS_OBS("ibs=N obs=N/") "bs=N] [count=N] [skip=N] [seek=N]" 59//usage: "[if=FILE] [of=FILE] [" IF_FEATURE_DD_IBS_OBS("ibs=N obs=N/") "bs=N] [count=N] [skip=N] [seek=N]"
60//usage: IF_FEATURE_DD_IBS_OBS("\n" 60//usage: IF_FEATURE_DD_IBS_OBS("\n"
61//usage: " [conv=notrunc|noerror|sync|fsync]\n" 61//usage: " [conv=notrunc|noerror|sync|fsync]\n"
62//usage: IF_NOT_PLATFORM_MINGW32(
62//usage: " [iflag=skip_bytes|count_bytes|fullblock|direct] [oflag=seek_bytes|append|direct]" 63//usage: " [iflag=skip_bytes|count_bytes|fullblock|direct] [oflag=seek_bytes|append|direct]"
63//usage: ) 64//usage: )
65//usage: IF_PLATFORM_MINGW32(
66//usage: " [iflag=skip_bytes|count_bytes|fullblock] [oflag=seek_bytes|append]"
67//usage: )
68//usage: )
64//usage:#define dd_full_usage "\n\n" 69//usage:#define dd_full_usage "\n\n"
65//usage: "Copy a file with converting and formatting\n" 70//usage: "Copy a file with converting and formatting\n"
66//usage: "\n if=FILE Read from FILE instead of stdin" 71//usage: "\n if=FILE Read from FILE instead of stdin"
@@ -84,8 +89,10 @@
84//usage: "\n iflag=skip_bytes skip=N is in bytes" 89//usage: "\n iflag=skip_bytes skip=N is in bytes"
85//usage: "\n iflag=count_bytes count=N is in bytes" 90//usage: "\n iflag=count_bytes count=N is in bytes"
86//usage: "\n oflag=seek_bytes seek=N is in bytes" 91//usage: "\n oflag=seek_bytes seek=N is in bytes"
92//usage: IF_NOT_PLATFORM_MINGW32(
87//usage: "\n iflag=direct O_DIRECT input" 93//usage: "\n iflag=direct O_DIRECT input"
88//usage: "\n oflag=direct O_DIRECT output" 94//usage: "\n oflag=direct O_DIRECT output"
95//usage: )
89//usage: "\n iflag=fullblock Read full blocks" 96//usage: "\n iflag=fullblock Read full blocks"
90//usage: "\n oflag=append Open output in append mode" 97//usage: "\n oflag=append Open output in append mode"
91//usage: ) 98//usage: )
@@ -94,6 +101,9 @@
94//usage: "\n status=none Suppress all output" 101//usage: "\n status=none Suppress all output"
95//usage: ) 102//usage: )
96//usage: "\n" 103//usage: "\n"
104//usage: IF_PLATFORM_MINGW32(
105//usage: "\nif=/dev/zero and if=/dev/urandom are supported"
106//usage: )
97//usage: "\nN may be suffixed by c (1), w (2), b (512), kB (1000), k (1024), MB, M, GB, G" 107//usage: "\nN may be suffixed by c (1), w (2), b (512), kB (1000), k (1024), MB, M, GB, G"
98//usage: 108//usage:
99//usage:#define dd_example_usage 109//usage:#define dd_example_usage
@@ -104,6 +114,10 @@
104#include "libbb.h" 114#include "libbb.h"
105#include "common_bufsiz.h" 115#include "common_bufsiz.h"
106 116
117#if ENABLE_PLATFORM_MINGW32
118# undef O_DIRECT
119#endif
120
107/* This is a NOEXEC applet. Be very careful! */ 121/* This is a NOEXEC applet. Be very careful! */
108 122
109 123
@@ -141,13 +155,13 @@ enum {
141 FLAG_SKIP_BYTES = (1 << 5) * ENABLE_FEATURE_DD_IBS_OBS, 155 FLAG_SKIP_BYTES = (1 << 5) * ENABLE_FEATURE_DD_IBS_OBS,
142 FLAG_COUNT_BYTES = (1 << 6) * ENABLE_FEATURE_DD_IBS_OBS, 156 FLAG_COUNT_BYTES = (1 << 6) * ENABLE_FEATURE_DD_IBS_OBS,
143 FLAG_FULLBLOCK = (1 << 7) * ENABLE_FEATURE_DD_IBS_OBS, 157 FLAG_FULLBLOCK = (1 << 7) * ENABLE_FEATURE_DD_IBS_OBS,
144 FLAG_IDIRECT = (1 << 8) * ENABLE_FEATURE_DD_IBS_OBS, 158 FLAG_IDIRECT = (1 << 8) * ENABLE_FEATURE_DD_IBS_OBS * ENABLE_PLATFORM_POSIX,
145 /* end of input flags */ 159 /* end of input flags */
146 /* start of output flags */ 160 /* start of output flags */
147 FLAG_OFLAG_SHIFT = 9, 161 FLAG_OFLAG_SHIFT = 9,
148 FLAG_SEEK_BYTES = (1 << 9) * ENABLE_FEATURE_DD_IBS_OBS, 162 FLAG_SEEK_BYTES = (1 << 9) * ENABLE_FEATURE_DD_IBS_OBS,
149 FLAG_APPEND = (1 << 10) * ENABLE_FEATURE_DD_IBS_OBS, 163 FLAG_APPEND = (1 << 10) * ENABLE_FEATURE_DD_IBS_OBS,
150 FLAG_ODIRECT = (1 << 11) * ENABLE_FEATURE_DD_IBS_OBS, 164 FLAG_ODIRECT = (1 << 11) * ENABLE_FEATURE_DD_IBS_OBS * ENABLE_PLATFORM_POSIX,
151 /* end of output flags */ 165 /* end of output flags */
152 FLAG_TWOBUFS = (1 << 12) * ENABLE_FEATURE_DD_IBS_OBS, 166 FLAG_TWOBUFS = (1 << 12) * ENABLE_FEATURE_DD_IBS_OBS,
153 FLAG_COUNT = 1 << 13, 167 FLAG_COUNT = 1 << 13,
@@ -220,7 +234,9 @@ static ssize_t dd_read(void *ibuf, size_t ibs)
220 ssize_t n; 234 ssize_t n;
221 235
222#if ENABLE_FEATURE_DD_IBS_OBS 236#if ENABLE_FEATURE_DD_IBS_OBS
237# if !ENABLE_PLATFORM_MINGW32
223 read_again: 238 read_again:
239# endif
224 if (G.flags & FLAG_FULLBLOCK) 240 if (G.flags & FLAG_FULLBLOCK)
225 n = full_read(ifd, ibuf, ibs); 241 n = full_read(ifd, ibuf, ibs);
226 else 242 else
@@ -240,7 +256,9 @@ static bool write_and_stats(const void *buf, size_t len, size_t obs,
240{ 256{
241 ssize_t n; 257 ssize_t n;
242 258
259#if !ENABLE_PLATFORM_MINGW32
243 IF_FEATURE_DD_IBS_OBS(write_again:) 260 IF_FEATURE_DD_IBS_OBS(write_again:)
261#endif
244 n = full_write(ofd, buf, len); 262 n = full_write(ofd, buf, len);
245#if ENABLE_FEATURE_DD_IBS_OBS 263#if ENABLE_FEATURE_DD_IBS_OBS
246# ifdef O_DIRECT 264# ifdef O_DIRECT
@@ -307,12 +325,25 @@ static int parse_comma_flags(char *val, const char *words, const char *error_in)
307 325
308static void *alloc_buf(size_t size) 326static void *alloc_buf(size_t size)
309{ 327{
328#if !ENABLE_PLATFORM_MINGW32
310 /* Important for "{i,o}flag=direct" - buffers must be page aligned */ 329 /* Important for "{i,o}flag=direct" - buffers must be page aligned */
311 if (size >= bb_getpagesize()) 330 if (size >= bb_getpagesize())
312 return xmmap_anon(size); 331 return xmmap_anon(size);
332#endif
313 return xmalloc(size); 333 return xmalloc(size);
314} 334}
315 335
336#if ENABLE_PLATFORM_MINGW32
337// Does 'path' refer to a physical drive in the win32 device namespace?
338static int is_drive_path(const char *path)
339{
340 char *s = auto_string(strdup(path));
341
342 bs_to_slash(s);
343 return strncasecmp(s, "//./PhysicalDrive", 17) == 0;
344}
345#endif
346
316int dd_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 347int dd_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
317int dd_main(int argc UNUSED_PARAM, char **argv) 348int dd_main(int argc UNUSED_PARAM, char **argv)
318{ 349{
@@ -326,9 +357,9 @@ int dd_main(int argc UNUSED_PARAM, char **argv)
326 static const char conv_words[] ALIGN1 = 357 static const char conv_words[] ALIGN1 =
327 "notrunc\0""sync\0""noerror\0""fsync\0""swab\0"; 358 "notrunc\0""sync\0""noerror\0""fsync\0""swab\0";
328 static const char iflag_words[] ALIGN1 = 359 static const char iflag_words[] ALIGN1 =
329 "skip_bytes\0""count_bytes\0""fullblock\0""direct\0"; 360 "skip_bytes\0""count_bytes\0""fullblock\0"IF_PLATFORM_POSIX("direct\0");
330 static const char oflag_words[] ALIGN1 = 361 static const char oflag_words[] ALIGN1 =
331 "seek_bytes\0append\0""direct\0"; 362 "seek_bytes\0append\0"IF_PLATFORM_POSIX("direct\0");
332#endif 363#endif
333#if ENABLE_FEATURE_DD_STATUS 364#if ENABLE_FEATURE_DD_STATUS
334 static const char status_words[] ALIGN1 = 365 static const char status_words[] ALIGN1 =
@@ -429,11 +460,11 @@ int dd_main(int argc UNUSED_PARAM, char **argv)
429#if ENABLE_FEATURE_DD_IBS_OBS 460#if ENABLE_FEATURE_DD_IBS_OBS
430 if (what == OP_ibs) { 461 if (what == OP_ibs) {
431 /* Must fit into positive ssize_t */ 462 /* Must fit into positive ssize_t */
432 ibs = xatoul_range_sfx(val, 1, ((size_t)-1L)/2, cwbkMG_suffixes); 463 ibs = xatoul_range_sfx(val, 1, ULONG_MAX/2, cwbkMG_suffixes);
433 /*continue;*/ 464 /*continue;*/
434 } 465 }
435 if (what == OP_obs) { 466 if (what == OP_obs) {
436 obs = xatoul_range_sfx(val, 1, ((size_t)-1L)/2, cwbkMG_suffixes); 467 obs = xatoul_range_sfx(val, 1, ULONG_MAX/2, cwbkMG_suffixes);
437 /*continue;*/ 468 /*continue;*/
438 } 469 }
439 if (what == OP_conv) { 470 if (what == OP_conv) {
@@ -450,7 +481,7 @@ int dd_main(int argc UNUSED_PARAM, char **argv)
450 } 481 }
451#endif 482#endif
452 if (what == OP_bs) { 483 if (what == OP_bs) {
453 ibs = xatoul_range_sfx(val, 1, ((size_t)-1L)/2, cwbkMG_suffixes); 484 ibs = xatoul_range_sfx(val, 1, ULONG_MAX/2, cwbkMG_suffixes);
454 obs = ibs; 485 obs = ibs;
455 /*continue;*/ 486 /*continue;*/
456 } 487 }
@@ -515,7 +546,10 @@ int dd_main(int argc UNUSED_PARAM, char **argv)
515# endif 546# endif
516 } 547 }
517#endif 548#endif
518 xmove_fd(xopen(infile, iflag), ifd); 549 xmove_fd(MINGW_SPECIAL(xopen)(infile, iflag), ifd);
550#if ENABLE_PLATFORM_MINGW32
551 update_special_fd(get_dev_type(infile), ifd);
552#endif
519 } else { 553 } else {
520 infile = bb_msg_standard_input; 554 infile = bb_msg_standard_input;
521 } 555 }
@@ -535,8 +569,35 @@ int dd_main(int argc UNUSED_PARAM, char **argv)
535# endif 569# endif
536 } 570 }
537#endif 571#endif
572#if ENABLE_PLATFORM_MINGW32
573 if (is_drive_path(outfile)) {
574 // Turn off options not supported by Windows device files.
575 oflag &= ~(O_CREAT | O_TRUNC);
576 }
577#endif
538 xmove_fd(xopen(outfile, oflag), ofd); 578 xmove_fd(xopen(outfile, oflag), ofd);
539 579
580#if ENABLE_PLATFORM_MINGW32
581 {
582 off_t len = (off_t)seek * ((G.flags & FLAG_SEEK_BYTES) ? 1 : obs);
583 struct stat st;
584 int ret = fstat(ofd, &st);
585
586 if (ret == 0 && !(G.flags & FLAG_APPEND) && len > st.st_size)
587 make_sparse(ofd, st.st_size, len);
588
589 if (seek && !(G.flags & FLAG_NOTRUNC)) {
590 if (ftruncate(ofd, len) < 0) {
591 if (ret < 0
592 || S_ISREG(st.st_mode)
593 || S_ISDIR(st.st_mode)
594 ) {
595 goto die_outfile;
596 }
597 }
598 }
599 }
600#else
540 if (seek && !(G.flags & FLAG_NOTRUNC)) { 601 if (seek && !(G.flags & FLAG_NOTRUNC)) {
541 size_t blocksz = (G.flags & FLAG_SEEK_BYTES) ? 1 : obs; 602 size_t blocksz = (G.flags & FLAG_SEEK_BYTES) ? 1 : obs;
542 if (ftruncate(ofd, seek * blocksz) < 0) { 603 if (ftruncate(ofd, seek * blocksz) < 0) {
@@ -550,6 +611,7 @@ int dd_main(int argc UNUSED_PARAM, char **argv)
550 } 611 }
551 } 612 }
552 } 613 }
614#endif
553 } else { 615 } else {
554 outfile = bb_msg_standard_output; 616 outfile = bb_msg_standard_output;
555 } 617 }
diff --git a/coreutils/du.c b/coreutils/du.c
index 4652b6300..338998fc9 100644
--- a/coreutils/du.c
+++ b/coreutils/du.c
@@ -137,7 +137,7 @@ static void print(unsigned long long size, const char *filename)
137 size >>= 10; 137 size >>= 10;
138 } 138 }
139 } 139 }
140 printf("%llu\t%s\n", size, filename); 140 printf("%"LL_FMT"u\t%s\n", size, filename);
141#endif 141#endif
142} 142}
143 143
diff --git a/coreutils/expr.c b/coreutils/expr.c
index 47ebe2fca..3f7e21871 100644
--- a/coreutils/expr.c
+++ b/coreutils/expr.c
@@ -84,7 +84,7 @@
84#if ENABLE_EXPR_MATH_SUPPORT_64 84#if ENABLE_EXPR_MATH_SUPPORT_64
85typedef int64_t arith_t; 85typedef int64_t arith_t;
86 86
87#define PF_REZ "ll" 87#define PF_REZ LL_FMT
88#define PF_REZ_TYPE (long long) 88#define PF_REZ_TYPE (long long)
89#define STRTOL(s, e, b) strtoll(s, e, b) 89#define STRTOL(s, e, b) strtoll(s, e, b)
90#else 90#else
diff --git a/coreutils/factor.c b/coreutils/factor.c
index 90e9ed761..9de5ea8eb 100644
--- a/coreutils/factor.c
+++ b/coreutils/factor.c
@@ -124,7 +124,7 @@ static NOINLINE void print_w(wide_t n)
124{ 124{
125 unsigned rep = square_count; 125 unsigned rep = square_count;
126 do 126 do
127 printf(" %llu", n); 127 printf(" %"LL_FMT"u", n);
128 while (--rep != 0); 128 while (--rep != 0);
129} 129}
130static NOINLINE void print_h(half_t n) 130static NOINLINE void print_h(half_t n)
@@ -226,7 +226,7 @@ static void factorize_numstr(const char *numstr)
226 N = bb_strtoull(numstr, NULL, 10); 226 N = bb_strtoull(numstr, NULL, 10);
227 if (errno) 227 if (errno)
228 bb_show_usage(); 228 bb_show_usage();
229 printf("%llu:", N); 229 printf("%"LL_FMT"u:", N);
230 square_count = 1; 230 square_count = 1;
231 factorize(N); 231 factorize(N);
232} 232}
diff --git a/coreutils/id.c b/coreutils/id.c
index a4f178bda..0e1286294 100644
--- a/coreutils/id.c
+++ b/coreutils/id.c
@@ -112,6 +112,7 @@ static int print_user(uid_t id, const char *prefix)
112 return print_common(id, uid2uname(id), prefix); 112 return print_common(id, uid2uname(id), prefix);
113} 113}
114 114
115#if !ENABLE_PLATFORM_MINGW32
115/* On error set *n < 0 and return >= 0 116/* On error set *n < 0 and return >= 0
116 * If *n is too small, update it and return < 0 117 * If *n is too small, update it and return < 0
117 * (ok to trash groups[] in both cases) 118 * (ok to trash groups[] in both cases)
@@ -142,6 +143,7 @@ static int get_groups(const char *username, gid_t rgid, gid_t *groups, int *n)
142 /* if *n >= 0, return -1 (got new *n), else return 0 (error): */ 143 /* if *n >= 0, return -1 (got new *n), else return 0 (error): */
143 return -(*n >= 0); 144 return -(*n >= 0);
144} 145}
146#endif
145 147
146int id_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 148int id_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
147int id_main(int argc UNUSED_PARAM, char **argv) 149int id_main(int argc UNUSED_PARAM, char **argv)
@@ -184,16 +186,26 @@ int id_main(int argc UNUSED_PARAM, char **argv)
184 euid = ruid = p->pw_uid; 186 euid = ruid = p->pw_uid;
185 egid = rgid = p->pw_gid; 187 egid = rgid = p->pw_gid;
186 } else { 188 } else {
189#if ENABLE_PLATFORM_MINGW32
190 // We don't distinguish real/effective ids on Windows.
191 euid = ruid = getuid();
192 egid = rgid = getegid();
193#else
187 egid = getegid(); 194 egid = getegid();
188 rgid = getgid(); 195 rgid = getgid();
189 euid = geteuid(); 196 euid = geteuid();
190 ruid = getuid(); 197 ruid = getuid();
198#endif
191 } 199 }
192 /* JUST_ALL_GROUPS ignores -r PRINT_REAL flag even if man page for */ 200 /* JUST_ALL_GROUPS ignores -r PRINT_REAL flag even if man page for */
193 /* id says: print the real ID instead of the effective ID, with -ugG */ 201 /* id says: print the real ID instead of the effective ID, with -ugG */
194 /* in fact in this case egid is always printed if egid != rgid */ 202 /* in fact in this case egid is always printed if egid != rgid */
195 if (!opt || (opt & JUST_ALL_GROUPS)) { 203 if (!opt || (opt & JUST_ALL_GROUPS)) {
204#if ENABLE_PLATFORM_MINGW32
205 gid_t groups[1];
206#else
196 gid_t *groups; 207 gid_t *groups;
208#endif
197 int n; 209 int n;
198 210
199 if (!opt) { 211 if (!opt) {
@@ -210,6 +222,11 @@ int id_main(int argc UNUSED_PARAM, char **argv)
210 if (egid != rgid) 222 if (egid != rgid)
211 status |= print_group(egid, " "); 223 status |= print_group(egid, " ");
212 } 224 }
225#if ENABLE_PLATFORM_MINGW32
226 // We only admit to having one group id on Windows.
227 n = 1;
228 groups[0] = rgid;
229#else
213 /* We are supplying largish buffer, trying 230 /* We are supplying largish buffer, trying
214 * to not run get_groups() twice. That might be slow 231 * to not run get_groups() twice. That might be slow
215 * ("user database in remote SQL server" case) */ 232 * ("user database in remote SQL server" case) */
@@ -220,6 +237,7 @@ int id_main(int argc UNUSED_PARAM, char **argv)
220 groups = xrealloc(groups, n * sizeof(groups[0])); 237 groups = xrealloc(groups, n * sizeof(groups[0]));
221 get_groups(username, rgid, groups, &n); 238 get_groups(username, rgid, groups, &n);
222 } 239 }
240#endif
223 if (n > 0) { 241 if (n > 0) {
224 /* Print the list */ 242 /* Print the list */
225 prefix = " groups="; 243 prefix = " groups=";
@@ -234,7 +252,7 @@ int id_main(int argc UNUSED_PARAM, char **argv)
234 bb_simple_error_msg_and_die("can't get groups"); 252 bb_simple_error_msg_and_die("can't get groups");
235 return EXIT_FAILURE; 253 return EXIT_FAILURE;
236 } 254 }
237 if (ENABLE_FEATURE_CLEAN_UP) 255 if (ENABLE_FEATURE_CLEAN_UP && !ENABLE_PLATFORM_MINGW32)
238 free(groups); 256 free(groups);
239#if ENABLE_SELINUX 257#if ENABLE_SELINUX
240 if (is_selinux_enabled()) { 258 if (is_selinux_enabled()) {
diff --git a/coreutils/ls.c b/coreutils/ls.c
index cc809b797..5d2e96a1e 100644
--- a/coreutils/ls.c
+++ b/coreutils/ls.c
@@ -109,8 +109,11 @@
109//usage:#define ls_full_usage "\n\n" 109//usage:#define ls_full_usage "\n\n"
110//usage: "List directory contents\n" 110//usage: "List directory contents\n"
111//usage: "\n -1 One column output" 111//usage: "\n -1 One column output"
112//usage: "\n -a Include names starting with ." 112//usage: "\n -a Include names starting with ." IF_PLATFORM_MINGW32(" and hidden files")
113//usage: "\n -A Like -a, but exclude . and .." 113//usage: "\n -A Like -a, but exclude . and .."
114//usage: IF_PLATFORM_MINGW32(
115//usage: "\n -aa,-AA Like -a,-A but omit hidden system files"
116//usage: )
114////usage: "\n -C List by columns" - don't show, this is a default anyway 117////usage: "\n -C List by columns" - don't show, this is a default anyway
115//usage: "\n -x List by lines" 118//usage: "\n -x List by lines"
116//usage: "\n -d List directory names, not contents" 119//usage: "\n -d List directory names, not contents"
@@ -316,6 +319,9 @@ struct dnode {
316 int dn_rdev_min; 319 int dn_rdev_min;
317// dev_t dn_dev; 320// dev_t dn_dev;
318// blksize_t dn_blksize; 321// blksize_t dn_blksize;
322#if ENABLE_PLATFORM_MINGW32
323 DWORD dn_attr;
324#endif
319}; 325};
320 326
321struct globals { 327struct globals {
@@ -337,6 +343,10 @@ struct globals {
337 /* Do time() just once. Saves one syscall per file for "ls -l" */ 343 /* Do time() just once. Saves one syscall per file for "ls -l" */
338 time_t current_time_t; 344 time_t current_time_t;
339#endif 345#endif
346#if ENABLE_PLATFORM_MINGW32
347 int a_count, A_count;
348# define HIDSYS (FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM)
349#endif
340} FIX_ALIASING; 350} FIX_ALIASING;
341#define G (*(struct globals*)bb_common_bufsiz1) 351#define G (*(struct globals*)bb_common_bufsiz1)
342#define INIT_G() do { \ 352#define INIT_G() do { \
@@ -497,7 +507,11 @@ static NOINLINE unsigned display_single(const struct dnode *dn)
497 lpath = xmalloc_readlink_or_warn(dn->fullname); 507 lpath = xmalloc_readlink_or_warn(dn->fullname);
498 508
499 if (opt & OPT_i) /* show inode# */ 509 if (opt & OPT_i) /* show inode# */
500 column += printf("%7llu ", (long long) dn->dn_ino); 510#if !ENABLE_FEATURE_EXTRA_FILE_DATA
511 column += printf("%7"LL_FMT"u ", (long long) dn->dn_ino);
512#else
513 column += printf("%19"LL_FMT"u ", (long long) dn->dn_ino);
514#endif
501 if (opt & OPT_s) { /* show allocated blocks */ 515 if (opt & OPT_s) { /* show allocated blocks */
502 if (opt & OPT_h) { 516 if (opt & OPT_h) {
503 column += printf("%"HUMAN_READABLE_MAX_WIDTH_STR"s ", 517 column += printf("%"HUMAN_READABLE_MAX_WIDTH_STR"s ",
@@ -659,7 +673,11 @@ static void display_files(struct dnode **dn, unsigned nfiles)
659 } 673 }
660 column_width += 2 674 column_width += 2
661 + ((option_mask32 & OPT_Z) ? 33 : 0) /* context width */ 675 + ((option_mask32 & OPT_Z) ? 33 : 0) /* context width */
676#if !ENABLE_FEATURE_EXTRA_FILE_DATA
662 + ((option_mask32 & OPT_i) ? 8 : 0) /* inode# width */ 677 + ((option_mask32 & OPT_i) ? 8 : 0) /* inode# width */
678#else
679 + ((option_mask32 & OPT_i) ? 20 : 0) /* inode# width */
680#endif
663 + ((option_mask32 & OPT_s) ? 5 : 0) /* "alloc block" width */ 681 + ((option_mask32 & OPT_s) ? 5 : 0) /* "alloc block" width */
664 ; 682 ;
665 ncols = (unsigned)G_terminal_width / column_width; 683 ncols = (unsigned)G_terminal_width / column_width;
@@ -740,6 +758,9 @@ static struct dnode *my_stat(const char *fullname, const char *name, int force_f
740 758
741 /* cur->dstat = statbuf: */ 759 /* cur->dstat = statbuf: */
742 cur->dn_mode = statbuf.st_mode ; 760 cur->dn_mode = statbuf.st_mode ;
761#if ENABLE_PLATFORM_MINGW32
762 cur->dn_attr = statbuf.st_attr ;
763#endif
743 cur->dn_size = statbuf.st_size ; 764 cur->dn_size = statbuf.st_size ;
744#if ENABLE_FEATURE_LS_TIMESTAMPS || ENABLE_FEATURE_LS_SORTFILES 765#if ENABLE_FEATURE_LS_TIMESTAMPS || ENABLE_FEATURE_LS_SORTFILES
745 cur->dn_time = statbuf.st_mtime ; 766 cur->dn_time = statbuf.st_mtime ;
@@ -920,6 +941,15 @@ static void sort_and_display_files(struct dnode **dn, unsigned nfiles)
920# define sort_and_display_files(dn, nfiles) display_files(dn, nfiles) 941# define sort_and_display_files(dn, nfiles) display_files(dn, nfiles)
921#endif 942#endif
922 943
944#if ENABLE_PLATFORM_MINGW32
945static int hide_file(DWORD attr)
946{
947 return
948 ((attr & FILE_ATTRIBUTE_HIDDEN) && !(option_mask32 & (OPT_a|OPT_A))) ||
949 (((attr & HIDSYS) == HIDSYS) && MAX(G.a_count, G.A_count) > 1);
950}
951#endif
952
923/* Returns NULL-terminated malloced vector of pointers (or NULL) */ 953/* Returns NULL-terminated malloced vector of pointers (or NULL) */
924static struct dnode **scan_one_dir(const char *path, unsigned *nfiles_p) 954static struct dnode **scan_one_dir(const char *path, unsigned *nfiles_p)
925{ 955{
@@ -927,6 +957,9 @@ static struct dnode **scan_one_dir(const char *path, unsigned *nfiles_p)
927 struct dirent *entry; 957 struct dirent *entry;
928 DIR *dir; 958 DIR *dir;
929 unsigned i, nfiles; 959 unsigned i, nfiles;
960#if ENABLE_PLATFORM_MINGW32
961 struct stat statbuf;
962#endif
930 963
931 *nfiles_p = 0; 964 *nfiles_p = 0;
932 dir = warn_opendir(path); 965 dir = warn_opendir(path);
@@ -949,9 +982,29 @@ static struct dnode **scan_one_dir(const char *path, unsigned *nfiles_p)
949 continue; /* if only -A, skip . and .. but show other dotfiles */ 982 continue; /* if only -A, skip . and .. but show other dotfiles */
950 } 983 }
951 } 984 }
985#if ENABLE_PLATFORM_MINGW32
986 if (has_dos_drive_prefix(path) && path[2] == '\0')
987 fullname = xasprintf("%s%s", path, entry->d_name);
988 else
989#endif
952 fullname = concat_path_file(path, entry->d_name); 990 fullname = concat_path_file(path, entry->d_name);
991#if ENABLE_PLATFORM_MINGW32
992 /* When showing link targets we must first check the
993 * attributes of the link itself to see if it's hidden. */
994 if ((option_mask32 & OPT_L) && !lstat(fullname, &statbuf)) {
995 if (hide_file(statbuf.st_attr)) {
996 free(fullname);
997 continue;
998 }
999 }
1000#endif
953 cur = my_stat(fullname, bb_basename(fullname), 0); 1001 cur = my_stat(fullname, bb_basename(fullname), 0);
1002#if !ENABLE_PLATFORM_MINGW32
954 if (!cur) { 1003 if (!cur) {
1004#else
1005 if (!cur || hide_file(cur->dn_attr)) {
1006 /* skip invalid or hidden files */
1007#endif
955 free(fullname); 1008 free(fullname);
956 continue; 1009 continue;
957 } 1010 }
@@ -1060,6 +1113,18 @@ static void scan_and_display_dirs_recur(struct dnode **dn, int first)
1060 } 1113 }
1061} 1114}
1062 1115
1116#if ENABLE_PLATFORM_MINGW32
1117static char *fix_backslash(char *p)
1118{
1119 const char *flag = getenv("BB_FIX_BACKSLASH");
1120 int value = flag ? atoi(flag) : 0;
1121
1122 if (value == 1)
1123 bs_to_slash(p);
1124 return p;
1125}
1126#endif
1127
1063 1128
1064int ls_main(int argc UNUSED_PARAM, char **argv) 1129int ls_main(int argc UNUSED_PARAM, char **argv)
1065{ /* ^^^^^^^^^^^^^^^^^ note: if FTPD, argc can be wrong, see ftpd.c */ 1130{ /* ^^^^^^^^^^^^^^^^^ note: if FTPD, argc can be wrong, see ftpd.c */
@@ -1129,9 +1194,11 @@ int ls_main(int argc UNUSED_PARAM, char **argv)
1129 IF_FEATURE_LS_TIMESTAMPS(":c-u:u-c") /* mtime/atime */ 1194 IF_FEATURE_LS_TIMESTAMPS(":c-u:u-c") /* mtime/atime */
1130 /* -w NUM: */ 1195 /* -w NUM: */
1131 IF_FEATURE_LS_WIDTH(":w+") 1196 IF_FEATURE_LS_WIDTH(":w+")
1197 IF_PLATFORM_MINGW32(":aa:AA")
1132 , ls_longopts 1198 , ls_longopts
1133 IF_FEATURE_LS_WIDTH(, /*-T*/ NULL, /*-w*/ &G_terminal_width) 1199 IF_FEATURE_LS_WIDTH(, /*-T*/ NULL, /*-w*/ &G_terminal_width)
1134 IF_FEATURE_LS_COLOR(, &color_opt) 1200 IF_FEATURE_LS_COLOR(, &color_opt)
1201 IF_PLATFORM_MINGW32(, &G.a_count, &G.A_count)
1135 ); 1202 );
1136#if 0 /* option bits debug */ 1203#if 0 /* option bits debug */
1137 bb_error_msg("opt:0x%08x l:%x H:%x color:%x dirs:%x", opt, OPT_l, OPT_H, OPT_color, OPT_dirs_first); 1204 bb_error_msg("opt:0x%08x l:%x H:%x color:%x dirs:%x", opt, OPT_l, OPT_H, OPT_color, OPT_dirs_first);
@@ -1155,6 +1222,11 @@ int ls_main(int argc UNUSED_PARAM, char **argv)
1155 /* set G_show_color = 1/0 */ 1222 /* set G_show_color = 1/0 */
1156 if (ENABLE_FEATURE_LS_COLOR_IS_DEFAULT && !is_TERM_dumb()) { 1223 if (ENABLE_FEATURE_LS_COLOR_IS_DEFAULT && !is_TERM_dumb()) {
1157 char *p = getenv("LS_COLORS"); 1224 char *p = getenv("LS_COLORS");
1225# if ENABLE_PLATFORM_MINGW32
1226 /* No colour if unset or empty: https://no-color.org */
1227 char *no_c = getenv("NO_COLOR");
1228 if (!no_c || no_c[0] == '\0')
1229# endif
1158 /* LS_COLORS is unset, or (not empty && not "none") ? */ 1230 /* LS_COLORS is unset, or (not empty && not "none") ? */
1159 if (!p || (p[0] && strcmp(p, "none") != 0)) { 1231 if (!p || (p[0] && strcmp(p, "none") != 0)) {
1160 if (isatty(STDOUT_FILENO)) { 1232 if (isatty(STDOUT_FILENO)) {
@@ -1204,6 +1276,12 @@ int ls_main(int argc UNUSED_PARAM, char **argv)
1204 option_mask32 |= OPT_dirs_first; 1276 option_mask32 |= OPT_dirs_first;
1205 } 1277 }
1206 1278
1279#if ENABLE_FEATURE_EXTRA_FILE_DATA
1280 /* Enable accurate link counts for directories */
1281 if (opt & OPT_l)
1282 count_subdirs(NULL);
1283#endif
1284
1207 argv += optind; 1285 argv += optind;
1208 if (!argv[0]) 1286 if (!argv[0])
1209 *--argv = (char*)"."; 1287 *--argv = (char*)".";
@@ -1215,6 +1293,9 @@ int ls_main(int argc UNUSED_PARAM, char **argv)
1215 dn = NULL; 1293 dn = NULL;
1216 nfiles = 0; 1294 nfiles = 0;
1217 do { 1295 do {
1296#if ENABLE_PLATFORM_MINGW32
1297 *argv = fix_backslash(*argv);
1298#endif
1218 cur = my_stat(*argv, *argv, 1299 cur = my_stat(*argv, *argv,
1219 /* follow links on command line unless -l, -i, -s or -F: */ 1300 /* follow links on command line unless -l, -i, -s or -F: */
1220 !(option_mask32 & (OPT_l|OPT_i|OPT_s|OPT_F)) 1301 !(option_mask32 & (OPT_l|OPT_i|OPT_s|OPT_F))
diff --git a/coreutils/nproc.c b/coreutils/nproc.c
index df63bf57a..44408b5f5 100644
--- a/coreutils/nproc.c
+++ b/coreutils/nproc.c
@@ -28,6 +28,9 @@
28int nproc_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 28int nproc_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
29int nproc_main(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) 29int nproc_main(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
30{ 30{
31#if ENABLE_PLATFORM_MINGW32
32 DWORD_PTR affinity, process_affinity, system_affinity;
33#endif
31 int count = 0; 34 int count = 0;
32#if ENABLE_LONG_OPTS 35#if ENABLE_LONG_OPTS
33 int ignore = 0; 36 int ignore = 0;
@@ -36,7 +39,10 @@ int nproc_main(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
36 "all\0" No_argument "\xff" 39 "all\0" No_argument "\xff"
37 , &ignore 40 , &ignore
38 ); 41 );
42#endif
39 43
44#if !ENABLE_PLATFORM_MINGW32
45#if ENABLE_LONG_OPTS
40 if (opts & (1 << 1)) { 46 if (opts & (1 << 1)) {
41 DIR *cpusd = opendir("/sys/devices/system/cpu"); 47 DIR *cpusd = opendir("/sys/devices/system/cpu");
42 if (cpusd) { 48 if (cpusd) {
@@ -61,6 +67,17 @@ int nproc_main(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
61 } 67 }
62 IF_FEATURE_CLEAN_UP(free(mask);) 68 IF_FEATURE_CLEAN_UP(free(mask);)
63 } 69 }
70#else /* ENABLE_PLATFORM_MINGW32 */
71 if (GetProcessAffinityMask(GetCurrentProcess(), &process_affinity,
72 &system_affinity)) {
73 affinity = IF_LONG_OPTS((opts & (1 << 1)) ? system_affinity :)
74 process_affinity;
75 while (affinity) {
76 count += affinity & 1;
77 affinity >>= 1;
78 }
79 }
80#endif /* ENABLE_PLATFORM_MINGW32 */
64 81
65 IF_LONG_OPTS(count -= ignore;) 82 IF_LONG_OPTS(count -= ignore;)
66 if (count <= 0) 83 if (count <= 0)
diff --git a/coreutils/od_bloaty.c b/coreutils/od_bloaty.c
index e886a4ed2..641d93503 100644
--- a/coreutils/od_bloaty.c
+++ b/coreutils/od_bloaty.c
@@ -110,6 +110,13 @@ typedef long long llong;
110# define LDBL_DIG DBL_DIG 110# define LDBL_DIG DBL_DIG
111#endif 111#endif
112 112
113#if ENABLE_PLATFORM_MINGW32
114/* symbol conflict */
115#define CHAR SIZE_CHAR
116#define SHORT SIZE_SHORT
117#define LONG SIZE_LONG
118#define INT SIZE_INT
119#endif
113enum size_spec { 120enum size_spec {
114 NO_SIZE, 121 NO_SIZE,
115 CHAR, 122 CHAR,
diff --git a/coreutils/printf.c b/coreutils/printf.c
index 4edcfa9b5..379c00cc6 100644
--- a/coreutils/printf.c
+++ b/coreutils/printf.c
@@ -152,6 +152,71 @@ static double my_xstrtod(const char *arg)
152 return result; 152 return result;
153} 153}
154 154
155#if ENABLE_PLATFORM_MINGW32
156static int buflen = 0;
157static int bufmax = 0;
158static char *buffer = NULL;
159
160static void my_flush(void)
161{
162 if (buffer)
163 full_write(STDOUT_FILENO, buffer, buflen);
164 free(buffer);
165 buffer = NULL;
166 buflen = bufmax = 0;
167}
168
169static void copy_to_buffer(const char *str, int len)
170{
171 char *newbuf;
172
173 if (buflen + len >= bufmax) {
174 bufmax += 256 + len;
175 if ((newbuf = realloc(buffer, bufmax)) == NULL) {
176 my_flush();
177 return;
178 }
179 buffer = newbuf;
180 }
181 memcpy(buffer + buflen, str, len);
182 buflen += len;
183
184 if (buflen > 40 && buffer[buflen-1] == '\n')
185 my_flush();
186}
187
188static int my_putchar(int ch)
189{
190 char str[1] = { (char)ch };
191 copy_to_buffer(str, 1);
192 return ch;
193}
194
195static int my_printf(const char *format, ...)
196{
197 va_list list;
198 char *str;
199 int len;
200
201 va_start(list, format);
202 len = vasprintf(&str, format, list);
203 va_end(list);
204
205 if (len >= 0) {
206 copy_to_buffer(str, len);
207 free(str);
208 }
209 return len;
210}
211
212#undef bb_putchar
213#undef putchar
214#undef printf
215#define bb_putchar(c) my_putchar(c)
216#define putchar(c) my_putchar(c)
217#define printf(...) my_printf(__VA_ARGS__)
218#endif
219
155/* Handles %b; return 1 if output is to be short-circuited by \c */ 220/* Handles %b; return 1 if output is to be short-circuited by \c */
156static int print_esc_string(const char *str) 221static int print_esc_string(const char *str)
157{ 222{
@@ -444,6 +509,9 @@ int printf_main(int argc UNUSED_PARAM, char **argv)
444 do { 509 do {
445 argv = argv2; 510 argv = argv2;
446 argv2 = print_formatted(format, argv, &conv_err); 511 argv2 = print_formatted(format, argv, &conv_err);
512#if ENABLE_PLATFORM_MINGW32
513 my_flush();
514#endif
447 } while (argv2 > argv && *argv2); 515 } while (argv2 > argv && *argv2);
448 516
449 /* coreutils compat (bash doesn't do this): 517 /* coreutils compat (bash doesn't do this):
diff --git a/coreutils/shred.c b/coreutils/shred.c
index 7c0be612a..9e53b4820 100644
--- a/coreutils/shred.c
+++ b/coreutils/shred.c
@@ -60,9 +60,9 @@ int shred_main(int argc UNUSED_PARAM, char **argv)
60 opt = getopt32(argv, "^" "fuzn:+vxs:" "\0" "-1"/*min 1 arg*/, &num_iter, &opt_s); 60 opt = getopt32(argv, "^" "fuzn:+vxs:" "\0" "-1"/*min 1 arg*/, &num_iter, &opt_s);
61 argv += optind; 61 argv += optind;
62 62
63 zero_fd = xopen("/dev/zero", O_RDONLY); 63 zero_fd = MINGW_SPECIAL(xopen)("/dev/zero", O_RDONLY);
64 if (num_iter != 0) 64 if (num_iter != 0)
65 rand_fd = xopen("/dev/urandom", O_RDONLY); 65 rand_fd = MINGW_SPECIAL(xopen)("/dev/urandom", O_RDONLY);
66 66
67 for (;;) { 67 for (;;) {
68 struct stat sb; 68 struct stat sb;
@@ -102,8 +102,14 @@ int shred_main(int argc UNUSED_PARAM, char **argv)
102 } 102 }
103 if (opt & OPT_u) { 103 if (opt & OPT_u) {
104 ftruncate(fd, 0); 104 ftruncate(fd, 0);
105#if ENABLE_PLATFORM_MINGW32
106 xclose(fd);
107#endif
105 xunlink(fname); 108 xunlink(fname);
106 } 109 }
110#if ENABLE_PLATFORM_MINGW32
111 else
112#endif
107 xclose(fd); 113 xclose(fd);
108 } 114 }
109 115
diff --git a/coreutils/shuf.c b/coreutils/shuf.c
index 0d23382a2..bd3f6840c 100644
--- a/coreutils/shuf.c
+++ b/coreutils/shuf.c
@@ -212,7 +212,7 @@ int shuf_main(int argc, char **argv)
212 printf("%.*s%0*llu%c", pfx_len, pfx, padding_width, lo + (uintptr_t)lines[i], eol); 212 printf("%.*s%0*llu%c", pfx_len, pfx, padding_width, lo + (uintptr_t)lines[i], eol);
213 else 213 else
214#endif 214#endif
215 printf("%llu%c", lo + (uintptr_t)lines[i], eol); 215 printf("%"LL_FMT"u%c", lo + (uintptr_t)lines[i], eol);
216 } else 216 } else
217 printf("%s%c", lines[i], eol); 217 printf("%s%c", lines[i], eol);
218 } 218 }
diff --git a/coreutils/sort.c b/coreutils/sort.c
index 2e952f81c..949948203 100644
--- a/coreutils/sort.c
+++ b/coreutils/sort.c
@@ -43,7 +43,12 @@
43 43
44//usage:#define sort_trivial_usage 44//usage:#define sort_trivial_usage
45//usage: "[-nru" 45//usage: "[-nru"
46//usage: IF_NOT_PLATFORM_MINGW32(
46//usage: IF_FEATURE_SORT_BIG("ghMcszbdfiokt] [-o FILE] [-k START[.OFS][OPTS][,END[.OFS][OPTS]] [-t CHAR") 47//usage: IF_FEATURE_SORT_BIG("ghMcszbdfiokt] [-o FILE] [-k START[.OFS][OPTS][,END[.OFS][OPTS]] [-t CHAR")
48//usage: )
49//usage: IF_PLATFORM_MINGW32(
50//usage: IF_FEATURE_SORT_BIG("ghMVcszbdfiokt] [-o FILE] [-k START[.OFS][OPTS][,END[.OFS][OPTS]] [-t CHAR")
51//usage: )
47//usage: "] [FILE]..." 52//usage: "] [FILE]..."
48//usage:#define sort_full_usage "\n\n" 53//usage:#define sort_full_usage "\n\n"
49//usage: "Sort lines of text\n" 54//usage: "Sort lines of text\n"
diff --git a/coreutils/split.c b/coreutils/split.c
index b6d1b9a7b..8d0e485d4 100644
--- a/coreutils/split.c
+++ b/coreutils/split.c
@@ -78,8 +78,10 @@ static char *next_file(char *old, unsigned suffix_len)
78 return old; 78 return old;
79} 79}
80 80
81#if !ENABLE_PLATFORM_MINGW32
81#define read_buffer bb_common_bufsiz1 82#define read_buffer bb_common_bufsiz1
82enum { READ_BUFFER_SIZE = COMMON_BUFSIZE - 1 }; 83enum { READ_BUFFER_SIZE = COMMON_BUFSIZE - 1 };
84#endif
83 85
84#define SPLIT_OPT_l (1<<0) 86#define SPLIT_OPT_l (1<<0)
85#define SPLIT_OPT_b (1<<1) 87#define SPLIT_OPT_b (1<<1)
@@ -97,8 +99,12 @@ int split_main(int argc UNUSED_PARAM, char **argv)
97 unsigned opt; 99 unsigned opt;
98 ssize_t bytes_read, to_write; 100 ssize_t bytes_read, to_write;
99 char *src; 101 char *src;
100 102#if ENABLE_PLATFORM_MINGW32
103 size_t READ_BUFFER_SIZE = 16*1024;
104 char *read_buffer = xmalloc(16*1024);
105#else
101 setup_common_bufsiz(); 106 setup_common_bufsiz();
107#endif
102 108
103 opt = getopt32(argv, "^" 109 opt = getopt32(argv, "^"
104 "l:b:a:+" /* -a N */ 110 "l:b:a:+" /* -a N */
diff --git a/coreutils/stat.c b/coreutils/stat.c
index 2c2909e7e..dc20c2356 100644
--- a/coreutils/stat.c
+++ b/coreutils/stat.c
@@ -190,6 +190,7 @@ FS_TYPE(0x012FF7B4, "xenix") \
190FS_TYPE(0x012FF7B5, "sysv4") \ 190FS_TYPE(0x012FF7B5, "sysv4") \
191FS_TYPE(0x012FF7B6, "sysv2") \ 191FS_TYPE(0x012FF7B6, "sysv2") \
192FS_TYPE(0x012FF7B7, "coh") \ 192FS_TYPE(0x012FF7B7, "coh") \
193IF_PLATFORM_MINGW32(FS_TYPE(0x15013346, "udf")) \
193FS_TYPE(0x00011954, "ufs") \ 194FS_TYPE(0x00011954, "ufs") \
194FS_TYPE(0x012FD16D, "xia") \ 195FS_TYPE(0x012FD16D, "xia") \
195FS_TYPE(0x5346544e, "ntfs") \ 196FS_TYPE(0x5346544e, "ntfs") \
@@ -784,6 +785,10 @@ int stat_main(int argc UNUSED_PARAM, char **argv)
784 selinux_or_die(); 785 selinux_or_die();
785 } 786 }
786#endif 787#endif
788#if ENABLE_FEATURE_EXTRA_FILE_DATA
789 /* Enable accurate link counts for directories */
790 count_subdirs(NULL);
791#endif
787 ok = 1; 792 ok = 1;
788 argv += optind; 793 argv += optind;
789 for (i = 0; argv[i]; ++i) 794 for (i = 0; argv[i]; ++i)
diff --git a/coreutils/sum.c b/coreutils/sum.c
index 78e69acc6..7c7cc6b6b 100644
--- a/coreutils/sum.c
+++ b/coreutils/sum.c
@@ -82,9 +82,9 @@ static unsigned sum_file(const char *file, unsigned type)
82 if (type >= SUM_SYSV) { 82 if (type >= SUM_SYSV) {
83 r = (s & 0xffff) + ((s & 0xffffffff) >> 16); 83 r = (s & 0xffff) + ((s & 0xffffffff) >> 16);
84 s = (r & 0xffff) + (r >> 16); 84 s = (r & 0xffff) + (r >> 16);
85 printf("%u %llu %s\n", s, (total_bytes + 511) / 512, file); 85 printf("%u %"LL_FMT"u %s\n", s, (total_bytes + 511) / 512, file);
86 } else 86 } else
87 printf("%05u %5llu %s\n", s, (total_bytes + 1023) / 1024, file); 87 printf("%05u %5"LL_FMT"u %s\n", s, (total_bytes + 1023) / 1024, file);
88 return 1; 88 return 1;
89#undef buf 89#undef buf
90} 90}
diff --git a/coreutils/test.c b/coreutils/test.c
index b63e33cc0..3d38ead00 100644
--- a/coreutils/test.c
+++ b/coreutils/test.c
@@ -1022,10 +1022,14 @@ int test_main(int argc, char **argv)
1022 1022
1023 info.euid = -1; 1023 info.euid = -1;
1024 info.egid = -1; 1024 info.egid = -1;
1025#if !ENABLE_PLATFORM_MINGW32
1025 info.ngroups = 0; 1026 info.ngroups = 0;
1026 info.supplementary_array = NULL; 1027 info.supplementary_array = NULL;
1028#endif
1027 r = test_main2(&info, argc, argv); 1029 r = test_main2(&info, argc, argv);
1030#if !ENABLE_PLATFORM_MINGW32
1028 free(info.supplementary_array); 1031 free(info.supplementary_array);
1032#endif
1029 1033
1030 return r; 1034 return r;
1031} 1035}
diff --git a/coreutils/timeout.c b/coreutils/timeout.c
index 84299a0a5..58f96192b 100644
--- a/coreutils/timeout.c
+++ b/coreutils/timeout.c
@@ -43,10 +43,35 @@
43//usage:#define timeout_full_usage "\n\n" 43//usage:#define timeout_full_usage "\n\n"
44//usage: "Run PROG. Send SIG to it if it is not gone in SECS seconds.\n" 44//usage: "Run PROG. Send SIG to it if it is not gone in SECS seconds.\n"
45//usage: "Default SIG: TERM." 45//usage: "Default SIG: TERM."
46//usage: IF_PLATFORM_MINGW32("\n")
46//usage: "If it still exists in KILL_SECS seconds, send KILL.\n" 47//usage: "If it still exists in KILL_SECS seconds, send KILL.\n"
47 48
48#include "libbb.h" 49#include "libbb.h"
49 50
51#if ENABLE_PLATFORM_MINGW32
52static HANDLE child = INVALID_HANDLE_VALUE;
53
54static void kill_child(void)
55{
56 if (child != INVALID_HANDLE_VALUE) {
57 pid_t pid = (pid_t)GetProcessId(child);
58 if (pid)
59 kill(pid, SIGTERM);
60 }
61}
62
63/* Return TRUE if child exits before timeout expires */
64static NOINLINE int timeout_wait(duration_t timeout, HANDLE proc, DWORD *status)
65{
66 DWORD t = (DWORD)(timeout * 1000);
67 if (WaitForSingleObject(proc, t) == WAIT_OBJECT_0) {
68 /* process is gone */
69 GetExitCodeProcess(proc, status);
70 return TRUE;
71 }
72 return FALSE;
73}
74#else
50static NOINLINE int timeout_wait(duration_t timeout, pid_t pid) 75static NOINLINE int timeout_wait(duration_t timeout, pid_t pid)
51{ 76{
52 /* Just sleep(HUGE_NUM); kill(parent) may kill wrong process! */ 77 /* Just sleep(HUGE_NUM); kill(parent) may kill wrong process! */
@@ -66,13 +91,19 @@ static NOINLINE int timeout_wait(duration_t timeout, pid_t pid)
66 } 91 }
67 return EXIT_FAILURE; 92 return EXIT_FAILURE;
68} 93}
94#endif
69 95
70int timeout_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 96int timeout_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
71int timeout_main(int argc UNUSED_PARAM, char **argv) 97int timeout_main(int argc UNUSED_PARAM, char **argv)
72{ 98{
73 int signo; 99 int signo;
100#if !ENABLE_PLATFORM_MINGW32
74 int status; 101 int status;
75 int parent = 0; 102 int parent = 0;
103#else
104 intptr_t ret;
105 DWORD status = EXIT_SUCCESS;
106#endif
76 duration_t timeout; 107 duration_t timeout;
77 duration_t kill_timeout; 108 duration_t kill_timeout;
78 pid_t pid; 109 pid_t pid;
@@ -82,15 +113,27 @@ int timeout_main(int argc UNUSED_PARAM, char **argv)
82 const char *opt_s = "TERM"; 113 const char *opt_s = "TERM";
83 char *opt_k = NULL; 114 char *opt_k = NULL;
84 115
116#if ENABLE_PLATFORM_MINGW32
117 xfunc_error_retval = 125;
118#endif
119
85 /* -p option is not documented, it is needed to support NOMMU. */ 120 /* -p option is not documented, it is needed to support NOMMU. */
86 121
87 /* -t SECONDS; -p PARENT_PID */ 122 /* -t SECONDS; -p PARENT_PID */
88 /* '+': stop at first non-option */ 123 /* '+': stop at first non-option */
124#if !ENABLE_PLATFORM_MINGW32
89 getopt32(argv, "+s:k:" USE_FOR_NOMMU("p:+"), &opt_s, &opt_k, &parent); 125 getopt32(argv, "+s:k:" USE_FOR_NOMMU("p:+"), &opt_s, &opt_k, &parent);
126#else
127 getopt32(argv, "+s:k:", &opt_s, &opt_k);
128#endif
90 /*argv += optind; - no, wait for bb_daemonize_or_rexec! */ 129 /*argv += optind; - no, wait for bb_daemonize_or_rexec! */
91 130
92 signo = get_signum(opt_s); 131 signo = get_signum(opt_s);
132#if !ENABLE_PLATFORM_MINGW32
93 if (signo < 0) 133 if (signo < 0)
134#else
135 if (!is_valid_signal(signo))
136#endif
94 bb_error_msg_and_die("unknown signal '%s'", opt_s); 137 bb_error_msg_and_die("unknown signal '%s'", opt_s);
95 138
96 kill_timeout = 0; 139 kill_timeout = 0;
@@ -103,6 +146,7 @@ int timeout_main(int argc UNUSED_PARAM, char **argv)
103 if (!argv[optind]) /* no PROG? */ 146 if (!argv[optind]) /* no PROG? */
104 bb_show_usage(); 147 bb_show_usage();
105 148
149#if !ENABLE_PLATFORM_MINGW32
106 /* We want to create a grandchild which will watch 150 /* We want to create a grandchild which will watch
107 * and kill the grandparent. Other methods: 151 * and kill the grandparent. Other methods:
108 * making parent watch child disrupts parent<->child link 152 * making parent watch child disrupts parent<->child link
@@ -155,4 +199,33 @@ int timeout_main(int argc UNUSED_PARAM, char **argv)
155 argv[1] = sv2; 199 argv[1] = sv2;
156#endif 200#endif
157 BB_EXECVP_or_die(argv); 201 BB_EXECVP_or_die(argv);
202#else /* ENABLE_PLATFORM_MINGW32 */
203 argv += optind;
204 if ((ret=mingw_spawn_proc((const char **)argv)) == -1) {
205 xfunc_error_retval = errno == EACCES ? 126 : 127;
206 bb_perror_msg_and_die("can't execute '%s'", argv[0]);
207 }
208
209 child = (HANDLE)ret;
210 atexit(kill_child);
211 if (timeout_wait(timeout, child, &status))
212 goto finish;
213 status = signo == SIGKILL ? 137 : 124;
214
215 pid = (pid_t)GetProcessId(child);
216 if (pid) {
217 kill(pid, signo);
218
219 if (kill_timeout > 0) {
220 if (timeout_wait(kill_timeout, child, &status))
221 goto finish;
222 kill(pid, SIGKILL);
223 status = 137;
224 }
225 }
226 finish:
227 CloseHandle(child);
228 child = INVALID_HANDLE_VALUE;
229 return status;
230#endif
158} 231}