diff options
Diffstat (limited to 'toolbox/upstream-netbsd/bin')
-rw-r--r-- | toolbox/upstream-netbsd/bin/cat/cat.c | 329 | ||||
-rw-r--r-- | toolbox/upstream-netbsd/bin/cp/cp.c | 548 | ||||
-rw-r--r-- | toolbox/upstream-netbsd/bin/cp/extern.h | 61 | ||||
-rw-r--r-- | toolbox/upstream-netbsd/bin/cp/utils.c | 444 | ||||
-rw-r--r-- | toolbox/upstream-netbsd/bin/dd/args.c | 391 | ||||
-rw-r--r-- | toolbox/upstream-netbsd/bin/dd/conv.c | 283 | ||||
-rw-r--r-- | toolbox/upstream-netbsd/bin/dd/dd.c | 598 | ||||
-rw-r--r-- | toolbox/upstream-netbsd/bin/dd/dd.h | 127 | ||||
-rw-r--r-- | toolbox/upstream-netbsd/bin/dd/dd_hostops.c | 53 | ||||
-rw-r--r-- | toolbox/upstream-netbsd/bin/dd/extern.h | 82 | ||||
-rw-r--r-- | toolbox/upstream-netbsd/bin/dd/misc.c | 342 | ||||
-rw-r--r-- | toolbox/upstream-netbsd/bin/dd/position.c | 185 | ||||
-rw-r--r-- | toolbox/upstream-netbsd/bin/ln/ln.c | 230 | ||||
-rw-r--r-- | toolbox/upstream-netbsd/bin/mv/mv.c | 396 | ||||
-rw-r--r-- | toolbox/upstream-netbsd/bin/mv/pathnames.h | 45 | ||||
-rw-r--r-- | toolbox/upstream-netbsd/bin/rm/rm.c | 625 | ||||
-rw-r--r-- | toolbox/upstream-netbsd/bin/rmdir/rmdir.c | 121 | ||||
-rw-r--r-- | toolbox/upstream-netbsd/bin/sleep/sleep.c | 159 | ||||
-rw-r--r-- | toolbox/upstream-netbsd/bin/sync/sync.c | 59 |
19 files changed, 5078 insertions, 0 deletions
diff --git a/toolbox/upstream-netbsd/bin/cat/cat.c b/toolbox/upstream-netbsd/bin/cat/cat.c new file mode 100644 index 0000000..cca8cf5 --- /dev/null +++ b/toolbox/upstream-netbsd/bin/cat/cat.c @@ -0,0 +1,329 @@ +/* $NetBSD: cat.c,v 1.54 2013/12/08 08:32:13 spz 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. + */ + +#if HAVE_NBTOOL_CONFIG_H +#include "nbtool_config.h" +#endif + +#include <sys/cdefs.h> +#if !defined(lint) +__COPYRIGHT( +"@(#) Copyright (c) 1989, 1993\ + The Regents of the University of California. All rights reserved."); +#if 0 +static char sccsid[] = "@(#)cat.c 8.2 (Berkeley) 4/27/95"; +#else +__RCSID("$NetBSD: cat.c,v 1.54 2013/12/08 08:32:13 spz Exp $"); +#endif +#endif /* not lint */ + +#include <sys/param.h> +#include <sys/stat.h> + +#include <ctype.h> +#include <err.h> +#include <errno.h> +#include <fcntl.h> +#include <locale.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +static int bflag, eflag, fflag, lflag, nflag, sflag, tflag, vflag; +static size_t bsize; +static int rval; +static const char *filename; + +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; + + setprogname(argv[0]); + (void)setlocale(LC_ALL, ""); + + while ((ch = getopt(argc, argv, "B:beflnstuv")) != -1) + switch (ch) { + case 'B': + bsize = (size_t)strtol(optarg, NULL, 0); + break; + 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': + setbuf(stdout, NULL); + break; + case 'v': + vflag = 1; + break; + default: + case '?': + (void)fprintf(stderr, + "Usage: %s [-beflnstuv] [-B bsize] [-] " + "[file ...]\n", getprogname()); + return EXIT_FAILURE; + } + 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) + err(EXIT_FAILURE, "stdout"); + } + + if (bflag || eflag || nflag || sflag || tflag || vflag) + cook_args(argv); + else + raw_args(argv); + if (fclose(stdout)) + err(EXIT_FAILURE, "stdout"); + return rval; +} + +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) { + warn("%s", *argv); + rval = EXIT_FAILURE; + ++argv; + continue; + } + filename = *argv++; + } + cook_buf(fp); + if (fp != stdin) + (void)fclose(fp); + else + clearerr(fp); + } while (*argv); +} + +void +cook_buf(FILE *fp) +{ + int ch, gobble, line, prev; + + line = gobble = 0; + for (prev = '\n'; (ch = getc(fp)) != EOF; prev = ch) { + if (prev == '\n') { + if (ch == '\n') { + if (sflag) { + if (!gobble && nflag && !bflag) + (void)fprintf(stdout, + "%6d\t\n", ++line); + else if (!gobble && putchar(ch) == EOF) + break; + gobble = 1; + continue; + } + if (nflag) { + if (!bflag) { + (void)fprintf(stdout, + "%6d\t", ++line); + if (ferror(stdout)) + break; + } else if (eflag) { + (void)fprintf(stdout, + "%6s\t", ""); + if (ferror(stdout)) + break; + } + } + } else if (nflag) { + (void)fprintf(stdout, "%6d\t", ++line); + if (ferror(stdout)) + 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 = toascii(ch); + } + if (iscntrl(ch)) { + if (putchar('^') == EOF || + putchar(ch == '\177' ? '?' : + ch | 0100) == EOF) + break; + continue; + } + } + if (putchar(ch) == EOF) + break; + } + if (ferror(fp)) { + warn("%s", filename); + rval = EXIT_FAILURE; + clearerr(fp); + } + if (ferror(stdout)) + err(EXIT_FAILURE, "stdout"); +} + +void +raw_args(char **argv) +{ + int fd; + + fd = fileno(stdin); + filename = "stdin"; + do { + if (*argv) { + if (!strcmp(*argv, "-")) { + fd = fileno(stdin); + if (fd < 0) + goto skip; + } 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); + warnx("%s: not a regular file", *argv); + goto skipnomsg; + } + } + else if ((fd = open(*argv, O_RDONLY, 0)) < 0) { +skip: + warn("%s", *argv); +skipnomsg: + rval = EXIT_FAILURE; + ++argv; + continue; + } + filename = *argv++; + } else if (fd < 0) { + err(EXIT_FAILURE, "stdin"); + } + 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]; + + ssize_t nr, nw, off; + int wfd; + + wfd = fileno(stdout); + if (wfd < 0) + err(EXIT_FAILURE, "stdout"); + if (buf == NULL) { + struct stat sbuf; + + if (bsize == 0) { + if (fstat(wfd, &sbuf) == 0 && sbuf.st_blksize > 0 && + (size_t)sbuf.st_blksize > sizeof(fb_buf)) + bsize = sbuf.st_blksize; + } + if (bsize > sizeof(fb_buf)) { + buf = malloc(bsize); + if (buf == NULL) + warnx("malloc, using %zu buffer", bsize); + } + if (buf == NULL) { + bsize = sizeof(fb_buf); + buf = fb_buf; + } + } + 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) + err(EXIT_FAILURE, "stdout"); + if (nr < 0) { + warn("%s", filename); + rval = EXIT_FAILURE; + } +} diff --git a/toolbox/upstream-netbsd/bin/cp/cp.c b/toolbox/upstream-netbsd/bin/cp/cp.c new file mode 100644 index 0000000..4bbe1b7 --- /dev/null +++ b/toolbox/upstream-netbsd/bin/cp/cp.c @@ -0,0 +1,548 @@ +/* $NetBSD: cp.c,v 1.58 2012/01/04 15:58:37 christos Exp $ */ + +/* + * Copyright (c) 1988, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * David Hitz of Auspex Systems Inc. + * + * 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. + */ + +#include <sys/cdefs.h> +#ifndef lint +__COPYRIGHT( +"@(#) Copyright (c) 1988, 1993, 1994\ + The Regents of the University of California. All rights reserved."); +#endif /* not lint */ + +#ifndef lint +#if 0 +static char sccsid[] = "@(#)cp.c 8.5 (Berkeley) 4/29/95"; +#else +__RCSID("$NetBSD: cp.c,v 1.58 2012/01/04 15:58:37 christos Exp $"); +#endif +#endif /* not lint */ + +/* + * Cp copies source files to target files. + * + * The global PATH_T structure "to" always contains the path to the + * current target file. Since fts(3) does not change directories, + * this path can be either absolute or dot-relative. + * + * The basic algorithm is to initialize "to" and use fts(3) to traverse + * the file hierarchy rooted in the argument list. A trivial case is the + * case of 'cp file1 file2'. The more interesting case is the case of + * 'cp file1 file2 ... fileN dir' where the hierarchy is traversed and the + * path (relative to the root of the traversal) is appended to dir (stored + * in "to") to form the final target path. + */ + +#include <sys/param.h> +#include <sys/stat.h> + +#include <assert.h> +#include <err.h> +#include <errno.h> +#include <fts.h> +#include <locale.h> +#include <signal.h> +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <unistd.h> + +#include "extern.h" + +#define STRIP_TRAILING_SLASH(p) { \ + while ((p).p_end > (p).p_path + 1 && (p).p_end[-1] == '/') \ + *--(p).p_end = '\0'; \ +} + +static char empty[] = ""; +PATH_T to = { .p_end = to.p_path, .target_end = empty }; + +uid_t myuid; +int Hflag, Lflag, Rflag, Pflag, fflag, iflag, lflag, pflag, rflag, vflag, Nflag; +mode_t myumask; +sig_atomic_t pinfo; + +enum op { FILE_TO_FILE, FILE_TO_DIR, DIR_TO_DNE }; + +static int copy(char *[], enum op, int); + +static void +progress(int sig __unused) +{ + + pinfo++; +} + +int +main(int argc, char *argv[]) +{ + struct stat to_stat, tmp_stat; + enum op type; + int ch, fts_options, r, have_trailing_slash; + char *target, **src; + + setprogname(argv[0]); + (void)setlocale(LC_ALL, ""); + + Hflag = Lflag = Pflag = Rflag = 0; + while ((ch = getopt(argc, argv, "HLNPRfailprv")) != -1) + switch (ch) { + case 'H': + Hflag = 1; + Lflag = Pflag = 0; + break; + case 'L': + Lflag = 1; + Hflag = Pflag = 0; + break; + case 'N': + Nflag = 1; + break; + case 'P': + Pflag = 1; + Hflag = Lflag = 0; + break; + case 'R': + Rflag = 1; + break; + case 'a': + Pflag = 1; + pflag = 1; + Rflag = 1; + Hflag = Lflag = 0; + break; + case 'f': + fflag = 1; + iflag = 0; + break; + case 'i': + iflag = isatty(fileno(stdin)); + fflag = 0; + break; + case 'l': + lflag = 1; + break; + case 'p': + pflag = 1; + break; + case 'r': + rflag = 1; + break; + case 'v': + vflag = 1; + break; + case '?': + default: + usage(); + /* NOTREACHED */ + } + argc -= optind; + argv += optind; + + if (argc < 2) + usage(); + + fts_options = FTS_NOCHDIR | FTS_PHYSICAL; + if (rflag) { + if (Rflag) { + errx(EXIT_FAILURE, + "the -R and -r options may not be specified together."); + /* NOTREACHED */ + } + if (Hflag || Lflag || Pflag) { + errx(EXIT_FAILURE, + "the -H, -L, and -P options may not be specified with the -r option."); + /* NOTREACHED */ + } + fts_options &= ~FTS_PHYSICAL; + fts_options |= FTS_LOGICAL; + } + + if (Rflag) { + if (Hflag) + fts_options |= FTS_COMFOLLOW; + if (Lflag) { + fts_options &= ~FTS_PHYSICAL; + fts_options |= FTS_LOGICAL; + } + } else if (!Pflag) { + fts_options &= ~FTS_PHYSICAL; + fts_options |= FTS_LOGICAL | FTS_COMFOLLOW; + } + + myuid = getuid(); + + /* Copy the umask for explicit mode setting. */ + myumask = umask(0); + (void)umask(myumask); + + /* Save the target base in "to". */ + target = argv[--argc]; + if (strlcpy(to.p_path, target, sizeof(to.p_path)) >= sizeof(to.p_path)) + errx(EXIT_FAILURE, "%s: name too long", target); + to.p_end = to.p_path + strlen(to.p_path); + have_trailing_slash = (to.p_end[-1] == '/'); + if (have_trailing_slash) + STRIP_TRAILING_SLASH(to); + to.target_end = to.p_end; + + /* Set end of argument list for fts(3). */ + argv[argc] = NULL; + + (void)signal(SIGINFO, progress); + + /* + * Cp has two distinct cases: + * + * cp [-R] source target + * cp [-R] source1 ... sourceN directory + * + * In both cases, source can be either a file or a directory. + * + * In (1), the target becomes a copy of the source. That is, if the + * source is a file, the target will be a file, and likewise for + * directories. + * + * In (2), the real target is not directory, but "directory/source". + */ + if (Pflag) + r = lstat(to.p_path, &to_stat); + else + r = stat(to.p_path, &to_stat); + if (r == -1 && errno != ENOENT) { + err(EXIT_FAILURE, "%s", to.p_path); + /* NOTREACHED */ + } + if (r == -1 || !S_ISDIR(to_stat.st_mode)) { + /* + * Case (1). Target is not a directory. + */ + if (argc > 1) + usage(); + /* + * Need to detect the case: + * cp -R dir foo + * Where dir is a directory and foo does not exist, where + * we want pathname concatenations turned on but not for + * the initial mkdir(). + */ + if (r == -1) { + if (rflag || (Rflag && (Lflag || Hflag))) + r = stat(*argv, &tmp_stat); + else + r = lstat(*argv, &tmp_stat); + if (r == -1) { + err(EXIT_FAILURE, "%s", *argv); + /* NOTREACHED */ + } + + if (S_ISDIR(tmp_stat.st_mode) && (Rflag || rflag)) + type = DIR_TO_DNE; + else + type = FILE_TO_FILE; + } else + type = FILE_TO_FILE; + + if (have_trailing_slash && type == FILE_TO_FILE) { + if (r == -1) + errx(1, "directory %s does not exist", + to.p_path); + else + errx(1, "%s is not a directory", to.p_path); + } + } else { + /* + * Case (2). Target is a directory. + */ + type = FILE_TO_DIR; + } + + /* + * make "cp -rp src/ dst" behave like "cp -rp src dst" not + * like "cp -rp src/. dst" + */ + for (src = argv; *src; src++) { + size_t len = strlen(*src); + while (len-- > 1 && (*src)[len] == '/') + (*src)[len] = '\0'; + } + + exit(copy(argv, type, fts_options)); + /* NOTREACHED */ +} + +static int dnestack[MAXPATHLEN]; /* unlikely we'll have more nested dirs */ +static ssize_t dnesp; +static void +pushdne(int dne) +{ + + dnestack[dnesp++] = dne; + assert(dnesp < MAXPATHLEN); +} + +static int +popdne(void) +{ + int rv; + + rv = dnestack[--dnesp]; + assert(dnesp >= 0); + return rv; +} + +static int +copy(char *argv[], enum op type, int fts_options) +{ + struct stat to_stat; + FTS *ftsp; + FTSENT *curr; + int base, dne, sval; + int this_failed, any_failed; + size_t nlen; + char *p, *target_mid; + + base = 0; /* XXX gcc -Wuninitialized (see comment below) */ + + if ((ftsp = fts_open(argv, fts_options, NULL)) == NULL) + err(EXIT_FAILURE, "%s", argv[0]); + /* NOTREACHED */ + for (any_failed = 0; (curr = fts_read(ftsp)) != NULL;) { + this_failed = 0; + switch (curr->fts_info) { + case FTS_NS: + case FTS_DNR: + case FTS_ERR: + warnx("%s: %s", curr->fts_path, + strerror(curr->fts_errno)); + this_failed = any_failed = 1; + continue; + case FTS_DC: /* Warn, continue. */ + warnx("%s: directory causes a cycle", curr->fts_path); + this_failed = any_failed = 1; + continue; + } + + /* + * If we are in case (2) or (3) above, we need to append the + * source name to the target name. + */ + if (type != FILE_TO_FILE) { + if ((curr->fts_namelen + + to.target_end - to.p_path + 1) > MAXPATHLEN) { + warnx("%s/%s: name too long (not copied)", + to.p_path, curr->fts_name); + this_failed = any_failed = 1; + continue; + } + + /* + * Need to remember the roots of traversals to create + * correct pathnames. If there's a directory being + * copied to a non-existent directory, e.g. + * cp -R a/dir noexist + * the resulting path name should be noexist/foo, not + * noexist/dir/foo (where foo is a file in dir), which + * is the case where the target exists. + * + * Also, check for "..". This is for correct path + * concatentation for paths ending in "..", e.g. + * cp -R .. /tmp + * Paths ending in ".." are changed to ".". This is + * tricky, but seems the easiest way to fix the problem. + * + * XXX + * Since the first level MUST be FTS_ROOTLEVEL, base + * is always initialized. + */ + if (curr->fts_level == FTS_ROOTLEVEL) { + if (type != DIR_TO_DNE) { + p = strrchr(curr->fts_path, '/'); + base = (p == NULL) ? 0 : + (int)(p - curr->fts_path + 1); + + if (!strcmp(&curr->fts_path[base], + "..")) + base += 1; + } else + base = curr->fts_pathlen; + } + + p = &curr->fts_path[base]; + nlen = curr->fts_pathlen - base; + target_mid = to.target_end; + if (*p != '/' && target_mid[-1] != '/') + *target_mid++ = '/'; + *target_mid = 0; + + if (target_mid - to.p_path + nlen >= PATH_MAX) { + warnx("%s%s: name too long (not copied)", + to.p_path, p); + this_failed = any_failed = 1; + continue; + } + (void)strncat(target_mid, p, nlen); + to.p_end = target_mid + nlen; + *to.p_end = 0; + STRIP_TRAILING_SLASH(to); + } + + sval = Pflag ? lstat(to.p_path, &to_stat) : stat(to.p_path, &to_stat); + /* Not an error but need to remember it happened */ + if (sval == -1) + dne = 1; + else { + if (to_stat.st_dev == curr->fts_statp->st_dev && + to_stat.st_ino == curr->fts_statp->st_ino) { + warnx("%s and %s are identical (not copied).", + to.p_path, curr->fts_path); + this_failed = any_failed = 1; + if (S_ISDIR(curr->fts_statp->st_mode)) + (void)fts_set(ftsp, curr, FTS_SKIP); + continue; + } + if (!S_ISDIR(curr->fts_statp->st_mode) && + S_ISDIR(to_stat.st_mode)) { + warnx("cannot overwrite directory %s with non-directory %s", + to.p_path, curr->fts_path); + this_failed = any_failed = 1; + continue; + } + dne = 0; + } + + switch (curr->fts_statp->st_mode & S_IFMT) { + case S_IFLNK: + /* Catch special case of a non dangling symlink */ + if((fts_options & FTS_LOGICAL) || + ((fts_options & FTS_COMFOLLOW) && curr->fts_level == 0)) { + if (copy_file(curr, dne)) + this_failed = any_failed = 1; + } else { + if (copy_link(curr, !dne)) + this_failed = any_failed = 1; + } + break; + case S_IFDIR: + if (!Rflag && !rflag) { + if (curr->fts_info == FTS_D) + warnx("%s is a directory (not copied).", + curr->fts_path); + (void)fts_set(ftsp, curr, FTS_SKIP); + this_failed = any_failed = 1; + break; + } + + /* + * Directories get noticed twice: + * In the first pass, create it if needed. + * In the second pass, after the children have been copied, set the permissions. + */ + if (curr->fts_info == FTS_D) /* First pass */ + { + /* + * If the directory doesn't exist, create the new + * one with the from file mode plus owner RWX bits, + * modified by the umask. Trade-off between being + * able to write the directory (if from directory is + * 555) and not causing a permissions race. If the + * umask blocks owner writes, we fail.. + */ + pushdne(dne); + if (dne) { + if (mkdir(to.p_path, + curr->fts_statp->st_mode | S_IRWXU) < 0) + err(EXIT_FAILURE, "%s", + to.p_path); + /* NOTREACHED */ + } else if (!S_ISDIR(to_stat.st_mode)) { + errno = ENOTDIR; + err(EXIT_FAILURE, "%s", + to.p_path); + /* NOTREACHED */ + } + } + else if (curr->fts_info == FTS_DP) /* Second pass */ + { + /* + * If not -p and directory didn't exist, set it to be + * the same as the from directory, umodified by the + * umask; arguably wrong, but it's been that way + * forever. + */ + if (pflag && setfile(curr->fts_statp, 0)) + this_failed = any_failed = 1; + else if ((dne = popdne())) + (void)chmod(to.p_path, + curr->fts_statp->st_mode); + } + else + { + warnx("directory %s encountered when not expected.", + curr->fts_path); + this_failed = any_failed = 1; + break; + } + + break; + case S_IFBLK: + case S_IFCHR: + if (Rflag) { + if (copy_special(curr->fts_statp, !dne)) + this_failed = any_failed = 1; + } else + if (copy_file(curr, dne)) + this_failed = any_failed = 1; + break; + case S_IFIFO: + if (Rflag) { + if (copy_fifo(curr->fts_statp, !dne)) + this_failed = any_failed = 1; + } else + if (copy_file(curr, dne)) + this_failed = any_failed = 1; + break; + default: + if (copy_file(curr, dne)) + this_failed = any_failed = 1; + break; + } + if (vflag && !this_failed) + (void)printf("%s -> %s\n", curr->fts_path, to.p_path); + } + if (errno) { + err(EXIT_FAILURE, "fts_read"); + /* NOTREACHED */ + } + (void)fts_close(ftsp); + return (any_failed); +} diff --git a/toolbox/upstream-netbsd/bin/cp/extern.h b/toolbox/upstream-netbsd/bin/cp/extern.h new file mode 100644 index 0000000..e393844 --- /dev/null +++ b/toolbox/upstream-netbsd/bin/cp/extern.h @@ -0,0 +1,61 @@ +/* $NetBSD: extern.h,v 1.17 2012/01/04 15:58:37 christos Exp $ */ + +/*- + * Copyright (c) 1991, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * 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. + * + * @(#)extern.h 8.2 (Berkeley) 4/1/94 + */ + +#ifndef _EXTERN_H_ +#define _EXTERN_H_ + +typedef struct { + char *p_end; /* pointer to NULL at end of path */ + char *target_end; /* pointer to end of target base */ + char p_path[MAXPATHLEN + 1]; /* pointer to the start of a path */ +} PATH_T; + +extern PATH_T to; +extern uid_t myuid; +extern int Rflag, rflag, Hflag, Lflag, Pflag, fflag, iflag, lflag, pflag, Nflag; +extern mode_t myumask; +extern sig_atomic_t pinfo; + +#include <sys/cdefs.h> + +__BEGIN_DECLS +int copy_fifo(struct stat *, int); +int copy_file(FTSENT *, int); +int copy_link(FTSENT *, int); +int copy_special(struct stat *, int); +int set_utimes(const char *, struct stat *); +int setfile(struct stat *, int); +void usage(void) __attribute__((__noreturn__)); +__END_DECLS + +#endif /* !_EXTERN_H_ */ diff --git a/toolbox/upstream-netbsd/bin/cp/utils.c b/toolbox/upstream-netbsd/bin/cp/utils.c new file mode 100644 index 0000000..d8f900a --- /dev/null +++ b/toolbox/upstream-netbsd/bin/cp/utils.c @@ -0,0 +1,444 @@ +/* $NetBSD: utils.c,v 1.42 2013/12/11 06:00:11 dholland Exp $ */ + +/*- + * Copyright (c) 1991, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * 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. + */ + +#include <sys/cdefs.h> +#ifndef lint +#if 0 +static char sccsid[] = "@(#)utils.c 8.3 (Berkeley) 4/1/94"; +#else +__RCSID("$NetBSD: utils.c,v 1.42 2013/12/11 06:00:11 dholland Exp $"); +#endif +#endif /* not lint */ + +#include <sys/mman.h> +#include <sys/param.h> +#include <sys/stat.h> +#include <sys/time.h> +#include <sys/extattr.h> + +#include <err.h> +#include <errno.h> +#include <fcntl.h> +#include <fts.h> +#include <stdbool.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include "extern.h" + +#define MMAP_MAX_SIZE (8 * 1048576) +#define MMAP_MAX_WRITE (64 * 1024) + +int +set_utimes(const char *file, struct stat *fs) +{ + static struct timeval tv[2]; + +#ifdef __ANDROID__ + tv[0].tv_sec = fs->st_atime; + tv[0].tv_usec = 0; + tv[1].tv_sec = fs->st_mtime; + tv[1].tv_usec = 0; + + if (utimes(file, tv)) { + warn("utimes: %s", file); + return 1; + } +#else + TIMESPEC_TO_TIMEVAL(&tv[0], &fs->st_atimespec); + TIMESPEC_TO_TIMEVAL(&tv[1], &fs->st_mtimespec); + + if (lutimes(file, tv)) { + warn("lutimes: %s", file); + return (1); + } +#endif + return (0); +} + +struct finfo { + const char *from; + const char *to; + size_t size; +}; + +static void +progress(const struct finfo *fi, size_t written) +{ + int pcent = (int)((100.0 * written) / fi->size); + + pinfo = 0; + (void)fprintf(stderr, "%s => %s %zu/%zu bytes %d%% written\n", + fi->from, fi->to, written, fi->size, pcent); +} + +int +copy_file(FTSENT *entp, int dne) +{ + static char buf[MAXBSIZE]; + struct stat to_stat, *fs; + int ch, checkch, from_fd, rcount, rval, to_fd, tolnk, wcount; + char *p; + size_t ptotal = 0; + + if ((from_fd = open(entp->fts_path, O_RDONLY, 0)) == -1) { + warn("%s", entp->fts_path); + return (1); + } + + to_fd = -1; + fs = entp->fts_statp; + tolnk = ((Rflag && !(Lflag || Hflag)) || Pflag); + + /* + * If the file exists and we're interactive, verify with the user. + * If the file DNE, set the mode to be the from file, minus setuid + * bits, modified by the umask; arguably wrong, but it makes copying + * executables work right and it's been that way forever. (The + * other choice is 666 or'ed with the execute bits on the from file + * modified by the umask.) + */ + if (!dne) { + struct stat sb; + int sval; + + if (iflag) { + (void)fprintf(stderr, "overwrite %s? ", to.p_path); + checkch = ch = getchar(); + while (ch != '\n' && ch != EOF) + ch = getchar(); + if (checkch != 'y' && checkch != 'Y') { + (void)close(from_fd); + return (0); + } + } + + sval = tolnk ? + lstat(to.p_path, &sb) : stat(to.p_path, &sb); + if (sval == -1) { + warn("stat: %s", to.p_path); + (void)close(from_fd); + return (1); + } + + if (!(tolnk && S_ISLNK(sb.st_mode))) + to_fd = open(to.p_path, O_WRONLY | O_TRUNC, 0); + } else + to_fd = open(to.p_path, O_WRONLY | O_TRUNC | O_CREAT, + fs->st_mode & ~(S_ISUID | S_ISGID)); + + if (to_fd == -1 && (fflag || tolnk)) { + /* + * attempt to remove existing destination file name and + * create a new file + */ + (void)unlink(to.p_path); + to_fd = open(to.p_path, O_WRONLY | O_TRUNC | O_CREAT, + fs->st_mode & ~(S_ISUID | S_ISGID)); + } + + if (to_fd == -1) { + warn("%s", to.p_path); + (void)close(from_fd); + return (1); + } + + rval = 0; + + /* if hard linking then simply close the open fds, link and return */ + if (lflag) { + (void)close(from_fd); + (void)close(to_fd); + (void)unlink(to.p_path); + if (link(entp->fts_path, to.p_path)) { + warn("%s", to.p_path); + return (1); + } + return (0); + } + + /* + * There's no reason to do anything other than close the file + * now if it's empty, so let's not bother. + */ +#ifndef __ANDROID__ // Files in /proc report length 0. mmap will fail but we'll fall back to read. + if (fs->st_size > 0) { +#endif + struct finfo fi; + + fi.from = entp->fts_path; + fi.to = to.p_path; + fi.size = (size_t)fs->st_size; + + /* + * Mmap and write if less than 8M (the limit is so + * we don't totally trash memory on big files). + * This is really a minor hack, but it wins some CPU back. + */ + bool use_read; + + use_read = true; + if (fs->st_size <= MMAP_MAX_SIZE) { + size_t fsize = (size_t)fs->st_size; + p = mmap(NULL, fsize, PROT_READ, MAP_FILE|MAP_SHARED, + from_fd, (off_t)0); + if (p != MAP_FAILED) { + size_t remainder; + + use_read = false; + + (void) madvise(p, (size_t)fs->st_size, + MADV_SEQUENTIAL); + + /* + * Write out the data in small chunks to + * avoid locking the output file for a + * long time if the reading the data from + * the source is slow. + */ + remainder = fsize; + do { + ssize_t chunk; + + chunk = (remainder > MMAP_MAX_WRITE) ? + MMAP_MAX_WRITE : remainder; + if (write(to_fd, &p[fsize - remainder], + chunk) != chunk) { + warn("%s", to.p_path); + rval = 1; + break; + } + remainder -= chunk; + ptotal += chunk; + if (pinfo) + progress(&fi, ptotal); + } while (remainder > 0); + + if (munmap(p, fsize) < 0) { + warn("%s", entp->fts_path); + rval = 1; + } + } + } + + if (use_read) { + while ((rcount = read(from_fd, buf, MAXBSIZE)) > 0) { + wcount = write(to_fd, buf, (size_t)rcount); + if (rcount != wcount || wcount == -1) { + warn("%s", to.p_path); + rval = 1; + break; + } + ptotal += wcount; + if (pinfo) + progress(&fi, ptotal); + } + if (rcount < 0) { + warn("%s", entp->fts_path); + rval = 1; + } + } +#ifndef __ANDROID__ + } +#endif + +#ifndef __ANDROID__ + if (pflag && (fcpxattr(from_fd, to_fd) != 0)) + warn("%s: error copying extended attributes", to.p_path); +#endif + + (void)close(from_fd); + + if (rval == 1) { + (void)close(to_fd); + return (1); + } + + if (pflag && setfile(fs, to_fd)) + rval = 1; + /* + * If the source was setuid or setgid, lose the bits unless the + * copy is owned by the same user and group. + */ +#define RETAINBITS \ + (S_ISUID | S_ISGID | S_ISVTX | S_IRWXU | S_IRWXG | S_IRWXO) + if (!pflag && dne + && fs->st_mode & (S_ISUID | S_ISGID) && fs->st_uid == myuid) { + if (fstat(to_fd, &to_stat)) { + warn("%s", to.p_path); + rval = 1; + } else if (fs->st_gid == to_stat.st_gid && + fchmod(to_fd, fs->st_mode & RETAINBITS & ~myumask)) { + warn("%s", to.p_path); + rval = 1; + } + } + if (close(to_fd)) { + warn("%s", to.p_path); + rval = 1; + } + /* set the mod/access times now after close of the fd */ + if (pflag && set_utimes(to.p_path, fs)) { + rval = 1; + } + return (rval); +} + +int +copy_link(FTSENT *p, int exists) +{ + int len; + char target[MAXPATHLEN]; + + if ((len = readlink(p->fts_path, target, sizeof(target)-1)) == -1) { + warn("readlink: %s", p->fts_path); + return (1); + } + target[len] = '\0'; + if (exists && unlink(to.p_path)) { + warn("unlink: %s", to.p_path); + return (1); + } + if (symlink(target, to.p_path)) { + warn("symlink: %s", target); + return (1); + } + return (pflag ? setfile(p->fts_statp, 0) : 0); +} + +int +copy_fifo(struct stat *from_stat, int exists) +{ + if (exists && unlink(to.p_path)) { + warn("unlink: %s", to.p_path); + return (1); + } + if (mkfifo(to.p_path, from_stat->st_mode)) { + warn("mkfifo: %s", to.p_path); + return (1); + } + return (pflag ? setfile(from_stat, 0) : 0); +} + +int +copy_special(struct stat *from_stat, int exists) +{ + if (exists && unlink(to.p_path)) { + warn("unlink: %s", to.p_path); + return (1); + } + if (mknod(to.p_path, from_stat->st_mode, from_stat->st_rdev)) { + warn("mknod: %s", to.p_path); + return (1); + } + return (pflag ? setfile(from_stat, 0) : 0); +} + + +/* + * Function: setfile + * + * Purpose: + * Set the owner/group/permissions for the "to" file to the information + * in the stat structure. If fd is zero, also call set_utimes() to set + * the mod/access times. If fd is non-zero, the caller must do a utimes + * itself after close(fd). + */ +int +setfile(struct stat *fs, int fd) +{ + int rval, islink; + + rval = 0; + islink = S_ISLNK(fs->st_mode); + fs->st_mode &= S_ISUID | S_ISGID | S_IRWXU | S_IRWXG | S_IRWXO; + + /* + * Changing the ownership probably won't succeed, unless we're root + * or POSIX_CHOWN_RESTRICTED is not set. Set uid/gid before setting + * the mode; current BSD behavior is to remove all setuid bits on + * chown. If chown fails, lose setuid/setgid bits. + */ + if (fd ? fchown(fd, fs->st_uid, fs->st_gid) : + lchown(to.p_path, fs->st_uid, fs->st_gid)) { + if (errno != EPERM) { + warn("chown: %s", to.p_path); + rval = 1; + } + fs->st_mode &= ~(S_ISUID | S_ISGID); + } +#ifdef __ANDROID__ + if (fd ? fchmod(fd, fs->st_mode) : chmod(to.p_path, fs->st_mode)) { +#else + if (fd ? fchmod(fd, fs->st_mode) : lchmod(to.p_path, fs->st_mode)) { +#endif + warn("chmod: %s", to.p_path); + rval = 1; + } + +#ifndef __ANDROID__ + if (!islink && !Nflag) { + unsigned long fflags = fs->st_flags; + /* + * XXX + * NFS doesn't support chflags; ignore errors unless + * there's reason to believe we're losing bits. + * (Note, this still won't be right if the server + * supports flags and we were trying to *remove* flags + * on a file that we copied, i.e., that we didn't create.) + */ + errno = 0; + if ((fd ? fchflags(fd, fflags) : + chflags(to.p_path, fflags)) == -1) + if (errno != EOPNOTSUPP || fs->st_flags != 0) { + warn("chflags: %s", to.p_path); + rval = 1; + } + } +#endif + /* if fd is non-zero, caller must call set_utimes() after close() */ + if (fd == 0 && set_utimes(to.p_path, fs)) + rval = 1; + return (rval); +} + +void +usage(void) +{ + (void)fprintf(stderr, + "usage: %s [-R [-H | -L | -P]] [-f | -i] [-alNpv] src target\n" + " %s [-R [-H | -L | -P]] [-f | -i] [-alNpv] src1 ... srcN directory\n", + getprogname(), getprogname()); + exit(1); + /* NOTREACHED */ +} diff --git a/toolbox/upstream-netbsd/bin/dd/args.c b/toolbox/upstream-netbsd/bin/dd/args.c new file mode 100644 index 0000000..207e300 --- /dev/null +++ b/toolbox/upstream-netbsd/bin/dd/args.c @@ -0,0 +1,391 @@ +/* $NetBSD: args.c,v 1.38 2013/07/17 12:55:48 christos Exp $ */ + +/*- + * Copyright (c) 1991, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Keith Muller of the University of California, San Diego and Lance + * Visser of Convex Computer Corporation. + * + * 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. + */ + +#include <sys/cdefs.h> +#ifndef lint +#if 0 +static char sccsid[] = "@(#)args.c 8.3 (Berkeley) 4/2/94"; +#else +__RCSID("$NetBSD: args.c,v 1.38 2013/07/17 12:55:48 christos Exp $"); +#endif +#endif /* not lint */ + +#include <sys/types.h> +#include <sys/time.h> + +#include <err.h> +#include <errno.h> +#include <limits.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "dd.h" +#include "extern.h" + +static int c_arg(const void *, const void *); + +#ifdef NO_MSGFMT +static void f_msgfmt(char *) __dead; +#else +static void f_msgfmt(char *); +#endif /* NO_MSGFMT */ + +#ifdef NO_CONV +static void f_conv(char *) __dead; +#else +static void f_conv(char *); +static int c_conv(const void *, const void *); +#endif /* NO_CONV */ + +static void f_bs(char *); +static void f_cbs(char *); +static void f_count(char *); +static void f_files(char *); +static void f_ibs(char *); +static void f_if(char *); +static void f_obs(char *); +static void f_of(char *); +static void f_seek(char *); +static void f_skip(char *); +static void f_progress(char *); + +static const struct arg { + const char *name; + void (*f)(char *); + u_int set, noset; +} args[] = { + /* the array needs to be sorted by the first column so + bsearch() can be used to find commands quickly */ + { "bs", f_bs, C_BS, C_BS|C_IBS|C_OBS|C_OSYNC }, + { "cbs", f_cbs, C_CBS, C_CBS }, + { "conv", f_conv, 0, 0 }, + { "count", f_count, C_COUNT, C_COUNT }, + { "files", f_files, C_FILES, C_FILES }, + { "ibs", f_ibs, C_IBS, C_BS|C_IBS }, + { "if", f_if, C_IF, C_IF }, + { "iseek", f_skip, C_SKIP, C_SKIP }, + { "msgfmt", f_msgfmt, 0, 0 }, + { "obs", f_obs, C_OBS, C_BS|C_OBS }, + { "of", f_of, C_OF, C_OF }, + { "oseek", f_seek, C_SEEK, C_SEEK }, + { "progress", f_progress, 0, 0 }, + { "seek", f_seek, C_SEEK, C_SEEK }, + { "skip", f_skip, C_SKIP, C_SKIP }, +}; + +/* + * args -- parse JCL syntax of dd. + */ +void +jcl(char **argv) +{ + struct arg *ap, tmp; + char *oper, *arg; + + in.dbsz = out.dbsz = 512; + + while ((oper = *++argv) != NULL) { + if ((oper = strdup(oper)) == NULL) { + errx(EXIT_FAILURE, + "unable to allocate space for the argument %s", + *argv); + /* NOTREACHED */ + } + if ((arg = strchr(oper, '=')) == NULL) { + errx(EXIT_FAILURE, "unknown operand %s", oper); + /* NOTREACHED */ + } + *arg++ = '\0'; + if (!*arg) { + errx(EXIT_FAILURE, "no value specified for %s", oper); + /* NOTREACHED */ + } + tmp.name = oper; + if (!(ap = bsearch(&tmp, args, + __arraycount(args), sizeof(*args), c_arg))) { + errx(EXIT_FAILURE, "unknown operand %s", tmp.name); + /* NOTREACHED */ + } + if (ddflags & ap->noset) { + errx(EXIT_FAILURE, + "%s: illegal argument combination or already set", + tmp.name); + /* NOTREACHED */ + } + ddflags |= ap->set; + ap->f(arg); + } + + /* Final sanity checks. */ + + if (ddflags & C_BS) { + /* + * Bs is turned off by any conversion -- we assume the user + * just wanted to set both the input and output block sizes + * and didn't want the bs semantics, so we don't warn. + */ + if (ddflags & (C_BLOCK | C_LCASE | C_SWAB | C_UCASE | + C_UNBLOCK | C_OSYNC | C_ASCII | C_EBCDIC | C_SPARSE)) { + ddflags &= ~C_BS; + ddflags |= C_IBS|C_OBS; + } + + /* Bs supersedes ibs and obs. */ + if (ddflags & C_BS && ddflags & (C_IBS|C_OBS)) + warnx("bs supersedes ibs and obs"); + } + + /* + * Ascii/ebcdic and cbs implies block/unblock. + * Block/unblock requires cbs and vice-versa. + */ + if (ddflags & (C_BLOCK|C_UNBLOCK)) { + if (!(ddflags & C_CBS)) { + errx(EXIT_FAILURE, "record operations require cbs"); + /* NOTREACHED */ + } + cfunc = ddflags & C_BLOCK ? block : unblock; + } else if (ddflags & C_CBS) { + if (ddflags & (C_ASCII|C_EBCDIC)) { + if (ddflags & C_ASCII) { + ddflags |= C_UNBLOCK; + cfunc = unblock; + } else { + ddflags |= C_BLOCK; + cfunc = block; + } + } else { + errx(EXIT_FAILURE, + "cbs meaningless if not doing record operations"); + /* NOTREACHED */ + } + } else + cfunc = def; + + /* Read, write and seek calls take off_t as arguments. + * + * The following check is not done because an off_t is a quad + * for current NetBSD implementations. + * + * if (in.offset > INT_MAX/in.dbsz || out.offset > INT_MAX/out.dbsz) + * errx(1, "seek offsets cannot be larger than %d", INT_MAX); + */ +} + +static int +c_arg(const void *a, const void *b) +{ + + return (strcmp(((const struct arg *)a)->name, + ((const struct arg *)b)->name)); +} + +static void +f_bs(char *arg) +{ + + in.dbsz = out.dbsz = strsuftoll("block size", arg, 1, UINT_MAX); +} + +static void +f_cbs(char *arg) +{ + + cbsz = strsuftoll("conversion record size", arg, 1, UINT_MAX); +} + +static void +f_count(char *arg) +{ + + cpy_cnt = strsuftoll("block count", arg, 0, LLONG_MAX); + if (!cpy_cnt) + terminate(0); +} + +static void +f_files(char *arg) +{ + + files_cnt = (u_int)strsuftoll("file count", arg, 0, UINT_MAX); + if (!files_cnt) + terminate(0); +} + +static void +f_ibs(char *arg) +{ + + if (!(ddflags & C_BS)) + in.dbsz = strsuftoll("input block size", arg, 1, UINT_MAX); +} + +static void +f_if(char *arg) +{ + + in.name = arg; +} + +#ifdef NO_MSGFMT +/* Build a small version (i.e. for a ramdisk root) */ +static void +f_msgfmt(char *arg) +{ + + errx(EXIT_FAILURE, "msgfmt option disabled"); + /* NOTREACHED */ +} +#else /* NO_MSGFMT */ +static void +f_msgfmt(char *arg) +{ + + /* + * If the format string is not valid, dd_write_msg() will print + * an error and exit. + */ + dd_write_msg(arg, 0); + + msgfmt = arg; +} +#endif /* NO_MSGFMT */ + +static void +f_obs(char *arg) +{ + + if (!(ddflags & C_BS)) + out.dbsz = strsuftoll("output block size", arg, 1, UINT_MAX); +} + +static void +f_of(char *arg) +{ + + out.name = arg; +} + +static void +f_seek(char *arg) +{ + + out.offset = strsuftoll("seek blocks", arg, 0, LLONG_MAX); +} + +static void +f_skip(char *arg) +{ + + in.offset = strsuftoll("skip blocks", arg, 0, LLONG_MAX); +} + +static void +f_progress(char *arg) +{ + + progress = strsuftoll("progress blocks", arg, 0, LLONG_MAX); +} + +#ifdef NO_CONV +/* Build a small version (i.e. for a ramdisk root) */ +static void +f_conv(char *arg) +{ + + errx(EXIT_FAILURE, "conv option disabled"); + /* NOTREACHED */ +} +#else /* NO_CONV */ + +static const struct conv { + const char *name; + u_int set, noset; + const u_char *ctab; +} clist[] = { + { "ascii", C_ASCII, C_EBCDIC, e2a_POSIX }, + { "block", C_BLOCK, C_UNBLOCK, NULL }, + { "ebcdic", C_EBCDIC, C_ASCII, a2e_POSIX }, + { "ibm", C_EBCDIC, C_ASCII, a2ibm_POSIX }, + { "lcase", C_LCASE, C_UCASE, NULL }, + { "noerror", C_NOERROR, 0, NULL }, + { "notrunc", C_NOTRUNC, 0, NULL }, + { "oldascii", C_ASCII, C_EBCDIC, e2a_32V }, + { "oldebcdic", C_EBCDIC, C_ASCII, a2e_32V }, + { "oldibm", C_EBCDIC, C_ASCII, a2ibm_32V }, + { "osync", C_OSYNC, C_BS, NULL }, + { "sparse", C_SPARSE, 0, NULL }, + { "swab", C_SWAB, 0, NULL }, + { "sync", C_SYNC, 0, NULL }, + { "ucase", C_UCASE, C_LCASE, NULL }, + { "unblock", C_UNBLOCK, C_BLOCK, NULL }, + /* If you add items to this table, be sure to add the + * conversions to the C_BS check in the jcl routine above. + */ +}; + +static void +f_conv(char *arg) +{ + struct conv *cp, tmp; + + while (arg != NULL) { + tmp.name = strsep(&arg, ","); + if (!(cp = bsearch(&tmp, clist, + __arraycount(clist), sizeof(*clist), c_conv))) { + errx(EXIT_FAILURE, "unknown conversion %s", tmp.name); + /* NOTREACHED */ + } + if (ddflags & cp->noset) { + errx(EXIT_FAILURE, + "%s: illegal conversion combination", tmp.name); + /* NOTREACHED */ + } + ddflags |= cp->set; + if (cp->ctab) + ctab = cp->ctab; + } +} + +static int +c_conv(const void *a, const void *b) +{ + + return (strcmp(((const struct conv *)a)->name, + ((const struct conv *)b)->name)); +} + +#endif /* NO_CONV */ diff --git a/toolbox/upstream-netbsd/bin/dd/conv.c b/toolbox/upstream-netbsd/bin/dd/conv.c new file mode 100644 index 0000000..d4a8a09 --- /dev/null +++ b/toolbox/upstream-netbsd/bin/dd/conv.c @@ -0,0 +1,283 @@ +/* $NetBSD: conv.c,v 1.17 2003/08/07 09:05:10 agc Exp $ */ + +/*- + * Copyright (c) 1991, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Keith Muller of the University of California, San Diego and Lance + * Visser of Convex Computer Corporation. + * + * 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. + */ + +#include <sys/cdefs.h> +#ifndef lint +#if 0 +static char sccsid[] = "@(#)conv.c 8.3 (Berkeley) 4/2/94"; +#else +__RCSID("$NetBSD: conv.c,v 1.17 2003/08/07 09:05:10 agc Exp $"); +#endif +#endif /* not lint */ + +#include <sys/param.h> +#include <sys/time.h> + +#include <err.h> +#include <string.h> +#include <stdlib.h> + +#include "dd.h" +#include "extern.h" + +/* + * def -- + * Copy input to output. Input is buffered until reaches obs, and then + * output until less than obs remains. Only a single buffer is used. + * Worst case buffer calculation is (ibs + obs - 1). + */ +void +def(void) +{ + uint64_t cnt; + u_char *inp; + const u_char *t; + + if ((t = ctab) != NULL) + for (inp = in.dbp - (cnt = in.dbrcnt); cnt--; ++inp) + *inp = t[*inp]; + + /* Make the output buffer look right. */ + out.dbp = in.dbp; + out.dbcnt = in.dbcnt; + + if (in.dbcnt >= out.dbsz) { + /* If the output buffer is full, write it. */ + dd_out(0); + + /* + * Ddout copies the leftover output to the beginning of + * the buffer and resets the output buffer. Reset the + * input buffer to match it. + */ + in.dbp = out.dbp; + in.dbcnt = out.dbcnt; + } +} + +void +def_close(void) +{ + + /* Just update the count, everything is already in the buffer. */ + if (in.dbcnt) + out.dbcnt = in.dbcnt; +} + +#ifdef NO_CONV +/* Build a smaller version (i.e. for a miniroot) */ +/* These can not be called, but just in case... */ +static const char no_block[] = "unblock and -DNO_CONV?"; +void block(void) { errx(EXIT_FAILURE, "%s", no_block + 2); } +void block_close(void) { errx(EXIT_FAILURE, "%s", no_block + 2); } +void unblock(void) { errx(EXIT_FAILURE, "%s", no_block); } +void unblock_close(void) { errx(EXIT_FAILURE, "%s", no_block); } +#else /* NO_CONV */ + +/* + * Copy variable length newline terminated records with a max size cbsz + * bytes to output. Records less than cbs are padded with spaces. + * + * max in buffer: MAX(ibs, cbsz) + * max out buffer: obs + cbsz + */ +void +block(void) +{ + static int intrunc; + int ch = 0; /* pacify gcc */ + uint64_t cnt, maxlen; + u_char *inp, *outp; + const u_char *t; + + /* + * Record truncation can cross block boundaries. If currently in a + * truncation state, keep tossing characters until reach a newline. + * Start at the beginning of the buffer, as the input buffer is always + * left empty. + */ + if (intrunc) { + for (inp = in.db, cnt = in.dbrcnt; + cnt && *inp++ != '\n'; --cnt); + if (!cnt) { + in.dbcnt = 0; + in.dbp = in.db; + return; + } + intrunc = 0; + /* Adjust the input buffer numbers. */ + in.dbcnt = cnt - 1; + in.dbp = inp + cnt - 1; + } + + /* + * Copy records (max cbsz size chunks) into the output buffer. The + * translation is done as we copy into the output buffer. + */ + for (inp = in.dbp - in.dbcnt, outp = out.dbp; in.dbcnt;) { + maxlen = MIN(cbsz, in.dbcnt); + if ((t = ctab) != NULL) + for (cnt = 0; + cnt < maxlen && (ch = *inp++) != '\n'; ++cnt) + *outp++ = t[ch]; + else + for (cnt = 0; + cnt < maxlen && (ch = *inp++) != '\n'; ++cnt) + *outp++ = ch; + /* + * Check for short record without a newline. Reassemble the + * input block. + */ + if (ch != '\n' && in.dbcnt < cbsz) { + (void)memmove(in.db, in.dbp - in.dbcnt, in.dbcnt); + break; + } + + /* Adjust the input buffer numbers. */ + in.dbcnt -= cnt; + if (ch == '\n') + --in.dbcnt; + + /* Pad short records with spaces. */ + if (cnt < cbsz) + (void)memset(outp, ctab ? ctab[' '] : ' ', cbsz - cnt); + else { + /* + * If the next character wouldn't have ended the + * block, it's a truncation. + */ + if (!in.dbcnt || *inp != '\n') + ++st.trunc; + + /* Toss characters to a newline. */ + for (; in.dbcnt && *inp++ != '\n'; --in.dbcnt); + if (!in.dbcnt) + intrunc = 1; + else + --in.dbcnt; + } + + /* Adjust output buffer numbers. */ + out.dbp += cbsz; + if ((out.dbcnt += cbsz) >= out.dbsz) + dd_out(0); + outp = out.dbp; + } + in.dbp = in.db + in.dbcnt; +} + +void +block_close(void) +{ + + /* + * Copy any remaining data into the output buffer and pad to a record. + * Don't worry about truncation or translation, the input buffer is + * always empty when truncating, and no characters have been added for + * translation. The bottom line is that anything left in the input + * buffer is a truncated record. Anything left in the output buffer + * just wasn't big enough. + */ + if (in.dbcnt) { + ++st.trunc; + (void)memmove(out.dbp, in.dbp - in.dbcnt, in.dbcnt); + (void)memset(out.dbp + in.dbcnt, + ctab ? ctab[' '] : ' ', cbsz - in.dbcnt); + out.dbcnt += cbsz; + } +} + +/* + * Convert fixed length (cbsz) records to variable length. Deletes any + * trailing blanks and appends a newline. + * + * max in buffer: MAX(ibs, cbsz) + cbsz + * max out buffer: obs + cbsz + */ +void +unblock(void) +{ + uint64_t cnt; + u_char *inp; + const u_char *t; + + /* Translation and case conversion. */ + if ((t = ctab) != NULL) + for (cnt = in.dbrcnt, inp = in.dbp - 1; cnt--; inp--) + *inp = t[*inp]; + /* + * Copy records (max cbsz size chunks) into the output buffer. The + * translation has to already be done or we might not recognize the + * spaces. + */ + for (inp = in.db; in.dbcnt >= cbsz; inp += cbsz, in.dbcnt -= cbsz) { + for (t = inp + cbsz - 1; t >= inp && *t == ' '; --t); + if (t >= inp) { + cnt = t - inp + 1; + (void)memmove(out.dbp, inp, cnt); + out.dbp += cnt; + out.dbcnt += cnt; + } + ++out.dbcnt; + *out.dbp++ = '\n'; + if (out.dbcnt >= out.dbsz) + dd_out(0); + } + if (in.dbcnt) + (void)memmove(in.db, in.dbp - in.dbcnt, in.dbcnt); + in.dbp = in.db + in.dbcnt; +} + +void +unblock_close(void) +{ + uint64_t cnt; + u_char *t; + + if (in.dbcnt) { + warnx("%s: short input record", in.name); + for (t = in.db + in.dbcnt - 1; t >= in.db && *t == ' '; --t); + if (t >= in.db) { + cnt = t - in.db + 1; + (void)memmove(out.dbp, in.db, cnt); + out.dbp += cnt; + out.dbcnt += cnt; + } + ++out.dbcnt; + *out.dbp++ = '\n'; + } +} + +#endif /* NO_CONV */ diff --git a/toolbox/upstream-netbsd/bin/dd/dd.c b/toolbox/upstream-netbsd/bin/dd/dd.c new file mode 100644 index 0000000..03d080c --- /dev/null +++ b/toolbox/upstream-netbsd/bin/dd/dd.c @@ -0,0 +1,598 @@ +/* $NetBSD: dd.c,v 1.49 2012/02/21 01:49:01 matt Exp $ */ + +/*- + * Copyright (c) 1991, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Keith Muller of the University of California, San Diego and Lance + * Visser of Convex Computer Corporation. + * + * 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. + */ + +#include <sys/cdefs.h> +#ifndef lint +__COPYRIGHT("@(#) Copyright (c) 1991, 1993, 1994\ + The Regents of the University of California. All rights reserved."); +#endif /* not lint */ + +#ifndef lint +#if 0 +static char sccsid[] = "@(#)dd.c 8.5 (Berkeley) 4/2/94"; +#else +__RCSID("$NetBSD: dd.c,v 1.49 2012/02/21 01:49:01 matt Exp $"); +#endif +#endif /* not lint */ + +#include <sys/param.h> +#include <sys/stat.h> +#include <sys/ioctl.h> +#include <sys/mtio.h> +#include <sys/time.h> + +#include <ctype.h> +#include <err.h> +#include <errno.h> +#include <fcntl.h> +#include <locale.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include "dd.h" +#include "extern.h" + +static void dd_close(void); +static void dd_in(void); +static void getfdtype(IO *); +static void redup_clean_fd(IO *); +static void setup(void); + +int main(int, char *[]); + +IO in, out; /* input/output state */ +STAT st; /* statistics */ +void (*cfunc)(void); /* conversion function */ +uint64_t cpy_cnt; /* # of blocks to copy */ +static off_t pending = 0; /* pending seek if sparse */ +u_int ddflags; /* conversion options */ +uint64_t cbsz; /* conversion block size */ +u_int files_cnt = 1; /* # of files to copy */ +uint64_t progress = 0; /* display sign of life */ +const u_char *ctab; /* conversion table */ +sigset_t infoset; /* a set blocking SIGINFO */ +const char *msgfmt = "posix"; /* default summary() message format */ + +/* + * Ops for stdin/stdout and crunch'd dd. These are always host ops. + */ +static const struct ddfops ddfops_stdfd = { + .op_open = open, + .op_close = close, + .op_fcntl = fcntl, + .op_ioctl = ioctl, + .op_fstat = fstat, + .op_fsync = fsync, + .op_ftruncate = ftruncate, + .op_lseek = lseek, + .op_read = read, + .op_write = write, +}; +extern const struct ddfops ddfops_prog; + +int +main(int argc, char *argv[]) +{ + int ch; + + setprogname(argv[0]); + (void)setlocale(LC_ALL, ""); + + while ((ch = getopt(argc, argv, "")) != -1) { + switch (ch) { + default: + errx(EXIT_FAILURE, "usage: dd [operand ...]"); + /* NOTREACHED */ + } + } + argc -= (optind - 1); + argv += (optind - 1); + + jcl(argv); +#ifndef CRUNCHOPS + if (ddfops_prog.op_init && ddfops_prog.op_init() == -1) + err(1, "prog init"); +#endif + setup(); + + (void)signal(SIGINFO, summaryx); + (void)signal(SIGINT, terminate); + (void)sigemptyset(&infoset); + (void)sigaddset(&infoset, SIGINFO); + + (void)atexit(summary); + + while (files_cnt--) + dd_in(); + + dd_close(); + exit(0); + /* NOTREACHED */ +} + +static void +setup(void) +{ +#ifdef CRUNCHOPS + const struct ddfops *prog_ops = &ddfops_stdfd; +#else + const struct ddfops *prog_ops = &ddfops_prog; +#endif + + if (in.name == NULL) { + in.name = "stdin"; + in.fd = STDIN_FILENO; + in.ops = &ddfops_stdfd; + } else { + in.ops = prog_ops; + in.fd = ddop_open(in, in.name, O_RDONLY, 0); + if (in.fd < 0) + err(EXIT_FAILURE, "%s", in.name); + /* NOTREACHED */ + + /* Ensure in.fd is outside the stdio descriptor range */ + redup_clean_fd(&in); + } + + getfdtype(&in); + + if (files_cnt > 1 && !(in.flags & ISTAPE)) { + errx(EXIT_FAILURE, "files is not supported for non-tape devices"); + /* NOTREACHED */ + } + + if (out.name == NULL) { + /* No way to check for read access here. */ + out.fd = STDOUT_FILENO; + out.name = "stdout"; + out.ops = &ddfops_stdfd; + } else { + out.ops = prog_ops; +#define OFLAGS \ + (O_CREAT | (ddflags & (C_SEEK | C_NOTRUNC) ? 0 : O_TRUNC)) + out.fd = ddop_open(out, out.name, O_RDWR | OFLAGS, DEFFILEMODE); + /* + * May not have read access, so try again with write only. + * Without read we may have a problem if output also does + * not support seeks. + */ + if (out.fd < 0) { + out.fd = ddop_open(out, out.name, O_WRONLY | OFLAGS, + DEFFILEMODE); + out.flags |= NOREAD; + } + if (out.fd < 0) { + err(EXIT_FAILURE, "%s", out.name); + /* NOTREACHED */ + } + + /* Ensure out.fd is outside the stdio descriptor range */ + redup_clean_fd(&out); + } + + getfdtype(&out); + + /* + * Allocate space for the input and output buffers. If not doing + * record oriented I/O, only need a single buffer. + */ + if (!(ddflags & (C_BLOCK|C_UNBLOCK))) { + size_t dbsz = out.dbsz; + if (!(ddflags & C_BS)) + dbsz += in.dbsz - 1; + if ((in.db = malloc(dbsz)) == NULL) { + err(EXIT_FAILURE, NULL); + /* NOTREACHED */ + } + out.db = in.db; + } else if ((in.db = + malloc((u_int)(MAX(in.dbsz, cbsz) + cbsz))) == NULL || + (out.db = malloc((u_int)(out.dbsz + cbsz))) == NULL) { + err(EXIT_FAILURE, NULL); + /* NOTREACHED */ + } + in.dbp = in.db; + out.dbp = out.db; + + /* Position the input/output streams. */ + if (in.offset) + pos_in(); + if (out.offset) + pos_out(); + + /* + * Truncate the output file; ignore errors because it fails on some + * kinds of output files, tapes, for example. + */ + if ((ddflags & (C_OF | C_SEEK | C_NOTRUNC)) == (C_OF | C_SEEK)) + (void)ddop_ftruncate(out, out.fd, (off_t)out.offset * out.dbsz); + + /* + * If converting case at the same time as another conversion, build a + * table that does both at once. If just converting case, use the + * built-in tables. + */ + if (ddflags & (C_LCASE|C_UCASE)) { +#ifdef NO_CONV + /* Should not get here, but just in case... */ + errx(EXIT_FAILURE, "case conv and -DNO_CONV"); + /* NOTREACHED */ +#else /* NO_CONV */ + u_int cnt; + + if (ddflags & C_ASCII || ddflags & C_EBCDIC) { + if (ddflags & C_LCASE) { + for (cnt = 0; cnt < 256; ++cnt) + casetab[cnt] = tolower(ctab[cnt]); + } else { + for (cnt = 0; cnt < 256; ++cnt) + casetab[cnt] = toupper(ctab[cnt]); + } + } else { + if (ddflags & C_LCASE) { + for (cnt = 0; cnt < 256; ++cnt) + casetab[cnt] = tolower(cnt); + } else { + for (cnt = 0; cnt < 256; ++cnt) + casetab[cnt] = toupper(cnt); + } + } + + ctab = casetab; +#endif /* NO_CONV */ + } + + (void)gettimeofday(&st.start, NULL); /* Statistics timestamp. */ +} + +static void +getfdtype(IO *io) +{ + struct mtget mt; + struct stat sb; + + if (io->ops->op_fstat(io->fd, &sb)) { + err(EXIT_FAILURE, "%s", io->name); + /* NOTREACHED */ + } + if (S_ISCHR(sb.st_mode)) + io->flags |= io->ops->op_ioctl(io->fd, MTIOCGET, &mt) + ? ISCHR : ISTAPE; + else if (io->ops->op_lseek(io->fd, (off_t)0, SEEK_CUR) == -1 + && errno == ESPIPE) + io->flags |= ISPIPE; /* XXX fixed in 4.4BSD */ +} + +/* + * Move the parameter file descriptor to a descriptor that is outside the + * stdio descriptor range, if necessary. This is required to avoid + * accidentally outputting completion or error messages into the + * output file that were intended for the tty. + */ +static void +redup_clean_fd(IO *io) +{ + int fd = io->fd; + int newfd; + + if (fd != STDIN_FILENO && fd != STDOUT_FILENO && + fd != STDERR_FILENO) + /* File descriptor is ok, return immediately. */ + return; + + /* + * 3 is the first descriptor greater than STD*_FILENO. Any + * free descriptor valued 3 or above is acceptable... + */ + newfd = io->ops->op_fcntl(fd, F_DUPFD, 3); + if (newfd < 0) { + err(EXIT_FAILURE, "dupfd IO"); + /* NOTREACHED */ + } + + io->ops->op_close(fd); + io->fd = newfd; +} + +static void +dd_in(void) +{ + int flags; + int64_t n; + + for (flags = ddflags;;) { + if (cpy_cnt && (st.in_full + st.in_part) >= cpy_cnt) + return; + + /* + * Clear the buffer first if doing "sync" on input. + * If doing block operations use spaces. This will + * affect not only the C_NOERROR case, but also the + * last partial input block which should be padded + * with zero and not garbage. + */ + if (flags & C_SYNC) { + if (flags & (C_BLOCK|C_UNBLOCK)) + (void)memset(in.dbp, ' ', in.dbsz); + else + (void)memset(in.dbp, 0, in.dbsz); + } + + n = ddop_read(in, in.fd, in.dbp, in.dbsz); + if (n == 0) { + in.dbrcnt = 0; + return; + } + + /* Read error. */ + if (n < 0) { + + /* + * If noerror not specified, die. POSIX requires that + * the warning message be followed by an I/O display. + */ + if (!(flags & C_NOERROR)) { + err(EXIT_FAILURE, "%s", in.name); + /* NOTREACHED */ + } + warn("%s", in.name); + summary(); + + /* + * If it's not a tape drive or a pipe, seek past the + * error. If your OS doesn't do the right thing for + * raw disks this section should be modified to re-read + * in sector size chunks. + */ + if (!(in.flags & (ISPIPE|ISTAPE)) && + ddop_lseek(in, in.fd, (off_t)in.dbsz, SEEK_CUR)) + warn("%s", in.name); + + /* If sync not specified, omit block and continue. */ + if (!(ddflags & C_SYNC)) + continue; + + /* Read errors count as full blocks. */ + in.dbcnt += in.dbrcnt = in.dbsz; + ++st.in_full; + + /* Handle full input blocks. */ + } else if ((uint64_t)n == in.dbsz) { + in.dbcnt += in.dbrcnt = n; + ++st.in_full; + + /* Handle partial input blocks. */ + } else { + /* If sync, use the entire block. */ + if (ddflags & C_SYNC) + in.dbcnt += in.dbrcnt = in.dbsz; + else + in.dbcnt += in.dbrcnt = n; + ++st.in_part; + } + + /* + * POSIX states that if bs is set and no other conversions + * than noerror, notrunc or sync are specified, the block + * is output without buffering as it is read. + */ + if (ddflags & C_BS) { + out.dbcnt = in.dbcnt; + dd_out(1); + in.dbcnt = 0; + continue; + } + + if (ddflags & C_SWAB) { + if ((n = in.dbrcnt) & 1) { + ++st.swab; + --n; + } + swab(in.dbp, in.dbp, n); + } + + in.dbp += in.dbrcnt; + (*cfunc)(); + } +} + +/* + * Cleanup any remaining I/O and flush output. If necessary, output file + * is truncated. + */ +static void +dd_close(void) +{ + + if (cfunc == def) + def_close(); + else if (cfunc == block) + block_close(); + else if (cfunc == unblock) + unblock_close(); + if (ddflags & C_OSYNC && out.dbcnt < out.dbsz) { + (void)memset(out.dbp, 0, out.dbsz - out.dbcnt); + out.dbcnt = out.dbsz; + } + /* If there are pending sparse blocks, make sure + * to write out the final block un-sparse + */ + if ((out.dbcnt == 0) && pending) { + memset(out.db, 0, out.dbsz); + out.dbcnt = out.dbsz; + out.dbp = out.db + out.dbcnt; + pending -= out.dbsz; + } + if (out.dbcnt) + dd_out(1); + + /* + * Reporting nfs write error may be deferred until next + * write(2) or close(2) system call. So, we need to do an + * extra check. If an output is stdout, the file structure + * may be shared with other processes and close(2) just + * decreases the reference count. + */ + if (out.fd == STDOUT_FILENO && ddop_fsync(out, out.fd) == -1 + && errno != EINVAL) { + err(EXIT_FAILURE, "fsync stdout"); + /* NOTREACHED */ + } + if (ddop_close(out, out.fd) == -1) { + err(EXIT_FAILURE, "close"); + /* NOTREACHED */ + } +} + +void +dd_out(int force) +{ + static int warned; + int64_t cnt, n, nw; + u_char *outp; + + /* + * Write one or more blocks out. The common case is writing a full + * output block in a single write; increment the full block stats. + * Otherwise, we're into partial block writes. If a partial write, + * and it's a character device, just warn. If a tape device, quit. + * + * The partial writes represent two cases. 1: Where the input block + * was less than expected so the output block was less than expected. + * 2: Where the input block was the right size but we were forced to + * write the block in multiple chunks. The original versions of dd(1) + * never wrote a block in more than a single write, so the latter case + * never happened. + * + * One special case is if we're forced to do the write -- in that case + * we play games with the buffer size, and it's usually a partial write. + */ + outp = out.db; + for (n = force ? out.dbcnt : out.dbsz;; n = out.dbsz) { + for (cnt = n;; cnt -= nw) { + + if (!force && ddflags & C_SPARSE) { + int sparse, i; + sparse = 1; /* Is buffer sparse? */ + for (i = 0; i < cnt; i++) + if (outp[i] != 0) { + sparse = 0; + break; + } + if (sparse) { + pending += cnt; + outp += cnt; + nw = 0; + break; + } + } + if (pending != 0) { + if (ddop_lseek(out, + out.fd, pending, SEEK_CUR) == -1) + err(EXIT_FAILURE, "%s: seek error creating sparse file", + out.name); + } + nw = bwrite(&out, outp, cnt); + if (nw <= 0) { + if (nw == 0) + errx(EXIT_FAILURE, + "%s: end of device", out.name); + /* NOTREACHED */ + if (errno != EINTR) + err(EXIT_FAILURE, "%s", out.name); + /* NOTREACHED */ + nw = 0; + } + if (pending) { + st.bytes += pending; + st.sparse += pending/out.dbsz; + st.out_full += pending/out.dbsz; + pending = 0; + } + outp += nw; + st.bytes += nw; + if (nw == n) { + if ((uint64_t)n != out.dbsz) + ++st.out_part; + else + ++st.out_full; + break; + } + ++st.out_part; + if (nw == cnt) + break; + if (out.flags & ISCHR && !warned) { + warned = 1; + warnx("%s: short write on character device", out.name); + } + if (out.flags & ISTAPE) + errx(EXIT_FAILURE, + "%s: short write on tape device", out.name); + /* NOTREACHED */ + + } + if ((out.dbcnt -= n) < out.dbsz) + break; + } + + /* Reassemble the output block. */ + if (out.dbcnt) + (void)memmove(out.db, out.dbp - out.dbcnt, out.dbcnt); + out.dbp = out.db + out.dbcnt; + + if (progress && (st.out_full + st.out_part) % progress == 0) + (void)write(STDERR_FILENO, ".", 1); +} + +/* + * A protected against SIGINFO write + */ +ssize_t +bwrite(IO *io, const void *buf, size_t len) +{ + sigset_t oset; + ssize_t rv; + int oerrno; + + (void)sigprocmask(SIG_BLOCK, &infoset, &oset); + rv = io->ops->op_write(io->fd, buf, len); + oerrno = errno; + (void)sigprocmask(SIG_SETMASK, &oset, NULL); + errno = oerrno; + return (rv); +} diff --git a/toolbox/upstream-netbsd/bin/dd/dd.h b/toolbox/upstream-netbsd/bin/dd/dd.h new file mode 100644 index 0000000..b01c7b3 --- /dev/null +++ b/toolbox/upstream-netbsd/bin/dd/dd.h @@ -0,0 +1,127 @@ +/* $NetBSD: dd.h,v 1.15 2011/02/04 19:42:12 pooka Exp $ */ + +/*- + * Copyright (c) 1991, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Keith Muller of the University of California, San Diego and Lance + * Visser of Convex Computer Corporation. + * + * 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. + * + * @(#)dd.h 8.3 (Berkeley) 4/2/94 + */ + +#include <sys/stat.h> + +struct ddfops { + int (*op_init)(void); + + int (*op_open)(const char *, int, ...); + int (*op_close)(int); + + int (*op_fcntl)(int, int, ...); +#ifdef __ANDROID__ + int (*op_ioctl)(int, int, ...); +#else + int (*op_ioctl)(int, unsigned long, ...); +#endif + + int (*op_fstat)(int, struct stat *); + int (*op_fsync)(int); + int (*op_ftruncate)(int, off_t); + + off_t (*op_lseek)(int, off_t, int); + + ssize_t (*op_read)(int, void *, size_t); + ssize_t (*op_write)(int, const void *, size_t); +}; + +#define ddop_open(dir, a1, a2, ...) dir.ops->op_open(a1, a2, __VA_ARGS__) +#define ddop_close(dir, a1) dir.ops->op_close(a1) +#define ddop_fcntl(dir, a1, a2, ...) dir.ops->op_fcntl(a1, a2, __VA_ARGS__) +#define ddop_ioctl(dir, a1, a2, ...) dir.ops->op_ioctl(a1, a2, __VA_ARGS__) +#define ddop_fsync(dir, a1) dir.ops->op_fsync(a1) +#define ddop_ftruncate(dir, a1, a2) dir.ops->op_ftruncate(a1, a2) +#define ddop_lseek(dir, a1, a2, a3) dir.ops->op_lseek(a1, a2, a3) +#define ddop_read(dir, a1, a2, a3) dir.ops->op_read(a1, a2, a3) +#define ddop_write(dir, a1, a2, a3) dir.ops->op_write(a1, a2, a3) + +/* Input/output stream state. */ +typedef struct { + u_char *db; /* buffer address */ + u_char *dbp; /* current buffer I/O address */ + uint64_t dbcnt; /* current buffer byte count */ + int64_t dbrcnt; /* last read byte count */ + uint64_t dbsz; /* buffer size */ + +#define ISCHR 0x01 /* character device (warn on short) */ +#define ISPIPE 0x02 /* pipe (not truncatable) */ +#define ISTAPE 0x04 /* tape (not seekable) */ +#define NOREAD 0x08 /* not readable */ + u_int flags; + + const char *name; /* name */ + int fd; /* file descriptor */ + uint64_t offset; /* # of blocks to skip */ + struct ddfops const *ops; /* ops to use with fd */ +} IO; + +typedef struct { + uint64_t in_full; /* # of full input blocks */ + uint64_t in_part; /* # of partial input blocks */ + uint64_t out_full; /* # of full output blocks */ + uint64_t out_part; /* # of partial output blocks */ + uint64_t trunc; /* # of truncated records */ + uint64_t swab; /* # of odd-length swab blocks */ + uint64_t sparse; /* # of sparse output blocks */ + uint64_t bytes; /* # of bytes written */ + struct timeval start; /* start time of dd */ +} STAT; + +/* Flags (in ddflags). */ +#define C_ASCII 0x00001 +#define C_BLOCK 0x00002 +#define C_BS 0x00004 +#define C_CBS 0x00008 +#define C_COUNT 0x00010 +#define C_EBCDIC 0x00020 +#define C_FILES 0x00040 +#define C_IBS 0x00080 +#define C_IF 0x00100 +#define C_LCASE 0x00200 +#define C_NOERROR 0x00400 +#define C_NOTRUNC 0x00800 +#define C_OBS 0x01000 +#define C_OF 0x02000 +#define C_SEEK 0x04000 +#define C_SKIP 0x08000 +#define C_SWAB 0x10000 +#define C_SYNC 0x20000 +#define C_UCASE 0x40000 +#define C_UNBLOCK 0x80000 +#define C_OSYNC 0x100000 +#define C_SPARSE 0x200000 diff --git a/toolbox/upstream-netbsd/bin/dd/dd_hostops.c b/toolbox/upstream-netbsd/bin/dd/dd_hostops.c new file mode 100644 index 0000000..d6e7a89 --- /dev/null +++ b/toolbox/upstream-netbsd/bin/dd/dd_hostops.c @@ -0,0 +1,53 @@ +/* $NetBSD: dd_hostops.c,v 1.1 2011/02/04 19:42:12 pooka Exp $ */ + +/*- + * Copyright (c) 2010 The NetBSD Foundation, Inc. + * All rights reserved. + * + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. 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 FOUNDATION 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. + */ + +#include <sys/cdefs.h> +#ifndef lint +__RCSID("$NetBSD: dd_hostops.c,v 1.1 2011/02/04 19:42:12 pooka Exp $"); +#endif /* !lint */ + +#include <sys/types.h> +#include <sys/ioctl.h> + +#include <fcntl.h> +#include <unistd.h> + +#include "dd.h" + +const struct ddfops ddfops_prog = { + .op_open = open, + .op_close = close, + .op_fcntl = fcntl, + .op_ioctl = ioctl, + .op_fstat = fstat, + .op_fsync = fsync, + .op_ftruncate = ftruncate, + .op_lseek = lseek, + .op_read = read, + .op_write = write, +}; diff --git a/toolbox/upstream-netbsd/bin/dd/extern.h b/toolbox/upstream-netbsd/bin/dd/extern.h new file mode 100644 index 0000000..9c59021 --- /dev/null +++ b/toolbox/upstream-netbsd/bin/dd/extern.h @@ -0,0 +1,82 @@ +/* $NetBSD: extern.h,v 1.22 2011/11/07 22:24:23 jym Exp $ */ + +/*- + * Copyright (c) 1991, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Keith Muller of the University of California, San Diego and Lance + * Visser of Convex Computer Corporation. + * + * 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. + * + * @(#)extern.h 8.3 (Berkeley) 4/2/94 + */ + +#include <sys/cdefs.h> + +#ifdef NO_CONV +__dead void block(void); +__dead void block_close(void); +__dead void unblock(void); +__dead void unblock_close(void); +#else +void block(void); +void block_close(void); +void unblock(void); +void unblock_close(void); +#endif + +#ifndef NO_MSGFMT +int dd_write_msg(const char *, int); +#endif + +void dd_out(int); +void def(void); +void def_close(void); +void jcl(char **); +void pos_in(void); +void pos_out(void); +void summary(void); +void summaryx(int); +__dead void terminate(int); +void unblock(void); +void unblock_close(void); +ssize_t bwrite(IO *, const void *, size_t); + +extern IO in, out; +extern STAT st; +extern void (*cfunc)(void); +extern uint64_t cpy_cnt; +extern uint64_t cbsz; +extern u_int ddflags; +extern u_int files_cnt; +extern uint64_t progress; +extern const u_char *ctab; +extern const u_char a2e_32V[], a2e_POSIX[]; +extern const u_char e2a_32V[], e2a_POSIX[]; +extern const u_char a2ibm_32V[], a2ibm_POSIX[]; +extern u_char casetab[]; +extern const char *msgfmt; diff --git a/toolbox/upstream-netbsd/bin/dd/misc.c b/toolbox/upstream-netbsd/bin/dd/misc.c new file mode 100644 index 0000000..0fac98b --- /dev/null +++ b/toolbox/upstream-netbsd/bin/dd/misc.c @@ -0,0 +1,342 @@ +/* $NetBSD: misc.c,v 1.23 2011/11/07 22:24:23 jym Exp $ */ + +/*- + * Copyright (c) 1991, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Keith Muller of the University of California, San Diego and Lance + * Visser of Convex Computer Corporation. + * + * 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. + */ + +#include <sys/cdefs.h> +#ifndef lint +#if 0 +static char sccsid[] = "@(#)misc.c 8.3 (Berkeley) 4/2/94"; +#else +__RCSID("$NetBSD: misc.c,v 1.23 2011/11/07 22:24:23 jym Exp $"); +#endif +#endif /* not lint */ + +#include <sys/param.h> +#include <sys/types.h> +#include <sys/time.h> + +#include <err.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <util.h> +#include <inttypes.h> + +#include "dd.h" +#include "extern.h" + +#define tv2mS(tv) ((tv).tv_sec * 1000LL + ((tv).tv_usec + 500) / 1000) + +static void posix_summary(void); +#ifndef NO_MSGFMT +static void custom_summary(void); +static void human_summary(void); +static void quiet_summary(void); + +static void buffer_write(const char *, size_t, int); +#endif /* NO_MSGFMT */ + +void +summary(void) +{ + + if (progress) + (void)write(STDERR_FILENO, "\n", 1); + +#ifdef NO_MSGFMT + return posix_summary(); +#else /* NO_MSGFMT */ + if (strncmp(msgfmt, "human", sizeof("human")) == 0) + return human_summary(); + + if (strncmp(msgfmt, "posix", sizeof("posix")) == 0) + return posix_summary(); + + if (strncmp(msgfmt, "quiet", sizeof("quiet")) == 0) + return quiet_summary(); + + return custom_summary(); +#endif /* NO_MSGFMT */ +} + +static void +posix_summary(void) +{ + char buf[100]; + int64_t mS; + struct timeval tv; + + if (progress) + (void)write(STDERR_FILENO, "\n", 1); + + (void)gettimeofday(&tv, NULL); + mS = tv2mS(tv) - tv2mS(st.start); + if (mS == 0) + mS = 1; + + /* Use snprintf(3) so that we don't reenter stdio(3). */ + (void)snprintf(buf, sizeof(buf), + "%llu+%llu records in\n%llu+%llu records out\n", + (unsigned long long)st.in_full, (unsigned long long)st.in_part, + (unsigned long long)st.out_full, (unsigned long long)st.out_part); + (void)write(STDERR_FILENO, buf, strlen(buf)); + if (st.swab) { + (void)snprintf(buf, sizeof(buf), "%llu odd length swab %s\n", + (unsigned long long)st.swab, + (st.swab == 1) ? "block" : "blocks"); + (void)write(STDERR_FILENO, buf, strlen(buf)); + } + if (st.trunc) { + (void)snprintf(buf, sizeof(buf), "%llu truncated %s\n", + (unsigned long long)st.trunc, + (st.trunc == 1) ? "block" : "blocks"); + (void)write(STDERR_FILENO, buf, strlen(buf)); + } + if (st.sparse) { + (void)snprintf(buf, sizeof(buf), "%llu sparse output %s\n", + (unsigned long long)st.sparse, + (st.sparse == 1) ? "block" : "blocks"); + (void)write(STDERR_FILENO, buf, strlen(buf)); + } + (void)snprintf(buf, sizeof(buf), + "%llu bytes transferred in %lu.%03d secs (%llu bytes/sec)\n", + (unsigned long long) st.bytes, + (long) (mS / 1000), + (int) (mS % 1000), + (unsigned long long) (st.bytes * 1000LL / mS)); + (void)write(STDERR_FILENO, buf, strlen(buf)); +} + +/* ARGSUSED */ +void +summaryx(int notused) +{ + + summary(); +} + +/* ARGSUSED */ +void +terminate(int signo) +{ + + summary(); + (void)raise_default_signal(signo); + _exit(127); +} + +#ifndef NO_MSGFMT +/* + * Buffer write(2) calls + */ +static void +buffer_write(const char *str, size_t size, int flush) +{ + static char wbuf[128]; + static size_t cnt = 0; /* Internal counter to allow wbuf to wrap */ + + unsigned int i; + + for (i = 0; i < size; i++) { + if (str != NULL) { + wbuf[cnt++] = str[i]; + } + if (cnt >= sizeof(wbuf)) { + (void)write(STDERR_FILENO, wbuf, cnt); + cnt = 0; + } + } + + if (flush != 0) { + (void)write(STDERR_FILENO, wbuf, cnt); + cnt = 0; + } +} + +/* + * Write summary to stderr according to format 'fmt'. If 'enable' is 0, it + * will not attempt to write anything. Can be used to validate the + * correctness of the 'fmt' string. + */ +int +dd_write_msg(const char *fmt, int enable) +{ + char hbuf[7], nbuf[32]; + const char *ptr; + int64_t mS; + struct timeval tv; + + (void)gettimeofday(&tv, NULL); + mS = tv2mS(tv) - tv2mS(st.start); + if (mS == 0) + mS = 1; + +#define ADDC(c) do { if (enable != 0) buffer_write(&c, 1, 0); } \ + while (/*CONSTCOND*/0) +#define ADDS(p) do { if (enable != 0) buffer_write(p, strlen(p), 0); } \ + while (/*CONSTCOND*/0) + + for (ptr = fmt; *ptr; ptr++) { + if (*ptr != '%') { + ADDC(*ptr); + continue; + } + + switch (*++ptr) { + case 'b': + (void)snprintf(nbuf, sizeof(nbuf), "%llu", + (unsigned long long)st.bytes); + ADDS(nbuf); + break; + case 'B': + if (humanize_number(hbuf, sizeof(hbuf), + st.bytes, "B", + HN_AUTOSCALE, HN_DECIMAL) == -1) + warnx("humanize_number (bytes transferred)"); + ADDS(hbuf); + break; + case 'e': + (void)snprintf(nbuf, sizeof(nbuf), "%llu", + (unsigned long long) (st.bytes * 1000LL / mS)); + ADDS(nbuf); + break; + case 'E': + if (humanize_number(hbuf, sizeof(hbuf), + st.bytes * 1000LL / mS, "B", + HN_AUTOSCALE, HN_DECIMAL) == -1) + warnx("humanize_number (bytes per second)"); + ADDS(hbuf); ADDS("/sec"); + break; + case 'i': + (void)snprintf(nbuf, sizeof(nbuf), "%llu", + (unsigned long long)st.in_part); + ADDS(nbuf); + break; + case 'I': + (void)snprintf(nbuf, sizeof(nbuf), "%llu", + (unsigned long long)st.in_full); + ADDS(nbuf); + break; + case 'o': + (void)snprintf(nbuf, sizeof(nbuf), "%llu", + (unsigned long long)st.out_part); + ADDS(nbuf); + break; + case 'O': + (void)snprintf(nbuf, sizeof(nbuf), "%llu", + (unsigned long long)st.out_full); + ADDS(nbuf); + break; + case 's': + (void)snprintf(nbuf, sizeof(nbuf), "%li.%03d", + (long) (mS / 1000), (int) (mS % 1000)); + ADDS(nbuf); + break; + case 'p': + (void)snprintf(nbuf, sizeof(nbuf), "%llu", + (unsigned long long)st.sparse); + ADDS(nbuf); + break; + case 't': + (void)snprintf(nbuf, sizeof(nbuf), "%llu", + (unsigned long long)st.trunc); + ADDS(nbuf); + break; + case 'w': + (void)snprintf(nbuf, sizeof(nbuf), "%llu", + (unsigned long long)st.swab); + ADDS(nbuf); + break; + case 'P': + ADDS("block"); + if (st.sparse != 1) ADDS("s"); + break; + case 'T': + ADDS("block"); + if (st.trunc != 1) ADDS("s"); + break; + case 'W': + ADDS("block"); + if (st.swab != 1) ADDS("s"); + break; + case '%': + ADDC(*ptr); + break; + default: + if (*ptr == '\0') + goto done; + errx(EXIT_FAILURE, "unknown specifier '%c' in " + "msgfmt string", *ptr); + /* NOTREACHED */ + } + } + +done: + /* flush buffer */ + buffer_write(NULL, 0, 1); + return 0; +} + +static void +custom_summary(void) +{ + + dd_write_msg(msgfmt, 1); +} + +static void +human_summary(void) +{ + (void)dd_write_msg("%I+%i records in\n%O+%o records out\n", 1); + if (st.swab) { + (void)dd_write_msg("%w odd length swab %W\n", 1); + } + if (st.trunc) { + (void)dd_write_msg("%t truncated %T\n", 1); + } + if (st.sparse) { + (void)dd_write_msg("%p sparse output %P\n", 1); + } + (void)dd_write_msg("%b bytes (%B) transferred in %s secs " + "(%e bytes/sec - %E)\n", 1); +} + +static void +quiet_summary(void) +{ + + /* stay quiet */ +} +#endif /* NO_MSGFMT */ diff --git a/toolbox/upstream-netbsd/bin/dd/position.c b/toolbox/upstream-netbsd/bin/dd/position.c new file mode 100644 index 0000000..36dd580 --- /dev/null +++ b/toolbox/upstream-netbsd/bin/dd/position.c @@ -0,0 +1,185 @@ +/* $NetBSD: position.c,v 1.18 2010/11/22 21:04:28 pooka Exp $ */ + +/*- + * Copyright (c) 1991, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Keith Muller of the University of California, San Diego and Lance + * Visser of Convex Computer Corporation. + * + * 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. + */ + +#include <sys/cdefs.h> +#ifndef lint +#if 0 +static char sccsid[] = "@(#)position.c 8.3 (Berkeley) 4/2/94"; +#else +__RCSID("$NetBSD: position.c,v 1.18 2010/11/22 21:04:28 pooka Exp $"); +#endif +#endif /* not lint */ + +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/ioctl.h> +#include <sys/mtio.h> +#include <sys/time.h> + +#include <err.h> +#include <errno.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include "dd.h" +#include "extern.h" + +/* + * Position input/output data streams before starting the copy. Device type + * dependent. Seekable devices use lseek, and the rest position by reading. + * Seeking past the end of file can cause null blocks to be written to the + * output. + */ +void +pos_in(void) +{ + int bcnt, cnt, nr, warned; + + /* If not a pipe or tape device, try to seek on it. */ + if (!(in.flags & (ISPIPE|ISTAPE))) { + if (ddop_lseek(in, in.fd, + (off_t)in.offset * (off_t)in.dbsz, SEEK_CUR) == -1) { + err(EXIT_FAILURE, "%s", in.name); + /* NOTREACHED */ + } + return; + /* NOTREACHED */ + } + + /* + * Read the data. If a pipe, read until satisfy the number of bytes + * being skipped. No differentiation for reading complete and partial + * blocks for other devices. + */ + for (bcnt = in.dbsz, cnt = in.offset, warned = 0; cnt;) { + if ((nr = ddop_read(in, in.fd, in.db, bcnt)) > 0) { + if (in.flags & ISPIPE) { + if (!(bcnt -= nr)) { + bcnt = in.dbsz; + --cnt; + } + } else + --cnt; + continue; + } + + if (nr == 0) { + if (files_cnt > 1) { + --files_cnt; + continue; + } + errx(EXIT_FAILURE, "skip reached end of input"); + /* NOTREACHED */ + } + + /* + * Input error -- either EOF with no more files, or I/O error. + * If noerror not set die. POSIX requires that the warning + * message be followed by an I/O display. + */ + if (ddflags & C_NOERROR) { + if (!warned) { + + warn("%s", in.name); + warned = 1; + summary(); + } + continue; + } + err(EXIT_FAILURE, "%s", in.name); + /* NOTREACHED */ + } +} + +void +pos_out(void) +{ + struct mtop t_op; + int n; + uint64_t cnt; + + /* + * If not a tape, try seeking on the file. Seeking on a pipe is + * going to fail, but don't protect the user -- they shouldn't + * have specified the seek operand. + */ + if (!(out.flags & ISTAPE)) { + if (ddop_lseek(out, out.fd, + (off_t)out.offset * (off_t)out.dbsz, SEEK_SET) == -1) + err(EXIT_FAILURE, "%s", out.name); + /* NOTREACHED */ + return; + } + + /* If no read access, try using mtio. */ + if (out.flags & NOREAD) { + t_op.mt_op = MTFSR; + t_op.mt_count = out.offset; + + if (ddop_ioctl(out, out.fd, MTIOCTOP, &t_op) < 0) + err(EXIT_FAILURE, "%s", out.name); + /* NOTREACHED */ + return; + } + + /* Read it. */ + for (cnt = 0; cnt < out.offset; ++cnt) { + if ((n = ddop_read(out, out.fd, out.db, out.dbsz)) > 0) + continue; + + if (n < 0) + err(EXIT_FAILURE, "%s", out.name); + /* NOTREACHED */ + + /* + * If reach EOF, fill with NUL characters; first, back up over + * the EOF mark. Note, cnt has not yet been incremented, so + * the EOF read does not count as a seek'd block. + */ + t_op.mt_op = MTBSR; + t_op.mt_count = 1; + if (ddop_ioctl(out, out.fd, MTIOCTOP, &t_op) == -1) + err(EXIT_FAILURE, "%s", out.name); + /* NOTREACHED */ + + while (cnt++ < out.offset) + if ((uint64_t)(n = bwrite(&out, + out.db, out.dbsz)) != out.dbsz) + err(EXIT_FAILURE, "%s", out.name); + /* NOTREACHED */ + break; + } +} diff --git a/toolbox/upstream-netbsd/bin/ln/ln.c b/toolbox/upstream-netbsd/bin/ln/ln.c new file mode 100644 index 0000000..9127477 --- /dev/null +++ b/toolbox/upstream-netbsd/bin/ln/ln.c @@ -0,0 +1,230 @@ +/* $NetBSD: ln.c,v 1.35 2011/08/29 14:38:30 joerg Exp $ */ + +/* + * Copyright (c) 1987, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * 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. + */ + +#include <sys/cdefs.h> +#ifndef lint +__COPYRIGHT("@(#) Copyright (c) 1987, 1993, 1994\ + The Regents of the University of California. All rights reserved."); +#endif /* not lint */ + +#ifndef lint +#if 0 +static char sccsid[] = "@(#)ln.c 8.2 (Berkeley) 3/31/94"; +#else +__RCSID("$NetBSD: ln.c,v 1.35 2011/08/29 14:38:30 joerg Exp $"); +#endif +#endif /* not lint */ + +#include <sys/param.h> +#include <sys/stat.h> + +#include <err.h> +#include <errno.h> +#include <locale.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +static int fflag; /* Unlink existing files. */ +static int hflag; /* Check new name for symlink first. */ +static int iflag; /* Interactive mode. */ +static int sflag; /* Symbolic, not hard, link. */ +static int vflag; /* Verbose output */ + + /* System link call. */ +static int (*linkf)(const char *, const char *); +static char linkch; + +static int linkit(const char *, const char *, int); +__dead static void usage(void); + +int +main(int argc, char *argv[]) +{ + struct stat sb; + int ch, exitval; + char *sourcedir; + + setprogname(argv[0]); + (void)setlocale(LC_ALL, ""); + + while ((ch = getopt(argc, argv, "fhinsv")) != -1) + switch (ch) { + case 'f': + fflag = 1; + iflag = 0; + break; + case 'h': + case 'n': + hflag = 1; + break; + case 'i': + iflag = 1; + fflag = 0; + break; + case 's': + sflag = 1; + break; + case 'v': + vflag = 1; + break; + case '?': + default: + usage(); + /* NOTREACHED */ + } + + argv += optind; + argc -= optind; + + if (sflag) { + linkf = symlink; + linkch = '-'; + } else { + linkf = link; + linkch = '='; + } + + switch(argc) { + case 0: + usage(); + /* NOTREACHED */ + case 1: /* ln target */ + exit(linkit(argv[0], ".", 1)); + /* NOTREACHED */ + case 2: /* ln target source */ + exit(linkit(argv[0], argv[1], 0)); + /* NOTREACHED */ + } + + /* ln target1 target2 directory */ + sourcedir = argv[argc - 1]; + if (hflag && lstat(sourcedir, &sb) == 0 && S_ISLNK(sb.st_mode)) { + /* we were asked not to follow symlinks, but found one at + the target--simulate "not a directory" error */ + errno = ENOTDIR; + err(EXIT_FAILURE, "%s", sourcedir); + /* NOTREACHED */ + } + if (stat(sourcedir, &sb)) { + err(EXIT_FAILURE, "%s", sourcedir); + /* NOTREACHED */ + } + if (!S_ISDIR(sb.st_mode)) { + usage(); + /* NOTREACHED */ + } + for (exitval = 0; *argv != sourcedir; ++argv) + exitval |= linkit(*argv, sourcedir, 1); + exit(exitval); + /* NOTREACHED */ +} + +static int +linkit(const char *target, const char *source, int isdir) +{ + struct stat sb; + const char *p; + char path[MAXPATHLEN]; + int ch, exists, first; + + if (!sflag) { + /* If target doesn't exist, quit now. */ + if (stat(target, &sb)) { + warn("%s", target); + return (1); + } + } + + /* If the source is a directory (and not a symlink if hflag), + append the target's name. */ + if (isdir || + (!lstat(source, &sb) && S_ISDIR(sb.st_mode)) || + (!hflag && !stat(source, &sb) && S_ISDIR(sb.st_mode))) { + if ((p = strrchr(target, '/')) == NULL) + p = target; + else + ++p; + (void)snprintf(path, sizeof(path), "%s/%s", source, p); + source = path; + } + + exists = !lstat(source, &sb); + + /* + * If the file exists, then unlink it forcibly if -f was specified + * and interactively if -i was specified. + */ + if (fflag && exists) { + if (unlink(source)) { + warn("%s", source); + return (1); + } + } else if (iflag && exists) { + fflush(stdout); + (void)fprintf(stderr, "replace %s? ", source); + + first = ch = getchar(); + while (ch != '\n' && ch != EOF) + ch = getchar(); + if (first != 'y' && first != 'Y') { + (void)fprintf(stderr, "not replaced\n"); + return (1); + } + + if (unlink(source)) { + warn("%s", source); + return (1); + } + } + + /* Attempt the link. */ + if ((*linkf)(target, source)) { + warn("%s", source); + return (1); + } + if (vflag) + (void)printf("%s %c> %s\n", source, linkch, target); + + return (0); +} + +static void +usage(void) +{ + + (void)fprintf(stderr, + "usage:\t%s [-fhinsv] file1 file2\n\t%s [-fhinsv] file ... directory\n", + getprogname(), getprogname()); + exit(1); + /* NOTREACHED */ +} diff --git a/toolbox/upstream-netbsd/bin/mv/mv.c b/toolbox/upstream-netbsd/bin/mv/mv.c new file mode 100644 index 0000000..4be6c30 --- /dev/null +++ b/toolbox/upstream-netbsd/bin/mv/mv.c @@ -0,0 +1,396 @@ +/* $NetBSD: mv.c,v 1.43 2011/08/29 14:46:54 joerg Exp $ */ + +/* + * Copyright (c) 1989, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Ken Smith of The State University of New York at Buffalo. + * + * 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. + */ + +#include <sys/cdefs.h> +#ifndef lint +__COPYRIGHT("@(#) Copyright (c) 1989, 1993, 1994\ + The Regents of the University of California. All rights reserved."); +#endif /* not lint */ + +#ifndef lint +#if 0 +static char sccsid[] = "@(#)mv.c 8.2 (Berkeley) 4/2/94"; +#else +__RCSID("$NetBSD: mv.c,v 1.43 2011/08/29 14:46:54 joerg Exp $"); +#endif +#endif /* not lint */ + +#include <sys/param.h> +#include <sys/time.h> +#include <sys/wait.h> +#include <sys/stat.h> +#include <sys/extattr.h> + +#include <err.h> +#include <errno.h> +#include <fcntl.h> +#include <grp.h> +#include <locale.h> +#include <pwd.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include "pathnames.h" + +static int fflg, iflg, vflg; +static int stdin_ok; + +static int copy(char *, char *); +static int do_move(char *, char *); +static int fastcopy(char *, char *, struct stat *); +__dead static void usage(void); + +int +main(int argc, char *argv[]) +{ + int ch, len, rval; + char *p, *endp; + struct stat sb; + char path[MAXPATHLEN + 1]; + size_t baselen; + + setprogname(argv[0]); + (void)setlocale(LC_ALL, ""); + + while ((ch = getopt(argc, argv, "ifv")) != -1) + switch (ch) { + case 'i': + fflg = 0; + iflg = 1; + break; + case 'f': + iflg = 0; + fflg = 1; + break; + case 'v': + vflg = 1; + break; + default: + usage(); + } + argc -= optind; + argv += optind; + + if (argc < 2) + usage(); + + stdin_ok = isatty(STDIN_FILENO); + + /* + * If the stat on the target fails or the target isn't a directory, + * try the move. More than 2 arguments is an error in this case. + */ + if (stat(argv[argc - 1], &sb) || !S_ISDIR(sb.st_mode)) { + if (argc > 2) + usage(); + exit(do_move(argv[0], argv[1])); + } + + /* It's a directory, move each file into it. */ + baselen = strlcpy(path, argv[argc - 1], sizeof(path)); + if (baselen >= sizeof(path)) + errx(1, "%s: destination pathname too long", argv[argc - 1]); + endp = &path[baselen]; + if (!baselen || *(endp - 1) != '/') { + *endp++ = '/'; + ++baselen; + } + for (rval = 0; --argc; ++argv) { + p = *argv + strlen(*argv) - 1; + while (*p == '/' && p != *argv) + *p-- = '\0'; + if ((p = strrchr(*argv, '/')) == NULL) + p = *argv; + else + ++p; + + if ((baselen + (len = strlen(p))) >= MAXPATHLEN) { + warnx("%s: destination pathname too long", *argv); + rval = 1; + } else { + memmove(endp, p, len + 1); + if (do_move(*argv, path)) + rval = 1; + } + } + exit(rval); + /* NOTREACHED */ +} + +static int +do_move(char *from, char *to) +{ + struct stat sb; + char modep[15]; + + /* + * (1) If the destination path exists, the -f option is not specified + * and either of the following conditions are true: + * + * (a) The permissions of the destination path do not permit + * writing and the standard input is a terminal. + * (b) The -i option is specified. + * + * the mv utility shall write a prompt to standard error and + * read a line from standard input. If the response is not + * affirmative, mv shall do nothing more with the current + * source file... + */ + if (!fflg && !access(to, F_OK)) { + int ask = 1; + int ch; + + if (iflg) { + if (access(from, F_OK)) { + warn("rename %s", from); + return (1); + } + (void)fprintf(stderr, "overwrite %s? ", to); + } else if (stdin_ok && access(to, W_OK) && !stat(to, &sb)) { + if (access(from, F_OK)) { + warn("rename %s", from); + return (1); + } + strmode(sb.st_mode, modep); + (void)fprintf(stderr, "override %s%s%s/%s for %s? ", + modep + 1, modep[9] == ' ' ? "" : " ", + user_from_uid(sb.st_uid, 0), + group_from_gid(sb.st_gid, 0), to); + } else + ask = 0; + if (ask) { + if ((ch = getchar()) != EOF && ch != '\n') { + int ch2; + while ((ch2 = getchar()) != EOF && ch2 != '\n') + continue; + } + if (ch != 'y' && ch != 'Y') + return (0); + } + } + + /* + * (2) If rename() succeeds, mv shall do nothing more with the + * current source file. If it fails for any other reason than + * EXDEV, mv shall write a diagnostic message to the standard + * error and do nothing more with the current source file. + * + * (3) If the destination path exists, and it is a file of type + * directory and source_file is not a file of type directory, + * or it is a file not of type directory, and source file is + * a file of type directory, mv shall write a diagnostic + * message to standard error, and do nothing more with the + * current source file... + */ + if (!rename(from, to)) { + if (vflg) + printf("%s -> %s\n", from, to); + return (0); + } + + if (errno != EXDEV) { + warn("rename %s to %s", from, to); + return (1); + } + + /* + * (4) If the destination path exists, mv shall attempt to remove it. + * If this fails for any reason, mv shall write a diagnostic + * message to the standard error and do nothing more with the + * current source file... + */ + if (!lstat(to, &sb)) { + if ((S_ISDIR(sb.st_mode)) ? rmdir(to) : unlink(to)) { + warn("can't remove %s", to); + return (1); + } + } + + /* + * (5) The file hierarchy rooted in source_file shall be duplicated + * as a file hierarchy rooted in the destination path... + */ + if (lstat(from, &sb)) { + warn("%s", from); + return (1); + } + + return (S_ISREG(sb.st_mode) ? + fastcopy(from, to, &sb) : copy(from, to)); +} + +static int +fastcopy(char *from, char *to, struct stat *sbp) +{ + struct timeval tval[2]; + static blksize_t blen; + static char *bp; + int nread, from_fd, to_fd; + + if ((from_fd = open(from, O_RDONLY, 0)) < 0) { + warn("%s", from); + return (1); + } + if ((to_fd = + open(to, O_CREAT | O_TRUNC | O_WRONLY, sbp->st_mode)) < 0) { + warn("%s", to); + (void)close(from_fd); + return (1); + } + if (!blen && !(bp = malloc(blen = sbp->st_blksize))) { + warn(NULL); + blen = 0; + (void)close(from_fd); + (void)close(to_fd); + return (1); + } + while ((nread = read(from_fd, bp, blen)) > 0) + if (write(to_fd, bp, nread) != nread) { + warn("%s", to); + goto err; + } + if (nread < 0) { + warn("%s", from); +err: if (unlink(to)) + warn("%s: remove", to); + (void)close(from_fd); + (void)close(to_fd); + return (1); + } + +#ifndef __ANDROID__ + if (fcpxattr(from_fd, to_fd) == -1) + warn("%s: error copying extended attributes", to); +#endif + + (void)close(from_fd); +#ifdef BSD4_4 + TIMESPEC_TO_TIMEVAL(&tval[0], &sbp->st_atimespec); + TIMESPEC_TO_TIMEVAL(&tval[1], &sbp->st_mtimespec); +#else + tval[0].tv_sec = sbp->st_atime; + tval[1].tv_sec = sbp->st_mtime; + tval[0].tv_usec = 0; + tval[1].tv_usec = 0; +#endif +#ifdef __SVR4 + if (utimes(to, tval)) +#else + if (futimes(to_fd, tval)) +#endif + warn("%s: set times", to); + if (fchown(to_fd, sbp->st_uid, sbp->st_gid)) { + if (errno != EPERM) + warn("%s: set owner/group", to); + sbp->st_mode &= ~(S_ISUID | S_ISGID); + } + if (fchmod(to_fd, sbp->st_mode)) + warn("%s: set mode", to); +#ifndef __ANDROID__ + if (fchflags(to_fd, sbp->st_flags) && (errno != EOPNOTSUPP)) + warn("%s: set flags (was: 0%07o)", to, sbp->st_flags); +#endif + + if (close(to_fd)) { + warn("%s", to); + return (1); + } + + if (unlink(from)) { + warn("%s: remove", from); + return (1); + } + + if (vflg) + printf("%s -> %s\n", from, to); + + return (0); +} + +static int +copy(char *from, char *to) +{ + pid_t pid; + int status; + + if ((pid = vfork()) == 0) { + execl(_PATH_CP, "mv", vflg ? "-PRpv" : "-PRp", "--", from, to, NULL); + warn("%s", _PATH_CP); + _exit(1); + } + if (waitpid(pid, &status, 0) == -1) { + warn("%s: waitpid", _PATH_CP); + return (1); + } + if (!WIFEXITED(status)) { + warnx("%s: did not terminate normally", _PATH_CP); + return (1); + } + if (WEXITSTATUS(status)) { + warnx("%s: terminated with %d (non-zero) status", + _PATH_CP, WEXITSTATUS(status)); + return (1); + } + if (!(pid = vfork())) { + execl(_PATH_RM, "mv", "-rf", "--", from, NULL); + warn("%s", _PATH_RM); + _exit(1); + } + if (waitpid(pid, &status, 0) == -1) { + warn("%s: waitpid", _PATH_RM); + return (1); + } + if (!WIFEXITED(status)) { + warnx("%s: did not terminate normally", _PATH_RM); + return (1); + } + if (WEXITSTATUS(status)) { + warnx("%s: terminated with %d (non-zero) status", + _PATH_RM, WEXITSTATUS(status)); + return (1); + } + return (0); +} + +static void +usage(void) +{ + (void)fprintf(stderr, "usage: %s [-fiv] source target\n" + " %s [-fiv] source ... directory\n", getprogname(), + getprogname()); + exit(1); + /* NOTREACHED */ +} diff --git a/toolbox/upstream-netbsd/bin/mv/pathnames.h b/toolbox/upstream-netbsd/bin/mv/pathnames.h new file mode 100644 index 0000000..7838946 --- /dev/null +++ b/toolbox/upstream-netbsd/bin/mv/pathnames.h @@ -0,0 +1,45 @@ +/* $NetBSD: pathnames.h,v 1.8 2004/08/19 22:26:07 christos Exp $ */ + +/* + * Copyright (c) 1989, 1993 + * The Regents of the University of California. All rights reserved. + * + * 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. + * + * @(#)pathnames.h 8.1 (Berkeley) 5/31/93 + */ + +#ifdef __ANDROID__ +#define _PATH_RM "/system/bin/rm" +#define _PATH_CP "/system/bin/cp" +#else +#ifdef RESCUEDIR +#define _PATH_RM RESCUEDIR "/rm" +#define _PATH_CP RESCUEDIR "/cp" +#else +#define _PATH_RM "/bin/rm" +#define _PATH_CP "/bin/cp" +#endif +#endif diff --git a/toolbox/upstream-netbsd/bin/rm/rm.c b/toolbox/upstream-netbsd/bin/rm/rm.c new file mode 100644 index 0000000..f183810 --- /dev/null +++ b/toolbox/upstream-netbsd/bin/rm/rm.c @@ -0,0 +1,625 @@ +/* $NetBSD: rm.c,v 1.53 2013/04/26 18:43:22 christos Exp $ */ + +/*- + * Copyright (c) 1990, 1993, 1994, 2003 + * The Regents of the University of California. All rights reserved. + * + * 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. + */ + +#include <sys/cdefs.h> +#ifndef lint +__COPYRIGHT("@(#) Copyright (c) 1990, 1993, 1994\ + The Regents of the University of California. All rights reserved."); +#endif /* not lint */ + +#ifndef lint +#if 0 +static char sccsid[] = "@(#)rm.c 8.8 (Berkeley) 4/27/95"; +#else +__RCSID("$NetBSD: rm.c,v 1.53 2013/04/26 18:43:22 christos Exp $"); +#endif +#endif /* not lint */ + +#include <sys/param.h> +#include <sys/stat.h> +#include <sys/types.h> + +#include <err.h> +#include <errno.h> +#include <fcntl.h> +#include <fts.h> +#include <grp.h> +#include <locale.h> +#include <pwd.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +static int dflag, eval, fflag, iflag, Pflag, stdin_ok, vflag, Wflag; +static int xflag; +static sig_atomic_t pinfo; + +static int check(char *, char *, struct stat *); +static void checkdot(char **); +static void progress(int); +static void rm_file(char **); +static int rm_overwrite(char *, struct stat *); +static void rm_tree(char **); +__dead static void usage(void); + +/* + * For the sake of the `-f' flag, check whether an error number indicates the + * failure of an operation due to an non-existent file, either per se (ENOENT) + * or because its filename argument was illegal (ENAMETOOLONG, ENOTDIR). + */ +#define NONEXISTENT(x) \ + ((x) == ENOENT || (x) == ENAMETOOLONG || (x) == ENOTDIR) + +/* + * rm -- + * This rm is different from historic rm's, but is expected to match + * POSIX 1003.2 behavior. The most visible difference is that -f + * has two specific effects now, ignore non-existent files and force + * file removal. + */ +int +main(int argc, char *argv[]) +{ + int ch, rflag; + + setprogname(argv[0]); + (void)setlocale(LC_ALL, ""); + + Pflag = rflag = xflag = 0; + while ((ch = getopt(argc, argv, "dfiPRrvWx")) != -1) + switch (ch) { + case 'd': + dflag = 1; + break; + case 'f': + fflag = 1; + iflag = 0; + break; + case 'i': + fflag = 0; + iflag = 1; + break; + case 'P': + Pflag = 1; + break; + case 'R': + case 'r': /* Compatibility. */ + rflag = 1; + break; + case 'v': + vflag = 1; + break; + case 'x': + xflag = 1; + break; +#ifndef __ANDROID__ + case 'W': + Wflag = 1; + break; +#endif + case '?': + default: + usage(); + } + argc -= optind; + argv += optind; + + if (argc < 1) { + if (fflag) + return 0; + usage(); + } + + (void)signal(SIGINFO, progress); + + checkdot(argv); + + if (*argv) { + stdin_ok = isatty(STDIN_FILENO); + + if (rflag) + rm_tree(argv); + else + rm_file(argv); + } + + exit(eval); + /* NOTREACHED */ +} + +static void +rm_tree(char **argv) +{ + FTS *fts; + FTSENT *p; + int flags, needstat, rval; + + /* + * Remove a file hierarchy. If forcing removal (-f), or interactive + * (-i) or can't ask anyway (stdin_ok), don't stat the file. + */ + needstat = !fflag && !iflag && stdin_ok; + + /* + * If the -i option is specified, the user can skip on the pre-order + * visit. The fts_number field flags skipped directories. + */ +#define SKIPPED 1 + + flags = FTS_PHYSICAL; + if (!needstat) + flags |= FTS_NOSTAT; +#ifndef __ANDROID__ + if (Wflag) + flags |= FTS_WHITEOUT; +#endif + if (xflag) + flags |= FTS_XDEV; + if ((fts = fts_open(argv, flags, NULL)) == NULL) + err(1, "fts_open failed"); + while ((p = fts_read(fts)) != NULL) { + + switch (p->fts_info) { + case FTS_DNR: + if (!fflag || p->fts_errno != ENOENT) { + warnx("%s: %s", p->fts_path, + strerror(p->fts_errno)); + eval = 1; + } + continue; + case FTS_ERR: + errx(EXIT_FAILURE, "%s: %s", p->fts_path, + strerror(p->fts_errno)); + /* NOTREACHED */ + case FTS_NS: + /* + * FTS_NS: assume that if can't stat the file, it + * can't be unlinked. + */ + if (fflag && NONEXISTENT(p->fts_errno)) + continue; + if (needstat) { + warnx("%s: %s", p->fts_path, + strerror(p->fts_errno)); + eval = 1; + continue; + } + break; + case FTS_D: + /* Pre-order: give user chance to skip. */ + if (!fflag && !check(p->fts_path, p->fts_accpath, + p->fts_statp)) { + (void)fts_set(fts, p, FTS_SKIP); + p->fts_number = SKIPPED; + } + continue; + case FTS_DP: + /* Post-order: see if user skipped. */ + if (p->fts_number == SKIPPED) + continue; + break; + default: + if (!fflag && + !check(p->fts_path, p->fts_accpath, p->fts_statp)) + continue; + } + + rval = 0; + /* + * If we can't read or search the directory, may still be + * able to remove it. Don't print out the un{read,search}able + * message unless the remove fails. + */ + switch (p->fts_info) { + case FTS_DP: + case FTS_DNR: + rval = rmdir(p->fts_accpath); + if (rval != 0 && fflag && errno == ENOENT) + continue; + break; + +#ifndef __ANDROID__ + case FTS_W: + rval = undelete(p->fts_accpath); + if (rval != 0 && fflag && errno == ENOENT) + continue; + break; +#endif + + default: + if (Pflag) { + if (rm_overwrite(p->fts_accpath, NULL)) + continue; + } + rval = unlink(p->fts_accpath); + if (rval != 0 && fflag && NONEXISTENT(errno)) + continue; + break; + } + if (rval != 0) { + warn("%s", p->fts_path); + eval = 1; + } else if (vflag || pinfo) { + pinfo = 0; + (void)printf("%s\n", p->fts_path); + } + } + if (errno) + err(1, "fts_read"); + fts_close(fts); +} + +static void +rm_file(char **argv) +{ + struct stat sb; + int rval; + char *f; + + /* + * Remove a file. POSIX 1003.2 states that, by default, attempting + * to remove a directory is an error, so must always stat the file. + */ + while ((f = *argv++) != NULL) { + /* Assume if can't stat the file, can't unlink it. */ + if (lstat(f, &sb)) { +#ifndef __ANDROID__ + if (Wflag) { + sb.st_mode = S_IFWHT|S_IWUSR|S_IRUSR; + } else { +#endif + if (!fflag || !NONEXISTENT(errno)) { + warn("%s", f); + eval = 1; + } + continue; +#ifndef __ANDROID__ + } + } else if (Wflag) { + warnx("%s: %s", f, strerror(EEXIST)); + eval = 1; + continue; +#endif + } + + if (S_ISDIR(sb.st_mode) && !dflag) { + warnx("%s: is a directory", f); + eval = 1; + continue; + } + if (!fflag && !S_ISWHT(sb.st_mode) && !check(f, f, &sb)) + continue; +#ifndef __ANDROID__ + if (S_ISWHT(sb.st_mode)) + rval = undelete(f); + else if (S_ISDIR(sb.st_mode)) +#else + if (S_ISDIR(sb.st_mode)) +#endif + rval = rmdir(f); + else { + if (Pflag) { + if (rm_overwrite(f, &sb)) + continue; + } + rval = unlink(f); + } + if (rval && (!fflag || !NONEXISTENT(errno))) { + warn("%s", f); + eval = 1; + } + if (vflag && rval == 0) + (void)printf("%s\n", f); + } +} + +/* + * rm_overwrite -- + * Overwrite the file 3 times with varying bit patterns. + * + * This is an expensive way to keep people from recovering files from your + * non-snapshotted FFS filesystems using fsdb(8). Really. No more. Only + * regular files are deleted, directories (and therefore names) will remain. + * Also, this assumes a fixed-block file system (like FFS, or a V7 or a + * System V file system). In a logging file system, you'll have to have + * kernel support. + * + * A note on standards: U.S. DoD 5220.22-M "National Industrial Security + * Program Operating Manual" ("NISPOM") is often cited as a reference + * for clearing and sanitizing magnetic media. In fact, a matrix of + * "clearing" and "sanitization" methods for various media was given in + * Chapter 8 of the original 1995 version of NISPOM. However, that + * matrix was *removed from the document* when Chapter 8 was rewritten + * in Change 2 to the document in 2001. Recently, the Defense Security + * Service has made a revised clearing and sanitization matrix available + * in Microsoft Word format on the DSS web site. The standardization + * status of this matrix is unclear. Furthermore, one must be very + * careful when referring to this matrix: it is intended for the "clearing" + * prior to reuse or "sanitization" prior to disposal of *entire media*, + * not individual files and the only non-physically-destructive method of + * "sanitization" that is permitted for magnetic disks of any kind is + * specifically noted to be prohibited for media that have contained + * Top Secret data. + * + * It is impossible to actually conform to the exact procedure given in + * the matrix if one is overwriting a file, not an entire disk, because + * the procedure requires examination and comparison of the disk's defect + * lists. Any program that claims to securely erase *files* while + * conforming to the standard, then, is not correct. We do as much of + * what the standard requires as can actually be done when erasing a + * file, rather than an entire disk; but that does not make us conformant. + * + * Furthermore, the presence of track caches, disk and controller write + * caches, and so forth make it extremely difficult to ensure that data + * have actually been written to the disk, particularly when one tries + * to repeatedly overwrite the same sectors in quick succession. We call + * fsync(), but controllers with nonvolatile cache, as well as IDE disks + * that just plain lie about the stable storage of data, will defeat this. + * + * Finally, widely respected research suggests that the given procedure + * is nowhere near sufficient to prevent the recovery of data using special + * forensic equipment and techniques that are well-known. This is + * presumably one reason that the matrix requires physical media destruction, + * rather than any technique of the sort attempted here, for secret data. + * + * Caveat Emptor. + * + * rm_overwrite will return 0 on success. + */ + +static int +rm_overwrite(char *file, struct stat *sbp) +{ + struct stat sb, sb2; + int fd, randint; + char randchar; + + fd = -1; + if (sbp == NULL) { + if (lstat(file, &sb)) + goto err; + sbp = &sb; + } + if (!S_ISREG(sbp->st_mode)) + return 0; + + /* flags to try to defeat hidden caching by forcing seeks */ + if ((fd = open(file, O_RDWR|O_SYNC|O_RSYNC|O_NOFOLLOW, 0)) == -1) + goto err; + + if (fstat(fd, &sb2)) { + goto err; + } + + if (sb2.st_dev != sbp->st_dev || sb2.st_ino != sbp->st_ino || + !S_ISREG(sb2.st_mode)) { + errno = EPERM; + goto err; + } + +#define RAND_BYTES 1 +#define THIS_BYTE 0 + +#define WRITE_PASS(mode, byte) do { \ + off_t len; \ + size_t wlen, i; \ + char buf[8 * 1024]; \ + \ + if (fsync(fd) || lseek(fd, (off_t)0, SEEK_SET)) \ + goto err; \ + \ + if (mode == THIS_BYTE) \ + memset(buf, byte, sizeof(buf)); \ + for (len = sbp->st_size; len > 0; len -= wlen) { \ + if (mode == RAND_BYTES) { \ + for (i = 0; i < sizeof(buf); \ + i+= sizeof(u_int32_t)) \ + *(int *)(buf + i) = arc4random(); \ + } \ + wlen = len < (off_t)sizeof(buf) ? (size_t)len : sizeof(buf); \ + if ((size_t)write(fd, buf, wlen) != wlen) \ + goto err; \ + } \ + sync(); /* another poke at hidden caches */ \ +} while (/* CONSTCOND */ 0) + +#define READ_PASS(byte) do { \ + off_t len; \ + size_t rlen; \ + char pattern[8 * 1024]; \ + char buf[8 * 1024]; \ + \ + if (fsync(fd) || lseek(fd, (off_t)0, SEEK_SET)) \ + goto err; \ + \ + memset(pattern, byte, sizeof(pattern)); \ + for(len = sbp->st_size; len > 0; len -= rlen) { \ + rlen = len < (off_t)sizeof(buf) ? (size_t)len : sizeof(buf); \ + if((size_t)read(fd, buf, rlen) != rlen) \ + goto err; \ + if(memcmp(buf, pattern, rlen)) \ + goto err; \ + } \ + sync(); /* another poke at hidden caches */ \ +} while (/* CONSTCOND */ 0) + + /* + * DSS sanitization matrix "clear" for magnetic disks: + * option 'c' "Overwrite all addressable locations with a single + * character." + */ + randint = arc4random(); + randchar = *(char *)&randint; + WRITE_PASS(THIS_BYTE, randchar); + + /* + * DSS sanitization matrix "sanitize" for magnetic disks: + * option 'd', sub 2 "Overwrite all addressable locations with a + * character, then its complement. Verify "complement" character + * was written successfully to all addressable locations, then + * overwrite all addressable locations with random characters; or + * verify third overwrite of random characters." The rest of the + * text in d-sub-2 specifies requirements for overwriting spared + * sectors; we cannot conform to it when erasing only a file, thus + * we do not conform to the standard. + */ + + /* 1. "a character" */ + WRITE_PASS(THIS_BYTE, 0xff); + + /* 2. "its complement" */ + WRITE_PASS(THIS_BYTE, 0x00); + + /* 3. "Verify 'complement' character" */ + READ_PASS(0x00); + + /* 4. "overwrite all addressable locations with random characters" */ + + WRITE_PASS(RAND_BYTES, 0x00); + + /* + * As the file might be huge, and we note that this revision of + * the matrix says "random characters", not "a random character" + * as the original did, we do not verify the random-character + * write; the "or" in the standard allows this. + */ + + if (close(fd) == -1) { + fd = -1; + goto err; + } + + return 0; + +err: eval = 1; + warn("%s", file); + if (fd != -1) + close(fd); + return 1; +} + +static int +check(char *path, char *name, struct stat *sp) +{ + int ch, first; + char modep[15]; + + /* Check -i first. */ + if (iflag) + (void)fprintf(stderr, "remove '%s'? ", path); + else { + /* + * If it's not a symbolic link and it's unwritable and we're + * talking to a terminal, ask. Symbolic links are excluded + * because their permissions are meaningless. Check stdin_ok + * first because we may not have stat'ed the file. + */ + if (!stdin_ok || S_ISLNK(sp->st_mode) || + !(access(name, W_OK) && (errno != ETXTBSY))) + return (1); + strmode(sp->st_mode, modep); + if (Pflag) { + warnx( + "%s: -P was specified but file could not" + " be overwritten", path); + return 0; + } + (void)fprintf(stderr, "override %s%s%s:%s for '%s'? ", + modep + 1, modep[9] == ' ' ? "" : " ", + user_from_uid(sp->st_uid, 0), + group_from_gid(sp->st_gid, 0), path); + } + (void)fflush(stderr); + + first = ch = getchar(); + while (ch != '\n' && ch != EOF) + ch = getchar(); + return (first == 'y' || first == 'Y'); +} + +/* + * POSIX.2 requires that if "." or ".." are specified as the basename + * portion of an operand, a diagnostic message be written to standard + * error and nothing more be done with such operands. + * + * Since POSIX.2 defines basename as the final portion of a path after + * trailing slashes have been removed, we'll remove them here. + */ +#define ISDOT(a) ((a)[0] == '.' && (!(a)[1] || ((a)[1] == '.' && !(a)[2]))) +static void +checkdot(char **argv) +{ + char *p, **save, **t; + int complained; + + complained = 0; + for (t = argv; *t;) { + /* strip trailing slashes */ + p = strrchr(*t, '\0'); + while (--p > *t && *p == '/') + *p = '\0'; + + /* extract basename */ + if ((p = strrchr(*t, '/')) != NULL) + ++p; + else + p = *t; + + if (ISDOT(p)) { + if (!complained++) + warnx("\".\" and \"..\" may not be removed"); + eval = 1; + for (save = t; (t[0] = t[1]) != NULL; ++t) + continue; + t = save; + } else + ++t; + } +} + +static void +usage(void) +{ + + (void)fprintf(stderr, "usage: %s [-f|-i] [-dPRrvWx] file ...\n", + getprogname()); + exit(1); + /* NOTREACHED */ +} + +static void +progress(int sig __unused) +{ + + pinfo++; +} diff --git a/toolbox/upstream-netbsd/bin/rmdir/rmdir.c b/toolbox/upstream-netbsd/bin/rmdir/rmdir.c new file mode 100644 index 0000000..03261ce --- /dev/null +++ b/toolbox/upstream-netbsd/bin/rmdir/rmdir.c @@ -0,0 +1,121 @@ +/* $NetBSD: rmdir.c,v 1.26 2011/08/29 14:49:38 joerg Exp $ */ + +/*- + * Copyright (c) 1992, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * 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. + */ + +#include <sys/cdefs.h> +#ifndef lint +__COPYRIGHT("@(#) Copyright (c) 1992, 1993, 1994\ + The Regents of the University of California. All rights reserved."); +#endif /* not lint */ + +#ifndef lint +#if 0 +static char sccsid[] = "@(#)rmdir.c 8.3 (Berkeley) 4/2/94"; +#else +__RCSID("$NetBSD: rmdir.c,v 1.26 2011/08/29 14:49:38 joerg Exp $"); +#endif +#endif /* not lint */ + +#include <sys/param.h> + +#include <err.h> +#include <locale.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +static int rm_path(char *); +__dead static void usage(void); + +int +main(int argc, char *argv[]) +{ + int ch, errors, pflag; + + setprogname(argv[0]); + (void)setlocale(LC_ALL, ""); + + pflag = 0; + while ((ch = getopt(argc, argv, "p")) != -1) + switch(ch) { + case 'p': + pflag = 1; + break; + case '?': + default: + usage(); + } + argc -= optind; + argv += optind; + + if (argc == 0) + usage(); + + for (errors = 0; *argv; argv++) { + /* We rely on the kernel to ignore trailing '/' characters. */ + if (rmdir(*argv) < 0) { + warn("%s", *argv); + errors = 1; + } else if (pflag) + errors |= rm_path(*argv); + } + + exit(errors); + /* NOTREACHED */ +} + +static int +rm_path(char *path) +{ + char *p; + + while ((p = strrchr(path, '/')) != NULL) { + *p = 0; + if (p[1] == 0) + /* Ignore trailing '/' on deleted name */ + continue; + + if (rmdir(path) < 0) { + warn("%s", path); + return (1); + } + } + + return (0); +} + +static void +usage(void) +{ + (void)fprintf(stderr, "usage: %s [-p] directory ...\n", getprogname()); + exit(1); + /* NOTREACHED */ +} diff --git a/toolbox/upstream-netbsd/bin/sleep/sleep.c b/toolbox/upstream-netbsd/bin/sleep/sleep.c new file mode 100644 index 0000000..4349af4 --- /dev/null +++ b/toolbox/upstream-netbsd/bin/sleep/sleep.c @@ -0,0 +1,159 @@ +/* $NetBSD: sleep.c,v 1.24 2011/08/29 14:51:19 joerg Exp $ */ + +/* + * Copyright (c) 1988, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * 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. + */ + +#include <sys/cdefs.h> +#ifndef lint +__COPYRIGHT("@(#) Copyright (c) 1988, 1993, 1994\ + The Regents of the University of California. All rights reserved."); +#endif /* not lint */ + +#ifndef lint +#if 0 +static char sccsid[] = "@(#)sleep.c 8.3 (Berkeley) 4/2/94"; +#else +__RCSID("$NetBSD: sleep.c,v 1.24 2011/08/29 14:51:19 joerg Exp $"); +#endif +#endif /* not lint */ + +#include <ctype.h> +#include <err.h> +#include <locale.h> +#include <math.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <time.h> +#include <unistd.h> + +__dead static void alarmhandle(int); +__dead static void usage(void); + +static volatile sig_atomic_t report_requested; +static void +report_request(int signo __unused) +{ + + report_requested = 1; +} + +int +main(int argc, char *argv[]) +{ + char *arg, *temp; + double fval, ival, val; + struct timespec ntime; + time_t original; + int ch, fracflag, rv; + + setprogname(argv[0]); + (void)setlocale(LC_ALL, ""); + + (void)signal(SIGALRM, alarmhandle); + + while ((ch = getopt(argc, argv, "")) != -1) + switch(ch) { + default: + usage(); + } + argc -= optind; + argv += optind; + + if (argc != 1) + usage(); + + /* + * Okay, why not just use atof for everything? Why bother + * checking if there is a fraction in use? Because the old + * sleep handled the full range of integers, that's why, and a + * double can't handle a large long. This is fairly useless + * given how large a number a double can hold on most + * machines, but now we won't ever have trouble. If you want + * 1000000000.9 seconds of sleep, well, that's your + * problem. Why use an isdigit() check instead of checking for + * a period? Because doing it this way means locales will be + * handled transparently by the atof code. + */ + fracflag = 0; + arg = *argv; + for (temp = arg; *temp != '\0'; temp++) + if (!isdigit((unsigned char)*temp)) + fracflag++; + + if (fracflag) { + val = atof(arg); + if (val <= 0) + usage(); + ival = floor(val); + fval = (1000000000 * (val-ival)); + ntime.tv_sec = ival; + ntime.tv_nsec = fval; + } + else { + ntime.tv_sec = atol(arg); + if (ntime.tv_sec <= 0) + return EXIT_SUCCESS; + ntime.tv_nsec = 0; + } + + original = ntime.tv_sec; + signal(SIGINFO, report_request); + while ((rv = nanosleep(&ntime, &ntime)) != 0) { + if (report_requested) { + /* Reporting does not bother with nanoseconds. */ + warnx("about %d second(s) left out of the original %d", + (int)ntime.tv_sec, (int)original); + report_requested = 0; + } else + break; + } + + if (rv == -1) + err(EXIT_FAILURE, "nanosleep failed"); + + return EXIT_SUCCESS; + /* NOTREACHED */ +} + +static void +usage(void) +{ + (void)fprintf(stderr, "usage: %s seconds\n", getprogname()); + exit(EXIT_FAILURE); + /* NOTREACHED */ +} + +/* ARGSUSED */ +static void +alarmhandle(int i) +{ + _exit(EXIT_SUCCESS); + /* NOTREACHED */ +} diff --git a/toolbox/upstream-netbsd/bin/sync/sync.c b/toolbox/upstream-netbsd/bin/sync/sync.c new file mode 100644 index 0000000..2b9c367 --- /dev/null +++ b/toolbox/upstream-netbsd/bin/sync/sync.c @@ -0,0 +1,59 @@ +/* $NetBSD: sync.c,v 1.13 2008/07/20 00:52:40 lukem Exp $ */ + +/* + * Copyright (c) 1987, 1993 + * The Regents of the University of California. All rights reserved. + * + * 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. + */ + +#include <sys/cdefs.h> +#ifndef lint +__COPYRIGHT("@(#) Copyright (c) 1987, 1993\ + The Regents of the University of California. All rights reserved."); +#endif /* not lint */ + +#ifndef lint +#if 0 +static char sccsid[] = "@(#)sync.c 8.1 (Berkeley) 5/31/93"; +#else +__RCSID("$NetBSD: sync.c,v 1.13 2008/07/20 00:52:40 lukem Exp $"); +#endif +#endif /* not lint */ + +#include <stdlib.h> +#include <unistd.h> + +int main(int, char *[]); + +/* ARGSUSED */ +int +main(int argc, char *argv[]) +{ + setprogname(argv[0]); + sync(); + exit(0); + /* NOTREACHED */ +} |