aboutsummaryrefslogtreecommitdiff
path: root/coreutils
diff options
context:
space:
mode:
authorRon Yorston <rmy@pobox.com>2017-05-29 14:20:10 +0100
committerRon Yorston <rmy@pobox.com>2017-05-29 14:34:28 +0100
commitda4f331955bed8afda670afcd58d524a04a0faa9 (patch)
treef6a3879aefdd714240f8c022375f687b512d2238 /coreutils
parent74163a535fd21f5fcca4c052d2e7c192d3e264fa (diff)
parent6683d1cbb44859f549f87f882545b84b9369585c (diff)
downloadbusybox-w32-da4f331955bed8afda670afcd58d524a04a0faa9.tar.gz
busybox-w32-da4f331955bed8afda670afcd58d524a04a0faa9.tar.bz2
busybox-w32-da4f331955bed8afda670afcd58d524a04a0faa9.zip
Merge branch 'busybox' into merge
Diffstat (limited to 'coreutils')
-rw-r--r--coreutils/cal.c390
-rw-r--r--coreutils/cat.c156
-rw-r--r--coreutils/catv.c96
-rw-r--r--coreutils/cksum.c4
-rw-r--r--coreutils/dd.c8
-rw-r--r--coreutils/dos2unix.c2
-rw-r--r--coreutils/factor.c219
-rw-r--r--coreutils/ls.c14
-rw-r--r--coreutils/mktemp.c122
-rw-r--r--coreutils/nl.c101
-rw-r--r--coreutils/nproc.c51
-rw-r--r--coreutils/paste.c140
-rw-r--r--coreutils/shred.c106
-rw-r--r--coreutils/timeout.c127
-rw-r--r--coreutils/uniq.c11
-rw-r--r--coreutils/who.c51
16 files changed, 1070 insertions, 528 deletions
diff --git a/coreutils/cal.c b/coreutils/cal.c
deleted file mode 100644
index af02608f0..000000000
--- a/coreutils/cal.c
+++ /dev/null
@@ -1,390 +0,0 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * Calendar implementation for busybox
4 *
5 * See original copyright at the end of this file
6 *
7 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
8 */
9/* Mar 16, 2003 Manuel Novoa III (mjn3@codepoet.org)
10 *
11 * Major size reduction... over 50% (>1.5k) on i386.
12 */
13//config:config CAL
14//config: bool "cal"
15//config: default y
16//config: help
17//config: cal is used to display a monthly calendar.
18
19//applet:IF_CAL(APPLET(cal, BB_DIR_USR_BIN, BB_SUID_DROP))
20
21//kbuild:lib-$(CONFIG_CAL) += cal.o
22
23/* BB_AUDIT SUSv3 compliant with -j and -y extensions (from util-linux). */
24/* BB_AUDIT BUG: The output of 'cal -j 1752' is incorrect. The upstream
25 * BB_AUDIT BUG: version in util-linux seems to be broken as well. */
26/* http://www.opengroup.org/onlinepubs/007904975/utilities/cal.html */
27
28//usage:#define cal_trivial_usage
29//usage: "[-jy] [[MONTH] YEAR]"
30//usage:#define cal_full_usage "\n\n"
31//usage: "Display a calendar\n"
32//usage: "\n -j Use julian dates"
33//usage: "\n -y Display the entire year"
34
35#include "libbb.h"
36#include "unicode.h"
37
38/* We often use "unsigned" intead of "int", it's easier to div on most CPUs */
39
40#define THURSDAY 4 /* for reformation */
41#define SATURDAY 6 /* 1 Jan 1 was a Saturday */
42
43#define FIRST_MISSING_DAY 639787 /* 3 Sep 1752 */
44#define NUMBER_MISSING_DAYS 11 /* 11 day correction */
45
46#define MAXDAYS 42 /* max slots in a month array */
47#define SPACE -1 /* used in day array */
48
49static const unsigned char days_in_month[] ALIGN1 = {
50 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
51};
52
53static const unsigned char sep1752[] ALIGN1 = {
54 1, 2, 14, 15, 16,
55 17, 18, 19, 20, 21, 22, 23,
56 24, 25, 26, 27, 28, 29, 30
57};
58
59/* Set to 0 or 1 in main */
60#define julian ((unsigned)option_mask32)
61
62/* leap year -- account for Gregorian reformation in 1752 */
63static int leap_year(unsigned yr)
64{
65 if (yr <= 1752)
66 return !(yr % 4);
67 return (!(yr % 4) && (yr % 100)) || !(yr % 400);
68}
69
70/* number of centuries since 1700, not inclusive */
71#define centuries_since_1700(yr) \
72 ((yr) > 1700 ? (yr) / 100 - 17 : 0)
73
74/* number of centuries since 1700 whose modulo of 400 is 0 */
75#define quad_centuries_since_1700(yr) \
76 ((yr) > 1600 ? ((yr) - 1600) / 400 : 0)
77
78/* number of leap years between year 1 and this year, not inclusive */
79#define leap_years_since_year_1(yr) \
80 ((yr) / 4 - centuries_since_1700(yr) + quad_centuries_since_1700(yr))
81
82static void center(char *, unsigned, unsigned);
83static void day_array(unsigned, unsigned, unsigned *);
84static void trim_trailing_spaces_and_print(char *);
85
86static void blank_string(char *buf, size_t buflen);
87static char *build_row(char *p, unsigned *dp);
88
89#define DAY_LEN 3 /* 3 spaces per day */
90#define J_DAY_LEN (DAY_LEN + 1)
91#define WEEK_LEN 20 /* 7 * 3 - one space at the end */
92#define J_WEEK_LEN (WEEK_LEN + 7)
93#define HEAD_SEP 2 /* spaces between day headings */
94
95int cal_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
96int cal_main(int argc UNUSED_PARAM, char **argv)
97{
98 struct tm zero_tm;
99 time_t now;
100 unsigned month, year, flags, i;
101 char *month_names[12];
102 /* normal heading: */
103 /* "Su Mo Tu We Th Fr Sa" */
104 /* -j heading: */
105 /* " Su Mo Tu We Th Fr Sa" */
106 char day_headings[ENABLE_UNICODE_SUPPORT ? 28 * 6 : 28];
107 IF_UNICODE_SUPPORT(char *hp = day_headings;)
108 char buf[40];
109
110 init_unicode();
111
112 flags = getopt32(argv, "jy");
113 /* This sets julian = flags & 1: */
114 option_mask32 &= 1;
115 month = 0;
116 argv += optind;
117
118 if (!argv[0]) {
119 struct tm *ptm;
120
121 time(&now);
122 ptm = localtime(&now);
123 year = ptm->tm_year + 1900;
124 if (!(flags & 2)) { /* no -y */
125 month = ptm->tm_mon + 1;
126 }
127 } else {
128 if (argv[1]) {
129 if (argv[2]) {
130 bb_show_usage();
131 }
132 if (!(flags & 2)) { /* no -y */
133 month = xatou_range(*argv, 1, 12);
134 }
135 argv++;
136 }
137 year = xatou_range(*argv, 1, 9999);
138 }
139
140 blank_string(day_headings, sizeof(day_headings) - 7 + 7*julian);
141
142 i = 0;
143 do {
144 zero_tm.tm_mon = i;
145 /* full month name according to locale */
146 strftime(buf, sizeof(buf), "%B", &zero_tm);
147 month_names[i] = xstrdup(buf);
148
149 if (i < 7) {
150 zero_tm.tm_wday = i;
151 /* abbreviated weekday name according to locale */
152 strftime(buf, sizeof(buf), "%a", &zero_tm);
153#if ENABLE_UNICODE_SUPPORT
154 if (julian)
155 *hp++ = ' ';
156 {
157 char *two_wchars = unicode_conv_to_printable_fixedwidth(/*NULL,*/ buf, 2);
158 strcpy(hp, two_wchars);
159 free(two_wchars);
160 }
161 hp += strlen(hp);
162 *hp++ = ' ';
163#else
164 strncpy(day_headings + i * (3+julian) + julian, buf, 2);
165#endif
166 }
167 } while (++i < 12);
168 IF_UNICODE_SUPPORT(hp[-1] = '\0';)
169
170 if (month) {
171 unsigned row, len, days[MAXDAYS];
172 unsigned *dp = days;
173 char lineout[30];
174
175 day_array(month, year, dp);
176 len = sprintf(lineout, "%s %u", month_names[month - 1], year);
177 printf("%*s%s\n%s\n",
178 ((7*julian + WEEK_LEN) - len) / 2, "",
179 lineout, day_headings);
180 for (row = 0; row < 6; row++) {
181 build_row(lineout, dp)[0] = '\0';
182 dp += 7;
183 trim_trailing_spaces_and_print(lineout);
184 }
185 } else {
186 unsigned row, which_cal, week_len, days[12][MAXDAYS];
187 unsigned *dp;
188 char lineout[80];
189
190 sprintf(lineout, "%u", year);
191 center(lineout,
192 (WEEK_LEN * 3 + HEAD_SEP * 2)
193 + julian * (J_WEEK_LEN * 2 + HEAD_SEP
194 - (WEEK_LEN * 3 + HEAD_SEP * 2)),
195 0
196 );
197 puts("\n"); /* two \n's */
198 for (i = 0; i < 12; i++) {
199 day_array(i + 1, year, days[i]);
200 }
201 blank_string(lineout, sizeof(lineout));
202 week_len = WEEK_LEN + julian * (J_WEEK_LEN - WEEK_LEN);
203 for (month = 0; month < 12; month += 3-julian) {
204 center(month_names[month], week_len, HEAD_SEP);
205 if (!julian) {
206 center(month_names[month + 1], week_len, HEAD_SEP);
207 }
208 center(month_names[month + 2 - julian], week_len, 0);
209 printf("\n%s%*s%s", day_headings, HEAD_SEP, "", day_headings);
210 if (!julian) {
211 printf("%*s%s", HEAD_SEP, "", day_headings);
212 }
213 bb_putchar('\n');
214 for (row = 0; row < (6*7); row += 7) {
215 for (which_cal = 0; which_cal < 3-julian; which_cal++) {
216 dp = days[month + which_cal] + row;
217 build_row(lineout + which_cal * (week_len + 2), dp);
218 }
219 /* blank_string took care of nul termination. */
220 trim_trailing_spaces_and_print(lineout);
221 }
222 }
223 }
224
225 fflush_stdout_and_exit(EXIT_SUCCESS);
226}
227
228/*
229 * day_array --
230 * Fill in an array of 42 integers with a calendar. Assume for a moment
231 * that you took the (maximum) 6 rows in a calendar and stretched them
232 * out end to end. You would have 42 numbers or spaces. This routine
233 * builds that array for any month from Jan. 1 through Dec. 9999.
234 */
235static void day_array(unsigned month, unsigned year, unsigned *days)
236{
237 unsigned long temp;
238 unsigned i;
239 unsigned day, dw, dm;
240
241 memset(days, SPACE, MAXDAYS * sizeof(int));
242
243 if ((month == 9) && (year == 1752)) {
244 /* Assumes the Gregorian reformation eliminates
245 * 3 Sep. 1752 through 13 Sep. 1752.
246 */
247 unsigned j_offset = julian * 244;
248 size_t oday = 0;
249
250 do {
251 days[oday+2] = sep1752[oday] + j_offset;
252 } while (++oday < sizeof(sep1752));
253
254 return;
255 }
256
257 /* day_in_year
258 * return the 1 based day number within the year
259 */
260 day = 1;
261 if ((month > 2) && leap_year(year)) {
262 ++day;
263 }
264
265 i = month;
266 while (i) {
267 day += days_in_month[--i];
268 }
269
270 /* day_in_week
271 * return the 0 based day number for any date from 1 Jan. 1 to
272 * 31 Dec. 9999. Assumes the Gregorian reformation eliminates
273 * 3 Sep. 1752 through 13 Sep. 1752. Returns Thursday for all
274 * missing days.
275 */
276 temp = (long)(year - 1) * 365 + leap_years_since_year_1(year - 1) + day;
277 if (temp < FIRST_MISSING_DAY) {
278 dw = ((temp - 1 + SATURDAY) % 7);
279 } else {
280 dw = (((temp - 1 + SATURDAY) - NUMBER_MISSING_DAYS) % 7);
281 }
282
283 if (!julian) {
284 day = 1;
285 }
286
287 dm = days_in_month[month];
288 if ((month == 2) && leap_year(year)) {
289 ++dm;
290 }
291
292 do {
293 days[dw++] = day++;
294 } while (--dm);
295}
296
297static void trim_trailing_spaces_and_print(char *s)
298{
299 char *p = s;
300
301 while (*p) {
302 ++p;
303 }
304 while (p != s) {
305 --p;
306 if (!isspace(*p)) {
307 p[1] = '\0';
308 break;
309 }
310 }
311
312 puts(s);
313}
314
315static void center(char *str, unsigned len, unsigned separate)
316{
317 unsigned n = strlen(str);
318 len -= n;
319 printf("%*s%*s", (len/2) + n, str, (len/2) + (len % 2) + separate, "");
320}
321
322static void blank_string(char *buf, size_t buflen)
323{
324 memset(buf, ' ', buflen);
325 buf[buflen-1] = '\0';
326}
327
328static char *build_row(char *p, unsigned *dp)
329{
330 unsigned col, val, day;
331
332 memset(p, ' ', (julian + DAY_LEN) * 7);
333
334 col = 0;
335 do {
336 day = *dp++;
337 if (day != SPACE) {
338 if (julian) {
339 ++p;
340 if (day >= 100) {
341 *p = '0';
342 p[-1] = (day / 100) + '0';
343 day %= 100;
344 }
345 }
346 val = day / 10;
347 if (val > 0) {
348 *p = val + '0';
349 }
350 *++p = day % 10 + '0';
351 p += 2;
352 } else {
353 p += DAY_LEN + julian;
354 }
355 } while (++col < 7);
356
357 return p;
358}
359
360/*
361 * Copyright (c) 1989, 1993, 1994
362 * The Regents of the University of California. All rights reserved.
363 *
364 * This code is derived from software contributed to Berkeley by
365 * Kim Letkeman.
366 *
367 * Redistribution and use in source and binary forms, with or without
368 * modification, are permitted provided that the following conditions
369 * are met:
370 * 1. Redistributions of source code must retain the above copyright
371 * notice, this list of conditions and the following disclaimer.
372 * 2. Redistributions in binary form must reproduce the above copyright
373 * notice, this list of conditions and the following disclaimer in the
374 * documentation and/or other materials provided with the distribution.
375 * 3. Neither the name of the University nor the names of its contributors
376 * may be used to endorse or promote products derived from this software
377 * without specific prior written permission.
378 *
379 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
380 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
381 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
382 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
383 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
384 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
385 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
386 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
387 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
388 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
389 * SUCH DAMAGE.
390 */
diff --git a/coreutils/cat.c b/coreutils/cat.c
index 65978887e..4d9147f8a 100644
--- a/coreutils/cat.c
+++ b/coreutils/cat.c
@@ -12,56 +12,168 @@
12//config: help 12//config: help
13//config: cat is used to concatenate files and print them to the standard 13//config: cat is used to concatenate files and print them to the standard
14//config: output. Enable this option if you wish to enable the 'cat' utility. 14//config: output. Enable this option if you wish to enable the 'cat' utility.
15//config:
16//config:config FEATURE_CATV
17//config: bool "cat -v[etA]"
18//config: default y
19//config: depends on CAT
20//config: help
21//config: Display nonprinting characters as escape sequences
15 22
16//applet:IF_CAT(APPLET_NOFORK(cat, cat, BB_DIR_BIN, BB_SUID_DROP, cat)) 23//applet:IF_CAT(APPLET(cat, BB_DIR_BIN, BB_SUID_DROP))
17 24
18//kbuild:lib-$(CONFIG_CAT) += cat.o 25//kbuild:lib-$(CONFIG_CAT) += cat.o
19 26
20/* BB_AUDIT SUSv3 compliant */ 27/* BB_AUDIT SUSv3 compliant */
21/* http://www.opengroup.org/onlinepubs/007904975/utilities/cat.html */ 28/* http://www.opengroup.org/onlinepubs/007904975/utilities/cat.html */
22 29
23//usage:#define cat_trivial_usage 30//usage:#define cat_trivial_usage
24//usage: "[FILE]..." 31//usage: "[-nb"IF_FEATURE_CATV("vteA")"] [FILE]..."
25//usage:#define cat_full_usage "\n\n" 32//usage:#define cat_full_usage "\n\n"
26//usage: "Concatenate FILEs and print them to stdout" 33//usage: "Print FILEs to stdout\n"
34//usage: "\n -n Number output lines"
35//usage: "\n -b Number nonempty lines"
36//usage: IF_FEATURE_CATV(
37//usage: "\n -v Show nonprinting characters as ^x or M-x"
38//usage: "\n -t ...and tabs as ^I"
39//usage: "\n -e ...and end lines with $"
40//usage: "\n -A Same as -vte"
41//usage: )
42/*
43 Longopts not implemented yet:
44 --number-nonblank number nonempty output lines, overrides -n
45 --number number all output lines
46 --show-nonprinting use ^ and M- notation, except for LFD and TAB
47 --show-all equivalent to -vet
48 Not implemented yet:
49 -E, --show-ends display $ at end of each line (-e sans -v)
50 -T, --show-tabs display TAB characters as ^I (-t sans -v)
51 -s, --squeeze-blank suppress repeated empty output lines
52*/
27//usage: 53//usage:
28//usage:#define cat_example_usage 54//usage:#define cat_example_usage
29//usage: "$ cat /proc/uptime\n" 55//usage: "$ cat /proc/uptime\n"
30//usage: "110716.72 17.67" 56//usage: "110716.72 17.67"
31 57
32#include "libbb.h" 58#include "libbb.h"
59#include "common_bufsiz.h"
33 60
34/* This is a NOFORK applet. Be very careful! */ 61#if ENABLE_FEATURE_CATV
35 62/*
36 63 * cat -v implementation for busybox
37int bb_cat(char **argv) 64 *
65 * Copyright (C) 2006 Rob Landley <rob@landley.net>
66 *
67 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
68 */
69/* Rob had "cat -v" implemented as a separate applet, catv.
70 * See "cat -v considered harmful" at
71 * http://cm.bell-labs.com/cm/cs/doc/84/kp.ps.gz
72 * From USENIX Summer Conference Proceedings, 1983
73 * """
74 * The talk reviews reasons for UNIX's popularity and shows, using UCB cat
75 * as a primary example, how UNIX has grown fat. cat isn't for printing
76 * files with line numbers, it isn't for compressing multiple blank lines,
77 * it's not for looking at non-printing ASCII characters, it's for
78 * concatenating files.
79 * We are reminded that ls isn't the place for code to break a single column
80 * into multiple ones, and that mailnews shouldn't have its own more
81 * processing or joke encryption code.
82 * """
83 *
84 * I agree with the argument. Unfortunately, this ship has sailed (1983...).
85 * There are dozens of Linux distros and each of them has "cat" which supports -v.
86 * It's unrealistic for us to "reeducate" them to use our, incompatible way
87 * to achieve "cat -v" effect. The actuall effect would be "users pissed off
88 * by gratuitous incompatibility".
89 */
90#define CATV_OPT_e (1<<0)
91#define CATV_OPT_t (1<<1)
92#define CATV_OPT_v (1<<2)
93static int catv(unsigned opts, char **argv)
38{ 94{
39 int fd;
40 int retval = EXIT_SUCCESS; 95 int retval = EXIT_SUCCESS;
96 int fd;
41 97
42 if (!*argv) 98 BUILD_BUG_ON(CATV_OPT_e != VISIBLE_ENDLINE);
43 argv = (char**) &bb_argv_dash; 99 BUILD_BUG_ON(CATV_OPT_t != VISIBLE_SHOW_TABS);
100#if 0 /* These consts match, we can just pass "opts" to visible() */
101 if (opts & CATV_OPT_e)
102 flags |= VISIBLE_ENDLINE;
103 if (opts & CATV_OPT_t)
104 flags |= VISIBLE_SHOW_TABS;
105#endif
106
107 /* Read from stdin if there's nothing else to do. */
108 if (!argv[0])
109 *--argv = (char*)"-";
44 110
111#define read_buf bb_common_bufsiz1
112 setup_common_bufsiz();
45 do { 113 do {
46 fd = open_or_warn_stdin(*argv); 114 fd = open_or_warn_stdin(*argv);
47 if (fd >= 0) { 115 if (fd < 0) {
48 /* This is not a xfunc - never exits */ 116 retval = EXIT_FAILURE;
49 off_t r = bb_copyfd_eof(fd, STDOUT_FILENO); 117 continue;
50 if (fd != STDIN_FILENO)
51 close(fd);
52 if (r >= 0)
53 continue;
54 } 118 }
55 retval = EXIT_FAILURE; 119 for (;;) {
120 int i, res;
121
122 res = read(fd, read_buf, COMMON_BUFSIZE);
123 if (res < 0)
124 retval = EXIT_FAILURE;
125 if (res <= 0)
126 break;
127 for (i = 0; i < res; i++) {
128 unsigned char c = read_buf[i];
129 char buf[sizeof("M-^c")];
130 visible(c, buf, opts);
131 fputs(buf, stdout);
132 }
133 }
134 if (ENABLE_FEATURE_CLEAN_UP && fd)
135 close(fd);
56 } while (*++argv); 136 } while (*++argv);
57 137
58 return retval; 138 fflush_stdout_and_exit(retval);
59} 139}
140#endif
60 141
61int cat_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 142int cat_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
62int cat_main(int argc UNUSED_PARAM, char **argv) 143int cat_main(int argc UNUSED_PARAM, char **argv)
63{ 144{
64 getopt32(argv, "u"); 145 struct number_state ns;
146 unsigned opts;
147
148 IF_FEATURE_CATV(opt_complementary = "Aetv"; /* -A == -vet */)
149 /* -u is ignored ("unbuffered") */
150 opts = getopt32(argv, IF_FEATURE_CATV("etvA")"nbu");
65 argv += optind; 151 argv += optind;
66 return bb_cat(argv); 152
153#if ENABLE_FEATURE_CATV
154 if (opts & 7)
155 return catv(opts, argv);
156//BUG: -v,-e,-t,-A ignore -nb
157 opts >>= 4;
158#endif
159
160#define CAT_OPT_n (1<<0)
161#define CAT_OPT_b (1<<1)
162#define CAT_OPT_u (1<<2)
163 if (!(opts & (CAT_OPT_n|CAT_OPT_b))) /* no -n or -b */
164 return bb_cat(argv);
165
166 if (!*argv)
167 *--argv = (char*)"-";
168 ns.width = 6;
169 ns.start = 1;
170 ns.inc = 1;
171 ns.sep = "\t";
172 ns.empty_str = "\n";
173 ns.all = !(opts & CAT_OPT_b); /* -n without -b */
174 ns.nonempty = (opts & CAT_OPT_b); /* -b (with or without -n) */
175 do {
176 print_numbered_lines(&ns, *argv);
177 } while (*++argv);
178 fflush_stdout_and_exit(EXIT_SUCCESS);
67} 179}
diff --git a/coreutils/catv.c b/coreutils/catv.c
deleted file mode 100644
index 1aeebe1d9..000000000
--- a/coreutils/catv.c
+++ /dev/null
@@ -1,96 +0,0 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * cat -v implementation for busybox
4 *
5 * Copyright (C) 2006 Rob Landley <rob@landley.net>
6 *
7 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
8 */
9
10/* See "Cat -v considered harmful" at
11 * http://cm.bell-labs.com/cm/cs/doc/84/kp.ps.gz */
12
13//config:config CATV
14//config: bool "catv"
15//config: default y
16//config: help
17//config: Display nonprinting characters as escape sequences (like some
18//config: implementations' cat -v option).
19
20//applet:IF_CATV(APPLET(catv, BB_DIR_BIN, BB_SUID_DROP))
21
22//kbuild:lib-$(CONFIG_CATV) += catv.o
23
24//usage:#define catv_trivial_usage
25//usage: "[-etv] [FILE]..."
26//usage:#define catv_full_usage "\n\n"
27//usage: "Display nonprinting characters as ^x or M-x\n"
28//usage: "\n -e End each line with $"
29//usage: "\n -t Show tabs as ^I"
30//usage: "\n -v Don't use ^x or M-x escapes"
31
32#include "libbb.h"
33#include "common_bufsiz.h"
34
35#define CATV_OPT_e (1<<0)
36#define CATV_OPT_t (1<<1)
37#define CATV_OPT_v (1<<2)
38struct BUG_const_mismatch {
39 char BUG_const_mismatch[
40 CATV_OPT_e == VISIBLE_ENDLINE && CATV_OPT_t == VISIBLE_SHOW_TABS
41 ? 1 : -1
42 ];
43};
44
45int catv_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
46int catv_main(int argc UNUSED_PARAM, char **argv)
47{
48 int retval = EXIT_SUCCESS;
49 int fd;
50 unsigned opts;
51 opts = getopt32(argv, "etv");
52 argv += optind;
53#if 0 /* These consts match, we can just pass "opts" to visible() */
54 if (opts & CATV_OPT_e)
55 flags |= VISIBLE_ENDLINE;
56 if (opts & CATV_OPT_t)
57 flags |= VISIBLE_SHOW_TABS;
58#endif
59
60 /* Read from stdin if there's nothing else to do. */
61 if (!argv[0])
62 *--argv = (char*)"-";
63
64#define read_buf bb_common_bufsiz1
65 setup_common_bufsiz();
66 do {
67 fd = open_or_warn_stdin(*argv);
68 if (fd < 0) {
69 retval = EXIT_FAILURE;
70 continue;
71 }
72 for (;;) {
73 int i, res;
74
75 res = read(fd, read_buf, COMMON_BUFSIZE);
76 if (res < 0)
77 retval = EXIT_FAILURE;
78 if (res <= 0)
79 break;
80 for (i = 0; i < res; i++) {
81 unsigned char c = read_buf[i];
82 if (opts & CATV_OPT_v) {
83 putchar(c);
84 } else {
85 char buf[sizeof("M-^c")];
86 visible(c, buf, opts);
87 fputs(buf, stdout);
88 }
89 }
90 }
91 if (ENABLE_FEATURE_CLEAN_UP && fd)
92 close(fd);
93 } while (*++argv);
94
95 fflush_stdout_and_exit(retval);
96}
diff --git a/coreutils/cksum.c b/coreutils/cksum.c
index aeec0188d..9034fc19a 100644
--- a/coreutils/cksum.c
+++ b/coreutils/cksum.c
@@ -17,9 +17,9 @@
17//kbuild:lib-$(CONFIG_CKSUM) += cksum.o 17//kbuild:lib-$(CONFIG_CKSUM) += cksum.o
18 18
19//usage:#define cksum_trivial_usage 19//usage:#define cksum_trivial_usage
20//usage: "FILES..." 20//usage: "FILE..."
21//usage:#define cksum_full_usage "\n\n" 21//usage:#define cksum_full_usage "\n\n"
22//usage: "Calculate the CRC32 checksums of FILES" 22//usage: "Calculate the CRC32 checksums of FILEs"
23 23
24#include "libbb.h" 24#include "libbb.h"
25#include "common_bufsiz.h" 25#include "common_bufsiz.h"
diff --git a/coreutils/dd.c b/coreutils/dd.c
index 85152d8ce..2fccf9d8e 100644
--- a/coreutils/dd.c
+++ b/coreutils/dd.c
@@ -543,11 +543,11 @@ int dd_main(int argc UNUSED_PARAM, char **argv)
543 if (write_and_stats(ibuf, n, obs, outfile)) 543 if (write_and_stats(ibuf, n, obs, outfile))
544 goto out_status; 544 goto out_status;
545 } 545 }
546 }
546 547
547 if (G.flags & FLAG_FSYNC) { 548 if (G.flags & FLAG_FSYNC) {
548 if (fsync(ofd) < 0) 549 if (fsync(ofd) < 0)
549 goto die_outfile; 550 goto die_outfile;
550 }
551 } 551 }
552 552
553 if (ENABLE_FEATURE_DD_IBS_OBS && oc) { 553 if (ENABLE_FEATURE_DD_IBS_OBS && oc) {
diff --git a/coreutils/dos2unix.c b/coreutils/dos2unix.c
index 6d2347163..9d81ccca6 100644
--- a/coreutils/dos2unix.c
+++ b/coreutils/dos2unix.c
@@ -2,7 +2,7 @@
2/* 2/*
3 * dos2unix for BusyBox 3 * dos2unix for BusyBox
4 * 4 *
5 * dos2unix '\n' convertor 0.5.0 5 * dos2unix '\n' converter 0.5.0
6 * based on Unix2Dos 0.9.0 by Peter Hanecak (made 19.2.1997) 6 * based on Unix2Dos 0.9.0 by Peter Hanecak (made 19.2.1997)
7 * Copyright 1997,.. by Peter Hanecak <hanecak@megaloman.sk>. 7 * Copyright 1997,.. by Peter Hanecak <hanecak@megaloman.sk>.
8 * All rights reserved. 8 * All rights reserved.
diff --git a/coreutils/factor.c b/coreutils/factor.c
new file mode 100644
index 000000000..205cdc053
--- /dev/null
+++ b/coreutils/factor.c
@@ -0,0 +1,219 @@
1/*
2 * Copyright (C) 2017 Denys Vlasenko <vda.linux@googlemail.com>
3 *
4 * Licensed under GPLv2, see file LICENSE in this source tree.
5 */
6//config:config FACTOR
7//config: bool "factor"
8//config: default y
9//config: help
10//config: factor factorizes integers
11
12//applet:IF_FACTOR(APPLET(factor, BB_DIR_USR_BIN, BB_SUID_DROP))
13
14//kbuild:lib-$(CONFIG_FACTOR) += factor.o
15
16//usage:#define factor_trivial_usage
17//usage: "[NUMBER]..."
18//usage:#define factor_full_usage "\n\n"
19//usage: "Print prime factors"
20
21#include "libbb.h"
22
23#if 0
24# define dbg(...) bb_error_msg(__VA_ARGS__)
25#else
26# define dbg(...) ((void)0)
27#endif
28
29typedef unsigned long long wide_t;
30
31#if ULLONG_MAX == (UINT_MAX * UINT_MAX + 2 * UINT_MAX)
32/* "unsigned" is half as wide as ullong */
33typedef unsigned half_t;
34#define HALF_MAX UINT_MAX
35#define HALF_FMT ""
36#elif ULLONG_MAX == (ULONG_MAX * ULONG_MAX + 2 * ULONG_MAX)
37/* long is half as wide as ullong */
38typedef unsigned long half_t;
39#define HALF_MAX ULONG_MAX
40#define HALF_FMT "l"
41#else
42#error Cant find an integer type which is half as wide as ullong
43#endif
44
45static half_t isqrt_odd(wide_t N)
46{
47 half_t s = isqrt(N);
48 /* Subtract 1 from even s, odd s won't change: */
49 /* (doesnt work for zero, but we know that s != 0 here) */
50 s = (s - 1) | 1;
51 return s;
52}
53
54static NOINLINE void factorize(wide_t N)
55{
56 half_t factor;
57 half_t max_factor;
58 // unsigned count3;
59 // unsigned count5;
60 // unsigned count7;
61 // ^^^^^^^^^^^^^^^ commented-out simple sieving code (easier to grasp).
62 // Faster sieving, using one word for potentially up to 6 counters:
63 // count upwards in each mask, counter "triggers" when it sets its mask to "100[0]..."
64 // 10987654321098765432109876543210 - bits 31-0 in 32-bit word
65 // 17777713333311111777775555333 - bit masks for counters for primes 3,5,7,11,13,17
66 // 100000100001000010001001 - value for adding 1 to each mask
67 // 10000010000010000100001000100 - value for checking that any mask reached msb
68 enum {
69 SHIFT_3 = 1 << 0,
70 SHIFT_5 = 1 << 3,
71 SHIFT_7 = 1 << 7,
72 INCREMENT_EACH = SHIFT_3 | SHIFT_5 | SHIFT_7,
73 MULTIPLE_OF_3 = 1 << 2,
74 MULTIPLE_OF_5 = 1 << 6,
75 MULTIPLE_OF_7 = 1 << 11,
76 MULTIPLE_DETECTED = MULTIPLE_OF_3 | MULTIPLE_OF_5 | MULTIPLE_OF_7,
77 };
78 unsigned sieve_word;
79
80 if (N < 4)
81 goto end;
82
83 while (!(N & 1)) {
84 printf(" 2");
85 N >>= 1;
86 }
87
88 /* The code needs to be optimized for the case where
89 * there are large prime factors. For example,
90 * this is not hard:
91 * 8262075252869367027 = 3 7 17 23 47 101 113 127 131 137 823
92 * (the largest factor to test is only ~sqrt(823) = 28)
93 * but this is:
94 * 18446744073709551601 = 53 348051774975651917
95 * the last factor requires testing up to
96 * 589959129 - about 100 million iterations.
97 * The slowest case (largest prime) for N < 2^64 is
98 * factor 18446744073709551557 (0xffffffffffffffc5).
99 */
100 max_factor = isqrt_odd(N);
101 // count3 = 3;
102 // count5 = 6;
103 // count7 = 9;
104 sieve_word = 0
105 /* initial count for SHIFT_n is (n-1)/2*3: */
106 + (MULTIPLE_OF_3 - 3 * SHIFT_3)
107 + (MULTIPLE_OF_5 - 6 * SHIFT_5)
108 + (MULTIPLE_OF_7 - 9 * SHIFT_7)
109 //+ (MULTIPLE_OF_11 - 15 * SHIFT_11)
110 //+ (MULTIPLE_OF_13 - 18 * SHIFT_13)
111 //+ (MULTIPLE_OF_17 - 24 * SHIFT_17)
112 ;
113 factor = 3;
114 for (;;) {
115 /* The division is the most costly part of the loop.
116 * On 64bit CPUs, takes at best 12 cycles, often ~20.
117 */
118 while ((N % factor) == 0) { /* not likely */
119 N = N / factor;
120 printf(" %"HALF_FMT"u", factor);
121 max_factor = isqrt_odd(N);
122 }
123 next_factor:
124 if (factor >= max_factor)
125 break;
126 factor += 2;
127 /* Rudimentary wheel sieving: skip multiples of 3, 5 and 7:
128 * Every third odd number is divisible by three and thus isn't a prime:
129 * 5 7 9 11 13 15 17 19 21 23 25 27 29 31 33 35 37 39 41 43 45 47...
130 * ^ ^ ^ ^ ^ ^ ^ _ ^ ^ _ ^ ^ ^ ^
131 * (^ = primes, _ = would-be-primes-if-not-divisible-by-5)
132 * The numbers with space under them are excluded by sieve 3.
133 */
134 // count7--;
135 // count5--;
136 // count3--;
137 // if (count3 && count5 && count7)
138 // continue;
139 sieve_word += INCREMENT_EACH;
140 if (!(sieve_word & MULTIPLE_DETECTED))
141 continue;
142 /*
143 * "factor" is multiple of 3 33% of the time (count3 reached 0),
144 * else, multiple of 5 13% of the time,
145 * else, multiple of 7 7.6% of the time.
146 * Cumulatively, with 3,5,7 sieving we are here 54.3% of the time.
147 */
148 // if (count3 == 0)
149 // count3 = 3;
150 if (sieve_word & MULTIPLE_OF_3)
151 sieve_word -= SHIFT_3 * 3;
152 // if (count5 == 0)
153 // count5 = 5;
154 if (sieve_word & MULTIPLE_OF_5)
155 sieve_word -= SHIFT_5 * 5;
156 // if (count7 == 0)
157 // count7 = 7;
158 if (sieve_word & MULTIPLE_OF_7)
159 sieve_word -= SHIFT_7 * 7;
160 goto next_factor;
161 }
162 end:
163 if (N > 1)
164 printf(" %llu", N);
165 bb_putchar('\n');
166}
167
168static void factorize_numstr(const char *numstr)
169{
170 wide_t N;
171
172 /* Leading + is ok (coreutils compat) */
173 if (*numstr == '+')
174 numstr++;
175 N = bb_strtoull(numstr, NULL, 10);
176 if (errno)
177 bb_show_usage();
178 printf("%llu:", N);
179 factorize(N);
180}
181
182int factor_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
183int factor_main(int argc UNUSED_PARAM, char **argv)
184{
185 //// coreutils has undocumented option ---debug (three dashes)
186 //getopt32(argv, "");
187 //argv += optind;
188 argv++;
189
190 if (!*argv) {
191 /* Read from stdin, several numbers per line are accepted */
192 for (;;) {
193 char *numstr, *line;
194 line = xmalloc_fgetline(stdin);
195 if (!line)
196 return EXIT_SUCCESS;
197 numstr = line;
198 for (;;) {
199 char *end;
200 numstr = skip_whitespace(numstr);
201 if (!numstr[0])
202 break;
203 end = skip_non_whitespace(numstr);
204 if (*end != '\0')
205 *end++ = '\0';
206 factorize_numstr(numstr);
207 numstr = end;
208 }
209 free(line);
210 }
211 }
212
213 do {
214 /* Leading spaces are ok (coreutils compat) */
215 factorize_numstr(skip_whitespace(*argv));
216 } while (*++argv);
217
218 return EXIT_SUCCESS;
219}
diff --git a/coreutils/ls.c b/coreutils/ls.c
index 6e0a52d75..6780057da 100644
--- a/coreutils/ls.c
+++ b/coreutils/ls.c
@@ -1067,17 +1067,19 @@ int ls_main(int argc UNUSED_PARAM, char **argv)
1067 * 'auto', 'tty', 'if-tty' 1067 * 'auto', 'tty', 'if-tty'
1068 * (and substrings: "--color=alwa" work too) 1068 * (and substrings: "--color=alwa" work too)
1069 */ 1069 */
1070 static const char ls_longopts[] ALIGN1 =
1071 "full-time\0" No_argument "\xff"
1072 "group-directories-first\0" No_argument "\xfe"
1073 "color\0" Optional_argument "\xfd"
1074 ;
1075 static const char color_str[] ALIGN1 = 1070 static const char color_str[] ALIGN1 =
1076 "always\0""yes\0""force\0" 1071 "always\0""yes\0""force\0"
1077 "auto\0""tty\0""if-tty\0"; 1072 "auto\0""tty\0""if-tty\0";
1078 /* need to initialize since --color has _an optional_ argument */ 1073 /* need to initialize since --color has _an optional_ argument */
1079 const char *color_opt = color_str; /* "always" */ 1074 const char *color_opt = color_str; /* "always" */
1080#endif 1075#endif
1076#if ENABLE_LONG_OPTS
1077 static const char ls_longopts[] ALIGN1 =
1078 "full-time\0" No_argument "\xff"
1079 "group-directories-first\0" No_argument "\xfe"
1080 "color\0" Optional_argument "\xfd"
1081 ;
1082#endif
1081 1083
1082 INIT_G(); 1084 INIT_G();
1083 1085
@@ -1091,7 +1093,7 @@ int ls_main(int argc UNUSED_PARAM, char **argv)
1091#endif 1093#endif
1092 1094
1093 /* process options */ 1095 /* process options */
1094 IF_FEATURE_LS_COLOR(applet_long_options = ls_longopts;) 1096 IF_LONG_OPTS(applet_long_options = ls_longopts;)
1095 opt_complementary = 1097 opt_complementary =
1096 /* -n and -g imply -l */ 1098 /* -n and -g imply -l */
1097 "nl:gl" 1099 "nl:gl"
diff --git a/coreutils/mktemp.c b/coreutils/mktemp.c
new file mode 100644
index 000000000..65353697a
--- /dev/null
+++ b/coreutils/mktemp.c
@@ -0,0 +1,122 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * Mini mktemp implementation for busybox
4 *
5 *
6 * Copyright (C) 2000 by Daniel Jacobowitz
7 * Written by Daniel Jacobowitz <dan@debian.org>
8 *
9 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
10 */
11
12/* Coreutils 6.12 man page says:
13 * mktemp [OPTION]... [TEMPLATE]
14 * Create a temporary file or directory, safely, and print its name. If
15 * TEMPLATE is not specified, use tmp.XXXXXXXXXX.
16 * -d, --directory
17 * create a directory, not a file
18 * -q, --quiet
19 * suppress diagnostics about file/dir-creation failure
20 * -u, --dry-run
21 * do not create anything; merely print a name (unsafe)
22 * --tmpdir[=DIR]
23 * interpret TEMPLATE relative to DIR. If DIR is not specified,
24 * use $TMPDIR if set, else /tmp. With this option, TEMPLATE must
25 * not be an absolute name. Unlike with -t, TEMPLATE may contain
26 * slashes, but even here, mktemp still creates only the final com-
27 * ponent.
28 * -p DIR use DIR as a prefix; implies -t [deprecated]
29 * -t interpret TEMPLATE as a single file name component, relative to
30 * a directory: $TMPDIR, if set; else the directory specified via
31 * -p; else /tmp [deprecated]
32 */
33//config:config MKTEMP
34//config: bool "mktemp"
35//config: default y
36//config: help
37//config: mktemp is used to create unique temporary files
38
39//applet:IF_MKTEMP(APPLET(mktemp, BB_DIR_BIN, BB_SUID_DROP))
40
41//kbuild:lib-$(CONFIG_MKTEMP) += mktemp.o
42
43//usage:#define mktemp_trivial_usage
44//usage: "[-dt] [-p DIR] [TEMPLATE]"
45//usage:#define mktemp_full_usage "\n\n"
46//usage: "Create a temporary file with name based on TEMPLATE and print its name.\n"
47//usage: "TEMPLATE must end with XXXXXX (e.g. [/dir/]nameXXXXXX).\n"
48//usage: "Without TEMPLATE, -t tmp.XXXXXX is assumed.\n"
49//usage: "\n -d Make directory, not file"
50//usage: "\n -q Fail silently on errors"
51//usage: "\n -t Prepend base directory name to TEMPLATE"
52//usage: "\n -p DIR Use DIR as a base directory (implies -t)"
53//usage: "\n -u Do not create anything; print a name"
54//usage: "\n"
55//usage: "\nBase directory is: -p DIR, else $TMPDIR, else /tmp"
56//usage:
57//usage:#define mktemp_example_usage
58//usage: "$ mktemp /tmp/temp.XXXXXX\n"
59//usage: "/tmp/temp.mWiLjM\n"
60//usage: "$ ls -la /tmp/temp.mWiLjM\n"
61//usage: "-rw------- 1 andersen andersen 0 Apr 25 17:10 /tmp/temp.mWiLjM\n"
62
63#include "libbb.h"
64
65int mktemp_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
66int mktemp_main(int argc UNUSED_PARAM, char **argv)
67{
68 const char *path;
69 char *chp;
70 unsigned opts;
71 enum {
72 OPT_d = 1 << 0,
73 OPT_q = 1 << 1,
74 OPT_t = 1 << 2,
75 OPT_p = 1 << 3,
76 OPT_u = 1 << 4,
77 };
78
79 path = getenv("TMPDIR");
80 if (!path || path[0] == '\0')
81 path = "/tmp";
82
83 opt_complementary = "?1"; /* 1 argument max */
84 opts = getopt32(argv, "dqtp:u", &path);
85
86 chp = argv[optind];
87 if (!chp) {
88 /* GNU coreutils 8.4:
89 * bare "mktemp" -> "mktemp -t tmp.XXXXXX"
90 */
91 chp = xstrdup("tmp.XXXXXX");
92 opts |= OPT_t;
93 }
94#if 0
95 /* Don't allow directory separator in template */
96 if ((opts & OPT_t) && bb_basename(chp) != chp) {
97 errno = EINVAL;
98 goto error;
99 }
100#endif
101 if (opts & (OPT_t|OPT_p))
102 chp = concat_path_file(path, chp);
103
104 if (opts & OPT_u) {
105 chp = mktemp(chp);
106 if (chp[0] == '\0')
107 goto error;
108 } else if (opts & OPT_d) {
109 if (mkdtemp(chp) == NULL)
110 goto error;
111 } else {
112 if (mkstemp(chp) < 0)
113 goto error;
114 }
115 puts(chp);
116 return EXIT_SUCCESS;
117 error:
118 if (opts & OPT_q)
119 return EXIT_FAILURE;
120 /* don't use chp as it gets mangled in case of error */
121 bb_perror_nomsg_and_die();
122}
diff --git a/coreutils/nl.c b/coreutils/nl.c
new file mode 100644
index 000000000..5c64923bb
--- /dev/null
+++ b/coreutils/nl.c
@@ -0,0 +1,101 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * Copyright (C) 2017 Denys Vlasenko <vda.linux@googlemail.com>
4 *
5 * Licensed under GPLv2, see file LICENSE in this source tree.
6 */
7//config:config NL
8//config: bool "nl"
9//config: default y
10//config: help
11//config: nl is used to number lines of files.
12
13//applet:IF_NL(APPLET(nl, BB_DIR_USR_BIN, BB_SUID_DROP))
14
15//kbuild:lib-$(CONFIG_NL) += nl.o
16
17//usage:#define nl_trivial_usage
18//usage: "[OPTIONS] [FILE]..."
19//usage:#define nl_full_usage "\n\n"
20//usage: "Write FILEs to standard output with line numbers added\n"
21//usage: "\n -b STYLE Which lines to number - a: all, t: nonempty, n: none"
22//^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^TODO: support "pBRE": number only lines thatmatch regexp BRE"
23////usage: "\n -f STYLE footer lines"
24////usage: "\n -h STYLE header lines"
25////usage: "\n -d CC use CC for separating logical pages"
26//usage: "\n -i N Line number increment"
27////usage: "\n -l NUMBER group of NUMBER empty lines counted as one"
28////usage: "\n -n FORMAT lneft justified, no leading zeros; rn or rz"
29////usage: "\n -p do not reset line numbers at logical pages (huh?)"
30//usage: "\n -s STRING Use STRING as line number separator"
31//usage: "\n -v N Start from N"
32//usage: "\n -w N Width of line numbers"
33
34/* By default, selects -v1 -i1 -l1 -sTAB -w6 -nrn -hn -bt -fn */
35
36#include "libbb.h"
37
38void FAST_FUNC print_numbered_lines(struct number_state *ns, const char *filename)
39{
40 FILE *fp = fopen_or_warn_stdin(filename);
41 unsigned N = ns->start;
42 char *line;
43
44 while ((line = xmalloc_fgetline(fp)) != NULL) {
45 if (ns->all
46 || (ns->nonempty && line[0])
47 ) {
48 printf("%*u%s%s\n", ns->width, N, ns->sep, line);
49 N += ns->inc;
50 } else if (ns->empty_str)
51 fputs(ns->empty_str, stdout);
52 free(line);
53 }
54
55 fclose(fp);
56}
57
58int nl_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
59int nl_main(int argc UNUSED_PARAM, char **argv)
60{
61 struct number_state ns;
62 const char *opt_b = "t";
63 enum {
64 OPT_p = (1 << 0),
65 };
66#if ENABLE_LONG_OPTS
67 static const char nl_longopts[] ALIGN1 =
68 "body-numbering\0" Required_argument "b"
69 // "footer-numbering\0" Required_argument "f" - not implemented yet
70 // "header-numbering\0" Required_argument "h" - not implemented yet
71 // "section-delimiter\0" Required_argument "d" - not implemented yet
72 "line-increment\0" Required_argument "i"
73 // "join-blank-lines\0" Required_argument "l" - not implemented yet
74 // "number-format\0" Required_argument "n" - not implemented yet
75 "no-renumber\0" No_argument "p" // no-op so far
76 "number-separator\0" Required_argument "s"
77 "starting-line-number\0"Required_argument "v"
78 "number-width\0" Required_argument "w"
79 ;
80
81 applet_long_options = nl_longopts;
82#endif
83 ns.width = 6;
84 ns.start = 1;
85 ns.inc = 1;
86 ns.sep = "\t";
87 getopt32(argv, "pw:+s:v:+i:+b:", &ns.width, &ns.sep, &ns.start, &ns.inc, &opt_b);
88 ns.all = (opt_b[0] == 'a');
89 ns.nonempty = (opt_b[0] == 't');
90 ns.empty_str = xasprintf("%*s\n", ns.width + (int)strlen(ns.sep), "");
91
92 argv += optind;
93 if (!*argv)
94 *--argv = (char*)"-";
95
96 do {
97 print_numbered_lines(&ns, *argv);
98 } while (*++argv);
99
100 fflush_stdout_and_exit(EXIT_SUCCESS);
101}
diff --git a/coreutils/nproc.c b/coreutils/nproc.c
new file mode 100644
index 000000000..d7c6a4ba1
--- /dev/null
+++ b/coreutils/nproc.c
@@ -0,0 +1,51 @@
1/*
2 * Copyright (C) 2017 Denys Vlasenko <vda.linux@googlemail.com>
3 *
4 * Licensed under GPLv2, see LICENSE in this source tree
5 */
6//config:config NPROC
7//config: bool "nproc"
8//config: default y
9//config: help
10//config: Print number of CPUs
11
12//applet:IF_NPROC(APPLET(nproc, BB_DIR_USR_BIN, BB_SUID_DROP))
13
14//kbuild:lib-$(CONFIG_NPROC) += nproc.o
15
16//usage:#define nproc_trivial_usage
17//usage: ""
18//TODO: "[--all] [--ignore=N]"
19//usage:#define nproc_full_usage "\n\n"
20//usage: "Print number of CPUs"
21
22#include <sched.h>
23#include "libbb.h"
24
25int nproc_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
26int nproc_main(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
27{
28 unsigned long mask[1024];
29 unsigned i, count = 0;
30
31 //applet_long_options = ...;
32 //getopt32(argv, "");
33
34 //if --all, count /sys/devices/system/cpu/cpuN dirs, else:
35
36 if (sched_getaffinity(0, sizeof(mask), (void*)mask) == 0) {
37 for (i = 0; i < ARRAY_SIZE(mask); i++) {
38 unsigned long m = mask[i];
39 while (m) {
40 if (m & 1)
41 count++;
42 m >>= 1;
43 }
44 }
45 }
46 if (count == 0)
47 count++;
48 printf("%u\n", count);
49
50 return 0;
51}
diff --git a/coreutils/paste.c b/coreutils/paste.c
new file mode 100644
index 000000000..3920859d6
--- /dev/null
+++ b/coreutils/paste.c
@@ -0,0 +1,140 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * paste.c - implementation of the posix paste command
4 *
5 * Written by Maxime Coste <mawww@kakoune.org>
6 *
7 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
8 */
9//config:config PASTE
10//config: bool "paste"
11//config: default y
12//config: help
13//config: paste is used to paste lines of different files together
14//config: and write the result to stdout
15
16//applet:IF_PASTE(APPLET_NOEXEC(paste, paste, BB_DIR_USR_BIN, BB_SUID_DROP, paste))
17
18//kbuild:lib-$(CONFIG_PASTE) += paste.o
19
20//usage:#define paste_trivial_usage
21//usage: "[OPTIONS] [FILE]..."
22//usage:#define paste_full_usage "\n\n"
23//usage: "Paste lines from each input file, separated with tab\n"
24//usage: "\n -d LIST Use delimiters from LIST, not tab"
25//usage: "\n -s Serial: one file at a time"
26//usage:
27//usage:#define paste_example_usage
28//usage: "# write out directory in four columns\n"
29//usage: "$ ls | paste - - - -\n"
30//usage: "# combine pairs of lines from a file into single lines\n"
31//usage: "$ paste -s -d '\\t\\n' file\n"
32
33#include "libbb.h"
34
35static void paste_files(FILE** files, int file_cnt, char* delims, int del_cnt)
36{
37 char *line;
38 char delim;
39 int active_files = file_cnt;
40 int i;
41
42 while (active_files > 0) {
43 int del_idx = 0;
44
45 for (i = 0; i < file_cnt; ++i) {
46 if (files[i] == NULL)
47 continue;
48
49 line = xmalloc_fgetline(files[i]);
50 if (!line) {
51 fclose_if_not_stdin(files[i]);
52 files[i] = NULL;
53 --active_files;
54 continue;
55 }
56 fputs(line, stdout);
57 free(line);
58 delim = '\n';
59 if (i != file_cnt - 1) {
60 delim = delims[del_idx++];
61 if (del_idx == del_cnt)
62 del_idx = 0;
63 }
64 if (delim != '\0')
65 fputc(delim, stdout);
66 }
67 }
68}
69
70static void paste_files_separate(FILE** files, char* delims, int del_cnt)
71{
72 char *line, *next_line;
73 char delim;
74 int i;
75
76 for (i = 0; files[i]; ++i) {
77 int del_idx = 0;
78
79 line = NULL;
80 while ((next_line = xmalloc_fgetline(files[i])) != NULL) {
81 if (line) {
82 fputs(line, stdout);
83 free(line);
84 delim = delims[del_idx++];
85 if (del_idx == del_cnt)
86 del_idx = 0;
87 if (delim != '\0')
88 fputc(delim, stdout);
89 }
90 line = next_line;
91 }
92 if (line) {
93 /* coreutils adds \n even if this is a final line
94 * of the last file and it was not \n-terminated.
95 */
96 printf("%s\n", line);
97 free(line);
98 }
99 fclose_if_not_stdin(files[i]);
100 }
101}
102
103#define PASTE_OPT_DELIMITERS (1 << 0)
104#define PASTE_OPT_SEPARATE (1 << 1)
105
106int paste_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
107int paste_main(int argc UNUSED_PARAM, char **argv)
108{
109 char *delims = (char*)"\t";
110 int del_cnt = 1;
111 unsigned opt;
112 int i;
113
114 opt = getopt32(argv, "d:s", &delims);
115 argv += optind;
116
117 if (opt & PASTE_OPT_DELIMITERS) {
118 if (!delims[0])
119 bb_error_msg_and_die("-d '' is not supported");
120 /* unknown mappings are not changed: "\z" -> '\\' 'z' */
121 /* trailing backslash, if any, is preserved */
122 del_cnt = strcpy_and_process_escape_sequences(delims, delims) - delims;
123 /* note: handle NUL properly (do not stop at it!): try -d'\t\0\t' */
124 }
125
126 if (!argv[0])
127 (--argv)[0] = (char*) "-";
128 for (i = 0; argv[i]; ++i) {
129 argv[i] = (void*) fopen_or_warn_stdin(argv[i]);
130 if (!argv[i])
131 xfunc_die();
132 }
133
134 if (opt & PASTE_OPT_SEPARATE)
135 paste_files_separate((FILE**)argv, delims, del_cnt);
136 else
137 paste_files((FILE**)argv, i, delims, del_cnt);
138
139 fflush_stdout_and_exit(0);
140}
diff --git a/coreutils/shred.c b/coreutils/shred.c
new file mode 100644
index 000000000..b3c009539
--- /dev/null
+++ b/coreutils/shred.c
@@ -0,0 +1,106 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * Copyright (C) 2017 Denys Vlasenko <vda.linux@googlemail.com>
4 *
5 * Licensed under GPLv2, see file LICENSE in this source tree.
6 */
7//config:config SHRED
8//config: bool "shred"
9//config: default y
10//config: help
11//config: Overwrite a file to hide its contents, and optionally delete it
12
13//applet:IF_SHRED(APPLET(shred, BB_DIR_USR_BIN, BB_SUID_DROP))
14
15//kbuild:lib-$(CONFIG_SHRED) += shred.o
16
17//usage:#define shred_trivial_usage
18//usage: "FILE..."
19//usage:#define shred_full_usage "\n\n"
20//usage: "Overwrite/delete FILEs\n"
21//usage: "\n -f Chmod to ensure writability"
22//usage: "\n -n N Overwrite N times (default 3)"
23//usage: "\n -z Final overwrite with zeros"
24//usage: "\n -u Remove file"
25//-x and -v are accepted but have no effect
26
27/* shred (GNU coreutils) 8.25:
28-f, --force change permissions to allow writing if necessary
29-u truncate and remove file after overwriting
30-z, --zero add a final overwrite with zeros to hide shredding
31-n, --iterations=N overwrite N times instead of the default (3)
32-v, --verbose show progress
33-x, --exact do not round file sizes up to the next full block; this is the default for non-regular files
34--random-source=FILE get random bytes from FILE
35-s, --size=N shred this many bytes (suffixes like K, M, G accepted)
36--remove[=HOW] like -u but give control on HOW to delete; See below
37*/
38
39#include "libbb.h"
40
41int shred_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
42int shred_main(int argc UNUSED_PARAM, char **argv)
43{
44 int rand_fd = rand_fd; /* for compiler */
45 int zero_fd;
46 unsigned num_iter = 3;
47 unsigned opt;
48 enum {
49 OPT_f = (1 << 0),
50 OPT_u = (1 << 1),
51 OPT_z = (1 << 2),
52 OPT_n = (1 << 3),
53 OPT_v = (1 << 4),
54 OPT_x = (1 << 5),
55 };
56
57 opt = getopt32(argv, "fuzn:+vx", &num_iter);
58 argv += optind;
59
60 zero_fd = xopen("/dev/zero", O_RDONLY);
61 if (num_iter != 0)
62 rand_fd = xopen("/dev/urandom", O_RDONLY);
63
64 if (!*argv)
65 bb_show_usage();
66
67 for (;;) {
68 struct stat sb;
69 const char *fname;
70 unsigned i;
71 int fd;
72
73 fname = *argv++;
74 if (!fname)
75 break;
76 fd = -1;
77 if (opt & OPT_f) {
78 fd = open(fname, O_WRONLY);
79 if (fd < 0)
80 chmod(fname, 0666);
81 }
82 if (fd < 0)
83 fd = xopen(fname, O_WRONLY);
84
85 if (fstat(fd, &sb) == 0 && sb.st_size > 0) {
86 off_t size = sb.st_size;
87
88 for (i = 0; i < num_iter; i++) {
89 bb_copyfd_size(rand_fd, fd, size);
90 fdatasync(fd);
91 xlseek(fd, 0, SEEK_SET);
92 }
93 if (opt & OPT_z) {
94 bb_copyfd_size(zero_fd, fd, size);
95 fdatasync(fd);
96 }
97 if (opt & OPT_u) {
98 ftruncate(fd, 0);
99 xunlink(fname);
100 }
101 xclose(fd);
102 }
103 }
104
105 return EXIT_SUCCESS;
106}
diff --git a/coreutils/timeout.c b/coreutils/timeout.c
new file mode 100644
index 000000000..f29dc8a9c
--- /dev/null
+++ b/coreutils/timeout.c
@@ -0,0 +1,127 @@
1/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
2 * COPYING NOTES
3 *
4 * timeout.c -- a timeout handler for shell commands
5 *
6 * Copyright (C) 2005-6, Roberto A. Foglietta <me@roberto.foglietta.name>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; version 2 of the License.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
20 */
21/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
22 * REVISION NOTES:
23 * released 17-11-2005 by Roberto A. Foglietta
24 * talarm 04-12-2005 by Roberto A. Foglietta
25 * modified 05-12-2005 by Roberto A. Foglietta
26 * sizerdct 06-12-2005 by Roberto A. Foglietta
27 * splitszf 12-05-2006 by Roberto A. Foglietta
28 * rewrite 14-11-2008 vda
29 */
30//config:config TIMEOUT
31//config: bool "timeout"
32//config: default y
33//config: help
34//config: Runs a program and watches it. If it does not terminate in
35//config: specified number of seconds, it is sent a signal.
36
37//applet:IF_TIMEOUT(APPLET(timeout, BB_DIR_USR_BIN, BB_SUID_DROP))
38
39//kbuild:lib-$(CONFIG_TIMEOUT) += timeout.o
40
41//usage:#define timeout_trivial_usage
42//usage: "[-t SECS] [-s SIG] PROG ARGS"
43//usage:#define timeout_full_usage "\n\n"
44//usage: "Runs PROG. Sends SIG to it if it is not gone in SECS seconds.\n"
45//usage: "Defaults: SECS: 10, SIG: TERM."
46
47#include "libbb.h"
48
49int timeout_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
50int timeout_main(int argc UNUSED_PARAM, char **argv)
51{
52 int signo;
53 int status;
54 int parent = 0;
55 int timeout = 10;
56 pid_t pid;
57#if !BB_MMU
58 char *sv1, *sv2;
59#endif
60 const char *opt_s = "TERM";
61
62 /* -p option is not documented, it is needed to support NOMMU. */
63
64 /* -t SECONDS; -p PARENT_PID */
65 /* '+': stop at first non-option */
66 getopt32(argv, "+s:t:+" USE_FOR_NOMMU("p:+"), &opt_s, &timeout, &parent);
67 /*argv += optind; - no, wait for bb_daemonize_or_rexec! */
68 signo = get_signum(opt_s);
69 if (signo < 0)
70 bb_error_msg_and_die("unknown signal '%s'", opt_s);
71
72 /* We want to create a grandchild which will watch
73 * and kill the grandparent. Other methods:
74 * making parent watch child disrupts parent<->child link
75 * (example: "tcpsvd 0.0.0.0 1234 timeout service_prog" -
76 * it's better if service_prog is a child of tcpsvd!),
77 * making child watch parent results in programs having
78 * unexpected children. */
79
80 if (parent) /* we were re-execed, already grandchild */
81 goto grandchild;
82 if (!argv[optind]) /* no PROG? */
83 bb_show_usage();
84
85#if !BB_MMU
86 sv1 = argv[optind];
87 sv2 = argv[optind + 1];
88#endif
89 pid = xvfork();
90 if (pid == 0) {
91 /* Child: spawn grandchild and exit */
92 parent = getppid();
93#if !BB_MMU
94 argv[optind] = xasprintf("-p%u", parent);
95 argv[optind + 1] = NULL;
96#endif
97 /* NB: exits with nonzero on error: */
98 bb_daemonize_or_rexec(0, argv);
99 /* Here we are grandchild. Sleep, then kill grandparent */
100 grandchild:
101 /* Just sleep(HUGE_NUM); kill(parent) may kill wrong process! */
102 while (1) {
103 sleep(1);
104 if (--timeout <= 0)
105 break;
106 if (kill(parent, 0)) {
107 /* process is gone */
108 return EXIT_SUCCESS;
109 }
110 }
111 kill(parent, signo);
112 return EXIT_SUCCESS;
113 }
114
115 /* Parent */
116 wait(&status); /* wait for child to die */
117 /* Did intermediate [v]fork or exec fail? */
118 if (!WIFEXITED(status) || WEXITSTATUS(status) != 0)
119 return EXIT_FAILURE;
120 /* Ok, exec a program as requested */
121 argv += optind;
122#if !BB_MMU
123 argv[0] = sv1;
124 argv[1] = sv2;
125#endif
126 BB_EXECVP_or_die(argv);
127}
diff --git a/coreutils/uniq.c b/coreutils/uniq.c
index be550b5cd..2b62ad3ae 100644
--- a/coreutils/uniq.c
+++ b/coreutils/uniq.c
@@ -26,6 +26,7 @@
26//usage: "\n -c Prefix lines by the number of occurrences" 26//usage: "\n -c Prefix lines by the number of occurrences"
27//usage: "\n -d Only print duplicate lines" 27//usage: "\n -d Only print duplicate lines"
28//usage: "\n -u Only print unique lines" 28//usage: "\n -u Only print unique lines"
29//usage: "\n -i Ignore case"
29//usage: "\n -f N Skip first N fields" 30//usage: "\n -f N Skip first N fields"
30//usage: "\n -s N Skip first N chars (after any skipped fields)" 31//usage: "\n -s N Skip first N chars (after any skipped fields)"
31//usage: "\n -w N Compare N characters in line" 32//usage: "\n -w N Compare N characters in line"
@@ -54,12 +55,13 @@ int uniq_main(int argc UNUSED_PARAM, char **argv)
54 OPT_f = 0x8, 55 OPT_f = 0x8,
55 OPT_s = 0x10, 56 OPT_s = 0x10,
56 OPT_w = 0x20, 57 OPT_w = 0x20,
58 OPT_i = 0x40,
57 }; 59 };
58 60
59 skip_fields = skip_chars = 0; 61 skip_fields = skip_chars = 0;
60 max_chars = INT_MAX; 62 max_chars = INT_MAX;
61 63
62 opt = getopt32(argv, "cduf:+s:+w:+", &skip_fields, &skip_chars, &max_chars); 64 opt = getopt32(argv, "cduf:+s:+w:+i", &skip_fields, &skip_chars, &max_chars);
63 argv += optind; 65 argv += optind;
64 66
65 input_filename = argv[0]; 67 input_filename = argv[0];
@@ -106,7 +108,12 @@ int uniq_main(int argc UNUSED_PARAM, char **argv)
106 ++cur_compare; 108 ++cur_compare;
107 } 109 }
108 110
109 if (!old_line || strncmp(old_compare, cur_compare, max_chars)) { 111 if (!old_line)
112 break;
113 if ((opt & OPT_i)
114 ? strncasecmp(old_compare, cur_compare, max_chars)
115 : strncmp(old_compare, cur_compare, max_chars)
116 ) {
110 break; 117 break;
111 } 118 }
112 119
diff --git a/coreutils/who.c b/coreutils/who.c
index e6179bb00..4adead77e 100644
--- a/coreutils/who.c
+++ b/coreutils/who.c
@@ -23,6 +23,14 @@
23//config: help 23//config: help
24//config: who is used to show who is logged on. 24//config: who is used to show who is logged on.
25//config: 25//config:
26// procps-ng has this variation of "who":
27//config:config W
28//config: bool "w"
29//config: default y
30//config: depends on FEATURE_UTMP
31//config: help
32//config: w is used to show who is logged on.
33//config:
26//config:config USERS 34//config:config USERS
27//config: bool "users" 35//config: bool "users"
28//config: default y 36//config: default y
@@ -32,10 +40,12 @@
32 40
33// APPLET_ODDNAME:name main location suid_type help 41// APPLET_ODDNAME:name main location suid_type help
34//applet:IF_USERS(APPLET_ODDNAME(users, who, BB_DIR_USR_BIN, BB_SUID_DROP, users)) 42//applet:IF_USERS(APPLET_ODDNAME(users, who, BB_DIR_USR_BIN, BB_SUID_DROP, users))
35//applet:IF_WHO(APPLET(who, BB_DIR_USR_BIN, BB_SUID_DROP)) 43//applet:IF_W( APPLET_ODDNAME(w, who, BB_DIR_USR_BIN, BB_SUID_DROP, w))
44//applet:IF_WHO( APPLET( who, BB_DIR_USR_BIN, BB_SUID_DROP))
36 45
37//kbuild:lib-$(CONFIG_USERS) += who.o 46//kbuild:lib-$(CONFIG_USERS) += who.o
38//kbuild:lib-$(CONFIG_WHO) += who.o 47//kbuild:lib-$(CONFIG_W) += who.o
48//kbuild:lib-$(CONFIG_WHO) += who.o
39 49
40/* BB_AUDIT SUSv3 _NOT_ compliant -- missing options -b, -d, -l, -m, -p, -q, -r, -s, -t, -T, -u; Missing argument 'file'. */ 50/* BB_AUDIT SUSv3 _NOT_ compliant -- missing options -b, -d, -l, -m, -p, -q, -r, -s, -t, -T, -u; Missing argument 'file'. */
41 51
@@ -44,6 +54,31 @@
44//usage:#define users_full_usage "\n\n" 54//usage:#define users_full_usage "\n\n"
45//usage: "Print the users currently logged on" 55//usage: "Print the users currently logged on"
46 56
57//usage:#define w_trivial_usage
58//usage: ""
59//usage:#define w_full_usage "\n\n"
60//usage: "Show who is logged on"
61//
62// procps-ng 3.3.10:
63// "\n -h, --no-header"
64// "\n -u, --no-current"
65// Ignores the username while figuring out the current process
66// and cpu times. To demonstrate this, do a "su" and do a "w" and a "w -u".
67// "\n -s, --short"
68// Short format. Don't print the login time, JCPU or PCPU times.
69// "\n -f, --from"
70// Toggle printing the from (remote hostname) field.
71// The default is for the from field to not be printed
72// "\n -i, --ip-addr"
73// Display IP address instead of hostname for from field.
74// "\n -o, --old-style"
75// Old style output. Prints blank space for idle times less than one minute.
76// Example output:
77// 17:28:00 up 4 days, 22:41, 4 users, load average: 0.84, 0.97, 0.90
78// USER TTY LOGIN@ IDLE JCPU PCPU WHAT
79// root tty1 Thu18 4days 4:33m 0.07s /bin/sh /etc/xdg/xfce4/xinitrc -- vt
80// root pts/1 Mon13 3:24m 1:01 0.01s w
81
47//usage:#define who_trivial_usage 82//usage:#define who_trivial_usage
48//usage: "[-a]" 83//usage: "[-a]"
49//usage:#define who_full_usage "\n\n" 84//usage:#define who_full_usage "\n\n"
@@ -74,14 +109,17 @@ static void idle_string(char *str6, time_t t)
74int who_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 109int who_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
75int who_main(int argc UNUSED_PARAM, char **argv) 110int who_main(int argc UNUSED_PARAM, char **argv)
76{ 111{
112#define CNT_APPLET (ENABLE_USERS + ENABLE_W + ENABLE_WHO)
113 int do_users = (ENABLE_USERS && (CNT_APPLET == 1 || applet_name[0] == 'u'));
114 int do_w = (ENABLE_W && (CNT_APPLET == 1 || applet_name[1] == '\0'));
115 int do_who = (ENABLE_WHO && (CNT_APPLET == 1 || applet_name[1] == 'h'));
77 struct utmpx *ut; 116 struct utmpx *ut;
78 unsigned opt; 117 unsigned opt;
79 int do_users = (ENABLE_USERS && (!ENABLE_WHO || applet_name[0] == 'u'));
80 const char *fmt = "%s"; 118 const char *fmt = "%s";
81 119
82 opt_complementary = "=0"; 120 opt_complementary = "=0";
83 opt = getopt32(argv, do_users ? "" : "aH"); 121 opt = getopt32(argv, do_who ? "aH" : "");
84 if (opt & 2) // -H 122 if ((opt & 2) || do_w) /* -H or we are w */
85 puts("USER\t\tTTY\t\tIDLE\tTIME\t\t HOST"); 123 puts("USER\t\tTTY\t\tIDLE\tTIME\t\t HOST");
86 124
87 setutxent(); 125 setutxent();
@@ -115,6 +153,9 @@ int who_main(int argc UNUSED_PARAM, char **argv)
115 (int)sizeof(ut->ut_user), ut->ut_user, 153 (int)sizeof(ut->ut_user), ut->ut_user,
116 (int)sizeof(ut->ut_line), ut->ut_line, 154 (int)sizeof(ut->ut_line), ut->ut_line,
117 str6, 155 str6,
156// TODO: with LANG=en_US.UTF-8, who from coreutils 8.25 shows
157// TIME col as "2017-04-06 18:47" (the default format is "Apr 6 18:47").
158// The former format looks saner to me. Switch to it unconditionally?
118 ctime(&seconds) + 4, 159 ctime(&seconds) + 4,
119 (int)sizeof(ut->ut_host), ut->ut_host 160 (int)sizeof(ut->ut_host), ut->ut_host
120 ); 161 );