aboutsummaryrefslogtreecommitdiff
path: root/util-linux
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 /util-linux
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 'util-linux')
-rw-r--r--util-linux/cal.c390
-rw-r--r--util-linux/chrt.c149
-rw-r--r--util-linux/eject.c152
-rw-r--r--util-linux/fallocate.c104
-rw-r--r--util-linux/fsfreeze.c54
-rw-r--r--util-linux/getopt.c7
-rw-r--r--util-linux/hwclock.c2
-rw-r--r--util-linux/ionice.c115
-rw-r--r--util-linux/last.c166
-rw-r--r--util-linux/last_fancy.c300
-rw-r--r--util-linux/losetup.c27
-rw-r--r--util-linux/mesg.c76
-rw-r--r--util-linux/mount.c21
-rw-r--r--util-linux/mountpoint.c105
-rw-r--r--util-linux/renice.c148
-rw-r--r--util-linux/setsid.c82
-rw-r--r--util-linux/switch_root.c12
-rw-r--r--util-linux/taskset.c221
-rw-r--r--util-linux/umount.c24
-rw-r--r--util-linux/volume_id/udf.c2
-rw-r--r--util-linux/wall.c63
21 files changed, 2189 insertions, 31 deletions
diff --git a/util-linux/cal.c b/util-linux/cal.c
new file mode 100644
index 000000000..8196619b0
--- /dev/null
+++ b/util-linux/cal.c
@@ -0,0 +1,390 @@
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" instead 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/util-linux/chrt.c b/util-linux/chrt.c
new file mode 100644
index 000000000..1604a6890
--- /dev/null
+++ b/util-linux/chrt.c
@@ -0,0 +1,149 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * chrt - manipulate real-time attributes of a process
4 * Copyright (c) 2006-2007 Bernhard Reutner-Fischer
5 *
6 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
7 */
8//config:config CHRT
9//config: bool "chrt"
10//config: default y
11//config: help
12//config: manipulate real-time attributes of a process.
13//config: This requires sched_{g,s}etparam support in your libc.
14
15//applet:IF_CHRT(APPLET(chrt, BB_DIR_USR_BIN, BB_SUID_DROP))
16
17//kbuild:lib-$(CONFIG_CHRT) += chrt.o
18
19//usage:#define chrt_trivial_usage
20//usage: "[-prfom] [PRIO] [PID | PROG ARGS]"
21//usage:#define chrt_full_usage "\n\n"
22//usage: "Change scheduling priority and class for a process\n"
23//usage: "\n -p Operate on PID"
24//usage: "\n -r Set SCHED_RR class"
25//usage: "\n -f Set SCHED_FIFO class"
26//usage: "\n -o Set SCHED_OTHER class"
27//usage: "\n -m Show min/max priorities"
28//usage:
29//usage:#define chrt_example_usage
30//usage: "$ chrt -r 4 sleep 900; x=$!\n"
31//usage: "$ chrt -f -p 3 $x\n"
32//usage: "You need CAP_SYS_NICE privileges to set scheduling attributes of a process"
33
34#include <sched.h>
35#include "libbb.h"
36
37static const struct {
38 int policy;
39 char name[sizeof("SCHED_OTHER")];
40} policies[] = {
41 {SCHED_OTHER, "SCHED_OTHER"},
42 {SCHED_FIFO, "SCHED_FIFO"},
43 {SCHED_RR, "SCHED_RR"}
44};
45
46//TODO: add
47// -b, SCHED_BATCH
48// -i, SCHED_IDLE
49
50static void show_min_max(int pol)
51{
52 const char *fmt = "%s min/max priority\t: %u/%u\n";
53 int max, min;
54
55 max = sched_get_priority_max(pol);
56 min = sched_get_priority_min(pol);
57 if ((max|min) < 0)
58 fmt = "%s not supported\n";
59 printf(fmt, policies[pol].name, min, max);
60}
61
62#define OPT_m (1<<0)
63#define OPT_p (1<<1)
64#define OPT_r (1<<2)
65#define OPT_f (1<<3)
66#define OPT_o (1<<4)
67
68int chrt_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
69int chrt_main(int argc UNUSED_PARAM, char **argv)
70{
71 pid_t pid = 0;
72 unsigned opt;
73 struct sched_param sp;
74 char *pid_str;
75 char *priority = priority; /* for compiler */
76 const char *current_new;
77 int policy = SCHED_RR;
78
79 /* only one policy accepted */
80 opt_complementary = "r--fo:f--ro:o--rf";
81 opt = getopt32(argv, "+mprfo");
82 if (opt & OPT_m) { /* print min/max and exit */
83 show_min_max(SCHED_FIFO);
84 show_min_max(SCHED_RR);
85 show_min_max(SCHED_OTHER);
86 fflush_stdout_and_exit(EXIT_SUCCESS);
87 }
88 if (opt & OPT_r)
89 policy = SCHED_RR;
90 if (opt & OPT_f)
91 policy = SCHED_FIFO;
92 if (opt & OPT_o)
93 policy = SCHED_OTHER;
94
95 argv += optind;
96 if (!argv[0])
97 bb_show_usage();
98 if (opt & OPT_p) {
99 pid_str = *argv++;
100 if (*argv) { /* "-p <priority> <pid> [...]" */
101 priority = pid_str;
102 pid_str = *argv;
103 }
104 /* else "-p <pid>", and *argv == NULL */
105 pid = xatoul_range(pid_str, 1, ((unsigned)(pid_t)ULONG_MAX) >> 1);
106 } else {
107 priority = *argv++;
108 if (!*argv)
109 bb_show_usage();
110 }
111
112 current_new = "current\0new";
113 if (opt & OPT_p) {
114 int pol;
115 print_rt_info:
116 pol = sched_getscheduler(pid);
117 if (pol < 0)
118 bb_perror_msg_and_die("can't %cet pid %d's policy", 'g', (int)pid);
119 printf("pid %d's %s scheduling policy: %s\n",
120 pid, current_new, policies[pol].name);
121 if (sched_getparam(pid, &sp))
122 bb_perror_msg_and_die("can't get pid %d's attributes", (int)pid);
123 printf("pid %d's %s scheduling priority: %d\n",
124 (int)pid, current_new, sp.sched_priority);
125 if (!*argv) {
126 /* Either it was just "-p <pid>",
127 * or it was "-p <priority> <pid>" and we came here
128 * for the second time (see goto below) */
129 return EXIT_SUCCESS;
130 }
131 *argv = NULL;
132 current_new += 8;
133 }
134
135 /* from the manpage of sched_getscheduler:
136 [...] sched_priority can have a value in the range 0 to 99.
137 [...] SCHED_OTHER or SCHED_BATCH must be assigned static priority 0.
138 [...] SCHED_FIFO or SCHED_RR can have static priority in 1..99 range.
139 */
140 sp.sched_priority = xstrtou_range(priority, 0, policy != SCHED_OTHER ? 1 : 0, 99);
141
142 if (sched_setscheduler(pid, policy, &sp) < 0)
143 bb_perror_msg_and_die("can't %cet pid %d's policy", 's', (int)pid);
144
145 if (!argv[0]) /* "-p <priority> <pid> [...]" */
146 goto print_rt_info;
147
148 BB_EXECVP_or_die(argv);
149}
diff --git a/util-linux/eject.c b/util-linux/eject.c
new file mode 100644
index 000000000..667932f6c
--- /dev/null
+++ b/util-linux/eject.c
@@ -0,0 +1,152 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * eject implementation for busybox
4 *
5 * Copyright (C) 2004 Peter Willis <psyphreak@phreaker.net>
6 * Copyright (C) 2005 Tito Ragusa <farmatito@tiscali.it>
7 *
8 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
9 */
10
11/*
12 * This is a simple hack of eject based on something Erik posted in #uclibc.
13 * Most of the dirty work blatantly ripped off from cat.c =)
14 */
15//config:config EJECT
16//config: bool "eject"
17//config: default y
18//config: select PLATFORM_LINUX
19//config: help
20//config: Used to eject cdroms. (defaults to /dev/cdrom)
21//config:
22//config:config FEATURE_EJECT_SCSI
23//config: bool "SCSI support"
24//config: default y
25//config: depends on EJECT
26//config: help
27//config: Add the -s option to eject, this allows to eject SCSI-Devices and
28//config: usb-storage devices.
29
30//applet:IF_EJECT(APPLET(eject, BB_DIR_USR_BIN, BB_SUID_DROP))
31
32//kbuild:lib-$(CONFIG_EJECT) += eject.o
33
34//usage:#define eject_trivial_usage
35//usage: "[-t] [-T] [DEVICE]"
36//usage:#define eject_full_usage "\n\n"
37//usage: "Eject DEVICE or default /dev/cdrom\n"
38//usage: IF_FEATURE_EJECT_SCSI(
39//usage: "\n -s SCSI device"
40//usage: )
41//usage: "\n -t Close tray"
42//usage: "\n -T Open/close tray (toggle)"
43
44#include <sys/mount.h>
45#include "libbb.h"
46#if ENABLE_FEATURE_EJECT_SCSI
47/* Must be after libbb.h: they need size_t */
48# include "fix_u32.h"
49# include <scsi/sg.h>
50# include <scsi/scsi.h>
51#endif
52
53#define dev_fd 3
54
55/* Code taken from the original eject (http://eject.sourceforge.net/),
56 * refactored it a bit for busybox (ne-bb@nicoerfurth.de) */
57
58#if ENABLE_FEATURE_EJECT_SCSI
59static void eject_scsi(const char *dev)
60{
61 static const char sg_commands[3][6] ALIGN1 = {
62 { ALLOW_MEDIUM_REMOVAL, 0, 0, 0, 0, 0 },
63 { START_STOP, 0, 0, 0, 1, 0 },
64 { START_STOP, 0, 0, 0, 2, 0 }
65 };
66
67 unsigned i;
68 unsigned char sense_buffer[32];
69 unsigned char inqBuff[2];
70 sg_io_hdr_t io_hdr;
71
72 if ((ioctl(dev_fd, SG_GET_VERSION_NUM, &i) < 0) || (i < 30000))
73 bb_error_msg_and_die("not a sg device or old sg driver");
74
75 memset(&io_hdr, 0, sizeof(sg_io_hdr_t));
76 io_hdr.interface_id = 'S';
77 io_hdr.cmd_len = 6;
78 io_hdr.mx_sb_len = sizeof(sense_buffer);
79 io_hdr.dxfer_direction = SG_DXFER_NONE;
80 /* io_hdr.dxfer_len = 0; */
81 io_hdr.dxferp = inqBuff;
82 io_hdr.sbp = sense_buffer;
83 io_hdr.timeout = 2000;
84
85 for (i = 0; i < 3; i++) {
86 io_hdr.cmdp = (void *)sg_commands[i];
87 ioctl_or_perror_and_die(dev_fd, SG_IO, (void *)&io_hdr, "%s", dev);
88 }
89
90 /* force kernel to reread partition table when new disc is inserted */
91 ioctl(dev_fd, BLKRRPART);
92}
93#else
94# define eject_scsi(dev) ((void)0)
95#endif
96
97/* various defines swiped from linux/cdrom.h */
98#define CDROMCLOSETRAY 0x5319 /* pendant of CDROMEJECT */
99#define CDROMEJECT 0x5309 /* Ejects the cdrom media */
100#define CDROM_DRIVE_STATUS 0x5326 /* Get tray position, etc. */
101/* drive status possibilities returned by CDROM_DRIVE_STATUS ioctl */
102#define CDS_TRAY_OPEN 2
103
104#define FLAG_CLOSE 1
105#define FLAG_SMART 2
106#define FLAG_SCSI 4
107
108static void eject_cdrom(unsigned flags, const char *dev)
109{
110 int cmd = CDROMEJECT;
111
112 if (flags & FLAG_CLOSE
113 || ((flags & FLAG_SMART) && ioctl(dev_fd, CDROM_DRIVE_STATUS) == CDS_TRAY_OPEN)
114 ) {
115 cmd = CDROMCLOSETRAY;
116 }
117
118 ioctl_or_perror_and_die(dev_fd, cmd, NULL, "%s", dev);
119}
120
121int eject_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
122int eject_main(int argc UNUSED_PARAM, char **argv)
123{
124 unsigned flags;
125 const char *device;
126
127 opt_complementary = "?1:t--T:T--t";
128 flags = getopt32(argv, "tT" IF_FEATURE_EJECT_SCSI("s"));
129 device = argv[optind] ? argv[optind] : "/dev/cdrom";
130
131 /* We used to do "umount <device>" here, but it was buggy
132 if something was mounted OVER cdrom and
133 if cdrom is mounted many times.
134
135 This works equally well (or better):
136 #!/bin/sh
137 umount /dev/cdrom
138 eject /dev/cdrom
139 */
140
141 xmove_fd(xopen_nonblocking(device), dev_fd);
142
143 if (ENABLE_FEATURE_EJECT_SCSI && (flags & FLAG_SCSI))
144 eject_scsi(device);
145 else
146 eject_cdrom(flags, device);
147
148 if (ENABLE_FEATURE_CLEAN_UP)
149 close(dev_fd);
150
151 return EXIT_SUCCESS;
152}
diff --git a/util-linux/fallocate.c b/util-linux/fallocate.c
new file mode 100644
index 000000000..1cd851bde
--- /dev/null
+++ b/util-linux/fallocate.c
@@ -0,0 +1,104 @@
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
8//config:config FALLOCATE
9//config: bool "fallocate"
10//config: default y
11//config: help
12//config: Preallocate space for files.
13
14//applet:IF_FALLOCATE(APPLET(fallocate, BB_DIR_USR_BIN, BB_SUID_DROP))
15
16//kbuild:lib-$(CONFIG_FALLOCATE) += fallocate.o
17
18//usage:#define fallocate_trivial_usage
19//usage: "[-o OFS] -l LEN FILE"
20// fallocate [-c|-p|-z] [-n] [-o OFS] -l LEN FILE
21// fallocate -d [-o OFS] [-l LEN] FILE
22//usage:#define fallocate_full_usage "\n\n"
23//usage: "Preallocate space for FILE\n"
24// "\n -c Remove range"
25// "\n -p Make hole"
26// "\n -z Zero and allocate range"
27// "\n -d Convert zeros to holes"
28// "\n -n Keep size"
29//usage: "\n -o OFS Offset of range"
30//usage: "\n -l LEN Length of range"
31
32//Upstream options:
33//The options --collapse-range, --dig-holes, --punch-hole and --zero-range
34//are mutually exclusive.
35//-c, --collapse-range
36// Removes a byte range from a file, without leaving a hole. The byte range
37// to be collapsed starts at offset and continues for length bytes.
38// At the completion of the operation, the contents of the file starting
39// at the location offset+length will be appended at the location offset,
40// and the file will be length bytes smaller. The option --keep-size may
41// not be specified for the collapse-range operation.
42//-d, --dig-holes
43// Detect and dig holes. This makes the file sparse in-place, without using
44// extra disk space. The minimum size of the hole depends on filesystem I/O
45// block size (usually 4096 bytes). Also,
46//-l, --length length
47// Specifies the length of the range, in bytes.
48//-n, --keep-size
49// Do not modify the apparent length of the file. This may effectively
50// allocate blocks past EOF, which can be removed with a truncate.
51//-o, --offset offset
52// Specifies the beginning offset of the range, in bytes.
53//-p, --punch-hole
54// Deallocates space (i.e., creates a hole) in the byte range starting
55// at offset and continuing for length bytes. Within the specified range,
56// partial filesystem blocks are zeroed, and whole
57// filesystem blocks are removed from the file. After a successful call,
58// subsequent reads from this range will return zeroes. This option may not
59// be specified at the same time as the
60// --zero-range option. Also, when using this option, --keep-size is implied.
61//-z, --zero-range
62// Zeroes space in the byte range starting at offset and continuing for
63// length bytes. Within the specified range, blocks are preallocated for
64// the regions that span the holes in the file. After
65// a successful call, subsequent reads from this range will return zeroes.
66// Zeroing is done within the filesystem preferably by converting the range
67// into unwritten extents. This approach means that the specified range
68// will not be physically zeroed out on the device (except for partial
69// blocks at the either end of the range), and I/O is (otherwise) required
70// only to update metadata.
71// Option --keep-size can be specified to prevent file length modification.
72
73#include "libbb.h"
74
75int fallocate_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
76int fallocate_main(int argc UNUSED_PARAM, char **argv)
77{
78 const char *str_l;
79 const char *str_o = "0";
80 off_t ofs, len;
81 unsigned opts;
82 int fd;
83
84 /* exactly one non-option arg */
85 opt_complementary = "=1";
86 opts = getopt32(argv, "l:o:", &str_l, &str_o);
87 if (!(opts & 1))
88 bb_show_usage();
89
90 ofs = xatoull_sfx(str_o, kmg_i_suffixes);
91 len = xatoull_sfx(str_l, kmg_i_suffixes);
92
93 argv += optind;
94 fd = xopen3(*argv, O_RDWR | O_CREAT, 0666);
95
96 /* posix_fallocate has unusual method of returning error */
97 /* maybe use Linux-specific fallocate(int fd, int mode, off_t offset, off_t len) instead? */
98 if ((errno = posix_fallocate(fd, ofs, len)) != 0)
99 bb_perror_msg_and_die("fallocate '%s'", *argv);
100
101 /* util-linux also performs fsync(fd); */
102
103 return EXIT_SUCCESS;
104}
diff --git a/util-linux/fsfreeze.c b/util-linux/fsfreeze.c
new file mode 100644
index 000000000..70dec24ec
--- /dev/null
+++ b/util-linux/fsfreeze.c
@@ -0,0 +1,54 @@
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
8//config:config FSFREEZE
9//config: bool "fsfreeze"
10//config: default y
11//config: select PLATFORM_LINUX
12//config: select LONG_OPTS
13//config: help
14//config: Halt new accesses and flush writes on a mounted filesystem.
15
16//applet:IF_FSFREEZE(APPLET(fsfreeze, BB_DIR_USR_SBIN, BB_SUID_DROP))
17
18//kbuild:lib-$(CONFIG_FSFREEZE) += fsfreeze.o
19
20//usage:#define fsfreeze_trivial_usage
21//usage: "--[un]freeze MOUNTPOINT"
22//usage:#define fsfreeze_full_usage "\n\n"
23//usage: "Flush and halt writes to MOUNTPOINT"
24
25#include "libbb.h"
26#include <linux/fs.h>
27
28#ifndef FIFREEZE
29# define FIFREEZE _IOWR('X', 119, int)
30# define FITHAW _IOWR('X', 120, int)
31#endif
32
33int fsfreeze_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
34int fsfreeze_main(int argc UNUSED_PARAM, char **argv)
35{
36 unsigned opts;
37 int fd;
38
39 applet_long_options =
40 "freeze\0" No_argument "\xff"
41 "unfreeze\0" No_argument "\xfe"
42 ;
43 /* exactly one non-option arg: the mountpoint */
44 /* one of opts is required */
45 /* opts are mutually exclusive */
46 opt_complementary = "=1:""\xff:\xfe:""\xff--\xfe:\xfe--\xff";
47 opts = getopt32(argv, "");
48
49 fd = xopen(argv[optind], O_RDONLY);
50 /* Works with NULL arg on linux-4.8.0 */
51 xioctl(fd, (opts & 1) ? FIFREEZE : FITHAW, NULL);
52
53 return EXIT_SUCCESS;
54}
diff --git a/util-linux/getopt.c b/util-linux/getopt.c
index 63294c520..79d54854b 100644
--- a/util-linux/getopt.c
+++ b/util-linux/getopt.c
@@ -246,12 +246,7 @@ static int generate_output(char **argv, int argc, const char *optstr, const stru
246 246
247 /* We used it already in main() in getopt32(), 247 /* We used it already in main() in getopt32(),
248 * we *must* reset getopt(3): */ 248 * we *must* reset getopt(3): */
249#ifdef __GLIBC__ 249 GETOPT_RESET();
250 optind = 0;
251#else /* BSD style */
252 optind = 1;
253 /* optreset = 1; */
254#endif
255 250
256 while (1) { 251 while (1) {
257#if ENABLE_FEATURE_GETOPT_LONG 252#if ENABLE_FEATURE_GETOPT_LONG
diff --git a/util-linux/hwclock.c b/util-linux/hwclock.c
index d65011a71..8cb908cb3 100644
--- a/util-linux/hwclock.c
+++ b/util-linux/hwclock.c
@@ -167,7 +167,7 @@ static void from_sys_clock(const char **pp_rtcname, int utc)
167 * On x86, even though code does set hw clock within <1ms of exact 167 * On x86, even though code does set hw clock within <1ms of exact
168 * whole seconds, apparently hw clock (at least on some machines) 168 * whole seconds, apparently hw clock (at least on some machines)
169 * doesn't reset internal fractional seconds to 0, 169 * doesn't reset internal fractional seconds to 0,
170 * making all this a pointless excercise. 170 * making all this a pointless exercise.
171 */ 171 */
172 /* If we see that we are N usec away from whole second, 172 /* If we see that we are N usec away from whole second,
173 * we'll sleep for N-ADJ usecs. ADJ corrects for the fact 173 * we'll sleep for N-ADJ usecs. ADJ corrects for the fact
diff --git a/util-linux/ionice.c b/util-linux/ionice.c
new file mode 100644
index 000000000..c54b3a6e1
--- /dev/null
+++ b/util-linux/ionice.c
@@ -0,0 +1,115 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * ionice implementation for busybox based on linux-utils-ng 2.14
4 *
5 * Copyright (C) 2008 by <u173034@informatik.uni-oldenburg.de>
6 *
7 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
8 */
9//config:config IONICE
10//config: bool "ionice"
11//config: default y
12//config: select PLATFORM_LINUX
13//config: help
14//config: Set/set program io scheduling class and priority
15//config: Requires kernel >= 2.6.13
16
17//applet:IF_IONICE(APPLET(ionice, BB_DIR_BIN, BB_SUID_DROP))
18
19//kbuild:lib-$(CONFIG_IONICE) += ionice.o
20
21//usage:#define ionice_trivial_usage
22//usage: "[-c 1-3] [-n 0-7] [-p PID] [PROG]"
23//usage:#define ionice_full_usage "\n\n"
24//usage: "Change I/O priority and class\n"
25//usage: "\n -c Class. 1:realtime 2:best-effort 3:idle"
26//usage: "\n -n Priority"
27
28#include <sys/syscall.h>
29#include <asm/unistd.h>
30#include "libbb.h"
31
32static int ioprio_set(int which, int who, int ioprio)
33{
34 return syscall(SYS_ioprio_set, which, who, ioprio);
35}
36
37static int ioprio_get(int which, int who)
38{
39 return syscall(SYS_ioprio_get, which, who);
40}
41
42enum {
43 IOPRIO_WHO_PROCESS = 1,
44 IOPRIO_WHO_PGRP,
45 IOPRIO_WHO_USER
46};
47
48enum {
49 IOPRIO_CLASS_NONE,
50 IOPRIO_CLASS_RT,
51 IOPRIO_CLASS_BE,
52 IOPRIO_CLASS_IDLE
53};
54
55static const char to_prio[] ALIGN1 = "none\0realtime\0best-effort\0idle";
56
57#define IOPRIO_CLASS_SHIFT 13
58
59int ionice_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
60int ionice_main(int argc UNUSED_PARAM, char **argv)
61{
62 /* Defaults */
63 int ioclass = 0;
64 int pri = 0;
65 int pid = 0; /* affect own porcess */
66 int opt;
67 enum {
68 OPT_n = 1,
69 OPT_c = 2,
70 OPT_p = 4,
71 };
72
73 /* Numeric params */
74 /* '+': stop at first non-option */
75 opt = getopt32(argv, "+n:+c:+p:+", &pri, &ioclass, &pid);
76 argv += optind;
77
78 if (opt & OPT_c) {
79 if (ioclass > 3)
80 bb_error_msg_and_die("bad class %d", ioclass);
81// Do we need this (compat?)?
82// if (ioclass == IOPRIO_CLASS_NONE)
83// ioclass = IOPRIO_CLASS_BE;
84// if (ioclass == IOPRIO_CLASS_IDLE) {
85// //if (opt & OPT_n)
86// // bb_error_msg("ignoring priority for idle class");
87// pri = 7;
88// }
89 }
90
91 if (!(opt & (OPT_n|OPT_c))) {
92 if (!(opt & OPT_p) && *argv)
93 pid = xatoi_positive(*argv);
94
95 pri = ioprio_get(IOPRIO_WHO_PROCESS, pid);
96 if (pri == -1)
97 bb_perror_msg_and_die("ioprio_%cet", 'g');
98
99 ioclass = (pri >> IOPRIO_CLASS_SHIFT) & 0x3;
100 pri &= 0xff;
101 printf((ioclass == IOPRIO_CLASS_IDLE) ? "%s\n" : "%s: prio %d\n",
102 nth_string(to_prio, ioclass), pri);
103 } else {
104//printf("pri=%d class=%d val=%x\n",
105//pri, ioclass, pri | (ioclass << IOPRIO_CLASS_SHIFT));
106 pri |= (ioclass << IOPRIO_CLASS_SHIFT);
107 if (ioprio_set(IOPRIO_WHO_PROCESS, pid, pri) == -1)
108 bb_perror_msg_and_die("ioprio_%cet", 's');
109 if (argv[0]) {
110 BB_EXECVP_or_die(argv);
111 }
112 }
113
114 return EXIT_SUCCESS;
115}
diff --git a/util-linux/last.c b/util-linux/last.c
new file mode 100644
index 000000000..b3f125c3f
--- /dev/null
+++ b/util-linux/last.c
@@ -0,0 +1,166 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * last implementation for busybox
4 *
5 * Copyright (C) 2003-2004 by Erik Andersen <andersen@codepoet.org>
6 *
7 * Licensed under GPLv2, see file LICENSE in this source tree.
8 */
9//config:config LAST
10//config: bool "last"
11//config: default y
12//config: depends on FEATURE_WTMP
13//config: help
14//config: 'last' displays a list of the last users that logged into the system.
15//config:
16//config:config FEATURE_LAST_FANCY
17//config: bool "Output extra information"
18//config: default y
19//config: depends on LAST
20//config: help
21//config: 'last' displays detailed information about the last users that
22//config: logged into the system (mimics sysvinit last). +900 bytes.
23
24//applet:IF_LAST(APPLET(last, BB_DIR_USR_BIN, BB_SUID_DROP))
25
26//kbuild:ifeq ($(CONFIG_FEATURE_LAST_FANCY),y)
27//kbuild:lib-$(CONFIG_FEATURE_LAST_FANCY) += last_fancy.o
28//kbuild:else
29//kbuild:lib-$(CONFIG_LAST) += last.o
30//kbuild:endif
31
32//usage:#define last_trivial_usage
33//usage: ""IF_FEATURE_LAST_FANCY("[-HW] [-f FILE]")
34//usage:#define last_full_usage "\n\n"
35//usage: "Show listing of the last users that logged into the system"
36//usage: IF_FEATURE_LAST_FANCY( "\n"
37/* //usage: "\n -H Show header line" */
38//usage: "\n -W Display with no host column truncation"
39//usage: "\n -f FILE Read from FILE instead of /var/log/wtmp"
40//usage: )
41
42#include "libbb.h"
43
44/* NB: ut_name and ut_user are the same field, use only one name (ut_user)
45 * to reduce confusion */
46
47#ifndef SHUTDOWN_TIME
48# define SHUTDOWN_TIME 254
49#endif
50
51/* Grr... utmp char[] members do not have to be nul-terminated.
52 * Do what we can while still keeping this reasonably small.
53 * Note: We are assuming the ut_id[] size is fixed at 4. */
54
55#if defined UT_LINESIZE \
56 && ((UT_LINESIZE != 32) || (UT_NAMESIZE != 32) || (UT_HOSTSIZE != 256))
57#error struct utmpx member char[] size(s) have changed!
58#elif defined __UT_LINESIZE \
59 && ((__UT_LINESIZE != 32) || (__UT_NAMESIZE != 32) || (__UT_HOSTSIZE != 256))
60/* __UT_NAMESIZE was checked with 64 above, but glibc-2.11 definitely uses 32! */
61#error struct utmpx member char[] size(s) have changed!
62#endif
63
64#if EMPTY != 0 || RUN_LVL != 1 || BOOT_TIME != 2 || NEW_TIME != 3 || \
65 OLD_TIME != 4
66#error Values for the ut_type field of struct utmpx changed
67#endif
68
69int last_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
70int last_main(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
71{
72 struct utmpx ut;
73 int n, file = STDIN_FILENO;
74 time_t t_tmp;
75 off_t pos;
76 static const char _ut_usr[] ALIGN1 =
77 "runlevel\0" "reboot\0" "shutdown\0";
78 static const char _ut_lin[] ALIGN1 =
79 "~\0" "{\0" "|\0" /* "LOGIN\0" "date\0" */;
80 enum {
81 TYPE_RUN_LVL = RUN_LVL, /* 1 */
82 TYPE_BOOT_TIME = BOOT_TIME, /* 2 */
83 TYPE_SHUTDOWN_TIME = SHUTDOWN_TIME
84 };
85 enum {
86 _TILDE = EMPTY, /* 0 */
87 TYPE_NEW_TIME, /* NEW_TIME, 3 */
88 TYPE_OLD_TIME /* OLD_TIME, 4 */
89 };
90
91 if (argv[1]) {
92 bb_show_usage();
93 }
94 file = xopen(bb_path_wtmp_file, O_RDONLY);
95
96 printf("%-10s %-14s %-18s %-12.12s %s\n",
97 "USER", "TTY", "HOST", "LOGIN", "TIME");
98 /* yikes. We reverse over the file and that is a not too elegant way */
99 pos = xlseek(file, 0, SEEK_END);
100 pos = lseek(file, pos - sizeof(ut), SEEK_SET);
101 while ((n = full_read(file, &ut, sizeof(ut))) > 0) {
102 if (n != sizeof(ut)) {
103 bb_perror_msg_and_die("short read");
104 }
105 n = index_in_strings(_ut_lin, ut.ut_line);
106 if (n == _TILDE) { /* '~' */
107#if 1
108/* do we really need to be cautious here? */
109 n = index_in_strings(_ut_usr, ut.ut_user);
110 if (++n > 0)
111 ut.ut_type = n != 3 ? n : SHUTDOWN_TIME;
112#else
113 if (is_prefixed_with(ut.ut_user, "shutdown"))
114 ut.ut_type = SHUTDOWN_TIME;
115 else if (is_prefixed_with(ut.ut_user, "reboot"))
116 ut.ut_type = BOOT_TIME;
117 else if (is_prefixed_with(ut.ut_user, "runlevel"))
118 ut.ut_type = RUN_LVL;
119#endif
120 } else {
121 if (ut.ut_user[0] == '\0' || strcmp(ut.ut_user, "LOGIN") == 0) {
122 /* Don't bother. This means we can't find how long
123 * someone was logged in for. Oh well. */
124 goto next;
125 }
126 if (ut.ut_type != DEAD_PROCESS
127 && ut.ut_user[0]
128 && ut.ut_line[0]
129 ) {
130 ut.ut_type = USER_PROCESS;
131 }
132 if (strcmp(ut.ut_user, "date") == 0) {
133 if (n == TYPE_OLD_TIME) { /* '|' */
134 ut.ut_type = OLD_TIME;
135 }
136 if (n == TYPE_NEW_TIME) { /* '{' */
137 ut.ut_type = NEW_TIME;
138 }
139 }
140 }
141
142 if (ut.ut_type != USER_PROCESS) {
143 switch (ut.ut_type) {
144 case OLD_TIME:
145 case NEW_TIME:
146 case RUN_LVL:
147 case SHUTDOWN_TIME:
148 goto next;
149 case BOOT_TIME:
150 strcpy(ut.ut_line, "system boot");
151 }
152 }
153 /* manpages say ut_tv.tv_sec *is* time_t,
154 * but some systems have it wrong */
155 t_tmp = (time_t)ut.ut_tv.tv_sec;
156 printf("%-10s %-14s %-18s %-12.12s\n",
157 ut.ut_user, ut.ut_line, ut.ut_host, ctime(&t_tmp) + 4);
158 next:
159 pos -= sizeof(ut);
160 if (pos <= 0)
161 break; /* done. */
162 xlseek(file, pos, SEEK_SET);
163 }
164
165 fflush_stdout_and_exit(EXIT_SUCCESS);
166}
diff --git a/util-linux/last_fancy.c b/util-linux/last_fancy.c
new file mode 100644
index 000000000..e56e0ba85
--- /dev/null
+++ b/util-linux/last_fancy.c
@@ -0,0 +1,300 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * (sysvinit like) last implementation
4 *
5 * Copyright (C) 2008 by Patricia Muscalu <patricia.muscalu@axis.com>
6 *
7 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
8 */
9
10#include "libbb.h"
11
12/* NB: ut_name and ut_user are the same field, use only one name (ut_user)
13 * to reduce confusion */
14
15#ifndef SHUTDOWN_TIME
16# define SHUTDOWN_TIME 254
17#endif
18
19#define HEADER_FORMAT "%-8.8s %-12.12s %-*.*s %-16.16s %-7.7s %s\n"
20#define HEADER_LINE "USER", "TTY", \
21 INET_ADDRSTRLEN, INET_ADDRSTRLEN, "HOST", "LOGIN", " TIME", ""
22#define HEADER_LINE_WIDE "USER", "TTY", \
23 INET6_ADDRSTRLEN, INET6_ADDRSTRLEN, "HOST", "LOGIN", " TIME", ""
24
25#if !defined __UT_LINESIZE && defined UT_LINESIZE
26# define __UT_LINESIZE UT_LINESIZE
27#endif
28
29enum {
30 NORMAL,
31 LOGGED,
32 DOWN,
33 REBOOT,
34 CRASH,
35 GONE
36};
37
38enum {
39 LAST_OPT_W = (1 << 0), /* -W wide */
40 LAST_OPT_f = (1 << 1), /* -f input file */
41 LAST_OPT_H = (1 << 2), /* -H header */
42};
43
44#define show_wide (option_mask32 & LAST_OPT_W)
45
46static void show_entry(struct utmpx *ut, int state, time_t dur_secs)
47{
48 unsigned days, hours, mins;
49 char duration[sizeof("(%u+02:02)") + sizeof(int)*3];
50 char login_time[17];
51 char logout_time[8];
52 const char *logout_str;
53 const char *duration_str;
54 time_t tmp;
55
56 /* manpages say ut_tv.tv_sec *is* time_t,
57 * but some systems have it wrong */
58 tmp = ut->ut_tv.tv_sec;
59 safe_strncpy(login_time, ctime(&tmp), 17);
60 tmp = dur_secs;
61 snprintf(logout_time, 8, "- %s", ctime(&tmp) + 11);
62
63 dur_secs = MAX(dur_secs - (time_t)ut->ut_tv.tv_sec, (time_t)0);
64 /* unsigned int is easier to divide than time_t (which may be signed long) */
65 mins = dur_secs / 60;
66 days = mins / (24*60);
67 mins = mins % (24*60);
68 hours = mins / 60;
69 mins = mins % 60;
70
71// if (days) {
72 sprintf(duration, "(%u+%02u:%02u)", days, hours, mins);
73// } else {
74// sprintf(duration, " (%02u:%02u)", hours, mins);
75// }
76
77 logout_str = logout_time;
78 duration_str = duration;
79 switch (state) {
80 case NORMAL:
81 break;
82 case LOGGED:
83 logout_str = " still";
84 duration_str = "logged in";
85 break;
86 case DOWN:
87 logout_str = "- down ";
88 break;
89 case REBOOT:
90 break;
91 case CRASH:
92 logout_str = "- crash";
93 break;
94 case GONE:
95 logout_str = " gone";
96 duration_str = "- no logout";
97 break;
98 }
99
100 printf(HEADER_FORMAT,
101 ut->ut_user,
102 ut->ut_line,
103 show_wide ? INET6_ADDRSTRLEN : INET_ADDRSTRLEN,
104 show_wide ? INET6_ADDRSTRLEN : INET_ADDRSTRLEN,
105 ut->ut_host,
106 login_time,
107 logout_str,
108 duration_str);
109}
110
111static int get_ut_type(struct utmpx *ut)
112{
113 if (ut->ut_line[0] == '~') {
114 if (strcmp(ut->ut_user, "shutdown") == 0) {
115 return SHUTDOWN_TIME;
116 }
117 if (strcmp(ut->ut_user, "reboot") == 0) {
118 return BOOT_TIME;
119 }
120 if (strcmp(ut->ut_user, "runlevel") == 0) {
121 return RUN_LVL;
122 }
123 return ut->ut_type;
124 }
125
126 if (ut->ut_user[0] == 0) {
127 return DEAD_PROCESS;
128 }
129
130 if ((ut->ut_type != DEAD_PROCESS)
131 && (strcmp(ut->ut_user, "LOGIN") != 0)
132 && ut->ut_user[0]
133 && ut->ut_line[0]
134 ) {
135 ut->ut_type = USER_PROCESS;
136 }
137
138 if (strcmp(ut->ut_user, "date") == 0) {
139 if (ut->ut_line[0] == '|') {
140 return OLD_TIME;
141 }
142 if (ut->ut_line[0] == '{') {
143 return NEW_TIME;
144 }
145 }
146 return ut->ut_type;
147}
148
149static int is_runlevel_shutdown(struct utmpx *ut)
150{
151 if (((ut->ut_pid & 255) == '0') || ((ut->ut_pid & 255) == '6')) {
152 return 1;
153 }
154
155 return 0;
156}
157
158int last_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
159int last_main(int argc UNUSED_PARAM, char **argv)
160{
161 struct utmpx ut;
162 const char *filename = _PATH_WTMP;
163 llist_t *zlist;
164 off_t pos;
165 time_t start_time;
166 time_t boot_time;
167 time_t down_time;
168 int file;
169 smallint going_down;
170 smallint boot_down;
171
172 /*opt =*/ getopt32(argv, "Wf:" /* "H" */, &filename);
173#ifdef BUT_UTIL_LINUX_LAST_HAS_NO_SUCH_OPT
174 if (opt & LAST_OPT_H) {
175 /* Print header line */
176 if (opt & LAST_OPT_W) {
177 printf(HEADER_FORMAT, HEADER_LINE_WIDE);
178 } else {
179 printf(HEADER_FORMAT, HEADER_LINE);
180 }
181 }
182#endif
183
184 file = xopen(filename, O_RDONLY);
185 {
186 /* in case the file is empty... */
187 struct stat st;
188 fstat(file, &st);
189 start_time = st.st_ctime;
190 }
191
192 time(&down_time);
193 going_down = 0;
194 boot_down = NORMAL; /* 0 */
195 zlist = NULL;
196 boot_time = 0;
197 /* get file size, rounding down to last full record */
198 pos = xlseek(file, 0, SEEK_END) / sizeof(ut) * sizeof(ut);
199 for (;;) {
200 pos -= (off_t)sizeof(ut);
201 if (pos < 0) {
202 /* Beyond the beginning of the file boundary =>
203 * the whole file has been read. */
204 break;
205 }
206 xlseek(file, pos, SEEK_SET);
207 xread(file, &ut, sizeof(ut));
208 /* rewritten by each record, eventially will have
209 * first record's ut_tv.tv_sec: */
210 start_time = ut.ut_tv.tv_sec;
211
212 switch (get_ut_type(&ut)) {
213 case SHUTDOWN_TIME:
214 down_time = ut.ut_tv.tv_sec;
215 boot_down = DOWN;
216 going_down = 1;
217 break;
218 case RUN_LVL:
219 if (is_runlevel_shutdown(&ut)) {
220 down_time = ut.ut_tv.tv_sec;
221 going_down = 1;
222 boot_down = DOWN;
223 }
224 break;
225 case BOOT_TIME:
226 strcpy(ut.ut_line, "system boot");
227 show_entry(&ut, REBOOT, down_time);
228 boot_down = CRASH;
229 going_down = 1;
230 break;
231 case DEAD_PROCESS:
232 if (!ut.ut_line[0]) {
233 break;
234 }
235 /* add_entry */
236 llist_add_to(&zlist, xmemdup(&ut, sizeof(ut)));
237 break;
238 case USER_PROCESS: {
239 int show;
240
241 if (!ut.ut_line[0]) {
242 break;
243 }
244 /* find_entry */
245 show = 1;
246 {
247 llist_t *el, *next;
248 for (el = zlist; el; el = next) {
249 struct utmpx *up = (struct utmpx *)el->data;
250 next = el->link;
251 if (strncmp(up->ut_line, ut.ut_line, __UT_LINESIZE) == 0) {
252 if (show) {
253 show_entry(&ut, NORMAL, up->ut_tv.tv_sec);
254 show = 0;
255 }
256 llist_unlink(&zlist, el);
257 free(el->data);
258 free(el);
259 }
260 }
261 }
262
263 if (show) {
264 int state = boot_down;
265
266 if (boot_time == 0) {
267 state = LOGGED;
268 /* Check if the process is alive */
269 if ((ut.ut_pid > 0)
270 && (kill(ut.ut_pid, 0) != 0)
271 && (errno == ESRCH)) {
272 state = GONE;
273 }
274 }
275 show_entry(&ut, state, boot_time);
276 }
277 /* add_entry */
278 llist_add_to(&zlist, xmemdup(&ut, sizeof(ut)));
279 break;
280 }
281 }
282
283 if (going_down) {
284 boot_time = ut.ut_tv.tv_sec;
285 llist_free(zlist, free);
286 zlist = NULL;
287 going_down = 0;
288 }
289 }
290
291 if (ENABLE_FEATURE_CLEAN_UP) {
292 llist_free(zlist, free);
293 }
294
295 printf("\nwtmp begins %s", ctime(&start_time));
296
297 if (ENABLE_FEATURE_CLEAN_UP)
298 close(file);
299 fflush_stdout_and_exit(EXIT_SUCCESS);
300}
diff --git a/util-linux/losetup.c b/util-linux/losetup.c
index 4424d9cbb..d356f49c2 100644
--- a/util-linux/losetup.c
+++ b/util-linux/losetup.c
@@ -127,12 +127,37 @@ int losetup_main(int argc UNUSED_PARAM, char **argv)
127 d = *argv++; 127 d = *argv++;
128 128
129 if (argv[0]) { 129 if (argv[0]) {
130 if (set_loop(&d, argv[0], offset, (opt & OPT_r)) < 0) 130 if (set_loop(&d, argv[0], offset, (opt & OPT_r) ? BB_LO_FLAGS_READ_ONLY : 0) < 0)
131 bb_simple_perror_msg_and_die(argv[0]); 131 bb_simple_perror_msg_and_die(argv[0]);
132 return EXIT_SUCCESS; 132 return EXIT_SUCCESS;
133 } 133 }
134 } 134 }
135 135
136 /* TODO: util-linux 2.28 shows this when run w/o params:
137 * NAME SIZELIMIT OFFSET AUTOCLEAR RO BACK-FILE DIO
138 * /dev/loop0 0 0 1 0 /PATH/TO/FILE 0
139 *
140 * implemented by reading /sys:
141 *
142 * open("/sys/block", O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC) = 3
143 * newfstatat(3, "loop0/loop/backing_file", {st_mode=S_IFREG|0444, st_size=4096, ...}, 0) = 0
144 * stat("/dev/loop0", {st_mode=S_IFBLK|0660, st_rdev=makedev(7, 0), ...}) = 0
145 * open("/sys/dev/block/7:0/loop/offset", O_RDONLY|O_CLOEXEC) = 5
146 * read(5, "0\n", 4096) = 2
147 * open("/sys/dev/block/7:0/loop/sizelimit", O_RDONLY|O_CLOEXEC) = 5
148 * read(5, "0\n", 4096) = 2
149 * open("/sys/dev/block/7:0/loop/offset", O_RDONLY|O_CLOEXEC) = 5
150 * read(5, "0\n", 4096) = 2
151 * open("/sys/dev/block/7:0/loop/autoclear", O_RDONLY|O_CLOEXEC) = 5
152 * read(5, "1\n", 4096) = 2
153 * open("/sys/dev/block/7:0/ro", O_RDONLY|O_CLOEXEC) = 5
154 * read(5, "0\n", 4096) = 2
155 * open("/sys/dev/block/7:0/loop/backing_file", O_RDONLY|O_CLOEXEC) = 5
156 * read(5, "/PATH/TO/FILE", 4096) = 37
157 * open("/sys/dev/block/7:0/loop/dio", O_RDONLY|O_CLOEXEC) = 5
158 * read(5, "0\n", 4096) = 2
159 */
160
136 bb_show_usage(); /* does not return */ 161 bb_show_usage(); /* does not return */
137 /*return EXIT_FAILURE;*/ 162 /*return EXIT_FAILURE;*/
138} 163}
diff --git a/util-linux/mesg.c b/util-linux/mesg.c
new file mode 100644
index 000000000..45c13b8e0
--- /dev/null
+++ b/util-linux/mesg.c
@@ -0,0 +1,76 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * mesg implementation for busybox
4 *
5 * Copyright (c) 2002 Manuel Novoa III <mjn3@codepoet.org>
6 *
7 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
8 */
9
10//config:config MESG
11//config: bool "mesg"
12//config: default y
13//config: help
14//config: Mesg controls access to your terminal by others. It is typically
15//config: used to allow or disallow other users to write to your terminal
16//config:
17//config:config FEATURE_MESG_ENABLE_ONLY_GROUP
18//config: bool "Enable writing to tty only by group, not by everybody"
19//config: default y
20//config: depends on MESG
21//config: help
22//config: Usually, ttys are owned by group "tty", and "write" tool is
23//config: setgid to this group. This way, "mesg y" only needs to enable
24//config: "write by owning group" bit in tty mode.
25//config:
26//config: If you set this option to N, "mesg y" will enable writing
27//config: by anybody at all. This is not recommended.
28
29//applet:IF_MESG(APPLET(mesg, BB_DIR_USR_BIN, BB_SUID_DROP))
30
31//kbuild:lib-$(CONFIG_MESG) += mesg.o
32
33//usage:#define mesg_trivial_usage
34//usage: "[y|n]"
35//usage:#define mesg_full_usage "\n\n"
36//usage: "Control write access to your terminal\n"
37//usage: " y Allow write access to your terminal\n"
38//usage: " n Disallow write access to your terminal"
39
40#include "libbb.h"
41
42#if ENABLE_FEATURE_MESG_ENABLE_ONLY_GROUP
43#define S_IWGRP_OR_S_IWOTH S_IWGRP
44#else
45#define S_IWGRP_OR_S_IWOTH (S_IWGRP | S_IWOTH)
46#endif
47
48int mesg_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
49int mesg_main(int argc UNUSED_PARAM, char **argv)
50{
51 struct stat sb;
52 mode_t m;
53 char c = 0;
54
55 argv++;
56
57 if (argv[0]
58 && (argv[1] || ((c = argv[0][0]) != 'y' && c != 'n'))
59 ) {
60 bb_show_usage();
61 }
62
63 if (!isatty(STDIN_FILENO))
64 bb_error_msg_and_die("not a tty");
65
66 xfstat(STDIN_FILENO, &sb, "stderr");
67 if (c == 0) {
68 puts((sb.st_mode & (S_IWGRP|S_IWOTH)) ? "is y" : "is n");
69 return EXIT_SUCCESS;
70 }
71 m = (c == 'y') ? sb.st_mode | S_IWGRP_OR_S_IWOTH
72 : sb.st_mode & ~(S_IWGRP|S_IWOTH);
73 if (fchmod(STDIN_FILENO, m) != 0)
74 bb_perror_nomsg_and_die();
75 return EXIT_SUCCESS;
76}
diff --git a/util-linux/mount.c b/util-linux/mount.c
index f0245f714..6bb18524d 100644
--- a/util-linux/mount.c
+++ b/util-linux/mount.c
@@ -1887,6 +1887,7 @@ static int nfsmount(struct mntent *mp, unsigned long vfsflags, char *filteropts)
1887// NB: mp->xxx fields may be trashed on exit 1887// NB: mp->xxx fields may be trashed on exit
1888static int singlemount(struct mntent *mp, int ignore_busy) 1888static int singlemount(struct mntent *mp, int ignore_busy)
1889{ 1889{
1890 int loopfd = -1;
1890 int rc = -1; 1891 int rc = -1;
1891 unsigned long vfsflags; 1892 unsigned long vfsflags;
1892 char *loopFile = NULL, *filteropts = NULL; 1893 char *loopFile = NULL, *filteropts = NULL;
@@ -2026,7 +2027,20 @@ static int singlemount(struct mntent *mp, int ignore_busy)
2026 if (ENABLE_FEATURE_MOUNT_LOOP && S_ISREG(st.st_mode)) { 2027 if (ENABLE_FEATURE_MOUNT_LOOP && S_ISREG(st.st_mode)) {
2027 loopFile = bb_simplify_path(mp->mnt_fsname); 2028 loopFile = bb_simplify_path(mp->mnt_fsname);
2028 mp->mnt_fsname = NULL; // will receive malloced loop dev name 2029 mp->mnt_fsname = NULL; // will receive malloced loop dev name
2029 if (set_loop(&mp->mnt_fsname, loopFile, 0, /*ro:*/ (vfsflags & MS_RDONLY)) < 0) { 2030
2031 // mount always creates AUTOCLEARed loopdevs, so that umounting
2032 // drops them without any code in the userspace.
2033 // This happens since circa linux-2.6.25:
2034 // commit 96c5865559cee0f9cbc5173f3c949f6ce3525581
2035 // Date: Wed Feb 6 01:36:27 2008 -0800
2036 // Subject: Allow auto-destruction of loop devices
2037 loopfd = set_loop(&mp->mnt_fsname,
2038 loopFile,
2039 0,
2040 ((vfsflags & MS_RDONLY) ? BB_LO_FLAGS_READ_ONLY : 0)
2041 | BB_LO_FLAGS_AUTOCLEAR
2042 );
2043 if (loopfd < 0) {
2030 if (errno == EPERM || errno == EACCES) 2044 if (errno == EPERM || errno == EACCES)
2031 bb_error_msg(bb_msg_perm_denied_are_you_root); 2045 bb_error_msg(bb_msg_perm_denied_are_you_root);
2032 else 2046 else
@@ -2074,6 +2088,8 @@ static int singlemount(struct mntent *mp, int ignore_busy)
2074 } 2088 }
2075 2089
2076 // If mount failed, clean up loop file (if any). 2090 // If mount failed, clean up loop file (if any).
2091 // (Newer kernels which support LO_FLAGS_AUTOCLEAR should not need this,
2092 // merely "close(loopfd)" should do it?)
2077 if (ENABLE_FEATURE_MOUNT_LOOP && rc && loopFile) { 2093 if (ENABLE_FEATURE_MOUNT_LOOP && rc && loopFile) {
2078 del_loop(mp->mnt_fsname); 2094 del_loop(mp->mnt_fsname);
2079 if (ENABLE_FEATURE_CLEAN_UP) { 2095 if (ENABLE_FEATURE_CLEAN_UP) {
@@ -2086,6 +2102,9 @@ static int singlemount(struct mntent *mp, int ignore_busy)
2086 if (ENABLE_FEATURE_CLEAN_UP) 2102 if (ENABLE_FEATURE_CLEAN_UP)
2087 free(filteropts); 2103 free(filteropts);
2088 2104
2105 if (loopfd >= 0)
2106 close(loopfd);
2107
2089 if (errno == EBUSY && ignore_busy) 2108 if (errno == EBUSY && ignore_busy)
2090 return 0; 2109 return 0;
2091 if (errno == ENOENT && (vfsflags & MOUNT_NOFAIL)) 2110 if (errno == ENOENT && (vfsflags & MOUNT_NOFAIL))
diff --git a/util-linux/mountpoint.c b/util-linux/mountpoint.c
new file mode 100644
index 000000000..8b9e1d779
--- /dev/null
+++ b/util-linux/mountpoint.c
@@ -0,0 +1,105 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * mountpoint implementation for busybox
4 *
5 * Copyright (C) 2005 Bernhard Reutner-Fischer
6 *
7 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
8 *
9 * Based on sysvinit's mountpoint
10 */
11//config:config MOUNTPOINT
12//config: bool "mountpoint"
13//config: default y
14//config: help
15//config: mountpoint checks if the directory is a mountpoint.
16
17//applet:IF_MOUNTPOINT(APPLET(mountpoint, BB_DIR_BIN, BB_SUID_DROP))
18
19//kbuild:lib-$(CONFIG_MOUNTPOINT) += mountpoint.o
20
21//usage:#define mountpoint_trivial_usage
22//usage: "[-q] <[-dn] DIR | -x DEVICE>"
23//usage:#define mountpoint_full_usage "\n\n"
24//usage: "Check if the directory is a mountpoint\n"
25//usage: "\n -q Quiet"
26//usage: "\n -d Print major/minor device number of the filesystem"
27//usage: "\n -n Print device name of the filesystem"
28//usage: "\n -x Print major/minor device number of the blockdevice"
29//usage:
30//usage:#define mountpoint_example_usage
31//usage: "$ mountpoint /proc\n"
32//usage: "/proc is not a mountpoint\n"
33//usage: "$ mountpoint /sys\n"
34//usage: "/sys is a mountpoint\n"
35
36#include "libbb.h"
37
38int mountpoint_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
39int mountpoint_main(int argc UNUSED_PARAM, char **argv)
40{
41 struct stat st;
42 const char *msg;
43 char *arg;
44 int rc, opt;
45
46 opt_complementary = "=1"; /* must have one argument */
47 opt = getopt32(argv, "qdxn");
48#define OPT_q (1)
49#define OPT_d (2)
50#define OPT_x (4)
51#define OPT_n (8)
52 arg = argv[optind];
53 msg = "%s";
54
55 rc = (opt & OPT_x) ? stat(arg, &st) : lstat(arg, &st);
56 if (rc != 0)
57 goto err;
58
59 if (opt & OPT_x) {
60 if (S_ISBLK(st.st_mode)) {
61 printf("%u:%u\n", major(st.st_rdev),
62 minor(st.st_rdev));
63 return EXIT_SUCCESS;
64 }
65 errno = 0; /* make perror_msg work as error_msg */
66 msg = "%s: not a block device";
67 goto err;
68 }
69
70 errno = ENOTDIR;
71 if (S_ISDIR(st.st_mode)) {
72 dev_t st_dev = st.st_dev;
73 ino_t st_ino = st.st_ino;
74 char *p = xasprintf("%s/..", arg);
75
76 if (stat(p, &st) == 0) {
77 //int is_mnt = (st_dev != st.st_dev) || (st_dev == st.st_dev && st_ino == st.st_ino);
78 int is_not_mnt = (st_dev == st.st_dev) && (st_ino != st.st_ino);
79
80 if (opt & OPT_d)
81 printf("%u:%u\n", major(st_dev), minor(st_dev));
82 if (opt & OPT_n) {
83 const char *d = find_block_device(arg);
84 /* name is undefined, but device is mounted -> anonymous superblock! */
85 /* happens with btrfs */
86 if (!d) {
87 d = "UNKNOWN";
88 /* TODO: iterate /proc/mounts, or /proc/self/mountinfo
89 * to find out the device name */
90 }
91 printf("%s %s\n", d, arg);
92 }
93 if (!(opt & (OPT_q | OPT_d | OPT_n)))
94 printf("%s is %sa mountpoint\n", arg, is_not_mnt ? "not " : "");
95 return is_not_mnt;
96 }
97 arg = p;
98 /* else: stat had set errno, just fall through */
99 }
100
101 err:
102 if (!(opt & OPT_q))
103 bb_perror_msg(msg, arg);
104 return EXIT_FAILURE;
105}
diff --git a/util-linux/renice.c b/util-linux/renice.c
new file mode 100644
index 000000000..4da3394a8
--- /dev/null
+++ b/util-linux/renice.c
@@ -0,0 +1,148 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * renice implementation for busybox
4 *
5 * Copyright (C) 2005 Manuel Novoa III <mjn3@codepoet.org>
6 *
7 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
8 */
9
10/* Notes:
11 * Setting an absolute priority was obsoleted in SUSv2 and removed
12 * in SUSv3. However, the common linux version of renice does
13 * absolute and not relative. So we'll continue supporting absolute,
14 * although the stdout logging has been removed since both SUSv2 and
15 * SUSv3 specify that stdout isn't used.
16 *
17 * This version is lenient in that it doesn't require any IDs. The
18 * options -p, -g, and -u are treated as mode switches for the
19 * following IDs (if any). Multiple switches are allowed.
20 */
21//config:config RENICE
22//config: bool "renice"
23//config: default y
24//config: help
25//config: Renice alters the scheduling priority of one or more running
26//config: processes.
27
28//applet:IF_RENICE(APPLET(renice, BB_DIR_USR_BIN, BB_SUID_DROP))
29
30//kbuild:lib-$(CONFIG_RENICE) += renice.o
31
32//usage:#define renice_trivial_usage
33//usage: "[-n] PRIORITY [[-p | -g | -u] ID...]..."
34//usage:#define renice_full_usage "\n\n"
35//usage: "Change scheduling priority of a running process\n"
36//usage: "\n -n Add PRIORITY to current nice value"
37//usage: "\n Without -n, nice value is set to PRIORITY"
38//usage: "\n -p Process ids (default)"
39//usage: "\n -g Process group ids"
40//usage: "\n -u Process user names"
41
42#include "libbb.h"
43#include <sys/resource.h>
44
45void BUG_bad_PRIO_PROCESS(void);
46void BUG_bad_PRIO_PGRP(void);
47void BUG_bad_PRIO_USER(void);
48
49int renice_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
50int renice_main(int argc UNUSED_PARAM, char **argv)
51{
52 static const char Xetpriority_msg[] ALIGN1 = "%cetpriority";
53
54 int retval = EXIT_SUCCESS;
55 int which = PRIO_PROCESS; /* Default 'which' value. */
56 int use_relative = 0;
57 int adjustment, new_priority;
58 unsigned who;
59 char *arg;
60
61 /* Yes, they are not #defines in glibc 2.4! #if won't work */
62 if (PRIO_PROCESS < CHAR_MIN || PRIO_PROCESS > CHAR_MAX)
63 BUG_bad_PRIO_PROCESS();
64 if (PRIO_PGRP < CHAR_MIN || PRIO_PGRP > CHAR_MAX)
65 BUG_bad_PRIO_PGRP();
66 if (PRIO_USER < CHAR_MIN || PRIO_USER > CHAR_MAX)
67 BUG_bad_PRIO_USER();
68
69 arg = *++argv;
70
71 /* Check if we are using a relative adjustment. */
72 if (arg && arg[0] == '-' && arg[1] == 'n') {
73 use_relative = 1;
74 if (!arg[2])
75 arg = *++argv;
76 else
77 arg += 2;
78 }
79
80 if (!arg) { /* No args? Then show usage. */
81 bb_show_usage();
82 }
83
84 /* Get the priority adjustment (absolute or relative). */
85 adjustment = xatoi_range(arg, INT_MIN/2, INT_MAX/2);
86
87 while ((arg = *++argv) != NULL) {
88 /* Check for a mode switch. */
89 if (arg[0] == '-' && arg[1]) {
90 static const char opts[] ALIGN1 = {
91 'p', 'g', 'u', 0, PRIO_PROCESS, PRIO_PGRP, PRIO_USER
92 };
93 const char *p = strchr(opts, arg[1]);
94 if (p) {
95 which = p[4];
96 if (!arg[2])
97 continue;
98 arg += 2;
99 }
100 }
101
102 /* Process an ID arg. */
103 if (which == PRIO_USER) {
104 struct passwd *p;
105 p = getpwnam(arg);
106 if (!p) {
107 bb_error_msg("unknown user %s", arg);
108 goto HAD_ERROR;
109 }
110 who = p->pw_uid;
111 } else {
112 who = bb_strtou(arg, NULL, 10);
113 if (errno) {
114 bb_error_msg("invalid number '%s'", arg);
115 goto HAD_ERROR;
116 }
117 }
118
119 /* Get priority to use, and set it. */
120 if (use_relative) {
121 int old_priority;
122
123 errno = 0; /* Needed for getpriority error detection. */
124 old_priority = getpriority(which, who);
125 if (errno) {
126 bb_perror_msg(Xetpriority_msg, 'g');
127 goto HAD_ERROR;
128 }
129
130 new_priority = old_priority + adjustment;
131 } else {
132 new_priority = adjustment;
133 }
134
135 if (setpriority(which, who, new_priority) == 0) {
136 continue;
137 }
138
139 bb_perror_msg(Xetpriority_msg, 's');
140 HAD_ERROR:
141 retval = EXIT_FAILURE;
142 }
143
144 /* No need to check for errors outputting to stderr since, if it
145 * was used, the HAD_ERROR label was reached and retval was set. */
146
147 return retval;
148}
diff --git a/util-linux/setsid.c b/util-linux/setsid.c
new file mode 100644
index 000000000..143a8f8fa
--- /dev/null
+++ b/util-linux/setsid.c
@@ -0,0 +1,82 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * setsid.c -- execute a command in a new session
4 * Rick Sladkey <jrs@world.std.com>
5 * In the public domain.
6 *
7 * 1999-02-22 Arkadiusz Mickiewicz <misiek@pld.ORG.PL>
8 * - added Native Language Support
9 *
10 * 2001-01-18 John Fremlin <vii@penguinpowered.com>
11 * - fork in case we are process group leader
12 *
13 * 2004-11-12 Paul Fox
14 * - busyboxed
15 */
16//config:config SETSID
17//config: bool "setsid"
18//config: default y
19//config: help
20//config: setsid runs a program in a new session
21
22//applet:IF_SETSID(APPLET(setsid, BB_DIR_USR_BIN, BB_SUID_DROP))
23
24//kbuild:lib-$(CONFIG_SETSID) += setsid.o
25
26//usage:#define setsid_trivial_usage
27//usage: "[-c] PROG ARGS"
28//usage:#define setsid_full_usage "\n\n"
29//usage: "Run PROG in a new session. PROG will have no controlling terminal\n"
30//usage: "and will not be affected by keyboard signals (^C etc).\n"
31//usage: "\n -c Set controlling terminal to stdin"
32
33#include "libbb.h"
34
35int setsid_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
36int setsid_main(int argc UNUSED_PARAM, char **argv)
37{
38 unsigned opt;
39
40 opt_complementary = "-1"; /* at least one arg */
41 opt = getopt32(argv, "+c"); /* +: stop on first non-opt */
42 argv += optind;
43
44 /* setsid() is allowed only when we are not a process group leader.
45 * Otherwise our PID serves as PGID of some existing process group
46 * and cannot be used as PGID of a new process group.
47 *
48 * Example: setsid() below fails when run alone in interactive shell:
49 * $ setsid PROG
50 * because shell's child (setsid) is put in a new process group.
51 * But doesn't fail if shell is not interactive
52 * (and therefore doesn't create process groups for pipes),
53 * or if setsid is not the first process in the process group:
54 * $ true | setsid PROG
55 * or if setsid is executed in backquotes (`setsid PROG`)...
56 */
57 if (setsid() < 0) {
58 pid_t pid = fork_or_rexec(argv);
59 if (pid != 0) {
60 /* parent */
61 /* TODO:
62 * we can waitpid(pid, &status, 0) and then even
63 * emulate exitcode, making the behavior consistent
64 * in both forked and non forked cases.
65 * However, the code is larger and upstream
66 * does not do such trick.
67 */
68 return EXIT_SUCCESS;
69 }
70
71 /* child */
72 /* now there should be no error: */
73 setsid();
74 }
75
76 if (opt) {
77 /* -c: set (with stealing) controlling tty */
78 ioctl(0, TIOCSCTTY, 1);
79 }
80
81 BB_EXECVP_or_die(argv);
82}
diff --git a/util-linux/switch_root.c b/util-linux/switch_root.c
index 6034485d7..f18e8a5ce 100644
--- a/util-linux/switch_root.c
+++ b/util-linux/switch_root.c
@@ -141,10 +141,12 @@ int switch_root_main(int argc UNUSED_PARAM, char **argv)
141 141
142 // If a new console specified, redirect stdin/stdout/stderr to it 142 // If a new console specified, redirect stdin/stdout/stderr to it
143 if (console) { 143 if (console) {
144 close(0); 144 int fd = open_or_warn(console, O_RDWR);
145 xopen(console, O_RDWR); 145 if (fd >= 0) {
146 xdup2(0, 1); 146 xmove_fd(fd, 0);
147 xdup2(0, 2); 147 xdup2(0, 1);
148 xdup2(0, 2);
149 }
148 } 150 }
149 151
150 // Exec real init 152 // Exec real init
@@ -181,7 +183,7 @@ So there's a step that needs to be sort of atomic but can't be as a shell
181script. (You can work around this with static linking or very carefully laid 183script. (You can work around this with static linking or very carefully laid
182out paths and sequencing, but it's brittle, ugly, and non-obvious.) 184out paths and sequencing, but it's brittle, ugly, and non-obvious.)
183 185
1842) The "find | rm" bit will acually delete everything because the mount points 1862) The "find | rm" bit will actually delete everything because the mount points
185still show up (even if their contents don't), and rm -rf will then happily zap 187still show up (even if their contents don't), and rm -rf will then happily zap
186that. So the first line is an oversimplification of what you need to do _not_ 188that. So the first line is an oversimplification of what you need to do _not_
187to descend into other filesystems and delete their contents. 189to descend into other filesystems and delete their contents.
diff --git a/util-linux/taskset.c b/util-linux/taskset.c
new file mode 100644
index 000000000..94a07383a
--- /dev/null
+++ b/util-linux/taskset.c
@@ -0,0 +1,221 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * taskset - retrieve or set a processes' CPU affinity
4 * Copyright (c) 2006 Bernhard Reutner-Fischer
5 *
6 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
7 */
8
9//config:config TASKSET
10//config: bool "taskset"
11//config: default y
12//config: help
13//config: Retrieve or set a processes's CPU affinity.
14//config: This requires sched_{g,s}etaffinity support in your libc.
15//config:
16//config:config FEATURE_TASKSET_FANCY
17//config: bool "Fancy output"
18//config: default y
19//config: depends on TASKSET
20//config: help
21//config: Needed for machines with more than 32-64 CPUs:
22//config: affinity parameter 0xHHHHHHHHHHHHHHHHHHHH can be arbitrarily long
23//config: in this case. Otherwise, it is limited to sizeof(long).
24
25//applet:IF_TASKSET(APPLET(taskset, BB_DIR_USR_BIN, BB_SUID_DROP))
26//kbuild:lib-$(CONFIG_TASKSET) += taskset.o
27
28//usage:#define taskset_trivial_usage
29//usage: "[-p] [HEXMASK] PID | PROG ARGS"
30//usage:#define taskset_full_usage "\n\n"
31//usage: "Set or get CPU affinity\n"
32//usage: "\n -p Operate on an existing PID"
33//usage:
34//usage:#define taskset_example_usage
35//usage: "$ taskset 0x7 ./dgemm_test&\n"
36//usage: "$ taskset -p 0x1 $!\n"
37//usage: "pid 4790's current affinity mask: 7\n"
38//usage: "pid 4790's new affinity mask: 1\n"
39//usage: "$ taskset 0x7 /bin/sh -c './taskset -p 0x1 $$'\n"
40//usage: "pid 6671's current affinity mask: 1\n"
41//usage: "pid 6671's new affinity mask: 1\n"
42//usage: "$ taskset -p 1\n"
43//usage: "pid 1's current affinity mask: 3\n"
44/*
45 * Not yet implemented:
46 * -a/--all-tasks (affect all threads)
47 * needs to get TIDs from /proc/PID/task/ and use _them_ as "pid" in sched_setaffinity(pid)
48 * -c/--cpu-list (specify CPUs via "1,3,5-7")
49 */
50
51#include <sched.h>
52#include "libbb.h"
53
54typedef unsigned long ul;
55#define SZOF_UL (unsigned)(sizeof(ul))
56#define BITS_UL (unsigned)(sizeof(ul)*8)
57#define MASK_UL (unsigned)(sizeof(ul)*8 - 1)
58
59#if ENABLE_FEATURE_TASKSET_FANCY
60#define TASKSET_PRINTF_MASK "%s"
61/* craft a string from the mask */
62static char *from_mask(const ul *mask, unsigned sz_in_bytes)
63{
64 char *str = xzalloc((sz_in_bytes+1) * 2); /* we will leak it */
65 char *p = str;
66 for (;;) {
67 ul v = *mask++;
68 if (SZOF_UL == 4)
69 p += sprintf(p, "%08lx", v);
70 if (SZOF_UL == 8)
71 p += sprintf(p, "%016lx", v);
72 if (SZOF_UL == 16)
73 p += sprintf(p, "%032lx", v); /* :) */
74 sz_in_bytes -= SZOF_UL;
75 if ((int)sz_in_bytes <= 0)
76 break;
77 }
78 while (str[0] == '0' && str[1])
79 str++;
80 return str;
81}
82#else
83#define TASKSET_PRINTF_MASK "%lx"
84static unsigned long long from_mask(ul *mask, unsigned sz_in_bytes UNUSED_PARAM)
85{
86 return *mask;
87}
88#endif
89
90static unsigned long *get_aff(int pid, unsigned *sz)
91{
92 int r;
93 unsigned long *mask = NULL;
94 unsigned sz_in_bytes = *sz;
95
96 for (;;) {
97 mask = xrealloc(mask, sz_in_bytes);
98 r = sched_getaffinity(pid, sz_in_bytes, (void*)mask);
99 if (r == 0)
100 break;
101 sz_in_bytes *= 2;
102 if (errno == EINVAL && (int)sz_in_bytes > 0)
103 continue;
104 bb_perror_msg_and_die("can't %cet pid %d's affinity", 'g', pid);
105 }
106 //bb_error_msg("get mask[0]:%lx sz_in_bytes:%d", mask[0], sz_in_bytes);
107 *sz = sz_in_bytes;
108 return mask;
109}
110
111int taskset_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
112int taskset_main(int argc UNUSED_PARAM, char **argv)
113{
114 ul *mask;
115 unsigned mask_size_in_bytes;
116 pid_t pid = 0;
117 unsigned opt_p;
118 const char *current_new;
119 char *aff;
120
121 /* NB: we mimic util-linux's taskset: -p does not take
122 * an argument, i.e., "-pN" is NOT valid, only "-p N"!
123 * Indeed, util-linux-2.13-pre7 uses:
124 * getopt_long(argc, argv, "+pchV", ...), not "...p:..." */
125
126 opt_complementary = "-1"; /* at least 1 arg */
127 opt_p = getopt32(argv, "+p");
128 argv += optind;
129
130 aff = *argv++;
131 if (opt_p) {
132 char *pid_str = aff;
133 if (*argv) { /* "-p <aff> <pid> ...rest.is.ignored..." */
134 pid_str = *argv; /* NB: *argv != NULL in this case */
135 }
136 /* else it was just "-p <pid>", and *argv == NULL */
137 pid = xatoul_range(pid_str, 1, ((unsigned)(pid_t)ULONG_MAX) >> 1);
138 } else {
139 /* <aff> <cmd...> */
140 if (!*argv)
141 bb_show_usage();
142 }
143
144 mask_size_in_bytes = SZOF_UL;
145 current_new = "current";
146 print_aff:
147 mask = get_aff(pid, &mask_size_in_bytes);
148 if (opt_p) {
149 printf("pid %d's %s affinity mask: "TASKSET_PRINTF_MASK"\n",
150 pid, current_new, from_mask(mask, mask_size_in_bytes));
151 if (*argv == NULL) {
152 /* Either it was just "-p <pid>",
153 * or it was "-p <aff> <pid>" and we came here
154 * for the second time (see goto below) */
155 return EXIT_SUCCESS;
156 }
157 *argv = NULL;
158 current_new = "new";
159 }
160 memset(mask, 0, mask_size_in_bytes);
161
162 /* Affinity was specified, translate it into mask */
163 /* it is always in hex, skip "0x" if it exists */
164 if (aff[0] == '0' && (aff[1]|0x20) == 'x')
165 aff += 2;
166
167 if (!ENABLE_FEATURE_TASKSET_FANCY) {
168 mask[0] = xstrtoul(aff, 16);
169 } else {
170 unsigned i;
171 char *last_char;
172
173 i = 0; /* bit pos in mask[] */
174
175 /* aff is ASCII hex string, accept very long masks in this form.
176 * Process hex string AABBCCDD... to ulong mask[]
177 * from the rightmost nibble, which is least-significant.
178 * Bits not fitting into mask[] are ignored: (example: 1234
179 * in 12340000000000000000000000000000000000000ff)
180 */
181 last_char = strchrnul(aff, '\0');
182 while (last_char > aff) {
183 char c;
184 ul val;
185
186 last_char--;
187 c = *last_char;
188 if (isdigit(c))
189 val = c - '0';
190 else if ((c|0x20) >= 'a' && (c|0x20) <= 'f')
191 val = (c|0x20) - ('a' - 10);
192 else
193 bb_error_msg_and_die("bad affinity '%s'", aff);
194
195 if (i < mask_size_in_bytes * 8) {
196 mask[i / BITS_UL] |= val << (i & MASK_UL);
197 //bb_error_msg("bit %d set", i);
198 }
199 /* else:
200 * We can error out here, but we don't.
201 * For one, kernel itself ignores bits in mask[]
202 * which do not map to any CPUs:
203 * if mask[] has one 32-bit long element,
204 * but you have only 8 CPUs, all bits beyond first 8
205 * are ignored, silently.
206 * No point in making bits past 31th to be errors.
207 */
208 i += 4;
209 }
210 }
211
212 /* Set pid's or our own (pid==0) affinity */
213 if (sched_setaffinity(pid, mask_size_in_bytes, (void*)mask))
214 bb_perror_msg_and_die("can't %cet pid %d's affinity", 's', pid);
215 //bb_error_msg("set mask[0]:%lx", mask[0]);
216
217 if (!argv[0]) /* "-p <aff> <pid> [...ignored...]" */
218 goto print_aff; /* print new affinity and exit */
219
220 BB_EXECVP_or_die(argv);
221}
diff --git a/util-linux/umount.c b/util-linux/umount.c
index c958fd552..0c50dc9ee 100644
--- a/util-linux/umount.c
+++ b/util-linux/umount.c
@@ -42,7 +42,7 @@
42//usage: "\n -l Lazy umount (detach filesystem)" 42//usage: "\n -l Lazy umount (detach filesystem)"
43//usage: "\n -f Force umount (i.e., unreachable NFS server)" 43//usage: "\n -f Force umount (i.e., unreachable NFS server)"
44//usage: IF_FEATURE_MOUNT_LOOP( 44//usage: IF_FEATURE_MOUNT_LOOP(
45//usage: "\n -D Don't free loop device even if it has been used" 45//usage: "\n -d Free loop device if it has been used"
46//usage: ) 46//usage: )
47//usage: 47//usage:
48//usage:#define umount_example_usage 48//usage:#define umount_example_usage
@@ -68,22 +68,14 @@ static struct mntent *getmntent_r(FILE* stream, struct mntent* result,
68} 68}
69#endif 69#endif
70 70
71/* Ignored: -v -t -i 71/* ignored: -v -t -i */
72 * bbox always acts as if -d is present. 72#define OPTION_STRING "fldnra" "vt:i"
73 * -D can be used to suppress it (bbox extension).
74 * Rationale:
75 * (1) util-linux's umount does it if "loop=..." is seen in /etc/mtab:
76 * thus, on many systems, bare umount _does_ drop loop devices.
77 * (2) many users request this feature.
78 */
79#define OPTION_STRING "fldDnra" "vt:i"
80#define OPT_FORCE (1 << 0) // Same as MNT_FORCE 73#define OPT_FORCE (1 << 0) // Same as MNT_FORCE
81#define OPT_LAZY (1 << 1) // Same as MNT_DETACH 74#define OPT_LAZY (1 << 1) // Same as MNT_DETACH
82//#define OPT_FREE_LOOP (1 << 2) // -d is assumed always present 75#define OPT_FREELOOP (1 << 2)
83#define OPT_DONT_FREE_LOOP (1 << 3) 76#define OPT_NO_MTAB (1 << 3)
84#define OPT_NO_MTAB (1 << 4) 77#define OPT_REMOUNT (1 << 4)
85#define OPT_REMOUNT (1 << 5) 78#define OPT_ALL (ENABLE_FEATURE_UMOUNT_ALL ? (1 << 5) : 0)
86#define OPT_ALL (ENABLE_FEATURE_UMOUNT_ALL ? (1 << 6) : 0)
87 79
88int umount_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 80int umount_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
89int umount_main(int argc UNUSED_PARAM, char **argv) 81int umount_main(int argc UNUSED_PARAM, char **argv)
@@ -206,7 +198,7 @@ int umount_main(int argc UNUSED_PARAM, char **argv)
206 } else { 198 } else {
207 // De-allocate the loop device. This ioctl should be ignored on 199 // De-allocate the loop device. This ioctl should be ignored on
208 // any non-loop block devices. 200 // any non-loop block devices.
209 if (ENABLE_FEATURE_MOUNT_LOOP && !(opt & OPT_DONT_FREE_LOOP) && m) 201 if (ENABLE_FEATURE_MOUNT_LOOP && (opt & OPT_FREELOOP) && m)
210 del_loop(m->device); 202 del_loop(m->device);
211 if (ENABLE_FEATURE_MTAB_SUPPORT && !(opt & OPT_NO_MTAB) && m) 203 if (ENABLE_FEATURE_MTAB_SUPPORT && !(opt & OPT_NO_MTAB) && m)
212 erase_mtab(m->dir); 204 erase_mtab(m->dir);
diff --git a/util-linux/volume_id/udf.c b/util-linux/volume_id/udf.c
index 613c80c86..fa5dccee7 100644
--- a/util-linux/volume_id/udf.c
+++ b/util-linux/volume_id/udf.c
@@ -137,7 +137,7 @@ anchor:
137 if (type != 2) /* TAG_ID_AVDP */ 137 if (type != 2) /* TAG_ID_AVDP */
138 goto found; 138 goto found;
139 139
140 /* get desriptor list address and block count */ 140 /* get descriptor list address and block count */
141 count = le32_to_cpu(vd->type.anchor.length) / bs; 141 count = le32_to_cpu(vd->type.anchor.length) / bs;
142 loc = le32_to_cpu(vd->type.anchor.location); 142 loc = le32_to_cpu(vd->type.anchor.location);
143 dbg("0x%x descriptors starting at logical secor 0x%x", count, loc); 143 dbg("0x%x descriptors starting at logical secor 0x%x", count, loc);
diff --git a/util-linux/wall.c b/util-linux/wall.c
new file mode 100644
index 000000000..50658f457
--- /dev/null
+++ b/util-linux/wall.c
@@ -0,0 +1,63 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * wall - write a message to all logged-in users
4 * Copyright (c) 2009 Bernhard Reutner-Fischer
5 *
6 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
7 */
8
9//config:config WALL
10//config: bool "wall"
11//config: default y
12//config: depends on FEATURE_UTMP
13//config: help
14//config: Write a message to all users that are logged in.
15
16/* Needs to be run by root or be suid root - needs to write to /dev/TTY: */
17//applet:IF_WALL(APPLET(wall, BB_DIR_USR_BIN, BB_SUID_REQUIRE))
18
19//kbuild:lib-$(CONFIG_WALL) += wall.o
20
21//usage:#define wall_trivial_usage
22//usage: "[FILE]"
23//usage:#define wall_full_usage "\n\n"
24//usage: "Write content of FILE or stdin to all logged-in users"
25//usage:
26//usage:#define wall_sample_usage
27//usage: "echo foo | wall\n"
28//usage: "wall ./mymessage"
29
30#include "libbb.h"
31
32int wall_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
33int wall_main(int argc UNUSED_PARAM, char **argv)
34{
35 struct utmpx *ut;
36 char *msg;
37 int fd;
38
39 fd = STDIN_FILENO;
40 if (argv[1]) {
41 /* The applet is setuid.
42 * Access to the file must be under user's uid/gid.
43 */
44 fd = xopen_as_uid_gid(argv[1], O_RDONLY, getuid(), getgid());
45 }
46 msg = xmalloc_read(fd, NULL);
47 if (ENABLE_FEATURE_CLEAN_UP && argv[1])
48 close(fd);
49 setutxent();
50 while ((ut = getutxent()) != NULL) {
51 char *line;
52 if (ut->ut_type != USER_PROCESS)
53 continue;
54 line = concat_path_file("/dev", ut->ut_line);
55 xopen_xwrite_close(line, msg);
56 free(line);
57 }
58 if (ENABLE_FEATURE_CLEAN_UP) {
59 endutxent();
60 free(msg);
61 }
62 return EXIT_SUCCESS;
63}