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;
+ outp += cnt;
+ nw = 0;
+ break;
+ }
+ }
+ if (pending != 0) {
+ if (lseek(out.fd, pending, SEEK_CUR) ==
+ -1) {
+ fprintf(stderr,
+ "%s: seek error creating "
+ "sparse file: %s\n",
+ out.name, strerror(errno));
+ exit(1);
+ }
+ }
+ nw = bwrite(out.fd, outp, cnt);
+ if (nw <= 0) {
+ if (nw == 0) {
+ fprintf(stderr, "%s: end of device\n",
+ out.name);
+ exit(1);
+ /* NOTREACHED */
+ }
+ if (errno != EINTR) {
+ fprintf(stderr, "%s: write error: %s\n",
+ out.name, strerror(errno));
+ /* NOTREACHED */
+ exit(1);
+ }
+ 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 (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;
+ fprintf(stderr, "%s: short write on character "
+ "device\n", out.name);
+ }
+ if (out.flags & ISTAPE) {
+ fprintf(stderr,
+ "%s: short write on tape device",
+ out.name);
+ exit(1);
+ /* 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)
+ (void)write(STDERR_FILENO, ".", 1);
+}
+
+/*
+ * A protected against SIGINFO write
+ */
+ssize_t
+bwrite(int fd, const void *buf, size_t len)
+{
+ sigset_t oset;
+ ssize_t rv;
+ int oerrno;
+
+ (void)sigprocmask(SIG_BLOCK, &infoset, &oset);
+ rv = write(fd, buf, len);
+ oerrno = errno;
+ (void)sigprocmask(SIG_SETMASK, &oset, NULL);
+ errno = oerrno;
+ return (rv);
+}
+
+/*
+ * 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 (lseek64(in.fd,
+ (off64_t)in.offset * (off64_t)in.dbsz, SEEK_CUR) == -1) {
+ fprintf(stderr, "%s: seek error: %s",
+ in.name, strerror(errno));
+ exit(1);
+ /* 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 = read(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;
+ }
+ fprintf(stderr, "skip reached end of input\n");
+ exit(1);
+ /* 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) {
+
+ fprintf(stderr, "%s: error occurred\n",
+ in.name);
+ warned = 1;
+ summary();
+ }
+ continue;
+ }
+ fprintf(stderr, "%s: read error: %s", in.name, strerror(errno));
+ exit(1);
+ /* NOTREACHED */
+ }
+}
+
+void
+pos_out(void)
+{
+// struct mtop t_op;
+ int cnt, n;
+
+ /*
+ * 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 (lseek64(out.fd,
+ (off64_t)out.offset * (off64_t)out.dbsz, SEEK_SET) == -1) {
+ fprintf(stderr, "%s: seek error: %s\n",
+ out.name, strerror(errno));
+ exit(1);
+ /* 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 (ioctl(out.fd, MTIOCTOP, &t_op) < 0)*/
+ fprintf(stderr, "%s: cannot read", out.name);
+ exit(1);
+ /* NOTREACHED */
+ return;
+ }
+
+ /* Read it. */
+ for (cnt = 0; cnt < out.offset; ++cnt) {
+ if ((n = read(out.fd, out.db, out.dbsz)) > 0)
+ continue;
+
+ if (n < 0) {
+ fprintf(stderr, "%s: cannot position by reading: %s\n",
+ out.name, strerror(errno));
+ exit(1);
+ /* 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 (ioctl(out.fd, MTIOCTOP, &t_op) == -1) */ {
+ fprintf(stderr, "%s: cannot position\n", out.name);
+ exit(1);
+ /* NOTREACHED */
+ }
+
+ while (cnt++ < out.offset)
+ if ((n = bwrite(out.fd, out.db, out.dbsz)) != out.dbsz) {
+ fprintf(stderr, "%s: cannot position "
+ "by writing: %s\n",
+ out.name, strerror(errno));
+ exit(1);
+ /* NOTREACHED */
+ }
+ break;
+ }
+}
+
+/*
+ * 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)
+{
+ if (ddflags & C_FDATASYNC) {
+ fdatasync(out.fd);
+ }
+
+ /* 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?\n";
+void block(void) { fprintf(stderr, "%s", no_block + 2); exit(1); }
+void block_close(void) { fprintf(stderr, "%s", no_block + 2); exit(1); }
+void unblock(void) { fprintf(stderr, "%s", no_block); exit(1); }
+void unblock_close(void) { fprintf(stderr, "%s", no_block); exit(1); }
+#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 */
+
+#define tv2mS(tv) ((tv).tv_sec * 1000LL + ((tv).tv_usec + 500) / 1000)
+
+void
+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));
+}
+
+void
+terminate(int notused)
+{
+
+ exit(0);
+ /* NOTREACHED */
+}
+
+static int c_arg(const void *, const void *);
+#ifndef NO_CONV
+static int c_conv(const void *, const void *);
+#endif
+static void f_bs(char *);
+static void f_cbs(char *);
+static void f_conv(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 },
+ { "obs", f_obs, C_OBS, C_BS|C_OBS },
+ { "of", f_of, C_OF, C_OF },
+ { "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 ((arg = strchr(oper, '=')) == NULL) {
+ fprintf(stderr, "unknown operand %s\n", oper);
+ exit(1);
+ /* NOTREACHED */
+ }
+ *arg++ = '\0';
+ if (!*arg) {
+ fprintf(stderr, "no value specified for %s\n", oper);
+ exit(1);
+ /* NOTREACHED */
+ }
+ tmp.name = oper;
+ if (!(ap = (struct arg *)bsearch(&tmp, args,
+ sizeof(args)/sizeof(struct arg), sizeof(struct arg),
+ c_arg))) {
+ fprintf(stderr, "unknown operand %s\n", tmp.name);
+ exit(1);
+ /* NOTREACHED */
+ }
+ if (ddflags & ap->noset) {
+ fprintf(stderr,
+ "%s: illegal argument combination or already set\n",
+ tmp.name);
+ exit(1);
+ /* 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))
+ fprintf(stderr, "bs supersedes ibs and obs\n");
+ }
+
+ /*
+ * Ascii/ebcdic and cbs implies block/unblock.
+ * Block/unblock requires cbs and vice-versa.
+ */
+ if (ddflags & (C_BLOCK|C_UNBLOCK)) {
+ if (!(ddflags & C_CBS)) {
+ fprintf(stderr, "record operations require cbs\n");
+ exit(1);
+ /* 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 {
+ fprintf(stderr,
+ "cbs meaningless if not doing record operations\n");
+ exit(1);
+ /* 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 long long strsuftoll(const char* name, const char* arg, int def, unsigned long long max)
+{
+ long long result;
+
+ if (sscanf(arg, "%lld", &result) == 0)
+ result = def;
+ return result;
+}
+
+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;
+}
+
+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)
+{
+
+ if (*arg != '0')
+ progress = 1;
+}
+
+#ifdef NO_CONV
+/* Build a small version (i.e. for a ramdisk root) */
+static void
+f_conv(char *arg)
+{
+
+ fprintf(stderr, "conv option disabled\n");
+ exit(1);
+ /* NOTREACHED */
+}
+#else /* NO_CONV */
+
+static const struct conv {
+ const char *name;
+ u_int set, noset;
+ const u_char *ctab;
+} clist[] = {
+ { "block", C_BLOCK, C_UNBLOCK, NULL },
+ { "fdatasync", C_FDATASYNC, 0, NULL },
+ { "noerror", C_NOERROR, 0, NULL },
+ { "notrunc", C_NOTRUNC, 0, NULL },
+ { "osync", C_OSYNC, C_BS, NULL },
+ { "sparse", C_SPARSE, 0, NULL },
+ { "swab", C_SWAB, 0, NULL },
+ { "sync", C_SYNC, 0, 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 = (struct conv *)bsearch(&tmp, clist,
+ sizeof(clist)/sizeof(struct conv), sizeof(struct conv),
+ 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/package/toolbox/src/src/dd.h b/package/toolbox/src/src/dd.h
new file mode 100644
index 000000000..89f28332c
--- /dev/null
+++ b/package/toolbox/src/src/dd.h
@@ -0,0 +1,94 @@
+/* $NetBSD: dd.h,v 1.12 2004/01/17 20:48:57 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.
+ *
+ * @(#)dd.h 8.3 (Berkeley) 4/2/94
+ */
+
+#include <stdint.h>
+
+/* 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 */
+} 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
+#define C_FDATASYNC 0x400000
diff --git a/package/toolbox/src/src/df.c b/package/toolbox/src/src/df.c
new file mode 100644
index 000000000..8cff0c8c2
--- /dev/null
+++ b/package/toolbox/src/src/df.c
@@ -0,0 +1,85 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <sys/statfs.h>
+
+static int ok = EXIT_SUCCESS;
+
+static void printsize(long long n)
+{
+ char unit = 'K';
+ long long t;
+
+ n *= 10;
+
+ if (n > 1024*1024*10) {
+ n /= 1024;
+ unit = 'M';
+ }
+
+ if (n > 1024*1024*10) {
+ n /= 1024;
+ unit = 'G';
+ }
+
+ t = (n + 512) / 1024;
+ printf("%4lld.%1lld%c", t/10, t%10, unit);
+}
+
+static void df(char *s, int always) {
+ struct statfs st;
+
+ if (statfs(s, &st) < 0) {
+ fprintf(stderr, "%s: %s\n", s, strerror(errno));
+ ok = EXIT_FAILURE;
+ } else {
+ if (st.f_blocks == 0 && !always)
+ return;
+ printf("%-20s ", s);
+ printsize((long long)st.f_blocks * (long long)st.f_bsize);
+ printf(" ");
+ printsize((long long)(st.f_blocks - (long long)st.f_bfree) * st.f_bsize);
+ printf(" ");
+ printsize((long long)st.f_bfree * (long long)st.f_bsize);
+ printf(" %d\n", (int) st.f_bsize);
+ }
+}
+
+int main(int argc, char *argv[]) {
+ printf("Filesystem Size Used Free Blksize\n");
+ if (argc == 1) {
+ char s[2000];
+ FILE *f = fopen("/proc/mounts", "r");
+
+ while (fgets(s, 2000, f)) {
+ char *c, *e = s;
+
+ for (c = s; *c; c++) {
+ if (*c == ' ') {
+ e = c + 1;
+ break;
+ }
+ }
+
+ for (c = e; *c; c++) {
+ if (*c == ' ') {
+ *c = '\0';
+ break;
+ }
+ }
+
+ df(e, 0);
+ }
+
+ fclose(f);
+ } else {
+ int i;
+
+ for (i = 1; i < argc; i++) {
+ df(argv[i], 1);
+ }
+ }
+
+ exit(ok);
+}
diff --git a/package/toolbox/src/src/dmesg.c b/package/toolbox/src/src/dmesg.c
new file mode 100644
index 000000000..9fac63287
--- /dev/null
+++ b/package/toolbox/src/src/dmesg.c
@@ -0,0 +1,64 @@
+#include <stdlib.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <errno.h>
+#include <sys/klog.h>
+#include <string.h>
+
+#define FALLBACK_KLOG_BUF_SHIFT 17 /* CONFIG_LOG_BUF_SHIFT from our kernel */
+#define FALLBACK_KLOG_BUF_LEN (1 << FALLBACK_KLOG_BUF_SHIFT)
+
+#ifndef KLOG_SIZE_BUFFER
+#define KLOG_READ_ALL 3
+#define KLOG_READ_CLEAR 4
+#define KLOG_SIZE_BUFFER 10
+#endif
+
+int main(int argc, char **argv)
+{
+ char *buffer;
+ char *p;
+ ssize_t ret;
+ int n, op, klog_buf_len;
+
+ klog_buf_len = klogctl(KLOG_SIZE_BUFFER, 0, 0);
+
+ if (klog_buf_len <= 0) {
+ klog_buf_len = FALLBACK_KLOG_BUF_LEN;
+ }
+
+ buffer = (char *)malloc(klog_buf_len + 1);
+
+ if (!buffer) {
+ perror("malloc");
+ return EXIT_FAILURE;
+ }
+
+ p = buffer;
+
+ if((argc == 2) && (!strcmp(argv[1],"-c"))) {
+ op = KLOG_READ_CLEAR;
+ } else {
+ op = KLOG_READ_ALL;
+ }
+
+ n = klogctl(op, buffer, klog_buf_len);
+ if (n < 0) {
+ perror("klogctl");
+ return EXIT_FAILURE;
+ }
+ buffer[n] = '\0';
+
+ while((ret = write(STDOUT_FILENO, p, n))) {
+ if (ret == -1) {
+ if (errno == EINTR)
+ continue;
+ perror("write");
+ return EXIT_FAILURE;
+ }
+ p += ret;
+ n -= ret;
+ }
+
+ return 0;
+}
diff --git a/package/toolbox/src/src/du.c b/package/toolbox/src/src/du.c
new file mode 100644
index 000000000..8fd6b3644
--- /dev/null
+++ b/package/toolbox/src/src/du.c
@@ -0,0 +1,322 @@
+/* $NetBSD: du.c,v 1.33 2008/07/30 22:03:40 dsl 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
+ * Chris Newcomb.
+ *
+ * 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[] = "@(#)du.c 8.5 (Berkeley) 5/4/95";
+#else
+__RCSID("$NetBSD: du.c,v 1.33 2008/07/30 22:03:40 dsl Exp $");
+#endif
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <dirent.h>
+#include <err.h>
+#include <errno.h>
+#include <fts.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <limits.h>
+
+int linkchk(dev_t, ino_t);
+void prstat(const char *, int64_t);
+static void usage(void);
+
+long blocksize;
+
+#define howmany(x, y) (((x)+((y)-1))/(y))
+
+int
+main(int argc, char *argv[])
+{
+ FTS *fts;
+ FTSENT *p;
+ int64_t totalblocks;
+ int ftsoptions, listfiles;
+ int depth;
+ int Hflag, Lflag, aflag, ch, cflag, dflag, gkmflag, rval, sflag;
+ char *noargv[2];
+
+ Hflag = Lflag = aflag = cflag = dflag = gkmflag = sflag = 0;
+ totalblocks = 0;
+ ftsoptions = FTS_PHYSICAL;
+ depth = INT_MAX;
+ while ((ch = getopt(argc, argv, "HLPacd:ghkmnrsx")) != -1)
+ switch (ch) {
+ case 'H':
+ Hflag = 1;
+ Lflag = 0;
+ break;
+ case 'L':
+ Lflag = 1;
+ Hflag = 0;
+ break;
+ case 'P':
+ Hflag = Lflag = 0;
+ break;
+ case 'a':
+ aflag = 1;
+ break;
+ case 'c':
+ cflag = 1;
+ break;
+ case 'd':
+ dflag = 1;
+ depth = atoi(optarg);
+ if (depth < 0 || depth > SHRT_MAX) {
+ warnx("invalid argument to option d: %s",
+ optarg);
+ usage();
+ }
+ break;
+ case 'g':
+ blocksize = 1024 * 1024 * 1024;
+ gkmflag = 1;
+ break;
+ case 'k':
+ blocksize = 1024;
+ gkmflag = 1;
+ break;
+ case 'm':
+ blocksize = 1024 * 1024;
+ gkmflag = 1;
+ break;
+ case 'r':
+ break;
+ case 's':
+ sflag = 1;
+ break;
+ case 'x':
+ ftsoptions |= FTS_XDEV;
+ break;
+ case '?':
+ default:
+ usage();
+ }
+ argc -= optind;
+ argv += optind;
+
+ /*
+ * XXX
+ * Because of the way that fts(3) works, logical walks will not count
+ * the blocks actually used by symbolic links. We rationalize this by
+ * noting that users computing logical sizes are likely to do logical
+ * copies, so not counting the links is correct. The real reason is
+ * that we'd have to re-implement the kernel's symbolic link traversing
+ * algorithm to get this right. If, for example, you have relative
+ * symbolic links referencing other relative symbolic links, it gets
+ * very nasty, very fast. The bottom line is that it's documented in
+ * the man page, so it's a feature.
+ */
+ if (Hflag)
+ ftsoptions |= FTS_COMFOLLOW;
+ if (Lflag) {
+ ftsoptions &= ~FTS_PHYSICAL;
+ ftsoptions |= FTS_LOGICAL;
+ }
+
+ listfiles = 0;
+ if (aflag) {
+ if (sflag || dflag)
+ usage();
+ listfiles = 1;
+ } else if (sflag) {
+ if (dflag)
+ usage();
+ depth = 0;
+ }
+
+ if (!*argv) {
+ noargv[0] = strdup(".");
+ noargv[1] = NULL;
+ argv = noargv;
+ }
+
+ if (!gkmflag)
+ blocksize = 512;
+ blocksize /= 512;
+
+ if ((fts = fts_open(argv, ftsoptions, NULL)) == NULL)
+ err(1, "fts_open `%s'", *argv);
+
+ for (rval = 0; (p = fts_read(fts)) != NULL;) {
+ switch (p->fts_info) {
+ case FTS_D: /* Ignore. */
+ break;
+ case FTS_DP:
+ p->fts_parent->fts_number +=
+ p->fts_number += p->fts_statp->st_blocks;
+ if (cflag)
+ totalblocks += p->fts_statp->st_blocks;
+ /*
+ * If listing each directory, or not listing files
+ * or directories and this is post-order of the
+ * root of a traversal, display the total.
+ */
+ if (p->fts_level <= depth
+ || (!listfiles && !p->fts_level))
+ prstat(p->fts_path, p->fts_number);
+ break;
+ case FTS_DC: /* Ignore. */
+ break;
+ case FTS_DNR: /* Warn, continue. */
+ case FTS_ERR:
+ case FTS_NS:
+ warnx("%s: %s", p->fts_path, strerror(p->fts_errno));
+ rval = 1;
+ break;
+ default:
+ if (p->fts_statp->st_nlink > 1 &&
+ linkchk(p->fts_statp->st_dev, p->fts_statp->st_ino))
+ break;
+ /*
+ * If listing each file, or a non-directory file was
+ * the root of a traversal, display the total.
+ */
+ if (listfiles || !p->fts_level)
+ prstat(p->fts_path, p->fts_statp->st_blocks);
+ p->fts_parent->fts_number += p->fts_statp->st_blocks;
+ if (cflag)
+ totalblocks += p->fts_statp->st_blocks;
+ }
+ }
+ if (errno)
+ err(1, "fts_read");
+ if (cflag)
+ prstat("total", totalblocks);
+ exit(rval);
+}
+
+void
+prstat(const char *fname, int64_t blocks)
+{
+ (void)printf("%lld\t%s\n",
+ (long long)howmany(blocks, (int64_t)blocksize),
+ fname);
+}
+
+int
+linkchk(dev_t dev, ino_t ino)
+{
+ static struct entry {
+ dev_t dev;
+ ino_t ino;
+ } *htable;
+ static int htshift; /* log(allocated size) */
+ static int htmask; /* allocated size - 1 */
+ static int htused; /* 2*number of insertions */
+ static int sawzero; /* Whether zero is in table or not */
+ int h, h2;
+ uint64_t tmp;
+ /* this constant is (1<<64)/((1+sqrt(5))/2)
+ * aka (word size)/(golden ratio)
+ */
+ const uint64_t HTCONST = 11400714819323198485ULL;
+ const int HTBITS = CHAR_BIT * sizeof(tmp);
+
+ /* Never store zero in hashtable */
+ if (dev == 0 && ino == 0) {
+ h = sawzero;
+ sawzero = 1;
+ return h;
+ }
+
+ /* Extend hash table if necessary, keep load under 0.5 */
+ if (htused<<1 >= htmask) {
+ struct entry *ohtable;
+
+ if (!htable)
+ htshift = 10; /* starting hashtable size */
+ else
+ htshift++; /* exponential hashtable growth */
+
+ htmask = (1 << htshift) - 1;
+ htused = 0;
+
+ ohtable = htable;
+ htable = calloc(htmask+1, sizeof(*htable));
+ if (!htable)
+ err(1, "calloc");
+
+ /* populate newly allocated hashtable */
+ if (ohtable) {
+ int i;
+ for (i = 0; i <= htmask>>1; i++)
+ if (ohtable[i].ino || ohtable[i].dev)
+ linkchk(ohtable[i].dev, ohtable[i].ino);
+ free(ohtable);
+ }
+ }
+
+ /* multiplicative hashing */
+ tmp = dev;
+ tmp <<= HTBITS>>1;
+ tmp |= ino;
+ tmp *= HTCONST;
+ h = tmp >> (HTBITS - htshift);
+ h2 = 1 | ( tmp >> (HTBITS - (htshift<<1) - 1)); /* must be odd */
+
+ /* open address hashtable search with double hash probing */
+ while (htable[h].ino || htable[h].dev) {
+ if ((htable[h].ino == ino) && (htable[h].dev == dev))
+ return 1;
+ h = (h + h2) & htmask;
+ }
+
+ /* Insert the current entry into hashtable */
+ htable[h].dev = dev;
+ htable[h].ino = ino;
+ htused++;
+ return 0;
+}
+
+static void
+usage(void)
+{
+
+ (void)fprintf(stderr,
+ "usage: du [-H | -L | -P] [-a | -d depth | -s] [-cgkmrx] [file ...]\n");
+ exit(1);
+}
diff --git a/package/toolbox/src/src/dynarray.c b/package/toolbox/src/src/dynarray.c
new file mode 100644
index 000000000..3714542e6
--- /dev/null
+++ b/package/toolbox/src/src/dynarray.c
@@ -0,0 +1,104 @@
+#include "dynarray.h"
+#include <stdlib.h>
+#include <string.h>
+#include <limits.h>
+
+void
+dynarray_init( dynarray_t *a )
+{
+ a->count = a->capacity = 0;
+ a->items = NULL;
+}
+
+
+static void
+dynarray_reserve_more( dynarray_t *a, int count )
+{
+ int old_cap = a->capacity;
+ int new_cap = old_cap;
+ const int max_cap = INT_MAX/sizeof(void*);
+ void** new_items;
+ int new_count = a->count + count;
+
+ if (count <= 0)
+ return;
+
+ if (count > max_cap - a->count)
+ abort();
+
+ new_count = a->count + count;
+
+ while (new_cap < new_count) {
+ old_cap = new_cap;
+ new_cap += (new_cap >> 2) + 4;
+ if (new_cap < old_cap || new_cap > max_cap) {
+ new_cap = max_cap;
+ }
+ }
+ new_items = realloc(a->items, new_cap*sizeof(void*));
+ if (new_items == NULL)
+ abort();
+
+ a->items = new_items;
+ a->capacity = new_cap;
+}
+
+void
+dynarray_append( dynarray_t *a, void* item )
+{
+ if (a->count >= a->capacity)
+ dynarray_reserve_more(a, 1);
+
+ a->items[a->count++] = item;
+}
+
+void
+dynarray_done( dynarray_t *a )
+{
+ free(a->items);
+ a->items = NULL;
+ a->count = a->capacity = 0;
+}
+
+// string arrays
+
+void strlist_init( strlist_t *list )
+{
+ dynarray_init(list);
+}
+
+void strlist_append_b( strlist_t *list, const void* str, size_t slen )
+{
+ char *copy = malloc(slen+1);
+ memcpy(copy, str, slen);
+ copy[slen] = '\0';
+ dynarray_append(list, copy);
+}
+
+void strlist_append_dup( strlist_t *list, const char *str)
+{
+ strlist_append_b(list, str, strlen(str));
+}
+
+void strlist_done( strlist_t *list )
+{
+ STRLIST_FOREACH(list, string, free(string));
+ dynarray_done(list);
+}
+
+static int strlist_compare_strings(const void* a, const void* b)
+{
+ const char *sa = *(const char **)a;
+ const char *sb = *(const char **)b;
+ return strcmp(sa, sb);
+}
+
+void strlist_sort( strlist_t *list )
+{
+ if (list->count > 0) {
+ qsort(list->items,
+ (size_t)list->count,
+ sizeof(void*),
+ strlist_compare_strings);
+ }
+}
diff --git a/package/toolbox/src/src/dynarray.h b/package/toolbox/src/src/dynarray.h
new file mode 100644
index 000000000..f73fb3b9c
--- /dev/null
+++ b/package/toolbox/src/src/dynarray.h
@@ -0,0 +1,80 @@
+#ifndef DYNARRAY_H
+#define DYNARRAY_H
+
+#include <stddef.h>
+
+/* simple dynamic array of pointers */
+typedef struct {
+ int count;
+ int capacity;
+ void** items;
+} dynarray_t;
+
+#define DYNARRAY_INITIALIZER { 0, 0, NULL }
+
+void dynarray_init( dynarray_t *a );
+void dynarray_done( dynarray_t *a );
+
+void dynarray_append( dynarray_t *a, void* item );
+
+/* Used to iterate over a dynarray_t
+ * _array :: pointer to the array
+ * _item_type :: type of objects pointed to by the array
+ * _item :: name of a local variable defined within the loop
+ * with type '_item_type'
+ * _stmnt :: C statement that will be executed in each iteration.
+ *
+ * You case use 'break' and 'continue' within _stmnt
+ *
+ * This macro is only intended for simple uses. I.e. do not add or
+ * remove items from the array during iteration.
+ */
+#define DYNARRAY_FOREACH_TYPE(_array,_item_type,_item,_stmnt) \
+ do { \
+ int _nn_##__LINE__ = 0; \
+ for (;_nn_##__LINE__ < (_array)->count; ++ _nn_##__LINE__) { \
+ _item_type _item = (_item_type)(_array)->items[_nn_##__LINE__]; \
+ _stmnt; \
+ } \
+ } while (0)
+
+#define DYNARRAY_FOREACH(_array,_item,_stmnt) \
+ DYNARRAY_FOREACH_TYPE(_array,void *,_item,_stmnt)
+
+/* Simple dynamic string arrays
+ *
+ * NOTE: A strlist_t owns the strings it references.
+ */
+typedef dynarray_t strlist_t;
+
+#define STRLIST_INITIALIZER DYNARRAY_INITIALIZER
+
+/* Used to iterate over a strlist_t
+ * _list :: pointer to strlist_t object
+ * _string :: name of local variable name defined within the loop with
+ * type 'char*'
+ * _stmnt :: C statement executed in each iteration
+ *
+ * This macro is only intended for simple uses. Do not add or remove items
+ * to/from the list during iteration.
+ */
+#define STRLIST_FOREACH(_list,_string,_stmnt) \
+ DYNARRAY_FOREACH_TYPE(_list,char *,_string,_stmnt)
+
+void strlist_init( strlist_t *list );
+
+/* note: strlist_done will free all the strings owned by the list */
+void strlist_done( strlist_t *list );
+
+/* append a new string made of the first 'slen' characters from 'str'
+ * followed by a trailing zero.
+ */
+void strlist_append_b( strlist_t *list, const void* str, size_t slen );
+
+/* append the copy of a given input string to a strlist_t */
+void strlist_append_dup( strlist_t *list, const char *str);
+
+/* sort the strings in a given list (using strcmp) */
+void strlist_sort( strlist_t *list );
+
+#endif /* DYNARRAY_H */ \ No newline at end of file
diff --git a/package/toolbox/src/src/exists.c b/package/toolbox/src/src/exists.c
new file mode 100644
index 000000000..59c2a272b
--- /dev/null
+++ b/package/toolbox/src/src/exists.c
@@ -0,0 +1,16 @@
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+int main(int argc, char *argv[])
+{
+ struct stat s;
+
+ if(argc < 2) return 1;
+
+ if(stat(argv[1], &s)) {
+ return 1;
+ } else {
+ return 0;
+ }
+}
diff --git a/package/toolbox/src/src/hd.c b/package/toolbox/src/src/hd.c
new file mode 100644
index 000000000..333042fca
--- /dev/null
+++ b/package/toolbox/src/src/hd.c
@@ -0,0 +1,97 @@
+#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 fd;
+ unsigned char buf[4096];
+ int res;
+ int read_len;
+ int i;
+ int filepos = 0;
+ int sum;
+ int lsum;
+
+ int base = -1;
+ int count = 0;
+ int repeat = 0;
+
+ do {
+ c = getopt(argc, argv, "b:c:r:");
+ if (c == EOF)
+ break;
+ switch (c) {
+ case 'b':
+ base = strtol(optarg, NULL, 0);
+ break;
+ case 'c':
+ count = strtol(optarg, NULL, 0);
+ break;
+ case 'r':
+ repeat = strtol(optarg, NULL, 0);
+ break;
+ case '?':
+ fprintf(stderr, "%s: invalid option -%c\n",
+ argv[0], optopt);
+ exit(1);
+ }
+ } while (1);
+
+ if (optind + 1 != argc) {
+ fprintf(stderr, "Usage: %s [-b base] [-c count] [-r delay] file\n", argv[0]);
+ exit(1);
+ }
+
+ fd = open(argv[optind], O_RDONLY);
+ if(fd < 0) {
+ fprintf(stderr, "could not open %s, %s\n", argv[optind], strerror(errno));
+ return 1;
+ }
+
+ do {
+ if(base >= 0) {
+ lseek(fd, base, SEEK_SET);
+ filepos = base;
+ }
+ sum = 0;
+ lsum = 0;
+ while(1) {
+ read_len = sizeof(buf);
+ if(count > 0 && base + count - filepos < read_len)
+ read_len = base + count - filepos;
+ res = read(fd, &buf, read_len);
+ if(res == 0)
+ break;
+ for(i = 0; i < res; i++) {
+ if((i & 15) == 0) {
+ printf("%08x: ", filepos + i);
+ }
+ lsum += buf[i];
+ sum += buf[i];
+ printf("%02x ", buf[i]);
+ if(((i & 15) == 15) || (i == res - 1)) {
+ printf("s %x\n", lsum);
+ lsum = 0;
+ }
+ }
+ if(res < 0) {
+ printf("Read error on %s, offset %d len %d, %s\n", argv[optind], filepos, read_len, strerror(errno));
+ return 1;
+ }
+ filepos += res;
+ if(filepos == base + count)
+ break;
+ }
+ printf("sum %x\n", sum);
+ if(repeat)
+ sleep(repeat);
+ } while(repeat);
+ return 0;
+}
diff --git a/package/toolbox/src/src/id.c b/package/toolbox/src/src/id.c
new file mode 100644
index 000000000..60c0f0f6d
--- /dev/null
+++ b/package/toolbox/src/src/id.c
@@ -0,0 +1,51 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <pwd.h>
+#include <grp.h>
+
+static void print_uid(uid_t uid)
+{
+ struct passwd *pw = getpwuid(uid);
+
+ if (pw) {
+ printf("%d(%s)", uid, pw->pw_name);
+ } else {
+ printf("%d",uid);
+ }
+}
+
+static void print_gid(gid_t gid)
+{
+ struct group *gr = getgrgid(gid);
+ if (gr) {
+ printf("%d(%s)", gid, gr->gr_name);
+ } else {
+ printf("%d",gid);
+ }
+}
+
+int main(int argc, char **argv)
+{
+ gid_t list[64];
+ int n, max;
+
+ max = getgroups(64, list);
+ if (max < 0) max = 0;
+
+ printf("uid=");
+ print_uid(getuid());
+ printf(" gid=");
+ print_gid(getgid());
+ if (max) {
+ printf(" groups=");
+ print_gid(list[0]);
+ for(n = 1; n < max; n++) {
+ printf(",");
+ print_gid(list[n]);
+ }
+ }
+ printf("\n");
+ return 0;
+}
diff --git a/package/toolbox/src/src/ifconfig.c b/package/toolbox/src/src/ifconfig.c
new file mode 100644
index 000000000..510d3b555
--- /dev/null
+++ b/package/toolbox/src/src/ifconfig.c
@@ -0,0 +1,164 @@
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include <errno.h>
+#include <string.h>
+#include <ctype.h>
+
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <linux/if.h>
+#include <linux/sockios.h>
+#include <arpa/inet.h>
+
+static void die(const char *s)
+{
+ fprintf(stderr,"error: %s (%s)\n", s, strerror(errno));
+ exit(-1);
+}
+
+static void setflags(int s, struct ifreq *ifr, int set, int clr)
+{
+ if(ioctl(s, SIOCGIFFLAGS, ifr) < 0) die("SIOCGIFFLAGS");
+ ifr->ifr_flags = (ifr->ifr_flags & (~clr)) | set;
+ if(ioctl(s, SIOCSIFFLAGS, ifr) < 0) die("SIOCSIFFLAGS");
+}
+
+static inline void init_sockaddr_in(struct sockaddr_in *sin, const char *addr)
+{
+ sin->sin_family = AF_INET;
+ sin->sin_port = 0;
+ sin->sin_addr.s_addr = inet_addr(addr);
+}
+
+static void setmtu(int s, struct ifreq *ifr, const char *mtu)
+{
+ int m = atoi(mtu);
+ ifr->ifr_mtu = m;
+ if(ioctl(s, SIOCSIFMTU, ifr) < 0) die("SIOCSIFMTU");
+}
+static void setdstaddr(int s, struct ifreq *ifr, const char *addr)
+{
+ init_sockaddr_in((struct sockaddr_in *) &ifr->ifr_dstaddr, addr);
+ if(ioctl(s, SIOCSIFDSTADDR, ifr) < 0) die("SIOCSIFDSTADDR");
+}
+
+static void setnetmask(int s, struct ifreq *ifr, const char *addr)
+{
+ init_sockaddr_in((struct sockaddr_in *) &ifr->ifr_netmask, addr);
+ if(ioctl(s, SIOCSIFNETMASK, ifr) < 0) die("SIOCSIFNETMASK");
+}
+
+static void setaddr(int s, struct ifreq *ifr, const char *addr)
+{
+ init_sockaddr_in((struct sockaddr_in *) &ifr->ifr_addr, addr);
+ if(ioctl(s, SIOCSIFADDR, ifr) < 0) die("SIOCSIFADDR");
+}
+
+int main(int argc, char *argv[])
+{
+ struct ifreq ifr;
+ int s;
+ unsigned int addr, mask, flags;
+ char astring[20];
+ char mstring[20];
+ char *updown, *brdcst, *loopbk, *ppp, *running, *multi;
+
+ argc--;
+ argv++;
+
+ if(argc == 0) return 0;
+
+ memset(&ifr, 0, sizeof(struct ifreq));
+ strncpy(ifr.ifr_name, argv[0], IFNAMSIZ);
+ ifr.ifr_name[IFNAMSIZ-1] = 0;
+ argc--, argv++;
+
+ if((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
+ die("cannot open control socket\n");
+ }
+
+ if (argc == 0) {
+ if (ioctl(s, SIOCGIFADDR, &ifr) < 0) {
+ perror(ifr.ifr_name);
+ return -1;
+ } else
+ addr = ((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr.s_addr;
+
+ if (ioctl(s, SIOCGIFNETMASK, &ifr) < 0) {
+ perror(ifr.ifr_name);
+ return -1;
+ } else
+ mask = ((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr.s_addr;
+
+ if (ioctl(s, SIOCGIFFLAGS, &ifr) < 0) {
+ perror(ifr.ifr_name);
+ return -1;
+ } else
+ flags = ifr.ifr_flags;
+
+ sprintf(astring, "%d.%d.%d.%d",
+ addr & 0xff,
+ ((addr >> 8) & 0xff),
+ ((addr >> 16) & 0xff),
+ ((addr >> 24) & 0xff));
+ sprintf(mstring, "%d.%d.%d.%d",
+ mask & 0xff,
+ ((mask >> 8) & 0xff),
+ ((mask >> 16) & 0xff),
+ ((mask >> 24) & 0xff));
+ printf("%s: ip %s mask %s flags [", ifr.ifr_name,
+ astring,
+ mstring
+ );
+
+ updown = (flags & IFF_UP) ? "up" : "down";
+ brdcst = (flags & IFF_BROADCAST) ? " broadcast" : "";
+ loopbk = (flags & IFF_LOOPBACK) ? " loopback" : "";
+ ppp = (flags & IFF_POINTOPOINT) ? " point-to-point" : "";
+ running = (flags & IFF_RUNNING) ? " running" : "";
+ multi = (flags & IFF_MULTICAST) ? " multicast" : "";
+ printf("%s%s%s%s%s%s]\n", updown, brdcst, loopbk, ppp, running, multi);
+ return 0;
+ }
+
+ while(argc > 0) {
+ if (!strcmp(argv[0], "up")) {
+ setflags(s, &ifr, IFF_UP, 0);
+ } else if (!strcmp(argv[0], "mtu")) {
+ argc--, argv++;
+ if (!argc) {
+ errno = EINVAL;
+ die("expecting a value for parameter \"mtu\"");
+ }
+ setmtu(s, &ifr, argv[0]);
+ } else if (!strcmp(argv[0], "-pointopoint")) {
+ setflags(s, &ifr, IFF_POINTOPOINT, 1);
+ } else if (!strcmp(argv[0], "pointopoint")) {
+ argc--, argv++;
+ if (!argc) {
+ errno = EINVAL;
+ die("expecting an IP address for parameter \"pointtopoint\"");
+ }
+ setdstaddr(s, &ifr, argv[0]);
+ setflags(s, &ifr, IFF_POINTOPOINT, 0);
+ } else if (!strcmp(argv[0], "down")) {
+ setflags(s, &ifr, 0, IFF_UP);
+ } else if (!strcmp(argv[0], "netmask")) {
+ argc--, argv++;
+ if (!argc) {
+ errno = EINVAL;
+ die("expecting an IP address for parameter \"netmask\"");
+ }
+ setnetmask(s, &ifr, argv[0]);
+ } else if (isdigit(argv[0][0])) {
+ setaddr(s, &ifr, argv[0]);
+ setflags(s, &ifr, IFF_UP, 0);
+ }
+ argc--, argv++;
+ }
+ return 0;
+}
diff --git a/package/toolbox/src/src/iftop.c b/package/toolbox/src/src/iftop.c
new file mode 100644
index 000000000..7bb946895
--- /dev/null
+++ b/package/toolbox/src/src/iftop.c
@@ -0,0 +1,278 @@
+/*
+ * Copyright (c) 2008, 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 <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <net/if.h>
+
+#define PROC_NET_DEV "/proc/net/dev"
+
+#define MAX_IF 8 /* max interfaces we can handle */
+
+#ifndef PAGE_SIZE
+# define PAGE_SIZE 4096
+#endif
+
+#define _STR(s) #s
+#define STR(s) _STR(s)
+
+struct if_stats {
+ char name[IFNAMSIZ];
+
+ unsigned int mtu;
+
+ unsigned int rx_bytes;
+ unsigned int rx_packets;
+ unsigned int rx_errors;
+ unsigned int rx_dropped;
+
+ unsigned int tx_bytes;
+ unsigned int tx_packets;
+ unsigned int tx_errors;
+ unsigned int tx_dropped;
+};
+
+static int get_mtu(const char *if_name)
+{
+ struct ifreq ifr;
+ int s, ret;
+
+ s = socket(AF_INET, SOCK_DGRAM, 0);
+ if (s < 0) {
+ perror("socket");
+ exit(EXIT_FAILURE);
+ }
+
+ memset(&ifr, 0, sizeof(struct ifreq));
+ ifr.ifr_addr.sa_family = AF_INET;
+ strcpy(ifr.ifr_name, if_name);
+
+ ret = ioctl(s, SIOCGIFMTU, &ifr);
+ if (ret < 0) {
+ perror("ioctl");
+ exit(EXIT_FAILURE);
+ }
+
+ ret = close(s);
+ if (ret < 0) {
+ perror("close");
+ exit(EXIT_FAILURE);
+ }
+
+ return ifr.ifr_mtu;
+}
+
+static int get_interfaces(struct if_stats *ifs)
+{
+ char buf[PAGE_SIZE];
+ char *p;
+ int ret, nr, fd;
+
+ fd = open(PROC_NET_DEV, O_RDONLY);
+ if (fd < 0) {
+ perror("open");
+ exit(EXIT_FAILURE);
+ }
+
+ ret = read(fd, buf, sizeof(buf) - 1);
+ if (ret < 0) {
+ perror("read");
+ exit(EXIT_FAILURE);
+ } else if (!ret) {
+ fprintf(stderr, "reading " PROC_NET_DEV " returned premature EOF\n");
+ exit(EXIT_FAILURE);
+ }
+ buf[ret] = '\0';
+
+ /* skip down to the third line */
+ p = strchr(buf, '\n');
+ if (!p) {
+ fprintf(stderr, "parsing " PROC_NET_DEV " failed unexpectedly\n");
+ exit(EXIT_FAILURE);
+ }
+ p = strchr(p + 1, '\n');
+ if (!p) {
+ fprintf(stderr, "parsing " PROC_NET_DEV " failed unexpectedly\n");
+ exit(EXIT_FAILURE);
+ }
+ p += 1;
+
+ /*
+ * Key:
+ * if: (Rx) bytes packets errs drop fifo frame compressed multicast \
+ * (Tx) bytes packets errs drop fifo colls carrier compressed
+ */
+ for (nr = 0; nr < MAX_IF; nr++) {
+ char *c;
+
+ ret = sscanf(p, "%" STR(IFNAMSIZ) "s", ifs->name);
+ if (ret != 1) {
+ fprintf(stderr, "parsing " PROC_NET_DEV " failed unexpectedly\n");
+ exit(EXIT_FAILURE);
+ }
+
+ /*
+ * This works around a bug in the proc file where large interface names
+ * or Rx byte counts eat the delimiter, breaking sscanf.
+ */
+ c = strchr(ifs->name, ':');
+ if (c)
+ *c = '\0';
+
+ p = strchr(p, ':') + 1;
+
+ ret = sscanf(p, "%u %u %u %u %*u %*u %*u %*u %u %u %u %u %*u %*u "
+ "%*u %*u\n", &ifs->rx_bytes, &ifs->rx_packets,
+ &ifs->rx_errors, &ifs->rx_dropped, &ifs->tx_bytes,
+ &ifs->tx_packets, &ifs->tx_errors, &ifs->tx_dropped);
+ if (ret != 8) {
+ fprintf(stderr, "parsing " PROC_NET_DEV " failed unexpectedly\n");
+ exit(EXIT_FAILURE);
+ }
+
+ ifs->mtu = get_mtu(ifs->name);
+
+ p = strchr(p, '\n') + 1;
+ if (*p == '\0') {
+ nr++;
+ break;
+ }
+
+ ifs++;
+ }
+
+ ret = close(fd);
+ if (ret) {
+ perror("close");
+ exit(EXIT_FAILURE);
+ }
+
+ return nr;
+}
+
+static void print_header(void)
+{
+ printf(" Rx Tx\n");
+ printf("%-8s %-5s %-10s %-8s %-5s %-5s %-10s %-8s %-5s %-5s\n",
+ "name", "MTU", "bytes", "packets", "errs", "drpd", "bytes",
+ "packets", "errs", "drpd");
+}
+
+static int print_interfaces(struct if_stats *old, struct if_stats *new, int nr)
+{
+ int i = 0;
+
+ while (nr--) {
+ if (old->rx_packets || old->tx_packets) {
+ printf("%-8s %-5u %-10u %-8u %-5u %-5u %-10u %-8u %-5u %-5u\n",
+ new->name, new->mtu,
+ new->rx_bytes - old->rx_bytes,
+ new->rx_packets - old->rx_packets,
+ new->rx_errors - old->rx_errors,
+ new->rx_dropped - old->rx_dropped,
+ new->tx_bytes - old->tx_bytes,
+ new->tx_packets - old->tx_packets,
+ new->tx_errors - old->tx_errors,
+ new->tx_dropped - old->tx_dropped);
+ i++;
+ }
+ old++;
+ new++;
+ }
+
+ return i;
+}
+
+static void usage(const char *cmd)
+{
+ fprintf(stderr, "usage: %s [ -r repeats] [ -d delay ]\n", cmd);
+}
+
+int main(int argc, char *argv[])
+{
+ struct if_stats ifs[2][MAX_IF];
+ int count = 0, header_interval = 22, delay = 1, i;
+ unsigned int toggle = 0;
+
+ for (i = 1; i < argc; i++) {
+ if (!strcmp(argv[i], "-d")) {
+ if (i >= argc - 1) {
+ fprintf(stderr, "Option -d requires an argument.\n");
+ exit(EXIT_FAILURE);
+ }
+ delay = atoi(argv[i++]);
+ if (!delay)
+ delay = 1;
+ continue;
+ }
+ if (!strcmp(argv[i], "-r")) {
+ if (i >= argc - 1) {
+ fprintf(stderr, "Option -r requires an argument.\n");
+ exit(EXIT_FAILURE);
+ }
+ header_interval = atoi(argv[i++]);
+ if (header_interval < MAX_IF)
+ header_interval = MAX_IF;
+ continue;
+ }
+ if (!strcmp(argv[i], "-h")) {
+ usage(argv[0]);
+ exit(EXIT_SUCCESS);
+ }
+ usage(argv[0]);
+ exit(EXIT_FAILURE);
+ }
+
+ get_interfaces(ifs[!toggle]);
+ if (header_interval)
+ print_header();
+ while (1) {
+ int nr;
+
+ sleep(delay);
+ nr = get_interfaces(ifs[toggle]);
+ if (header_interval && count + nr > header_interval) {
+ print_header();
+ count = 0;
+ }
+ count += print_interfaces(ifs[!toggle], ifs[toggle], nr);
+ toggle = !toggle;
+ }
+
+ return 0;
+}
diff --git a/package/toolbox/src/src/insmod.c b/package/toolbox/src/src/insmod.c
new file mode 100644
index 000000000..22e3d6160
--- /dev/null
+++ b/package/toolbox/src/src/insmod.c
@@ -0,0 +1,97 @@
+#include <stdio.h>
+#include <string.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <malloc.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+extern int init_module(void *, unsigned long, const char *);
+
+static void *read_file(const char *filename, ssize_t *_size)
+{
+ int ret, fd;
+ struct stat sb;
+ ssize_t size;
+ void *buffer = NULL;
+
+ /* open the file */
+ fd = open(filename, O_RDONLY);
+ if (fd < 0)
+ return NULL;
+
+ /* find out how big it is */
+ if (fstat(fd, &sb) < 0)
+ goto bail;
+ size = sb.st_size;
+
+ /* allocate memory for it to be read into */
+ buffer = malloc(size);
+ if (!buffer)
+ goto bail;
+
+ /* slurp it into our buffer */
+ ret = read(fd, buffer, size);
+ if (ret != size)
+ goto bail;
+
+ /* let the caller know how big it is */
+ *_size = size;
+
+bail:
+ close(fd);
+ return buffer;
+}
+
+#define min(x,y) ((x) < (y) ? (x) : (y))
+int main(int argc, char **argv)
+{
+ void *file;
+ ssize_t size = 0;
+ char opts[1024];
+ int ret;
+
+ /* make sure we've got an argument */
+ if (argc < 2) {
+ fprintf(stderr, "usage: insmod <module.o>\n");
+ return -1;
+ }
+
+ /* read the file into memory */
+ file = read_file(argv[1], &size);
+ if (!file) {
+ fprintf(stderr, "insmod: can't open '%s'\n", argv[1]);
+ return -1;
+ }
+
+ opts[0] = '\0';
+ if (argc > 2) {
+ int i, len;
+ char *end = opts + sizeof(opts) - 1;
+ char *ptr = opts;
+
+ for (i = 2; (i < argc) && (ptr < end); i++) {
+ len = min(strlen(argv[i]), end - ptr);
+ memcpy(ptr, argv[i], len);
+ ptr += len;
+ *ptr++ = ' ';
+ }
+ *(ptr - 1) = '\0';
+ }
+
+ /* pass it to the kernel */
+ ret = init_module(file, size, opts);
+ if (ret != 0) {
+ fprintf(stderr,
+ "insmod: init_module '%s' failed (%s)\n",
+ argv[1], strerror(errno));
+ }
+
+ /* free the file buffer */
+ free(file);
+
+ return ret;
+}
+
diff --git a/package/toolbox/src/src/ioctl.c b/package/toolbox/src/src/ioctl.c
new file mode 100644
index 000000000..abc1bec79
--- /dev/null
+++ b/package/toolbox/src/src/ioctl.c
@@ -0,0 +1,124 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <fcntl.h>
+#include <getopt.h>
+#include <string.h>
+#include <linux/kd.h>
+#include <linux/vt.h>
+#include <errno.h>
+#include <pthread.h>
+#include <sys/ioctl.h>
+
+int main(int argc, char *argv[])
+{
+ int c;
+ int fd;
+ int res;
+
+ int length = -1;
+ int arg_size = 4;
+ int direct_arg = 0;
+ uint32_t ioctl_nr;
+ void *ioctl_args = NULL;
+ uint8_t *ioctl_argp;
+ uint8_t *ioctl_argp_save = NULL;
+ int rem;
+
+ do {
+ c = getopt(argc, argv, "rdl:a:h");
+ if (c == EOF)
+ break;
+ switch (c) {
+ case 'd':
+ direct_arg = 1;
+ break;
+ case 'l':
+ length = strtol(optarg, NULL, 0);
+ break;
+ case 'a':
+ arg_size = strtol(optarg, NULL, 0);
+ break;
+ case 'h':
+ fprintf(stderr, "%s [-l <length>] [-a <argsize>] [-rdh] <device> <ioctlnr>\n"
+ " -l <lenght> Length of io buffer\n"
+ " -a <argsize> Size of each argument (1-8)\n"
+ " -r Open device in read only mode\n"
+ " -d Direct argument (no iobuffer)\n"
+ " -h Print help\n", argv[0]);
+ return -1;
+ case '?':
+ fprintf(stderr, "%s: invalid option -%c\n",
+ argv[0], optopt);
+ exit(1);
+ }
+ } while (1);
+
+ if(optind + 2 > argc) {
+ fprintf(stderr, "%s: too few arguments\n", argv[0]);
+ exit(1);
+ }
+
+ fd = open(argv[optind], O_RDWR | O_SYNC);
+ if (fd < 0) {
+ fprintf(stderr, "cannot open %s\n", argv[optind]);
+ return 1;
+ }
+ optind++;
+
+ ioctl_nr = strtol(argv[optind], NULL, 0);
+ optind++;
+
+ if(direct_arg) {
+ arg_size = 4;
+ length = 4;
+ }
+
+ if(length < 0) {
+ length = (argc - optind) * arg_size;
+ }
+ if(length) {
+ ioctl_args = calloc(1, length);
+
+ ioctl_argp_save = ioctl_argp = ioctl_args;
+ rem = length;
+ while(optind < argc) {
+ uint64_t tmp = strtoull(argv[optind], NULL, 0);
+ if(rem < arg_size) {
+ fprintf(stderr, "%s: too many arguments\n", argv[0]);
+ exit(1);
+ }
+ memcpy(ioctl_argp, &tmp, arg_size);
+ ioctl_argp += arg_size;
+ rem -= arg_size;
+ optind++;
+ }
+ }
+ printf("sending ioctl 0x%x", ioctl_nr);
+ rem = length;
+ while(rem--) {
+ printf(" 0x%02x", *ioctl_argp_save++);
+ }
+ printf("\n");
+
+ if(direct_arg)
+ res = ioctl(fd, ioctl_nr, *(uint32_t*)ioctl_args);
+ else if(length)
+ res = ioctl(fd, ioctl_nr, ioctl_args);
+ else
+ res = ioctl(fd, ioctl_nr, 0);
+ if (res < 0) {
+ fprintf(stderr, "ioctl 0x%x failed, %d\n", ioctl_nr, res);
+ return 1;
+ }
+ if(length) {
+ printf("return buf:");
+ ioctl_argp = ioctl_args;
+ rem = length;
+ while(rem--) {
+ printf(" %02x", *ioctl_argp++);
+ }
+ printf("\n");
+ }
+ return 0;
+}
diff --git a/package/toolbox/src/src/kill.c b/package/toolbox/src/src/kill.c
new file mode 100644
index 000000000..994ad31b2
--- /dev/null
+++ b/package/toolbox/src/src/kill.c
@@ -0,0 +1,149 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+#include <sys/types.h>
+#include <signal.h>
+
+static struct {
+ unsigned int number;
+ char *name;
+} signals[] = {
+#define _SIG(name) {SIG##name, #name}
+ /* Single Unix Specification signals */
+ _SIG(ABRT),
+ _SIG(ALRM),
+ _SIG(FPE),
+ _SIG(HUP),
+ _SIG(ILL),
+ _SIG(INT),
+ _SIG(KILL),
+ _SIG(PIPE),
+ _SIG(QUIT),
+ _SIG(SEGV),
+ _SIG(TERM),
+ _SIG(USR1),
+ _SIG(USR2),
+ _SIG(CHLD),
+ _SIG(CONT),
+ _SIG(STOP),
+ _SIG(TSTP),
+ _SIG(TTIN),
+ _SIG(TTOU),
+ _SIG(BUS),
+ _SIG(POLL),
+ _SIG(PROF),
+ _SIG(SYS),
+ _SIG(TRAP),
+ _SIG(URG),
+ _SIG(VTALRM),
+ _SIG(XCPU),
+ _SIG(XFSZ),
+ /* non-SUS signals */
+ _SIG(IO),
+ _SIG(PWR),
+#ifdef SIGSTKFLT
+ _SIG(STKFLT),
+#endif
+ _SIG(WINCH),
+#undef _SIG
+};
+
+/* To indicate a matching signal was not found */
+static const unsigned int SENTINEL = (unsigned int) -1;
+
+void list_signals()
+{
+ unsigned int sorted_signals[_NSIG];
+ unsigned int i;
+ unsigned int num;
+
+ memset(sorted_signals, SENTINEL, sizeof(sorted_signals));
+
+ // Sort the signals
+ for (i = 0; i < sizeof(signals)/sizeof(signals[0]); i++) {
+ sorted_signals[signals[i].number] = i;
+ }
+
+ num = 0;
+ for (i = 1; i < _NSIG; i++) {
+ unsigned int index = sorted_signals[i];
+ if (index == SENTINEL) {
+ continue;
+ }
+
+ fprintf(stderr, "%2d) SIG%-9s ", i, signals[index].name);
+
+ if ((num++ % 4) == 3) {
+ fprintf(stderr, "\n");
+ }
+ }
+
+ if ((num % 4) == 3) {
+ fprintf(stderr, "\n");
+ }
+}
+
+unsigned int name_to_signal(const char* name)
+{
+ unsigned int i;
+
+ for (i = 1; i < sizeof(signals) / sizeof(signals[0]); i++) {
+ if (!strcasecmp(name, signals[i].name)) {
+ return signals[i].number;
+ }
+ }
+
+ return SENTINEL;
+}
+
+int main(int argc, char **argv)
+{
+ unsigned int sig = SIGTERM;
+ int result = 0;
+
+ argc--;
+ argv++;
+
+ if (argc >= 1 && argv[0][0] == '-') {
+ char *endptr;
+ size_t arg_len = strlen(argv[0]);
+ if (arg_len < 2) {
+ fprintf(stderr, "invalid argument: -\n");
+ return -1;
+ }
+
+ char* arg = argv[0] + 1;
+ if (arg_len == 2 && *arg == 'l') {
+ list_signals();
+ return 0;
+ }
+
+ sig = strtol(arg, &endptr, 10);
+ if (*endptr != '\0') {
+ sig = name_to_signal(arg);
+ if (sig == SENTINEL) {
+ fprintf(stderr, "invalid signal name: %s\n", arg);
+ return -1;
+ }
+ }
+
+ argc--;
+ argv++;
+ }
+
+ while(argc > 0){
+ int pid = atoi(argv[0]);
+ int err = kill(pid, sig);
+ if (err < 0) {
+ result = err;
+ fprintf(stderr, "could not kill pid %d: %s\n", pid, strerror(errno));
+ }
+
+ argc--;
+ argv++;
+ }
+
+ return result;
+}
diff --git a/package/toolbox/src/src/ln.c b/package/toolbox/src/src/ln.c
new file mode 100644
index 000000000..6d67823e8
--- /dev/null
+++ b/package/toolbox/src/src/ln.c
@@ -0,0 +1,34 @@
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+
+static int usage()
+{
+ fprintf(stderr,"ln [-s] <target> <name>\n");
+ return -1;
+}
+
+int main(int argc, char *argv[])
+{
+ int symbolic = 0;
+ int ret;
+ if(argc < 2) return usage();
+
+ if(!strcmp(argv[1],"-s")) {
+ symbolic = 1;
+ argc--;
+ argv++;
+ }
+
+ if(argc < 3) return usage();
+
+ if(symbolic) {
+ ret = symlink(argv[1], argv[2]);
+ } else {
+ ret = link(argv[1], argv[2]);
+ }
+ if(ret < 0)
+ fprintf(stderr, "link failed %s\n", strerror(errno));
+ return ret;
+}
diff --git a/package/toolbox/src/src/ls.c b/package/toolbox/src/src/ls.c
new file mode 100644
index 000000000..a56bfaa87
--- /dev/null
+++ b/package/toolbox/src/src/ls.c
@@ -0,0 +1,424 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <dirent.h>
+#include <errno.h>
+
+#include <sys/stat.h>
+#include <unistd.h>
+#include <time.h>
+
+#include <pwd.h>
+#include <grp.h>
+
+#include <linux/kdev_t.h>
+#include <limits.h>
+
+#include "dynarray.h"
+
+// bits for flags argument
+#define LIST_LONG (1 << 0)
+#define LIST_ALL (1 << 1)
+#define LIST_RECURSIVE (1 << 2)
+#define LIST_DIRECTORIES (1 << 3)
+#define LIST_SIZE (1 << 4)
+#define LIST_LONG_NUMERIC (1 << 5)
+#define LIST_CLASSIFY (1 << 6)
+#define LIST_INODE (1 << 8)
+
+// fwd
+static int listpath(const char *name, int flags);
+
+static char mode2kind(unsigned mode)
+{
+ switch(mode & S_IFMT){
+ case S_IFSOCK: return 's';
+ case S_IFLNK: return 'l';
+ case S_IFREG: return '-';
+ case S_IFDIR: return 'd';
+ case S_IFBLK: return 'b';
+ case S_IFCHR: return 'c';
+ case S_IFIFO: return 'p';
+ default: return '?';
+ }
+}
+
+static void mode2str(unsigned mode, char *out)
+{
+ *out++ = mode2kind(mode);
+
+ *out++ = (mode & 0400) ? 'r' : '-';
+ *out++ = (mode & 0200) ? 'w' : '-';
+ if(mode & 04000) {
+ *out++ = (mode & 0100) ? 's' : 'S';
+ } else {
+ *out++ = (mode & 0100) ? 'x' : '-';
+ }
+ *out++ = (mode & 040) ? 'r' : '-';
+ *out++ = (mode & 020) ? 'w' : '-';
+ if(mode & 02000) {
+ *out++ = (mode & 010) ? 's' : 'S';
+ } else {
+ *out++ = (mode & 010) ? 'x' : '-';
+ }
+ *out++ = (mode & 04) ? 'r' : '-';
+ *out++ = (mode & 02) ? 'w' : '-';
+ if(mode & 01000) {
+ *out++ = (mode & 01) ? 't' : 'T';
+ } else {
+ *out++ = (mode & 01) ? 'x' : '-';
+ }
+ *out = 0;
+}
+
+static void user2str(unsigned uid, char *out)
+{
+ struct passwd *pw = getpwuid(uid);
+ if(pw) {
+ strcpy(out, pw->pw_name);
+ } else {
+ sprintf(out, "%d", uid);
+ }
+}
+
+static void group2str(unsigned gid, char *out)
+{
+ struct group *gr = getgrgid(gid);
+ if(gr) {
+ strcpy(out, gr->gr_name);
+ } else {
+ sprintf(out, "%d", gid);
+ }
+}
+
+static int show_total_size(const char *dirname, DIR *d, int flags)
+{
+ struct dirent *de;
+ char tmp[1024];
+ struct stat s;
+ int sum = 0;
+
+ /* run through the directory and sum up the file block sizes */
+ while ((de = readdir(d)) != 0) {
+ if (strcmp(de->d_name, ".") == 0 || strcmp(de->d_name, "..") == 0)
+ continue;
+ if (de->d_name[0] == '.' && (flags & LIST_ALL) == 0)
+ continue;
+
+ if (strcmp(dirname, "/") == 0)
+ snprintf(tmp, sizeof(tmp), "/%s", de->d_name);
+ else
+ snprintf(tmp, sizeof(tmp), "%s/%s", dirname, de->d_name);
+
+ if (lstat(tmp, &s) < 0) {
+ fprintf(stderr, "stat failed on %s: %s\n", tmp, strerror(errno));
+ rewinddir(d);
+ return -1;
+ }
+
+ sum += s.st_blocks / 2;
+ }
+
+ printf("total %d\n", sum);
+ rewinddir(d);
+ return 0;
+}
+
+static int listfile_size(const char *path, const char *filename, struct stat *s,
+ int flags)
+{
+ if(!s || !path) {
+ return -1;
+ }
+
+ /* blocks are 512 bytes, we want output to be KB */
+ if ((flags & LIST_SIZE) != 0) {
+ printf("%lld ", (long long)(s->st_blocks / 2));
+ }
+
+ if ((flags & LIST_CLASSIFY) != 0) {
+ char filetype = mode2kind(s->st_mode);
+ if (filetype != 'l') {
+ printf("%c ", filetype);
+ } else {
+ struct stat link_dest;
+ if (!stat(path, &link_dest)) {
+ printf("l%c ", mode2kind(link_dest.st_mode));
+ } else {
+ fprintf(stderr, "stat '%s' failed: %s\n", path, strerror(errno));
+ printf("l? ");
+ }
+ }
+ }
+
+ printf("%s\n", filename);
+
+ return 0;
+}
+
+static int listfile_long(const char *path, struct stat *s, int flags)
+{
+ char date[32];
+ char mode[16];
+ char user[16];
+ char group[16];
+ const char *name;
+
+ if(!s || !path) {
+ return -1;
+ }
+
+ /* name is anything after the final '/', or the whole path if none*/
+ name = strrchr(path, '/');
+ if(name == 0) {
+ name = path;
+ } else {
+ name++;
+ }
+
+ mode2str(s->st_mode, mode);
+ if (flags & LIST_LONG_NUMERIC) {
+ sprintf(user, "%ld", (long)s->st_uid);
+ sprintf(group, "%ld", (long)s->st_gid);
+ } else {
+ user2str(s->st_uid, user);
+ group2str(s->st_gid, group);
+ }
+
+ strftime(date, 32, "%Y-%m-%d %H:%M", localtime((const time_t*)&s->st_mtime));
+ date[31] = 0;
+
+// 12345678901234567890123456789012345678901234567890123456789012345678901234567890
+// MMMMMMMM UUUUUUUU GGGGGGGGG XXXXXXXX YYYY-MM-DD HH:MM NAME (->LINK)
+
+ switch(s->st_mode & S_IFMT) {
+ case S_IFBLK:
+ case S_IFCHR:
+ printf("%s %-8s %-8s %3d, %3d %s %s\n",
+ mode, user, group,
+ (int) MAJOR(s->st_rdev), (int) MINOR(s->st_rdev),
+ date, name);
+ break;
+ case S_IFREG:
+ printf("%s %-8s %-8s %8lld %s %s\n",
+ mode, user, group, (long long)s->st_size, date, name);
+ break;
+ case S_IFLNK: {
+ char linkto[256];
+ int len;
+
+ len = readlink(path, linkto, 256);
+ if(len < 0) return -1;
+
+ if(len > 255) {
+ linkto[252] = '.';
+ linkto[253] = '.';
+ linkto[254] = '.';
+ linkto[255] = 0;
+ } else {
+ linkto[len] = 0;
+ }
+
+ printf("%s %-8s %-8s %s %s -> %s\n",
+ mode, user, group, date, name, linkto);
+ break;
+ }
+ default:
+ printf("%s %-8s %-8s %s %s\n",
+ mode, user, group, date, name);
+
+ }
+ return 0;
+}
+
+static int listfile(const char *dirname, const char *filename, int flags)
+{
+ struct stat s;
+
+ if ((flags & (LIST_LONG | LIST_SIZE | LIST_CLASSIFY | LIST_INODE)) == 0) {
+ printf("%s\n", filename);
+ return 0;
+ }
+
+ char tmp[4096];
+ const char* pathname = filename;
+
+ if (dirname != NULL) {
+ snprintf(tmp, sizeof(tmp), "%s/%s", dirname, filename);
+ pathname = tmp;
+ } else {
+ pathname = filename;
+ }
+
+ if(lstat(pathname, &s) < 0) {
+ return -1;
+ }
+
+ if(flags & LIST_INODE) {
+ printf("%8llu ", (unsigned long long)s.st_ino);
+ }
+
+ if ((flags & LIST_LONG) != 0) {
+ return listfile_long(pathname, &s, flags);
+ } else /*((flags & LIST_SIZE) != 0)*/ {
+ return listfile_size(pathname, filename, &s, flags);
+ }
+}
+
+static int listdir(const char *name, int flags)
+{
+ char tmp[4096];
+ DIR *d;
+ struct dirent *de;
+ strlist_t files = STRLIST_INITIALIZER;
+
+ d = opendir(name);
+ if(d == 0) {
+ fprintf(stderr, "opendir failed, %s\n", strerror(errno));
+ return -1;
+ }
+
+ if ((flags & LIST_SIZE) != 0) {
+ show_total_size(name, d, flags);
+ }
+
+ while((de = readdir(d)) != 0){
+ if (!strcmp(de->d_name, ".") || !strcmp(de->d_name, "..")) continue;
+ if(de->d_name[0] == '.' && (flags & LIST_ALL) == 0) continue;
+
+ strlist_append_dup(&files, de->d_name);
+ }
+
+ strlist_sort(&files);
+ STRLIST_FOREACH(&files, filename, listfile(name, filename, flags));
+ strlist_done(&files);
+
+ if (flags & LIST_RECURSIVE) {
+ strlist_t subdirs = STRLIST_INITIALIZER;
+
+ rewinddir(d);
+
+ while ((de = readdir(d)) != 0) {
+ struct stat s;
+ int err;
+
+ if (!strcmp(de->d_name, ".") || !strcmp(de->d_name, ".."))
+ continue;
+ if (de->d_name[0] == '.' && (flags & LIST_ALL) == 0)
+ continue;
+
+ if (!strcmp(name, "/"))
+ snprintf(tmp, sizeof(tmp), "/%s", de->d_name);
+ else
+ snprintf(tmp, sizeof(tmp), "%s/%s", name, de->d_name);
+
+ /*
+ * If the name ends in a '/', use stat() so we treat it like a
+ * directory even if it's a symlink.
+ */
+ if (tmp[strlen(tmp)-1] == '/')
+ err = stat(tmp, &s);
+ else
+ err = lstat(tmp, &s);
+
+ if (err < 0) {
+ perror(tmp);
+ closedir(d);
+ return -1;
+ }
+
+ if (S_ISDIR(s.st_mode)) {
+ strlist_append_dup(&subdirs, tmp);
+ }
+ }
+ strlist_sort(&subdirs);
+ STRLIST_FOREACH(&subdirs, path, {
+ printf("\n%s:\n", path);
+ listdir(path, flags);
+ });
+ strlist_done(&subdirs);
+ }
+
+ closedir(d);
+ return 0;
+}
+
+static int listpath(const char *name, int flags)
+{
+ struct stat s;
+ int err;
+
+ /*
+ * If the name ends in a '/', use stat() so we treat it like a
+ * directory even if it's a symlink.
+ */
+ if (name[strlen(name)-1] == '/')
+ err = stat(name, &s);
+ else
+ err = lstat(name, &s);
+
+ if (err < 0) {
+ perror(name);
+ return -1;
+ }
+
+ if ((flags & LIST_DIRECTORIES) == 0 && S_ISDIR(s.st_mode)) {
+ if (flags & LIST_RECURSIVE)
+ printf("\n%s:\n", name);
+ return listdir(name, flags);
+ } else {
+ /* yeah this calls stat() again*/
+ return listfile(NULL, name, flags);
+ }
+}
+
+int main(int argc, char **argv)
+{
+ int flags = 0;
+
+ if(argc > 1) {
+ int i;
+ int err = 0;
+ strlist_t files = STRLIST_INITIALIZER;
+
+ for (i = 1; i < argc; i++) {
+ if (argv[i][0] == '-') {
+ /* an option ? */
+ const char *arg = argv[i]+1;
+ while (arg[0]) {
+ switch (arg[0]) {
+ case 'l': flags |= LIST_LONG; break;
+ case 'n': flags |= LIST_LONG | LIST_LONG_NUMERIC; break;
+ case 's': flags |= LIST_SIZE; break;
+ case 'R': flags |= LIST_RECURSIVE; break;
+ case 'd': flags |= LIST_DIRECTORIES; break;
+ case 'a': flags |= LIST_ALL; break;
+ case 'F': flags |= LIST_CLASSIFY; break;
+ case 'i': flags |= LIST_INODE; break;
+ default:
+ fprintf(stderr, "%s: Unknown option '-%c'. Aborting.\n", "ls", arg[0]);
+ exit(1);
+ }
+ arg++;
+ }
+ } else {
+ /* not an option ? */
+ strlist_append_dup(&files, argv[i]);
+ }
+ }
+
+ if (files.count > 0) {
+ STRLIST_FOREACH(&files, path, {
+ if (listpath(path, flags) != 0) {
+ err = EXIT_FAILURE;
+ }
+ });
+ strlist_done(&files);
+ return err;
+ }
+ }
+
+ // list working directory if no files or directories were specified
+ return listpath(".", flags);
+}
diff --git a/package/toolbox/src/src/lsof.c b/package/toolbox/src/src/lsof.c
new file mode 100644
index 000000000..c4d9c5f30
--- /dev/null
+++ b/package/toolbox/src/src/lsof.c
@@ -0,0 +1,253 @@
+/*
+ * Copyright (c) 2010, 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 <dirent.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <libgen.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <pwd.h>
+#include <sys/stat.h>
+
+#define BUF_MAX 1024
+#define CMD_DISPLAY_MAX (9 + 1)
+#define USER_DISPLAY_MAX (10 + 1)
+
+struct pid_info_t {
+ pid_t pid;
+ char user[USER_DISPLAY_MAX];
+
+ char cmdline[CMD_DISPLAY_MAX];
+
+ char path[PATH_MAX];
+ ssize_t parent_length;
+};
+
+static void print_header()
+{
+ printf("%-9s %5s %10s %4s %9s %18s %9s %10s %s\n",
+ "COMMAND",
+ "PID",
+ "USER",
+ "FD",
+ "TYPE",
+ "DEVICE",
+ "SIZE/OFF",
+ "NODE",
+ "NAME");
+}
+
+static void print_type(char *type, struct pid_info_t* info)
+{
+ static ssize_t link_dest_size;
+ static char link_dest[PATH_MAX + 64];
+
+ strlcat(info->path, type, sizeof(info->path));
+ if ((link_dest_size = readlink(info->path, link_dest, sizeof(link_dest)-1)) < 0) {
+ if (errno == ENOENT)
+ goto out;
+
+ snprintf(link_dest, sizeof(link_dest), "%s (readlink: %s)", info->path, strerror(errno));
+ } else {
+ link_dest[link_dest_size] = '\0';
+ }
+
+ // Things that are just the root filesystem are uninteresting (we already know)
+ if (!strcmp(link_dest, "/"))
+ goto out;
+
+ printf("%-9s %5d %10s %4s %9s %18s %9s %10s %s\n",
+ info->cmdline, info->pid, info->user, type,
+ "???", "???", "???", "???", link_dest);
+
+out:
+ info->path[info->parent_length] = '\0';
+}
+
+// Prints out all file that have been memory mapped
+static void print_maps(struct pid_info_t* info)
+{
+ FILE *maps;
+ size_t offset;
+ char device[10];
+ long int inode;
+ char file[PATH_MAX];
+
+ strlcat(info->path, "maps", sizeof(info->path));
+
+ maps = fopen(info->path, "r");
+ if (!maps)
+ goto out;
+
+ while (fscanf(maps, "%*x-%*x %*s %zx %5s %ld %s\n", &offset, device, &inode,
+ file) == 4) {
+ // We don't care about non-file maps
+ if (inode == 0 || !strcmp(device, "00:00"))
+ continue;
+
+ printf("%-9s %5d %10s %4s %9s %18s %9zd %10ld %s\n",
+ info->cmdline, info->pid, info->user, "mem",
+ "???", device, offset, inode, file);
+ }
+
+ fclose(maps);
+
+out:
+ info->path[info->parent_length] = '\0';
+}
+
+// Prints out all open file descriptors
+static void print_fds(struct pid_info_t* info)
+{
+ static char* fd_path = "fd/";
+ strlcat(info->path, fd_path, sizeof(info->path));
+
+ int previous_length = info->parent_length;
+ info->parent_length += strlen(fd_path);
+
+ DIR *dir = opendir(info->path);
+ if (dir == NULL) {
+ char msg[PATH_MAX + 64];
+ snprintf(msg, sizeof(msg), "%s (opendir: %s)", info->path, strerror(errno));
+ printf("%-9s %5d %10s %4s %9s %18s %9s %10s %s\n",
+ info->cmdline, info->pid, info->user, "FDS",
+ "", "", "", "", msg);
+ goto out;
+ }
+
+ struct dirent* de;
+ while ((de = readdir(dir))) {
+ if (!strcmp(de->d_name, ".") || !strcmp(de->d_name, ".."))
+ continue;
+
+ print_type(de->d_name, info);
+ }
+ closedir(dir);
+
+out:
+ info->parent_length = previous_length;
+ info->path[info->parent_length] = '\0';
+}
+
+static void lsof_dumpinfo(pid_t pid)
+{
+ int fd;
+ struct pid_info_t info;
+ struct stat pidstat;
+ struct passwd *pw;
+
+ info.pid = pid;
+ snprintf(info.path, sizeof(info.path), "/proc/%d/", pid);
+ info.parent_length = strlen(info.path);
+
+ // Get the UID by calling stat on the proc/pid directory.
+ if (!stat(info.path, &pidstat)) {
+ pw = getpwuid(pidstat.st_uid);
+ if (pw) {
+ strlcpy(info.user, pw->pw_name, sizeof(info.user));
+ } else {
+ snprintf(info.user, USER_DISPLAY_MAX, "%d", (int)pidstat.st_uid);
+ }
+ } else {
+ strcpy(info.user, "???");
+ }
+
+ // Read the command line information; each argument is terminated with NULL.
+ strlcat(info.path, "cmdline", sizeof(info.path));
+ fd = open(info.path, O_RDONLY);
+ if (fd < 0) {
+ fprintf(stderr, "Couldn't read %s\n", info.path);
+ return;
+ }
+
+ char cmdline[PATH_MAX];
+ int numRead = read(fd, cmdline, sizeof(cmdline) - 1);
+ close(fd);
+
+ if (numRead < 0) {
+ fprintf(stderr, "Error reading cmdline: %s: %s\n", info.path, strerror(errno));
+ return;
+ }
+
+ cmdline[numRead] = '\0';
+
+ // We only want the basename of the cmdline
+ strlcpy(info.cmdline, basename(cmdline), sizeof(info.cmdline));
+
+ // Read each of these symlinks
+ print_type("cwd", &info);
+ print_type("exe", &info);
+ print_type("root", &info);
+
+ print_fds(&info);
+ print_maps(&info);
+}
+
+int main(int argc, char *argv[])
+{
+ long int pid = 0;
+ char* endptr;
+ if (argc == 2) {
+ pid = strtol(argv[1], &endptr, 10);
+ }
+
+ print_header();
+
+ if (pid) {
+ lsof_dumpinfo(pid);
+ } else {
+ DIR *dir = opendir("/proc");
+ if (dir == NULL) {
+ fprintf(stderr, "Couldn't open /proc\n");
+ return -1;
+ }
+
+ struct dirent* de;
+ while ((de = readdir(dir))) {
+ if (!strcmp(de->d_name, ".") || !strcmp(de->d_name, ".."))
+ continue;
+
+ // Only inspect directories that are PID numbers
+ pid = strtol(de->d_name, &endptr, 10);
+ if (*endptr != '\0')
+ continue;
+
+ lsof_dumpinfo(pid);
+ }
+ closedir(dir);
+ }
+
+ return 0;
+}
diff --git a/package/toolbox/src/src/md5.c b/package/toolbox/src/src/md5.c
new file mode 100644
index 000000000..3261c7fae
--- /dev/null
+++ b/package/toolbox/src/src/md5.c
@@ -0,0 +1,75 @@
+#include <errno.h>
+#include <fcntl.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <md5.h>
+
+static int usage()
+{
+ fprintf(stderr,"md5 file ...\n");
+ return -1;
+}
+
+static int do_md5(const char *path)
+{
+ unsigned int i;
+ int fd;
+ MD5_CTX md5_ctx;
+ unsigned char md5[MD5_DIGEST_LENGTH];
+
+ fd = open(path, O_RDONLY);
+ if (fd < 0) {
+ fprintf(stderr,"could not open %s, %s\n", path, strerror(errno));
+ return -1;
+ }
+
+ /* Note that bionic's MD5_* functions return void. */
+ MD5Init(&md5_ctx);
+
+ while (1) {
+ char buf[4096];
+ ssize_t rlen;
+ rlen = read(fd, buf, sizeof(buf));
+ if (rlen == 0)
+ break;
+ else if (rlen < 0) {
+ (void)close(fd);
+ fprintf(stderr,"could not read %s, %s\n", path, strerror(errno));
+ return -1;
+ }
+ MD5Update(&md5_ctx, (const void *)buf, rlen);
+ }
+ if (close(fd)) {
+ fprintf(stderr,"could not close %s, %s\n", path, strerror(errno));
+ return -1;
+ }
+
+ MD5Final(md5, &md5_ctx);
+
+ for (i = 0; i < (int)sizeof(md5); i++)
+ printf("%02x", md5[i]);
+ printf(" %s\n", path);
+
+ return 0;
+}
+
+int
+main(int argc, char *argv[])
+{
+ int i, ret = 0;
+
+ if (argc < 2)
+ return usage();
+
+ /* loop over the file args */
+ for (i = 1; i < argc; i++) {
+ if (do_md5(argv[i]))
+ ret = 1;
+ }
+
+ return ret;
+}
diff --git a/package/toolbox/src/src/mkdir.c b/package/toolbox/src/src/mkdir.c
new file mode 100644
index 000000000..e0b701291
--- /dev/null
+++ b/package/toolbox/src/src/mkdir.c
@@ -0,0 +1,77 @@
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include <limits.h>
+#include <sys/stat.h>
+
+static int usage()
+{
+ fprintf(stderr,"mkdir [OPTION] <target>\n");
+ fprintf(stderr," --help display usage and exit\n");
+ fprintf(stderr," -p, --parents create parent directories as needed\n");
+ return -1;
+}
+
+int main(int argc, char *argv[])
+{
+ int ret;
+ if(argc < 2 || strcmp(argv[1], "--help") == 0) {
+ return usage();
+ }
+
+ int recursive = (strcmp(argv[1], "-p") == 0 ||
+ strcmp(argv[1], "--parents") == 0) ? 1 : 0;
+
+ if(recursive && argc < 3) {
+ // -p specified without a path
+ return usage();
+ }
+
+ if(recursive) {
+ argc--;
+ argv++;
+ }
+
+ char currpath[PATH_MAX], *pathpiece;
+ struct stat st;
+
+ while(argc > 1) {
+ argc--;
+ argv++;
+ if(recursive) {
+ // reset path
+ strcpy(currpath, "");
+ // create the pieces of the path along the way
+ pathpiece = strtok(argv[0], "/");
+ if(argv[0][0] == '/') {
+ // prepend / if needed
+ strcat(currpath, "/");
+ }
+ while(pathpiece != NULL) {
+ if(strlen(currpath) + strlen(pathpiece) + 2/*NUL and slash*/ > PATH_MAX) {
+ fprintf(stderr, "Invalid path specified: too long\n");
+ return 1;
+ }
+ strcat(currpath, pathpiece);
+ strcat(currpath, "/");
+ if(stat(currpath, &st) != 0) {
+ ret = mkdir(currpath, 0777);
+ if(ret < 0) {
+ fprintf(stderr, "mkdir failed for %s, %s\n", currpath, strerror(errno));
+ return ret;
+ }
+ }
+ pathpiece = strtok(NULL, "/");
+ }
+ } else {
+ ret = mkdir(argv[0], 0777);
+ if(ret < 0) {
+ fprintf(stderr, "mkdir failed for %s, %s\n", argv[0], strerror(errno));
+ return ret;
+ }
+ }
+ }
+
+ return 0;
+}
diff --git a/package/toolbox/src/src/mount.c b/package/toolbox/src/src/mount.c
new file mode 100644
index 000000000..af7e5c182
--- /dev/null
+++ b/package/toolbox/src/src/mount.c
@@ -0,0 +1,360 @@
+/*
+ * mount.c, by rmk
+ */
+
+#include <sys/mount.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <linux/loop.h>
+
+#define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0]))
+
+#define DEFAULT_LOOP_DEVICE "/dev/block/loop0"
+#define LOOPDEV_MAXLEN 64
+
+struct mount_opts {
+ const char str[16];
+ unsigned long rwmask;
+ unsigned long rwset;
+ unsigned long rwnoset;
+};
+
+struct extra_opts {
+ char *str;
+ char *end;
+ int used_size;
+ int alloc_size;
+};
+
+/*
+ * These options define the function of "mount(2)".
+ */
+#define MS_TYPE (MS_REMOUNT|MS_BIND|MS_MOVE)
+
+
+static const struct mount_opts options[] = {
+ /* name mask set noset */
+ { "async", MS_SYNCHRONOUS, 0, MS_SYNCHRONOUS },
+ { "atime", MS_NOATIME, 0, MS_NOATIME },
+ { "bind", MS_TYPE, MS_BIND, 0, },
+ { "dev", MS_NODEV, 0, MS_NODEV },
+ { "diratime", MS_NODIRATIME, 0, MS_NODIRATIME },
+ { "dirsync", MS_DIRSYNC, MS_DIRSYNC, 0 },
+ { "exec", MS_NOEXEC, 0, MS_NOEXEC },
+ { "move", MS_TYPE, MS_MOVE, 0 },
+ { "recurse", MS_REC, MS_REC, 0 },
+ { "rec", MS_REC, MS_REC, 0 },
+ { "remount", MS_TYPE, MS_REMOUNT, 0 },
+ { "ro", MS_RDONLY, MS_RDONLY, 0 },
+ { "rw", MS_RDONLY, 0, MS_RDONLY },
+ { "suid", MS_NOSUID, 0, MS_NOSUID },
+ { "sync", MS_SYNCHRONOUS, MS_SYNCHRONOUS, 0 },
+ { "verbose", MS_SILENT, MS_SILENT, 0 },
+ { "unbindable", MS_UNBINDABLE, MS_UNBINDABLE, 0 },
+ { "private", MS_PRIVATE, MS_PRIVATE, 0 },
+ { "slave", MS_SLAVE, MS_SLAVE, 0 },
+ { "shared", MS_SHARED, MS_SHARED, 0 },
+};
+
+static void add_extra_option(struct extra_opts *extra, char *s)
+{
+ int len = strlen(s);
+ int newlen;
+
+ if (extra->str)
+ len++; /* +1 for ',' */
+ newlen = extra->used_size + len;
+
+ if (newlen >= extra->alloc_size) {
+ char *new;
+
+ new = realloc(extra->str, newlen + 1); /* +1 for NUL */
+ if (!new)
+ return;
+
+ extra->str = new;
+ extra->end = extra->str + extra->used_size;
+ extra->alloc_size = newlen + 1;
+ }
+
+ if (extra->used_size) {
+ *extra->end = ',';
+ extra->end++;
+ }
+ strcpy(extra->end, s);
+ extra->used_size += len;
+
+}
+
+static unsigned long
+parse_mount_options(char *arg, unsigned long rwflag, struct extra_opts *extra, int* loop, char *loopdev)
+{
+ char *s;
+
+ *loop = 0;
+ while ((s = strsep(&arg, ",")) != NULL) {
+ char *opt = s;
+ unsigned int i;
+ int res, no = s[0] == 'n' && s[1] == 'o';
+
+ if (no)
+ s += 2;
+
+ if (strncmp(s, "loop=", 5) == 0) {
+ *loop = 1;
+ strlcpy(loopdev, s + 5, LOOPDEV_MAXLEN);
+ continue;
+ }
+
+ if (strcmp(s, "loop") == 0) {
+ *loop = 1;
+ strlcpy(loopdev, DEFAULT_LOOP_DEVICE, LOOPDEV_MAXLEN);
+ continue;
+ }
+ for (i = 0, res = 1; i < ARRAY_SIZE(options); i++) {
+ res = strcmp(s, options[i].str);
+
+ if (res == 0) {
+ rwflag &= ~options[i].rwmask;
+ if (no)
+ rwflag |= options[i].rwnoset;
+ else
+ rwflag |= options[i].rwset;
+ }
+ if (res <= 0)
+ break;
+ }
+
+ if (res != 0 && s[0])
+ add_extra_option(extra, opt);
+ }
+
+ return rwflag;
+}
+
+/*
+ * Mark the given block device as read-write, using the BLKROSET ioctl.
+ */
+static void fs_set_blk_rw(const char *blockdev)
+{
+ int fd;
+ int OFF = 0;
+
+ fd = open(blockdev, O_RDONLY);
+ if (fd < 0) {
+ // should never happen
+ return;
+ }
+
+ ioctl(fd, BLKROSET, &OFF);
+ close(fd);
+}
+
+static char *progname;
+
+static struct extra_opts extra;
+static unsigned long rwflag;
+
+static int
+do_mount(char *dev, char *dir, char *type, unsigned long rwflag, void *data, int loop,
+ char *loopdev)
+{
+ char *s;
+ int error = 0;
+
+ if (loop) {
+ int file_fd, device_fd;
+ int flags;
+
+ flags = (rwflag & MS_RDONLY) ? O_RDONLY : O_RDWR;
+
+ file_fd = open(dev, flags);
+ if (file_fd < 0) {
+ perror("open backing file failed");
+ return 1;
+ }
+ device_fd = open(loopdev, flags);
+ if (device_fd < 0) {
+ perror("open loop device failed");
+ close(file_fd);
+ return 1;
+ }
+ if (ioctl(device_fd, LOOP_SET_FD, file_fd) < 0) {
+ perror("ioctl LOOP_SET_FD failed");
+ close(file_fd);
+ close(device_fd);
+ return 1;
+ }
+
+ close(file_fd);
+ close(device_fd);
+ dev = loopdev;
+ }
+
+ if ((rwflag & MS_RDONLY) == 0) {
+ fs_set_blk_rw(dev);
+ }
+
+ while ((s = strsep(&type, ",")) != NULL) {
+retry:
+ if (mount(dev, dir, s, rwflag, data) == -1) {
+ error = errno;
+ /*
+ * If the filesystem is not found, or the
+ * superblock is invalid, try the next.
+ */
+ if (error == ENODEV || error == EINVAL)
+ continue;
+
+ /*
+ * If we get EACCESS, and we're trying to
+ * mount readwrite and this isn't a remount,
+ * try read only.
+ */
+ if (error == EACCES &&
+ (rwflag & (MS_REMOUNT|MS_RDONLY)) == 0) {
+ rwflag |= MS_RDONLY;
+ goto retry;
+ }
+ break;
+ }
+ }
+
+ if (error) {
+ errno = error;
+ perror("mount");
+ return 255;
+ }
+
+ return 0;
+}
+
+static int print_mounts()
+{
+ FILE* f;
+ int length;
+ char buffer[100];
+
+ f = fopen("/proc/mounts", "r");
+ if (!f) {
+ fprintf(stdout, "could not open /proc/mounts\n");
+ return -1;
+ }
+
+ do {
+ length = fread(buffer, 1, 100, f);
+ if (length > 0)
+ fwrite(buffer, 1, length, stdout);
+ } while (length > 0);
+
+ fclose(f);
+ return 0;
+}
+
+static int get_mounts_dev_dir(const char *arg, char **dev, char **dir)
+{
+ FILE *f;
+ char mount_dev[256];
+ char mount_dir[256];
+ char mount_type[256];
+ char mount_opts[256];
+ int mount_freq;
+ int mount_passno;
+ int match;
+
+ f = fopen("/proc/mounts", "r");
+ if (!f) {
+ fprintf(stdout, "could not open /proc/mounts\n");
+ return -1;
+ }
+
+ do {
+ match = fscanf(f, "%255s %255s %255s %255s %d %d\n",
+ mount_dev, mount_dir, mount_type,
+ mount_opts, &mount_freq, &mount_passno);
+ mount_dev[255] = 0;
+ mount_dir[255] = 0;
+ mount_type[255] = 0;
+ mount_opts[255] = 0;
+ if (match == 6 &&
+ (strcmp(arg, mount_dev) == 0 ||
+ strcmp(arg, mount_dir) == 0)) {
+ *dev = strdup(mount_dev);
+ *dir = strdup(mount_dir);
+ fclose(f);
+ return 0;
+ }
+ } while (match != EOF);
+
+ fclose(f);
+ return -1;
+}
+
+int main(int argc, char *argv[])
+{
+ char *type = NULL;
+ char *dev = NULL;
+ char *dir = NULL;
+ int c;
+ int loop = 0;
+ char loopdev[LOOPDEV_MAXLEN];
+
+ progname = argv[0];
+ rwflag = MS_SILENT;
+
+ // mount with no arguments is equivalent to "cat /proc/mounts"
+ if (argc == 1) return print_mounts();
+
+ do {
+ c = getopt(argc, argv, "o:rt:w");
+ if (c == EOF)
+ break;
+ switch (c) {
+ case 'o':
+ rwflag = parse_mount_options(optarg, rwflag, &extra, &loop, loopdev);
+ break;
+ case 'r':
+ rwflag |= MS_RDONLY;
+ break;
+ case 't':
+ type = optarg;
+ break;
+ case 'w':
+ rwflag &= ~MS_RDONLY;
+ break;
+ case '?':
+ fprintf(stderr, "%s: invalid option -%c\n",
+ progname, optopt);
+ exit(1);
+ }
+ } while (1);
+
+ /*
+ * If remount, bind or move was specified, then we don't
+ * have a "type" as such. Use the dummy "none" type.
+ */
+ if (rwflag & MS_TYPE)
+ type = "none";
+
+ if (optind + 2 == argc) {
+ dev = argv[optind];
+ dir = argv[optind + 1];
+ } else if (optind + 1 == argc && rwflag & MS_REMOUNT) {
+ get_mounts_dev_dir(argv[optind], &dev, &dir);
+ }
+
+ if (dev == NULL || dir == NULL || type == NULL) {
+ fprintf(stderr, "Usage: %s [-r] [-w] [-o options] [-t type] "
+ "device directory\n", progname);
+ exit(1);
+ }
+
+ return do_mount(dev, dir, type, rwflag, extra.str, loop, loopdev);
+ /* We leak dev and dir in some cases, but we're about to exit */
+}
diff --git a/package/toolbox/src/src/mv.c b/package/toolbox/src/src/mv.c
new file mode 100644
index 000000000..d5406b8ac
--- /dev/null
+++ b/package/toolbox/src/src/mv.c
@@ -0,0 +1,59 @@
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <limits.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+
+int main(int argc, char *argv[])
+{
+ const char* dest;
+ struct stat st;
+ int i;
+
+ if (argc < 3) {
+ fprintf(stderr,"USAGE: %s <source...> <destination>\n", argv[0]);
+ return -1;
+ }
+
+ /* check if destination exists */
+ dest = argv[argc - 1];
+ if (stat(dest, &st)) {
+ /* an error, unless the destination was missing */
+ if (errno != ENOENT) {
+ fprintf(stderr, "failed on %s - %s\n", dest, strerror(errno));
+ return -1;
+ }
+ st.st_mode = 0;
+ }
+
+ for (i = 1; i < argc - 1; i++) {
+ const char *source = argv[i];
+ char fullDest[PATH_MAX + 1 + PATH_MAX + 1];
+ /* assume we build "dest/source", and let rename() fail on pathsize */
+ if (strlen(dest) + 1 + strlen(source) + 1 > sizeof(fullDest)) {
+ fprintf(stderr, "path too long\n");
+ return -1;
+ }
+ strcpy(fullDest, dest);
+
+ /* if destination is a directory, concat the source file name */
+ if (S_ISDIR(st.st_mode)) {
+ const char *fileName = strrchr(source, '/');
+ if (fullDest[strlen(fullDest)-1] != '/') {
+ strcat(fullDest, "/");
+ }
+ strcat(fullDest, fileName ? fileName + 1 : source);
+ }
+
+ /* attempt to move it */
+ if (rename(source, fullDest)) {
+ fprintf(stderr, "failed on '%s' - %s\n", source, strerror(errno));
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
diff --git a/package/toolbox/src/src/netstat.c b/package/toolbox/src/src/netstat.c
new file mode 100644
index 000000000..31365acd6
--- /dev/null
+++ b/package/toolbox/src/src/netstat.c
@@ -0,0 +1,155 @@
+/*
+ * Copyright (c) 2008, 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 <arpa/inet.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+
+typedef union iaddr iaddr;
+typedef union iaddr6 iaddr6;
+
+union iaddr {
+ unsigned u;
+ unsigned char b[4];
+};
+
+union iaddr6 {
+ struct {
+ unsigned a;
+ unsigned b;
+ unsigned c;
+ unsigned d;
+ } u;
+ unsigned char b[16];
+};
+
+static const char *state2str(unsigned state)
+{
+ switch(state){
+ case 0x1: return "ESTABLISHED";
+ case 0x2: return "SYN_SENT";
+ case 0x3: return "SYN_RECV";
+ case 0x4: return "FIN_WAIT1";
+ case 0x5: return "FIN_WAIT2";
+ case 0x6: return "TIME_WAIT";
+ case 0x7: return "CLOSE";
+ case 0x8: return "CLOSE_WAIT";
+ case 0x9: return "LAST_ACK";
+ case 0xA: return "LISTEN";
+ case 0xB: return "CLOSING";
+ default: return "UNKNOWN";
+ }
+}
+
+/* addr + : + port + \0 */
+#define ADDR_LEN INET6_ADDRSTRLEN + 1 + 5 + 1
+
+static void addr2str(int af, const void *addr, unsigned port, char *buf)
+{
+ if (inet_ntop(af, addr, buf, ADDR_LEN) == NULL) {
+ *buf = '\0';
+ return;
+ }
+ size_t len = strlen(buf);
+ if (port) {
+ snprintf(buf+len, ADDR_LEN-len, ":%d", port);
+ } else {
+ strncat(buf+len, ":*", ADDR_LEN-len-1);
+ }
+}
+
+static void ipv4(const char *filename, const char *label) {
+ FILE *fp = fopen(filename, "r");
+ if (fp == NULL) {
+ return;
+ }
+ char buf[BUFSIZ];
+ fgets(buf, BUFSIZ, fp);
+ while (fgets(buf, BUFSIZ, fp)){
+ char lip[ADDR_LEN];
+ char rip[ADDR_LEN];
+ iaddr laddr, raddr;
+ unsigned lport, rport, state, txq, rxq, num;
+ int n = sscanf(buf, " %d: %x:%x %x:%x %x %x:%x",
+ &num, &laddr.u, &lport, &raddr.u, &rport,
+ &state, &txq, &rxq);
+ if (n == 8) {
+ addr2str(AF_INET, &laddr, lport, lip);
+ addr2str(AF_INET, &raddr, rport, rip);
+
+ printf("%4s %6d %6d %-22s %-22s %s\n",
+ label, rxq, txq, lip, rip,
+ state2str(state));
+ }
+ }
+ fclose(fp);
+}
+
+static void ipv6(const char *filename, const char *label) {
+ FILE *fp = fopen(filename, "r");
+ if (fp == NULL) {
+ return;
+ }
+ char buf[BUFSIZ];
+ fgets(buf, BUFSIZ, fp);
+ while (fgets(buf, BUFSIZ, fp)){
+ char lip[ADDR_LEN];
+ char rip[ADDR_LEN];
+ iaddr6 laddr6, raddr6;
+ unsigned lport, rport, state, txq, rxq, num;
+ int n = sscanf(buf, " %d: %8x%8x%8x%8x:%x %8x%8x%8x%8x:%x %x %x:%x",
+ &num, &laddr6.u.a, &laddr6.u.b, &laddr6.u.c, &laddr6.u.d, &lport,
+ &raddr6.u.a, &raddr6.u.b, &raddr6.u.c, &raddr6.u.d, &rport,
+ &state, &txq, &rxq);
+ if (n == 14) {
+ addr2str(AF_INET6, &laddr6, lport, lip);
+ addr2str(AF_INET6, &raddr6, rport, rip);
+
+ printf("%4s %6d %6d %-22s %-22s %s\n",
+ label, rxq, txq, lip, rip,
+ state2str(state));
+ }
+ }
+ fclose(fp);
+}
+
+int main(int argc, char *argv[])
+{
+ printf("Proto Recv-Q Send-Q Local Address Foreign Address State\n");
+ ipv4("/proc/net/tcp", "tcp");
+ ipv4("/proc/net/udp", "udp");
+ ipv6("/proc/net/tcp6", "tcp6");
+ ipv6("/proc/net/udp6", "udp6");
+ return 0;
+}
diff --git a/package/toolbox/src/src/notify.c b/package/toolbox/src/src/notify.c
new file mode 100644
index 000000000..56294b73f
--- /dev/null
+++ b/package/toolbox/src/src/notify.c
@@ -0,0 +1,145 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdint.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/ioctl.h>
+#include <sys/inotify.h>
+#include <errno.h>
+
+int main(int argc, char *argv[])
+{
+ int c;
+ int nfd, ffd;
+ int res;
+ char event_buf[512];
+ struct inotify_event *event;
+ int event_mask = IN_ALL_EVENTS;
+ int event_count = 1;
+ int print_files = 0;
+ int verbose = 2;
+ int width = 80;
+ char **file_names;
+ int file_count;
+ int id_offset = 0;
+ int i;
+ char *buf;
+
+ do {
+ c = getopt(argc, argv, "m:c:pv:w:");
+ if (c == EOF)
+ break;
+ switch (c) {
+ case 'm':
+ event_mask = strtol(optarg, NULL, 0);
+ break;
+ case 'c':
+ event_count = atoi(optarg);
+ break;
+ case 'p':
+ print_files = 1;
+ break;
+ case 'v':
+ verbose = atoi(optarg);
+ break;
+ case 'w':
+ width = atoi(optarg);
+ break;
+ case '?':
+ fprintf(stderr, "%s: invalid option -%c\n",
+ argv[0], optopt);
+ exit(1);
+ }
+ } while (1);
+
+ if (argc <= optind) {
+ fprintf(stderr, "Usage: %s [-m eventmask] [-c count] [-p] [-v verbosity] path [path ...]\n", argv[0]);
+ return 1;
+ }
+
+ nfd = inotify_init();
+ if(nfd < 0) {
+ fprintf(stderr, "inotify_init failed, %s\n", strerror(errno));
+ return 1;
+ }
+ file_names = argv + optind;
+ file_count = argc - optind;
+ for(i = 0; i < file_count; i++) {
+ res = inotify_add_watch(nfd, file_names[i], event_mask);
+ if(res < 0) {
+ fprintf(stderr, "inotify_add_watch failed for %s, %s\n", file_names[i], strerror(errno));
+ return 1;
+ }
+ if(i == 0)
+ id_offset = -res;
+ if(res + id_offset != i) {
+ fprintf(stderr, "%s got unexpected id %d instead of %d\n", file_names[i], res, i);
+ return 1;
+ }
+ }
+
+ buf = malloc(width + 2);
+
+ while(1) {
+ int event_pos = 0;
+ res = read(nfd, event_buf, sizeof(event_buf));
+ if(res < (int)sizeof(*event)) {
+ if(errno == EINTR)
+ continue;
+ fprintf(stderr, "could not get event, %s\n", strerror(errno));
+ return 1;
+ }
+ //printf("got %d bytes of event information\n", res);
+ while(res >= (int)sizeof(*event)) {
+ int event_size;
+ event = (struct inotify_event *)(event_buf + event_pos);
+ if(verbose >= 2)
+ printf("%s: %08x %08x \"%s\"\n", file_names[event->wd + id_offset], event->mask, event->cookie, event->len ? event->name : "");
+ else if(verbose >= 2)
+ printf("%s: %08x \"%s\"\n", file_names[event->wd + id_offset], event->mask, event->len ? event->name : "");
+ else if(verbose >= 1)
+ printf("%d: %08x \"%s\"\n", event->wd, event->mask, event->len ? event->name : "");
+ if(print_files && (event->mask & IN_MODIFY)) {
+ char filename[512];
+ ssize_t read_len;
+ char *display_name;
+ int buflen;
+ strcpy(filename, file_names[event->wd + id_offset]);
+ if(event->len) {
+ strcat(filename, "/");
+ strcat(filename, event->name);
+ }
+ ffd = open(filename, O_RDONLY);
+ display_name = (verbose >= 2 || event->len == 0) ? filename : event->name;
+ buflen = width - strlen(display_name);
+ read_len = read(ffd, buf, buflen);
+ if(read_len > 0) {
+ if(read_len < buflen && buf[read_len-1] != '\n') {
+ buf[read_len] = '\n';
+ read_len++;
+ }
+ if(read_len == buflen) {
+ buf[--read_len] = '\0';
+ buf[--read_len] = '\n';
+ buf[--read_len] = '.';
+ buf[--read_len] = '.';
+ buf[--read_len] = '.';
+ }
+ else {
+ buf[read_len] = '\0';
+ }
+ printf("%s: %s", display_name, buf);
+ }
+ close(ffd);
+ }
+ if(event_count && --event_count == 0)
+ return 0;
+ event_size = sizeof(*event) + event->len;
+ res -= event_size;
+ event_pos += event_size;
+ }
+ }
+
+ return 0;
+}
diff --git a/package/toolbox/src/src/printenv.c b/package/toolbox/src/src/printenv.c
new file mode 100644
index 000000000..304258c4a
--- /dev/null
+++ b/package/toolbox/src/src/printenv.c
@@ -0,0 +1,33 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+extern char** environ;
+
+int main (int argc, char **argv)
+{
+ char** e;
+ char* v;
+ int i;
+
+ if (argc == 1) {
+ e = environ;
+ while (*e) {
+ write(1, *e, strlen(*e));
+ write(1, "\n", 1);
+ e++;
+ }
+ } else {
+ for (i=1; i<argc; i++) {
+ v = getenv(argv[i]);
+ if (v) {
+ write(1, v, strlen(v));
+ write(1, "\n", 1);
+ }
+ }
+ }
+
+ return 0;
+}
+
diff --git a/package/toolbox/src/src/ps.c b/package/toolbox/src/src/ps.c
new file mode 100644
index 000000000..07fe5c94b
--- /dev/null
+++ b/package/toolbox/src/src/ps.c
@@ -0,0 +1,244 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+#include <string.h>
+
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <dirent.h>
+
+#include <pwd.h>
+
+static char *nexttoksep(char **strp, char *sep)
+{
+ char *p = strsep(strp,sep);
+ return (p == 0) ? "" : p;
+}
+static char *nexttok(char **strp)
+{
+ return nexttoksep(strp, " ");
+}
+
+#define SHOW_PRIO 1
+#define SHOW_TIME 2
+#define SHOW_CPU 8
+#define SHOW_MACLABEL 16
+
+static int display_flags = 0;
+
+static int ps_line(int pid, int tid, char *namefilter)
+{
+ char statline[1024];
+ char cmdline[1024];
+ char macline[1024];
+ char user[32];
+ struct stat stats;
+ int fd, r;
+ char *ptr, *name, *state;
+ int ppid;
+ unsigned wchan, rss, vss, eip;
+ unsigned utime, stime;
+ int prio, nice, rtprio, sched, psr;
+ struct passwd *pw;
+
+ sprintf(statline, "/proc/%d", pid);
+ stat(statline, &stats);
+
+ if(tid) {
+ sprintf(statline, "/proc/%d/task/%d/stat", pid, tid);
+ cmdline[0] = 0;
+ snprintf(macline, sizeof(macline), "/proc/%d/task/%d/attr/current", pid, tid);
+ } else {
+ sprintf(statline, "/proc/%d/stat", pid);
+ sprintf(cmdline, "/proc/%d/cmdline", pid);
+ snprintf(macline, sizeof(macline), "/proc/%d/attr/current", pid);
+ fd = open(cmdline, O_RDONLY);
+ if(fd == 0) {
+ r = 0;
+ } else {
+ r = read(fd, cmdline, 1023);
+ close(fd);
+ if(r < 0) r = 0;
+ }
+ cmdline[r] = 0;
+ }
+
+ fd = open(statline, O_RDONLY);
+ if(fd == 0) return -1;
+ r = read(fd, statline, 1023);
+ close(fd);
+ if(r < 0) return -1;
+ statline[r] = 0;
+
+ ptr = statline;
+ nexttok(&ptr); // skip pid
+ ptr++; // skip "("
+
+ name = ptr;
+ ptr = strrchr(ptr, ')'); // Skip to *last* occurence of ')',
+ *ptr++ = '\0'; // and null-terminate name.
+
+ ptr++; // skip " "
+ state = nexttok(&ptr);
+ ppid = atoi(nexttok(&ptr));
+ nexttok(&ptr); // pgrp
+ nexttok(&ptr); // sid
+ nexttok(&ptr); // tty
+
+ nexttok(&ptr); // tpgid
+ nexttok(&ptr); // flags
+ nexttok(&ptr); // minflt
+ nexttok(&ptr); // cminflt
+ nexttok(&ptr); // majflt
+ nexttok(&ptr); // cmajflt
+#if 1
+ utime = atoi(nexttok(&ptr));
+ stime = atoi(nexttok(&ptr));
+#else
+ nexttok(&ptr); // utime
+ nexttok(&ptr); // stime
+#endif
+ nexttok(&ptr); // cutime
+ nexttok(&ptr); // cstime
+ prio = atoi(nexttok(&ptr));
+ nice = atoi(nexttok(&ptr));
+ nexttok(&ptr); // threads
+ nexttok(&ptr); // itrealvalue
+ nexttok(&ptr); // starttime
+ vss = strtoul(nexttok(&ptr), 0, 10); // vsize
+ rss = strtoul(nexttok(&ptr), 0, 10); // rss
+ nexttok(&ptr); // rlim
+ nexttok(&ptr); // startcode
+ nexttok(&ptr); // endcode
+ nexttok(&ptr); // startstack
+ nexttok(&ptr); // kstkesp
+ eip = strtoul(nexttok(&ptr), 0, 10); // kstkeip
+ nexttok(&ptr); // signal
+ nexttok(&ptr); // blocked
+ nexttok(&ptr); // sigignore
+ nexttok(&ptr); // sigcatch
+ wchan = strtoul(nexttok(&ptr), 0, 10); // wchan
+ nexttok(&ptr); // nswap
+ nexttok(&ptr); // cnswap
+ nexttok(&ptr); // exit signal
+ psr = atoi(nexttok(&ptr)); // processor
+ rtprio = atoi(nexttok(&ptr)); // rt_priority
+ sched = atoi(nexttok(&ptr)); // scheduling policy
+
+ nexttok(&ptr); // tty
+
+ if(tid != 0) {
+ ppid = pid;
+ pid = tid;
+ }
+
+ pw = getpwuid(stats.st_uid);
+ if(pw == 0) {
+ sprintf(user,"%d",(int)stats.st_uid);
+ } else {
+ strcpy(user,pw->pw_name);
+ }
+
+ if(!namefilter || !strncmp(name, namefilter, strlen(namefilter))) {
+ if (display_flags & SHOW_MACLABEL) {
+ fd = open(macline, O_RDONLY);
+ strcpy(macline, "-");
+ if (fd >= 0) {
+ r = read(fd, macline, sizeof(macline)-1);
+ close(fd);
+ if (r > 0)
+ macline[r] = 0;
+ }
+ printf("%-30s %-9s %-5d %-5d %s\n", macline, user, pid, ppid, cmdline[0] ? cmdline : name);
+ return 0;
+ }
+
+ printf("%-9s %-5d %-5d %-6d %-5d", user, pid, ppid, vss / 1024, rss * 4);
+ if (display_flags & SHOW_CPU)
+ printf(" %-2d", psr);
+ if (display_flags & SHOW_PRIO)
+ printf(" %-5d %-5d %-5d %-5d", prio, nice, rtprio, sched);
+ printf(" %08x %08x %s %s", wchan, eip, state, cmdline[0] ? cmdline : name);
+ if(display_flags&SHOW_TIME)
+ printf(" (u:%d, s:%d)", utime, stime);
+
+ printf("\n");
+ }
+ return 0;
+}
+
+
+void ps_threads(int pid, char *namefilter)
+{
+ char tmp[128];
+ DIR *d;
+ struct dirent *de;
+
+ sprintf(tmp,"/proc/%d/task",pid);
+ d = opendir(tmp);
+ if(d == 0) return;
+
+ while((de = readdir(d)) != 0){
+ if(isdigit(de->d_name[0])){
+ int tid = atoi(de->d_name);
+ if(tid == pid) continue;
+ ps_line(pid, tid, namefilter);
+ }
+ }
+ closedir(d);
+}
+
+int main(int argc, char **argv)
+{
+ DIR *d;
+ struct dirent *de;
+ char *namefilter = 0;
+ int pidfilter = 0;
+ int threads = 0;
+
+ d = opendir("/proc");
+ if(d == 0) return -1;
+
+ while(argc > 1){
+ if(!strcmp(argv[1],"-t")) {
+ threads = 1;
+ } else if(!strcmp(argv[1],"-x")) {
+ display_flags |= SHOW_TIME;
+ } else if(!strcmp(argv[1], "-Z")) {
+ display_flags |= SHOW_MACLABEL;
+ } else if(!strcmp(argv[1],"-p")) {
+ display_flags |= SHOW_PRIO;
+ } else if(!strcmp(argv[1],"-c")) {
+ display_flags |= SHOW_CPU;
+ } else if(isdigit(argv[1][0])){
+ pidfilter = atoi(argv[1]);
+ } else {
+ namefilter = argv[1];
+ }
+ argc--;
+ argv++;
+ }
+
+ if (display_flags & SHOW_MACLABEL) {
+ printf("LABEL USER PID PPID NAME\n");
+ } else {
+ printf("USER PID PPID VSIZE RSS %s%s WCHAN PC NAME\n",
+ (display_flags&SHOW_CPU)?"CPU ":"",
+ (display_flags&SHOW_PRIO)?"PRIO NICE RTPRI SCHED ":"");
+ }
+ while((de = readdir(d)) != 0){
+ if(isdigit(de->d_name[0])){
+ int pid = atoi(de->d_name);
+ if(!pidfilter || (pidfilter == pid)) {
+ ps_line(pid, 0, namefilter);
+ if(threads) ps_threads(pid, namefilter);
+ }
+ }
+ }
+ closedir(d);
+ return 0;
+}
+
diff --git a/package/toolbox/src/src/readlink.c b/package/toolbox/src/src/readlink.c
new file mode 100644
index 000000000..71f74ebb3
--- /dev/null
+++ b/package/toolbox/src/src/readlink.c
@@ -0,0 +1,95 @@
+/*
+ * Copyright (c) 2013, 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 <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+static int skip_newline, quiet_errors, canonicalize;
+
+static void usage(char* name) {
+ fprintf(stderr, "Usage: %s [OPTION]... FILE\n", name);
+}
+
+int main(int argc, char* argv[]) {
+ int c;
+ while ((c = getopt(argc, argv, "nfqs")) != -1) {
+ switch (c) {
+ case 'n':
+ skip_newline = 1;
+ break;
+ case 'f':
+ canonicalize = 1;
+ break;
+ case 'q':
+ case 's':
+ quiet_errors = 1;
+ break;
+ case '?':
+ default:
+ usage(argv[0]);
+ return EXIT_FAILURE;
+ }
+ }
+ int index = optind;
+ if (argc - index != 1) {
+ usage(argv[0]);
+ return EXIT_FAILURE;
+ }
+
+ char name[PATH_MAX+1];
+ if (canonicalize) {
+ if(!realpath(argv[optind], name)) {
+ if (!quiet_errors) {
+ perror("readlink");
+ }
+ return EXIT_FAILURE;
+ }
+ } else {
+ ssize_t len = readlink(argv[1], name, PATH_MAX);
+
+ if (len < 0) {
+ if (!quiet_errors) {
+ perror("readlink");
+ }
+ return EXIT_FAILURE;
+ }
+ name[len] = '\0';
+ }
+
+ fputs(name, stdout);
+ if (!skip_newline) {
+ fputs("\n", stdout);
+ }
+
+ return EXIT_SUCCESS;
+}
diff --git a/package/toolbox/src/src/renice.c b/package/toolbox/src/src/renice.c
new file mode 100644
index 000000000..dece920a6
--- /dev/null
+++ b/package/toolbox/src/src/renice.c
@@ -0,0 +1,161 @@
+/*
+ * Copyright (c) 2008, 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>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+#include <sched.h>
+#include <getopt.h>
+
+static void
+usage(const char *s)
+{
+ fprintf(stderr, "USAGE: %s [[-r] [-t TYPE] priority pids ...] [-g pid]\n", s);
+ exit(EXIT_FAILURE);
+}
+
+void print_prio(pid_t pid)
+{
+ int sched;
+ struct sched_param sp;
+
+ printf("pid %d's priority: %d\n", pid, getpriority(PRIO_PROCESS, pid));
+
+ printf("scheduling class: ");
+ sched = sched_getscheduler(pid);
+ switch (sched) {
+ case SCHED_FIFO:
+ printf("FIFO\n");
+ break;
+ case SCHED_RR:
+ printf("RR\n");
+ break;
+ case SCHED_OTHER:
+ printf("Normal\n");
+ break;
+ case -1:
+ perror("sched_getscheduler");
+ break;
+ default:
+ printf("Unknown\n");
+ }
+
+ sched_getparam(pid, &sp);
+ printf("RT prio: %d (of %d to %d)\n", sp.sched_priority,
+ sched_get_priority_min(sched), sched_get_priority_max(sched));
+}
+
+int get_sched(char *str)
+{
+ if (strcasecmp(str, "RR") == 0)
+ return SCHED_RR;
+ else if (strcasecmp(str, "FIFO") == 0)
+ return SCHED_FIFO;
+ else if (strcasecmp(str, "NORMAL") == 0)
+ return SCHED_OTHER;
+ else if (strcasecmp(str, "OTHER") == 0)
+ return SCHED_OTHER;
+ return SCHED_RR;
+}
+
+int main(int argc, char *argv[])
+{
+ int prio;
+ int realtime = 0;
+ int opt;
+ int sched = SCHED_RR;
+ char *cmd = argv[0];
+
+ do {
+ opt = getopt(argc, argv, "rt:g:");
+ if (opt == -1)
+ break;
+ switch (opt) {
+ case 'r':
+ // do realtime priority adjustment
+ realtime = 1;
+ break;
+ case 't':
+ sched = get_sched(optarg);
+ break;
+ case 'g':
+ print_prio(atoi(optarg));
+ return 0;
+ default:
+ usage(cmd);
+ }
+ } while (1);
+
+ argc -= optind;
+ argv += optind;
+
+ if (argc < 1)
+ usage(cmd);
+
+ prio = atoi(argv[0]);
+ argc--;
+ argv++;
+
+ if (argc < 1)
+ usage(cmd);
+
+ while(argc) {
+ pid_t pid;
+
+ pid = atoi(argv[0]);
+ argc--;
+ argv++;
+
+ if (realtime) {
+ struct sched_param sp = { .sched_priority = prio };
+ int ret;
+
+ ret = sched_setscheduler(pid, sched, &sp);
+ if (ret) {
+ perror("sched_set_scheduler");
+ exit(EXIT_FAILURE);
+ }
+ } else {
+ int ret;
+
+ ret = setpriority(PRIO_PROCESS, pid, prio);
+ if (ret) {
+ perror("setpriority");
+ exit(EXIT_FAILURE);
+ }
+ }
+ }
+
+ return 0;
+}
diff --git a/package/toolbox/src/src/rm.c b/package/toolbox/src/src/rm.c
new file mode 100644
index 000000000..4cc4f8a14
--- /dev/null
+++ b/package/toolbox/src/src/rm.c
@@ -0,0 +1,126 @@
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include <dirent.h>
+#include <limits.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#define OPT_RECURSIVE 1
+#define OPT_FORCE 2
+
+static int usage()
+{
+ fprintf(stderr,"Usage: rm [-rR] [-f] <target>\n");
+ return -1;
+}
+
+/* return -1 on failure, with errno set to the first error */
+static int unlink_recursive(const char* name, int flags)
+{
+ struct stat st;
+ DIR *dir;
+ struct dirent *de;
+ int fail = 0;
+
+ /* is it a file or directory? */
+ if (lstat(name, &st) < 0)
+ return ((flags & OPT_FORCE) && errno == ENOENT) ? 0 : -1;
+
+ /* a file, so unlink it */
+ if (!S_ISDIR(st.st_mode))
+ return unlink(name);
+
+ /* a directory, so open handle */
+ dir = opendir(name);
+ if (dir == NULL)
+ return -1;
+
+ /* recurse over components */
+ errno = 0;
+ while ((de = readdir(dir)) != NULL) {
+ char dn[PATH_MAX];
+ if (!strcmp(de->d_name, "..") || !strcmp(de->d_name, "."))
+ continue;
+ sprintf(dn, "%s/%s", name, de->d_name);
+ if (unlink_recursive(dn, flags) < 0) {
+ if (!(flags & OPT_FORCE)) {
+ fail = 1;
+ break;
+ }
+ }
+ errno = 0;
+ }
+ /* in case readdir or unlink_recursive failed */
+ if (fail || errno < 0) {
+ int save = errno;
+ closedir(dir);
+ errno = save;
+ return -1;
+ }
+
+ /* close directory handle */
+ if (closedir(dir) < 0)
+ return -1;
+
+ /* delete target directory */
+ return rmdir(name);
+}
+
+int main(int argc, char *argv[])
+{
+ int ret;
+ int i, c;
+ int flags = 0;
+ int something_failed = 0;
+
+ if (argc < 2)
+ return usage();
+
+ /* check flags */
+ do {
+ c = getopt(argc, argv, "frR");
+ if (c == EOF)
+ break;
+ switch (c) {
+ case 'f':
+ flags |= OPT_FORCE;
+ break;
+ case 'r':
+ case 'R':
+ flags |= OPT_RECURSIVE;
+ break;
+ }
+ } while (1);
+
+ if (optind < 1 || optind >= argc) {
+ usage();
+ return -1;
+ }
+
+ /* loop over the file/directory args */
+ for (i = optind; i < argc; i++) {
+
+ if (flags & OPT_RECURSIVE) {
+ ret = unlink_recursive(argv[i], flags);
+ } else {
+ ret = unlink(argv[i]);
+ if (ret < 0 && errno == ENOENT && (flags & OPT_FORCE)) {
+ continue;
+ }
+ }
+
+ if (ret < 0) {
+ fprintf(stderr, "rm failed for %s, %s\n", argv[i], strerror(errno));
+ if (!(flags & OPT_FORCE)) {
+ return -1;
+ } else {
+ something_failed = 1;
+ }
+ }
+ }
+
+ return something_failed;
+}
+
diff --git a/package/toolbox/src/src/rmdir.c b/package/toolbox/src/src/rmdir.c
new file mode 100644
index 000000000..bec1f406e
--- /dev/null
+++ b/package/toolbox/src/src/rmdir.c
@@ -0,0 +1,28 @@
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+
+static int usage()
+{
+ fprintf(stderr,"rmdir <directory>\n");
+ return -1;
+}
+
+int main(int argc, char *argv[])
+{
+ int ret;
+ if(argc < 2) return usage();
+
+ while(argc > 1) {
+ argc--;
+ argv++;
+ ret = rmdir(argv[0]);
+ if(ret < 0) {
+ fprintf(stderr, "rmdir failed for %s, %s\n", argv[0], strerror(errno));
+ return ret;
+ }
+ }
+
+ return 0;
+}
diff --git a/package/toolbox/src/src/rmmod.c b/package/toolbox/src/src/rmmod.c
new file mode 100644
index 000000000..48ec5b977
--- /dev/null
+++ b/package/toolbox/src/src/rmmod.c
@@ -0,0 +1,53 @@
+#include <stdio.h>
+#include <string.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <malloc.h>
+#include <errno.h>
+#include <asm/unistd.h>
+
+extern int delete_module(const char *, unsigned int);
+
+int main(int argc, char **argv)
+{
+ int ret, i;
+ char *modname, *dot;
+
+ /* make sure we've got an argument */
+ if (argc < 2) {
+ fprintf(stderr, "usage: rmmod <module>\n");
+ return -1;
+ }
+
+ /* if given /foo/bar/blah.ko, make a weak attempt
+ * to convert to "blah", just for convenience
+ */
+ modname = strrchr(argv[1], '/');
+ if (!modname)
+ modname = argv[1];
+ else modname++;
+
+ dot = strchr(argv[1], '.');
+ if (dot)
+ *dot = '\0';
+
+ /* Replace "-" with "_". This would keep rmmod
+ * compatible with module-init-tools version of
+ * rmmod
+ */
+ for (i = 0; modname[i] != '\0'; i++) {
+ if (modname[i] == '-')
+ modname[i] = '_';
+ }
+
+ /* pass it to the kernel */
+ ret = delete_module(modname, O_NONBLOCK | O_EXCL);
+ if (ret != 0) {
+ fprintf(stderr, "rmmod: delete_module '%s' failed (errno %d)\n",
+ modname, errno);
+ return -1;
+ }
+
+ return 0;
+}
+
diff --git a/package/toolbox/src/src/route.c b/package/toolbox/src/src/route.c
new file mode 100644
index 000000000..031d52160
--- /dev/null
+++ b/package/toolbox/src/src/route.c
@@ -0,0 +1,113 @@
+/*
+ * Copyright (c) 2009, 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>
+#include <string.h>
+#include <errno.h>
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <linux/route.h>
+
+static inline int set_address(const char *address, struct sockaddr *sa) {
+ return inet_aton(address, &((struct sockaddr_in *)sa)->sin_addr);
+}
+
+/* current support the following routing entries */
+/* route add default dev wlan0 */
+/* route add default gw 192.168.1.1 dev wlan0 */
+/* route add -net 192.168.1.2 netmask 255.255.255.0 gw 192.168.1.1 */
+
+int main(int argc, char *argv[])
+{
+ struct rtentry rt = {
+ .rt_dst = {.sa_family = AF_INET},
+ .rt_genmask = {.sa_family = AF_INET},
+ .rt_gateway = {.sa_family = AF_INET},
+ };
+
+ errno = EINVAL;
+ if (argc > 2 && !strcmp(argv[1], "add")) {
+ if (!strcmp(argv[2], "default")) {
+ /* route add default dev wlan0 */
+ if (argc > 4 && !strcmp(argv[3], "dev")) {
+ rt.rt_flags = RTF_UP;
+ rt.rt_dev = argv[4];
+ errno = 0;
+ goto apply;
+ }
+
+ /* route add default gw 192.168.1.1 dev wlan0 */
+ if (argc > 6 && !strcmp(argv[3], "gw") && !strcmp(argv[5], "dev")) {
+ rt.rt_flags = RTF_UP | RTF_GATEWAY;
+ rt.rt_dev = argv[6];
+ if (set_address(argv[4], &rt.rt_gateway)) {
+ errno = 0;
+ }
+ goto apply;
+ }
+ }
+
+ /* route add -net 192.168.1.2 netmask 255.255.255.0 gw 192.168.1.1 */
+ if (argc > 7 && !strcmp(argv[2], "-net") &&
+ !strcmp(argv[4], "netmask")) {
+ if (!strcmp(argv[6], "gw")) {
+ rt.rt_flags = RTF_UP | RTF_GATEWAY;
+ if (set_address(argv[3], &rt.rt_dst) &&
+ set_address(argv[5], &rt.rt_genmask) &&
+ set_address(argv[7], &rt.rt_gateway)) {
+ errno = 0;
+ }
+ goto apply;
+ } else if (!strcmp(argv[6], "dev")) {
+ rt.rt_flags = RTF_UP;
+ rt.rt_dev = argv[7];
+ if (set_address(argv[3], &rt.rt_dst) &&
+ set_address(argv[5], &rt.rt_genmask)) {
+ errno = 0;
+ }
+ goto apply;
+ }
+ }
+ }
+
+apply:
+ if (!errno) {
+ int s = socket(AF_INET, SOCK_DGRAM, 0);
+ if (s != -1 && (ioctl(s, SIOCADDRT, &rt) != -1 || errno == EEXIST)) {
+ return 0;
+ }
+ }
+ puts(strerror(errno));
+ return errno;
+}
diff --git a/package/toolbox/src/src/schedtop.c b/package/toolbox/src/src/schedtop.c
new file mode 100644
index 000000000..abbc32861
--- /dev/null
+++ b/package/toolbox/src/src/schedtop.c
@@ -0,0 +1,332 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+#include <stdint.h>
+#include <string.h>
+
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <dirent.h>
+#include <signal.h>
+
+#include <pwd.h>
+
+struct thread_info {
+ int pid;
+ int tid;
+ char name[64];
+ unsigned long long exec_time;
+ unsigned long long delay_time;
+ uint32_t run_count;
+};
+
+struct thread_table {
+ size_t allocated;
+ size_t active;
+ struct thread_info *data;
+};
+
+enum {
+ FLAG_BATCH = 1U << 0,
+ FLAG_HIDE_IDLE = 1U << 1,
+ FLAG_SHOW_THREADS = 1U << 2,
+ FLAG_USE_ALTERNATE_SCREEN = 1U << 3,
+};
+
+static int time_dp = 9;
+static int time_div = 1;
+#define NS_TO_S_D(ns) \
+ (uint32_t)((ns) / 1000000000), time_dp, ((uint32_t)((ns) % 1000000000) / time_div)
+
+struct thread_table processes;
+struct thread_table last_processes;
+struct thread_table threads;
+struct thread_table last_threads;
+
+static void grow_table(struct thread_table *table)
+{
+ size_t size = table->allocated;
+ struct thread_info *new_table;
+ if (size < 128)
+ size = 128;
+ else
+ size *= 2;
+
+ new_table = realloc(table->data, size * sizeof(*table->data));
+ if (new_table == NULL) {
+ fprintf(stderr, "out of memory\n");
+ exit(1);
+ }
+ table->data = new_table;
+ table->allocated = size;
+}
+
+static struct thread_info *get_item(struct thread_table *table)
+{
+ if (table->active >= table->allocated)
+ grow_table(table);
+ return table->data + table->active;
+}
+
+static void commit_item(struct thread_table *table)
+{
+ table->active++;
+}
+
+static int read_line(char *line, size_t line_size)
+{
+ int fd;
+ int len;
+ fd = open(line, O_RDONLY);
+ if(fd == 0)
+ return -1;
+ len = read(fd, line, line_size - 1);
+ close(fd);
+ if (len <= 0)
+ return -1;
+ line[len] = '\0';
+ return 0;
+}
+
+static void add_thread(int pid, int tid, struct thread_info *proc_info)
+{
+ char line[1024];
+ char *name, *name_end;
+ size_t name_len;
+ struct thread_info *info;
+ if(tid == 0)
+ info = get_item(&processes);
+ else
+ info = get_item(&threads);
+ info->pid = pid;
+ info->tid = tid;
+
+ if(tid)
+ sprintf(line, "/proc/%d/task/%d/schedstat", pid, tid);
+ else
+ sprintf(line, "/proc/%d/schedstat", pid);
+ if (read_line(line, sizeof(line)))
+ return;
+ if(sscanf(line, "%llu %llu %u", &info->exec_time, &info->delay_time, &info->run_count) != 3)
+ return;
+ if (proc_info) {
+ proc_info->exec_time += info->exec_time;
+ proc_info->delay_time += info->delay_time;
+ proc_info->run_count += info->run_count;
+ }
+
+ name = NULL;
+ if (!tid) {
+ sprintf(line, "/proc/%d/cmdline", pid);
+ if (read_line(line, sizeof(line)) == 0 && line[0]) {
+ name = line;
+ name_len = strlen(name);
+ }
+ }
+ if (!name) {
+ if (tid)
+ sprintf(line, "/proc/%d/task/%d/stat", pid, tid);
+ else
+ sprintf(line, "/proc/%d/stat", pid);
+ if (read_line(line, sizeof(line)))
+ return;
+ name = strchr(line, '(');
+ if (name == NULL)
+ return;
+ name_end = strchr(name, ')');
+ if (name_end == NULL)
+ return;
+ name++;
+ name_len = name_end - name;
+ }
+ if (name_len >= sizeof(info->name))
+ name_len = sizeof(info->name) - 1;
+ memcpy(info->name, name, name_len);
+ info->name[name_len] = '\0';
+ if(tid == 0)
+ commit_item(&processes);
+ else
+ commit_item(&threads);
+}
+
+static void add_threads(int pid, struct thread_info *proc_info)
+{
+ char path[1024];
+ DIR *d;
+ struct dirent *de;
+ sprintf(path, "/proc/%d/task", pid);
+ d = opendir(path);
+ if(d == 0) return;
+ while((de = readdir(d)) != 0){
+ if(isdigit(de->d_name[0])){
+ int tid = atoi(de->d_name);
+ add_thread(pid, tid, proc_info);
+ }
+ }
+ closedir(d);
+}
+
+static void print_threads(int pid, uint32_t flags)
+{
+ size_t i, j;
+ for (i = 0; i < last_threads.active; i++) {
+ int epid = last_threads.data[i].pid;
+ int tid = last_threads.data[i].tid;
+ if (epid != pid)
+ continue;
+ for (j = 0; j < threads.active; j++)
+ if (tid == threads.data[j].tid)
+ break;
+ if (j == threads.active)
+ printf(" %5u died\n", tid);
+ else if (!(flags & FLAG_HIDE_IDLE) || threads.data[j].run_count - last_threads.data[i].run_count)
+ printf(" %5u %2u.%0*u %2u.%0*u %5u %5u.%0*u %5u.%0*u %7u %s\n", tid,
+ NS_TO_S_D(threads.data[j].exec_time - last_threads.data[i].exec_time),
+ NS_TO_S_D(threads.data[j].delay_time - last_threads.data[i].delay_time),
+ threads.data[j].run_count - last_threads.data[i].run_count,
+ NS_TO_S_D(threads.data[j].exec_time), NS_TO_S_D(threads.data[j].delay_time),
+ threads.data[j].run_count, threads.data[j].name);
+ }
+}
+
+static void update_table(DIR *d, uint32_t flags)
+{
+ size_t i, j;
+ struct dirent *de;
+
+ rewinddir(d);
+ while((de = readdir(d)) != 0){
+ if(isdigit(de->d_name[0])){
+ int pid = atoi(de->d_name);
+ struct thread_info *proc_info;
+ add_thread(pid, 0, NULL);
+ proc_info = &processes.data[processes.active - 1];
+ proc_info->exec_time = 0;
+ proc_info->delay_time = 0;
+ proc_info->run_count = 0;
+ add_threads(pid, proc_info);
+ }
+ }
+ if (!(flags & FLAG_BATCH))
+ printf("\e[H\e[0J");
+ printf("Processes: %zu, Threads %zu\n", processes.active, threads.active);
+ switch (time_dp) {
+ case 3:
+ printf(" TID --- SINCE LAST ---- ---------- TOTAL ----------\n");
+ printf(" PID EXEC_T DELAY SCHED EXEC_TIME DELAY_TIM SCHED NAME\n");
+ break;
+ case 6:
+ printf(" TID ------ SINCE LAST ------- ------------ TOTAL -----------\n");
+ printf(" PID EXEC_TIME DELAY_TIM SCHED EXEC_TIME DELAY_TIME SCHED NAME\n");
+ break;
+ default:
+ printf(" TID -------- SINCE LAST -------- ------------- TOTAL -------------\n");
+ printf(" PID EXEC_TIME DELAY_TIME SCHED EXEC_TIME DELAY_TIME SCHED NAME\n");
+ break;
+ }
+ for (i = 0; i < last_processes.active; i++) {
+ int pid = last_processes.data[i].pid;
+ for (j = 0; j < processes.active; j++)
+ if (pid == processes.data[j].pid)
+ break;
+ if (j == processes.active)
+ printf("%5u died\n", pid);
+ else if (!(flags & FLAG_HIDE_IDLE) || processes.data[j].run_count - last_processes.data[i].run_count) {
+ printf("%5u %2u.%0*u %2u.%0*u %5u %5u.%0*u %5u.%0*u %7u %s\n", pid,
+ NS_TO_S_D(processes.data[j].exec_time - last_processes.data[i].exec_time),
+ NS_TO_S_D(processes.data[j].delay_time - last_processes.data[i].delay_time),
+ processes.data[j].run_count - last_processes.data[i].run_count,
+ NS_TO_S_D(processes.data[j].exec_time), NS_TO_S_D(processes.data[j].delay_time),
+ processes.data[j].run_count, processes.data[j].name);
+ if (flags & FLAG_SHOW_THREADS)
+ print_threads(pid, flags);
+ }
+ }
+
+ {
+ struct thread_table tmp;
+ tmp = last_processes;
+ last_processes = processes;
+ processes = tmp;
+ processes.active = 0;
+ tmp = last_threads;
+ last_threads = threads;
+ threads = tmp;
+ threads.active = 0;
+ }
+}
+
+void
+sig_abort(int signum)
+{
+ printf("\e[?47l");
+ exit(0);
+}
+
+
+int main(int argc, char **argv)
+{
+ int c;
+ DIR *d;
+ uint32_t flags = 0;
+ int delay = 3000000;
+ float delay_f;
+
+ while(1) {
+ c = getopt(argc, argv, "d:ibtamun");
+ if (c == EOF)
+ break;
+ switch (c) {
+ case 'd':
+ delay_f = atof(optarg);
+ delay = delay_f * 1000000;
+ break;
+ case 'b':
+ flags |= FLAG_BATCH;
+ break;
+ case 'i':
+ flags |= FLAG_HIDE_IDLE;
+ break;
+ case 't':
+ flags |= FLAG_SHOW_THREADS;
+ break;
+ case 'a':
+ flags |= FLAG_USE_ALTERNATE_SCREEN;
+ break;
+ case 'm':
+ time_dp = 3;
+ time_div = 1000000;
+ break;
+ case 'u':
+ time_dp = 6;
+ time_div = 1000;
+ break;
+ case 'n':
+ time_dp = 9;
+ time_div = 1;
+ break;
+ }
+ }
+
+ d = opendir("/proc");
+ if(d == 0) return -1;
+
+ if (!(flags & FLAG_BATCH)) {
+ if(flags & FLAG_USE_ALTERNATE_SCREEN) {
+ signal(SIGINT, sig_abort);
+ signal(SIGPIPE, sig_abort);
+ signal(SIGTERM, sig_abort);
+ printf("\e7\e[?47h");
+ }
+ printf("\e[2J");
+ }
+ while (1) {
+ update_table(d, flags);
+ usleep(delay);
+ }
+ closedir(d);
+ return 0;
+}
diff --git a/package/toolbox/src/src/setkey.c b/package/toolbox/src/src/setkey.c
new file mode 100644
index 000000000..3b4fd700b
--- /dev/null
+++ b/package/toolbox/src/src/setkey.c
@@ -0,0 +1,91 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <string.h>
+#include <unistd.h>
+#include <linux/kd.h>
+#include <linux/vt.h>
+#include <errno.h>
+#include <sys/ioctl.h>
+
+static void setkey_usage(char *argv[])
+{
+ fprintf(stderr, "%s [-t <table>] [-k <index>] [-v value] [-r] [-h]\n"
+ " -t <table> Select table\n"
+ " -k <index> Select key\n"
+ " -v <value> Set entry\n"
+ " -r Read current entry\n"
+ " -h Print help\n", argv[0]);
+}
+
+#define TTYDEV "/dev/tty0"
+
+int main(int argc, char *argv[])
+{
+ int fd;
+ struct kbentry kbe;
+ int did_something = 0;
+
+ kbe.kb_table = 0;
+ kbe.kb_index = -1;
+ kbe.kb_value = 0;
+
+ fd = open(TTYDEV, O_RDWR | O_SYNC);
+ if (fd < 0) {
+ fprintf(stderr, "open %s: %s\n", TTYDEV, strerror(errno));
+ return 1;
+ }
+
+ do {
+ int c, ret;
+
+ c = getopt(argc, argv, "t:k:v:hr");
+ if (c == EOF)
+ break;
+
+ switch (c) {
+ case 't':
+ kbe.kb_table = strtol(optarg, NULL, 0);
+ break;
+ case 'k':
+ kbe.kb_index = strtol(optarg, NULL, 0);
+ break;
+ case 'v':
+ kbe.kb_value = strtol(optarg, NULL, 0);
+ ret = ioctl(fd, KDSKBENT, &kbe);
+ if (ret < 0) {
+ fprintf(stderr, "KDSKBENT %d %d %d failed: %s\n",
+ kbe.kb_table, kbe.kb_index, kbe.kb_value,
+ strerror(errno));
+ return 1;
+ }
+ did_something = 1;
+ break;
+ case 'r':
+ ret = ioctl(fd, KDGKBENT, &kbe);
+ if (ret < 0) {
+ fprintf(stderr, "KDGKBENT %d %d failed: %s\n",
+ kbe.kb_table, kbe.kb_index, strerror(errno));
+ return 1;
+ }
+ printf("0x%x 0x%x 0x%x\n",
+ kbe.kb_table, kbe.kb_index, kbe.kb_value);
+ did_something = 1;
+ break;
+ case 'h':
+ setkey_usage(argv);
+ return 1;
+ case '?':
+ fprintf(stderr, "%s: invalid option -%c\n",
+ argv[0], optopt);
+ return 1;
+ }
+ } while (1);
+
+ if(optind != argc || !did_something) {
+ setkey_usage(argv);
+ return 1;
+ }
+
+ return 0;
+}
diff --git a/package/toolbox/src/src/sleep.c b/package/toolbox/src/src/sleep.c
new file mode 100644
index 000000000..b83e8ecdb
--- /dev/null
+++ b/package/toolbox/src/src/sleep.c
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2008, 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>
+#include <unistd.h>
+#include <stdlib.h>
+
+static void
+usage(const char *s)
+{
+ fprintf(stderr, "USAGE: %s SECONDS\n", s);
+ exit(-1);
+}
+
+int main(int argc, char *argv[])
+{
+ unsigned long seconds;
+ char *endptr;
+
+ if (argc != 2) {
+ usage(argv[0]);
+ }
+
+ seconds = strtoul(argv[1], &endptr, 10);
+
+ if (endptr == argv[1]) {
+ usage(argv[0]);
+ }
+
+
+ sleep((unsigned int)seconds);
+
+ return 0;
+}
+
+
diff --git a/package/toolbox/src/src/sync.c b/package/toolbox/src/src/sync.c
new file mode 100644
index 000000000..d882a2eef
--- /dev/null
+++ b/package/toolbox/src/src/sync.c
@@ -0,0 +1,7 @@
+#include <unistd.h>
+
+int main(int argc, char **argv)
+{
+ sync();
+ return 0;
+}
diff --git a/package/toolbox/src/src/top.c b/package/toolbox/src/src/top.c
new file mode 100644
index 000000000..c4ac14ce2
--- /dev/null
+++ b/package/toolbox/src/src/top.c
@@ -0,0 +1,542 @@
+/*
+ * Copyright (c) 2008, 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 <ctype.h>
+#include <dirent.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <grp.h>
+#include <pwd.h>
+
+struct cpu_info {
+ long unsigned utime, ntime, stime, itime;
+ long unsigned iowtime, irqtime, sirqtime;
+};
+
+#define PROC_NAME_LEN 64
+#define THREAD_NAME_LEN 32
+
+struct proc_info {
+ struct proc_info *next;
+ pid_t pid;
+ pid_t tid;
+ uid_t uid;
+ gid_t gid;
+ char name[PROC_NAME_LEN];
+ char tname[THREAD_NAME_LEN];
+ char state;
+ long unsigned utime;
+ long unsigned stime;
+ long unsigned delta_utime;
+ long unsigned delta_stime;
+ long unsigned delta_time;
+ long vss;
+ long rss;
+ int prs;
+ int num_threads;
+};
+
+struct proc_list {
+ struct proc_info **array;
+ int size;
+};
+
+#define die(...) { fprintf(stderr, __VA_ARGS__); exit(EXIT_FAILURE); }
+
+#define INIT_PROCS 50
+#define THREAD_MULT 8
+static struct proc_info **old_procs, **new_procs;
+static int num_old_procs, num_new_procs;
+static struct proc_info *free_procs;
+static int num_used_procs, num_free_procs;
+
+static int max_procs, delay, iterations, threads;
+
+static struct cpu_info old_cpu, new_cpu;
+
+static struct proc_info *alloc_proc(void);
+static void free_proc(struct proc_info *proc);
+static void read_procs(void);
+static int read_stat(char *filename, struct proc_info *proc);
+static void add_proc(int proc_num, struct proc_info *proc);
+static int read_cmdline(char *filename, struct proc_info *proc);
+static int read_status(char *filename, struct proc_info *proc);
+static void print_procs(void);
+static struct proc_info *find_old_proc(pid_t pid, pid_t tid);
+static void free_old_procs(void);
+static int (*proc_cmp)(const void *a, const void *b);
+static int proc_cpu_cmp(const void *a, const void *b);
+static int proc_vss_cmp(const void *a, const void *b);
+static int proc_rss_cmp(const void *a, const void *b);
+static int proc_thr_cmp(const void *a, const void *b);
+static int numcmp(long long a, long long b);
+static void usage(char *cmd);
+
+int main(int argc, char *argv[]) {
+ int i;
+
+ num_used_procs = num_free_procs = 0;
+
+ max_procs = 0;
+ delay = 3;
+ iterations = -1;
+ proc_cmp = &proc_cpu_cmp;
+ for (i = 1; i < argc; i++) {
+ if (!strcmp(argv[i], "-m")) {
+ if (i + 1 >= argc) {
+ fprintf(stderr, "Option -m expects an argument.\n");
+ usage(argv[0]);
+ exit(EXIT_FAILURE);
+ }
+ max_procs = atoi(argv[++i]);
+ continue;
+ }
+ if (!strcmp(argv[i], "-n")) {
+ if (i + 1 >= argc) {
+ fprintf(stderr, "Option -n expects an argument.\n");
+ usage(argv[0]);
+ exit(EXIT_FAILURE);
+ }
+ iterations = atoi(argv[++i]);
+ continue;
+ }
+ if (!strcmp(argv[i], "-d")) {
+ if (i + 1 >= argc) {
+ fprintf(stderr, "Option -d expects an argument.\n");
+ usage(argv[0]);
+ exit(EXIT_FAILURE);
+ }
+ delay = atoi(argv[++i]);
+ continue;
+ }
+ if (!strcmp(argv[i], "-s")) {
+ if (i + 1 >= argc) {
+ fprintf(stderr, "Option -s expects an argument.\n");
+ usage(argv[0]);
+ exit(EXIT_FAILURE);
+ }
+ ++i;
+ if (!strcmp(argv[i], "cpu")) { proc_cmp = &proc_cpu_cmp; continue; }
+ if (!strcmp(argv[i], "vss")) { proc_cmp = &proc_vss_cmp; continue; }
+ if (!strcmp(argv[i], "rss")) { proc_cmp = &proc_rss_cmp; continue; }
+ if (!strcmp(argv[i], "thr")) { proc_cmp = &proc_thr_cmp; continue; }
+ fprintf(stderr, "Invalid argument \"%s\" for option -s.\n", argv[i]);
+ exit(EXIT_FAILURE);
+ }
+ if (!strcmp(argv[i], "-t")) { threads = 1; continue; }
+ if (!strcmp(argv[i], "-h")) {
+ usage(argv[0]);
+ exit(EXIT_SUCCESS);
+ }
+ fprintf(stderr, "Invalid argument \"%s\".\n", argv[i]);
+ usage(argv[0]);
+ exit(EXIT_FAILURE);
+ }
+
+ if (threads && proc_cmp == &proc_thr_cmp) {
+ fprintf(stderr, "Sorting by threads per thread makes no sense!\n");
+ exit(EXIT_FAILURE);
+ }
+
+ free_procs = NULL;
+
+ num_new_procs = num_old_procs = 0;
+ new_procs = old_procs = NULL;
+
+ read_procs();
+ while ((iterations == -1) || (iterations-- > 0)) {
+ old_procs = new_procs;
+ num_old_procs = num_new_procs;
+ memcpy(&old_cpu, &new_cpu, sizeof(old_cpu));
+ sleep(delay);
+ read_procs();
+ print_procs();
+ free_old_procs();
+ }
+
+ return 0;
+}
+
+static struct proc_info *alloc_proc(void) {
+ struct proc_info *proc;
+
+ if (free_procs) {
+ proc = free_procs;
+ free_procs = free_procs->next;
+ num_free_procs--;
+ } else {
+ proc = malloc(sizeof(*proc));
+ if (!proc) die("Could not allocate struct process_info.\n");
+ }
+
+ num_used_procs++;
+
+ return proc;
+}
+
+static void free_proc(struct proc_info *proc) {
+ proc->next = free_procs;
+ free_procs = proc;
+
+ num_used_procs--;
+ num_free_procs++;
+}
+
+#define MAX_LINE 256
+
+static void read_procs(void) {
+ DIR *proc_dir, *task_dir;
+ struct dirent *pid_dir, *tid_dir;
+ char filename[64];
+ FILE *file;
+ int proc_num;
+ struct proc_info *proc;
+ pid_t pid, tid;
+
+ int i;
+
+ proc_dir = opendir("/proc");
+ if (!proc_dir) die("Could not open /proc.\n");
+
+ new_procs = calloc(INIT_PROCS * (threads ? THREAD_MULT : 1), sizeof(struct proc_info *));
+ num_new_procs = INIT_PROCS * (threads ? THREAD_MULT : 1);
+
+ file = fopen("/proc/stat", "r");
+ if (!file) die("Could not open /proc/stat.\n");
+ fscanf(file, "cpu %lu %lu %lu %lu %lu %lu %lu", &new_cpu.utime, &new_cpu.ntime, &new_cpu.stime,
+ &new_cpu.itime, &new_cpu.iowtime, &new_cpu.irqtime, &new_cpu.sirqtime);
+ fclose(file);
+
+ proc_num = 0;
+ while ((pid_dir = readdir(proc_dir))) {
+ if (!isdigit(pid_dir->d_name[0]))
+ continue;
+
+ pid = atoi(pid_dir->d_name);
+
+ struct proc_info cur_proc;
+
+ if (!threads) {
+ proc = alloc_proc();
+
+ proc->pid = proc->tid = pid;
+
+ sprintf(filename, "/proc/%d/stat", pid);
+ read_stat(filename, proc);
+
+ sprintf(filename, "/proc/%d/cmdline", pid);
+ read_cmdline(filename, proc);
+
+ sprintf(filename, "/proc/%d/status", pid);
+ read_status(filename, proc);
+
+ proc->num_threads = 0;
+ } else {
+ sprintf(filename, "/proc/%d/cmdline", pid);
+ read_cmdline(filename, &cur_proc);
+
+ sprintf(filename, "/proc/%d/status", pid);
+ read_status(filename, &cur_proc);
+
+ proc = NULL;
+ }
+
+ sprintf(filename, "/proc/%d/task", pid);
+ task_dir = opendir(filename);
+ if (!task_dir) continue;
+
+ while ((tid_dir = readdir(task_dir))) {
+ if (!isdigit(tid_dir->d_name[0]))
+ continue;
+
+ if (threads) {
+ tid = atoi(tid_dir->d_name);
+
+ proc = alloc_proc();
+
+ proc->pid = pid; proc->tid = tid;
+
+ sprintf(filename, "/proc/%d/task/%d/stat", pid, tid);
+ read_stat(filename, proc);
+
+ strcpy(proc->name, cur_proc.name);
+ proc->uid = cur_proc.uid;
+ proc->gid = cur_proc.gid;
+
+ add_proc(proc_num++, proc);
+ } else {
+ proc->num_threads++;
+ }
+ }
+
+ closedir(task_dir);
+
+ if (!threads)
+ add_proc(proc_num++, proc);
+ }
+
+ for (i = proc_num; i < num_new_procs; i++)
+ new_procs[i] = NULL;
+
+ closedir(proc_dir);
+}
+
+static int read_stat(char *filename, struct proc_info *proc) {
+ FILE *file;
+ char buf[MAX_LINE], *open_paren, *close_paren;
+
+ file = fopen(filename, "r");
+ if (!file) return 1;
+ fgets(buf, MAX_LINE, file);
+ fclose(file);
+
+ /* Split at first '(' and last ')' to get process name. */
+ open_paren = strchr(buf, '(');
+ close_paren = strrchr(buf, ')');
+ if (!open_paren || !close_paren) return 1;
+
+ *open_paren = *close_paren = '\0';
+ strncpy(proc->tname, open_paren + 1, THREAD_NAME_LEN);
+ proc->tname[THREAD_NAME_LEN-1] = 0;
+
+ /* Scan rest of string. */
+ sscanf(close_paren + 1, " %c %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d "
+ "%lu %lu %*d %*d %*d %*d %*d %*d %*d %lu %ld "
+ "%*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %d",
+ &proc->state, &proc->utime, &proc->stime, &proc->vss, &proc->rss, &proc->prs);
+
+ return 0;
+}
+
+static void add_proc(int proc_num, struct proc_info *proc) {
+ int i;
+
+ if (proc_num >= num_new_procs) {
+ new_procs = realloc(new_procs, 2 * num_new_procs * sizeof(struct proc_info *));
+ if (!new_procs) die("Could not expand procs array.\n");
+ for (i = num_new_procs; i < 2 * num_new_procs; i++)
+ new_procs[i] = NULL;
+ num_new_procs = 2 * num_new_procs;
+ }
+ new_procs[proc_num] = proc;
+}
+
+static int read_cmdline(char *filename, struct proc_info *proc) {
+ FILE *file;
+ char line[MAX_LINE];
+
+ line[0] = '\0';
+ file = fopen(filename, "r");
+ if (!file) return 1;
+ fgets(line, MAX_LINE, file);
+ fclose(file);
+ if (strlen(line) > 0) {
+ strncpy(proc->name, line, PROC_NAME_LEN);
+ proc->name[PROC_NAME_LEN-1] = 0;
+ } else
+ proc->name[0] = 0;
+ return 0;
+}
+
+static int read_status(char *filename, struct proc_info *proc) {
+ FILE *file;
+ char line[MAX_LINE];
+ unsigned int uid, gid;
+
+ file = fopen(filename, "r");
+ if (!file) return 1;
+ while (fgets(line, MAX_LINE, file)) {
+ sscanf(line, "Uid: %u", &uid);
+ sscanf(line, "Gid: %u", &gid);
+ }
+ fclose(file);
+ proc->uid = uid; proc->gid = gid;
+ return 0;
+}
+
+static void print_procs(void) {
+ int i;
+ struct proc_info *old_proc, *proc;
+ long unsigned total_delta_time;
+ struct passwd *user;
+ char *user_str, user_buf[20];
+
+ for (i = 0; i < num_new_procs; i++) {
+ if (new_procs[i]) {
+ old_proc = find_old_proc(new_procs[i]->pid, new_procs[i]->tid);
+ if (old_proc) {
+ new_procs[i]->delta_utime = new_procs[i]->utime - old_proc->utime;
+ new_procs[i]->delta_stime = new_procs[i]->stime - old_proc->stime;
+ } else {
+ new_procs[i]->delta_utime = 0;
+ new_procs[i]->delta_stime = 0;
+ }
+ new_procs[i]->delta_time = new_procs[i]->delta_utime + new_procs[i]->delta_stime;
+ }
+ }
+
+ total_delta_time = (new_cpu.utime + new_cpu.ntime + new_cpu.stime + new_cpu.itime
+ + new_cpu.iowtime + new_cpu.irqtime + new_cpu.sirqtime)
+ - (old_cpu.utime + old_cpu.ntime + old_cpu.stime + old_cpu.itime
+ + old_cpu.iowtime + old_cpu.irqtime + old_cpu.sirqtime);
+
+ qsort(new_procs, num_new_procs, sizeof(struct proc_info *), proc_cmp);
+
+ printf("\n\n\n");
+ printf("User %ld%%, System %ld%%, IOW %ld%%, IRQ %ld%%\n",
+ ((new_cpu.utime + new_cpu.ntime) - (old_cpu.utime + old_cpu.ntime)) * 100 / total_delta_time,
+ ((new_cpu.stime ) - (old_cpu.stime)) * 100 / total_delta_time,
+ ((new_cpu.iowtime) - (old_cpu.iowtime)) * 100 / total_delta_time,
+ ((new_cpu.irqtime + new_cpu.sirqtime)
+ - (old_cpu.irqtime + old_cpu.sirqtime)) * 100 / total_delta_time);
+ printf("User %ld + Nice %ld + Sys %ld + Idle %ld + IOW %ld + IRQ %ld + SIRQ %ld = %ld\n",
+ new_cpu.utime - old_cpu.utime,
+ new_cpu.ntime - old_cpu.ntime,
+ new_cpu.stime - old_cpu.stime,
+ new_cpu.itime - old_cpu.itime,
+ new_cpu.iowtime - old_cpu.iowtime,
+ new_cpu.irqtime - old_cpu.irqtime,
+ new_cpu.sirqtime - old_cpu.sirqtime,
+ total_delta_time);
+ printf("\n");
+ if (!threads)
+ printf("%5s %2s %4s %1s %5s %7s %7s %3s %-8s %s\n", "PID", "PR", "CPU%", "S", "#THR", "VSS", "RSS", "PCY", "UID", "Name");
+ else
+ printf("%5s %5s %2s %4s %1s %7s %7s %3s %-8s %-15s %s\n", "PID", "TID", "PR", "CPU%", "S", "VSS", "RSS", "PCY", "UID", "Thread", "Proc");
+
+ for (i = 0; i < num_new_procs; i++) {
+ proc = new_procs[i];
+
+ if (!proc || (max_procs && (i >= max_procs)))
+ break;
+ user = getpwuid(proc->uid);
+ if (user && user->pw_name) {
+ user_str = user->pw_name;
+ } else {
+ snprintf(user_buf, 20, "%d", proc->uid);
+ user_str = user_buf;
+ }
+ if (!threads)
+ printf("%5d %2d %3ld%% %c %5d %6ldK %6ldK %-8.8s %s\n", proc->pid, proc->prs, proc->delta_time * 100 / total_delta_time, proc->state, proc->num_threads,
+ proc->vss / 1024, proc->rss * getpagesize() / 1024, user_str, proc->name[0] != 0 ? proc->name : proc->tname);
+ else
+ printf("%5d %5d %2d %3ld%% %c %6ldK %6ldK %-8.8s %-15s %s\n", proc->pid, proc->tid, proc->prs, proc->delta_time * 100 / total_delta_time, proc->state,
+ proc->vss / 1024, proc->rss * getpagesize() / 1024, user_str, proc->tname, proc->name);
+ }
+}
+
+static struct proc_info *find_old_proc(pid_t pid, pid_t tid) {
+ int i;
+
+ for (i = 0; i < num_old_procs; i++)
+ if (old_procs[i] && (old_procs[i]->pid == pid) && (old_procs[i]->tid == tid))
+ return old_procs[i];
+
+ return NULL;
+}
+
+static void free_old_procs(void) {
+ int i;
+
+ for (i = 0; i < num_old_procs; i++)
+ if (old_procs[i])
+ free_proc(old_procs[i]);
+
+ free(old_procs);
+}
+
+static int proc_cpu_cmp(const void *a, const void *b) {
+ struct proc_info *pa, *pb;
+
+ pa = *((struct proc_info **)a); pb = *((struct proc_info **)b);
+
+ if (!pa && !pb) return 0;
+ if (!pa) return 1;
+ if (!pb) return -1;
+
+ return -numcmp(pa->delta_time, pb->delta_time);
+}
+
+static int proc_vss_cmp(const void *a, const void *b) {
+ struct proc_info *pa, *pb;
+
+ pa = *((struct proc_info **)a); pb = *((struct proc_info **)b);
+
+ if (!pa && !pb) return 0;
+ if (!pa) return 1;
+ if (!pb) return -1;
+
+ return -numcmp(pa->vss, pb->vss);
+}
+
+static int proc_rss_cmp(const void *a, const void *b) {
+ struct proc_info *pa, *pb;
+
+ pa = *((struct proc_info **)a); pb = *((struct proc_info **)b);
+
+ if (!pa && !pb) return 0;
+ if (!pa) return 1;
+ if (!pb) return -1;
+
+ return -numcmp(pa->rss, pb->rss);
+}
+
+static int proc_thr_cmp(const void *a, const void *b) {
+ struct proc_info *pa, *pb;
+
+ pa = *((struct proc_info **)a); pb = *((struct proc_info **)b);
+
+ if (!pa && !pb) return 0;
+ if (!pa) return 1;
+ if (!pb) return -1;
+
+ return -numcmp(pa->num_threads, pb->num_threads);
+}
+
+static int numcmp(long long a, long long b) {
+ if (a < b) return -1;
+ if (a > b) return 1;
+ return 0;
+}
+
+static void usage(char *cmd) {
+ fprintf(stderr, "Usage: %s [ -m max_procs ] [ -n iterations ] [ -d delay ] [ -s sort_column ] [ -t ] [ -h ]\n"
+ " -m num Maximum number of processes to display.\n"
+ " -n num Updates to show before exiting.\n"
+ " -d num Seconds to wait between updates.\n"
+ " -s col Column to sort by (cpu,vss,rss,thr).\n"
+ " -t Show threads instead of processes.\n"
+ " -h Display this help screen.\n",
+ cmd);
+}
diff --git a/package/toolbox/src/src/touch.c b/package/toolbox/src/src/touch.c
new file mode 100644
index 000000000..7c38aa05a
--- /dev/null
+++ b/package/toolbox/src/src/touch.c
@@ -0,0 +1,115 @@
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <time.h>
+#include <unistd.h>
+
+static void usage(void)
+{
+ fprintf(stderr, "touch: usage: touch [-alm] [-t YYYYMMDD[.hhmmss]] <file>\n");
+ exit(1);
+}
+
+static time_t parse_time(char *s)
+{
+ struct tm tm;
+ int day = atoi(s);
+ int hour = 0;
+
+ while (*s && *s != '.') {
+ s++;
+ }
+
+ if (*s) {
+ s++;
+ hour = atoi(s);
+ }
+
+ tm.tm_year = day / 10000 - 1900;
+ tm.tm_mon = (day % 10000) / 100 - 1;
+ tm.tm_mday = day % 100;
+ tm.tm_hour = hour / 10000;
+ tm.tm_min = (hour % 10000) / 100;
+ tm.tm_sec = hour % 100;
+ tm.tm_isdst = -1;
+
+ return mktime(&tm);
+}
+
+int main(int argc, char *argv[])
+{
+ int i, fd, aflag = 0, mflag = 0, debug = 0, flags = 0;
+ struct timespec specified_time, times[2];
+ char *file = 0;
+
+ specified_time.tv_nsec = UTIME_NOW;
+
+ for (i = 1; i < argc; i++) {
+ if (argv[i][0] == '-') {
+ /* an option */
+ const char *arg = argv[i]+1;
+ while (arg[0]) {
+ switch (arg[0]) {
+ case 'a': aflag = 1; break;
+ case 'm': mflag = 1; break;
+ case 't':
+ if ((i+1) >= argc)
+ usage();
+ specified_time.tv_sec = parse_time(argv[++i]);
+ if (specified_time.tv_sec == -1) {
+ fprintf(stderr, "touch: invalid timestamp specified\n");
+ exit(1);
+ }
+ specified_time.tv_nsec = 0;
+ break;
+ case 'l': flags |= AT_SYMLINK_NOFOLLOW; break;
+ case 'd': debug = 1; break;
+ default:
+ usage();
+ }
+ arg++;
+ }
+ } else {
+ /* not an option, and only accept one filename */
+ if (i+1 != argc)
+ usage();
+ file = argv[i];
+ }
+ }
+
+ if (! file) {
+ fprintf(stderr, "touch: no file specified\n");
+ exit(1);
+ }
+
+ if (access(file, F_OK))
+ if ((fd=creat(file, 0666)) != -1)
+ close(fd);
+
+ if ((mflag == 0) && (aflag == 0))
+ aflag = mflag = 1;
+
+ if (aflag)
+ times[0] = specified_time;
+ else
+ times[0].tv_nsec = UTIME_OMIT;
+
+ if (mflag)
+ times[1] = specified_time;
+ else
+ times[1].tv_nsec = UTIME_OMIT;
+
+ if (debug) {
+ fprintf(stderr, "file = %s\n", file);
+ fprintf(stderr, "times[0].tv_sec = %lld, times[0].tv_nsec = %ld\n", (long long)times[0].tv_sec, (long)times[0].tv_nsec);
+ fprintf(stderr, "times[1].tv_sec = %lld, times[1].tv_nsec = %ld\n", (long long)times[1].tv_sec, (long)times[1].tv_nsec);
+ fprintf(stderr, "flags = 0x%8.8x\n", flags);
+ }
+
+ return utimensat(AT_FDCWD, file, times, flags);
+}
+
diff --git a/package/toolbox/src/src/umount.c b/package/toolbox/src/src/umount.c
new file mode 100644
index 000000000..aee3bdd39
--- /dev/null
+++ b/package/toolbox/src/src/umount.c
@@ -0,0 +1,91 @@
+
+#include <sys/mount.h>
+#include <sys/stat.h>
+#include <sys/sysmacros.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <linux/loop.h>
+#include <errno.h>
+
+#define LOOPDEV_MAXLEN 64
+#define LOOP_MAJOR 7
+
+static int is_loop(char *dev)
+{
+ struct stat st;
+ int ret = 0;
+
+ if (stat(dev, &st) == 0) {
+ if (S_ISBLK(st.st_mode) && (major(st.st_rdev) == LOOP_MAJOR)) {
+ ret = 1;
+ }
+ }
+
+ return ret;
+}
+
+static int is_loop_mount(const char* path, char *loopdev)
+{
+ FILE* f;
+ int count;
+ char device[256];
+ char mount_path[256];
+ char rest[256];
+ int result = 0;
+
+ f = fopen("/proc/mounts", "r");
+ if (!f) {
+ fprintf(stdout, "could not open /proc/mounts: %s\n", strerror(errno));
+ return -1;
+ }
+
+ do {
+ count = fscanf(f, "%255s %255s %255s\n", device, mount_path, rest);
+ if (count == 3) {
+ if (is_loop(device) && strcmp(path, mount_path) == 0) {
+ strlcpy(loopdev, device, LOOPDEV_MAXLEN);
+ result = 1;
+ break;
+ }
+ }
+ } while (count == 3);
+
+ fclose(f);
+ return result;
+}
+
+int main(int argc, char *argv[])
+{
+ int loop, loop_fd;
+ char loopdev[LOOPDEV_MAXLEN];
+
+ if(argc != 2) {
+ fprintf(stderr,"umount <path>\n");
+ return 1;
+ }
+
+ loop = is_loop_mount(argv[1], loopdev);
+ if (umount(argv[1])) {
+ fprintf(stderr, "failed: %s\n", strerror(errno));
+ return 1;
+ }
+
+ if (loop) {
+ // free the loop device
+ loop_fd = open(loopdev, O_RDONLY);
+ if (loop_fd < 0) {
+ fprintf(stderr, "open loop device failed: %s\n", strerror(errno));
+ return 1;
+ }
+ if (ioctl(loop_fd, LOOP_CLR_FD, 0) < 0) {
+ fprintf(stderr, "ioctl LOOP_CLR_FD failed: %s\n", strerror(errno));
+ return 1;
+ }
+
+ close(loop_fd);
+ }
+
+ return 0;
+}
diff --git a/package/toolbox/src/src/vmstat.c b/package/toolbox/src/src/vmstat.c
new file mode 100644
index 000000000..1ede95977
--- /dev/null
+++ b/package/toolbox/src/src/vmstat.c
@@ -0,0 +1,248 @@
+/*
+ * Copyright (c) 2008, 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 <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/param.h>
+#include <unistd.h>
+
+struct state {
+ long procs_r;
+ long procs_b;
+
+ long mem_free;
+ long mem_mapped;
+ long mem_anon;
+ long mem_slab;
+
+ long sys_in;
+ long sys_cs;
+ long sys_flt;
+
+ long cpu_us;
+ long cpu_ni;
+ long cpu_sy;
+ long cpu_id;
+ long cpu_wa;
+ long cpu_ir;
+ long cpu_si;
+};
+
+#define MAX_LINE 256
+
+char line[MAX_LINE];
+
+static void read_state(struct state *s);
+static int read_meminfo(struct state *s);
+static int read_stat(struct state *s);
+static int read_vmstat(struct state *s);
+static void print_header(void);
+static void print_line(struct state *old, struct state *new);
+static void usage(char *cmd);
+
+int main(int argc, char *argv[]) {
+ struct state s[2];
+ int iterations, delay, header_interval;
+ int toggle, count;
+ int i;
+
+ iterations = -1;
+ delay = 1;
+ header_interval = 20;
+
+ for (i = 1; i < argc; i++) {
+ if (!strcmp(argv[i], "-n")) {
+ if (i >= argc - 1) {
+ fprintf(stderr, "Option -n requires an argument.\n");
+ exit(EXIT_FAILURE);
+ }
+ iterations = atoi(argv[++i]);
+ continue;
+ }
+ if (!strcmp(argv[i], "-d")) {
+ if (i >= argc - 1) {
+ fprintf(stderr, "Option -d requires an argument.\n");
+ exit(EXIT_FAILURE);
+ }
+ delay = atoi(argv[++i]);
+ continue;
+ }
+ if (!strcmp(argv[i], "-r")) {
+ if (i >= argc - 1) {
+ fprintf(stderr, "Option -r requires an argument.\n");
+ exit(EXIT_FAILURE);
+ }
+ header_interval = atoi(argv[++i]);
+ continue;
+ }
+ if (!strcmp(argv[i], "-h")) {
+ usage(argv[0]);
+ exit(EXIT_SUCCESS);
+ }
+ fprintf(stderr, "Invalid argument \"%s\".\n", argv[i]);
+ usage(argv[0]);
+ exit(EXIT_FAILURE);
+ }
+
+ toggle = 0;
+ count = 0;
+
+ if (!header_interval)
+ print_header();
+ read_state(&s[1 - toggle]);
+ while ((iterations < 0) || (iterations-- > 0)) {
+ sleep(delay);
+ read_state(&s[toggle]);
+ if (header_interval) {
+ if (count == 0)
+ print_header();
+ count = (count + 1) % header_interval;
+ }
+ print_line(&s[1 - toggle], &s[toggle]);
+ toggle = 1 - toggle;
+ }
+
+ return 0;
+}
+
+static void read_state(struct state *s) {
+ int error;
+
+ error = read_meminfo(s);
+ if (error) {
+ fprintf(stderr, "vmstat: could not read /proc/meminfo: %s\n", strerror(error));
+ exit(EXIT_FAILURE);
+ }
+
+ error = read_stat(s);
+ if (error) {
+ fprintf(stderr, "vmstat: could not read /proc/stat: %s\n", strerror(error));
+ exit(EXIT_FAILURE);
+ }
+
+ error = read_vmstat(s);
+ if (error) {
+ fprintf(stderr, "vmstat: could not read /proc/vmstat: %s\n", strerror(error));
+ exit(EXIT_FAILURE);
+ }
+}
+
+static int read_meminfo(struct state *s) {
+ FILE *f;
+
+ f = fopen("/proc/meminfo", "r");
+ if (!f) return errno;
+
+ while (fgets(line, MAX_LINE, f)) {
+ sscanf(line, "MemFree: %ld kB", &s->mem_free);
+ sscanf(line, "AnonPages: %ld kB", &s->mem_anon);
+ sscanf(line, "Mapped: %ld kB", &s->mem_mapped);
+ sscanf(line, "Slab: %ld kB", &s->mem_slab);
+ }
+
+ fclose(f);
+
+ return 0;
+}
+
+static int read_stat(struct state *s) {
+ FILE *f;
+
+ f = fopen("/proc/stat", "r");
+ if (!f) return errno;
+
+ while (fgets(line, MAX_LINE, f)) {
+ if (!strncmp(line, "cpu ", 4)) {
+ sscanf(line, "cpu %ld %ld %ld %ld %ld %ld %ld",
+ &s->cpu_us, &s->cpu_ni, &s->cpu_sy, &s->cpu_id, &s->cpu_wa,
+ &s->cpu_ir, &s->cpu_si);
+ }
+ sscanf(line, "intr %ld", &s->sys_in);
+ sscanf(line, "ctxt %ld", &s->sys_cs);
+ sscanf(line, "procs_running %ld", &s->procs_r);
+ sscanf(line, "procs_blocked %ld", &s->procs_b);
+ }
+
+ fclose(f);
+
+ return 0;
+}
+
+static int read_vmstat(struct state *s) {
+ FILE *f;
+
+ f = fopen("/proc/vmstat", "r");
+ if (!f) return errno;
+
+ while (fgets(line, MAX_LINE, f)) {
+ sscanf(line, "pgmajfault %ld", &s->sys_flt);
+ }
+
+ fclose(f);
+
+ return 0;
+}
+
+static void print_header(void) {
+ printf("%-5s %-27s %-14s %-17s\n", "procs", "memory", "system", "cpu");
+ printf("%2s %2s %6s %6s %6s %6s %4s %4s %4s %2s %2s %2s %2s %2s %2s\n", "r", "b", "free", "mapped", "anon", "slab", "in", "cs", "flt", "us", "ni", "sy", "id", "wa", "ir");
+}
+
+/* Jiffies to percent conversion */
+#define JP(jif) ((jif) * 100 / (HZ))
+#define NORM(var) ((var) = (((var) > 99) ? (99) : (var)))
+
+static void print_line(struct state *old, struct state *new) {
+ int us, ni, sy, id, wa, ir;
+ us = JP(new->cpu_us - old->cpu_us); NORM(us);
+ ni = JP(new->cpu_ni - old->cpu_ni); NORM(ni);
+ sy = JP(new->cpu_sy - old->cpu_sy); NORM(sy);
+ id = JP(new->cpu_id - old->cpu_id); NORM(id);
+ wa = JP(new->cpu_wa - old->cpu_wa); NORM(wa);
+ ir = JP(new->cpu_ir - old->cpu_ir); NORM(ir);
+ printf("%2ld %2ld %6ld %6ld %6ld %6ld %4ld %4ld %4ld %2d %2d %2d %2d %2d %2d\n",
+ new->procs_r ? (new->procs_r - 1) : 0, new->procs_b,
+ new->mem_free, new->mem_mapped, new->mem_anon, new->mem_slab,
+ new->sys_in - old->sys_in, new->sys_cs - old->sys_cs, new->sys_flt - old->sys_flt,
+ us, ni, sy, id, wa, ir);
+}
+
+static void usage(char *cmd) {
+ fprintf(stderr, "Usage: %s [ -h ] [ -n iterations ] [ -d delay ] [ -r header_repeat ]\n"
+ " -n iterations How many rows of data to print.\n"
+ " -d delay How long to sleep between rows.\n"
+ " -r header_repeat How many rows to print before repeating\n"
+ " the header. Zero means never repeat.\n"
+ " -h Displays this help screen.\n",
+ cmd);
+}