[klibc] Miscellaneous utilities for klibc A collection of minor utilities for klibc. Signed-off-by: H. Peter Anvin --- commit 2f07e6a94ccb19e7ac325cdbc725628ed7f80cd7 tree d410edaca20efe62ef2b8a7bb7992f68575bfd52 parent f18b78199b11d1e0e3ed504deed9309aff6d40f9 author H. Peter Anvin Sun, 02 Jul 2006 12:26:33 -0700 committer H. Peter Anvin Sun, 02 Jul 2006 12:26:33 -0700 usr/Kbuild | 2 usr/utils/Kbuild | 62 ++++++ usr/utils/cat.c | 329 ++++++++++++++++++++++++++++++ usr/utils/chroot.c | 25 ++ usr/utils/dd.c | 533 ++++++++++++++++++++++++++++++++++++++++++++++++ usr/utils/false.c | 4 usr/utils/file_mode.c | 143 +++++++++++++ usr/utils/file_mode.h | 1 usr/utils/halt.c | 55 +++++ usr/utils/insmod.c | 140 +++++++++++++ usr/utils/ln.c | 77 +++++++ usr/utils/minips.c | 508 ++++++++++++++++++++++++++++++++++++++++++++++ usr/utils/mkdir.c | 150 ++++++++++++++ usr/utils/mkfifo.c | 71 ++++++ usr/utils/mknod.c | 58 +++++ usr/utils/mount_main.c | 105 +++++++++ usr/utils/mount_opts.c | 94 ++++++++ usr/utils/mount_opts.h | 21 ++ usr/utils/nuke.c | 134 ++++++++++++ usr/utils/pivot_root.c | 19 ++ usr/utils/sleep.c | 25 ++ usr/utils/true.c | 4 usr/utils/umount.c | 45 ++++ usr/utils/uname.c | 154 ++++++++++++++ 24 files changed, 2758 insertions(+), 1 deletions(-) diff --git a/usr/Kbuild b/usr/Kbuild index 4b2be06..4fea24c 100644 --- a/usr/Kbuild +++ b/usr/Kbuild @@ -6,7 +6,7 @@ CONFIG_KLIBC := 1 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 +#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 +#include + +#include +#ifndef __KLIBC__ +#include +#endif +#include +#include +#ifndef __KLIBC__ +#include +#endif +#include +#include +#include +#include + +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 +#include + +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 +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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 +#include +#include +#include +#include +#include +#include + +#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 +#include +#include +#include +#include + +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 +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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 +#include +#include +#include +#include +#include + +#include + +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 +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include /* 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 "" */ + *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 +#include +#include +#include +#include +#include +#include +#include +#include + +#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 +#include +#include +#include +#include +#include +#include +#include +#include + +#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 +#include +#include + +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 +#include +#include +#include +#include +#include + +#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 +#include +#include + +#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 +#include +#include +#include +#include +#include +#include +#include + +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 +#include + +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 +#include +#include +#include + +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 +#include +#include +#include +#include +#include + +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 +#include +#include +#include +#include + +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; +}