aboutsummaryrefslogtreecommitdiff
path: root/miscutils
diff options
context:
space:
mode:
Diffstat (limited to 'miscutils')
-rw-r--r--miscutils/chrt.c149
-rw-r--r--miscutils/eject.c152
-rw-r--r--miscutils/ionice.c115
-rw-r--r--miscutils/last.c166
-rw-r--r--miscutils/last_fancy.c300
-rw-r--r--miscutils/mountpoint.c105
-rw-r--r--miscutils/setsid.c82
-rw-r--r--miscutils/taskset.c221
-rw-r--r--miscutils/timeout.c127
-rw-r--r--miscutils/wall.c63
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
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/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
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/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
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/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
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/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
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/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
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/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
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/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
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/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
49int timeout_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
50int timeout_main(int argc UNUSED_PARAM, char **argv)
51{
52 int signo;
53 int status;
54 int parent = 0;
55 int timeout = 10;
56 pid_t pid;
57#if !BB_MMU
58 char *sv1, *sv2;
59#endif
60 const char *opt_s = "TERM";
61
62 /* -p option is not documented, it is needed to support NOMMU. */
63
64 /* -t SECONDS; -p PARENT_PID */
65 /* '+': stop at first non-option */
66 getopt32(argv, "+s:t:+" USE_FOR_NOMMU("p:+"), &opt_s, &timeout, &parent);
67 /*argv += optind; - no, wait for bb_daemonize_or_rexec! */
68 signo = get_signum(opt_s);
69 if (signo < 0)
70 bb_error_msg_and_die("unknown signal '%s'", opt_s);
71
72 /* We want to create a grandchild which will watch
73 * and kill the grandparent. Other methods:
74 * making parent watch child disrupts parent<->child link
75 * (example: "tcpsvd 0.0.0.0 1234 timeout service_prog" -
76 * it's better if service_prog is a child of tcpsvd!),
77 * making child watch parent results in programs having
78 * unexpected children. */
79
80 if (parent) /* we were re-execed, already grandchild */
81 goto grandchild;
82 if (!argv[optind]) /* no PROG? */
83 bb_show_usage();
84
85#if !BB_MMU
86 sv1 = argv[optind];
87 sv2 = argv[optind + 1];
88#endif
89 pid = xvfork();
90 if (pid == 0) {
91 /* Child: spawn grandchild and exit */
92 parent = getppid();
93#if !BB_MMU
94 argv[optind] = xasprintf("-p%u", parent);
95 argv[optind + 1] = NULL;
96#endif
97 /* NB: exits with nonzero on error: */
98 bb_daemonize_or_rexec(0, argv);
99 /* Here we are grandchild. Sleep, then kill grandparent */
100 grandchild:
101 /* Just sleep(HUGE_NUM); kill(parent) may kill wrong process! */
102 while (1) {
103 sleep(1);
104 if (--timeout <= 0)
105 break;
106 if (kill(parent, 0)) {
107 /* process is gone */
108 return EXIT_SUCCESS;
109 }
110 }
111 kill(parent, signo);
112 return EXIT_SUCCESS;
113 }
114
115 /* Parent */
116 wait(&status); /* wait for child to die */
117 /* Did intermediate [v]fork or exec fail? */
118 if (!WIFEXITED(status) || WEXITSTATUS(status) != 0)
119 return EXIT_FAILURE;
120 /* Ok, exec a program as requested */
121 argv += optind;
122#if !BB_MMU
123 argv[0] = sv1;
124 argv[1] = sv2;
125#endif
126 BB_EXECVP_or_die(argv);
127}
diff --git a/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
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}