diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-19 17:06:04 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-19 17:06:04 +0000 |
commit | 2f0649f6fe411d7e07c8d56cf8ea56db53536da8 (patch) | |
tree | 778611fb52176dce1ad06c68e87b2cb348ca0f7b /usr/utils | |
parent | Initial commit. (diff) | |
download | klibc-2f0649f6fe411d7e07c8d56cf8ea56db53536da8.tar.xz klibc-2f0649f6fe411d7e07c8d56cf8ea56db53536da8.zip |
Adding upstream version 2.0.13.upstream/2.0.13upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to '')
-rw-r--r-- | usr/utils/Kbuild | 86 | ||||
-rw-r--r-- | usr/utils/cat.c | 309 | ||||
-rw-r--r-- | usr/utils/chroot.c | 30 | ||||
-rw-r--r-- | usr/utils/cpio.c | 1079 | ||||
-rw-r--r-- | usr/utils/dd.c | 540 | ||||
-rw-r--r-- | usr/utils/dmesg.c | 79 | ||||
-rw-r--r-- | usr/utils/false.c | 4 | ||||
-rw-r--r-- | usr/utils/file_mode.c | 143 | ||||
-rw-r--r-- | usr/utils/file_mode.h | 6 | ||||
-rw-r--r-- | usr/utils/halt.c | 64 | ||||
-rw-r--r-- | usr/utils/insmod.c | 140 | ||||
-rw-r--r-- | usr/utils/kill.c | 33 | ||||
-rw-r--r-- | usr/utils/ln.c | 77 | ||||
-rw-r--r-- | usr/utils/losetup.c | 400 | ||||
-rw-r--r-- | usr/utils/ls.c | 223 | ||||
-rw-r--r-- | usr/utils/minips.c | 511 | ||||
-rw-r--r-- | usr/utils/mkdir.c | 154 | ||||
-rw-r--r-- | usr/utils/mkfifo.c | 70 | ||||
-rw-r--r-- | usr/utils/mknod.c | 84 | ||||
-rw-r--r-- | usr/utils/mount_main.c | 156 | ||||
-rw-r--r-- | usr/utils/mount_opts.c | 102 | ||||
-rw-r--r-- | usr/utils/mount_opts.h | 26 | ||||
-rw-r--r-- | usr/utils/mv.c | 69 | ||||
-rw-r--r-- | usr/utils/nuke.c | 121 | ||||
-rw-r--r-- | usr/utils/pivot_root.c | 19 | ||||
-rw-r--r-- | usr/utils/readlink.c | 57 | ||||
-rw-r--r-- | usr/utils/sleep.c | 26 | ||||
-rw-r--r-- | usr/utils/sync.c | 7 | ||||
-rw-r--r-- | usr/utils/true.c | 4 | ||||
-rw-r--r-- | usr/utils/umount.c | 51 | ||||
-rw-r--r-- | usr/utils/uname.c | 155 |
31 files changed, 4825 insertions, 0 deletions
diff --git a/usr/utils/Kbuild b/usr/utils/Kbuild new file mode 100644 index 0000000..a389c2a --- /dev/null +++ b/usr/utils/Kbuild @@ -0,0 +1,86 @@ +# +# Kbuild file for klib utils +# + +progs := chroot dd mkdir mkfifo mknod mount pivot_root umount +progs += true false sleep ln mv nuke minips cat ls losetup +progs += insmod uname halt kill readlink cpio sync dmesg + +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/dmesg-y := dmesg.o +shared/dmesg-y := dmesg.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/ls-y := ls.o +shared/ls-y := ls.o +static/mv-y := mv.o +shared/mv-y := mv.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 +static/kill-y := kill.o +shared/kill-y := kill.o +static/readlink-y := readlink.o +shared/readlink-y := readlink.o +static/cpio-y := cpio.o +shared/cpio-y := cpio.o +static/sync-y := sync.o +shared/sync-y := sync.o +static/losetup-y := losetup.o +shared/losetup-y := losetup.o + +# Additionally linked targets +always := static/reboot static/poweroff +ifdef KLIBCSHAREDFLAGS +always += shared/reboot shared/poweroff +endif + +$(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 the shared binaries by preference +ifdef KLIBCSHAREDFLAGS +install-y := $(shared-y) +else +install-y := $(static-y) +endif +install-link-y := reboot=halt poweroff=halt diff --git a/usr/utils/cat.c b/usr/utils/cat.c new file mode 100644 index 0000000..7465148 --- /dev/null +++ b/usr/utils/cat.c @@ -0,0 +1,309 @@ +/* $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 !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> +#include <errno.h> +#include <fcntl.h> +#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; + + 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': + /* unimplemented */ + 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..bc1b94f --- /dev/null +++ b/usr/utils/chroot.c @@ -0,0 +1,30 @@ +/* + * 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 (chdir("/") == -1) { + perror("chdir"); + return 1; + } + + if (execvp(argv[2], argv + 2) == -1) { + perror("execvp"); + return 1; + } + + return 0; +} diff --git a/usr/utils/cpio.c b/usr/utils/cpio.c new file mode 100644 index 0000000..9b0b6ae --- /dev/null +++ b/usr/utils/cpio.c @@ -0,0 +1,1079 @@ +/* copyin.c - extract or list a cpio archive + Copyright (C) 1990,1991,1992,2001,2002,2003,2004 Free Software Foundation, Inc. + + 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, 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 <errno.h> +#include <fcntl.h> +#include <limits.h> +#include <malloc.h> +#include <stdbool.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <time.h> +#include <unistd.h> +#include <utime.h> +#include <fnmatch.h> + +# ifndef DIRECTORY_SEPARATOR +# define DIRECTORY_SEPARATOR '/' +# endif + +# ifndef ISSLASH +# define ISSLASH(C) ((C) == DIRECTORY_SEPARATOR) +# endif + +/* Return 1 if an array of N objects, each of size S, cannot exist due + to size arithmetic overflow. S must be positive and N must be + nonnegative. This is a macro, not an inline function, so that it + works correctly even when SIZE_MAX < N. + + By gnulib convention, SIZE_MAX represents overflow in size + calculations, so the conservative dividend to use here is + SIZE_MAX - 1, since SIZE_MAX might represent an overflowed value. + However, malloc (SIZE_MAX) fails on all known hosts where + sizeof (ptrdiff_t) <= sizeof (size_t), so do not bother to test for + exactly-SIZE_MAX allocations on such hosts; this avoids a test and + branch when S is known to be 1. */ +# define xalloc_oversized(n, s) \ + ((size_t) (sizeof (ptrdiff_t) <= sizeof (size_t) ? -1 : -2) / (s) < (n)) + +#define DISK_IO_BLOCK_SIZE (512) + +char *progname = NULL; + +/* If true, print a . for each file processed. (-V) */ +char dot_flag = false; + +/* Input and output buffers. */ +char *input_buffer, *output_buffer; + +/* The size of the input buffer. */ +long input_buffer_size; + +/* Current locations in `input_buffer' and `output_buffer'. */ +char *in_buff, *out_buff; + +/* Current number of bytes stored at `input_buff' and `output_buff'. */ +long input_size, output_size; + +/* Block size value, initially 512. -B sets to 5120. */ +int io_block_size = 512; + +struct new_cpio_header { + unsigned short c_magic; + union { + struct { + unsigned long c_ino; + unsigned long c_mode; + unsigned long c_uid; + unsigned long c_gid; + unsigned long c_nlink; + unsigned long c_mtime; + unsigned long c_filesize; + long c_dev_maj; + long c_dev_min; + long c_rdev_maj; + long c_rdev_min; + unsigned long c_namesize; + unsigned long c_chksum; + }; + unsigned long c_hdr[13]; + }; + char *c_name; + char *c_tar_linkname; +}; + +/* Total number of bytes read and written for all files. + * Now that many tape drives hold more than 4Gb we need more than 32 + * bits to hold input_bytes and output_bytes. + */ +long long input_bytes, output_bytes; + +/* Allocate N bytes of memory dynamically, with error checking. */ + +static void *xmalloc(size_t n) +{ + void *p; + if (xalloc_oversized(n, 1) || (!(p = malloc(n)) && n != 0)) { + fprintf(stderr, "%s: memory exhausted\n", progname); + exit(1); + } + return p; +/* return xnmalloc_inline (n, 1); */ +} + +/* Clone STRING. */ + +static char *xstrdup(char const *string) +{ + size_t s = strlen(string) + 1; + return memcpy(xmalloc(s), string, s); +/* return xmemdup_inline (string, strlen (string) + 1); */ +} + +/* Copy NUM_BYTES of buffer `in_buff' into IN_BUF. + `in_buff' may be partly full. + When `in_buff' is exhausted, refill it from file descriptor IN_DES. */ + +static void tape_fill_input_buffer(int in_des, int num_bytes) +{ + in_buff = input_buffer; + num_bytes = (num_bytes < io_block_size) ? num_bytes : io_block_size; + input_size = read(in_des, input_buffer, num_bytes); + if (input_size < 0) { + fprintf(stderr, "%s: read error: %s\n", progname, + strerror(errno)); + exit(1); + } + if (input_size == 0) { + fprintf(stderr, "%s: premature end of file\n", progname); + exit(1); + } + input_bytes += input_size; +} + +/* Write `output_size' bytes of `output_buffer' to file + descriptor OUT_DES and reset `output_size' and `out_buff'. + If `swapping_halfwords' or `swapping_bytes' is set, + do the appropriate swapping first. Our callers have + to make sure to only set these flags if `output_size' + is appropriate (a multiple of 4 for `swapping_halfwords', + 2 for `swapping_bytes'). The fact that DISK_IO_BLOCK_SIZE + must always be a multiple of 4 helps us (and our callers) + insure this. */ + +static void disk_empty_output_buffer(int out_des) +{ + int bytes_written; + + bytes_written = write(out_des, output_buffer, output_size); + + if (bytes_written != output_size) { + fprintf(stderr, "%s: write error: %s\n", + progname, strerror(errno)); + exit(1); + } + output_bytes += output_size; + out_buff = output_buffer; + output_size = 0; +} + +/* Copy NUM_BYTES of buffer IN_BUF to `out_buff', which may be partly full. + When `out_buff' fills up, flush it to file descriptor OUT_DES. */ + +static void disk_buffered_write(char *in_buf, int out_des, long num_bytes) +{ + register long bytes_left = num_bytes; /* Bytes needing to be copied. */ + register long space_left; /* Room left in output buffer. */ + + while (bytes_left > 0) { + space_left = DISK_IO_BLOCK_SIZE - output_size; + if (space_left == 0) + disk_empty_output_buffer(out_des); + else { + if (bytes_left < space_left) + space_left = bytes_left; + memmove(out_buff, in_buf, (unsigned)space_left); + out_buff += space_left; + output_size += space_left; + in_buf += space_left; + bytes_left -= space_left; + } + } +} + +/* Copy a file using the input and output buffers, which may start out + partly full. After the copy, the files are not closed nor the last + block flushed to output, and the input buffer may still be partly + full. If `crc_i_flag' is set, add each byte to `crc'. + IN_DES is the file descriptor for input; + OUT_DES is the file descriptor for output; + NUM_BYTES is the number of bytes to copy. */ + +static void copy_files_tape_to_disk(int in_des, int out_des, long num_bytes) +{ + long size; + + while (num_bytes > 0) { + if (input_size == 0) + tape_fill_input_buffer(in_des, io_block_size); + size = (input_size < num_bytes) ? input_size : num_bytes; + disk_buffered_write(in_buff, out_des, size); + num_bytes -= size; + input_size -= size; + in_buff += size; + } +} + +/* if IN_BUF is NULL, Skip the next NUM_BYTES bytes of file descriptor IN_DES. */ +static void tape_buffered_read(char *in_buf, int in_des, long num_bytes) +{ + register long bytes_left = num_bytes; /* Bytes needing to be copied. */ + register long space_left; /* Bytes to copy from input buffer. */ + + while (bytes_left > 0) { + if (input_size == 0) + tape_fill_input_buffer(in_des, io_block_size); + if (bytes_left < input_size) + space_left = bytes_left; + else + space_left = input_size; + if (in_buf != NULL) { + memmove(in_buf, in_buff, (unsigned)space_left); + in_buf += space_left; + } + in_buff += space_left; + input_size -= space_left; + bytes_left -= space_left; + } +} + +/* Skip the next NUM_BYTES bytes of file descriptor IN_DES. */ +#define tape_toss_input(in_des,num_bytes) \ +(tape_buffered_read(NULL,(in_des),(num_bytes))) + +struct deferment { + struct deferment *next; + struct new_cpio_header header; +}; + +static struct deferment *create_deferment(struct new_cpio_header *file_hdr) +{ + struct deferment *d; + d = (struct deferment *)xmalloc(sizeof(struct deferment)); + d->header = *file_hdr; + d->header.c_name = (char *)xmalloc(strlen(file_hdr->c_name) + 1); + strcpy(d->header.c_name, file_hdr->c_name); + return d; +} + +static void free_deferment(struct deferment *d) +{ + free(d->header.c_name); + free(d); +} + +static int link_to_name(char *link_name, char *link_target) +{ + int res = link(link_target, link_name); + return res; +} + +struct inode_val { + unsigned long inode; + unsigned long major_num; + unsigned long minor_num; + char *file_name; +}; + +/* Inode hash table. Allocated by first call to add_inode. */ +static struct inode_val **hash_table = NULL; + +/* Size of current hash table. Initial size is 47. (47 = 2*22 + 3) */ +static int hash_size = 22; + +/* Number of elements in current hash table. */ +static int hash_num; + +/* Do the hash insert. Used in normal inserts and resizing the hash + table. It is guaranteed that there is room to insert the item. + NEW_VALUE is the pointer to the previously allocated inode, file + name association record. */ + +static void hash_insert(struct inode_val *new_value) +{ + int start; /* Home position for the value. */ + int temp; /* Used for rehashing. */ + + /* Hash function is node number modulo the table size. */ + start = new_value->inode % hash_size; + + /* Do the initial look into the table. */ + if (hash_table[start] == NULL) { + hash_table[start] = new_value; + return; + } + + /* If we get to here, the home position is full with a different inode + record. Do a linear search for the first NULL pointer and insert + the new item there. */ + temp = (start + 1) % hash_size; + while (hash_table[temp] != NULL) + temp = (temp + 1) % hash_size; + + /* Insert at the NULL. */ + hash_table[temp] = new_value; +} + +/* Associate FILE_NAME with the inode NODE_NUM. (Insert into hash table.) */ + +static void +add_inode(unsigned long node_num, char *file_name, unsigned long major_num, + unsigned long minor_num) +{ + struct inode_val *temp; + + /* Create new inode record. */ + temp = (struct inode_val *)xmalloc(sizeof(struct inode_val)); + temp->inode = node_num; + temp->major_num = major_num; + temp->minor_num = minor_num; + temp->file_name = xstrdup(file_name); + + /* Do we have to increase the size of (or initially allocate) + the hash table? */ + if (hash_num == hash_size || hash_table == NULL) { + struct inode_val **old_table; /* Pointer to old table. */ + int i; /* Index for re-insert loop. */ + + /* Save old table. */ + old_table = hash_table; + if (old_table == NULL) + hash_num = 0; + + /* Calculate new size of table and allocate it. + Sequence of table sizes is 47, 97, 197, 397, 797, 1597, 3197, 6397 ... + where 3197 and most of the sizes after 6397 are not prime. The other + numbers listed are prime. */ + hash_size = 2 * hash_size + 3; + hash_table = (struct inode_val **) + xmalloc(hash_size * sizeof(struct inode_val *)); + memset(hash_table, 0, hash_size * sizeof(struct inode_val *)); + + /* Insert the values from the old table into the new table. */ + for (i = 0; i < hash_num; i++) + hash_insert(old_table[i]); + + free(old_table); + } + + /* Insert the new record and increment the count of elements in the + hash table. */ + hash_insert(temp); + hash_num++; +} + +static char *find_inode_file(unsigned long node_num, unsigned long major_num, + unsigned long minor_num) +{ + int start; /* Initial hash location. */ + int temp; /* Rehash search variable. */ + + if (hash_table != NULL) { + /* Hash function is node number modulo the table size. */ + start = node_num % hash_size; + + /* Initial look into the table. */ + if (hash_table[start] == NULL) + return NULL; + if (hash_table[start]->inode == node_num + && hash_table[start]->major_num == major_num + && hash_table[start]->minor_num == minor_num) + return hash_table[start]->file_name; + + /* The home position is full with a different inode record. + Do a linear search terminated by a NULL pointer. */ + for (temp = (start + 1) % hash_size; + hash_table[temp] != NULL && temp != start; + temp = (temp + 1) % hash_size) { + if (hash_table[temp]->inode == node_num + && hash_table[start]->major_num == major_num + && hash_table[start]->minor_num == minor_num) + return hash_table[temp]->file_name; + } + } + return NULL; +} + +/* Try and create a hard link from FILE_NAME to another file + with the given major/minor device number and inode. If no other + file with the same major/minor/inode numbers is known, add this file + to the list of known files and associated major/minor/inode numbers + and return -1. If another file with the same major/minor/inode + numbers is found, try and create another link to it using + link_to_name, and return 0 for success and -1 for failure. */ + +static int +link_to_maj_min_ino(char *file_name, int st_dev_maj, int st_dev_min, int st_ino) +{ + int link_res; + char *link_name; + link_res = -1; + /* Is the file a link to a previously copied file? */ + link_name = find_inode_file(st_ino, st_dev_maj, st_dev_min); + if (link_name == NULL) + add_inode(st_ino, file_name, st_dev_maj, st_dev_min); + else + link_res = link_to_name(file_name, link_name); + return link_res; +} + +static void copyin_regular_file(struct new_cpio_header *file_hdr, + int in_file_des); + +static void warn_junk_bytes(long bytes_skipped) +{ + fprintf(stderr, "%s: warning: skipped %ld byte(s) of junk\n", + progname, bytes_skipped); +} + +/* Skip the padding on IN_FILE_DES after a header or file, + up to the next header. + The number of bytes skipped is based on OFFSET -- the current offset + from the last start of a header (or file) -- and the current + header type. */ + +static void tape_skip_padding(int in_file_des, int offset) +{ + int pad; + pad = (4 - (offset % 4)) % 4; + + if (pad != 0) + tape_toss_input(in_file_des, pad); +} + +static int +try_existing_file(struct new_cpio_header *file_hdr, int in_file_des, + int *existing_dir) +{ + struct stat file_stat; + + *existing_dir = false; + if (lstat(file_hdr->c_name, &file_stat) == 0) { + if (S_ISDIR(file_stat.st_mode) + && ((file_hdr->c_mode & S_IFMT) == S_IFDIR)) { + /* If there is already a directory there that + we are trying to create, don't complain about + it. */ + *existing_dir = true; + return 0; + } else if (S_ISDIR(file_stat.st_mode) + ? rmdir(file_hdr->c_name) + : unlink(file_hdr->c_name)) { + fprintf(stderr, "%s: cannot remove current %s: %s\n", + progname, file_hdr->c_name, strerror(errno)); + tape_toss_input(in_file_des, file_hdr->c_filesize); + tape_skip_padding(in_file_des, file_hdr->c_filesize); + return -1; /* Go to the next file. */ + } + } + return 0; +} + +/* The newc and crc formats store multiply linked copies of the same file + in the archive only once. The actual data is attached to the last link + in the archive, and the other links all have a filesize of 0. When a + file in the archive has multiple links and a filesize of 0, its data is + probably "attatched" to another file in the archive, so we can't create + it right away. We have to "defer" creating it until we have created + the file that has the data "attatched" to it. We keep a list of the + "defered" links on deferments. */ + +struct deferment *deferments = NULL; + +/* Add a file header to the deferments list. For now they all just + go on one list, although we could optimize this if necessary. */ + +static void defer_copyin(struct new_cpio_header *file_hdr) +{ + struct deferment *d; + d = create_deferment(file_hdr); + d->next = deferments; + deferments = d; + return; +} + +/* We just created a file that (probably) has some other links to it + which have been defered. Go through all of the links on the deferments + list and create any which are links to this file. */ + +static void create_defered_links(struct new_cpio_header *file_hdr) +{ + struct deferment *d; + struct deferment *d_prev; + int ino; + int maj; + int min; + int link_res; + ino = file_hdr->c_ino; + maj = file_hdr->c_dev_maj; + min = file_hdr->c_dev_min; + d = deferments; + d_prev = NULL; + while (d != NULL) { + if ((d->header.c_ino == ino) && (d->header.c_dev_maj == maj) + && (d->header.c_dev_min == min)) { + struct deferment *d_free; + link_res = + link_to_name(d->header.c_name, file_hdr->c_name); + if (link_res < 0) { + fprintf(stderr, + "%s: cannot link %s to %s: %s\n", + progname, d->header.c_name, + file_hdr->c_name, strerror(errno)); + } + if (d_prev != NULL) + d_prev->next = d->next; + else + deferments = d->next; + d_free = d; + d = d->next; + free_deferment(d_free); + } else { + d_prev = d; + d = d->next; + } + } +} + +/* If we had a multiply linked file that really was empty then we would + have defered all of its links, since we never found any with data + "attached", and they will still be on the deferment list even when + we are done reading the whole archive. Write out all of these + empty links that are still on the deferments list. */ + +static void create_final_defers(void) +{ + struct deferment *d; + int link_res; + int out_file_des; + struct utimbuf times; /* For setting file times. */ + /* Initialize this in case it has members we don't know to set. */ + memset(×, 0, sizeof(struct utimbuf)); + + for (d = deferments; d != NULL; d = d->next) { + /* Debian hack: A line, which could cause an endless loop, was + removed (97/1/2). It was reported by Ronald F. Guilmette to + the upstream maintainers. -BEM */ + /* Debian hack: This was reported by Horst Knobloch. This bug has + been reported to "bug-gnu-utils@prep.ai.mit.edu". (99/1/6) -BEM + */ + link_res = link_to_maj_min_ino(d->header.c_name, + d->header.c_dev_maj, + d->header.c_dev_min, + d->header.c_ino); + if (link_res == 0) { + continue; + } + out_file_des = open(d->header.c_name, O_CREAT | O_WRONLY, 0600); + if (out_file_des < 0) { + fprintf(stderr, "%s: open %s: %s\n", + progname, d->header.c_name, strerror(errno)); + continue; + } + + /* File is now copied; set attributes. */ + if ((fchown(out_file_des, d->header.c_uid, d->header.c_gid) < 0) + && errno != EPERM) + fprintf(stderr, "%s: fchown %s: %s\n", + progname, d->header.c_name, strerror(errno)); + /* chown may have turned off some permissions we wanted. */ + if (fchmod(out_file_des, (int)d->header.c_mode) < 0) + fprintf(stderr, "%s: fchmod %s: %s\n", + progname, d->header.c_name, strerror(errno)); + + if (close(out_file_des) < 0) + fprintf(stderr, "%s: close %s: %s\n", + progname, d->header.c_name, strerror(errno)); + + } +} + +static void +copyin_regular_file(struct new_cpio_header *file_hdr, int in_file_des) +{ + int out_file_des; /* Output file descriptor. */ + + /* Can the current file be linked to a previously copied file? */ + if (file_hdr->c_nlink > 1) { + int link_res; + if (file_hdr->c_filesize == 0) { + /* The newc and crc formats store multiply linked copies + of the same file in the archive only once. The + actual data is attached to the last link in the + archive, and the other links all have a filesize + of 0. Since this file has multiple links and a + filesize of 0, its data is probably attatched to + another file in the archive. Save the link, and + process it later when we get the actual data. We + can't just create it with length 0 and add the + data later, in case the file is readonly. We still + lose if its parent directory is readonly (and we aren't + running as root), but there's nothing we can do about + that. */ + defer_copyin(file_hdr); + tape_toss_input(in_file_des, file_hdr->c_filesize); + tape_skip_padding(in_file_des, file_hdr->c_filesize); + return; + } + /* If the file has data (filesize != 0), then presumably + any other links have already been defer_copyin'ed(), + but GNU cpio version 2.0-2.2 didn't do that, so we + still have to check for links here (and also in case + the archive was created and later appeneded to). */ + /* Debian hack: (97/1/2) This was reported by Ronald + F. Guilmette to the upstream maintainers. -BEM */ + link_res = link_to_maj_min_ino(file_hdr->c_name, + file_hdr->c_dev_maj, + file_hdr->c_dev_min, + file_hdr->c_ino); + if (link_res == 0) { + tape_toss_input(in_file_des, file_hdr->c_filesize); + tape_skip_padding(in_file_des, file_hdr->c_filesize); + return; + } + } + + /* If not linked, copy the contents of the file. */ + out_file_des = open(file_hdr->c_name, O_CREAT | O_WRONLY, 0600); + + if (out_file_des < 0) { + fprintf(stderr, "%s: open %s: %s\n", + progname, file_hdr->c_name, strerror(errno)); + tape_toss_input(in_file_des, file_hdr->c_filesize); + tape_skip_padding(in_file_des, file_hdr->c_filesize); + return; + } + + copy_files_tape_to_disk(in_file_des, out_file_des, + file_hdr->c_filesize); + disk_empty_output_buffer(out_file_des); + + if (close(out_file_des) < 0) + fprintf(stderr, "%s: close %s: %s\n", + progname, file_hdr->c_name, strerror(errno)); + + /* File is now copied; set attributes. */ + if ((chown(file_hdr->c_name, file_hdr->c_uid, file_hdr->c_gid) < 0) + && errno != EPERM) + fprintf(stderr, "%s: chown %s: %s\n", + progname, file_hdr->c_name, strerror(errno)); + + /* chown may have turned off some permissions we wanted. */ + if (chmod(file_hdr->c_name, (int)file_hdr->c_mode) < 0) + fprintf(stderr, "%s: chmod %s: %s\n", + progname, file_hdr->c_name, strerror(errno)); + + tape_skip_padding(in_file_des, file_hdr->c_filesize); + if (file_hdr->c_nlink > 1) { + /* (see comment above for how the newc and crc formats + store multiple links). Now that we have the data + for this file, create any other links to it which + we defered. */ + create_defered_links(file_hdr); + } +} + +/* In general, we can't use the builtin `basename' function if available, + since it has different meanings in different environments. + In some environments the builtin `basename' modifies its argument. + + Return the address of the last file name component of NAME. If + NAME has no file name components because it is all slashes, return + NAME if it is empty, the address of its last slash otherwise. */ + +static char *base_name(char const *name) +{ + char const *base = name; + char const *p; + + for (p = base; *p; p++) { + if (ISSLASH(*p)) { + /* Treat multiple adjacent slashes like a single slash. */ + do + p++; + while (ISSLASH(*p)); + + /* If the file name ends in slash, use the trailing slash as + the basename if no non-slashes have been found. */ + if (!*p) { + if (ISSLASH(*base)) + base = p - 1; + break; + } + + /* *P is a non-slash preceded by a slash. */ + base = p; + } + } + + return (char *)base; +} + +/* Return the length of of the basename NAME. Typically NAME is the + value returned by base_name. Act like strlen (NAME), except omit + redundant trailing slashes. */ + +static size_t base_len(char const *name) +{ + size_t len; + + for (len = strlen(name); 1 < len && ISSLASH(name[len - 1]); len--) + continue; + + return len; +} + +/* Remove trailing slashes from PATH. + Return true if a trailing slash was removed. + This is useful when using filename completion from a shell that + adds a "/" after directory names (such as tcsh and bash), because + the Unix rename and rmdir system calls return an "Invalid argument" error + when given a path that ends in "/" (except for the root directory). */ + +static bool strip_trailing_slashes(char *path) +{ + char *base = base_name(path); + char *base_lim = base + base_len(base); + bool had_slash = (*base_lim != '\0'); + *base_lim = '\0'; + return had_slash; +} + +static void copyin_directory(struct new_cpio_header *file_hdr, int existing_dir) +{ + int res; /* Result of various function calls. */ + + /* Strip any trailing `/'s off the filename; tar puts + them on. We might as well do it here in case anybody + else does too, since they cause strange things to happen. */ + strip_trailing_slashes(file_hdr->c_name); + + /* Ignore the current directory. It must already exist, + and we don't want to change its permission, ownership + or time. */ + if (file_hdr->c_name[0] == '.' && file_hdr->c_name[1] == '\0') { + return; + } + + if (!existing_dir) + { + res = mkdir(file_hdr->c_name, file_hdr->c_mode); + } else + res = 0; + if (res < 0) { + /* In some odd cases where the file_hdr->c_name includes `.', + the directory may have actually been created by + create_all_directories(), so the mkdir will fail + because the directory exists. If that's the case, + don't complain about it. */ + struct stat file_stat; + if ((errno != EEXIST) || + (lstat(file_hdr->c_name, &file_stat) != 0) || + !(S_ISDIR(file_stat.st_mode))) { + fprintf(stderr, "%s: lstat %s: %s\n", + progname, file_hdr->c_name, strerror(errno)); + return; + } + } + if ((chown(file_hdr->c_name, file_hdr->c_uid, file_hdr->c_gid) < 0) + && errno != EPERM) + fprintf(stderr, "%s: chown %s: %s\n", + progname, file_hdr->c_name, strerror(errno)); + /* chown may have turned off some permissions we wanted. */ + if (chmod(file_hdr->c_name, (int)file_hdr->c_mode) < 0) + fprintf(stderr, "%s: chmod %s: %s\n", + progname, file_hdr->c_name, strerror(errno)); +} + +static void copyin_device(struct new_cpio_header *file_hdr) +{ + int res; /* Result of various function calls. */ + + if (file_hdr->c_nlink > 1) { + int link_res; + /* Debian hack: This was reported by Horst + Knobloch. This bug has been reported to + "bug-gnu-utils@prep.ai.mit.edu". (99/1/6) -BEM */ + link_res = link_to_maj_min_ino(file_hdr->c_name, + file_hdr->c_dev_maj, + file_hdr->c_dev_min, + file_hdr->c_ino); + if (link_res == 0) { + return; + } + } + + res = mknod(file_hdr->c_name, file_hdr->c_mode, + makedev(file_hdr->c_rdev_maj, file_hdr->c_rdev_min)); + if (res < 0) { + fprintf(stderr, "%s: mknod %s: %s\n", progname, + file_hdr->c_name, strerror(errno)); + return; + } + if ((chown(file_hdr->c_name, file_hdr->c_uid, file_hdr->c_gid) < 0) + && errno != EPERM) + fprintf(stderr, "%s: chown %s: %s\n", progname, + file_hdr->c_name, strerror(errno)); + /* chown may have turned off some permissions we wanted. */ + if (chmod(file_hdr->c_name, file_hdr->c_mode) < 0) + fprintf(stderr, "%s: chmod %s: %s\n", progname, + file_hdr->c_name, strerror(errno)); +} + +static void copyin_link(struct new_cpio_header *file_hdr, int in_file_des) +{ + char *link_name = NULL; /* Name of hard and symbolic links. */ + int res; /* Result of various function calls. */ + + link_name = (char *)xmalloc(file_hdr->c_filesize + 1); + link_name[file_hdr->c_filesize] = '\0'; + tape_buffered_read(link_name, in_file_des, file_hdr->c_filesize); + tape_skip_padding(in_file_des, file_hdr->c_filesize); + + res = symlink(link_name, file_hdr->c_name); + if (res < 0) { + fprintf(stderr, "%s: symlink %s: %s\n", + progname, file_hdr->c_name, strerror(errno)); + free(link_name); + return; + } + if ((lchown(file_hdr->c_name, file_hdr->c_uid, file_hdr->c_gid) < 0) + && errno != EPERM) { + fprintf(stderr, "%s: lchown %s: %s\n", + progname, file_hdr->c_name, strerror(errno)); + } + free(link_name); +} + +static void copyin_file(struct new_cpio_header *file_hdr, int in_file_des) +{ + int existing_dir; + + if (try_existing_file(file_hdr, in_file_des, &existing_dir) < 0) + return; + + /* Do the real copy or link. */ + switch (file_hdr->c_mode & S_IFMT) { + case S_IFREG: + copyin_regular_file(file_hdr, in_file_des); + break; + + case S_IFDIR: + copyin_directory(file_hdr, existing_dir); + break; + + case S_IFCHR: + case S_IFBLK: + case S_IFSOCK: + case S_IFIFO: + copyin_device(file_hdr); + break; + + case S_IFLNK: + copyin_link(file_hdr, in_file_des); + break; + + default: + fprintf(stderr, "%s: %s: unknown file type\n", + progname, file_hdr->c_name); + tape_toss_input(in_file_des, file_hdr->c_filesize); + tape_skip_padding(in_file_des, file_hdr->c_filesize); + } +} + +/* Fill in FILE_HDR by reading a new-format ASCII format cpio header from + file descriptor IN_DES, except for the magic number, which is + already filled in. */ + +static void read_in_new_ascii(struct new_cpio_header *file_hdr, int in_des) +{ + char ascii_header[13*8], *ah, hexbuf[9]; + int i; + + tape_buffered_read(ascii_header, in_des, 13*8); + ah = ascii_header; + hexbuf[8] = '\0'; + for (i = 0; i < 13; i++) { + memcpy(hexbuf, ah, 8); + file_hdr->c_hdr[i] = strtoul(hexbuf, NULL, 16); + ah += 8; + } + + /* Sizes > LONG_MAX can currently result in integer overflow + in various places. Fail if name is too large. */ + if (file_hdr->c_namesize > LONG_MAX) { + fprintf(stderr, "%s: name size out of range\n", + progname); + exit(1); + } + + /* Read file name from input. */ + free(file_hdr->c_name); + file_hdr->c_name = (char *)xmalloc(file_hdr->c_namesize); + tape_buffered_read(file_hdr->c_name, in_des, + (long)file_hdr->c_namesize); + + /* In SVR4 ASCII format, the amount of space allocated for the header + is rounded up to the next long-word, so we might need to drop + 1-3 bytes. */ + tape_skip_padding(in_des, file_hdr->c_namesize + 110); + + /* Fail if file is too large. We could check this earlier + but it's helpful to report the name. */ + if (file_hdr->c_filesize > LONG_MAX) { + fprintf(stderr, "%s: %s: file size out of range\n", + progname, file_hdr->c_name); + exit(1); + } +} + +/* Return 16-bit integer I with the bytes swapped. */ +#define swab_short(i) ((((i) << 8) & 0xff00) | (((i) >> 8) & 0x00ff)) + +/* Read the header, including the name of the file, from file + descriptor IN_DES into FILE_HDR. */ + +static void read_in_header(struct new_cpio_header *file_hdr, int in_des) +{ + long bytes_skipped = 0; /* Bytes of junk found before magic number. */ + + /* Search for a valid magic number. */ + + file_hdr->c_tar_linkname = NULL; + + tape_buffered_read((char *)file_hdr, in_des, 6L); + while (1) { + if (!strncmp((char *)file_hdr, "070702", 6) + || !strncmp((char *)file_hdr, "070701", 6)) + { + if (bytes_skipped > 0) + warn_junk_bytes(bytes_skipped); + + read_in_new_ascii(file_hdr, in_des); + break; + } + bytes_skipped++; + memmove((char *)file_hdr, (char *)file_hdr + 1, 5); + tape_buffered_read((char *)file_hdr + 5, in_des, 1L); + } +} + +/* Read the collection from standard input and create files + in the file system. */ + +static void process_copy_in(void) +{ + char done = false; /* True if trailer reached. */ + struct new_cpio_header file_hdr; /* Output header information. */ + int in_file_des; /* Input file descriptor. */ + + /* Initialize the copy in. */ + file_hdr.c_name = NULL; + + /* only from stdin */ + in_file_des = 0; + + /* While there is more input in the collection, process the input. */ + while (!done) { + /* Start processing the next file by reading the header. */ + read_in_header(&file_hdr, in_file_des); + + /* Is this the header for the TRAILER file? */ + if (strcmp("TRAILER!!!", file_hdr.c_name) == 0) { + done = true; + break; + } + + /* Copy the input file into the directory structure. */ + + copyin_file(&file_hdr, in_file_des); + + if (dot_flag) + fputc('.', stderr); + } + + if (dot_flag) + fputc('\n', stderr); + + create_final_defers(); + +} + +/* Initialize the input and output buffers to their proper size and + initialize all variables associated with the input and output + buffers. */ + +static void initialize_buffers(void) +{ + int in_buf_size, out_buf_size; + + /* Make sure the input buffer can always hold 2 blocks and that it + is big enough to hold 1 tar record (512 bytes) even if it + is not aligned on a block boundary. The extra buffer space + is needed by process_copyin and peek_in_buf to automatically + figure out what kind of archive it is reading. */ + if (io_block_size >= 512) + in_buf_size = 2 * io_block_size; + else + in_buf_size = 1024; + out_buf_size = DISK_IO_BLOCK_SIZE; + + input_buffer = (char *)xmalloc(in_buf_size); + in_buff = input_buffer; + input_buffer_size = in_buf_size; + input_size = 0; + input_bytes = 0; + + output_buffer = (char *)xmalloc(out_buf_size); + out_buff = output_buffer; + output_size = 0; + output_bytes = 0; + +} + +int main(int argc, char *argv[]) +{ + int c; + int extract_flag = false; + + progname = argv[0]; + + do { + c = getopt(argc, argv, "iV"); + if (c == EOF) + break; + switch (c) { + case 'V': + dot_flag = true; + break; + + case 'i': + extract_flag = true; + break; + case '?': + fprintf(stderr, + "%s: not implemented or invalid option -%c\n", + progname, optopt); + exit(1); + + } + } while (1); + + if (extract_flag) { + initialize_buffers(); + + process_copy_in(); + } else { + fprintf(stderr, "Usage: %s [-V] -i [< archive]\n", progname); + exit(1); + } + + return 0; +} diff --git a/usr/utils/dd.c b/usr/utils/dd.c new file mode 100644 index 0000000..706b8c3 --- /dev/null +++ b/usr/utils/dd.c @@ -0,0 +1,540 @@ +#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"); + close(rd_fd); + return 1; + } + } + + /* + * Skip obs-sized blocks of output file. + */ + if (OPT_SEEK->str && skip_blocks(wr_fd, out_buf, seek, obs)) { + close(rd_fd); + close(wr_fd); + return 1; + } + + /* + * Skip ibs-sized blocks of input file. + */ + if (OPT_SKIP->str && skip_blocks(rd_fd, in_buf, skip, ibs)) { + close(rd_fd); + close(wr_fd); + 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/dmesg.c b/usr/utils/dmesg.c new file mode 100644 index 0000000..1960713 --- /dev/null +++ b/usr/utils/dmesg.c @@ -0,0 +1,79 @@ +#include <unistd.h> +#include <stdio.h> +#include <ctype.h> +#include <stdlib.h> +#include <sys/klog.h> + +static void usage(char *name) +{ + fprintf(stderr, "usage: %s [-c]\n", name); +} + +int main(int argc, char *argv[]) +{ + char *buf = NULL; + const char *p; + int c; + int bufsz = 0; + int cmd = 3; /* Read all messages remaining in the ring buffer */ + int len = 0; + int opt; + int newline; + + while ((opt = getopt(argc, argv, "c")) != -1) { + switch (opt) { + /* Read and clear all messages remaining in the ring buffer */ + case 'c': + cmd = 4; + break; + case '?': + default: + usage(argv[0]); + exit(1); + } + } + + if (!bufsz) { + len = klogctl(10, NULL, 0); /* Get size of log buffer */ + if (len > 0) + bufsz = len; + } + + if (bufsz) { + int sz = bufsz + 8; + + buf = (char *)malloc(sz); + len = klogctl(cmd, buf, sz); + } + + if (len < 0) { + perror("klogctl"); + exit(1); + } + + newline = 1; + p = buf; + while ((c = *p)) { + switch (c) { + case '\n': + newline = 1; + putchar(c); + p++; + break; + case '<': + if (newline && isdigit(p[1]) && p[2] == '>') { + p += 3; + break; + } + /* else fall through */ + default: + newline = 0; + putchar(c); + p++; + } + } + if (!newline) + putchar('\n'); + + return 0; +} 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..364f603 --- /dev/null +++ b/usr/utils/file_mode.h @@ -0,0 +1,6 @@ +#ifndef UTILS_FILE_MODE_H +#define UTILS_FILE_MODE_H + +mode_t parse_file_mode(char *arg, mode_t mode, mode_t sumask); + +#endif /* UTILS_FILE_MODE_H */ diff --git a/usr/utils/halt.c b/usr/utils/halt.c new file mode 100644 index 0000000..368f095 --- /dev/null +++ b/usr/utils/halt.c @@ -0,0 +1,64 @@ +#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] [reboot-arg]\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; + char *reboot_arg = NULL; + + /* 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) + if (**argv == '-') { + switch (*++*argv) { + case 'f': + break; /* -f assumed */ + case 'n': + do_sync = 0; + break; + default: + usage(); + } + } else if (cmd == LINUX_REBOOT_CMD_RESTART) { + reboot_arg = *argv; + cmd = LINUX_REBOOT_CMD_RESTART2; + } else { + usage(); /* args, not reboot == error */ + } + + if (do_sync) + sync(); + reboot(LINUX_REBOOT_CMD_CAD_OFF, NULL); /* Enable CTRL+ALT+DEL */ + if (!reboot(cmd, reboot_arg)) { + /* 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/kill.c b/usr/utils/kill.c new file mode 100644 index 0000000..188f1b5 --- /dev/null +++ b/usr/utils/kill.c @@ -0,0 +1,33 @@ +#include <stdio.h> +#include <stdlib.h> +#include <signal.h> +#include <string.h> + +char *progname; + +static __noreturn usage(void) +{ + fprintf(stderr, "Usage: %s pid\n", progname); + exit(1); +} +int main(int argc, char *argv[]) +{ + long pid; + char *endp; + + progname = argv[0]; + if (argc != 2) + usage(); + + pid = strtol(argv[1], &endp, 10); + if (*endp != '\0') { + perror("pid"); + usage(); + } + + if (kill(pid, SIGTERM) == -1) { + perror("kill"); + 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/losetup.c b/usr/utils/losetup.c new file mode 100644 index 0000000..16159eb --- /dev/null +++ b/usr/utils/losetup.c @@ -0,0 +1,400 @@ +/* Originally from Ted's losetup.c */ + +#define LOOPMAJOR 7 + +/* + * losetup.c - setup and control loop devices + */ + +/* We want __u64 to be unsigned long long */ +#define __SANE_USERSPACE_TYPES__ + +#include <stdio.h> +#include <string.h> +#include <ctype.h> +#include <fcntl.h> +#include <errno.h> +#include <stdlib.h> +#include <unistd.h> +#include <sys/ioctl.h> +#include <sys/stat.h> +#include <sys/mman.h> +#include <sys/sysmacros.h> +#include <stdarg.h> +#include <linux/loop.h> + +extern int verbose; +extern char *progname; +extern char *xstrdup (const char *s); /* not: #include "sundries.h" */ +extern void error (const char *fmt, ...); /* idem */ + +/* caller guarantees n > 0 */ +void xstrncpy(char *dest, const char *src, size_t n) +{ + strncpy(dest, src, n-1); + dest[n-1] = 0; +} + + +static int show_loop(char *device) +{ + struct loop_info64 loopinfo64; + int fd, errsv; + + if ((fd = open(device, O_RDONLY)) < 0) { + int errsv = errno; + fprintf(stderr, "loop: can't open device %s: %s\n", + device, strerror (errsv)); + return 2; + } + + if (ioctl(fd, LOOP_GET_STATUS64, &loopinfo64) == 0) { + + loopinfo64.lo_file_name[LO_NAME_SIZE-2] = '*'; + loopinfo64.lo_file_name[LO_NAME_SIZE-1] = 0; + loopinfo64.lo_crypt_name[LO_NAME_SIZE-1] = 0; + + printf("%s: [%04llx]:%llu (%s)", + device, loopinfo64.lo_device, loopinfo64.lo_inode, + loopinfo64.lo_file_name); + + if (loopinfo64.lo_offset) + printf(", offset %lld", loopinfo64.lo_offset); + + if (loopinfo64.lo_sizelimit) + printf(", sizelimit %lld", loopinfo64.lo_sizelimit); + + if (loopinfo64.lo_encrypt_type || + loopinfo64.lo_crypt_name[0]) { + const char *e = (const char *)loopinfo64.lo_crypt_name; + + if (*e == 0 && loopinfo64.lo_encrypt_type == 1) + e = "XOR"; + printf(", encryption %s (type %d)", + e, loopinfo64.lo_encrypt_type); + } + printf("\n"); + close (fd); + return 0; + } + + errsv = errno; + fprintf(stderr, "loop: can't get info on device %s: %s\n", + device, strerror (errsv)); + close (fd); + return 1; +} + +int +is_loop_device (const char *device) { + struct stat statbuf; + + return (stat(device, &statbuf) == 0 && + S_ISBLK(statbuf.st_mode) && + major(statbuf.st_rdev) == LOOPMAJOR); +} + +#define SIZE(a) (sizeof(a)/sizeof(a[0])) + +char * find_unused_loop_device (void) +{ + char dev[20]; + int fd, rc; + + fd = open("/dev/loop-control", O_RDWR); + if (fd < 0) { + error("%s: could not open /dev/loop-control. Maybe this kernel " + "does not know\n" + " about the loop device? (If so, recompile or " + "`modprobe loop'.)", progname); + return NULL; + } + rc = ioctl(fd, LOOP_CTL_GET_FREE, 0); + close(fd); + if (rc < 0) { + error("%s: could not find any free loop device", progname); + return NULL; + } + + sprintf(dev, "/dev/loop%d", rc); + return xstrdup(dev); +} + +/* + * A function to read the passphrase either from the terminal or from + * an open file descriptor. + */ +static char * xgetpass(int pfd, const char *prompt) +{ + char *pass; + int buflen, i; + + pass = NULL; + buflen = 0; + for (i=0; ; i++) { + if (i >= buflen-1) { + /* we're running out of space in the buffer. + * Make it bigger: */ + char *tmppass = pass; + buflen += 128; + pass = realloc(tmppass, buflen); + if (pass == NULL) { + /* realloc failed. Stop reading. */ + error("Out of memory while reading passphrase"); + pass = tmppass; /* the old buffer hasn't changed */ + break; + } + } + if (read(pfd, pass+i, 1) != 1 || + pass[i] == '\n' || pass[i] == 0) + break; + } + + if (pass == NULL) + return ""; + + pass[i] = 0; + return pass; +} + +static int digits_only(const char *s) +{ + while (*s) + if (!isdigit(*s++)) + return 0; + return 1; +} + +int set_loop(const char *device, const char *file, unsigned long long offset, + const char *encryption, int pfd, int *loopro) { + struct loop_info64 loopinfo64; + int fd, ffd, mode, i; + char *pass; + + mode = (*loopro ? O_RDONLY : O_RDWR); + if ((ffd = open(file, mode)) < 0) { + if (!*loopro && errno == EROFS) + ffd = open(file, mode = O_RDONLY); + if (ffd < 0) { + perror(file); + return 1; + } + } + if ((fd = open(device, mode)) < 0) { + perror (device); + return 1; + } + *loopro = (mode == O_RDONLY); + + memset(&loopinfo64, 0, sizeof(loopinfo64)); + + xstrncpy((char *)loopinfo64.lo_file_name, file, LO_NAME_SIZE); + + if (encryption && *encryption) { + if (digits_only(encryption)) { + loopinfo64.lo_encrypt_type = atoi(encryption); + } else { + loopinfo64.lo_encrypt_type = LO_CRYPT_CRYPTOAPI; + snprintf((char *)loopinfo64.lo_crypt_name, LO_NAME_SIZE, + "%s", encryption); + } + } + + loopinfo64.lo_offset = offset; + + + switch (loopinfo64.lo_encrypt_type) { + case LO_CRYPT_NONE: + loopinfo64.lo_encrypt_key_size = 0; + break; + case LO_CRYPT_XOR: + pass = xgetpass(pfd, "Password: "); + goto gotpass; + default: + pass = xgetpass(pfd, "Password: "); + gotpass: + memset(loopinfo64.lo_encrypt_key, 0, LO_KEY_SIZE); + xstrncpy((char *)loopinfo64.lo_encrypt_key, pass, LO_KEY_SIZE); + memset(pass, 0, strlen(pass)); + loopinfo64.lo_encrypt_key_size = LO_KEY_SIZE; + } + + if (ioctl(fd, LOOP_SET_FD, (void *)(size_t)ffd) < 0) { + perror("ioctl: LOOP_SET_FD"); + return 1; + } + close (ffd); + + i = ioctl(fd, LOOP_SET_STATUS64, &loopinfo64); + if (i) + perror("ioctl: LOOP_SET_STATUS64"); + memset(&loopinfo64, 0, sizeof(loopinfo64)); + + if (i) { + ioctl (fd, LOOP_CLR_FD, 0); + close (fd); + return 1; + } + close (fd); + + if (verbose > 1) + printf("set_loop(%s,%s,%llu): success\n", + device, file, offset); + return 0; +} + +int del_loop (const char *device) +{ + int fd; + + if ((fd = open (device, O_RDONLY)) < 0) { + int errsv = errno; + fprintf(stderr, "loop: can't delete device %s: %s\n", + device, strerror (errsv)); + return 1; + } + if (ioctl (fd, LOOP_CLR_FD, 0) < 0) { + perror ("ioctl: LOOP_CLR_FD"); + close (fd); + return 1; + } + close (fd); + if (verbose > 1) + printf("del_loop(%s): success\n", device); + return 0; +} + + +int verbose = 0; +char *progname; + +static void usage(FILE *f) +{ + fprintf(f, "usage:\n\ + %s loop_device # give info\n\ + %s -d loop_device # delete\n\ + %s -f # find unused\n\ + %s -h # this help\n\ + %s [-e encryption] [-o offset] {-f|loop_device} file # setup\n", + progname, progname, progname, progname, progname); + exit(f == stderr ? EXIT_FAILURE : EXIT_SUCCESS); +} + +char * xstrdup (const char *s) { + char *t; + + if (s == NULL) + return NULL; + + t = strdup (s); + + if (t == NULL) { + fprintf(stderr, "not enough memory"); + exit(1); + } + + return t; +} + +void error (const char *fmt, ...) +{ + va_list args; + + va_start (args, fmt); + vfprintf (stderr, fmt, args); + va_end (args); + fprintf (stderr, "\n"); +} + +int main(int argc, char **argv) +{ + char *p, *offset, *encryption, *passfd, *device, *file; + int delete, find, c; + int res = 0; + int ro = 0; + int pfd = -1; + unsigned long long off; + + + delete = find = 0; + off = 0; + offset = encryption = passfd = NULL; + + progname = argv[0]; + if ((p = strrchr(progname, '/')) != NULL) + progname = p+1; + + while ((c = getopt(argc, argv, "de:E:fho:p:v")) != -1) { + switch (c) { + case 'd': + delete = 1; + break; + case 'E': + case 'e': + encryption = optarg; + break; + case 'f': + find = 1; + break; + case 'h': + usage(stdout); + break; + case 'o': + offset = optarg; + break; + case 'p': + passfd = optarg; + break; + case 'v': + verbose = 1; + break; + default: + usage(stderr); + } + } + + if (argc == 1) { + usage(stderr); + } else if (delete) { + if (argc != optind+1 || encryption || offset || find) + usage(stderr); + } else if (find) { + if (argc < optind || argc > optind+1) + usage(stderr); + } else { + if (argc < optind+1 || argc > optind+2) + usage(stderr); + } + + if (find) { + device = find_unused_loop_device(); + if (device == NULL) + return -1; + if (verbose) + printf("Loop device is %s\n", device); + if (argc == optind) { + printf("%s\n", device); + return 0; + } + file = argv[optind]; + } else { + device = argv[optind]; + if (argc == optind+1) + file = NULL; + else + file = argv[optind+1]; + } + + if (delete) + res = del_loop(device); + else if (file == NULL) + res = show_loop(device); + else { + if (offset && sscanf(offset, "%llu", &off) != 1) + usage(stderr); + if (passfd && sscanf(passfd, "%d", &pfd) != 1) + usage(stderr); + res = set_loop(device, file, off, encryption, pfd, &ro); + } + return res; +} diff --git a/usr/utils/ls.c b/usr/utils/ls.c new file mode 100644 index 0000000..50af434 --- /dev/null +++ b/usr/utils/ls.c @@ -0,0 +1,223 @@ +#include <stdio.h> +#include <stdlib.h> +#include <dirent.h> +#include <unistd.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <sys/sysmacros.h> + +#define STAT_ISSET(mode, mask) (((mode) & mask) == mask) + +static size_t max_linksiz = 128; +static int max_nlinks = 1; +static int max_size = 1; +static int max_uid = 1; +static int max_gid = 1; +static int max_min = 1; +static int max_maj = 1; + +static void do_preformat(const struct stat *st) +{ + int bytes; + + bytes = snprintf(NULL, 0, "%ju", (uintmax_t) st->st_nlink); + if (bytes > max_nlinks) + max_nlinks = bytes; + + bytes = snprintf(NULL, 0, "%ju", (uintmax_t) st->st_uid); + if (bytes > max_uid) + max_uid = bytes; + + bytes = snprintf(NULL, 0, "%ju", (uintmax_t) st->st_gid); + if (bytes > max_gid) + max_gid = bytes; + + if (S_ISCHR(st->st_mode) || S_ISBLK(st->st_mode)) { + bytes = snprintf(NULL, 0, "%u", major(st->st_rdev)); + if (bytes > max_maj) + max_maj = bytes; + + bytes = snprintf(NULL, 0, "%u", minor(st->st_rdev)); + if (bytes > max_min) + max_min = bytes; + + max_size = max_maj + max_min + 1; + } else { + bytes = snprintf(NULL, 0, "%ju", (uintmax_t) st->st_size); + if (bytes > max_size) + max_size = bytes; + } + return; +} + +static void do_stat(const struct stat *st, int dir_fd, const char *path) +{ + char *fmt, *link_name; + int rc; + + switch (st->st_mode & S_IFMT) { + case S_IFBLK: + putchar('b'); + break; + case S_IFCHR: + putchar('c'); + break; + case S_IFDIR: + putchar('d'); + break; + case S_IFIFO: + putchar('p'); + break; + case S_IFLNK: + putchar('l'); + break; + case S_IFSOCK: + putchar('s'); + break; + case S_IFREG: + putchar('-'); + break; + default: + putchar('?'); + break; + } + putchar(STAT_ISSET(st->st_mode, S_IRUSR) ? 'r' : '-'); + putchar(STAT_ISSET(st->st_mode, S_IWUSR) ? 'w' : '-'); + + !STAT_ISSET(st->st_mode, S_ISUID) ? + putchar(STAT_ISSET(st->st_mode, S_IXUSR) ? 'x' : '-') : + putchar('S'); + + putchar(STAT_ISSET(st->st_mode, S_IRGRP) ? 'r' : '-'); + putchar(STAT_ISSET(st->st_mode, S_IWGRP) ? 'w' : '-'); + + !STAT_ISSET(st->st_mode, S_ISGID) ? + putchar(STAT_ISSET(st->st_mode, S_IXGRP) ? 'x' : '-') : + putchar('S'); + + putchar(STAT_ISSET(st->st_mode, S_IROTH) ? 'r' : '-'); + putchar(STAT_ISSET(st->st_mode, S_IWOTH) ? 'w' : '-'); + + !STAT_ISSET(st->st_mode, S_ISVTX) ? + putchar(STAT_ISSET(st->st_mode, S_IXOTH) ? 'x' : '-') : + putchar(S_ISDIR(st->st_mode) ? 't' : 'T'); + + if (S_ISCHR(st->st_mode) || S_ISBLK(st->st_mode)) { + rc = asprintf(&fmt, " %%%dju %%%dju %%%dju %%%du,%%%du %%s", + max_nlinks, max_uid, max_gid, max_maj, max_min); + if (rc == -1) { + perror("asprintf"); + exit(1); + } + fprintf(stdout, fmt, + (uintmax_t) st->st_nlink, + (uintmax_t) st->st_uid, + (uintmax_t) st->st_gid, + major(st->st_rdev), + minor(st->st_rdev), + path); + } else { + rc = asprintf(&fmt, " %%%dju %%%dju %%%dju %%%dju %%s", + max_nlinks, max_uid, max_gid, max_size); + if (rc == -1) { + perror("asprintf"); + exit(1); + } + fprintf(stdout, fmt, + (uintmax_t) st->st_nlink, + (uintmax_t) st->st_uid, + (uintmax_t) st->st_gid, + (uintmax_t) st->st_size, + path); + } + free(fmt); + + if (S_ISLNK(st->st_mode)) { + link_name = malloc(max_linksiz); + if (link_name == NULL) { + perror("malloc"); + exit(1); + } + rc = readlinkat(dir_fd, path, link_name, max_linksiz); + if (rc == -1) { + free(link_name); + perror("readlink"); + exit(1); + } + link_name[rc] = '\0'; + fprintf(stdout, " -> %s", link_name); + free(link_name); + } + + putchar('\n'); + return; +} + +static void do_dir(const char *path, int preformat) +{ + DIR *dir; + int dir_fd; + struct dirent *dent; + struct stat st; + + dir = opendir(path); + if (dir == NULL) { + perror(path); + exit(1); + } + dir_fd = dirfd(dir); + + while ((dent = readdir(dir)) != NULL) { + if (fstatat(dir_fd, dent->d_name, &st, + AT_SYMLINK_NOFOLLOW)) { + perror(dent->d_name); + exit(1); + } + (preformat) ? + do_preformat(&st) : + do_stat(&st, dir_fd, dent->d_name); + } + + closedir(dir); +} + +int main(int argc, char *argv[]) +{ + int i; + struct stat st; + + if (argc == 1) { + do_dir(".", 1); + do_dir(".", 0); + return 0; + } + + for (i = 1; i < argc; i++) { + if (argv[i][0] == '-' && argv[i][1] == 'h') { + fprintf(stdout, "Usage: ls [-h] [FILE ...]\n"); + return 0; + } + + if (lstat(argv[i], &st)) { + perror(argv[i]); + exit(1); + } + + S_ISDIR(st.st_mode) ? + do_dir(argv[i], 1) : + do_preformat(&st); + } + + for (i = 1; i < argc; i++) { + if (lstat(argv[i], &st)) { + perror(argv[i]); + exit(1); + } + + S_ISDIR(st.st_mode) ? + do_dir(argv[i], 0) : + do_stat(&st, AT_FDCWD, argv[i]); + } + + return 0; +} diff --git a/usr/utils/minips.c b/usr/utils/minips.c new file mode 100644 index 0000000..f48505f --- /dev/null +++ b/usr/utils/minips.c @@ -0,0 +1,511 @@ +/* + * 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 <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); + fd = open(buf, O_RDONLY, 0); + if (fd == -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"); + if (!dir) + exit(1); + 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..af241ef --- /dev/null +++ b/usr/utils/mkdir.c @@ -0,0 +1,154 @@ +#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 __noreturn usage(void) +{ + fprintf(stderr, "Usage: %s [-p] [-m mode] dir...\n", progname); + exit(1); +} + +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); + usage(); + } + } while (1); + + if (optind == argc) + usage(); + + 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..5a758b2 --- /dev/null +++ b/usr/utils/mkfifo.c @@ -0,0 +1,70 @@ +#include <sys/stat.h> +#include <sys/types.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..fa7ac7a --- /dev/null +++ b/usr/utils/mknod.c @@ -0,0 +1,84 @@ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/stat.h> + +char *progname; + +static __noreturn usage(void) +{ + fprintf(stderr, "Usage: %s [-m mode] name {b|c|p} major minor\n", + progname); + exit(1); +} + +int main(int argc, char *argv[]) +{ + char *name, *type, typec, *endp; + unsigned int major_num, minor_num; + mode_t mode, mode_set = 0; + dev_t dev; + + progname = *argv++; + if (argc == 1) + usage(); + + if (argv[0][0] == '-' && argv[0][1] == 'm' && !argv[0][2]) { + mode_set = strtoul(argv[1], &endp, 8); + argv += 2; + } + + name = *argv++; + if (!name) + usage(); + + type = *argv++; + if (!type || !type[0] || type[1]) + usage(); + typec = type[0]; + + mode = 0; + switch (typec) { + case 'c': + mode = S_IFCHR; + break; + case 'b': + mode = S_IFBLK; + break; + case 'p': + mode = S_IFIFO; + break; + default: + usage(); + } + + if (mode == S_IFIFO) { + dev = 0; + } else { + if (!argv[0] || !argv[1]) + usage(); + + major_num = strtol(*argv++, &endp, 0); + if (*endp != '\0') + usage(); + minor_num = strtol(*argv++, &endp, 0); + if (*endp != '\0') + usage(); + dev = makedev(major_num, minor_num); + } + + if (*argv) + usage(); + + if (mknod(name, mode|0666, dev) == -1) { + perror("mknod"); + exit(1); + } + + if (mode_set && chmod(name, mode_set)) { + perror("chmod"); + exit(1); + } + + exit(0); +} diff --git a/usr/utils/mount_main.c b/usr/utils/mount_main.c new file mode 100644 index 0000000..0d299c4 --- /dev/null +++ b/usr/utils/mount_main.c @@ -0,0 +1,156 @@ +/* + * by rmk + */ +#include <sys/mount.h> +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <mntent.h> + +#include "mount_opts.h" + +#define _PATH_MOUNTED "/etc/mtab" +#define _PATH_PROC_MOUNTS "/proc/mounts" + +char *progname; + +static struct extra_opts extra; +static unsigned long rwflag; + +static __noreturn usage(void) +{ + fprintf(stderr, "Usage: %s [-r] [-w] [-o options] [-t type] [-f] [-i] " + "[-n] device directory\n", progname); + exit(1); +} + +static __noreturn print_mount(char *type) +{ + FILE *mfp; + struct mntent *mnt; + + mfp = setmntent(_PATH_PROC_MOUNTS, "r"); + if (!mfp) + mfp = setmntent(_PATH_MOUNTED, "r"); + if (!mfp) + perror("setmntent"); + + while ((mnt = getmntent(mfp)) != NULL) { + if (mnt->mnt_fsname && !strncmp(mnt->mnt_fsname, "no", 2)) + continue; + if (type && mnt->mnt_type && strcmp(type, mnt->mnt_type)) + continue; + printf("%s on %s", mnt->mnt_fsname, mnt->mnt_dir); + if (mnt->mnt_type != NULL && *mnt->mnt_type != '\0') + printf(" type %s", mnt->mnt_type); + if (mnt->mnt_opts != NULL && *mnt->mnt_opts != '\0') + printf(" (%s)", mnt->mnt_opts); + printf("\n"); + } + endmntent(mfp); + exit(0); +} + +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; + } + } else { + error = 0; + } + 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, "fhino:rt:w"); + if (c == EOF) + break; + switch (c) { + case 'f': + /* we can't edit /etc/mtab yet anyway; exit */ + exit(0); + case 'i': + /* ignore for now; no support for mount helpers */ + break; + case 'h': + usage(); + case 'n': + /* no mtab writing */ + break; + 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 (optind == argc) + print_mount(type); + + /* + * 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) + usage(); + + 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..bb26c7d --- /dev/null +++ b/usr/utils/mount_opts.c @@ -0,0 +1,102 @@ +/* + * 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}, + {"nodev", MS_NODEV, MS_NODEV, 0}, + {"noexec", MS_NOEXEC, MS_NOEXEC, 0}, + {"nosuid", MS_NOSUID, MS_NOSUID, 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]) { + if (!strcmp(opt, "defaults")) + rwflag &= ~(MS_RDONLY|MS_NOSUID|MS_NODEV| + MS_NOEXEC|MS_SYNCHRONOUS); + else + 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..cf47cae --- /dev/null +++ b/usr/utils/mount_opts.h @@ -0,0 +1,26 @@ +#ifndef UTILS_MOUNT_OPTS_H +#define UTILS_MOUNT_OPTS_H + +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); + +#endif /* UTILS_MOUNT_OPTS_H */ diff --git a/usr/utils/mv.c b/usr/utils/mv.c new file mode 100644 index 0000000..e3f38ed --- /dev/null +++ b/usr/utils/mv.c @@ -0,0 +1,69 @@ +#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, f; + char *p; + struct stat sb; + + f = 0; + do { + c = getopt(argc, argv, "f"); + if (c == EOF) + break; + + switch (c) { + + 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 [-f] source dest\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 (rename(argv[c], target) == -1) + perror(target); + } + + return 0; +} diff --git a/usr/utils/nuke.c b/usr/utils/nuke.c new file mode 100644 index 0000000..93a04af --- /dev/null +++ b/usr/utils/nuke.c @@ -0,0 +1,121 @@ +/* ----------------------------------------------------------------------- * + * + * Copyright 2004-2006 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. + * + * ----------------------------------------------------------------------- */ + +/* + * 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 <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; + + dir = opendir(what); + if (!dir) { + /* 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) + rmdir(what); + } + } + + return 0; +} + +int main(int argc, char *argv[]) +{ + int i; + + program = argv[0]; + + for (i = 1; i < argc; i++) + nuke(argv[i]); + + return 0; +} diff --git a/usr/utils/pivot_root.c b/usr/utils/pivot_root.c new file mode 100644 index 0000000..41b2ea0 --- /dev/null +++ b/usr/utils/pivot_root.c @@ -0,0 +1,19 @@ +/* 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/readlink.c b/usr/utils/readlink.c new file mode 100644 index 0000000..1f16c02 --- /dev/null +++ b/usr/utils/readlink.c @@ -0,0 +1,57 @@ +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <sys/stat.h> + +const char *progname; + +static __noreturn usage(void) +{ + fprintf(stderr, "Usage: %s [-f] link...\n", progname); + exit(1); +} + +int main(int argc, char *argv[]) +{ + int c, f_flag = 0; + const char *name; + char link_name[PATH_MAX]; + int rv; + + progname = argv[0]; + + do { + c = getopt(argc, argv, "f"); + if (c == EOF) + break; + switch (c) { + case 'f': + f_flag = 1; + break; + + case '?': + fprintf(stderr, "%s: invalid option -%c\n", + progname, optopt); + usage(); + } + } while (1); + + if (optind == argc) + usage(); + + argv += optind; + while ((name = *argv++)) { + if (f_flag) + rv = realpath(name, link_name) ? strlen(link_name) : -1; + else + rv = readlink(name, link_name, sizeof link_name - 1); + if (rv < 0) { + perror(name); + exit(1); + } + link_name[rv] = '\n'; + _fwrite(link_name, rv+1, stdout); + } + + return 0; +} diff --git a/usr/utils/sleep.c b/usr/utils/sleep.c new file mode 100644 index 0000000..991cdbe --- /dev/null +++ b/usr/utils/sleep.c @@ -0,0 +1,26 @@ +#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/sync.c b/usr/utils/sync.c new file mode 100644 index 0000000..de3093c --- /dev/null +++ b/usr/utils/sync.c @@ -0,0 +1,7 @@ +#include <unistd.h> + +int main(void) +{ + sync(); + return 0; +} 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..41275f7 --- /dev/null +++ b/usr/utils/umount.c @@ -0,0 +1,51 @@ +/* + * by rmk + */ +#include <sys/mount.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, "fli"); + if (c == EOF) + break; + switch (c) { + case 'f': + flag |= MNT_FORCE; + break; + case 'l': + flag |= MNT_DETACH; + break; + case 'i': + /* ignore for now; no support for umount helpers */ + break; + case '?': + fprintf(stderr, "%s: invalid option -%c\n", + progname, optopt); + exit(1); + } + } while (1); + + if (optind + 1 != argc) { + fprintf(stderr, "Usage: %s [-f] [-l] [-i] 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..6ea4dbe --- /dev/null +++ b/usr/utils/uname.c @@ -0,0 +1,155 @@ +/* + * 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 +}; + +static 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); +} + +static char *make_hardware(const char *machine) +{ + char *hardware; + + hardware = strdup(machine); + if (!hardware) { + 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; +} |