Sort some miscutils/ applets into coreutils or util-linux
authorDenys Vlasenko <vda.linux@googlemail.com>
Wed, 12 Apr 2017 11:58:40 +0000 (13:58 +0200)
committerDenys Vlasenko <vda.linux@googlemail.com>
Wed, 12 Apr 2017 11:58:40 +0000 (13:58 +0200)
No code changes

Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
20 files changed:
coreutils/timeout.c [new file with mode: 0644]
miscutils/chrt.c [deleted file]
miscutils/eject.c [deleted file]
miscutils/ionice.c [deleted file]
miscutils/last.c [deleted file]
miscutils/last_fancy.c [deleted file]
miscutils/mountpoint.c [deleted file]
miscutils/setsid.c [deleted file]
miscutils/taskset.c [deleted file]
miscutils/timeout.c [deleted file]
miscutils/wall.c [deleted file]
util-linux/chrt.c [new file with mode: 0644]
util-linux/eject.c [new file with mode: 0644]
util-linux/ionice.c [new file with mode: 0644]
util-linux/last.c [new file with mode: 0644]
util-linux/last_fancy.c [new file with mode: 0644]
util-linux/mountpoint.c [new file with mode: 0644]
util-linux/setsid.c [new file with mode: 0644]
util-linux/taskset.c [new file with mode: 0644]
util-linux/wall.c [new file with mode: 0644]

