diff options
Diffstat (limited to 'package/toolbox/src/src')
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); +} |