summaryrefslogtreecommitdiff
path: root/package/toolbox/src/src
diff options
context:
space:
mode:
Diffstat (limited to 'package/toolbox/src/src')
-rw-r--r--package/toolbox/src/src/chmod.c101
-rw-r--r--package/toolbox/src/src/chown.c73
-rw-r--r--package/toolbox/src/src/clear.c41
-rw-r--r--package/toolbox/src/src/cmp.c91
-rw-r--r--package/toolbox/src/src/dd.c1323
-rw-r--r--package/toolbox/src/src/dd.h94
-rw-r--r--package/toolbox/src/src/df.c85
-rw-r--r--package/toolbox/src/src/dmesg.c64
-rw-r--r--package/toolbox/src/src/du.c322
-rw-r--r--package/toolbox/src/src/dynarray.c104
-rw-r--r--package/toolbox/src/src/dynarray.h80
-rw-r--r--package/toolbox/src/src/exists.c16
-rw-r--r--package/toolbox/src/src/hd.c97
-rw-r--r--package/toolbox/src/src/id.c51
-rw-r--r--package/toolbox/src/src/ifconfig.c164
-rw-r--r--package/toolbox/src/src/iftop.c278
-rw-r--r--package/toolbox/src/src/insmod.c97
-rw-r--r--package/toolbox/src/src/ioctl.c124
-rw-r--r--package/toolbox/src/src/kill.c149
-rw-r--r--package/toolbox/src/src/ln.c34
-rw-r--r--package/toolbox/src/src/ls.c424
-rw-r--r--package/toolbox/src/src/lsof.c253
-rw-r--r--package/toolbox/src/src/md5.c75
-rw-r--r--package/toolbox/src/src/mkdir.c77
-rw-r--r--package/toolbox/src/src/mount.c360
-rw-r--r--package/toolbox/src/src/mv.c59
-rw-r--r--package/toolbox/src/src/netstat.c155
-rw-r--r--package/toolbox/src/src/notify.c145
-rw-r--r--package/toolbox/src/src/printenv.c33
-rw-r--r--package/toolbox/src/src/ps.c244
-rw-r--r--package/toolbox/src/src/readlink.c95
-rw-r--r--package/toolbox/src/src/renice.c161
-rw-r--r--package/toolbox/src/src/rm.c126
-rw-r--r--package/toolbox/src/src/rmdir.c28
-rw-r--r--package/toolbox/src/src/rmmod.c53
-rw-r--r--package/toolbox/src/src/route.c113
-rw-r--r--package/toolbox/src/src/schedtop.c332
-rw-r--r--package/toolbox/src/src/setkey.c91
-rw-r--r--package/toolbox/src/src/sleep.c64
-rw-r--r--package/toolbox/src/src/sync.c7
-rw-r--r--package/toolbox/src/src/top.c542
-rw-r--r--package/toolbox/src/src/touch.c115
-rw-r--r--package/toolbox/src/src/umount.c91
-rw-r--r--package/toolbox/src/src/vmstat.c248
44 files changed, 7279 insertions, 0 deletions
diff --git a/package/toolbox/src/src/chmod.c b/package/toolbox/src/src/chmod.c
new file mode 100644
index 000000000..1de14aa2c
--- /dev/null
+++ b/package/toolbox/src/src/chmod.c
@@ -0,0 +1,101 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <dirent.h>
+#include <errno.h>
+#include <limits.h>
+#include <sys/stat.h>
+
+#include <unistd.h>
+#include <time.h>
+
+void recurse_chmod(char* path, int mode)
+{
+ struct dirent *dp;
+ DIR *dir = opendir(path);
+ if (dir == NULL) {
+ // not a directory, carry on
+ return;
+ }
+ char *subpath = malloc(sizeof(char)*PATH_MAX);
+ int pathlen = strlen(path);
+
+ while ((dp = readdir(dir)) != NULL) {
+ if (strcmp(dp->d_name, ".") == 0 ||
+ strcmp(dp->d_name, "..") == 0) continue;
+
+ if (strlen(dp->d_name) + pathlen + 2/*NUL and slash*/ > PATH_MAX) {
+ fprintf(stderr, "Invalid path specified: too long\n");
+ exit(1);
+ }
+
+ strcpy(subpath, path);
+ strcat(subpath, "/");
+ strcat(subpath, dp->d_name);
+
+ if (chmod(subpath, mode) < 0) {
+ fprintf(stderr, "Unable to chmod %s: %s\n", subpath, strerror(errno));
+ exit(1);
+ }
+
+ recurse_chmod(subpath, mode);
+ }
+ free(subpath);
+ closedir(dir);
+}
+
+static int usage()
+{
+ fprintf(stderr, "Usage: chmod [OPTION] <MODE> <FILE>\n");
+ fprintf(stderr, " -R, --recursive change files and directories recursively\n");
+ fprintf(stderr, " --help display this help and exit\n");
+
+ return 10;
+}
+
+int main(int argc, char **argv)
+{
+ int i;
+
+ if (argc < 3 || strcmp(argv[1], "--help") == 0) {
+ return usage();
+ }
+
+ int recursive = (strcmp(argv[1], "-R") == 0 ||
+ strcmp(argv[1], "--recursive") == 0) ? 1 : 0;
+
+ if (recursive && argc < 4) {
+ return usage();
+ }
+
+ if (recursive) {
+ argc--;
+ argv++;
+ }
+
+ int mode = 0;
+ const char* s = argv[1];
+ while (*s) {
+ if (*s >= '0' && *s <= '7') {
+ mode = (mode<<3) | (*s-'0');
+ }
+ else {
+ fprintf(stderr, "Bad mode\n");
+ return 10;
+ }
+ s++;
+ }
+
+ for (i = 2; i < argc; i++) {
+ if (chmod(argv[i], mode) < 0) {
+ fprintf(stderr, "Unable to chmod %s: %s\n", argv[i], strerror(errno));
+ return 10;
+ }
+ if (recursive) {
+ recurse_chmod(argv[i], mode);
+ }
+ }
+ return 0;
+}
+
diff --git a/package/toolbox/src/src/chown.c b/package/toolbox/src/src/chown.c
new file mode 100644
index 000000000..d02721718
--- /dev/null
+++ b/package/toolbox/src/src/chown.c
@@ -0,0 +1,73 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <dirent.h>
+#include <errno.h>
+#include <pwd.h>
+#include <grp.h>
+
+#include <unistd.h>
+#include <time.h>
+
+int main(int argc, char **argv)
+{
+ int i;
+
+ if (argc < 3) {
+ fprintf(stderr, "Usage: chown <USER>[:GROUP] <FILE1> [FILE2] ...\n");
+ return 10;
+ }
+
+ // Copy argv[1] to 'user' so we can truncate it at the period
+ // if a group id specified.
+ char user[32];
+ char *group = NULL;
+ strncpy(user, argv[1], sizeof(user));
+ if ((group = strchr(user, ':')) != NULL) {
+ *group++ = '\0';
+ } else if ((group = strchr(user, '.')) != NULL) {
+ *group++ = '\0';
+ }
+
+ // Lookup uid (and gid if specified)
+ struct passwd *pw;
+ struct group *grp = NULL;
+ uid_t uid;
+ gid_t gid = -1; // passing -1 to chown preserves current group
+
+ pw = getpwnam(user);
+ if (pw != NULL) {
+ uid = pw->pw_uid;
+ } else {
+ char* endptr;
+ uid = (int) strtoul(user, &endptr, 0);
+ if (endptr == user) { // no conversion
+ fprintf(stderr, "No such user '%s'\n", user);
+ return 10;
+ }
+ }
+
+ if (group != NULL) {
+ grp = getgrnam(group);
+ if (grp != NULL) {
+ gid = grp->gr_gid;
+ } else {
+ char* endptr;
+ gid = (int) strtoul(group, &endptr, 0);
+ if (endptr == group) { // no conversion
+ fprintf(stderr, "No such group '%s'\n", group);
+ return 10;
+ }
+ }
+ }
+
+ for (i = 2; i < argc; i++) {
+ if (chown(argv[i], uid, gid) < 0) {
+ fprintf(stderr, "Unable to chown %s: %s\n", argv[i], strerror(errno));
+ return 10;
+ }
+ }
+
+ return 0;
+}
diff --git a/package/toolbox/src/src/clear.c b/package/toolbox/src/src/clear.c
new file mode 100644
index 000000000..434ab4ace
--- /dev/null
+++ b/package/toolbox/src/src/clear.c
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2012, The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of Google, Inc. 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 COPYRIGHT HOLDERS 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
+ * COPYRIGHT OWNER 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 <stdio.h>
+
+int main(int argc, char **argv) {
+ /* This prints the clear screen and move cursor to top-left corner control
+ * characters for VT100 terminals. This means it will not work on
+ * non-VT100 compliant terminals, namely Windows' cmd.exe, but should
+ * work on anything unix-y. */
+ fputs("\x1b[2J\x1b[H", stdout);
+ return 0;
+}
diff --git a/package/toolbox/src/src/cmp.c b/package/toolbox/src/src/cmp.c
new file mode 100644
index 000000000..79e56c41a
--- /dev/null
+++ b/package/toolbox/src/src/cmp.c
@@ -0,0 +1,91 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdint.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <errno.h>
+
+int main(int argc, char *argv[])
+{
+ int c;
+ int fd1, fd2;
+ char buf1[4096], buf2[4096];
+ int res, res1, res2;
+ int rv = 0;
+ int i;
+ int filepos = 0;
+
+ int show_byte = 0;
+ int show_all = 0;
+ int limit = 0;
+
+ do {
+ c = getopt(argc, argv, "bln:");
+ if (c == EOF)
+ break;
+ switch (c) {
+ case 'b':
+ show_byte = 1;
+ break;
+ case 'l':
+ show_all = 1;
+ break;
+ case 'n':
+ limit = atoi(optarg);
+ break;
+ case '?':
+ fprintf(stderr, "%s: invalid option -%c\n",
+ argv[0], optopt);
+ exit(1);
+ }
+ } while (1);
+
+ if (optind + 2 != argc) {
+ fprintf(stderr, "Usage: %s [-b] [-l] [-n count] file1 file2\n", argv[0]);
+ exit(1);
+ }
+
+ fd1 = open(argv[optind], O_RDONLY);
+ if(fd1 < 0) {
+ fprintf(stderr, "could not open %s, %s\n", argv[optind], strerror(errno));
+ return 1;
+ }
+
+ fd2 = open(argv[optind+1], O_RDONLY);
+ if(fd2 < 0) {
+ fprintf(stderr, "could not open %s, %s\n", argv[optind+1], strerror(errno));
+ return 1;
+ }
+
+ while(1) {
+ res1 = read(fd1, &buf1, sizeof(buf1));
+ res2 = read(fd2, &buf2, sizeof(buf2));
+ res = res1 < res2 ? res1 : res2;
+ if(res1 == 0 && res2 == 0) {
+ return rv;
+ }
+ for(i = 0; i < res; i++) {
+ if(buf1[i] != buf2[i]) {
+ printf("%s %s differ byte %d", argv[optind], argv[optind+1], filepos + i);
+ if(show_byte)
+ printf(" 0x%02x 0x%02x", buf1[i], buf2[i]);
+ printf("\n");
+ if(!show_all)
+ return 1;
+ rv = 1;
+ }
+ if(limit) {
+ limit--;
+ if(limit == 0)
+ return rv;
+ }
+ }
+ if(res1 != res2 || res < 0) {
+ printf("%s on %s\n", res < 0 ? "Read error" : "EOF", res1 < res2 ? argv[optind] : argv[optind+1]);
+ return 1;
+ }
+ filepos += res;
+ }
+}
diff --git a/package/toolbox/src/src/dd.c b/package/toolbox/src/src/dd.c
new file mode 100644
index 000000000..605f18775
--- /dev/null
+++ b/package/toolbox/src/src/dd.c
@@ -0,0 +1,1323 @@
+/* $NetBSD: dd.c,v 1.37 2004/01/17 21:00:16 dbj 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\n\
+ The Regents of the University of California. All rights reserved.\n");
+#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.37 2004/01/17 21:00:16 dbj Exp $");
+#endif
+#endif /* not lint */
+
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <sys/time.h>
+
+#include <ctype.h>
+#include <err.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "dd.h"
+
+//#define NO_CONV
+
+//#include "extern.h"
+void block(void);
+void block_close(void);
+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);
+void terminate(int);
+void unblock(void);
+void unblock_close(void);
+ssize_t bwrite(int, 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 int progress;
+extern const u_char *ctab;
+
+
+#ifndef MIN
+#define MIN(a, b) ((a) < (b) ? (a) : (b))
+#endif
+#ifndef MAX
+#define MAX(a, b) ((a) > (b) ? (a) : (b))
+#endif
+#ifndef DEFFILEMODE
+#define DEFFILEMODE (S_IRUSR | S_IWUSR)
+#endif
+
+static void dd_close(void);
+static void dd_in(void);
+static void getfdtype(IO *);
+static int redup_clean_fd(int);
+static void setup(void);
+
+
+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 */
+int progress = 0; /* display sign of life */
+const u_char *ctab; /* conversion table */
+sigset_t infoset; /* a set blocking SIGINFO */
+
+int
+main(int argc, char *argv[])
+{
+ int ch;
+
+ while ((ch = getopt(argc, argv, "")) != -1) {
+ switch (ch) {
+ default:
+ fprintf(stderr, "usage: dd [operand ...]\n");
+ exit(1);
+ /* NOTREACHED */
+ }
+ }
+ argc -= (optind - 1);
+ argv += (optind - 1);
+
+ jcl(argv);
+ 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)
+{
+
+ if (in.name == NULL) {
+ in.name = "stdin";
+ in.fd = STDIN_FILENO;
+ } else {
+ in.fd = open(in.name, O_RDONLY, 0);
+ if (in.fd < 0) {
+ fprintf(stderr, "%s: cannot open for read: %s\n",
+ in.name, strerror(errno));
+ exit(1);
+ /* NOTREACHED */
+ }
+
+ /* Ensure in.fd is outside the stdio descriptor range */
+ in.fd = redup_clean_fd(in.fd);
+ }
+
+ getfdtype(&in);
+
+ if (files_cnt > 1 && !(in.flags & ISTAPE)) {
+ fprintf(stderr,
+ "files is not supported for non-tape devices\n");
+ exit(1);
+ /* NOTREACHED */
+ }
+
+ if (out.name == NULL) {
+ /* No way to check for read access here. */
+ out.fd = STDOUT_FILENO;
+ out.name = "stdout";
+ } else {
+#define OFLAGS \
+ (O_CREAT | (ddflags & (C_SEEK | C_NOTRUNC) ? 0 : O_TRUNC))
+ out.fd = open(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 = open(out.name, O_WRONLY | OFLAGS, DEFFILEMODE);
+ out.flags |= NOREAD;
+ }
+ if (out.fd < 0) {
+ fprintf(stderr, "%s: cannot open for write: %s\n",
+ out.name, strerror(errno));
+ exit(1);
+ /* NOTREACHED */
+ }
+
+ /* Ensure out.fd is outside the stdio descriptor range */
+ out.fd = redup_clean_fd(out.fd);
+ }
+
+ 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))) {
+ if ((in.db = malloc(out.dbsz + in.dbsz - 1)) == NULL) {
+ exit(1);
+ /* 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) {
+ exit(1);
+ /* 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)ftruncate(out.fd, (off_t)out.offset * out.dbsz);
+
+ (void)gettimeofday(&st.start, NULL); /* Statistics timestamp. */
+}
+
+static void
+getfdtype(IO *io)
+{
+// struct mtget mt;
+ struct stat sb;
+
+ if (fstat(io->fd, &sb)) {
+ fprintf(stderr, "%s: cannot fstat: %s\n",
+ io->name, strerror(errno));
+ exit(1);
+ /* NOTREACHED */
+ }
+ if (S_ISCHR(sb.st_mode))
+ io->flags |= /*ioctl(io->fd, MTIOCGET, &mt) ? ISCHR : ISTAPE; */ ISCHR;
+ else if (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 int
+redup_clean_fd(int fd)
+{
+ int newfd;
+
+ if (fd != STDIN_FILENO && fd != STDOUT_FILENO &&
+ fd != STDERR_FILENO)
+ /* File descriptor is ok, return immediately. */
+ return fd;
+
+ /*
+ * 3 is the first descriptor greater than STD*_FILENO. Any
+ * free descriptor valued 3 or above is acceptable...
+ */
+ newfd = fcntl(fd, F_DUPFD, 3);
+ if (newfd < 0) {
+ fprintf(stderr, "dupfd IO: %s\n", strerror(errno));
+ exit(1);
+ /* NOTREACHED */
+ }
+
+ close(fd);
+
+ return 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 = read(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.
+ */
+ fprintf(stderr, "%s: read error: %s\n",
+ in.name, strerror(errno));
+ if (!(flags & C_NOERROR)) {
+ exit(1);
+ /* NOTREACHED */
+ }
+ 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)) &&
+ lseek(in.fd, (off_t)in.dbsz, SEEK_CUR))
+ fprintf(stderr, "%s: seek error: %s\n",
+ in.name, strerror(errno));
+
+ /* 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 (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 necesssary, 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 defered 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 among with other processes and close(2) just
+ * decreases the reference count.
+ */
+ if (out.fd == STDOUT_FILENO && fsync(out.fd) == -1 && errno != EINVAL) {
+ fprintf(stderr, "fsync stdout: %s\n", strerror(errno));
+ exit(1);
+ /* NOTREACHED */
+ }
+ if (close(out.fd) == -1) {
+ fprintf(stderr, "close: %s\n", strerror(errno));
+ exit(1);
+ /* 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;