diff --git a/coreutils/timeout.c b/coreutils/timeout.c
new file mode 100644 (file)
index 0000000..f29dc8a
--- /dev/null
@@ -0,0 +1,127 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * COPYING NOTES
+ *
+ * timeout.c -- a timeout handler for shell commands
+ *
+ * Copyright (C) 2005-6, Roberto A. Foglietta <me@roberto.foglietta.name>
+ *
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; version 2 of the License.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program; if not, write to the Free Software
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
+ */
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * REVISION NOTES:
+ * released 17-11-2005 by Roberto A. Foglietta
+ * talarm   04-12-2005 by Roberto A. Foglietta
+ * modified 05-12-2005 by Roberto A. Foglietta
+ * sizerdct 06-12-2005 by Roberto A. Foglietta
+ * splitszf 12-05-2006 by Roberto A. Foglietta
+ * rewrite  14-11-2008 vda
+ */
+//config:config TIMEOUT
+//config:      bool "timeout"
+//config:      default y
+//config:      help
+//config:        Runs a program and watches it. If it does not terminate in
+//config:        specified number of seconds, it is sent a signal.
+
+//applet:IF_TIMEOUT(APPLET(timeout, BB_DIR_USR_BIN, BB_SUID_DROP))
+
+//kbuild:lib-$(CONFIG_TIMEOUT) += timeout.o
+
+//usage:#define timeout_trivial_usage
+//usage:       "[-t SECS] [-s SIG] PROG ARGS"
+//usage:#define timeout_full_usage "\n\n"
+//usage:       "Runs PROG. Sends SIG to it if it is not gone in SECS seconds.\n"
+//usage:       "Defaults: SECS: 10, SIG: TERM."
+
+#include "libbb.h"
+
+int timeout_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int timeout_main(int argc UNUSED_PARAM, char **argv)
+{
+       int signo;
+       int status;
+       int parent = 0;
+       int timeout = 10;
+       pid_t pid;
+#if !BB_MMU
+       char *sv1, *sv2;
+#endif
+       const char *opt_s = "TERM";
+
+       /* -p option is not documented, it is needed to support NOMMU. */
+
+       /* -t SECONDS; -p PARENT_PID */
+       /* '+': stop at first non-option */
+       getopt32(argv, "+s:t:+" USE_FOR_NOMMU("p:+"), &opt_s, &timeout, &parent);
+       /*argv += optind; - no, wait for bb_daemonize_or_rexec! */
+       signo = get_signum(opt_s);
+       if (signo < 0)
+               bb_error_msg_and_die("unknown signal '%s'", opt_s);
+
+       /* We want to create a grandchild which will watch
+        * and kill the grandparent. Other methods:
+        * making parent watch child disrupts parent<->child link
+        * (example: "tcpsvd 0.0.0.0 1234 timeout service_prog" -
+        * it's better if service_prog is a child of tcpsvd!),
+        * making child watch parent results in programs having
+        * unexpected children. */
+
+       if (parent) /* we were re-execed, already grandchild */
+               goto grandchild;
+       if (!argv[optind]) /* no PROG? */
+               bb_show_usage();
+
+#if !BB_MMU
+       sv1 = argv[optind];
+       sv2 = argv[optind + 1];
+#endif
+       pid = xvfork();
+       if (pid == 0) {
+               /* Child: spawn grandchild and exit */
+               parent = getppid();
+#if !BB_MMU
+               argv[optind] = xasprintf("-p%u", parent);
+               argv[optind + 1] = NULL;
+#endif
+               /* NB: exits with nonzero on error: */
+               bb_daemonize_or_rexec(0, argv);
+               /* Here we are grandchild. Sleep, then kill grandparent */
+ grandchild:
+               /* Just sleep(HUGE_NUM); kill(parent) may kill wrong process! */
+               while (1) {
+                       sleep(1);
+                       if (--timeout <= 0)
+                               break;
+                       if (kill(parent, 0)) {
+                               /* process is gone */
+                               return EXIT_SUCCESS;
+                       }
+               }
+               kill(parent, signo);
+               return EXIT_SUCCESS;
+       }
+
+       /* Parent */
+       wait(&status); /* wait for child to die */
+       /* Did intermediate [v]fork or exec fail? */
+       if (!WIFEXITED(status) || WEXITSTATUS(status) != 0)
+               return EXIT_FAILURE;
+       /* Ok, exec a program as requested */
+       argv += optind;
+#if !BB_MMU
+       argv[0] = sv1;
+       argv[1] = sv2;
+#endif
+       BB_EXECVP_or_die(argv);
+}
diff --git a/miscutils/chrt.c b/miscutils/chrt.c
deleted file mode 100644 (file)
index 1604a68..0000000
+++ /dev/null
@@ -1,149 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * chrt - manipulate real-time attributes of a process
- * Copyright (c) 2006-2007 Bernhard Reutner-Fischer
- *
- * Licensed under GPLv2 or later, see file LICENSE in this source tree.
- */
-//config:config CHRT
-//config:      bool "chrt"
-//config:      default y
-//config:      help
-//config:        manipulate real-time attributes of a process.
-//config:        This requires sched_{g,s}etparam support in your libc.
-
-//applet:IF_CHRT(APPLET(chrt, BB_DIR_USR_BIN, BB_SUID_DROP))
-
-//kbuild:lib-$(CONFIG_CHRT) += chrt.o
-
-//usage:#define chrt_trivial_usage
-//usage:       "[-prfom] [PRIO] [PID | PROG ARGS]"
-//usage:#define chrt_full_usage "\n\n"
-//usage:       "Change scheduling priority and class for a process\n"
-//usage:     "\n       -p      Operate on PID"
-//usage:     "\n       -r      Set SCHED_RR class"
-//usage:     "\n       -f      Set SCHED_FIFO class"
-//usage:     "\n       -o      Set SCHED_OTHER class"
-//usage:     "\n       -m      Show min/max priorities"
-//usage:
-//usage:#define chrt_example_usage
-//usage:       "$ chrt -r 4 sleep 900; x=$!\n"
-//usage:       "$ chrt -f -p 3 $x\n"
-//usage:       "You need CAP_SYS_NICE privileges to set scheduling attributes of a process"
-
-#include <sched.h>
-#include "libbb.h"
-
-static const struct {
-       int policy;
-       char name[sizeof("SCHED_OTHER")];
-} policies[] = {
-       {SCHED_OTHER, "SCHED_OTHER"},
-       {SCHED_FIFO, "SCHED_FIFO"},
-       {SCHED_RR, "SCHED_RR"}
-};
-
-//TODO: add
-// -b, SCHED_BATCH
-// -i, SCHED_IDLE
-
-static void show_min_max(int pol)
-{
-       const char *fmt = "%s min/max priority\t: %u/%u\n";
-       int max, min;
-
-       max = sched_get_priority_max(pol);
-       min = sched_get_priority_min(pol);
-       if ((max|min) < 0)
-               fmt = "%s not supported\n";
-       printf(fmt, policies[pol].name, min, max);
-}
-
-#define OPT_m (1<<0)
-#define OPT_p (1<<1)
-#define OPT_r (1<<2)
-#define OPT_f (1<<3)
-#define OPT_o (1<<4)
-
-int chrt_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
-int chrt_main(int argc UNUSED_PARAM, char **argv)
-{
-       pid_t pid = 0;
-       unsigned opt;
-       struct sched_param sp;
-       char *pid_str;
-       char *priority = priority; /* for compiler */
-       const char *current_new;
-       int policy = SCHED_RR;
-
-       /* only one policy accepted */
-       opt_complementary = "r--fo:f--ro:o--rf";
-       opt = getopt32(argv, "+mprfo");
-       if (opt & OPT_m) { /* print min/max and exit */
-               show_min_max(SCHED_FIFO);
-               show_min_max(SCHED_RR);
-               show_min_max(SCHED_OTHER);
-               fflush_stdout_and_exit(EXIT_SUCCESS);
-       }
-       if (opt & OPT_r)
-               policy = SCHED_RR;
-       if (opt & OPT_f)
-               policy = SCHED_FIFO;
-       if (opt & OPT_o)
-               policy = SCHED_OTHER;
-
-       argv += optind;
-       if (!argv[0])
-               bb_show_usage();
-       if (opt & OPT_p) {
-               pid_str = *argv++;
-               if (*argv) { /* "-p <priority> <pid> [...]" */
-                       priority = pid_str;
-                       pid_str = *argv;
-               }
-               /* else "-p <pid>", and *argv == NULL */
-               pid = xatoul_range(pid_str, 1, ((unsigned)(pid_t)ULONG_MAX) >> 1);
-       } else {
-               priority = *argv++;
-               if (!*argv)
-                       bb_show_usage();
-       }
-
-       current_new = "current\0new";
-       if (opt & OPT_p) {
-               int pol;
- print_rt_info:
-               pol = sched_getscheduler(pid);
-               if (pol < 0)
-                       bb_perror_msg_and_die("can't %cet pid %d's policy", 'g', (int)pid);
-               printf("pid %d's %s scheduling policy: %s\n",
-                               pid, current_new, policies[pol].name);
-               if (sched_getparam(pid, &sp))
-                       bb_perror_msg_and_die("can't get pid %d's attributes", (int)pid);
-               printf("pid %d's %s scheduling priority: %d\n",
-                               (int)pid, current_new, sp.sched_priority);
-               if (!*argv) {
-                       /* Either it was just "-p <pid>",
-                        * or it was "-p <priority> <pid>" and we came here
-                        * for the second time (see goto below) */
-                       return EXIT_SUCCESS;
-               }
-               *argv = NULL;
-               current_new += 8;
-       }
-
-       /* from the manpage of sched_getscheduler:
-       [...] sched_priority can have a value in the range 0 to 99.
-       [...] SCHED_OTHER or SCHED_BATCH must be assigned static priority 0.
-       [...] SCHED_FIFO or SCHED_RR can have static priority in 1..99 range.
-       */
-       sp.sched_priority = xstrtou_range(priority, 0, policy != SCHED_OTHER ? 1 : 0, 99);
-
-       if (sched_setscheduler(pid, policy, &sp) < 0)
-               bb_perror_msg_and_die("can't %cet pid %d's policy", 's', (int)pid);
-
-       if (!argv[0]) /* "-p <priority> <pid> [...]" */
-               goto print_rt_info;
-
-       BB_EXECVP_or_die(argv);
-}
diff --git a/miscutils/eject.c b/miscutils/eject.c
deleted file mode 100644 (file)
index 667932f..0000000
+++ /dev/null
@@ -1,152 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * eject implementation for busybox
- *
- * Copyright (C) 2004  Peter Willis <psyphreak@phreaker.net>
- * Copyright (C) 2005  Tito Ragusa <farmatito@tiscali.it>
- *
- * Licensed under GPLv2 or later, see file LICENSE in this source tree.
- */
-
-/*
- * This is a simple hack of eject based on something Erik posted in #uclibc.
- * Most of the dirty work blatantly ripped off from cat.c =)
- */
-//config:config EJECT
-//config:      bool "eject"
-//config:      default y
-//config:      select PLATFORM_LINUX
-//config:      help
-//config:        Used to eject cdroms. (defaults to /dev/cdrom)
-//config:
-//config:config FEATURE_EJECT_SCSI
-//config:      bool "SCSI support"
-//config:      default y
-//config:      depends on EJECT
-//config:      help
-//config:        Add the -s option to eject, this allows to eject SCSI-Devices and
-//config:        usb-storage devices.
-
-//applet:IF_EJECT(APPLET(eject, BB_DIR_USR_BIN, BB_SUID_DROP))
-
-//kbuild:lib-$(CONFIG_EJECT) += eject.o
-
-//usage:#define eject_trivial_usage
-//usage:       "[-t] [-T] [DEVICE]"
-//usage:#define eject_full_usage "\n\n"
-//usage:       "Eject DEVICE or default /dev/cdrom\n"
-//usage:       IF_FEATURE_EJECT_SCSI(
-//usage:     "\n       -s      SCSI device"
-//usage:       )
-//usage:     "\n       -t      Close tray"
-//usage:     "\n       -T      Open/close tray (toggle)"
-
-#include <sys/mount.h>
-#include "libbb.h"
-#if ENABLE_FEATURE_EJECT_SCSI
-/* Must be after libbb.h: they need size_t */
-# include "fix_u32.h"
-# include <scsi/sg.h>
-# include <scsi/scsi.h>
-#endif
-
-#define dev_fd 3
-
-/* Code taken from the original eject (http://eject.sourceforge.net/),
- * refactored it a bit for busybox (ne-bb@nicoerfurth.de) */
-
-#if ENABLE_FEATURE_EJECT_SCSI
-static void eject_scsi(const char *dev)
-{
-       static const char sg_commands[3][6] ALIGN1 = {
-               { ALLOW_MEDIUM_REMOVAL, 0, 0, 0, 0, 0 },
-               { START_STOP, 0, 0, 0, 1, 0 },
-               { START_STOP, 0, 0, 0, 2, 0 }
-       };
-
-       unsigned i;
-       unsigned char sense_buffer[32];
-       unsigned char inqBuff[2];
-       sg_io_hdr_t io_hdr;
-
-       if ((ioctl(dev_fd, SG_GET_VERSION_NUM, &i) < 0) || (i < 30000))
-               bb_error_msg_and_die("not a sg device or old sg driver");
-
-       memset(&io_hdr, 0, sizeof(sg_io_hdr_t));
-       io_hdr.interface_id = 'S';
-       io_hdr.cmd_len = 6;
-       io_hdr.mx_sb_len = sizeof(sense_buffer);
-       io_hdr.dxfer_direction = SG_DXFER_NONE;
-       /* io_hdr.dxfer_len = 0; */
-       io_hdr.dxferp = inqBuff;
-       io_hdr.sbp = sense_buffer;
-       io_hdr.timeout = 2000;
-
-       for (i = 0; i < 3; i++) {
-               io_hdr.cmdp = (void *)sg_commands[i];
-               ioctl_or_perror_and_die(dev_fd, SG_IO, (void *)&io_hdr, "%s", dev);
-       }
-
-       /* force kernel to reread partition table when new disc is inserted */
-       ioctl(dev_fd, BLKRRPART);
-}
-#else
-# define eject_scsi(dev) ((void)0)
-#endif
-
-/* various defines swiped from linux/cdrom.h */
-#define CDROMCLOSETRAY            0x5319  /* pendant of CDROMEJECT  */
-#define CDROMEJECT                0x5309  /* Ejects the cdrom media */
-#define CDROM_DRIVE_STATUS        0x5326  /* Get tray position, etc. */
-/* drive status possibilities returned by CDROM_DRIVE_STATUS ioctl */
-#define CDS_TRAY_OPEN        2
-
-#define FLAG_CLOSE  1
-#define FLAG_SMART  2
-#define FLAG_SCSI   4
-
-static void eject_cdrom(unsigned flags, const char *dev)
-{
-       int cmd = CDROMEJECT;
-
-       if (flags & FLAG_CLOSE
-        || ((flags & FLAG_SMART) && ioctl(dev_fd, CDROM_DRIVE_STATUS) == CDS_TRAY_OPEN)
-       ) {
-               cmd = CDROMCLOSETRAY;
-       }
-
-       ioctl_or_perror_and_die(dev_fd, cmd, NULL, "%s", dev);
-}
-
-int eject_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
-int eject_main(int argc UNUSED_PARAM, char **argv)
-{
-       unsigned flags;
-       const char *device;
-
-       opt_complementary = "?1:t--T:T--t";
-       flags = getopt32(argv, "tT" IF_FEATURE_EJECT_SCSI("s"));
-       device = argv[optind] ? argv[optind] : "/dev/cdrom";
-
-       /* We used to do "umount <device>" here, but it was buggy
-          if something was mounted OVER cdrom and
-          if cdrom is mounted many times.
-
-          This works equally well (or better):
-          #!/bin/sh
-          umount /dev/cdrom
-          eject /dev/cdrom
-       */
-
-       xmove_fd(xopen_nonblocking(device), dev_fd);
-
-       if (ENABLE_FEATURE_EJECT_SCSI && (flags & FLAG_SCSI))
-               eject_scsi(device);
-       else
-               eject_cdrom(flags, device);
-
-       if (ENABLE_FEATURE_CLEAN_UP)
-               close(dev_fd);
-
-       return EXIT_SUCCESS;
-}
diff --git a/miscutils/ionice.c b/miscutils/ionice.c
deleted file mode 100644 (file)
index c54b3a6..0000000
+++ /dev/null
@@ -1,115 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * ionice implementation for busybox based on linux-utils-ng 2.14
- *
- * Copyright (C) 2008 by  <u173034@informatik.uni-oldenburg.de>
- *
- * Licensed under GPLv2 or later, see file LICENSE in this source tree.
- */
-//config:config IONICE
-//config:      bool "ionice"
-//config:      default y
-//config:      select PLATFORM_LINUX
-//config:      help
-//config:        Set/set program io scheduling class and priority
-//config:        Requires kernel >= 2.6.13
-
-//applet:IF_IONICE(APPLET(ionice, BB_DIR_BIN, BB_SUID_DROP))
-
-//kbuild:lib-$(CONFIG_IONICE) += ionice.o
-
-//usage:#define ionice_trivial_usage
-//usage:       "[-c 1-3] [-n 0-7] [-p PID] [PROG]"
-//usage:#define ionice_full_usage "\n\n"
-//usage:       "Change I/O priority and class\n"
-//usage:     "\n       -c      Class. 1:realtime 2:best-effort 3:idle"
-//usage:     "\n       -n      Priority"
-
-#include <sys/syscall.h>
-#include <asm/unistd.h>
-#include "libbb.h"
-
-static int ioprio_set(int which, int who, int ioprio)
-{
-       return syscall(SYS_ioprio_set, which, who, ioprio);
-}
-
-static int ioprio_get(int which, int who)
-{
-       return syscall(SYS_ioprio_get, which, who);
-}
-
-enum {
-       IOPRIO_WHO_PROCESS = 1,
-       IOPRIO_WHO_PGRP,
-       IOPRIO_WHO_USER
-};
-
-enum {
-       IOPRIO_CLASS_NONE,
-       IOPRIO_CLASS_RT,
-       IOPRIO_CLASS_BE,
-       IOPRIO_CLASS_IDLE
-};
-
-static const char to_prio[] ALIGN1 = "none\0realtime\0best-effort\0idle";
-
-#define IOPRIO_CLASS_SHIFT      13
-
-int ionice_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
-int ionice_main(int argc UNUSED_PARAM, char **argv)
-{
-       /* Defaults */
-       int ioclass = 0;
-       int pri = 0;
-       int pid = 0; /* affect own porcess */
-       int opt;
-       enum {
-               OPT_n = 1,
-               OPT_c = 2,
-               OPT_p = 4,
-       };
-
-       /* Numeric params */
-       /* '+': stop at first non-option */
-       opt = getopt32(argv, "+n:+c:+p:+", &pri, &ioclass, &pid);
-       argv += optind;
-
-       if (opt & OPT_c) {
-               if (ioclass > 3)
-                       bb_error_msg_and_die("bad class %d", ioclass);
-// Do we need this (compat?)?
-//             if (ioclass == IOPRIO_CLASS_NONE)
-//                     ioclass = IOPRIO_CLASS_BE;
-//             if (ioclass == IOPRIO_CLASS_IDLE) {
-//                     //if (opt & OPT_n)
-//                     //      bb_error_msg("ignoring priority for idle class");
-//                     pri = 7;
-//             }
-       }
-
-       if (!(opt & (OPT_n|OPT_c))) {
-               if (!(opt & OPT_p) && *argv)
-                       pid = xatoi_positive(*argv);
-
-               pri = ioprio_get(IOPRIO_WHO_PROCESS, pid);
-               if (pri == -1)
-                       bb_perror_msg_and_die("ioprio_%cet", 'g');
-
-               ioclass = (pri >> IOPRIO_CLASS_SHIFT) & 0x3;
-               pri &= 0xff;
-               printf((ioclass == IOPRIO_CLASS_IDLE) ? "%s\n" : "%s: prio %d\n",
-                               nth_string(to_prio, ioclass), pri);
-       } else {
-//printf("pri=%d class=%d val=%x\n",
-//pri, ioclass, pri | (ioclass << IOPRIO_CLASS_SHIFT));
-               pri |= (ioclass << IOPRIO_CLASS_SHIFT);
-               if (ioprio_set(IOPRIO_WHO_PROCESS, pid, pri) == -1)
-                       bb_perror_msg_and_die("ioprio_%cet", 's');
-               if (argv[0]) {
-                       BB_EXECVP_or_die(argv);
-               }
-       }
-
-       return EXIT_SUCCESS;
-}
diff --git a/miscutils/last.c b/miscutils/last.c
deleted file mode 100644 (file)
index b3f125c..0000000
+++ /dev/null
@@ -1,166 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * last implementation for busybox
- *
- * Copyright (C) 2003-2004 by Erik Andersen <andersen@codepoet.org>
- *
- * Licensed under GPLv2, see file LICENSE in this source tree.
- */
-//config:config LAST
-//config:      bool "last"
-//config:      default y
-//config:      depends on FEATURE_WTMP
-//config:      help
-//config:        'last' displays a list of the last users that logged into the system.
-//config:
-//config:config FEATURE_LAST_FANCY
-//config:      bool "Output extra information"
-//config:      default y
-//config:      depends on LAST
-//config:      help
-//config:        'last' displays detailed information about the last users that
-//config:        logged into the system (mimics sysvinit last). +900 bytes.
-
-//applet:IF_LAST(APPLET(last, BB_DIR_USR_BIN, BB_SUID_DROP))
-
-//kbuild:ifeq ($(CONFIG_FEATURE_LAST_FANCY),y)
-//kbuild:lib-$(CONFIG_FEATURE_LAST_FANCY) += last_fancy.o
-//kbuild:else
-//kbuild:lib-$(CONFIG_LAST) += last.o
-//kbuild:endif
-
-//usage:#define last_trivial_usage
-//usage:       ""IF_FEATURE_LAST_FANCY("[-HW] [-f FILE]")
-//usage:#define last_full_usage "\n\n"
-//usage:       "Show listing of the last users that logged into the system"
-//usage:       IF_FEATURE_LAST_FANCY( "\n"
-/* //usage:  "\n       -H      Show header line" */
-//usage:     "\n       -W      Display with no host column truncation"
-//usage:     "\n       -f FILE Read from FILE instead of /var/log/wtmp"
-//usage:       )
-
-#include "libbb.h"
-
-/* NB: ut_name and ut_user are the same field, use only one name (ut_user)
- * to reduce confusion */
-
-#ifndef SHUTDOWN_TIME
-#  define SHUTDOWN_TIME 254
-#endif
-
-/* Grr... utmp char[] members do not have to be nul-terminated.
- * Do what we can while still keeping this reasonably small.
- * Note: We are assuming the ut_id[] size is fixed at 4. */
-
-#if defined UT_LINESIZE \
-       && ((UT_LINESIZE != 32) || (UT_NAMESIZE != 32) || (UT_HOSTSIZE != 256))
-#error struct utmpx member char[] size(s) have changed!
-#elif defined __UT_LINESIZE \
-       && ((__UT_LINESIZE != 32) || (__UT_NAMESIZE != 32) || (__UT_HOSTSIZE != 256))
-/* __UT_NAMESIZE was checked with 64 above, but glibc-2.11 definitely uses 32! */
-#error struct utmpx member char[] size(s) have changed!
-#endif
-
-#if EMPTY != 0 || RUN_LVL != 1 || BOOT_TIME != 2 || NEW_TIME != 3 || \
-       OLD_TIME != 4
-#error Values for the ut_type field of struct utmpx changed
-#endif
-
-int last_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
-int last_main(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
-{
-       struct utmpx ut;
-       int n, file = STDIN_FILENO;
-       time_t t_tmp;
-       off_t pos;
-       static const char _ut_usr[] ALIGN1 =
-                       "runlevel\0" "reboot\0" "shutdown\0";
-       static const char _ut_lin[] ALIGN1 =
-                       "~\0" "{\0" "|\0" /* "LOGIN\0" "date\0" */;
-       enum {
-               TYPE_RUN_LVL = RUN_LVL,         /* 1 */
-               TYPE_BOOT_TIME = BOOT_TIME,     /* 2 */
-               TYPE_SHUTDOWN_TIME = SHUTDOWN_TIME
-       };
-       enum {
-               _TILDE = EMPTY, /* 0 */
-               TYPE_NEW_TIME,  /* NEW_TIME, 3 */
-               TYPE_OLD_TIME   /* OLD_TIME, 4 */
-       };
-
-       if (argv[1]) {
-               bb_show_usage();
-       }
-       file = xopen(bb_path_wtmp_file, O_RDONLY);
-
-       printf("%-10s %-14s %-18s %-12.12s %s\n",
-               "USER", "TTY", "HOST", "LOGIN", "TIME");
-       /* yikes. We reverse over the file and that is a not too elegant way */
-       pos = xlseek(file, 0, SEEK_END);
-       pos = lseek(file, pos - sizeof(ut), SEEK_SET);
-       while ((n = full_read(file, &ut, sizeof(ut))) > 0) {
-               if (n != sizeof(ut)) {
-                       bb_perror_msg_and_die("short read");
-               }
-               n = index_in_strings(_ut_lin, ut.ut_line);
-               if (n == _TILDE) { /* '~' */
-#if 1
-/* do we really need to be cautious here? */
-                       n = index_in_strings(_ut_usr, ut.ut_user);
-                       if (++n > 0)
-                               ut.ut_type = n != 3 ? n : SHUTDOWN_TIME;
-#else
-                       if (is_prefixed_with(ut.ut_user, "shutdown"))
-                               ut.ut_type = SHUTDOWN_TIME;
-                       else if (is_prefixed_with(ut.ut_user, "reboot"))
-                               ut.ut_type = BOOT_TIME;
-                       else if (is_prefixed_with(ut.ut_user, "runlevel"))
-                               ut.ut_type = RUN_LVL;
-#endif
-               } else {
-                       if (ut.ut_user[0] == '\0' || strcmp(ut.ut_user, "LOGIN") == 0) {
-                               /* Don't bother.  This means we can't find how long
-                                * someone was logged in for.  Oh well. */
-                               goto next;
-                       }
-                       if (ut.ut_type != DEAD_PROCESS
-                        && ut.ut_user[0]
-                        && ut.ut_line[0]
-                       ) {
-                               ut.ut_type = USER_PROCESS;
-                       }
-                       if (strcmp(ut.ut_user, "date") == 0) {
-                               if (n == TYPE_OLD_TIME) { /* '|' */
-                                       ut.ut_type = OLD_TIME;
-                               }
-                               if (n == TYPE_NEW_TIME) { /* '{' */
-                                       ut.ut_type = NEW_TIME;
-                               }
-                       }
-               }
-
-               if (ut.ut_type != USER_PROCESS) {
-                       switch (ut.ut_type) {
-                               case OLD_TIME:
-                               case NEW_TIME:
-                               case RUN_LVL:
-                               case SHUTDOWN_TIME:
-                                       goto next;
-                               case BOOT_TIME:
-                                       strcpy(ut.ut_line, "system boot");
-                       }
-               }
-               /* manpages say ut_tv.tv_sec *is* time_t,
-                * but some systems have it wrong */
-               t_tmp = (time_t)ut.ut_tv.tv_sec;
-               printf("%-10s %-14s %-18s %-12.12s\n",
-                       ut.ut_user, ut.ut_line, ut.ut_host, ctime(&t_tmp) + 4);
- next:
-               pos -= sizeof(ut);
-               if (pos <= 0)
-                       break; /* done. */
-               xlseek(file, pos, SEEK_SET);
-       }
-
-       fflush_stdout_and_exit(EXIT_SUCCESS);
-}
diff --git a/miscutils/last_fancy.c b/miscutils/last_fancy.c
deleted file mode 100644 (file)
index e56e0ba..0000000
+++ /dev/null
@@ -1,300 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * (sysvinit like) last implementation
- *
- * Copyright (C) 2008 by Patricia Muscalu <patricia.muscalu@axis.com>
- *
- * Licensed under GPLv2 or later, see file LICENSE in this source tree.
- */
-
-#include "libbb.h"
-
-/* NB: ut_name and ut_user are the same field, use only one name (ut_user)
- * to reduce confusion */
-
-#ifndef SHUTDOWN_TIME
-#  define SHUTDOWN_TIME 254
-#endif
-
-#define HEADER_FORMAT     "%-8.8s %-12.12s %-*.*s %-16.16s %-7.7s %s\n"
-#define HEADER_LINE       "USER", "TTY", \
-       INET_ADDRSTRLEN, INET_ADDRSTRLEN, "HOST", "LOGIN", "  TIME", ""
-#define HEADER_LINE_WIDE  "USER", "TTY", \
-       INET6_ADDRSTRLEN, INET6_ADDRSTRLEN, "HOST", "LOGIN", "  TIME", ""
-
-#if !defined __UT_LINESIZE && defined UT_LINESIZE
-# define __UT_LINESIZE UT_LINESIZE
-#endif
-
-enum {
-       NORMAL,
-       LOGGED,
-       DOWN,
-       REBOOT,
-       CRASH,
-       GONE
-};
-
-enum {
-       LAST_OPT_W = (1 << 0),  /* -W wide            */
-       LAST_OPT_f = (1 << 1),  /* -f input file      */
-       LAST_OPT_H = (1 << 2),  /* -H header          */
-};
-
-#define show_wide (option_mask32 & LAST_OPT_W)
-
-static void show_entry(struct utmpx *ut, int state, time_t dur_secs)
-{
-       unsigned days, hours, mins;
-       char duration[sizeof("(%u+02:02)") + sizeof(int)*3];
-       char login_time[17];
-       char logout_time[8];
-       const char *logout_str;
-       const char *duration_str;
-       time_t tmp;
-
-       /* manpages say ut_tv.tv_sec *is* time_t,
-        * but some systems have it wrong */
-       tmp = ut->ut_tv.tv_sec;
-       safe_strncpy(login_time, ctime(&tmp), 17);
-       tmp = dur_secs;
-       snprintf(logout_time, 8, "- %s", ctime(&tmp) + 11);
-
-       dur_secs = MAX(dur_secs - (time_t)ut->ut_tv.tv_sec, (time_t)0);
-       /* unsigned int is easier to divide than time_t (which may be signed long) */
-       mins = dur_secs / 60;
-       days = mins / (24*60);
-       mins = mins % (24*60);
-       hours = mins / 60;
-       mins = mins % 60;
-
-//     if (days) {
-               sprintf(duration, "(%u+%02u:%02u)", days, hours, mins);
-//     } else {
-//             sprintf(duration, " (%02u:%02u)", hours, mins);
-//     }
-
-       logout_str = logout_time;
-       duration_str = duration;
-       switch (state) {
-       case NORMAL:
-               break;
-       case LOGGED:
-               logout_str = "  still";
-               duration_str = "logged in";
-               break;
-       case DOWN:
-               logout_str = "- down ";
-               break;
-       case REBOOT:
-               break;
-       case CRASH:
-               logout_str = "- crash";
-               break;
-       case GONE:
-               logout_str = "   gone";
-               duration_str = "- no logout";
-               break;
-       }
-
-       printf(HEADER_FORMAT,
-               ut->ut_user,
-               ut->ut_line,
-               show_wide ? INET6_ADDRSTRLEN : INET_ADDRSTRLEN,
-               show_wide ? INET6_ADDRSTRLEN : INET_ADDRSTRLEN,
-               ut->ut_host,
-               login_time,
-               logout_str,
-               duration_str);
-}
-
-static int get_ut_type(struct utmpx *ut)
-{
-       if (ut->ut_line[0] == '~') {
-               if (strcmp(ut->ut_user, "shutdown") == 0) {
-                       return SHUTDOWN_TIME;
-               }
-               if (strcmp(ut->ut_user, "reboot") == 0) {
-                       return BOOT_TIME;
-               }
-               if (strcmp(ut->ut_user, "runlevel") == 0) {
-                       return RUN_LVL;
-               }
-               return ut->ut_type;
-       }
-
-       if (ut->ut_user[0] == 0) {
-               return DEAD_PROCESS;
-       }
-
-       if ((ut->ut_type != DEAD_PROCESS)
-        && (strcmp(ut->ut_user, "LOGIN") != 0)
-        && ut->ut_user[0]
-        && ut->ut_line[0]
-       ) {
-               ut->ut_type = USER_PROCESS;
-       }
-
-       if (strcmp(ut->ut_user, "date") == 0) {
-               if (ut->ut_line[0] == '|') {
-                       return OLD_TIME;
-               }
-               if (ut->ut_line[0] == '{') {
-                       return NEW_TIME;
-               }
-       }
-       return ut->ut_type;
-}
-
-static int is_runlevel_shutdown(struct utmpx *ut)
-{
-       if (((ut->ut_pid & 255) == '0') || ((ut->ut_pid & 255) == '6')) {
-               return 1;
-       }
-
-       return 0;
-}
-
-int last_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
-int last_main(int argc UNUSED_PARAM, char **argv)
-{
-       struct utmpx ut;
-       const char *filename = _PATH_WTMP;
-       llist_t *zlist;
-       off_t pos;
-       time_t start_time;
-       time_t boot_time;
-       time_t down_time;
-       int file;
-       smallint going_down;
-       smallint boot_down;
-
-       /*opt =*/ getopt32(argv, "Wf:" /* "H" */, &filename);
-#ifdef BUT_UTIL_LINUX_LAST_HAS_NO_SUCH_OPT
-       if (opt & LAST_OPT_H) {
-               /* Print header line */
-               if (opt & LAST_OPT_W) {
-                       printf(HEADER_FORMAT, HEADER_LINE_WIDE);
-               } else {
-                       printf(HEADER_FORMAT, HEADER_LINE);
-               }
-       }
-#endif
-
-       file = xopen(filename, O_RDONLY);
-       {
-               /* in case the file is empty... */
-               struct stat st;
-               fstat(file, &st);
-               start_time = st.st_ctime;
-       }
-
-       time(&down_time);
-       going_down = 0;
-       boot_down = NORMAL; /* 0 */
-       zlist = NULL;
-       boot_time = 0;
-       /* get file size, rounding down to last full record */
-       pos = xlseek(file, 0, SEEK_END) / sizeof(ut) * sizeof(ut);
-       for (;;) {
-               pos -= (off_t)sizeof(ut);
-               if (pos < 0) {
-                       /* Beyond the beginning of the file boundary =>
-                        * the whole file has been read. */
-                       break;
-               }
-               xlseek(file, pos, SEEK_SET);
-               xread(file, &ut, sizeof(ut));
-               /* rewritten by each record, eventially will have
-                * first record's ut_tv.tv_sec: */
-               start_time = ut.ut_tv.tv_sec;
-
-               switch (get_ut_type(&ut)) {
-               case SHUTDOWN_TIME:
-                       down_time = ut.ut_tv.tv_sec;
-                       boot_down = DOWN;
-                       going_down = 1;
-                       break;
-               case RUN_LVL:
-                       if (is_runlevel_shutdown(&ut)) {
-                               down_time = ut.ut_tv.tv_sec;
-                               going_down = 1;
-                               boot_down = DOWN;
-                       }
-                       break;
-               case BOOT_TIME:
-                       strcpy(ut.ut_line, "system boot");
-                       show_entry(&ut, REBOOT, down_time);
-                       boot_down = CRASH;
-                       going_down = 1;
-                       break;
-               case DEAD_PROCESS:
-                       if (!ut.ut_line[0]) {
-                               break;
-                       }
-                       /* add_entry */
-                       llist_add_to(&zlist, xmemdup(&ut, sizeof(ut)));
-                       break;
-               case USER_PROCESS: {
-                       int show;
-
-                       if (!ut.ut_line[0]) {
-                               break;
-                       }
-                       /* find_entry */
-                       show = 1;
-                       {
-                               llist_t *el, *next;
-                               for (el = zlist; el; el = next) {
-                                       struct utmpx *up = (struct utmpx *)el->data;
-                                       next = el->link;
-                                       if (strncmp(up->ut_line, ut.ut_line, __UT_LINESIZE) == 0) {
-                                               if (show) {
-                                                       show_entry(&ut, NORMAL, up->ut_tv.tv_sec);
-                                                       show = 0;
-                                               }
-                                               llist_unlink(&zlist, el);
-                                               free(el->data);
-                                               free(el);
-                                       }
-                               }
-                       }
-
-                       if (show) {
-                               int state = boot_down;
-
-                               if (boot_time == 0) {
-                                       state = LOGGED;
-                                       /* Check if the process is alive */
-                                       if ((ut.ut_pid > 0)
-                                        && (kill(ut.ut_pid, 0) != 0)
-                                        && (errno == ESRCH)) {
-                                               state = GONE;
-                                       }
-                               }
-                               show_entry(&ut, state, boot_time);
-                       }
-                       /* add_entry */
-                       llist_add_to(&zlist, xmemdup(&ut, sizeof(ut)));
-                       break;
-               }
-               }
-
-               if (going_down) {
-                       boot_time = ut.ut_tv.tv_sec;
-                       llist_free(zlist, free);
-                       zlist = NULL;
-                       going_down = 0;
-               }
-       }
-
-       if (ENABLE_FEATURE_CLEAN_UP) {
-               llist_free(zlist, free);
-       }
-
-       printf("\nwtmp begins %s", ctime(&start_time));
-
-       if (ENABLE_FEATURE_CLEAN_UP)
-               close(file);
-       fflush_stdout_and_exit(EXIT_SUCCESS);
-}
diff --git a/miscutils/mountpoint.c b/miscutils/mountpoint.c
deleted file mode 100644 (file)
index 8b9e1d7..0000000
+++ /dev/null
@@ -1,105 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * mountpoint implementation for busybox
- *
- * Copyright (C) 2005 Bernhard Reutner-Fischer
- *
- * Licensed under GPLv2 or later, see file LICENSE in this source tree.
- *
- * Based on sysvinit's mountpoint
- */
-//config:config MOUNTPOINT
-//config:      bool "mountpoint"
-//config:      default y
-//config:      help
-//config:        mountpoint checks if the directory is a mountpoint.
-
-//applet:IF_MOUNTPOINT(APPLET(mountpoint, BB_DIR_BIN, BB_SUID_DROP))
-
-//kbuild:lib-$(CONFIG_MOUNTPOINT) += mountpoint.o
-
-//usage:#define mountpoint_trivial_usage
-//usage:       "[-q] <[-dn] DIR | -x DEVICE>"
-//usage:#define mountpoint_full_usage "\n\n"
-//usage:       "Check if the directory is a mountpoint\n"
-//usage:     "\n       -q      Quiet"
-//usage:     "\n       -d      Print major/minor device number of the filesystem"
-//usage:     "\n       -n      Print device name of the filesystem"
-//usage:     "\n       -x      Print major/minor device number of the blockdevice"
-//usage:
-//usage:#define mountpoint_example_usage
-//usage:       "$ mountpoint /proc\n"
-//usage:       "/proc is not a mountpoint\n"
-//usage:       "$ mountpoint /sys\n"
-//usage:       "/sys is a mountpoint\n"
-
-#include "libbb.h"
-
-int mountpoint_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
-int mountpoint_main(int argc UNUSED_PARAM, char **argv)
-{
-       struct stat st;
-       const char *msg;
-       char *arg;
-       int rc, opt;
-
-       opt_complementary = "=1"; /* must have one argument */
-       opt = getopt32(argv, "qdxn");
-#define OPT_q (1)
-#define OPT_d (2)
-#define OPT_x (4)
-#define OPT_n (8)
-       arg = argv[optind];
-       msg = "%s";
-
-       rc = (opt & OPT_x) ? stat(arg, &st) : lstat(arg, &st);
-       if (rc != 0)
-               goto err;
-
-       if (opt & OPT_x) {
-               if (S_ISBLK(st.st_mode)) {
-                       printf("%u:%u\n", major(st.st_rdev),
-                                               minor(st.st_rdev));
-                       return EXIT_SUCCESS;
-               }
-               errno = 0; /* make perror_msg work as error_msg */
-               msg = "%s: not a block device";
-               goto err;
-       }
-
-       errno = ENOTDIR;
-       if (S_ISDIR(st.st_mode)) {
-               dev_t st_dev = st.st_dev;
-               ino_t st_ino = st.st_ino;
-               char *p = xasprintf("%s/..", arg);
-
-               if (stat(p, &st) == 0) {
-                       //int is_mnt = (st_dev != st.st_dev) || (st_dev == st.st_dev && st_ino == st.st_ino);
-                       int is_not_mnt = (st_dev == st.st_dev) && (st_ino != st.st_ino);
-
-                       if (opt & OPT_d)
-                               printf("%u:%u\n", major(st_dev), minor(st_dev));
-                       if (opt & OPT_n) {
-                               const char *d = find_block_device(arg);
-                               /* name is undefined, but device is mounted -> anonymous superblock! */
-                               /* happens with btrfs */
-                               if (!d) {
-                                       d = "UNKNOWN";
-                                       /* TODO: iterate /proc/mounts, or /proc/self/mountinfo
-                                        * to find out the device name */
-                               }
-                               printf("%s %s\n", d, arg);
-                       }
-                       if (!(opt & (OPT_q | OPT_d | OPT_n)))
-                               printf("%s is %sa mountpoint\n", arg, is_not_mnt ? "not " : "");
-                       return is_not_mnt;
-               }
-               arg = p;
-               /* else: stat had set errno, just fall through */
-       }
-
- err:
-       if (!(opt & OPT_q))
-               bb_perror_msg(msg, arg);
-       return EXIT_FAILURE;
-}
diff --git a/miscutils/setsid.c b/miscutils/setsid.c
deleted file mode 100644 (file)
index 143a8f8..0000000
+++ /dev/null
@@ -1,82 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * setsid.c -- execute a command in a new session
- * Rick Sladkey <jrs@world.std.com>
- * In the public domain.
- *
- * 1999-02-22 Arkadiusz Mickiewicz <misiek@pld.ORG.PL>
- * - added Native Language Support
- *
- * 2001-01-18 John Fremlin <vii@penguinpowered.com>
- * - fork in case we are process group leader
- *
- * 2004-11-12 Paul Fox
- * - busyboxed
- */
-//config:config SETSID
-//config:      bool "setsid"
-//config:      default y
-//config:      help
-//config:        setsid runs a program in a new session
-
-//applet:IF_SETSID(APPLET(setsid, BB_DIR_USR_BIN, BB_SUID_DROP))
-
-//kbuild:lib-$(CONFIG_SETSID) += setsid.o
-
-//usage:#define setsid_trivial_usage
-//usage:       "[-c] PROG ARGS"
-//usage:#define setsid_full_usage "\n\n"
-//usage:       "Run PROG in a new session. PROG will have no controlling terminal\n"
-//usage:       "and will not be affected by keyboard signals (^C etc).\n"
-//usage:     "\n       -c      Set controlling terminal to stdin"
-
-#include "libbb.h"
-
-int setsid_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
-int setsid_main(int argc UNUSED_PARAM, char **argv)
-{
-       unsigned opt;
-
-       opt_complementary = "-1"; /* at least one arg */
-       opt = getopt32(argv, "+c"); /* +: stop on first non-opt */
-       argv += optind;
-
-       /* setsid() is allowed only when we are not a process group leader.
-        * Otherwise our PID serves as PGID of some existing process group
-        * and cannot be used as PGID of a new process group.
-        *
-        * Example: setsid() below fails when run alone in interactive shell:
-        *  $ setsid PROG
-        * because shell's child (setsid) is put in a new process group.
-        * But doesn't fail if shell is not interactive
-        * (and therefore doesn't create process groups for pipes),
-        * or if setsid is not the first process in the process group:
-        *  $ true | setsid PROG
-        * or if setsid is executed in backquotes (`setsid PROG`)...
-        */
-       if (setsid() < 0) {
-               pid_t pid = fork_or_rexec(argv);
-               if (pid != 0) {
-                       /* parent */
-                       /* TODO:
-                        * we can waitpid(pid, &status, 0) and then even
-                        * emulate exitcode, making the behavior consistent
-                        * in both forked and non forked cases.
-                        * However, the code is larger and upstream
-                        * does not do such trick.
-                        */
-                       return EXIT_SUCCESS;
-               }
-
-               /* child */
-               /* now there should be no error: */
-               setsid();
-       }
-
-       if (opt) {
-               /* -c: set (with stealing) controlling tty */
-               ioctl(0, TIOCSCTTY, 1);
-       }
-
-       BB_EXECVP_or_die(argv);
-}
diff --git a/miscutils/taskset.c b/miscutils/taskset.c
deleted file mode 100644 (file)
index 94a0738..0000000
+++ /dev/null
@@ -1,221 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * taskset - retrieve or set a processes' CPU affinity
- * Copyright (c) 2006 Bernhard Reutner-Fischer
- *
- * Licensed under GPLv2 or later, see file LICENSE in this source tree.
- */
-
-//config:config TASKSET
-//config:      bool "taskset"
-//config:      default y
-//config:      help
-//config:        Retrieve or set a processes's CPU affinity.
-//config:        This requires sched_{g,s}etaffinity support in your libc.
-//config:
-//config:config FEATURE_TASKSET_FANCY
-//config:      bool "Fancy output"
-//config:      default y
-//config:      depends on TASKSET
-//config:      help
-//config:        Needed for machines with more than 32-64 CPUs:
-//config:        affinity parameter 0xHHHHHHHHHHHHHHHHHHHH can be arbitrarily long
-//config:        in this case. Otherwise, it is limited to sizeof(long).
-
-//applet:IF_TASKSET(APPLET(taskset, BB_DIR_USR_BIN, BB_SUID_DROP))
-//kbuild:lib-$(CONFIG_TASKSET) += taskset.o
-
-//usage:#define taskset_trivial_usage
-//usage:       "[-p] [HEXMASK] PID | PROG ARGS"
-//usage:#define taskset_full_usage "\n\n"
-//usage:       "Set or get CPU affinity\n"
-//usage:     "\n       -p      Operate on an existing PID"
-//usage:
-//usage:#define taskset_example_usage
-//usage:       "$ taskset 0x7 ./dgemm_test&\n"
-//usage:       "$ taskset -p 0x1 $!\n"
-//usage:       "pid 4790's current affinity mask: 7\n"
-//usage:       "pid 4790's new affinity mask: 1\n"
-//usage:       "$ taskset 0x7 /bin/sh -c './taskset -p 0x1 $$'\n"
-//usage:       "pid 6671's current affinity mask: 1\n"
-//usage:       "pid 6671's new affinity mask: 1\n"
-//usage:       "$ taskset -p 1\n"
-//usage:       "pid 1's current affinity mask: 3\n"
-/*
- * Not yet implemented:
- * -a/--all-tasks (affect all threads)
- *     needs to get TIDs from /proc/PID/task/ and use _them_ as "pid" in sched_setaffinity(pid)
- * -c/--cpu-list  (specify CPUs via "1,3,5-7")
- */
-
-#include <sched.h>
-#include "libbb.h"
-
-typedef unsigned long ul;
-#define SZOF_UL (unsigned)(sizeof(ul))
-#define BITS_UL (unsigned)(sizeof(ul)*8)
-#define MASK_UL (unsigned)(sizeof(ul)*8 - 1)
-
-#if ENABLE_FEATURE_TASKSET_FANCY
-#define TASKSET_PRINTF_MASK "%s"
-/* craft a string from the mask */
-static char *from_mask(const ul *mask, unsigned sz_in_bytes)
-{
-       char *str = xzalloc((sz_in_bytes+1) * 2); /* we will leak it */
-       char *p = str;
-       for (;;) {
-               ul v = *mask++;
-               if (SZOF_UL == 4)
-                       p += sprintf(p, "%08lx", v);
-               if (SZOF_UL == 8)
-                       p += sprintf(p, "%016lx", v);
-               if (SZOF_UL == 16)
-                       p += sprintf(p, "%032lx", v); /* :) */
-               sz_in_bytes -= SZOF_UL;
-               if ((int)sz_in_bytes <= 0)
-                       break;
-       }
-       while (str[0] == '0' && str[1])
-               str++;
-       return str;
-}
-#else
-#define TASKSET_PRINTF_MASK "%lx"
-static unsigned long long from_mask(ul *mask, unsigned sz_in_bytes UNUSED_PARAM)
-{
-       return *mask;
-}
-#endif
-
-static unsigned long *get_aff(int pid, unsigned *sz)
-{
-       int r;
-       unsigned long *mask = NULL;
-       unsigned sz_in_bytes = *sz;
-
-       for (;;) {
-               mask = xrealloc(mask, sz_in_bytes);
-               r = sched_getaffinity(pid, sz_in_bytes, (void*)mask);
-               if (r == 0)
-                       break;
-               sz_in_bytes *= 2;
-               if (errno == EINVAL && (int)sz_in_bytes > 0)
-                       continue;
-               bb_perror_msg_and_die("can't %cet pid %d's affinity", 'g', pid);
-       }
-       //bb_error_msg("get mask[0]:%lx sz_in_bytes:%d", mask[0], sz_in_bytes);
-       *sz = sz_in_bytes;
-       return mask;
-}
-
-int taskset_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
-int taskset_main(int argc UNUSED_PARAM, char **argv)
-{
-       ul *mask;
-       unsigned mask_size_in_bytes;
-       pid_t pid = 0;
-       unsigned opt_p;
-       const char *current_new;
-       char *aff;
-
-       /* NB: we mimic util-linux's taskset: -p does not take
-        * an argument, i.e., "-pN" is NOT valid, only "-p N"!
-        * Indeed, util-linux-2.13-pre7 uses:
-        * getopt_long(argc, argv, "+pchV", ...), not "...p:..." */
-
-       opt_complementary = "-1"; /* at least 1 arg */
-       opt_p = getopt32(argv, "+p");
-       argv += optind;
-
-       aff = *argv++;
-       if (opt_p) {
-               char *pid_str = aff;
-               if (*argv) { /* "-p <aff> <pid> ...rest.is.ignored..." */
-                       pid_str = *argv; /* NB: *argv != NULL in this case */
-               }
-               /* else it was just "-p <pid>", and *argv == NULL */
-               pid = xatoul_range(pid_str, 1, ((unsigned)(pid_t)ULONG_MAX) >> 1);
-       } else {
-               /* <aff> <cmd...> */
-               if (!*argv)
-                       bb_show_usage();
-       }
-
-       mask_size_in_bytes = SZOF_UL;
-       current_new = "current";
- print_aff:
-       mask = get_aff(pid, &mask_size_in_bytes);
-       if (opt_p) {
-               printf("pid %d's %s affinity mask: "TASKSET_PRINTF_MASK"\n",
-                               pid, current_new, from_mask(mask, mask_size_in_bytes));
-               if (*argv == NULL) {
-                       /* Either it was just "-p <pid>",
-                        * or it was "-p <aff> <pid>" and we came here
-                        * for the second time (see goto below) */
-                       return EXIT_SUCCESS;
-               }
-               *argv = NULL;
-               current_new = "new";
-       }
-       memset(mask, 0, mask_size_in_bytes);
-
-       /* Affinity was specified, translate it into mask */
-       /* it is always in hex, skip "0x" if it exists */
-       if (aff[0] == '0' && (aff[1]|0x20) == 'x')
-               aff += 2;
-
-       if (!ENABLE_FEATURE_TASKSET_FANCY) {
-               mask[0] = xstrtoul(aff, 16);
-       } else {
-               unsigned i;
-               char *last_char;
-
-               i = 0; /* bit pos in mask[] */
-
-               /* aff is ASCII hex string, accept very long masks in this form.
-                * Process hex string AABBCCDD... to ulong mask[]
-                * from the rightmost nibble, which is least-significant.
-                * Bits not fitting into mask[] are ignored: (example: 1234
-                * in 12340000000000000000000000000000000000000ff)
-                */
-               last_char = strchrnul(aff, '\0');
-               while (last_char > aff) {
-                       char c;
-                       ul val;
-
-                       last_char--;
-                       c = *last_char;
-                       if (isdigit(c))
-                               val = c - '0';
-                       else if ((c|0x20) >= 'a' && (c|0x20) <= 'f')
-                               val = (c|0x20) - ('a' - 10);
-                       else
-                               bb_error_msg_and_die("bad affinity '%s'", aff);
-
-                       if (i < mask_size_in_bytes * 8) {
-                               mask[i / BITS_UL] |= val << (i & MASK_UL);
-                               //bb_error_msg("bit %d set", i);
-                       }
-                       /* else:
-                        * We can error out here, but we don't.
-                        * For one, kernel itself ignores bits in mask[]
-                        * which do not map to any CPUs:
-                        * if mask[] has one 32-bit long element,
-                        * but you have only 8 CPUs, all bits beyond first 8
-                        * are ignored, silently.
-                        * No point in making bits past 31th to be errors.
-                        */
-                       i += 4;
-               }
-       }
-
-       /* Set pid's or our own (pid==0) affinity */
-       if (sched_setaffinity(pid, mask_size_in_bytes, (void*)mask))
-               bb_perror_msg_and_die("can't %cet pid %d's affinity", 's', pid);
-       //bb_error_msg("set mask[0]:%lx", mask[0]);
-
-       if (!argv[0]) /* "-p <aff> <pid> [...ignored...]" */
-               goto print_aff; /* print new affinity and exit */
-
-       BB_EXECVP_or_die(argv);
-}
diff --git a/miscutils/timeout.c b/miscutils/timeout.c
deleted file mode 100644 (file)
index f29dc8a..0000000
+++ /dev/null
@@ -1,127 +0,0 @@
-/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
- * COPYING NOTES
- *
- * timeout.c -- a timeout handler for shell commands
- *
- * Copyright (C) 2005-6, Roberto A. Foglietta <me@roberto.foglietta.name>
- *
- *   This program is free software; you can redistribute it and/or modify
- *   it under the terms of the GNU General Public License as published by
- *   the Free Software Foundation; version 2 of the License.
- *
- *   This program is distributed in the hope that it will be useful,
- *   but WITHOUT ANY WARRANTY; without even the implied warranty of
- *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *   GNU General Public License for more details.
- *
- *   You should have received a copy of the GNU General Public License
- *   along with this program; if not, write to the Free Software
- *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
- */
-/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
- * REVISION NOTES:
- * released 17-11-2005 by Roberto A. Foglietta
- * talarm   04-12-2005 by Roberto A. Foglietta
- * modified 05-12-2005 by Roberto A. Foglietta
- * sizerdct 06-12-2005 by Roberto A. Foglietta
- * splitszf 12-05-2006 by Roberto A. Foglietta
- * rewrite  14-11-2008 vda
- */
-//config:config TIMEOUT
-//config:      bool "timeout"
-//config:      default y
-//config:      help
-//config:        Runs a program and watches it. If it does not terminate in
-//config:        specified number of seconds, it is sent a signal.
-
-//applet:IF_TIMEOUT(APPLET(timeout, BB_DIR_USR_BIN, BB_SUID_DROP))
-
-//kbuild:lib-$(CONFIG_TIMEOUT) += timeout.o
-
-//usage:#define timeout_trivial_usage
-//usage:       "[-t SECS] [-s SIG] PROG ARGS"
-//usage:#define timeout_full_usage "\n\n"
-//usage:       "Runs PROG. Sends SIG to it if it is not gone in SECS seconds.\n"
-//usage:       "Defaults: SECS: 10, SIG: TERM."
-
-#include "libbb.h"
-
-int timeout_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
-int timeout_main(int argc UNUSED_PARAM, char **argv)
-{
-       int signo;
-       int status;
-       int parent = 0;
-       int timeout = 10;
-       pid_t pid;
-#if !BB_MMU
-       char *sv1, *sv2;
-#endif
-       const char *opt_s = "TERM";
-
-       /* -p option is not documented, it is needed to support NOMMU. */
-
-       /* -t SECONDS; -p PARENT_PID */
-       /* '+': stop at first non-option */
-       getopt32(argv, "+s:t:+" USE_FOR_NOMMU("p:+"), &opt_s, &timeout, &parent);
-       /*argv += optind; - no, wait for bb_daemonize_or_rexec! */
-       signo = get_signum(opt_s);
-       if (signo < 0)
-               bb_error_msg_and_die("unknown signal '%s'", opt_s);
-
-       /* We want to create a grandchild which will watch
-        * and kill the grandparent. Other methods:
-        * making parent watch child disrupts parent<->child link
-        * (example: "tcpsvd 0.0.0.0 1234 timeout service_prog" -
-        * it's better if service_prog is a child of tcpsvd!),
-        * making child watch parent results in programs having
-        * unexpected children. */
-
-       if (parent) /* we were re-execed, already grandchild */
-               goto grandchild;
-       if (!argv[optind]) /* no PROG? */
-               bb_show_usage();
-
-#if !BB_MMU
-       sv1 = argv[optind];
-       sv2 = argv[optind + 1];
-#endif
-       pid = xvfork();
-       if (pid == 0) {
-               /* Child: spawn grandchild and exit */
-               parent = getppid();
-#if !BB_MMU
-               argv[optind] = xasprintf("-p%u", parent);
-               argv[optind + 1] = NULL;
-#endif
-               /* NB: exits with nonzero on error: */
-               bb_daemonize_or_rexec(0, argv);
-               /* Here we are grandchild. Sleep, then kill grandparent */
- grandchild:
-               /* Just sleep(HUGE_NUM); kill(parent) may kill wrong process! */
-               while (1) {
-                       sleep(1);
-                       if (--timeout <= 0)
-                               break;
-                       if (kill(parent, 0)) {
-                               /* process is gone */
-                               return EXIT_SUCCESS;
-                       }
-               }
-               kill(parent, signo);
-               return EXIT_SUCCESS;
-       }
-
-       /* Parent */
-       wait(&status); /* wait for child to die */
-       /* Did intermediate [v]fork or exec fail? */
-       if (!WIFEXITED(status) || WEXITSTATUS(status) != 0)
-               return EXIT_FAILURE;
-       /* Ok, exec a program as requested */
-       argv += optind;
-#if !BB_MMU
-       argv[0] = sv1;
-       argv[1] = sv2;
-#endif
-       BB_EXECVP_or_die(argv);
-}
diff --git a/miscutils/wall.c b/miscutils/wall.c
deleted file mode 100644 (file)
index 50658f4..0000000
+++ /dev/null
@@ -1,63 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * wall - write a message to all logged-in users
- * Copyright (c) 2009 Bernhard Reutner-Fischer
- *
- * Licensed under GPLv2 or later, see file LICENSE in this source tree.
- */
-
-//config:config WALL
-//config:      bool "wall"
-//config:      default y
-//config:      depends on FEATURE_UTMP
-//config:      help
-//config:        Write a message to all users that are logged in.
-
-/* Needs to be run by root or be suid root - needs to write to /dev/TTY: */
-//applet:IF_WALL(APPLET(wall, BB_DIR_USR_BIN, BB_SUID_REQUIRE))
-
-//kbuild:lib-$(CONFIG_WALL) += wall.o
-
-//usage:#define wall_trivial_usage
-//usage:       "[FILE]"
-//usage:#define wall_full_usage "\n\n"
-//usage:       "Write content of FILE or stdin to all logged-in users"
-//usage:
-//usage:#define wall_sample_usage
-//usage:       "echo foo | wall\n"
-//usage:       "wall ./mymessage"
-
-#include "libbb.h"
-
-int wall_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
-int wall_main(int argc UNUSED_PARAM, char **argv)
-{
-       struct utmpx *ut;
-       char *msg;
-       int fd;
-
-       fd = STDIN_FILENO;
-       if (argv[1]) {
-               /* The applet is setuid.
-                * Access to the file must be under user's uid/gid.
-                */
-               fd = xopen_as_uid_gid(argv[1], O_RDONLY, getuid(), getgid());
-       }
-       msg = xmalloc_read(fd, NULL);
-       if (ENABLE_FEATURE_CLEAN_UP && argv[1])
-               close(fd);
-       setutxent();
-       while ((ut = getutxent()) != NULL) {
-               char *line;
-               if (ut->ut_type != USER_PROCESS)
-                       continue;
-               line = concat_path_file("/dev", ut->ut_line);
-               xopen_xwrite_close(line, msg);
-               free(line);
-       }
-       if (ENABLE_FEATURE_CLEAN_UP) {
-               endutxent();
-               free(msg);
-       }
-       return EXIT_SUCCESS;
-}
diff --git a/util-linux/chrt.c b/util-linux/chrt.c
new file mode 100644 (file)
index 0000000..1604a68
--- /dev/null
@@ -0,0 +1,149 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * chrt - manipulate real-time attributes of a process
+ * Copyright (c) 2006-2007 Bernhard Reutner-Fischer
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this source tree.
+ */
+//config:config CHRT
+//config:      bool "chrt"
+//config:      default y
+//config:      help
+//config:        manipulate real-time attributes of a process.
+//config:        This requires sched_{g,s}etparam support in your libc.
+
+//applet:IF_CHRT(APPLET(chrt, BB_DIR_USR_BIN, BB_SUID_DROP))
+
+//kbuild:lib-$(CONFIG_CHRT) += chrt.o
+
+//usage:#define chrt_trivial_usage
+//usage:       "[-prfom] [PRIO] [PID | PROG ARGS]"
+//usage:#define chrt_full_usage "\n\n"
+//usage:       "Change scheduling priority and class for a process\n"
+//usage:     "\n       -p      Operate on PID"
+//usage:     "\n       -r      Set SCHED_RR class"
+//usage:     "\n       -f      Set SCHED_FIFO class"
+//usage:     "\n       -o      Set SCHED_OTHER class"
+//usage:     "\n       -m      Show min/max priorities"
+//usage:
+//usage:#define chrt_example_usage
+//usage:       "$ chrt -r 4 sleep 900; x=$!\n"
+//usage:       "$ chrt -f -p 3 $x\n"
+//usage:       "You need CAP_SYS_NICE privileges to set scheduling attributes of a process"
+
+#include <sched.h>
+#include "libbb.h"
+
+static const struct {
+       int policy;
+       char name[sizeof("SCHED_OTHER")];
+} policies[] = {
+       {SCHED_OTHER, "SCHED_OTHER"},
+       {SCHED_FIFO, "SCHED_FIFO"},
+       {SCHED_RR, "SCHED_RR"}
+};
+
+//TODO: add
+// -b, SCHED_BATCH
+// -i, SCHED_IDLE
+
+static void show_min_max(int pol)
+{
+       const char *fmt = "%s min/max priority\t: %u/%u\n";
+       int max, min;
+
+       max = sched_get_priority_max(pol);
+       min = sched_get_priority_min(pol);
+       if ((max|min) < 0)
+               fmt = "%s not supported\n";
+       printf(fmt, policies[pol].name, min, max);
+}
+
+#define OPT_m (1<<0)
+#define OPT_p (1<<1)
+#define OPT_r (1<<2)
+#define OPT_f (1<<3)
+#define OPT_o (1<<4)
+
+int chrt_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int chrt_main(int argc UNUSED_PARAM, char **argv)
+{
+       pid_t pid = 0;
+       unsigned opt;
+       struct sched_param sp;
+       char *pid_str;
+       char *priority = priority; /* for compiler */
+       const char *current_new;
+       int policy = SCHED_RR;
+
+       /* only one policy accepted */
+       opt_complementary = "r--fo:f--ro:o--rf";
+       opt = getopt32(argv, "+mprfo");
+       if (opt & OPT_m) { /* print min/max and exit */
+               show_min_max(SCHED_FIFO);
+               show_min_max(SCHED_RR);
+               show_min_max(SCHED_OTHER);
+               fflush_stdout_and_exit(EXIT_SUCCESS);
+       }
+       if (opt & OPT_r)
+               policy = SCHED_RR;
+       if (opt & OPT_f)
+               policy = SCHED_FIFO;
+       if (opt & OPT_o)
+               policy = SCHED_OTHER;
+
+       argv += optind;
+       if (!argv[0])
+               bb_show_usage();
+       if (opt & OPT_p) {
+               pid_str = *argv++;
+               if (*argv) { /* "-p <priority> <pid> [...]" */
+                       priority = pid_str;
+                       pid_str = *argv;
+               }
+               /* else "-p <pid>", and *argv == NULL */
+               pid = xatoul_range(pid_str, 1, ((unsigned)(pid_t)ULONG_MAX) >> 1);
+       } else {
+               priority = *argv++;
+               if (!*argv)
+                       bb_show_usage();
+       }
+
+       current_new = "current\0new";
+       if (opt & OPT_p) {
+               int pol;
+ print_rt_info:
+               pol = sched_getscheduler(pid);
+               if (pol < 0)
+                       bb_perror_msg_and_die("can't %cet pid %d's policy", 'g', (int)pid);
+               printf("pid %d's %s scheduling policy: %s\n",
+                               pid, current_new, policies[pol].name);
+               if (sched_getparam(pid, &sp))
+                       bb_perror_msg_and_die("can't get pid %d's attributes", (int)pid);
+               printf("pid %d's %s scheduling priority: %d\n",
+                               (int)pid, current_new, sp.sched_priority);
+               if (!*argv) {
+                       /* Either it was just "-p <pid>",
+                        * or it was "-p <priority> <pid>" and we came here
+                        * for the second time (see goto below) */
+                       return EXIT_SUCCESS;
+               }
+               *argv = NULL;
+               current_new += 8;
+       }
+
+       /* from the manpage of sched_getscheduler:
+       [...] sched_priority can have a value in the range 0 to 99.
+       [...] SCHED_OTHER or SCHED_BATCH must be assigned static priority 0.
+       [...] SCHED_FIFO or SCHED_RR can have static priority in 1..99 range.
+       */
+       sp.sched_priority = xstrtou_range(priority, 0, policy != SCHED_OTHER ? 1 : 0, 99);
+
+       if (sched_setscheduler(pid, policy, &sp) < 0)
+               bb_perror_msg_and_die("can't %cet pid %d's policy", 's', (int)pid);
+
+       if (!argv[0]) /* "-p <priority> <pid> [...]" */
+               goto print_rt_info;
+
+       BB_EXECVP_or_die(argv);
+}
diff --git a/util-linux/eject.c b/util-linux/eject.c
new file mode 100644 (file)
index 0000000..667932f
--- /dev/null
@@ -0,0 +1,152 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * eject implementation for busybox
+ *
+ * Copyright (C) 2004  Peter Willis <psyphreak@phreaker.net>
+ * Copyright (C) 2005  Tito Ragusa <farmatito@tiscali.it>
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this source tree.
+ */
+
+/*
+ * This is a simple hack of eject based on something Erik posted in #uclibc.
+ * Most of the dirty work blatantly ripped off from cat.c =)
+ */
+//config:config EJECT
+//config:      bool "eject"
+//config:      default y
+//config:      select PLATFORM_LINUX
+//config:      help
+//config:        Used to eject cdroms. (defaults to /dev/cdrom)
+//config:
+//config:config FEATURE_EJECT_SCSI
+//config:      bool "SCSI support"
+//config:      default y
+//config:      depends on EJECT
+//config:      help
+//config:        Add the -s option to eject, this allows to eject SCSI-Devices and
+//config:        usb-storage devices.
+
+//applet:IF_EJECT(APPLET(eject, BB_DIR_USR_BIN, BB_SUID_DROP))
+
+//kbuild:lib-$(CONFIG_EJECT) += eject.o
+
+//usage:#define eject_trivial_usage
+//usage:       "[-t] [-T] [DEVICE]"
+//usage:#define eject_full_usage "\n\n"
+//usage:       "Eject DEVICE or default /dev/cdrom\n"
+//usage:       IF_FEATURE_EJECT_SCSI(
+//usage:     "\n       -s      SCSI device"
+//usage:       )
+//usage:     "\n       -t      Close tray"
+//usage:     "\n       -T      Open/close tray (toggle)"
+
+#include <sys/mount.h>
+#include "libbb.h"
+#if ENABLE_FEATURE_EJECT_SCSI
+/* Must be after libbb.h: they need size_t */
+# include "fix_u32.h"
+# include <scsi/sg.h>
+# include <scsi/scsi.h>
+#endif
+
+#define dev_fd 3
+
+/* Code taken from the original eject (http://eject.sourceforge.net/),
+ * refactored it a bit for busybox (ne-bb@nicoerfurth.de) */
+
+#if ENABLE_FEATURE_EJECT_SCSI
+static void eject_scsi(const char *dev)
+{
+       static const char sg_commands[3][6] ALIGN1 = {
+               { ALLOW_MEDIUM_REMOVAL, 0, 0, 0, 0, 0 },
+               { START_STOP, 0, 0, 0, 1, 0 },
+               { START_STOP, 0, 0, 0, 2, 0 }
+       };
+
+       unsigned i;
+       unsigned char sense_buffer[32];
+       unsigned char inqBuff[2];
+       sg_io_hdr_t io_hdr;
+
+       if ((ioctl(dev_fd, SG_GET_VERSION_NUM, &i) < 0) || (i < 30000))
+               bb_error_msg_and_die("not a sg device or old sg driver");
+
+       memset(&io_hdr, 0, sizeof(sg_io_hdr_t));
+       io_hdr.interface_id = 'S';
+       io_hdr.cmd_len = 6;
+       io_hdr.mx_sb_len = sizeof(sense_buffer);
+       io_hdr.dxfer_direction = SG_DXFER_NONE;
+       /* io_hdr.dxfer_len = 0; */
+       io_hdr.dxferp = inqBuff;
+       io_hdr.sbp = sense_buffer;
+       io_hdr.timeout = 2000;
+
+       for (i = 0; i < 3; i++) {
+               io_hdr.cmdp = (void *)sg_commands[i];
+               ioctl_or_perror_and_die(dev_fd, SG_IO, (void *)&io_hdr, "%s", dev);
+       }
+
+       /* force kernel to reread partition table when new disc is inserted */
+       ioctl(dev_fd, BLKRRPART);
+}
+#else
+# define eject_scsi(dev) ((void)0)
+#endif
+
+/* various defines swiped from linux/cdrom.h */
+#define CDROMCLOSETRAY            0x5319  /* pendant of CDROMEJECT  */
+#define CDROMEJECT                0x5309  /* Ejects the cdrom media */
+#define CDROM_DRIVE_STATUS        0x5326  /* Get tray position, etc. */
+/* drive status possibilities returned by CDROM_DRIVE_STATUS ioctl */
+#define CDS_TRAY_OPEN        2
+
+#define FLAG_CLOSE  1
+#define FLAG_SMART  2
+#define FLAG_SCSI   4
+
+static void eject_cdrom(unsigned flags, const char *dev)
+{
+       int cmd = CDROMEJECT;
+
+       if (flags & FLAG_CLOSE
+        || ((flags & FLAG_SMART) && ioctl(dev_fd, CDROM_DRIVE_STATUS) == CDS_TRAY_OPEN)
+       ) {
+               cmd = CDROMCLOSETRAY;
+       }
+
+       ioctl_or_perror_and_die(dev_fd, cmd, NULL, "%s", dev);
+}
+
+int eject_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int eject_main(int argc UNUSED_PARAM, char **argv)
+{
+       unsigned flags;
+       const char *device;
+
+       opt_complementary = "?1:t--T:T--t";
+       flags = getopt32(argv, "tT" IF_FEATURE_EJECT_SCSI("s"));
+       device = argv[optind] ? argv[optind] : "/dev/cdrom";
+
+       /* We used to do "umount <device>" here, but it was buggy
+          if something was mounted OVER cdrom and
+          if cdrom is mounted many times.
+
+          This works equally well (or better):
+          #!/bin/sh
+          umount /dev/cdrom
+          eject /dev/cdrom
+       */
+
+       xmove_fd(xopen_nonblocking(device), dev_fd);
+
+       if (ENABLE_FEATURE_EJECT_SCSI && (flags & FLAG_SCSI))
+               eject_scsi(device);
+       else
+               eject_cdrom(flags, device);
+
+       if (ENABLE_FEATURE_CLEAN_UP)
+               close(dev_fd);
+
+       return EXIT_SUCCESS;
+}
diff --git a/util-linux/ionice.c b/util-linux/ionice.c
new file mode 100644 (file)
index 0000000..c54b3a6
--- /dev/null
@@ -0,0 +1,115 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * ionice implementation for busybox based on linux-utils-ng 2.14
+ *
+ * Copyright (C) 2008 by  <u173034@informatik.uni-oldenburg.de>
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this source tree.
+ */
+//config:config IONICE
+//config:      bool "ionice"
+//config:      default y
+//config:      select PLATFORM_LINUX
+//config:      help
+//config:        Set/set program io scheduling class and priority
+//config:        Requires kernel >= 2.6.13
+
+//applet:IF_IONICE(APPLET(ionice, BB_DIR_BIN, BB_SUID_DROP))
+
+//kbuild:lib-$(CONFIG_IONICE) += ionice.o
+
+//usage:#define ionice_trivial_usage
+//usage:       "[-c 1-3] [-n 0-7] [-p PID] [PROG]"
+//usage:#define ionice_full_usage "\n\n"
+//usage:       "Change I/O priority and class\n"
+//usage:     "\n       -c      Class. 1:realtime 2:best-effort 3:idle"
+//usage:     "\n       -n      Priority"
+
+#include <sys/syscall.h>
+#include <asm/unistd.h>
+#include "libbb.h"
+
+static int ioprio_set(int which, int who, int ioprio)
+{
+       return syscall(SYS_ioprio_set, which, who, ioprio);
+}
+
+static int ioprio_get(int which, int who)
+{
+       return syscall(SYS_ioprio_get, which, who);
+}
+
+enum {
+       IOPRIO_WHO_PROCESS = 1,
+       IOPRIO_WHO_PGRP,
+       IOPRIO_WHO_USER
+};
+
+enum {
+       IOPRIO_CLASS_NONE,
+       IOPRIO_CLASS_RT,
+       IOPRIO_CLASS_BE,
+       IOPRIO_CLASS_IDLE
+};
+
+static const char to_prio[] ALIGN1 = "none\0realtime\0best-effort\0idle";
+
+#define IOPRIO_CLASS_SHIFT      13
+
+int ionice_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int ionice_main(int argc UNUSED_PARAM, char **argv)
+{
+       /* Defaults */
+       int ioclass = 0;
+       int pri = 0;
+       int pid = 0; /* affect own porcess */
+       int opt;
+       enum {
+               OPT_n = 1,
+               OPT_c = 2,
+               OPT_p = 4,
+       };
+
+       /* Numeric params */
+       /* '+': stop at first non-option */
+       opt = getopt32(argv, "+n:+c:+p:+", &pri, &ioclass, &pid);
+       argv += optind;
+
+       if (opt & OPT_c) {
+               if (ioclass > 3)
+                       bb_error_msg_and_die("bad class %d", ioclass);
+// Do we need this (compat?)?
+//             if (ioclass == IOPRIO_CLASS_NONE)
+//                     ioclass = IOPRIO_CLASS_BE;
+//             if (ioclass == IOPRIO_CLASS_IDLE) {
+//                     //if (opt & OPT_n)
+//                     //      bb_error_msg("ignoring priority for idle class");
+//                     pri = 7;
+//             }
+       }
+
+       if (!(opt & (OPT_n|OPT_c))) {
+               if (!(opt & OPT_p) && *argv)
+                       pid = xatoi_positive(*argv);
+
+               pri = ioprio_get(IOPRIO_WHO_PROCESS, pid);
+               if (pri == -1)
+                       bb_perror_msg_and_die("ioprio_%cet", 'g');
+
+               ioclass = (pri >> IOPRIO_CLASS_SHIFT) & 0x3;
+               pri &= 0xff;
+               printf((ioclass == IOPRIO_CLASS_IDLE) ? "%s\n" : "%s: prio %d\n",
+                               nth_string(to_prio, ioclass), pri);
+       } else {
+//printf("pri=%d class=%d val=%x\n",
+//pri, ioclass, pri | (ioclass << IOPRIO_CLASS_SHIFT));
+               pri |= (ioclass << IOPRIO_CLASS_SHIFT);
+               if (ioprio_set(IOPRIO_WHO_PROCESS, pid, pri) == -1)
+                       bb_perror_msg_and_die("ioprio_%cet", 's');
+               if (argv[0]) {
+                       BB_EXECVP_or_die(argv);
+               }
+       }
+
+       return EXIT_SUCCESS;
+}
diff --git a/util-linux/last.c b/util-linux/last.c
new file mode 100644 (file)
index 0000000..b3f125c
--- /dev/null
@@ -0,0 +1,166 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * last implementation for busybox
+ *
+ * Copyright (C) 2003-2004 by Erik Andersen <andersen@codepoet.org>
+ *
+ * Licensed under GPLv2, see file LICENSE in this source tree.
+ */
+//config:config LAST
+//config:      bool "last"
+//config:      default y
+//config:      depends on FEATURE_WTMP
+//config:      help
+//config:        'last' displays a list of the last users that logged into the system.
+//config:
+//config:config FEATURE_LAST_FANCY
+//config:      bool "Output extra information"
+//config:      default y
+//config:      depends on LAST
+//config:      help
+//config:        'last' displays detailed information about the last users that
+//config:        logged into the system (mimics sysvinit last). +900 bytes.
+
+//applet:IF_LAST(APPLET(last, BB_DIR_USR_BIN, BB_SUID_DROP))
+
+//kbuild:ifeq ($(CONFIG_FEATURE_LAST_FANCY),y)
+//kbuild:lib-$(CONFIG_FEATURE_LAST_FANCY) += last_fancy.o
+//kbuild:else
+//kbuild:lib-$(CONFIG_LAST) += last.o
+//kbuild:endif
+
+//usage:#define last_trivial_usage
+//usage:       ""IF_FEATURE_LAST_FANCY("[-HW] [-f FILE]")
+//usage:#define last_full_usage "\n\n"
+//usage:       "Show listing of the last users that logged into the system"
+//usage:       IF_FEATURE_LAST_FANCY( "\n"
+/* //usage:  "\n       -H      Show header line" */
+//usage:     "\n       -W      Display with no host column truncation"
+//usage:     "\n       -f FILE Read from FILE instead of /var/log/wtmp"
+//usage:       )
+
+#include "libbb.h"
+
+/* NB: ut_name and ut_user are the same field, use only one name (ut_user)
+ * to reduce confusion */
+
+#ifndef SHUTDOWN_TIME
+#  define SHUTDOWN_TIME 254
+#endif
+
+/* Grr... utmp char[] members do not have to be nul-terminated.
+ * Do what we can while still keeping this reasonably small.
+ * Note: We are assuming the ut_id[] size is fixed at 4. */
+
+#if defined UT_LINESIZE \
+       && ((UT_LINESIZE != 32) || (UT_NAMESIZE != 32) || (UT_HOSTSIZE != 256))
+#error struct utmpx member char[] size(s) have changed!
+#elif defined __UT_LINESIZE \
+       && ((__UT_LINESIZE != 32) || (__UT_NAMESIZE != 32) || (__UT_HOSTSIZE != 256))
+/* __UT_NAMESIZE was checked with 64 above, but glibc-2.11 definitely uses 32! */
+#error struct utmpx member char[] size(s) have changed!
+#endif
+
+#if EMPTY != 0 || RUN_LVL != 1 || BOOT_TIME != 2 || NEW_TIME != 3 || \
+       OLD_TIME != 4
+#error Values for the ut_type field of struct utmpx changed
+#endif
+
+int last_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int last_main(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
+{
+       struct utmpx ut;
+       int n, file = STDIN_FILENO;
+       time_t t_tmp;
+       off_t pos;
+       static const char _ut_usr[] ALIGN1 =
+                       "runlevel\0" "reboot\0" "shutdown\0";
+       static const char _ut_lin[] ALIGN1 =
+                       "~\0" "{\0" "|\0" /* "LOGIN\0" "date\0" */;
+       enum {
+               TYPE_RUN_LVL = RUN_LVL,         /* 1 */
+               TYPE_BOOT_TIME = BOOT_TIME,     /* 2 */
+               TYPE_SHUTDOWN_TIME = SHUTDOWN_TIME
+       };
+       enum {
+               _TILDE = EMPTY, /* 0 */
+               TYPE_NEW_TIME,  /* NEW_TIME, 3 */
+               TYPE_OLD_TIME   /* OLD_TIME, 4 */
+       };
+
+       if (argv[1]) {
+               bb_show_usage();
+       }
+       file = xopen(bb_path_wtmp_file, O_RDONLY);
+
+       printf("%-10s %-14s %-18s %-12.12s %s\n",
+               "USER", "TTY", "HOST", "LOGIN", "TIME");
+       /* yikes. We reverse over the file and that is a not too elegant way */
+       pos = xlseek(file, 0, SEEK_END);
+       pos = lseek(file, pos - sizeof(ut), SEEK_SET);
+       while ((n = full_read(file, &ut, sizeof(ut))) > 0) {
+               if (n != sizeof(ut)) {
+                       bb_perror_msg_and_die("short read");
+               }
+               n = index_in_strings(_ut_lin, ut.ut_line);
+               if (n == _TILDE) { /* '~' */
+#if 1
+/* do we really need to be cautious here? */
+                       n = index_in_strings(_ut_usr, ut.ut_user);
+                       if (++n > 0)
+                               ut.ut_type = n != 3 ? n : SHUTDOWN_TIME;
+#else
+                       if (is_prefixed_with(ut.ut_user, "shutdown"))
+                               ut.ut_type = SHUTDOWN_TIME;
+                       else if (is_prefixed_with(ut.ut_user, "reboot"))
+                               ut.ut_type = BOOT_TIME;
+                       else if (is_prefixed_with(ut.ut_user, "runlevel"))
+                               ut.ut_type = RUN_LVL;
+#endif
+               } else {
+                       if (ut.ut_user[0] == '\0' || strcmp(ut.ut_user, "LOGIN") == 0) {
+                               /* Don't bother.  This means we can't find how long
+                                * someone was logged in for.  Oh well. */
+                               goto next;
+                       }
+                       if (ut.ut_type != DEAD_PROCESS
+                        && ut.ut_user[0]
+                        && ut.ut_line[0]
+                       ) {
+                               ut.ut_type = USER_PROCESS;
+                       }
+                       if (strcmp(ut.ut_user, "date") == 0) {
+                               if (n == TYPE_OLD_TIME) { /* '|' */
+                                       ut.ut_type = OLD_TIME;
+                               }
+                               if (n == TYPE_NEW_TIME) { /* '{' */
+                                       ut.ut_type = NEW_TIME;
+                               }
+                       }
+               }
+
+               if (ut.ut_type != USER_PROCESS) {
+                       switch (ut.ut_type) {
+                               case OLD_TIME:
+                               case NEW_TIME:
+                               case RUN_LVL:
+                               case SHUTDOWN_TIME:
+                                       goto next;
+                               case BOOT_TIME:
+                                       strcpy(ut.ut_line, "system boot");
+                       }
+               }
+               /* manpages say ut_tv.tv_sec *is* time_t,
+                * but some systems have it wrong */
+               t_tmp = (time_t)ut.ut_tv.tv_sec;
+               printf("%-10s %-14s %-18s %-12.12s\n",
+                       ut.ut_user, ut.ut_line, ut.ut_host, ctime(&t_tmp) + 4);
+ next:
+               pos -= sizeof(ut);
+               if (pos <= 0)
+                       break; /* done. */
+               xlseek(file, pos, SEEK_SET);
+       }
+
+       fflush_stdout_and_exit(EXIT_SUCCESS);
+}
diff --git a/util-linux/last_fancy.c b/util-linux/last_fancy.c
new file mode 100644 (file)
index 0000000..e56e0ba
--- /dev/null
@@ -0,0 +1,300 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * (sysvinit like) last implementation
+ *
+ * Copyright (C) 2008 by Patricia Muscalu <patricia.muscalu@axis.com>
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this source tree.
+ */
+
+#include "libbb.h"
+
+/* NB: ut_name and ut_user are the same field, use only one name (ut_user)
+ * to reduce confusion */
+
+#ifndef SHUTDOWN_TIME
+#  define SHUTDOWN_TIME 254
+#endif
+
+#define HEADER_FORMAT     "%-8.8s %-12.12s %-*.*s %-16.16s %-7.7s %s\n"
+#define HEADER_LINE       "USER", "TTY", \
+       INET_ADDRSTRLEN, INET_ADDRSTRLEN, "HOST", "LOGIN", "  TIME", ""
+#define HEADER_LINE_WIDE  "USER", "TTY", \
+       INET6_ADDRSTRLEN, INET6_ADDRSTRLEN, "HOST", "LOGIN", "  TIME", ""
+
+#if !defined __UT_LINESIZE && defined UT_LINESIZE
+# define __UT_LINESIZE UT_LINESIZE
+#endif
+
+enum {
+       NORMAL,
+       LOGGED,
+       DOWN,
+       REBOOT,
+       CRASH,
+       GONE
+};
+
+enum {
+       LAST_OPT_W = (1 << 0),  /* -W wide            */
+       LAST_OPT_f = (1 << 1),  /* -f input file      */
+       LAST_OPT_H = (1 << 2),  /* -H header          */
+};
+
+#define show_wide (option_mask32 & LAST_OPT_W)
+
+static void show_entry(struct utmpx *ut, int state, time_t dur_secs)
+{
+       unsigned days, hours, mins;
+       char duration[sizeof("(%u+02:02)") + sizeof(int)*3];
+       char login_time[17];
+       char logout_time[8];
+       const char *logout_str;
+       const char *duration_str;
+       time_t tmp;
+
+       /* manpages say ut_tv.tv_sec *is* time_t,
+        * but some systems have it wrong */
+       tmp = ut->ut_tv.tv_sec;
+       safe_strncpy(login_time, ctime(&tmp), 17);
+       tmp = dur_secs;
+       snprintf(logout_time, 8, "- %s", ctime(&tmp) + 11);
+
+       dur_secs = MAX(dur_secs - (time_t)ut->ut_tv.tv_sec, (time_t)0);
+       /* unsigned int is easier to divide than time_t (which may be signed long) */
+       mins = dur_secs / 60;
+       days = mins / (24*60);
+       mins = mins % (24*60);
+       hours = mins / 60;
+       mins = mins % 60;
+
+//     if (days) {
+               sprintf(duration, "(%u+%02u:%02u)", days, hours, mins);
+//     } else {
+//             sprintf(duration, " (%02u:%02u)", hours, mins);
+//     }
+
+       logout_str = logout_time;
+       duration_str = duration;
+       switch (state) {
+       case NORMAL:
+               break;
+       case LOGGED:
+               logout_str = "  still";
+               duration_str = "logged in";
+               break;
+       case DOWN:
+               logout_str = "- down ";
+               break;
+       case REBOOT:
+               break;
+       case CRASH:
+               logout_str = "- crash";
+               break;
+       case GONE:
+               logout_str = "   gone";
+               duration_str = "- no logout";
+               break;
+       }
+
+       printf(HEADER_FORMAT,
+               ut->ut_user,
+               ut->ut_line,
+               show_wide ? INET6_ADDRSTRLEN : INET_ADDRSTRLEN,
+               show_wide ? INET6_ADDRSTRLEN : INET_ADDRSTRLEN,
+               ut->ut_host,
+               login_time,
+               logout_str,
+               duration_str);
+}
+
+static int get_ut_type(struct utmpx *ut)
+{
+       if (ut->ut_line[0] == '~') {
+               if (strcmp(ut->ut_user, "shutdown") == 0) {
+                       return SHUTDOWN_TIME;
+               }
+               if (strcmp(ut->ut_user, "reboot") == 0) {
+                       return BOOT_TIME;
+               }
+               if (strcmp(ut->ut_user, "runlevel") == 0) {
+                       return RUN_LVL;
+               }
+               return ut->ut_type;
+       }
+
+       if (ut->ut_user[0] == 0) {
+               return DEAD_PROCESS;
+       }
+
+       if ((ut->ut_type != DEAD_PROCESS)
+        && (strcmp(ut->ut_user, "LOGIN") != 0)
+        && ut->ut_user[0]
+        && ut->ut_line[0]
+       ) {
+               ut->ut_type = USER_PROCESS;
+       }
+
+       if (strcmp(ut->ut_user, "date") == 0) {
+               if (ut->ut_line[0] == '|') {
+                       return OLD_TIME;
+               }
+               if (ut->ut_line[0] == '{') {
+                       return NEW_TIME;
+               }
+       }
+       return ut->ut_type;
+}
+
+static int is_runlevel_shutdown(struct utmpx *ut)
+{
+       if (((ut->ut_pid & 255) == '0') || ((ut->ut_pid & 255) == '6')) {
+               return 1;
+       }
+
+       return 0;
+}
+
+int last_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int last_main(int argc UNUSED_PARAM, char **argv)
+{
+       struct utmpx ut;
+       const char *filename = _PATH_WTMP;
+       llist_t *zlist;
+       off_t pos;
+       time_t start_time;
+       time_t boot_time;
+       time_t down_time;
+       int file;
+       smallint going_down;
+       smallint boot_down;
+
+       /*opt =*/ getopt32(argv, "Wf:" /* "H" */, &filename);
+#ifdef BUT_UTIL_LINUX_LAST_HAS_NO_SUCH_OPT
+       if (opt & LAST_OPT_H) {
+               /* Print header line */
+               if (opt & LAST_OPT_W) {
+                       printf(HEADER_FORMAT, HEADER_LINE_WIDE);
+               } else {
+                       printf(HEADER_FORMAT, HEADER_LINE);
+               }
+       }
+#endif
+
+       file = xopen(filename, O_RDONLY);
+       {
+               /* in case the file is empty... */
+               struct stat st;
+               fstat(file, &st);
+               start_time = st.st_ctime;
+       }
+
+       time(&down_time);
+       going_down = 0;
+       boot_down = NORMAL; /* 0 */
+       zlist = NULL;
+       boot_time = 0;
+       /* get file size, rounding down to last full record */
+       pos = xlseek(file, 0, SEEK_END) / sizeof(ut) * sizeof(ut);
+       for (;;) {
+               pos -= (off_t)sizeof(ut);
+               if (pos < 0) {
+                       /* Beyond the beginning of the file boundary =>
+                        * the whole file has been read. */
+                       break;
+               }
+               xlseek(file, pos, SEEK_SET);
+               xread(file, &ut, sizeof(ut));
+               /* rewritten by each record, eventially will have
+                * first record's ut_tv.tv_sec: */
+               start_time = ut.ut_tv.tv_sec;
+
+               switch (get_ut_type(&ut)) {
+               case SHUTDOWN_TIME:
+                       down_time = ut.ut_tv.tv_sec;
+                       boot_down = DOWN;
+                       going_down = 1;
+                       break;
+               case RUN_LVL:
+                       if (is_runlevel_shutdown(&ut)) {
+                               down_time = ut.ut_tv.tv_sec;
+                               going_down = 1;
+                               boot_down = DOWN;
+                       }
+                       break;
+               case BOOT_TIME:
+                       strcpy(ut.ut_line, "system boot");
+                       show_entry(&ut, REBOOT, down_time);
+                       boot_down = CRASH;
+                       going_down = 1;
+                       break;
+               case DEAD_PROCESS:
+                       if (!ut.ut_line[0]) {
+                               break;
+                       }
+                       /* add_entry */
+                       llist_add_to(&zlist, xmemdup(&ut, sizeof(ut)));
+                       break;
+               case USER_PROCESS: {
+                       int show;
+
+                       if (!ut.ut_line[0]) {
+                               break;
+                       }
+                       /* find_entry */
+                       show = 1;
+                       {
+                               llist_t *el, *next;
+                               for (el = zlist; el; el = next) {
+                                       struct utmpx *up = (struct utmpx *)el->data;
+                                       next = el->link;
+                                       if (strncmp(up->ut_line, ut.ut_line, __UT_LINESIZE) == 0) {
+                                               if (show) {
+                                                       show_entry(&ut, NORMAL, up->ut_tv.tv_sec);
+                                                       show = 0;
+                                               }
+                                               llist_unlink(&zlist, el);
+                                               free(el->data);
+                                               free(el);
+                                       }
+                               }
+                       }
+
+                       if (show) {
+                               int state = boot_down;
+
+                               if (boot_time == 0) {
+                                       state = LOGGED;
+                                       /* Check if the process is alive */
+                                       if ((ut.ut_pid > 0)
+                                        && (kill(ut.ut_pid, 0) != 0)
+                                        && (errno == ESRCH)) {
+                                               state = GONE;
+                                       }
+                               }
+                               show_entry(&ut, state, boot_time);
+                       }
+                       /* add_entry */
+                       llist_add_to(&zlist, xmemdup(&ut, sizeof(ut)));
+                       break;
+               }
+               }
+
+               if (going_down) {
+                       boot_time = ut.ut_tv.tv_sec;
+                       llist_free(zlist, free);
+                       zlist = NULL;
+                       going_down = 0;
+               }
+       }
+
+       if (ENABLE_FEATURE_CLEAN_UP) {
+               llist_free(zlist, free);
+       }
+
+       printf("\nwtmp begins %s", ctime(&start_time));
+
+       if (ENABLE_FEATURE_CLEAN_UP)
+               close(file);
+       fflush_stdout_and_exit(EXIT_SUCCESS);
+}
diff --git a/util-linux/mountpoint.c b/util-linux/mountpoint.c
new file mode 100644 (file)
index 0000000..8b9e1d7
--- /dev/null
@@ -0,0 +1,105 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * mountpoint implementation for busybox
+ *
+ * Copyright (C) 2005 Bernhard Reutner-Fischer
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this source tree.
+ *
+ * Based on sysvinit's mountpoint
+ */
+//config:config MOUNTPOINT
+//config:      bool "mountpoint"
+//config:      default y
+//config:      help
+//config:        mountpoint checks if the directory is a mountpoint.
+
+//applet:IF_MOUNTPOINT(APPLET(mountpoint, BB_DIR_BIN, BB_SUID_DROP))
+
+//kbuild:lib-$(CONFIG_MOUNTPOINT) += mountpoint.o
+
+//usage:#define mountpoint_trivial_usage
+//usage:       "[-q] <[-dn] DIR | -x DEVICE>"
+//usage:#define mountpoint_full_usage "\n\n"
+//usage:       "Check if the directory is a mountpoint\n"
+//usage:     "\n       -q      Quiet"
+//usage:     "\n       -d      Print major/minor device number of the filesystem"
+//usage:     "\n       -n      Print device name of the filesystem"
+//usage:     "\n       -x      Print major/minor device number of the blockdevice"
+//usage:
+//usage:#define mountpoint_example_usage
+//usage:       "$ mountpoint /proc\n"
+//usage:       "/proc is not a mountpoint\n"
+//usage:       "$ mountpoint /sys\n"
+//usage:       "/sys is a mountpoint\n"
+
+#include "libbb.h"
+
+int mountpoint_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int mountpoint_main(int argc UNUSED_PARAM, char **argv)
+{
+       struct stat st;
+       const char *msg;
+       char *arg;
+       int rc, opt;
+
+       opt_complementary = "=1"; /* must have one argument */
+       opt = getopt32(argv, "qdxn");
+#define OPT_q (1)
+#define OPT_d (2)
+#define OPT_x (4)
+#define OPT_n (8)
+       arg = argv[optind];
+       msg = "%s";
+
+       rc = (opt & OPT_x) ? stat(arg, &st) : lstat(arg, &st);
+       if (rc != 0)
+               goto err;
+
+       if (opt & OPT_x) {
+               if (S_ISBLK(st.st_mode)) {
+                       printf("%u:%u\n", major(st.st_rdev),
+                                               minor(st.st_rdev));
+                       return EXIT_SUCCESS;
+               }
+               errno = 0; /* make perror_msg work as error_msg */
+               msg = "%s: not a block device";
+               goto err;
+       }
+
+       errno = ENOTDIR;
+       if (S_ISDIR(st.st_mode)) {
+               dev_t st_dev = st.st_dev;
+               ino_t st_ino = st.st_ino;
+               char *p = xasprintf("%s/..", arg);
+
+               if (stat(p, &st) == 0) {
+                       //int is_mnt = (st_dev != st.st_dev) || (st_dev == st.st_dev && st_ino == st.st_ino);
+                       int is_not_mnt = (st_dev == st.st_dev) && (st_ino != st.st_ino);
+
+                       if (opt & OPT_d)
+                               printf("%u:%u\n", major(st_dev), minor(st_dev));
+                       if (opt & OPT_n) {
+                               const char *d = find_block_device(arg);
+                               /* name is undefined, but device is mounted -> anonymous superblock! */
+                               /* happens with btrfs */
+                               if (!d) {
+                                       d = "UNKNOWN";
+                                       /* TODO: iterate /proc/mounts, or /proc/self/mountinfo
+                                        * to find out the device name */
+                               }
+                               printf("%s %s\n", d, arg);
+                       }
+                       if (!(opt & (OPT_q | OPT_d | OPT_n)))
+                               printf("%s is %sa mountpoint\n", arg, is_not_mnt ? "not " : "");
+                       return is_not_mnt;
+               }
+               arg = p;
+               /* else: stat had set errno, just fall through */
+       }
+
+ err:
+       if (!(opt & OPT_q))
+               bb_perror_msg(msg, arg);
+       return EXIT_FAILURE;
+}
diff --git a/util-linux/setsid.c b/util-linux/setsid.c
new file mode 100644 (file)
index 0000000..143a8f8
--- /dev/null
@@ -0,0 +1,82 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * setsid.c -- execute a command in a new session
+ * Rick Sladkey <jrs@world.std.com>
+ * In the public domain.
+ *
+ * 1999-02-22 Arkadiusz Mickiewicz <misiek@pld.ORG.PL>
+ * - added Native Language Support
+ *
+ * 2001-01-18 John Fremlin <vii@penguinpowered.com>
+ * - fork in case we are process group leader
+ *
+ * 2004-11-12 Paul Fox
+ * - busyboxed
+ */
+//config:config SETSID
+//config:      bool "setsid"
+//config:      default y
+//config:      help
+//config:        setsid runs a program in a new session
+
+//applet:IF_SETSID(APPLET(setsid, BB_DIR_USR_BIN, BB_SUID_DROP))
+
+//kbuild:lib-$(CONFIG_SETSID) += setsid.o
+
+//usage:#define setsid_trivial_usage
+//usage:       "[-c] PROG ARGS"
+//usage:#define setsid_full_usage "\n\n"
+//usage:       "Run PROG in a new session. PROG will have no controlling terminal\n"
+//usage:       "and will not be affected by keyboard signals (^C etc).\n"
+//usage:     "\n       -c      Set controlling terminal to stdin"
+
+#include "libbb.h"
+
+int setsid_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int setsid_main(int argc UNUSED_PARAM, char **argv)
+{
+       unsigned opt;
+
+       opt_complementary = "-1"; /* at least one arg */
+       opt = getopt32(argv, "+c"); /* +: stop on first non-opt */
+       argv += optind;
+
+       /* setsid() is allowed only when we are not a process group leader.
+        * Otherwise our PID serves as PGID of some existing process group
+        * and cannot be used as PGID of a new process group.
+        *
+        * Example: setsid() below fails when run alone in interactive shell:
+        *  $ setsid PROG
+        * because shell's child (setsid) is put in a new process group.
+        * But doesn't fail if shell is not interactive
+        * (and therefore doesn't create process groups for pipes),
+        * or if setsid is not the first process in the process group:
+        *  $ true | setsid PROG
+        * or if setsid is executed in backquotes (`setsid PROG`)...
+        */
+       if (setsid() < 0) {
+               pid_t pid = fork_or_rexec(argv);
+               if (pid != 0) {
+                       /* parent */
+                       /* TODO:
+                        * we can waitpid(pid, &status, 0) and then even
+                        * emulate exitcode, making the behavior consistent
+                        * in both forked and non forked cases.
+                        * However, the code is larger and upstream
+                        * does not do such trick.
+                        */
+                       return EXIT_SUCCESS;
+               }
+
+               /* child */
+               /* now there should be no error: */
+               setsid();
+       }
+
+       if (opt) {
+               /* -c: set (with stealing) controlling tty */
+               ioctl(0, TIOCSCTTY, 1);
+       }
+
+       BB_EXECVP_or_die(argv);
+}
diff --git a/util-linux/taskset.c b/util-linux/taskset.c
new file mode 100644 (file)
index 0000000..94a0738
--- /dev/null
@@ -0,0 +1,221 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * taskset - retrieve or set a processes' CPU affinity
+ * Copyright (c) 2006 Bernhard Reutner-Fischer
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this source tree.
+ */
+
+//config:config TASKSET
+//config:      bool "taskset"
+//config:      default y
+//config:      help
+//config:        Retrieve or set a processes's CPU affinity.
+//config:        This requires sched_{g,s}etaffinity support in your libc.
+//config:
+//config:config FEATURE_TASKSET_FANCY
+//config:      bool "Fancy output"
+//config:      default y
+//config:      depends on TASKSET
+//config:      help
+//config:        Needed for machines with more than 32-64 CPUs:
+//config:        affinity parameter 0xHHHHHHHHHHHHHHHHHHHH can be arbitrarily long
+//config:        in this case. Otherwise, it is limited to sizeof(long).
+
+//applet:IF_TASKSET(APPLET(taskset, BB_DIR_USR_BIN, BB_SUID_DROP))
+//kbuild:lib-$(CONFIG_TASKSET) += taskset.o
+
+//usage:#define taskset_trivial_usage
+//usage:       "[-p] [HEXMASK] PID | PROG ARGS"
+//usage:#define taskset_full_usage "\n\n"
+//usage:       "Set or get CPU affinity\n"
+//usage:     "\n       -p      Operate on an existing PID"
+//usage:
+//usage:#define taskset_example_usage
+//usage:       "$ taskset 0x7 ./dgemm_test&\n"
+//usage:       "$ taskset -p 0x1 $!\n"
+//usage:       "pid 4790's current affinity mask: 7\n"
+//usage:       "pid 4790's new affinity mask: 1\n"
+//usage:       "$ taskset 0x7 /bin/sh -c './taskset -p 0x1 $$'\n"
+//usage:       "pid 6671's current affinity mask: 1\n"
+//usage:       "pid 6671's new affinity mask: 1\n"
+//usage:       "$ taskset -p 1\n"
+//usage:       "pid 1's current affinity mask: 3\n"
+/*
+ * Not yet implemented:
+ * -a/--all-tasks (affect all threads)
+ *     needs to get TIDs from /proc/PID/task/ and use _them_ as "pid" in sched_setaffinity(pid)
+ * -c/--cpu-list  (specify CPUs via "1,3,5-7")
+ */
+
+#include <sched.h>
+#include "libbb.h"
+
+typedef unsigned long ul;
+#define SZOF_UL (unsigned)(sizeof(ul))
+#define BITS_UL (unsigned)(sizeof(ul)*8)
+#define MASK_UL (unsigned)(sizeof(ul)*8 - 1)
+
+#if ENABLE_FEATURE_TASKSET_FANCY
+#define TASKSET_PRINTF_MASK "%s"
+/* craft a string from the mask */
+static char *from_mask(const ul *mask, unsigned sz_in_bytes)
+{
+       char *str = xzalloc((sz_in_bytes+1) * 2); /* we will leak it */
+       char *p = str;
+       for (;;) {
+               ul v = *mask++;
+               if (SZOF_UL == 4)
+                       p += sprintf(p, "%08lx", v);
+               if (SZOF_UL == 8)
+                       p += sprintf(p, "%016lx", v);
+               if (SZOF_UL == 16)
+                       p += sprintf(p, "%032lx", v); /* :) */
+               sz_in_bytes -= SZOF_UL;
+               if ((int)sz_in_bytes <= 0)
+                       break;
+       }
+       while (str[0] == '0' && str[1])
+               str++;
+       return str;
+}
+#else
+#define TASKSET_PRINTF_MASK "%lx"
+static unsigned long long from_mask(ul *mask, unsigned sz_in_bytes UNUSED_PARAM)
+{
+       return *mask;
+}
+#endif
+
+static unsigned long *get_aff(int pid, unsigned *sz)
+{
+       int r;
+       unsigned long *mask = NULL;
+       unsigned sz_in_bytes = *sz;
+
+       for (;;) {
+               mask = xrealloc(mask, sz_in_bytes);
+               r = sched_getaffinity(pid, sz_in_bytes, (void*)mask);
+               if (r == 0)
+                       break;
+               sz_in_bytes *= 2;
+               if (errno == EINVAL && (int)sz_in_bytes > 0)
+                       continue;
+               bb_perror_msg_and_die("can't %cet pid %d's affinity", 'g', pid);
+       }
+       //bb_error_msg("get mask[0]:%lx sz_in_bytes:%d", mask[0], sz_in_bytes);
+       *sz = sz_in_bytes;
+       return mask;
+}
+
+int taskset_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int taskset_main(int argc UNUSED_PARAM, char **argv)
+{
+       ul *mask;
+       unsigned mask_size_in_bytes;
+       pid_t pid = 0;
+       unsigned opt_p;
+       const char *current_new;
+       char *aff;
+
+       /* NB: we mimic util-linux's taskset: -p does not take
+        * an argument, i.e., "-pN" is NOT valid, only "-p N"!
+        * Indeed, util-linux-2.13-pre7 uses:
+        * getopt_long(argc, argv, "+pchV", ...), not "...p:..." */
+
+       opt_complementary = "-1"; /* at least 1 arg */
+       opt_p = getopt32(argv, "+p");
+       argv += optind;
+
+       aff = *argv++;
+       if (opt_p) {
+               char *pid_str = aff;
+               if (*argv) { /* "-p <aff> <pid> ...rest.is.ignored..." */
+                       pid_str = *argv; /* NB: *argv != NULL in this case */
+               }
+               /* else it was just "-p <pid>", and *argv == NULL */
+               pid = xatoul_range(pid_str, 1, ((unsigned)(pid_t)ULONG_MAX) >> 1);
+       } else {
+               /* <aff> <cmd...> */
+               if (!*argv)
+                       bb_show_usage();
+       }
+
+       mask_size_in_bytes = SZOF_UL;
+       current_new = "current";
+ print_aff:
+       mask = get_aff(pid, &mask_size_in_bytes);
+       if (opt_p) {
+               printf("pid %d's %s affinity mask: "TASKSET_PRINTF_MASK"\n",
+                               pid, current_new, from_mask(mask, mask_size_in_bytes));
+               if (*argv == NULL) {
+                       /* Either it was just "-p <pid>",
+                        * or it was "-p <aff> <pid>" and we came here
+                        * for the second time (see goto below) */
+                       return EXIT_SUCCESS;
+               }
+               *argv = NULL;
+               current_new = "new";
+       }
+       memset(mask, 0, mask_size_in_bytes);
+
+       /* Affinity was specified, translate it into mask */
+       /* it is always in hex, skip "0x" if it exists */
+       if (aff[0] == '0' && (aff[1]|0x20) == 'x')
+               aff += 2;
+
+       if (!ENABLE_FEATURE_TASKSET_FANCY) {
+               mask[0] = xstrtoul(aff, 16);
+       } else {
+               unsigned i;
+               char *last_char;
+
+               i = 0; /* bit pos in mask[] */
+
+               /* aff is ASCII hex string, accept very long masks in this form.
+                * Process hex string AABBCCDD... to ulong mask[]
+                * from the rightmost nibble, which is least-significant.
+                * Bits not fitting into mask[] are ignored: (example: 1234
+                * in 12340000000000000000000000000000000000000ff)
+                */
+               last_char = strchrnul(aff, '\0');
+               while (last_char > aff) {
+                       char c;
+                       ul val;
+
+                       last_char--;
+                       c = *last_char;
+                       if (isdigit(c))
+                               val = c - '0';
+                       else if ((c|0x20) >= 'a' && (c|0x20) <= 'f')
+                               val = (c|0x20) - ('a' - 10);
+                       else
+                               bb_error_msg_and_die("bad affinity '%s'", aff);
+
+                       if (i < mask_size_in_bytes * 8) {
+                               mask[i / BITS_UL] |= val << (i & MASK_UL);
+                               //bb_error_msg("bit %d set", i);
+                       }
+                       /* else:
+                        * We can error out here, but we don't.
+                        * For one, kernel itself ignores bits in mask[]
+                        * which do not map to any CPUs:
+                        * if mask[] has one 32-bit long element,
+                        * but you have only 8 CPUs, all bits beyond first 8
+                        * are ignored, silently.
+                        * No point in making bits past 31th to be errors.
+                        */
+                       i += 4;
+               }
+       }
+
+       /* Set pid's or our own (pid==0) affinity */
+       if (sched_setaffinity(pid, mask_size_in_bytes, (void*)mask))
+               bb_perror_msg_and_die("can't %cet pid %d's affinity", 's', pid);
+       //bb_error_msg("set mask[0]:%lx", mask[0]);
+
+       if (!argv[0]) /* "-p <aff> <pid> [...ignored...]" */
+               goto print_aff; /* print new affinity and exit */
+
+       BB_EXECVP_or_die(argv);
+}
diff --git a/util-linux/wall.c b/util-linux/wall.c
new file mode 100644 (file)
index 0000000..50658f4
--- /dev/null
@@ -0,0 +1,63 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * wall - write a message to all logged-in users
+ * Copyright (c) 2009 Bernhard Reutner-Fischer
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this source tree.
+ */
+
+//config:config WALL
+//config:      bool "wall"
+//config:      default y
+//config:      depends on FEATURE_UTMP
+//config:      help
+//config:        Write a message to all users that are logged in.
+
+/* Needs to be run by root or be suid root - needs to write to /dev/TTY: */
+//applet:IF_WALL(APPLET(wall, BB_DIR_USR_BIN, BB_SUID_REQUIRE))
+
+//kbuild:lib-$(CONFIG_WALL) += wall.o
+
+//usage:#define wall_trivial_usage
+//usage:       "[FILE]"
+//usage:#define wall_full_usage "\n\n"
+//usage:       "Write content of FILE or stdin to all logged-in users"
+//usage:
+//usage:#define wall_sample_usage
+//usage:       "echo foo | wall\n"
+//usage:       "wall ./mymessage"
+
+#include "libbb.h"
+
+int wall_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int wall_main(int argc UNUSED_PARAM, char **argv)
+{
+       struct utmpx *ut;
+       char *msg;
+       int fd;
+
+       fd = STDIN_FILENO;
+       if (argv[1]) {
+               /* The applet is setuid.
+                * Access to the file must be under user's uid/gid.
+                */
+               fd = xopen_as_uid_gid(argv[1], O_RDONLY, getuid(), getgid());
+       }
+       msg = xmalloc_read(fd, NULL);
+       if (ENABLE_FEATURE_CLEAN_UP && argv[1])
+               close(fd);
+       setutxent();
+       while ((ut = getutxent()) != NULL) {
+               char *line;
+               if (ut->ut_type != USER_PROCESS)
+                       continue;
+               line = concat_path_file("/dev", ut->ut_line);
+               xopen_xwrite_close(line, msg);
+               free(line);
+       }
+       if (ENABLE_FEATURE_CLEAN_UP) {
+               endutxent();
+               free(msg);
+       }
+       return EXIT_SUCCESS;
+}