diff options
author | Ron Yorston <rmy@pobox.com> | 2017-05-29 14:20:10 +0100 |
---|---|---|
committer | Ron Yorston <rmy@pobox.com> | 2017-05-29 14:34:28 +0100 |
commit | da4f331955bed8afda670afcd58d524a04a0faa9 (patch) | |
tree | f6a3879aefdd714240f8c022375f687b512d2238 /coreutils | |
parent | 74163a535fd21f5fcca4c052d2e7c192d3e264fa (diff) | |
parent | 6683d1cbb44859f549f87f882545b84b9369585c (diff) | |
download | busybox-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.c | 390 | ||||
-rw-r--r-- | coreutils/cat.c | 156 | ||||
-rw-r--r-- | coreutils/catv.c | 96 | ||||
-rw-r--r-- | coreutils/cksum.c | 4 | ||||
-rw-r--r-- | coreutils/dd.c | 8 | ||||
-rw-r--r-- | coreutils/dos2unix.c | 2 | ||||
-rw-r--r-- | coreutils/factor.c | 219 | ||||
-rw-r--r-- | coreutils/ls.c | 14 | ||||
-rw-r--r-- | coreutils/mktemp.c | 122 | ||||
-rw-r--r-- | coreutils/nl.c | 101 | ||||
-rw-r--r-- | coreutils/nproc.c | 51 | ||||
-rw-r--r-- | coreutils/paste.c | 140 | ||||
-rw-r--r-- | coreutils/shred.c | 106 | ||||
-rw-r--r-- | coreutils/timeout.c | 127 | ||||
-rw-r--r-- | coreutils/uniq.c | 11 | ||||
-rw-r--r-- | coreutils/who.c | 51 |
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 | |||
49 | static const unsigned char days_in_month[] ALIGN1 = { | ||
50 | 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 | ||
51 | }; | ||
52 | |||
53 | static 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 */ | ||
63 | static 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 | |||
82 | static void center(char *, unsigned, unsigned); | ||
83 | static void day_array(unsigned, unsigned, unsigned *); | ||
84 | static void trim_trailing_spaces_and_print(char *); | ||
85 | |||
86 | static void blank_string(char *buf, size_t buflen); | ||
87 | static 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 | |||
95 | int cal_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | ||
96 | int 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 | */ | ||
235 | static 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 | |||
297 | static 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 | |||
315 | static 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 | |||
322 | static void blank_string(char *buf, size_t buflen) | ||
323 | { | ||
324 | memset(buf, ' ', buflen); | ||
325 | buf[buflen-1] = '\0'; | ||
326 | } | ||
327 | |||
328 | static 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 | |
37 | int 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) | ||
93 | static 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 | ||
61 | int cat_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | 142 | int cat_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; |
62 | int cat_main(int argc UNUSED_PARAM, char **argv) | 143 | int 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) | ||
38 | struct 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 | |||
45 | int catv_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | ||
46 | int 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 | |||
29 | typedef 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 */ | ||
33 | typedef 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 */ | ||
38 | typedef 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 | |||
45 | static 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 | |||
54 | static 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 | |||
168 | static 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 | |||
182 | int factor_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | ||
183 | int 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 | |||
65 | int mktemp_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | ||
66 | int 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 | |||
38 | void 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 | |||
58 | int nl_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | ||
59 | int 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 | |||
25 | int nproc_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | ||
26 | int 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 | |||
35 | static 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 | |||
70 | static 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 | |||
106 | int paste_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | ||
107 | int 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 | |||
41 | int shred_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | ||
42 | int 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 | |||
49 | int timeout_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | ||
50 | int 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) | |||
74 | int who_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | 109 | int who_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; |
75 | int who_main(int argc UNUSED_PARAM, char **argv) | 110 | int 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 | ); |