diff options
Diffstat (limited to 'miscutils')
-rw-r--r-- | miscutils/chrt.c | 149 | ||||
-rw-r--r-- | miscutils/eject.c | 152 | ||||
-rw-r--r-- | miscutils/ionice.c | 115 | ||||
-rw-r--r-- | miscutils/last.c | 166 | ||||
-rw-r--r-- | miscutils/last_fancy.c | 300 | ||||
-rw-r--r-- | miscutils/mountpoint.c | 105 | ||||
-rw-r--r-- | miscutils/setsid.c | 82 | ||||
-rw-r--r-- | miscutils/taskset.c | 221 | ||||
-rw-r--r-- | miscutils/timeout.c | 127 | ||||
-rw-r--r-- | miscutils/wall.c | 63 |
10 files changed, 0 insertions, 1480 deletions
diff --git a/miscutils/chrt.c b/miscutils/chrt.c deleted file mode 100644 index 1604a6890..000000000 --- a/miscutils/chrt.c +++ /dev/null | |||
@@ -1,149 +0,0 @@ | |||
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 | |||
37 | static 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 | |||
50 | static 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 | |||
68 | int chrt_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | ||
69 | int 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/miscutils/eject.c b/miscutils/eject.c deleted file mode 100644 index 667932f6c..000000000 --- a/miscutils/eject.c +++ /dev/null | |||
@@ -1,152 +0,0 @@ | |||
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 | ||
59 | static 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 | |||
108 | static 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 | |||
121 | int eject_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | ||
122 | int 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/miscutils/ionice.c b/miscutils/ionice.c deleted file mode 100644 index c54b3a6e1..000000000 --- a/miscutils/ionice.c +++ /dev/null | |||
@@ -1,115 +0,0 @@ | |||
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 | |||
32 | static int ioprio_set(int which, int who, int ioprio) | ||
33 | { | ||
34 | return syscall(SYS_ioprio_set, which, who, ioprio); | ||
35 | } | ||
36 | |||
37 | static int ioprio_get(int which, int who) | ||
38 | { | ||
39 | return syscall(SYS_ioprio_get, which, who); | ||
40 | } | ||
41 | |||
42 | enum { | ||
43 | IOPRIO_WHO_PROCESS = 1, | ||
44 | IOPRIO_WHO_PGRP, | ||
45 | IOPRIO_WHO_USER | ||
46 | }; | ||
47 | |||
48 | enum { | ||
49 | IOPRIO_CLASS_NONE, | ||
50 | IOPRIO_CLASS_RT, | ||
51 | IOPRIO_CLASS_BE, | ||
52 | IOPRIO_CLASS_IDLE | ||
53 | }; | ||
54 | |||
55 | static const char to_prio[] ALIGN1 = "none\0realtime\0best-effort\0idle"; | ||
56 | |||
57 | #define IOPRIO_CLASS_SHIFT 13 | ||
58 | |||
59 | int ionice_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | ||
60 | int 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/miscutils/last.c b/miscutils/last.c deleted file mode 100644 index b3f125c3f..000000000 --- a/miscutils/last.c +++ /dev/null | |||
@@ -1,166 +0,0 @@ | |||
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 | |||
69 | int last_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | ||
70 | int 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/miscutils/last_fancy.c b/miscutils/last_fancy.c deleted file mode 100644 index e56e0ba85..000000000 --- a/miscutils/last_fancy.c +++ /dev/null | |||
@@ -1,300 +0,0 @@ | |||
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 | |||
29 | enum { | ||
30 | NORMAL, | ||
31 | LOGGED, | ||
32 | DOWN, | ||
33 | REBOOT, | ||
34 | CRASH, | ||
35 | GONE | ||
36 | }; | ||
37 | |||
38 | enum { | ||
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 | |||
46 | static 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 | |||
111 | static 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 | |||
149 | static 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 | |||
158 | int last_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | ||
159 | int 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/miscutils/mountpoint.c b/miscutils/mountpoint.c deleted file mode 100644 index 8b9e1d779..000000000 --- a/miscutils/mountpoint.c +++ /dev/null | |||
@@ -1,105 +0,0 @@ | |||
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 | |||
38 | int mountpoint_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | ||
39 | int 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/miscutils/setsid.c b/miscutils/setsid.c deleted file mode 100644 index 143a8f8fa..000000000 --- a/miscutils/setsid.c +++ /dev/null | |||
@@ -1,82 +0,0 @@ | |||
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 | |||
35 | int setsid_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | ||
36 | int 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/miscutils/taskset.c b/miscutils/taskset.c deleted file mode 100644 index 94a07383a..000000000 --- a/miscutils/taskset.c +++ /dev/null | |||
@@ -1,221 +0,0 @@ | |||
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 | |||
54 | typedef 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 */ | ||
62 | static 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" | ||
84 | static unsigned long long from_mask(ul *mask, unsigned sz_in_bytes UNUSED_PARAM) | ||
85 | { | ||
86 | return *mask; | ||
87 | } | ||
88 | #endif | ||
89 | |||
90 | static 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 | |||
111 | int taskset_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | ||
112 | int 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/miscutils/timeout.c b/miscutils/timeout.c deleted file mode 100644 index f29dc8a9c..000000000 --- a/miscutils/timeout.c +++ /dev/null | |||
@@ -1,127 +0,0 @@ | |||
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/miscutils/wall.c b/miscutils/wall.c deleted file mode 100644 index 50658f457..000000000 --- a/miscutils/wall.c +++ /dev/null | |||
@@ -1,63 +0,0 @@ | |||
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 | |||
32 | int wall_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | ||
33 | int 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 | } | ||