[klibc] Miscellaneous utilities for klibc
A collection of minor utilities for klibc.
Signed-off-by: H. Peter Anvin <hpa@zytor.com>
diff --git a/usr/Kbuild b/usr/Kbuild
index 4b2be06..4fea24c 100644
--- a/usr/Kbuild
+++ b/usr/Kbuild
@@ -6,7 +6,7 @@
include-subdir := include
klibc-subdir := klibc
-usr-subdirs := kinit
+usr-subdirs := kinit utils
subdir- := $(include-subdir) $(klibc-subdir) $(usr-subdirs)
usr-subdirs := $(addprefix _usr_,$(usr-subdirs))
diff --git a/usr/utils/Kbuild b/usr/utils/Kbuild
new file mode 100644
index 0000000..76ffff0
--- /dev/null
+++ b/usr/utils/Kbuild
@@ -0,0 +1,62 @@
+#
+# Kbuild file for klib utils
+#
+
+progs := chroot dd mkdir mkfifo mknod mount pivot_root umount
+progs += true false sleep ln nuke minips cat
+progs += insmod uname halt
+
+static-y := $(addprefix static/, $(progs))
+shared-y := $(addprefix shared/, $(progs))
+
+# The binary is placed in a subdir, so we need to tell kbuild this
+static/chroot-y := chroot.o
+shared/chroot-y := chroot.o
+static/dd-y := dd.o
+shared/dd-y := dd.o
+static/mkdir-y := mkdir.o file_mode.o
+shared/mkdir-y := mkdir.o file_mode.o
+static/mkfifo-y := mkfifo.o file_mode.o
+shared/mkfifo-y := mkfifo.o file_mode.o
+static/mknod-y := mknod.o file_mode.o
+shared/mknod-y := mknod.o file_mode.o
+static/mount-y := mount_main.o mount_opts.o
+shared/mount-y := mount_main.o mount_opts.o
+static/pivot_root-y := pivot_root.o
+shared/pivot_root-y := pivot_root.o
+static/umount-y := umount.o
+shared/umount-y := umount.o
+static/true-y := true.o
+shared/true-y := true.o
+static/false-y := false.o
+shared/false-y := false.o
+static/sleep-y := sleep.o
+shared/sleep-y := sleep.o
+static/ln-y := ln.o
+shared/ln-y := ln.o
+static/nuke-y := nuke.o
+shared/nuke-y := nuke.o
+static/minips-y := minips.o
+shared/minips-y := minips.o
+static/cat-y := cat.o
+shared/cat-y := cat.o
+static/insmod-y := insmod.o
+shared/insmod-y := insmod.o
+static/uname-y := uname.o
+shared/uname-y := uname.o
+static/halt-y := halt.o
+shared/halt-y := halt.o
+
+# Additionally linked targets
+always := static/reboot static/poweroff shared/reboot shared/poweroff
+
+$(obj)/static/reboot $(obj)/static/poweroff: $(obj)/static/halt
+ $(call cmd,ln)
+$(obj)/shared/reboot $(obj)/shared/poweroff: $(obj)/shared/halt
+ $(call cmd,ln)
+
+# Clean deletes the static and shared dir
+clean-dirs := static shared
+
+# install only install the shared binaries
+install-y := $(shared-y) shared/reboot shared/poweroff
diff --git a/usr/utils/cat.c b/usr/utils/cat.c
new file mode 100644
index 0000000..1108d2e
--- /dev/null
+++ b/usr/utils/cat.c
@@ -0,0 +1,329 @@
+/* $NetBSD: cat.c,v 1.43 2004/01/04 03:31:28 jschauma Exp $ */
+
+/*
+ * Copyright (c) 1989, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Kevin Fall.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef __COPYRIGHT
+#define __COPYRIGHT(arg)
+#endif
+#ifndef __RCSID
+#define __RCSID(arg)
+#endif
+
+#if HAVE_NBTOOL_CONFIG_H
+#include "nbtool_config.h"
+#endif
+
+#ifndef __KLIBC__
+#include <sys/cdefs.h>
+#endif
+#if !defined(lint)
+__COPYRIGHT("@(#) Copyright (c) 1989, 1993\n\
+ The Regents of the University of California. All rights reserved.\n");
+#if 0
+static char sccsid[] = "@(#)cat.c 8.2 (Berkeley) 4/27/95";
+#else
+__RCSID("$NetBSD: cat.c,v 1.43 2004/01/04 03:31:28 jschauma Exp $");
+#endif
+#endif /* not lint */
+
+#include <sys/param.h>
+#include <sys/stat.h>
+
+#include <ctype.h>
+#ifndef __KLIBC__
+#include <err.h>
+#endif
+#include <errno.h>
+#include <fcntl.h>
+#ifndef __KLIBC__
+#include <locale.h>
+#endif
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+int bflag, eflag, fflag, lflag, nflag, sflag, tflag, vflag;
+int rval;
+const char *filename;
+
+int main(int, char *[]);
+void cook_args(char *argv[]);
+void cook_buf(FILE *);
+void raw_args(char *argv[]);
+void raw_cat(int);
+
+int main(int argc, char *argv[])
+{
+ int ch;
+ struct flock stdout_lock;
+
+#ifndef __KLIBC__
+ setprogname(argv[0]);
+ (void)setlocale(LC_ALL, "");
+#endif
+
+ while ((ch = getopt(argc, argv, "beflnstuv")) != -1)
+ switch (ch) {
+ case 'b':
+ bflag = nflag = 1; /* -b implies -n */
+ break;
+ case 'e':
+ eflag = vflag = 1; /* -e implies -v */
+ break;
+ case 'f':
+ fflag = 1;
+ break;
+ case 'l':
+ lflag = 1;
+ break;
+ case 'n':
+ nflag = 1;
+ break;
+ case 's':
+ sflag = 1;
+ break;
+ case 't':
+ tflag = vflag = 1; /* -t implies -v */
+ break;
+ case 'u':
+#ifndef __KLIBC__
+ setbuf(stdout, NULL);
+#endif
+ break;
+ case 'v':
+ vflag = 1;
+ break;
+ default:
+ case '?':
+ (void)fprintf(stderr,
+ "usage: cat [-beflnstuv] [-] [file ...]\n");
+ exit(1);
+ /* NOTREACHED */
+ }
+ argv += optind;
+
+ if (lflag) {
+ stdout_lock.l_len = 0;
+ stdout_lock.l_start = 0;
+ stdout_lock.l_type = F_WRLCK;
+ stdout_lock.l_whence = SEEK_SET;
+ if (fcntl(STDOUT_FILENO, F_SETLKW, &stdout_lock) == -1) {
+ perror("fcntl");
+ exit(1);
+ }
+ }
+
+ if (bflag || eflag || nflag || sflag || tflag || vflag)
+ cook_args(argv);
+ else
+ raw_args(argv);
+ if (fclose(stdout)) {
+ perror("fclose");
+ exit(1);
+ }
+ exit(rval);
+ /* NOTREACHED */
+}
+
+void cook_args(char **argv)
+{
+ FILE *fp;
+
+ fp = stdin;
+ filename = "stdin";
+ do {
+ if (*argv) {
+ if (!strcmp(*argv, "-"))
+ fp = stdin;
+ else if ((fp = fopen(*argv,
+ fflag ? "rf" : "r")) == NULL) {
+ perror("fopen");
+ rval = 1;
+ ++argv;
+ continue;
+ }
+ filename = *argv++;
+ }
+ cook_buf(fp);
+ if (fp != stdin)
+ (void)fclose(fp);
+ } while (*argv);
+}
+
+void cook_buf(FILE * fp)
+{
+ int ch, gobble, line, prev;
+ int stdout_err = 0;
+
+ line = gobble = 0;
+ for (prev = '\n'; (ch = getc(fp)) != EOF; prev = ch) {
+ if (prev == '\n') {
+ if (ch == '\n') {
+ if (sflag) {
+ if (!gobble && putchar(ch) == EOF)
+ break;
+ gobble = 1;
+ continue;
+ }
+ if (nflag) {
+ if (!bflag) {
+ if (fprintf(stdout,
+ "%6d\t",
+ ++line) < 0) {
+ stdout_err++;
+ break;
+ }
+ } else if (eflag) {
+ if (fprintf(stdout,
+ "%6s\t", "") < 0) {
+ stdout_err++;
+ break;
+ }
+ }
+ }
+ } else if (nflag) {
+ if (fprintf(stdout, "%6d\t", ++line) < 0) {
+ stdout_err++;
+ break;
+ }
+ }
+ }
+ gobble = 0;
+ if (ch == '\n') {
+ if (eflag)
+ if (putchar('$') == EOF)
+ break;
+ } else if (ch == '\t') {
+ if (tflag) {
+ if (putchar('^') == EOF || putchar('I') == EOF)
+ break;
+ continue;
+ }
+ } else if (vflag) {
+ if (!isascii(ch)) {
+ if (putchar('M') == EOF || putchar('-') == EOF)
+ break;
+ ch = (ch) & 0x7f;
+ }
+ if (iscntrl(ch)) {
+ if (putchar('^') == EOF ||
+ putchar(ch == '\177' ? '?' :
+ ch | 0100) == EOF)
+ break;
+ continue;
+ }
+ }
+ if (putchar(ch) == EOF)
+ break;
+ }
+ if (stdout_err) {
+ perror(filename);
+ rval = 1;
+ }
+}
+
+void raw_args(char **argv)
+{
+ int fd;
+
+ fd = fileno(stdin);
+ filename = "stdin";
+ do {
+ if (*argv) {
+ if (!strcmp(*argv, "-"))
+ fd = fileno(stdin);
+ else if (fflag) {
+ struct stat st;
+ fd = open(*argv, O_RDONLY | O_NONBLOCK, 0);
+ if (fd < 0)
+ goto skip;
+
+ if (fstat(fd, &st) == -1) {
+ close(fd);
+ goto skip;
+ }
+ if (!S_ISREG(st.st_mode)) {
+ close(fd);
+ errno = EINVAL;
+ goto skipnomsg;
+ }
+ } else if ((fd = open(*argv, O_RDONLY, 0)) < 0) {
+ skip:
+ perror(*argv);
+ skipnomsg:
+ rval = 1;
+ ++argv;
+ continue;
+ }
+ filename = *argv++;
+ }
+ raw_cat(fd);
+ if (fd != fileno(stdin))
+ (void)close(fd);
+ } while (*argv);
+}
+
+void raw_cat(int rfd)
+{
+ static char *buf;
+ static char fb_buf[BUFSIZ];
+ static size_t bsize;
+
+ struct stat sbuf;
+ ssize_t nr, nw, off;
+ int wfd;
+
+ wfd = fileno(stdout);
+ if (buf == NULL) {
+ if (fstat(wfd, &sbuf) == 0) {
+ bsize = sbuf.st_blksize > BUFSIZ ?
+ sbuf.st_blksize : BUFSIZ;
+ buf = malloc(bsize);
+ }
+ if (buf == NULL) {
+ buf = fb_buf;
+ bsize = BUFSIZ;
+ }
+ }
+ while ((nr = read(rfd, buf, bsize)) > 0)
+ for (off = 0; nr; nr -= nw, off += nw)
+ if ((nw = write(wfd, buf + off, (size_t) nr)) < 0) {
+ perror("write");
+ exit(1);
+ }
+ if (nr < 0) {
+ fprintf(stderr, "%s: invalid length\n", filename);
+ rval = 1;
+ }
+}
diff --git a/usr/utils/chroot.c b/usr/utils/chroot.c
new file mode 100644
index 0000000..a734301
--- /dev/null
+++ b/usr/utils/chroot.c
@@ -0,0 +1,25 @@
+/*
+ * chroot.c, by rmk
+ */
+#include <unistd.h>
+#include <stdio.h>
+
+int main(int argc, char *argv[], char *envp[])
+{
+ if (argc < 3) {
+ fprintf(stderr, "Usage: %s newroot command...\n", argv[0]);
+ return 1;
+ }
+
+ if (chroot(argv[1]) == -1) {
+ perror("chroot");
+ return 1;
+ }
+
+ if (execve(argv[2], argv + 2, envp) == -1) {
+ perror("execve");
+ return 1;
+ }
+
+ return 0;
+}
diff --git a/usr/utils/dd.c b/usr/utils/dd.c
new file mode 100644
index 0000000..562e2cf
--- /dev/null
+++ b/usr/utils/dd.c
@@ -0,0 +1,533 @@
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <setjmp.h>
+#include <signal.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0]))
+
+static char *progname;
+
+struct option {
+ const char *opt;
+ char *str;
+ char *arg;
+};
+
+struct conv {
+ const char str[8];
+ unsigned int set;
+ unsigned int exclude;
+};
+
+#define CONV_BLOCK (1<<0)
+#define CONV_UNBLOCK (1<<1)
+
+#define CONV_LCASE (1<<2)
+#define CONV_UCASE (1<<3)
+
+#define CONV_SWAB (1<<4)
+#define CONV_NOERROR (1<<5)
+#define CONV_NOTRUNC (1<<6)
+#define CONV_SYNC (1<<7)
+
+static struct option options[] = {
+ {"bs", NULL, NULL},
+#define OPT_BS (&options[0])
+ {"cbs", NULL, NULL},
+#define OPT_CBS (&options[1])
+ {"conv", NULL, NULL},
+#define OPT_CONV (&options[2])
+ {"count", NULL, NULL},
+#define OPT_COUNT (&options[3])
+ {"ibs", NULL, NULL},
+#define OPT_IBS (&options[4])
+ {"if", NULL, NULL},
+#define OPT_IF (&options[5])
+ {"obs", NULL, NULL},
+#define OPT_OBS (&options[6])
+ {"of", NULL, NULL},
+#define OPT_OF (&options[7])
+ {"seek", NULL, NULL},
+#define OPT_SEEK (&options[8])
+ {"skip", NULL, NULL}
+#define OPT_SKIP (&options[9])
+};
+
+static const struct conv conv_opts[] = {
+ {"block", CONV_BLOCK, CONV_UNBLOCK},
+ {"unblock", CONV_UNBLOCK, CONV_BLOCK},
+ {"lcase", CONV_LCASE, CONV_UCASE},
+ {"ucase", CONV_UCASE, CONV_LCASE},
+ {"swab", CONV_SWAB, 0},
+ {"noerror", CONV_NOERROR, 0},
+ {"notrunc", CONV_NOTRUNC, 0},
+ {"sync", CONV_SYNC, 0},
+};
+
+static size_t cbs;
+static unsigned int conv;
+static unsigned int count;
+static size_t ibs = 512;
+static size_t obs = 512;
+static unsigned int seek;
+static unsigned int skip;
+static char *in_buf;
+static char *out_buf;
+
+static size_t parse_bs(struct option *opt)
+{
+ unsigned long val, realval = 1;
+ char *str = opt->str;
+ int err = 0;
+
+ do {
+ char *s = str;
+ val = strtoul(str, &str, 10);
+ if (s == str || (val == ULONG_MAX && errno == ERANGE)) {
+ err = 1;
+ break;
+ }
+
+ /*
+ * This option may be followed by
+ * 'b', 'k' or 'x'
+ */
+ if (*str == 'b') {
+ val *= 512;
+ str++;
+ } else if (*str == 'k') {
+ val *= 1024;
+ str++;
+ }
+ realval *= val;
+ if (*str != 'x')
+ break;
+ str++;
+ } while (1);
+
+ if (*str != '\0')
+ err = 1;
+
+ if (err) {
+ fprintf(stderr, "%s: bad operand `%s'\n", progname, opt->arg);
+ exit(1);
+ }
+
+ return (size_t) realval;
+}
+
+static unsigned int parse_num(struct option *opt)
+{
+ unsigned long val;
+ char *str = opt->str;
+
+ val = strtoul(str, &str, 10);
+ if (str == opt->str || (val == ULONG_MAX && errno == ERANGE) ||
+ val > UINT_MAX) {
+ fprintf(stderr, "%s: bad operand `%s'\n", progname, opt->arg);
+ exit(1);
+ }
+
+ return (unsigned int)val;
+}
+
+static int parse_options(int argc, char *argv[])
+{
+ unsigned int i;
+ char *p, *s;
+ int arg;
+
+ /*
+ * We cheat here; we don't parse the operand values
+ * themselves here. We merely split the operands
+ * up. This means that bs=foo bs=1 won't produce
+ * an error.
+ */
+ for (arg = 1; arg < argc; arg++) {
+ unsigned int len;
+
+ s = strchr(argv[arg], '=');
+ if (!s)
+ s = argv[arg]; /* don't recognise this arg */
+
+ len = s - argv[arg];
+ for (i = 0; i < ARRAY_SIZE(options); i++) {
+ if (strncmp(options[i].opt, argv[arg], len) != 0)
+ continue;
+
+ options[i].str = s + 1;
+ options[i].arg = argv[arg];
+ break;
+ }
+
+ if (i == ARRAY_SIZE(options)) {
+ fprintf(stderr, "%s: bad operand `%s'\n",
+ progname, argv[arg]);
+ return 1;
+ }
+ }
+
+ /*
+ * Translate numeric operands.
+ */
+ if (OPT_IBS->str)
+ ibs = parse_bs(OPT_IBS);
+ if (OPT_OBS->str)
+ obs = parse_bs(OPT_OBS);
+ if (OPT_CBS->str)
+ cbs = parse_bs(OPT_CBS);
+ if (OPT_COUNT->str)
+ count = parse_num(OPT_COUNT);
+ if (OPT_SEEK->str)
+ seek = parse_num(OPT_SEEK);
+ if (OPT_SKIP->str)
+ skip = parse_num(OPT_SKIP);
+
+ /*
+ * If bs= is specified, it overrides ibs= and obs=
+ */
+ if (OPT_BS->str)
+ ibs = obs = parse_bs(OPT_BS);
+
+ /*
+ * And finally conv=
+ */
+ if (OPT_CONV->str) {
+ p = OPT_CONV->str;
+
+ while ((s = strsep(&p, ",")) != NULL) {
+ for (i = 0; i < ARRAY_SIZE(conv_opts); i++) {
+ if (strcmp(s, conv_opts[i].str) != 0)
+ continue;
+ conv &= ~conv_opts[i].exclude;
+ conv |= conv_opts[i].set;
+ break;
+ }
+
+ if (i == ARRAY_SIZE(conv_opts)) {
+ fprintf(stderr, "%s: bad conversion `%s'\n",
+ progname, s);
+ return 1;
+ }
+ }
+ }
+
+ if (conv & (CONV_BLOCK | CONV_UNBLOCK) && cbs == 0) {
+ fprintf(stderr, "%s: block/unblock conversion with zero cbs\n",
+ progname);
+ return 1;
+ }
+
+ return 0;
+}
+
+static int safe_read(int fd, void *buf, size_t size)
+{
+ int ret, count = 0;
+ char *p = buf;
+
+ while (size) {
+ ret = read(fd, p, size);
+
+ /*
+ * If we got EINTR, go again.
+ */
+ if (ret == -1 && errno == EINTR)
+ continue;
+
+ /*
+ * If we encountered an error condition
+ * or read 0 bytes (EOF) return what we
+ * have.
+ */
+ if (ret == -1 || ret == 0)
+ return count ? count : ret;
+
+ /*
+ * We read some bytes.
+ */
+ count += ret;
+ size -= ret;
+ p += ret;
+ }
+
+ return count;
+}
+
+static int skip_blocks(int fd, void *buf, unsigned int blks, size_t size)
+{
+ unsigned int blk;
+ int ret = 0;
+
+ /*
+ * Try to seek.
+ */
+ for (blk = 0; blk < blks; blk++) {
+ ret = lseek(fd, size, SEEK_CUR);
+ if (ret == -1)
+ break;
+ }
+
+ /*
+ * If we failed to seek, read instead.
+ * FIXME: we don't handle short reads here, or
+ * EINTR correctly.
+ */
+ if (blk == 0 && ret == -1 && errno == ESPIPE) {
+ for (blk = 0; blk < blks; blk++) {
+ ret = safe_read(fd, buf, size);
+ if (ret != (int)size)
+ break;
+ }
+ }
+
+ if (ret == -1) {
+ perror("seek/skip");
+ return 1;
+ }
+ return 0;
+}
+
+struct stats {
+ unsigned int in_full;
+ unsigned int in_partial;
+ unsigned int out_full;
+ unsigned int out_partial;
+ unsigned int truncated;
+};
+
+static int do_dd(int rd, int wr, struct stats *stats)
+{
+ unsigned int i;
+ int ret;
+ int fill_val = 0;
+ size_t out_size = 0;
+ size_t in_size;
+ char *buf;
+
+ if (conv & (CONV_BLOCK | CONV_UNBLOCK))
+ fill_val = ' ';
+
+ while (!OPT_COUNT->str || count-- != 0) {
+ buf = in_buf;
+
+ /*
+ * 1. read ibs-sized buffer
+ */
+ in_size = ret = read(rd, in_buf, ibs);
+ if (ret == -1 || (ret == 0 && (conv & CONV_NOERROR) == 0))
+ break;
+
+ if (in_size == ibs) {
+ stats->in_full++;
+ } else {
+ stats->in_partial++;
+
+ /*
+ * 2. zero (or append spaces)
+ */
+ if (conv & CONV_SYNC) {
+ memset(in_buf + in_size, fill_val,
+ ibs - in_size);
+ in_size = ibs;
+ }
+ }
+
+ /*
+ * 4. swab conversion. With an odd number of bytes,
+ * last byte does not get swapped.
+ */
+ if (conv & CONV_SWAB) {
+ char c;
+
+ for (i = 1; i < in_size; i += 2) {
+ c = in_buf[i - 1];
+ in_buf[i - 1] = in_buf[i];
+ in_buf[i] = c;
+ }
+ }
+
+ /*
+ * 5. remaining conversions.
+ */
+ if (conv & CONV_LCASE)
+ for (i = 0; i < in_size; i++)
+ in_buf[i] = tolower(in_buf[i]);
+
+ if (conv & CONV_UCASE)
+ for (i = 0; i < in_size; i++)
+ in_buf[i] = toupper(in_buf[i]);
+
+ /* block/unblock ? */
+
+ /*
+ * 6. Aggregate into obs sized buffers.
+ * If the in_size is obs-sized and we have no
+ * data waiting, just write "buf" to the output.
+ */
+ if (out_size == 0 && in_size == obs) {
+ write(wr, buf, obs);
+ stats->out_full++;
+ } else {
+ /*
+ * We had data waiting, or we didn't have an
+ * obs-sized input block. We need to append
+ * the input data to the output buffer.
+ */
+ unsigned int space;
+ char *in_ptr = in_buf;
+
+ do {
+ space = obs - out_size;
+ if (space > in_size)
+ space = in_size;
+
+ memcpy(out_buf + out_size, in_ptr, space);
+ out_size += space;
+ in_size -= space;
+ in_ptr += space;
+
+ if (out_size == obs) {
+ write(wr, out_buf, obs);
+ stats->out_full++;
+ out_size = 0;
+ }
+ } while (out_size == 0 && in_size);
+
+ if (in_size) {
+ memcpy(out_buf, in_ptr, in_size);
+ out_size = in_size;
+ }
+ }
+ }
+
+ if (out_size) {
+ write(wr, out_buf, out_size);
+ stats->out_partial++;
+ }
+
+ return 0;
+}
+
+static sigjmp_buf jmp;
+
+static void sigint_handler(int sig)
+{
+ siglongjmp(jmp, -sig);
+}
+
+static int dd(int rd_fd, int wr_fd, struct stats *stats)
+{
+ int ret;
+
+ ret = sigsetjmp(jmp, 1);
+ if (ret == 0) {
+ sysv_signal(SIGINT, sigint_handler);
+ ret = do_dd(rd_fd, wr_fd, stats);
+ }
+
+ sysv_signal(SIGINT, SIG_DFL);
+ return ret;
+}
+
+int main(int argc, char *argv[])
+{
+ struct stats stats;
+ int ret;
+ int rd_fd = 0, wr_fd = 1;
+
+ progname = argv[0];
+
+ ret = parse_options(argc, argv);
+ if (ret)
+ return ret;
+
+ if (conv & (CONV_BLOCK | CONV_UNBLOCK)) {
+ fprintf(stderr, "%s: block/unblock not implemented\n",
+ progname);
+ return 1;
+ }
+
+ in_buf = malloc(ibs);
+ if (!in_buf) {
+ perror("malloc ibs");
+ return 1;
+ }
+
+ out_buf = malloc(obs);
+ if (!out_buf) {
+ perror("malloc obs");
+ return 1;
+ }
+
+ /*
+ * Open the input file, if specified.
+ */
+ if (OPT_IF->str) {
+ rd_fd = open(OPT_IF->str, O_RDONLY);
+ if (rd_fd == -1) {
+ perror("open input file");
+ return 1;
+ }
+ }
+
+ /*
+ * Open the output file, if specified.
+ */
+ if (OPT_OF->str) {
+ int flags = O_WRONLY|O_CREAT;
+ flags |= (conv & CONV_NOTRUNC) ? 0 : O_TRUNC;
+ wr_fd = open(OPT_OF->str, flags, 0666);
+ if (wr_fd == -1) {
+ perror("open output file");
+ return 1;
+ }
+ }
+
+ /*
+ * Skip obs-sized blocks of output file.
+ */
+ if (OPT_SEEK->str && skip_blocks(wr_fd, out_buf, seek, obs))
+ return 1;
+
+ /*
+ * Skip ibs-sized blocks of input file.
+ */
+ if (OPT_SKIP->str && skip_blocks(rd_fd, in_buf, skip, ibs))
+ return 1;
+
+ memset(&stats, 0, sizeof(stats));
+
+ /*
+ * Do the real work
+ */
+ ret = dd(rd_fd, wr_fd, &stats);
+
+ if (close(rd_fd) == -1)
+ perror(OPT_IF->str ? OPT_IF->str : "stdin");
+ if (close(wr_fd) == -1)
+ perror(OPT_OF->str ? OPT_OF->str : "stdout");
+
+ fprintf(stderr, "%u+%u records in\n", stats.in_full, stats.in_partial);
+ fprintf(stderr, "%u+%u records out\n",
+ stats.out_full, stats.out_partial);
+ if (stats.truncated)
+ fprintf(stderr, "%u truncated record%s\n",
+ stats.truncated, stats.truncated == 1 ? "" : "s");
+
+ /*
+ * ret will be -SIGINT if we got a SIGINT. Raise
+ * the signal again to cause us to terminate with
+ * SIGINT status.
+ */
+ if (ret == -SIGINT)
+ raise(SIGINT);
+
+ return ret;
+}
diff --git a/usr/utils/false.c b/usr/utils/false.c
new file mode 100644
index 0000000..2c3243a
--- /dev/null
+++ b/usr/utils/false.c
@@ -0,0 +1,4 @@
+int main(void)
+{
+ return 1;
+}
diff --git a/usr/utils/file_mode.c b/usr/utils/file_mode.c
new file mode 100644
index 0000000..48f7f43
--- /dev/null
+++ b/usr/utils/file_mode.c
@@ -0,0 +1,143 @@
+#include <sys/stat.h>
+#include <ctype.h>
+#include <errno.h>
+#include <limits.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "file_mode.h"
+
+extern char *progname;
+
+mode_t parse_file_mode(char *arg, mode_t mode, mode_t sumask)
+{
+ char *clause;
+
+ if (isdigit(*arg) && *arg < '8') {
+ unsigned long num;
+
+ num = strtoul(arg, NULL, 8);
+ if ((num == ULONG_MAX && errno == ERANGE) || num > 07777) {
+ fprintf(stderr, "%s: invalid mode `%s'\n", progname,
+ arg);
+ exit(255);
+ }
+ return (mode_t) num;
+ }
+
+ while ((clause = strsep(&arg, ",")) != NULL) {
+ mode_t who = 0;
+ int action;
+ char *p = clause;
+
+ /*
+ * Parse the who list. Optional.
+ */
+ while (1) {
+ switch (*p++) {
+ case 'u':
+ who |= S_IRWXU | S_ISUID;
+ continue;
+ case 'g':
+ who |= S_IRWXG | S_ISGID;
+ continue;
+ case 'o':
+ who |= S_IRWXO | S_ISVTX;
+ continue;
+ case 'a':
+ who =
+ S_IRWXU | S_IRWXG | S_IRWXO | S_ISUID |
+ S_ISGID | S_ISVTX;
+ continue;
+ }
+ /* undo the increment above */
+ p--;
+ break;
+ }
+
+ if (who == 0)
+ who = (~sumask) | S_ISVTX;
+
+ /*
+ * Parse an action list. Must be at least one action.
+ */
+ while (*p) {
+ mode_t perm = 0;
+
+ /*
+ * Parse the action
+ */
+ action = *p;
+ if (action == '+' || action == '-' || action == '=')
+ p++;
+
+ /*
+ * Parse perm
+ */
+ while (*p) {
+ switch (*p++) {
+ case 'r':
+ perm |= S_IRUSR | S_IRGRP | S_IROTH;
+ continue;
+ case 'w':
+ perm |= S_IWUSR | S_IWGRP | S_IWOTH;
+ continue;
+ case 'x':
+ perm |= S_IXUSR | S_IXGRP | S_IXOTH;
+ continue;
+ case 'X':
+ perm |= S_ISVTX;
+ continue;
+ case 's':
+ perm |= S_ISUID | S_ISGID;
+ continue;
+ case 'u':
+ perm = mode & S_IRWXU;
+ perm |= perm >> 3 | perm >> 6;
+ if (mode & S_ISUID)
+ perm |= S_ISGID;
+ continue;
+ case 'g':
+ perm = mode & S_IRWXG;
+ perm |= perm << 3 | perm >> 3;
+ if (mode & S_ISGID)
+ perm |= S_ISUID;
+ continue;
+ case 'o':
+ perm = mode & S_IRWXO;
+ perm |= perm << 6 | perm << 3;
+ continue;
+ }
+ /* undo the increment above */
+ p--;
+ break;
+ }
+
+ perm &= who;
+
+ switch (action) {
+ case '+':
+ mode |= perm;
+ continue;
+
+ case '-':
+ mode &= ~perm;
+ continue;
+
+ case '=':
+ mode &= ~who;
+ mode |= perm;
+ continue;
+ }
+
+ if (!action)
+ break;
+ fprintf(stderr, "%s: invalid mode `%s'\n", progname,
+ clause);
+ exit(255);
+ }
+ }
+
+ return mode;
+}
diff --git a/usr/utils/file_mode.h b/usr/utils/file_mode.h
new file mode 100644
index 0000000..ee84cb9
--- /dev/null
+++ b/usr/utils/file_mode.h
@@ -0,0 +1 @@
+mode_t parse_file_mode(char *arg, mode_t mode, mode_t sumask);
diff --git a/usr/utils/halt.c b/usr/utils/halt.c
new file mode 100644
index 0000000..a6656b5
--- /dev/null
+++ b/usr/utils/halt.c
@@ -0,0 +1,55 @@
+#include <stdlib.h>
+#include <unistd.h>
+#include <signal.h>
+#include <sys/reboot.h>
+#include <klibc/compiler.h>
+
+static __noreturn usage(void)
+{
+ static char mesg[] = "Usage: {halt|reboot|poweroff} [-n]\n";
+ write(2, mesg, sizeof(mesg) - 1);
+ exit(1);
+}
+
+int main(int argc, char *argv[])
+{
+ int cmd = 0; /* initalize to shut gcc up */
+ int do_sync = 1;
+ char *ptr, *ptr2;
+
+ /* Which action (program name)? */
+ ptr2 = ptr = argv[0];
+ while (*ptr2)
+ if (*ptr2++ == '/')
+ ptr = ptr2;
+ if (*ptr == 'r')
+ cmd = LINUX_REBOOT_CMD_RESTART;
+ else if (*ptr == 'h')
+ cmd = LINUX_REBOOT_CMD_HALT;
+ else if (*ptr == 'p')
+ cmd = LINUX_REBOOT_CMD_POWER_OFF;
+ else
+ usage();
+
+ /* Walk options */
+ while (*++argv && **argv == '-')
+ switch (*++*argv) {
+ case 'f': break; /* -f assumed */
+ case 'n': do_sync = 0; break;
+ default:
+ usage();
+ }
+ if (*argv)
+ usage(); /* any args == error */
+
+ if (do_sync)
+ sync();
+ reboot(LINUX_REBOOT_CMD_CAD_OFF); /* Enable CTRL+ALT+DEL */
+ if (!reboot(cmd)) {
+ /* Success. Currently, CMD_HALT returns, so stop the world */
+ /* kill(-1, SIGSTOP); */
+ kill(getpid(), SIGSTOP);
+ }
+ write(2, "failed.\n", 8);
+ return 1;
+}
diff --git a/usr/utils/insmod.c b/usr/utils/insmod.c
new file mode 100644
index 0000000..47b5880
--- /dev/null
+++ b/usr/utils/insmod.c
@@ -0,0 +1,140 @@
+/* insmod.c: insert a module into the kernel.
+ Copyright (C) 2001 Rusty Russell.
+ Copyright (C) 2002 Rusty Russell, IBM Corporation.
+
+ 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; either version 2 of the License, or
+ (at your option) any later version.
+
+ 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
+*/
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/mman.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <errno.h>
+
+#define streq(a,b) (strcmp((a),(b)) == 0)
+
+/* This really needs to be in a header file... */
+extern long init_module(void *, unsigned long, const char *);
+
+static void print_usage(const char *progname)
+{
+ fprintf(stderr, "Usage: %s filename [args]\n", progname);
+ exit(1);
+}
+
+/* We use error numbers in a loose translation... */
+static const char *moderror(int err)
+{
+ switch (err) {
+ case ENOEXEC:
+ return "Invalid module format";
+ case ENOENT:
+ return "Unknown symbol in module";
+ case ESRCH:
+ return "Module has wrong symbol version";
+ case EINVAL:
+ return "Invalid parameters";
+ default:
+ return strerror(err);
+ }
+}
+
+static void *grab_file(const char *filename, unsigned long *size)
+{
+ unsigned int max = 16384;
+ int ret, fd;
+ void *buffer = malloc(max);
+
+ if (streq(filename, "-"))
+ fd = dup(STDIN_FILENO);
+ else
+ fd = open(filename, O_RDONLY, 0);
+
+ if (fd < 0)
+ return NULL;
+
+ *size = 0;
+ while ((ret = read(fd, buffer + *size, max - *size)) > 0) {
+ *size += ret;
+ if (*size == max)
+ buffer = realloc(buffer, max *= 2);
+ }
+ if (ret < 0) {
+ free(buffer);
+ buffer = NULL;
+ }
+ close(fd);
+ return buffer;
+}
+
+int main(int argc, char *argv[])
+{
+ int i;
+ long int ret;
+ unsigned long len;
+ void *file;
+ char *filename, *options = strdup("");
+ char *progname = argv[0];
+
+ if (argv[1] && (streq(argv[1], "--version") || streq(argv[1], "-V"))) {
+ puts("klibc insmod");
+ exit(0);
+ }
+
+ /* Ignore old options, for backwards compat. */
+ while (argv[1] && (streq(argv[1], "-p")
+ || streq(argv[1], "-s")
+ || streq(argv[1], "-f"))) {
+ argv++;
+ argc--;
+ }
+
+ filename = argv[1];
+ if (!filename)
+ print_usage(progname);
+
+ /* Rest is options */
+ for (i = 2; i < argc; i++) {
+ options = realloc(options,
+ strlen(options) + 2 + strlen(argv[i]) + 2);
+ /* Spaces handled by "" pairs, but no way of escaping
+ quotes */
+ if (strchr(argv[i], ' '))
+ strcat(options, "\"");
+ strcat(options, argv[i]);
+ if (strchr(argv[i], ' '))
+ strcat(options, "\"");
+ strcat(options, " ");
+ }
+
+ file = grab_file(filename, &len);
+ if (!file) {
+ fprintf(stderr, "insmod: can't read '%s': %s\n",
+ filename, strerror(errno));
+ exit(1);
+ }
+
+ ret = init_module(file, len, options);
+ if (ret != 0) {
+ fprintf(stderr, "insmod: error inserting '%s': %li %s\n",
+ filename, ret, moderror(errno));
+ exit(1);
+ }
+ exit(0);
+}
diff --git a/usr/utils/ln.c b/usr/utils/ln.c
new file mode 100644
index 0000000..e826eb8
--- /dev/null
+++ b/usr/utils/ln.c
@@ -0,0 +1,77 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#include <linux/limits.h>
+
+int main(int argc, char *argv[])
+{
+ int c, s, f;
+ char *p;
+ struct stat sb;
+
+ s = f = 0;
+ do {
+ c = getopt(argc, argv, "sf");
+ if (c == EOF)
+ break;
+
+ switch (c) {
+
+ case 's':
+ s = 1;
+ break;
+ case 'f':
+ f = 1;
+ break;
+ case '?':
+ fprintf(stderr, "%s: invalid option -%c\n",
+ argv[0], optopt);
+ return 1;
+ }
+
+ } while (1);
+
+ if (optind == argc) {
+ fprintf(stderr, "Usage: %s [-s] [-f] target link\n", argv[0]);
+ return 1;
+ }
+
+ memset(&sb, 0, sizeof(struct stat));
+ if (stat(argv[argc - 1], &sb) < 0 && argc - optind > 2) {
+ if (!(S_ISDIR(sb.st_mode))) {
+ fprintf(stderr,
+ "multiple targets and %s is not a directory\n",
+ argv[argc - 1]);
+ return 1;
+ }
+ }
+
+ for (c = optind; c < argc - 1; c++) {
+ char target[PATH_MAX];
+
+ p = strrchr(argv[c], '/');
+ p++;
+
+ if (S_ISDIR(sb.st_mode))
+ snprintf(target, PATH_MAX, "%s/%s", argv[argc - 1], p);
+ else
+ snprintf(target, PATH_MAX, "%s", argv[argc - 1]);
+
+ if (f)
+ unlink(target);
+
+ if (s) {
+ if (symlink(argv[c], target) == -1)
+ perror(target);
+ } else {
+ if (link(argv[c], target) == -1)
+ perror(target);
+ }
+ }
+
+ return 0;
+}
diff --git a/usr/utils/minips.c b/usr/utils/minips.c
new file mode 100644
index 0000000..97893c2
--- /dev/null
+++ b/usr/utils/minips.c
@@ -0,0 +1,508 @@
+/*
+ * Copyright 1998 by Albert Cahalan; all rights reserved.
+ * This file may be used subject to the terms and conditions of the
+ * GNU Library General Public License Version 2, or any later version
+ * at your option, as published by the Free Software Foundation.
+ * 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 Library General Public License for more details.
+ */
+
+/* This is a minimal /bin/ps, designed to be smaller than the old ps
+ * while still supporting some of the more important features of the
+ * new ps. (for total size, note that this ps does not need libproc)
+ * It is suitable for Linux-on-a-floppy systems only.
+ *
+ * Maintainers: do not compile or install for normal systems.
+ * Anyone needing this will want to tweak their compiler anyway.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <dirent.h>
+#include <unistd.h>
+
+#include <asm/param.h> /* HZ */
+
+static int P_euid;
+static int P_pid;
+static char P_cmd[16];
+static char P_state;
+static int P_ppid, P_pgrp, P_session, P_tty, P_tpgid;
+static unsigned long P_flags, P_min_flt, P_cmin_flt, P_maj_flt, P_cmaj_flt,
+ P_utime, P_stime;
+static long P_cutime, P_cstime, P_priority, P_nice, P_timeout, P_it_real_value;
+static unsigned long P_start_time, P_vsize;
+static long P_rss;
+static unsigned long P_rss_rlim, P_start_code, P_end_code, P_start_stack,
+ P_kstk_esp, P_kstk_eip;
+static unsigned P_signal, P_blocked, P_sigignore, P_sigcatch;
+static unsigned long P_wchan, P_nswap, P_cnswap;
+
+#if 0
+static int screen_cols = 80;
+static int w_count;
+#endif
+
+static int want_one_pid;
+static const char *want_one_command;
+static int select_notty;
+static int select_all;
+
+static int ps_format;
+static int old_h_option;
+
+/* we only pretend to support this */
+static int show_args; /* implicit with -f and all BSD options */
+static int bsd_c_option; /* this option overrides the above */
+
+static int ps_argc; /* global argc */
+static char **ps_argv; /* global argv */
+static int thisarg; /* index into ps_argv */
+static char *flagptr; /* current location in ps_argv[thisarg] */
+
+#ifndef HZ
+#warning HZ not defined, assuming it is 100
+#define HZ 100
+#endif
+
+int page_shift; /* Page size as shift count */
+
+static void usage(void)
+{
+ fprintf(stderr,
+ "-C select by command name (minimal ps only accepts one)\n"
+ "-p select by process ID (minimal ps only accepts one)\n"
+ "-e all processes (same as ax)\n"
+ "a all processes w/ tty, including other users\n"
+ "x processes w/o controlling ttys\n"
+ "-f full format\n"
+ "-j,j job control format\n"
+ "v virtual memory format\n"
+ "-l,l long format\n"
+ "u user-oriented format\n"
+ "-o user-defined format (limited support, only \"ps -o pid=\")\n"
+ "h no header\n"
+/*
+ "-A all processes (same as ax)\n"
+ "c true command name\n"
+ "-w,w wide output\n"
+*/
+ );
+ exit(1);
+}
+
+/*
+ * Return the next argument, or call the usage function.
+ * This handles both: -oFOO -o FOO
+ */
+static const char *get_opt_arg(void)
+{
+ const char *ret;
+ ret = flagptr + 1; /* assume argument is part of ps_argv[thisarg] */
+ if (*ret)
+ return ret;
+ if (++thisarg >= ps_argc)
+ usage(); /* there is nothing left */
+ /* argument is the new ps_argv[thisarg] */
+ ret = ps_argv[thisarg];
+ if (!ret || !*ret)
+ usage();
+ return ret;
+}
+
+/* return the PID, or 0 if nothing good */
+static void parse_pid(const char *str)
+{
+ char *endp;
+ int num;
+ if (!str)
+ goto bad;
+ num = strtol(str, &endp, 0);
+ if (*endp != '\0')
+ goto bad;
+ if (num < 1)
+ goto bad;
+ if (want_one_pid)
+ goto bad;
+ want_one_pid = num;
+ return;
+ bad:
+ usage();
+}
+
+/***************** parse SysV options, including Unix98 *****************/
+static void parse_sysv_option(void)
+{
+ do {
+ switch (*flagptr) {
+ /**** selection ****/
+ case 'C': /* end */
+ if (want_one_command)
+ usage();
+ want_one_command = get_opt_arg();
+ return; /* can't have any more options */
+ case 'p': /* end */
+ parse_pid(get_opt_arg());
+ return; /* can't have any more options */
+ case 'A':
+ case 'e':
+ select_all++;
+ select_notty++;
+ case 'w': /* here for now, since the real one is not used */
+ break;
+ /**** output format ****/
+ case 'f':
+ show_args = 1;
+ /* FALL THROUGH */
+ case 'j':
+ case 'l':
+ if (ps_format)
+ usage();
+ ps_format = *flagptr;
+ break;
+ case 'o': /* end */
+ /* We only support a limited form: "ps -o pid=" (yes, just "pid=") */
+ if (strcmp(get_opt_arg(), "pid="))
+ usage();
+ if (ps_format)
+ usage();
+ ps_format = 'o';
+ old_h_option++;
+ return; /* can't have any more options */
+ /**** other stuff ****/
+#if 0
+ case 'w':
+ w_count++;
+ break;
+#endif
+ default:
+ usage();
+ } /* switch */
+ } while (*++flagptr);
+}
+
+/************************* parse BSD options **********************/
+static void parse_bsd_option(void)
+{
+ do {
+ switch (*flagptr) {
+ /**** selection ****/
+ case 'a':
+ select_all++;
+ break;
+ case 'x':
+ select_notty++;
+ break;
+ case 'p': /* end */
+ parse_pid(get_opt_arg());
+ return; /* can't have any more options */
+ /**** output format ****/
+ case 'j':
+ case 'l':
+ case 'u':
+ case 'v':
+ if (ps_format)
+ usage();
+ ps_format = 0x80 | *flagptr; /* use 0x80 to tell BSD from SysV */
+ break;
+ /**** other stuff ****/
+ case 'c':
+ bsd_c_option++;
+#if 0
+ break;
+#endif
+ case 'w':
+#if 0
+ w_count++;
+#endif
+ break;
+ case 'h':
+ old_h_option++;
+ break;
+ default:
+ usage();
+ } /* switch */
+ } while (*++flagptr);
+}
+
+#if 0
+/* not used yet */
+static void choose_dimensions(void)
+{
+ struct winsize ws;
+ char *columns;
+ /* screen_cols is 80 by default */
+ if (ioctl(1, TIOCGWINSZ, &ws) != -1 && ws.ws_col > 30)
+ screen_cols = ws.ws_col;
+ columns = getenv("COLUMNS");
+ if (columns && *columns) {
+ long t;
+ char *endptr;
+ t = strtol(columns, &endptr, 0);
+ if (!*endptr && (t > 30) && (t < (long)999999999))
+ screen_cols = (int)t;
+ }
+ if (w_count && (screen_cols < 132))
+ screen_cols = 132;
+ if (w_count > 1)
+ screen_cols = 999999999;
+}
+#endif
+
+static void arg_parse(int argc, char *argv[])
+{
+ int sel = 0; /* to verify option sanity */
+ ps_argc = argc;
+ ps_argv = argv;
+ thisarg = 0;
+ /**** iterate over the args ****/
+ while (++thisarg < ps_argc) {
+ flagptr = ps_argv[thisarg];
+ switch (*flagptr) {
+ case '0'...'9':
+ show_args = 1;
+ parse_pid(flagptr);
+ break;
+ case '-':
+ flagptr++;
+ parse_sysv_option();
+ break;
+ default:
+ show_args = 1;
+ parse_bsd_option();
+ break;
+ }
+ }
+ /**** sanity check and clean-up ****/
+ if (want_one_pid)
+ sel++;
+ if (want_one_command)
+ sel++;
+ if (select_notty || select_all)
+ sel++;
+ if (sel > 1 || select_notty > 1 || select_all > 1 || bsd_c_option > 1
+ || old_h_option > 1)
+ usage();
+ if (bsd_c_option)
+ show_args = 0;
+}
+
+/* return 1 if it works, or 0 for failure */
+static int stat2proc(int pid)
+{
+ char buf[800]; /* about 40 fields, 64-bit decimal is about 20 chars */
+ int num;
+ int fd;
+ char *tmp;
+ struct stat sb; /* stat() used to get EUID */
+ snprintf(buf, 32, "/proc/%d/stat", pid);
+ if ((fd = open(buf, O_RDONLY, 0)) == -1)
+ return 0;
+ num = read(fd, buf, sizeof buf - 1);
+ fstat(fd, &sb);
+ P_euid = sb.st_uid;
+ close(fd);
+ if (num < 80)
+ return 0;
+ buf[num] = '\0';
+ tmp = strrchr(buf, ')'); /* split into "PID (cmd" and "<rest>" */
+ *tmp = '\0'; /* replace trailing ')' with NUL */
+ /* parse these two strings separately, skipping the leading "(". */
+ memset(P_cmd, 0, sizeof P_cmd); /* clear */
+ sscanf(buf, "%d (%15c", &P_pid, P_cmd); /* comm[16] in kernel */
+ num = sscanf(tmp + 2, /* skip space after ')' too */
+ "%c " "%d %d %d %d %d " "%lu %lu %lu %lu %lu %lu %lu " "%ld %ld %ld %ld %ld %ld " "%lu %lu " "%ld " "%lu %lu %lu %lu %lu %lu " "%u %u %u %u " /* no use for RT signals */
+ "%lu %lu %lu",
+ &P_state,
+ &P_ppid, &P_pgrp, &P_session, &P_tty, &P_tpgid,
+ &P_flags, &P_min_flt, &P_cmin_flt, &P_maj_flt, &P_cmaj_flt,
+ &P_utime, &P_stime, &P_cutime, &P_cstime, &P_priority,
+ &P_nice, &P_timeout, &P_it_real_value, &P_start_time,
+ &P_vsize, &P_rss, &P_rss_rlim, &P_start_code, &P_end_code,
+ &P_start_stack, &P_kstk_esp, &P_kstk_eip, &P_signal,
+ &P_blocked, &P_sigignore, &P_sigcatch, &P_wchan, &P_nswap,
+ &P_cnswap);
+/* fprintf(stderr, "stat2proc converted %d fields.\n",num); */
+ P_vsize /= 1024;
+ P_rss <<= page_shift - 10;
+ if (num < 30)
+ return 0;
+ if (P_pid != pid)
+ return 0;
+ return 1;
+}
+
+static const char *do_time(unsigned long t)
+{
+ int hh, mm, ss;
+ static char buf[32];
+ int cnt = 0;
+ t /= HZ;
+ ss = t % 60;
+ t /= 60;
+ mm = t % 60;
+ t /= 60;
+ hh = t % 24;
+ t /= 24;
+ if (t)
+ cnt = snprintf(buf, sizeof buf, "%d-", (int)t);
+ snprintf(cnt + buf, sizeof(buf) - cnt, "%02d:%02d:%02d", hh, mm, ss);
+ return buf;
+}
+
+static void print_proc(void)
+{
+ char tty[16];
+ snprintf(tty, sizeof tty, "%3d,%-3d", (P_tty >> 8) & 0xff,
+ P_tty & 0xff);
+ switch (ps_format) {
+ case 0:
+ printf("%5d %s %s", P_pid, tty, do_time(P_utime + P_stime));
+ break;
+ case 'o':
+ printf("%d\n", P_pid);
+ return; /* don't want the command */
+ case 'l':
+ printf("%03x %c %5d %5d %5d - %3d %3d - "
+ "%5ld %06x %s %s",
+ (unsigned)P_flags & 0x777, P_state, P_euid, P_pid,
+ P_ppid, (int)P_priority, (int)P_nice,
+ P_vsize >> (page_shift - 10),
+ (unsigned)(P_wchan & 0xffffff), tty,
+ do_time(P_utime + P_stime)
+ );
+ break;
+ case 'f':
+ printf("%5d %5d %5d - - %s %s",
+ P_euid, P_pid, P_ppid, tty, do_time(P_utime + P_stime)
+ );
+ break;
+ case 'j':
+ printf("%5d %5d %5d %s %s",
+ P_pid, P_pgrp, P_session, tty, do_time(P_utime + P_stime)
+ );
+ break;
+ case 'u' | 0x80:
+ printf("%5d %5d - - %5ld %5ld %s %c - %s",
+ P_euid, P_pid, P_vsize, P_rss, tty, P_state,
+ do_time(P_utime + P_stime)
+ );
+ break;
+ case 'v' | 0x80:
+ printf("%5d %s %c %s %6d - - %5d -",
+ P_pid, tty, P_state, do_time(P_utime + P_stime),
+ (int)P_maj_flt, (int)P_rss);
+ break;
+ case 'j' | 0x80:
+ printf("%5d %5d %5d %5d %s %5d %c %5d %s",
+ P_ppid, P_pid, P_pgrp, P_session, tty, P_tpgid, P_state,
+ P_euid, do_time(P_utime + P_stime)
+ );
+ break;
+ case 'l' | 0x80:
+ printf("%03x %5d %5d %5d %3d %3d "
+ "%5ld %4ld %06x %c %s %s",
+ (unsigned)P_flags & 0x777, P_euid, P_pid, P_ppid,
+ (int)P_priority, (int)P_nice, P_vsize, P_rss,
+ (unsigned)(P_wchan & 0xffffff), P_state, tty,
+ do_time(P_utime + P_stime)
+ );
+ break;
+ default:
+ break;
+ }
+ if (show_args)
+ printf(" [%s]\n", P_cmd);
+ else
+ printf(" %s\n", P_cmd);
+}
+
+int main(int argc, char *argv[])
+{
+ arg_parse(argc, argv);
+
+ page_shift = __getpageshift();
+
+#if 0
+ choose_dimensions();
+#endif
+ if (!old_h_option) {
+ const char *head;
+ switch (ps_format) {
+ default: /* can't happen */
+ case 0:
+ head = " PID TTY TIME CMD";
+ break;
+ case 'l':
+ head =
+ " F S UID PID PPID C PRI NI ADDR SZ WCHAN TTY TIME CMD";
+ break;
+ case 'f':
+ head =
+ " UID PID PPID C STIME TTY TIME CMD";
+ break;
+ case 'j':
+ head = " PID PGID SID TTY TIME CMD";
+ break;
+ case 'u' | 0x80:
+ head =
+ " UID PID %CPU %MEM VSZ RSS TTY S START TIME COMMAND";
+ break;
+ case 'v' | 0x80:
+ head =
+ " PID TTY S TIME MAJFL TRS DRS RSS %MEM COMMAND";
+ break;
+ case 'j' | 0x80:
+ head =
+ " PPID PID PGID SID TTY TPGID S UID TIME COMMAND";
+ break;
+ case 'l' | 0x80:
+ head =
+ " F UID PID PPID PRI NI VSZ RSS WCHAN S TTY TIME COMMAND";
+ break;
+ }
+ printf("%s\n", head);
+ }
+ if (want_one_pid) {
+ if (stat2proc(want_one_pid))
+ print_proc();
+ else
+ exit(1);
+ } else {
+ struct dirent *ent; /* dirent handle */
+ DIR *dir;
+ int ouruid;
+ int found_a_proc;
+ found_a_proc = 0;
+ ouruid = getuid();
+ dir = opendir("/proc");
+ while ((ent = readdir(dir))) {
+ if (*ent->d_name < '0' || *ent->d_name > '9')
+ continue;
+ if (!stat2proc(atoi(ent->d_name)))
+ continue;
+ if (want_one_command) {
+ if (strcmp(want_one_command, P_cmd))
+ continue;
+ } else {
+ if (!select_notty && P_tty == -1)
+ continue;
+ if (!select_all && P_euid != ouruid)
+ continue;
+ }
+ found_a_proc++;
+ print_proc();
+ }
+ closedir(dir);
+ exit(!found_a_proc);
+ }
+ return 0;
+}
diff --git a/usr/utils/mkdir.c b/usr/utils/mkdir.c
new file mode 100644
index 0000000..1275472
--- /dev/null
+++ b/usr/utils/mkdir.c
@@ -0,0 +1,150 @@
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "file_mode.h"
+
+static mode_t leaf_mode, subdir_mode;
+static int p_flag;
+
+char *progname;
+
+static int make_one_dir(char *dir, mode_t mode)
+{
+ struct stat stbuf;
+
+ if (mkdir(dir, mode) == -1) {
+ int err = errno;
+
+ /*
+ * Ignore the error if it all of the following
+ * are satisfied:
+ * - error was EEXIST
+ * - -p was specified
+ * - stat indicates that its a directory
+ */
+ if (p_flag && errno == EEXIST &&
+ stat(dir, &stbuf) == 0 && S_ISDIR(stbuf.st_mode))
+ return 1;
+ errno = err;
+ fprintf(stderr, "%s: ", progname);
+ perror(dir);
+ return -1;
+ }
+ return 0;
+}
+
+static int make_dir(char *dir)
+{
+ int ret;
+
+ if (p_flag) {
+ char *s, *p;
+
+ /*
+ * Recurse each directory, trying to make it
+ * as we go. Should we check to see if it
+ * exists, and if so if it's a directory
+ * before calling mkdir?
+ */
+ s = dir;
+ while ((p = strchr(s, '/')) != NULL) {
+ /*
+ * Ignore the leading /
+ */
+ if (p != dir) {
+ *p = '\0';
+
+ /*
+ * Make the intermediary directory. POSIX
+ * says that these directories are created
+ * with umask,u+wx
+ */
+ if (make_one_dir(dir, subdir_mode) == -1)
+ return -1;
+
+ *p = '/';
+ }
+ s = p + 1;
+ }
+ }
+
+ /*
+ * Make the final target. Only complain if the
+ * target already exists if -p was not specified.
+ * This is created with the asked for mode & ~umask
+ */
+ ret = make_one_dir(dir, leaf_mode);
+ if (ret == -1)
+ return -1;
+
+ /*
+ * We might not set all the permission bits. Do that
+ * here (but only if we did create it.)
+ */
+ if (ret == 0 && chmod(dir, leaf_mode) == -1) {
+ int err_save = errno;
+
+ /*
+ * We failed, remove the directory we created
+ */
+ rmdir(dir);
+ errno = err_save;
+ fprintf(stderr, "%s: ", progname);
+ perror(dir);
+ return -1;
+ }
+ return 0;
+}
+
+int main(int argc, char *argv[])
+{
+ int c, ret = 0;
+ mode_t saved_umask;
+
+ progname = argv[0];
+
+ saved_umask = umask(0);
+ leaf_mode = (S_IRWXU | S_IRWXG | S_IRWXO) & ~saved_umask;
+ subdir_mode = (saved_umask ^ (S_IRWXU | S_IRWXG | S_IRWXO))
+ | S_IWUSR | S_IXUSR;
+
+ do {
+ c = getopt(argc, argv, "pm:");
+ if (c == EOF)
+ break;
+ switch (c) {
+ case 'm':
+ leaf_mode =
+ parse_file_mode(optarg, leaf_mode, saved_umask);
+ break;
+ case 'p':
+ p_flag = 1;
+ break;
+
+ case '?':
+ fprintf(stderr, "%s: invalid option -%c\n",
+ progname, optopt);
+ exit(1);
+ }
+ } while (1);
+
+ if (optind == argc) {
+ fprintf(stderr, "Usage: %s [-p] [-m mode] dir...\n", progname);
+ exit(1);
+ }
+
+ while (optind < argc) {
+ if (make_dir(argv[optind]))
+ ret = 255; /* seems to be what gnu mkdir does */
+ optind++;
+ }
+
+ return ret;
+}
diff --git a/usr/utils/mkfifo.c b/usr/utils/mkfifo.c
new file mode 100644
index 0000000..f2ac35f
--- /dev/null
+++ b/usr/utils/mkfifo.c
@@ -0,0 +1,71 @@
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "file_mode.h"
+
+static mode_t leaf_mode;
+
+char *progname;
+
+static int make_fifo(char *dir)
+{
+ if (mkfifo(dir, leaf_mode)) {
+ /*
+ * We failed, remove the directory we created.
+ */
+ fprintf(stderr, "%s: ", progname);
+ perror(dir);
+ return -1;
+ }
+ return 0;
+}
+
+int main(int argc, char *argv[])
+{
+ int c, ret = 0;
+ mode_t saved_umask;
+
+ progname = argv[0];
+
+ saved_umask = umask(0);
+ leaf_mode =
+ (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH) &
+ ~saved_umask;
+
+ do {
+ c = getopt(argc, argv, "m:");
+ if (c == EOF)
+ break;
+ switch (c) {
+ case 'm':
+ leaf_mode =
+ parse_file_mode(optarg, leaf_mode, saved_umask);
+ break;
+
+ case '?':
+ fprintf(stderr, "%s: invalid option -%c\n",
+ progname, optopt);
+ exit(1);
+ }
+ } while (1);
+
+ if (optind == argc) {
+ fprintf(stderr, "Usage: %s [-m mode] file...\n", progname);
+ exit(1);
+ }
+
+ while (optind < argc) {
+ if (make_fifo(argv[optind]))
+ ret = 255; /* seems to be what gnu mkdir does */
+ optind++;
+ }
+
+ return ret;
+}
diff --git a/usr/utils/mknod.c b/usr/utils/mknod.c
new file mode 100644
index 0000000..1facda7
--- /dev/null
+++ b/usr/utils/mknod.c
@@ -0,0 +1,58 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/stat.h>
+
+char *progname;
+
+static __noreturn usage(void)
+{
+ fprintf(stderr, "Usage: %s name {b|c} major minor\n", progname);
+ exit(1);
+}
+
+int main(int argc, char *argv[], char *envp[])
+{
+ char *name = NULL, *endp;
+ unsigned int major, minor;
+ mode_t mode;
+ dev_t dev;
+
+ progname = argv[0];
+ if (argc != 5)
+ usage();
+
+ name = argv[1];
+ if (!name) {
+ perror("device");
+ usage();
+ }
+
+ mode = 0666;
+ if (argv[2][0] == 'c')
+ mode |= S_IFCHR;
+ else if (argv[2][0] == 'b')
+ mode |= S_IFBLK;
+ else {
+ perror("block or char devices.");
+ usage();
+ }
+
+ major = strtol(argv[3], &endp, 0);
+ if (*endp != '\0') {
+ perror("major.");
+ usage();
+ }
+ minor = strtol(argv[4], &endp, 0);
+ if (*endp != '\0') {
+ perror("minor.");
+ usage();
+ }
+ dev = makedev(major, minor);
+
+ if (mknod(name, mode, dev) == -1) {
+ perror("mknod");
+ exit(1);
+ }
+
+ exit(0);
+}
diff --git a/usr/utils/mount_main.c b/usr/utils/mount_main.c
new file mode 100644
index 0000000..347ff0c
--- /dev/null
+++ b/usr/utils/mount_main.c
@@ -0,0 +1,105 @@
+/*
+ * mount.c, by rmk
+ */
+#include <sys/mount.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "mount_opts.h"
+
+char *progname;
+
+static struct extra_opts extra;
+static unsigned long rwflag;
+
+static int
+do_mount(char *dev, char *dir, char *type, unsigned long rwflag, void *data)
+{
+ char *s;
+ int error = 0;
+
+ while ((s = strsep(&type, ",")) != NULL) {
+ retry:
+ if (mount(dev, dir, s, rwflag, data) == -1) {
+ error = errno;
+ /*
+ * If the filesystem is not found, or the
+ * superblock is invalid, try the next.
+ */
+ if (error == ENODEV || error == EINVAL)
+ continue;
+
+ /*
+ * If we get EACCESS, and we're trying to
+ * mount readwrite and this isn't a remount,
+ * try read only.
+ */
+ if (error == EACCES &&
+ (rwflag & (MS_REMOUNT | MS_RDONLY)) == 0) {
+ rwflag |= MS_RDONLY;
+ goto retry;
+ }
+ break;
+ }
+ }
+
+ if (error) {
+ errno = error;
+ perror("mount");
+ return 255;
+ }
+
+ return 0;
+}
+
+int main(int argc, char *argv[])
+{
+ char *type = NULL;
+ int c;
+
+ progname = argv[0];
+ rwflag = MS_VERBOSE;
+
+ do {
+ c = getopt(argc, argv, "o:rt:w");
+ if (c == EOF)
+ break;
+ switch (c) {
+ case 'o':
+ rwflag = parse_mount_options(optarg, rwflag, &extra);
+ break;
+ case 'r':
+ rwflag |= MS_RDONLY;
+ break;
+ case 't':
+ type = optarg;
+ break;
+ case 'w':
+ rwflag &= ~MS_RDONLY;
+ break;
+ case '?':
+ fprintf(stderr, "%s: invalid option -%c\n",
+ progname, optopt);
+ exit(1);
+ }
+ } while (1);
+
+ /*
+ * If remount, bind or move was specified, then we don't
+ * have a "type" as such. Use the dummy "none" type.
+ */
+ if (rwflag & MS_TYPE)
+ type = "none";
+
+ if (optind + 2 != argc || type == NULL) {
+ fprintf(stderr, "Usage: %s [-r] [-w] [-o options] [-t type] "
+ "device directory\n", progname);
+ exit(1);
+ }
+
+ return do_mount(argv[optind], argv[optind + 1], type, rwflag,
+ extra.str);
+}
diff --git a/usr/utils/mount_opts.c b/usr/utils/mount_opts.c
new file mode 100644
index 0000000..f2a8047
--- /dev/null
+++ b/usr/utils/mount_opts.c
@@ -0,0 +1,94 @@
+/*
+ * mount_opts.c, by rmk
+ *
+ * Decode mount options.
+ */
+#include <sys/mount.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "mount_opts.h"
+
+#define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0]))
+
+static const struct mount_opts options[] = {
+ /* name mask set noset */
+ {"async", MS_SYNCHRONOUS, 0, MS_SYNCHRONOUS},
+ {"atime", MS_NOATIME, 0, MS_NOATIME},
+ {"bind", MS_TYPE, MS_BIND, 0,},
+ {"dev", MS_NODEV, 0, MS_NODEV},
+ {"diratime", MS_NODIRATIME, 0, MS_NODIRATIME},
+ {"dirsync", MS_DIRSYNC, MS_DIRSYNC, 0},
+ {"exec", MS_NOEXEC, 0, MS_NOEXEC},
+ {"move", MS_TYPE, MS_MOVE, 0},
+ {"recurse", MS_REC, MS_REC, 0},
+ {"remount", MS_TYPE, MS_REMOUNT, 0},
+ {"ro", MS_RDONLY, MS_RDONLY, 0},
+ {"rw", MS_RDONLY, 0, MS_RDONLY},
+ {"suid", MS_NOSUID, 0, MS_NOSUID},
+ {"sync", MS_SYNCHRONOUS, MS_SYNCHRONOUS, 0},
+ {"verbose", MS_VERBOSE, MS_VERBOSE, 0},
+};
+
+static void add_extra_option(struct extra_opts *extra, char *s)
+{
+ int len = strlen(s);
+ int newlen = extra->used_size + len;
+
+ if (extra->str)
+ len++; /* +1 for ',' */
+
+ if (newlen >= extra->alloc_size) {
+ char *new;
+
+ new = realloc(extra->str, newlen + 1); /* +1 for NUL */
+ if (!new)
+ return;
+
+ extra->str = new;
+ extra->end = extra->str + extra->used_size;
+ extra->alloc_size = newlen;
+ }
+
+ if (extra->used_size) {
+ *extra->end = ',';
+ extra->end++;
+ }
+ strcpy(extra->end, s);
+ extra->used_size += len;
+
+}
+
+unsigned long
+parse_mount_options(char *arg, unsigned long rwflag, struct extra_opts *extra)
+{
+ char *s;
+
+ while ((s = strsep(&arg, ",")) != NULL) {
+ char *opt = s;
+ unsigned int i;
+ int res, no = s[0] == 'n' && s[1] == 'o';
+
+ if (no)
+ s += 2;
+
+ for (i = 0, res = 1; i < ARRAY_SIZE(options); i++) {
+ res = strcmp(s, options[i].str);
+
+ if (res == 0) {
+ rwflag &= ~options[i].rwmask;
+ if (no)
+ rwflag |= options[i].rwnoset;
+ else
+ rwflag |= options[i].rwset;
+ }
+ if (res <= 0)
+ break;
+ }
+
+ if (res != 0 && s[0])
+ add_extra_option(extra, opt);
+ }
+
+ return rwflag;
+}
diff --git a/usr/utils/mount_opts.h b/usr/utils/mount_opts.h
new file mode 100644
index 0000000..2353262
--- /dev/null
+++ b/usr/utils/mount_opts.h
@@ -0,0 +1,21 @@
+struct mount_opts {
+ const char str[8];
+ unsigned long rwmask;
+ unsigned long rwset;
+ unsigned long rwnoset;
+};
+
+struct extra_opts {
+ char *str;
+ char *end;
+ int used_size;
+ int alloc_size;
+};
+
+/*
+ * These options define the function of "mount(2)".
+ */
+#define MS_TYPE (MS_REMOUNT|MS_BIND|MS_MOVE)
+
+unsigned long
+parse_mount_options(char *arg, unsigned long rwflag, struct extra_opts *extra);
diff --git a/usr/utils/nuke.c b/usr/utils/nuke.c
new file mode 100644
index 0000000..b0e4f8e
--- /dev/null
+++ b/usr/utils/nuke.c
@@ -0,0 +1,134 @@
+/* ----------------------------------------------------------------------- *
+ *
+ * Copyright 2004 H. Peter Anvin - All Rights Reserved
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom
+ * the Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall
+ * be included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * nuke.c
+ *
+ * Simple program which does the same thing as rm -rf, except it takes
+ * no options and can therefore not get confused by filenames starting
+ * with -. Similarly, an empty list of inputs is assumed to mean don't
+ * do anything.
+ */
+
+#include <alloca.h>
+#include <assert.h>
+#include <dirent.h>
+#include <errno.h>
+#include <string.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+static const char *program;
+
+static int nuke(const char *what);
+
+static int nuke_dirent(int len, const char *dir, const char *name)
+{
+ int bytes = len + strlen(name) + 2;
+ char path[bytes];
+ int xlen;
+
+ xlen = snprintf(path, bytes, "%s/%s", dir, name);
+ assert(xlen < bytes);
+
+ return nuke(path);
+}
+
+/* Wipe the contents of a directory, but not the directory itself */
+static int nuke_dir(const char *what)
+{
+ int len = strlen(what);
+ DIR *dir;
+ struct dirent *d;
+ int err = 0;
+
+ if (!(dir = opendir(what))) {
+ /* EACCES means we can't read it. Might be empty and removable;
+ if not, the rmdir() in nuke() will trigger an error. */
+ return (errno == EACCES) ? 0 : errno;
+ }
+
+ while ((d = readdir(dir))) {
+ /* Skip . and .. */
+ if (d->d_name[0] == '.' &&
+ (d->d_name[1] == '\0' ||
+ (d->d_name[1] == '.' && d->d_name[2] == '\0')))
+ continue;
+
+ err = nuke_dirent(len, what, d->d_name);
+ if (err) {
+ closedir(dir);
+ return err;
+ }
+ }
+
+ closedir(dir);
+
+ return 0;
+}
+
+static int nuke(const char *what)
+{
+ int rv;
+ int err = 0;
+
+ rv = unlink(what);
+ if (rv < 0) {
+ if (errno == EISDIR) {
+ /* It's a directory. */
+ err = nuke_dir(what);
+ if (!err)
+ err = rmdir(what) ? errno : err;
+ } else {
+ err = errno;
+ }
+ }
+
+ if (err) {
+ fprintf(stderr, "%s: %s: %s\n", program, what, strerror(err));
+ return err;
+ } else {
+ return 0;
+ }
+}
+
+int main(int argc, char *argv[])
+{
+ int i;
+ int err = 0;
+
+ program = argv[0];
+
+ for (i = 1; i < argc; i++) {
+ err = nuke(argv[i]);
+ if (err)
+ break;
+ }
+
+ return !!err;
+}
diff --git a/usr/utils/pivot_root.c b/usr/utils/pivot_root.c
new file mode 100644
index 0000000..7a570ed
--- /dev/null
+++ b/usr/utils/pivot_root.c
@@ -0,0 +1,19 @@
+/* pivot_root.c - Change the root file system */
+
+/* Written 2000 by Werner Almesberger */
+
+#include <stdio.h>
+#include <sys/mount.h>
+
+int main(int argc, const char **argv)
+{
+ if (argc != 3) {
+ fprintf(stderr, "Usage: %s new_root put_old\n", argv[0]);
+ return 1;
+ }
+ if (pivot_root(argv[1], argv[2]) < 0) {
+ perror("pivot_root");
+ return 1;
+ }
+ return 0;
+}
diff --git a/usr/utils/sleep.c b/usr/utils/sleep.c
new file mode 100644
index 0000000..5df6aee
--- /dev/null
+++ b/usr/utils/sleep.c
@@ -0,0 +1,25 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <time.h>
+#include <errno.h>
+
+int main(int argc, char *argv[])
+{
+ struct timespec ts;
+ char *p;
+
+ if (argc != 2)
+ goto err;
+
+ p = strtotimespec(argv[1], &ts);
+ if (*p)
+ goto err;
+
+ while (nanosleep(&ts, &ts) == -1 && errno == EINTR) ;
+
+ return 0;
+
+ err:
+ fprintf(stderr, "Usage: %s seconds[.fraction]\n", argv[0]);
+ return 1;
+}
diff --git a/usr/utils/true.c b/usr/utils/true.c
new file mode 100644
index 0000000..31dbf45
--- /dev/null
+++ b/usr/utils/true.c
@@ -0,0 +1,4 @@
+int main(void)
+{
+ return 0;
+}
diff --git a/usr/utils/umount.c b/usr/utils/umount.c
new file mode 100644
index 0000000..5628916
--- /dev/null
+++ b/usr/utils/umount.c
@@ -0,0 +1,45 @@
+/*
+ * umount.c, by rmk
+ */
+#include <sys/mount.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+char *progname;
+
+int main(int argc, char *argv[])
+{
+ int c, flag = 0;
+
+ progname = argv[0];
+
+ do {
+ c = getopt(argc, argv, "f");
+ if (c == EOF)
+ break;
+ switch (c) {
+ case 'f':
+ flag |= MNT_FORCE;
+ break;
+ case '?':
+ fprintf(stderr, "%s: invalid option -%c\n",
+ progname, optopt);
+ exit(1);
+ }
+ } while (1);
+
+ if (optind + 1 != argc) {
+ fprintf(stderr, "Usage: %s [-f] mntpoint\n", progname);
+ return 1;
+ }
+
+ if (umount2(argv[optind], flag) == -1) {
+ perror("umount2");
+ return 255;
+ }
+
+ return 0;
+}
diff --git a/usr/utils/uname.c b/usr/utils/uname.c
new file mode 100644
index 0000000..4b7bac8
--- /dev/null
+++ b/usr/utils/uname.c
@@ -0,0 +1,154 @@
+/*
+ * uname.c, by tlh
+ *
+ * The uname program for system information: kernel name, kernel
+ * release, kernel release, machine, processor, platform, os and
+ * hostname.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <string.h>
+#include <sys/utsname.h>
+
+enum uname_fields {
+ UN_SYSNAME,
+ UN_NODENAME,
+ UN_RELEASE,
+ UN_VERSION,
+ UN_MACHINE,
+#if NOT_IMPLEMENTED_PROCESSOR
+ UN_PROCESSOR,
+#endif
+ UN_HARDWARE,
+#if NOT_IMPLEMENTED_OS
+ UN_OS,
+#endif
+ UN_NR_FIELDS
+};
+
+void usage(FILE * stream, const char *progname)
+{
+ fprintf(stream,
+ "Usage: %s [OPTION] . . .\n"
+ "Print system information, No options defaults to -s.\n"
+ "\n"
+ " -a print all the information in the same order as follows below\n"
+ " -s kernel name\n"
+ " -n network node name (hostname)\n"
+ " -r kernel release\n"
+ " -v kernel version\n" " -m machine hardware name\n"
+#if NOT_IMPLEMENTED_PROCESSOR
+ " -p processor type\n"
+#endif
+ " -i hardware platform\n"
+#if NOT_IMPLEMENTED_OS
+ " -o operating system\n"
+#endif
+ "\n" " -h help/usage\n" "\n", progname);
+}
+
+char *make_hardware(const char *machine)
+{
+ char *hardware;
+
+ if (!(hardware = strdup(machine))) {
+ fprintf(stderr, "strdup() failed: %s\n", strerror(errno));
+ goto end;
+ }
+ if (strlen(hardware) == 4
+ && hardware[0] == 'i' && hardware[2] == '8' && hardware[3] == '6') {
+ hardware[1] = '3';
+ }
+ end:
+ return hardware;
+}
+
+int main(int argc, char *argv[])
+{
+ int ec = 1;
+ int opt;
+ int i;
+ int nr_pr;
+ struct utsname buf;
+ char *uname_fields[UN_NR_FIELDS] = { NULL };
+
+ if (-1 == uname(&buf)) {
+ fprintf(stderr, "uname() failure: %s\n", strerror(errno));
+ goto end;
+ }
+
+ if (1 == argc)
+ /* no options given - default to -s */
+ uname_fields[UN_SYSNAME] = buf.sysname;
+
+ while ((opt = getopt(argc, argv, "asnrvmpioh")) != -1) {
+ switch (opt) {
+ case 'a':
+ uname_fields[UN_SYSNAME] = buf.sysname;
+ uname_fields[UN_NODENAME] = buf.nodename;
+ uname_fields[UN_RELEASE] = buf.release;
+ uname_fields[UN_VERSION] = buf.version;
+ uname_fields[UN_MACHINE] = buf.machine;
+ uname_fields[UN_HARDWARE] = make_hardware(buf.machine);
+ if (!uname_fields[UN_HARDWARE])
+ goto end;
+ break;
+ case 's':
+ uname_fields[UN_SYSNAME] = buf.sysname;
+ break;
+ case 'n':
+ uname_fields[UN_NODENAME] = buf.nodename;
+ break;
+ case 'r':
+ uname_fields[UN_RELEASE] = buf.release;
+ break;
+ case 'v':
+ uname_fields[UN_VERSION] = buf.version;
+ break;
+ case 'm':
+ uname_fields[UN_MACHINE] = buf.machine;
+ break;
+#if NOT_IMPLEMENTED_PROCESSOR
+ case 'p':
+ break;
+#endif
+ case 'i':
+ uname_fields[UN_HARDWARE] = make_hardware(buf.machine);
+ if (!uname_fields[UN_HARDWARE])
+ goto end;
+ break;
+#if NOT_IMPLEMENTED_OS
+ case 'o':
+ break;
+#endif
+ case 'h':
+ usage(stdout, argv[0]);
+ ec = 0;
+ goto end;
+ break;
+ default:
+ usage(stderr, argv[0]);
+ goto end;
+ break;
+ }
+ }
+
+ for (nr_pr = 0, i = UN_SYSNAME; i < UN_NR_FIELDS; i++) {
+ if (!uname_fields[i])
+ continue;
+ if (nr_pr)
+ fputc(' ', stdout);
+ fputs(uname_fields[i], stdout);
+ nr_pr++;
+ }
+ fputc('\n', stdout);
+
+ ec = 0;
+
+ end:
+ if (uname_fields[UN_HARDWARE])
+ free(uname_fields[UN_HARDWARE]);
+ return ec;
+}