# HG changeset patch # User Rob Landley # Date 1345922722 18000 # Node ID 2986aa63a02192a2ed88685202c41bc354d650b0 # Parent 2d7c56913fda1908c0ca126c923b5085b3e195c0 Move commands into "posix", "lsb", and "other" menus/directories. diff -r 2d7c56913fda -r 2986aa63a021 Config.in --- a/Config.in Sat Aug 25 14:24:24 2012 -0500 +++ b/Config.in Sat Aug 25 14:25:22 2012 -0500 @@ -1,6 +1,6 @@ mainmenu "ToyBox Configuration" -menu "Global settings" +menu "Toybox global settings" config TOYBOX bool @@ -46,6 +46,6 @@ source generated/Config.probed -menu "Toys" +comment "" + source generated/Config.in -endmenu diff -r 2d7c56913fda -r 2986aa63a021 Makefile --- a/Makefile Sat Aug 25 14:24:24 2012 -0500 +++ b/Makefile Sat Aug 25 14:25:22 2012 -0500 @@ -3,7 +3,7 @@ all: toybox -toybox toybox_unstripped: .config *.[ch] lib/*.[ch] toys/*.[ch] scripts/*.sh +toybox toybox_unstripped: .config *.[ch] lib/*.[ch] toys/*.h toys/*/*.c scripts/*.sh scripts/make.sh .PHONY: clean distclean baseline bloatcheck install install_flat \ @@ -12,7 +12,7 @@ include kconfig/Makefile $(KCONFIG_TOP): generated/Config.in -generated/Config.in: toys/*.c scripts/genconfig.sh +generated/Config.in: toys/*/*.c scripts/genconfig.sh scripts/genconfig.sh HOSTCC?=cc diff -r 2d7c56913fda -r 2986aa63a021 scripts/genconfig.sh --- a/scripts/genconfig.sh Sat Aug 25 14:24:24 2012 -0500 +++ b/scripts/genconfig.sh Sat Aug 25 14:25:22 2012 -0500 @@ -26,14 +26,25 @@ genconfig() { - # extract config stanzas from each command source file, in alphabetical order - - for i in $(ls -1 toys/*.c) + # I could query the directory here, but I want to control the order + # and capitalization in the menu + for j in Posix LSB Other do - # Grab the config block for Config.in - echo "# $i" - sed -n '/^\*\//q;/^config [A-Z]/,$p' $i || return 1 + echo "menu \"$j commands\"" echo + + DIR=$(echo $j | tr A-Z a-z) + + # extract config stanzas from each source file, in alphabetical order + for i in $(ls -1 toys/$DIR/*.c) + do + # Grab the config block for Config.in + echo "# $i" + sed -n '/^\*\//q;/^config [A-Z]/,$p' $i || return 1 + echo + done + + echo endmenu done } diff -r 2d7c56913fda -r 2986aa63a021 scripts/make.sh --- a/scripts/make.sh Sat Aug 25 14:24:24 2012 -0500 +++ b/scripts/make.sh Sat Aug 25 14:25:22 2012 -0500 @@ -4,19 +4,27 @@ source ./configure +if [ -z ".config" ] +then + echo "No .config (see "make help" for configuration options)." + exit 1 +fi + echo "Extract configuration information from toys/*.c files..." scripts/genconfig.sh -echo "Generate headers from toys/*.c..." +echo "Generate headers from toys/*/*.c..." # Create a list of all the applets toybox can provide. Note that the first # entry is out of order on purpose (the toybox multiplexer applet must be the # first element of the array). The rest must be sorted in alphabetical order # for fast binary search. +echo "generated/newtoys.h" + function newtoys() { - for i in toys/*.c + for i in toys/*/*.c do sed -n -e '1,/^config [A-Z]/s/^USE_/&/p' $i || exit 1 done @@ -25,13 +33,13 @@ newtoys | sed 's/\(.*TOY(\)\([^,]*\),\(.*\)/\2 \1\2,\3/' | sort -k 1,1 \ | sed 's/[^ ]* //' >> generated/newtoys.h -# Extract global structure definitions and flag definitions from toys/*.c +# Extract global structure definitions and flag definitions from toys/*/*.c function getglobals() { - for i in toys/*.c + for i in toys/*/*.c do - NAME="$(echo $i | sed 's@toys/\(.*\)\.c@\1@')" + NAME="$(echo $i | sed 's@.*/\(.*\)\.c@\1@')" echo -e "// $i\n" sed -n -e '/^DEFINE_GLOBALS(/,/^)/b got;b;:got' \ @@ -58,6 +66,8 @@ done } +echo "generated/globals.h" + GLOBSTRUCT="$(getglobals)" ( echo "$GLOBSTRUCT" @@ -67,6 +77,7 @@ echo "} this;" ) > generated/globals.h +echo "generated/help.h" # Only recreate generated/help.h if python is installed if [ ! -z "$(which python)" ] && [ ! -z "$(grep 'CONFIG_HELP=y' .config)" ] then @@ -100,20 +111,24 @@ -e 's/.*/#define USE_&(...) __VA_ARGS__/p' \ .config > generated/config.h || exit 1 -# Extract a list of toys/*.c files to compile from the data in ".config" with -# sed, sort, and tr: +# Extract a list of toys/*/*.c files to compile from the data in ".config": # 1) Grab the XXX part of all CONFIG_XXX entries, removing everything after the # second underline # 2) Sort the list, keeping only one of each entry. # 3) Convert to lower case. # 4) Remove toybox itself from the list (as that indicates global symbols). -# 5) Add "toys/" prefix and ".c" suffix. +# 5) Add "toys/*/" prefix and ".c" suffix. -TOYFILES=$(cat .config | sed -nre 's/^CONFIG_(.*)=y/\1/;t skip;b;:skip;s/_.*//;p' | sort -u | tr A-Z a-z | grep -v '^toybox$' | sed 's@\(.*\)@toys/\1.c@' ) +TOYFILES=$(sed -nre 's/^CONFIG_(.*)=y/\1/;t skip;b;:skip;s/_.*//;p' < .config | sort -u | tr A-Z a-z | grep -v '^toybox$' | sed 's@\(.*\)@toys/\*/\1.c@') echo "Library probe..." +# We trust --as-needed to remove each library if we don't use any symbols +# out of it, this loop is because the compiler has no way to ignore a library +# that doesn't exist, so we have to detect and skip nonexistent libraries +# for it. + OPTLIBS="$(for i in util crypt m; do echo "int main(int argc, char *argv[]) {return 0;}" | ${CROSS_COMPILE}${CC} -xc - -o /dev/null -Wl,--as-needed -l$i > /dev/null 2>/dev/null && echo -l$i; done)" echo "Compile toybox..." diff -r 2d7c56913fda -r 2986aa63a021 toys/basename.c --- a/toys/basename.c Sat Aug 25 14:24:24 2012 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,45 +0,0 @@ -/* vi: set sw=4 ts=4: - * - * basename.c - Return non-directory portion of a pathname - * - * Copyright 2012 Tryn Mirell - * - * See http://opengroup.org/onlinepubs/9699919799/utilities/basename.html - - -USE_BASENAME(NEWTOY(basename, "<1>2", TOYFLAG_USR|TOYFLAG_BIN)) - -config BASENAME - bool "basename" - default y - help - usage: basename string [suffix] - - Return non-directory portion of a pathname removing suffix -*/ - -#include "toys.h" - -void basename_main(void) -{ - char *arg = toys.optargs[0], *suffix = toys.optargs[1], *base; - - while ((base = strrchr(arg, '/'))) { - if (base == arg) break; - if (!base[1]) *base = 0; - else { - base++; - break; - } - } - - if (!base) base = arg; - - // chop off the suffix if provided - if (suffix) { - arg = base + strlen(base) - strlen(suffix); - if (arg > base && !strcmp(arg, suffix)) *arg = 0; - } - - puts(base); -} diff -r 2d7c56913fda -r 2986aa63a021 toys/bzcat.c --- a/toys/bzcat.c Sat Aug 25 14:24:24 2012 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,30 +0,0 @@ -/* vi: set sw=4 ts=4: - * - * bzcat.c - decompress stdin to stdout using bunzip2. - * - * Copyright 2007 Rob Landley - * - * Not in SUSv3. - -USE_BZCAT(NEWTOY(bzcat, NULL, TOYFLAG_USR|TOYFLAG_BIN)) - -config BZCAT - bool "bzcat" - default y - help - usage: bzcat [filename...] - - Decompress listed files to stdout. Use stdin if no files listed. -*/ - -#include "toys.h" - -static void do_bzcat(int fd, char *name) -{ - bunzipStream(fd, 1); -} - -void bzcat_main(void) -{ - loopfiles(toys.optargs, do_bzcat); -} diff -r 2d7c56913fda -r 2986aa63a021 toys/cal.c --- a/toys/cal.c Sat Aug 25 14:24:24 2012 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,134 +0,0 @@ -/* vi: set sw=4 ts=4: - * - * cal.c - show calendar. - * - * Copyright 2011 Rob Landley - * - * See http://opengroup.org/onlinepubs/9699919799/utilities/cal.html - -USE_CAL(NEWTOY(cal, ">2", TOYFLAG_USR|TOYFLAG_BIN)) - -config CAL - bool "cal" - default y - help - usage: cal [[month] year] - Print a calendar. - - With one argument, prints all months of the specified year. - With two arguments, prints calendar for month and year. -*/ - -#include "toys.h" - -// Write calendar into buffer: each line is 20 chars wide, end indicated -// by empty string. - -static char *calstrings(char *buf, struct tm *tm) -{ - char temp[21]; - int wday, mday, start, len, line; - - // header - len = strftime(temp, 21, "%B %Y", tm); - len += (20-len)/2; - buf += sprintf(buf, "%*s%*s ", len, temp, 20-len, ""); - buf++; - buf += sprintf(buf, "Su Mo Tu We Th Fr Sa "); - buf++; - - // What day of the week does this month start on? - if (tm->tm_mday>1) - start = (36+tm->tm_wday-tm->tm_mday)%7; - else start = tm->tm_wday; - - // What day does this month end on? Alas, libc doesn't tell us... - len = 31; - if (tm->tm_mon == 1) { - int year = tm->tm_year; - len = 28; - if (!(year & 3) && !((year&100) && !(year&400))) len++; - } else if ((tm->tm_mon+(tm->tm_mon>6 ? 1 : 0)) & 1) len = 30; - - for (mday=line=0;line<6;line++) { - for (wday=0; wday<7; wday++) { - char *pat = " "; - if (!mday ? wday==start : mday high) error_exit(err, val, "greater", high); -} - -// Worst case scenario toybuf usage: sizeof(struct tm) plus 21 bytes/line -// plus 8 lines/month plus 12 months, comes to a bit over 2k of our 4k buffer. - -void cal_main(void) -{ - struct tm *tm; - char *buf = toybuf; - - if (toys.optc) { - // Conveniently starts zeroed - tm = (struct tm *)toybuf; - buf += sizeof(struct tm); - - // Last argument is year, one before that (if any) is month. - xcheckrange(tm->tm_year = atol(toys.optargs[--toys.optc]),1,9999); - tm->tm_year -= 1900; - tm->tm_mday = 1; - tm->tm_hour = 12; // noon to avoid timezone weirdness - if (toys.optc) { - xcheckrange(tm->tm_mon = atol(toys.optargs[--toys.optc]),1,12); - tm->tm_mon--; - - // Print 12 months of the year - - } else { - char *bufs[12]; - int i, j, k; - - for (i=0; i<12; i++) { - tm->tm_mon=i; - mktime(tm); - buf = calstrings(bufs[i]=buf, tm); - } - - // 4 rows, 6 lines each, 3 columns - for (i=0; i<4; i++) { - for (j=0; j<8; j++) { - for(k=0; k<3; k++) { - char **b = bufs+(k+i*3); - *b += printf("%s ", *b); - } - puts(""); - } - } - return; - } - - // What day of the week does that start on? - mktime(tm); - - } else { - time_t now; - time(&now); - tm = localtime(&now); - } - - calstrings(buf, tm); - while (*buf) buf += printf("%s\n", buf); -} diff -r 2d7c56913fda -r 2986aa63a021 toys/cat.c --- a/toys/cat.c Sat Aug 25 14:24:24 2012 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,42 +0,0 @@ -/* vi: set sw=4 ts=4: - * - * cat.c - copy inputs to stdout. - * - * Copyright 2006 Rob Landley - * - * See http://www.opengroup.org/onlinepubs/009695399/utilities/cat.html - -USE_CAT(NEWTOY(cat, "u", TOYFLAG_BIN)) - -config CAT - bool "cat" - default y - help - usage: cat [-u] [file...] - Copy (concatenate) files to stdout. If no files listed, copy from stdin. - Filename "-" is a synonym for stdin. - - -u Copy one byte at a time (slow). -*/ - -#include "toys.h" - -static void do_cat(int fd, char *name) -{ - int len, size=toys.optflags ? 1 : sizeof(toybuf); - - for (;;) { - len = read(fd, toybuf, size); - if (len<0) { - perror_msg("%s",name); - toys.exitval = EXIT_FAILURE; - } - if (len<1) break; - xwrite(1, toybuf, len); - } -} - -void cat_main(void) -{ - loopfiles(toys.optargs, do_cat); -} diff -r 2d7c56913fda -r 2986aa63a021 toys/catv.c --- a/toys/catv.c Sat Aug 25 14:24:24 2012 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,67 +0,0 @@ -/* vi: set sw=4 ts=4: - * - * cat -v implementation for toybox - * - * Copyright (C) 2006, 2007 Rob Landley - * - * Not in SUSv3, but see "Cat -v considered harmful" at - * http://cm.bell-labs.com/cm/cs/doc/84/kp.ps.gz - -USE_CATV(NEWTOY(catv, "vte", TOYFLAG_USR|TOYFLAG_BIN)) - -config CATV - bool "catv" - default y - help - usage: catv [-evt] [filename...] - - Display nonprinting characters as escape sequences. Use M-x for - high ascii characters (>127), and ^x for other nonprinting chars. - - -e Mark each newline with $ - -t Show tabs as ^I - -v Don't use ^x or M-x escapes. -*/ - -#include "toys.h" - -// Callback function for loopfiles() - -static void do_catv(int fd, char *name) -{ - for(;;) { - int i, len; - - len = read(fd, toybuf, sizeof(toybuf)); - if (len < 0) toys.exitval = EXIT_FAILURE; - if (len < 1) break; - for (i=0; i 126 && (toys.optflags & 4)) { - if (c == 127) { - printf("^?"); - continue; - } else { - printf("M-"); - c -= 128; - } - } - if (c < 32) { - if (c == 10) { - if (toys.optflags & 1) xputc('$'); - } else if (toys.optflags & (c==9 ? 2 : 4)) { - printf("^%c", c+'@'); - continue; - } - } - xputc(c); - } - } -} - -void catv_main(void) -{ - toys.optflags^=4; - loopfiles(toys.optargs, do_catv); -} diff -r 2d7c56913fda -r 2986aa63a021 toys/chgrp.c --- a/toys/chgrp.c Sat Aug 25 14:24:24 2012 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,124 +0,0 @@ -/* vi: set sw=4 ts=4: - * - * chown.c - Change ownership - * - * Copyright 2012 Georgi Chorbadzhiyski - * - * See http://pubs.opengroup.org/onlinepubs/009695399/utilities/chown.html - * See http://pubs.opengroup.org/onlinepubs/009695399/utilities/chgrp.html - * - * TODO: group only one of [HLP] - -USE_CHGRP(NEWTOY(chgrp, "<2hPLHRfv", TOYFLAG_BIN)) -USE_CHGRP(OLDTOY(chown, chgrp, "<2hPLHRfv", TOYFLAG_BIN)) - -config CHGRP - bool "chgrp/chown" - default y - help - usage: chown [-RHLP] [-fvh] [owner][:group] file... - usage: chgrp [-RHLP] [-fvh] group file... - - Change ownership of one or more files. - - -f suppress most error messages. - -h change symlinks instead of what they point to - -R recurse into subdirectories (implies -h). - -H with -R change target of symlink, follow command line symlinks - -L with -R change target of symlink, follow all symlinks - -P with -R change symlink, do not follow symlinks (default) - -v verbose output. -*/ - -#include "toys.h" - -#define FLAG_v 1 -#define FLAG_f 2 -#define FLAG_R 4 -#define FLAG_H 8 -#define FLAG_L 16 -#define FLAG_P 32 -#define FLAG_h 64 - -DEFINE_GLOBALS( - uid_t owner; - gid_t group; - char *owner_name, *group_name; - int symfollow; -) - -#define TT this.chgrp - -static int do_chgrp(struct dirtree *node) -{ - int fd, ret, flags = toys.optflags; - - // Depth first search - if (!dirtree_notdotdot(node)) return 0; - if ((flags & FLAG_R) && node->data != -1 && S_ISDIR(node->st.st_mode)) - return DIRTREE_COMEAGAIN|((flags&FLAG_L) ? DIRTREE_SYMFOLLOW : 0); - - fd = dirtree_parentfd(node); - ret = fchownat(fd, node->name, TT.owner, TT.group, - (flags&(FLAG_L|FLAG_H)) || !(flags&(FLAG_h|FLAG_R)) - ? 0 : AT_SYMLINK_NOFOLLOW); - - if (ret || (flags & FLAG_v)) { - char *path = dirtree_path(node, 0); - if (flags & FLAG_v) - xprintf("%s %s%s%s %s\n", toys.which->name, - TT.owner_name ? TT.owner_name : "", - toys.which->name[2]=='o' && TT.group_name ? ":" : "", - TT.group_name ? TT.group_name : "", path); - if (ret == -1 && !(toys.optflags & FLAG_f)) - perror_msg("changing owner:group of '%s' to '%s:%s'", path, - TT.owner_name, TT.group_name); - free(path); - } - toys.exitval |= ret; - - return 0; -} - -void chgrp_main(void) -{ - int ischown = toys.which->name[2] == 'o'; - char **s, *own; - - // Distinguish chown from chgrp - if (ischown) { - char *grp; - struct passwd *p; - - own = xstrdup(*toys.optargs); - if ((grp = strchr(own, ':')) || (grp = strchr(own, '.'))) { - *(grp++) = 0; - TT.group_name = grp; - } - if (*own) { - TT.owner_name = own; - p = getpwnam(own); - // TODO: trailing garbage? - if (!p && isdigit(*own)) p=getpwuid(atoi(own)); - if (!p) error_exit("no user '%s'", own); - TT.owner = p->pw_uid; - } - } else TT.group_name = *toys.optargs; - - if (TT.group_name) { - struct group *g; - g = getgrnam(TT.group_name); - if (!g) g=getgrgid(atoi(TT.group_name)); - if (!g) error_exit("no group '%s'", TT.group_name); - TT.group = g->gr_gid; - } - - for (s=toys.optargs+1; *s; s++) { - struct dirtree *new = dirtree_add_node(AT_FDCWD, *s, - toys.optflags&(FLAG_H|FLAG_L)); - if (new) handle_callback(new, do_chgrp); - else toys.exitval = 1; - } - - if (CFG_TOYBOX_FREE) free(own); -} diff -r 2d7c56913fda -r 2986aa63a021 toys/chmod.c --- a/toys/chmod.c Sat Aug 25 14:24:24 2012 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,72 +0,0 @@ -/* vi: set sw=4 ts=4: - * - * chmod.c - Change file mode bits - * - * Copyright 2012 Rob Landley - * - * See http://pubs.opengroup.org/onlinepubs/009695399/utilities/chmod.html - * - -USE_CHMOD(NEWTOY(chmod, "<2?vR", TOYFLAG_BIN)) - -config CHMOD - bool "chmod" - default y - help - usage: chmod [-R] MODE FILE... - - Change mode of listed file[s] (recursively with -R). - - MODE can be (comma-separated) stanzas: [ugoa][+-=][rwxstXugo] - - Stanzas are applied in order: For each category (u = user, - g = group, o = other, a = all three, if none specified default is a), - set (+), clear (-), or copy (=), r = read, w = write, x = execute. - s = u+s = suid, g+s = sgid, o+s = sticky. (+t is an alias for o+s). - suid/sgid: execute as the user/group who owns the file. - sticky: can't delete files you don't own out of this directory - X = x for directories or if any category already has x set. - - Or MODE can be an octal value up to 7777 ug uuugggooo top + - bit 1 = o+x, bit 1<<8 = u+w, 1<<11 = g+1 sstrwxrwxrwx bottom - - Examples: - chmod u+w file - allow owner of "file" to write to it. - chmod 744 file - user can read/write/execute, everyone else read only -*/ - -#include "toys.h" - -DEFINE_GLOBALS( - char *mode; -) - -#define TT this.chmod - -#define FLAG_R 1 -#define FLAG_v 2 - -int do_chmod(struct dirtree *try) -{ - mode_t mode; - - if (!dirtree_notdotdot(try)) return 0; - - mode = string_to_mode(TT.mode, try->st.st_mode); - if (toys.optflags & FLAG_v) { - char *s = dirtree_path(try, 0); - printf("chmod '%s' to %04o\n", s, mode); - free(s); - } - wfchmodat(dirtree_parentfd(try), try->name, mode); - - return (toys.optflags & FLAG_R) ? DIRTREE_RECURSE : 0; -} - -void chmod_main(void) -{ - TT.mode = *toys.optargs; - char **file; - - for (file = toys.optargs+1; *file; file++) dirtree_read(*file, do_chmod); -} diff -r 2d7c56913fda -r 2986aa63a021 toys/chroot.c --- a/toys/chroot.c Sat Aug 25 14:24:24 2012 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,28 +0,0 @@ -/* vi: set sw=4 ts=4: - * - * chroot.c - Run command in new root directory. - * - * Copyright 2007 Rob Landley - * - * Not in SUSv3. - -USE_CHROOT(NEWTOY(chroot, "^<1", TOYFLAG_USR|TOYFLAG_SBIN)) - -config CHROOT - bool "chroot" - default y - help - usage: chroot NEWPATH [commandline...] - - Run command within a new root directory. If no command, run /bin/sh. -*/ - -#include "toys.h" - -void chroot_main(void) -{ - char *binsh[] = {"/bin/sh", "-i", 0}; - if (chdir(*toys.optargs) || chroot(".")) - perror_exit("%s", *toys.optargs); - xexec(toys.optargs[1] ? toys.optargs+1 : binsh); -} diff -r 2d7c56913fda -r 2986aa63a021 toys/chvt.c --- a/toys/chvt.c Sat Aug 25 14:24:24 2012 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,51 +0,0 @@ -/* vi: set sw=4 ts=4: - * - * chvt.c - switch virtual terminals - * - * Copyright (C) 2008 David Anders - * - * Not in SUSv3. - -USE_CHVT(NEWTOY(chvt, "<1", TOYFLAG_USR|TOYFLAG_SBIN)) - -config CHVT - bool "chvt" - default y - help - usage: chvt N - - Change to virtual terminal number N. (This only works in text mode.) - - Virtual terminals are the Linux VGA text mode displays, ordinarily - switched between via alt-F1, alt-F2, etc. Use ctrl-alt-F1 to switch - from X to a virtual terminal, and alt-F6 (or F7, or F8) to get back. -*/ - -#include "toys.h" - -/* Note: get_console_fb() will need to be moved into a seperate lib section */ -int get_console_fd() -{ - int fd; - char *consoles[]={"/dev/console", "/dev/vc/0", "/dev/tty", NULL}, **cc; - - cc = consoles; - while (*cc) { - fd = open(*cc++, O_RDWR); - if (fd >= 0) return fd; - } - - return -1; -} - -void chvt_main(void) -{ - int vtnum, fd; - - vtnum=atoi(*toys.optargs); - - fd=get_console_fd(); - // These numbers are VT_ACTIVATE and VT_WAITACTIVE from linux/vt.h - if (fd < 0 || ioctl(fd, 0x5606, vtnum) || ioctl(fd, 0x5607, vtnum)) - perror_exit(NULL); -} diff -r 2d7c56913fda -r 2986aa63a021 toys/cksum.c --- a/toys/cksum.c Sat Aug 25 14:24:24 2012 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,87 +0,0 @@ -/* vi: set sw=4 ts=4: - * - * cksum.c - produce crc32 checksum value for each input - * - * Copyright 2008 Rob Landley - * - * See http://www.opengroup.org/onlinepubs/009695399/utilities/cksum.html - -USE_CKSUM(NEWTOY(cksum, "IPLN", TOYFLAG_BIN)) - -config CKSUM - bool "cksum" - default y - help - usage: cksum [-IPLN] [file...] - - For each file, output crc32 checksum value, length and name of file. - If no files listed, copy from stdin. Filename "-" is a synonym for stdin. - - -L Little endian (defaults to big endian) - -P Pre-inversion - -I Skip post-inversion - -N Do not include length in CRC calculation -*/ - -#include "toys.h" - -DEFINE_GLOBALS( - unsigned crc_table[256]; -) - -#define TT this.cksum - -static unsigned cksum_be(unsigned crc, unsigned char c) -{ - return (crc<<8)^TT.crc_table[(crc>>24)^c]; -} - -static unsigned cksum_le(unsigned crc, unsigned char c) -{ - return TT.crc_table[(crc^c)&0xff] ^ (crc>>8); -} - -static void do_cksum(int fd, char *name) -{ - unsigned crc = (toys.optflags&4) ? 0xffffffff : 0; - uint64_t llen = 0, llen2; - unsigned (*cksum)(unsigned crc, unsigned char c); - - - cksum = (toys.optflags&2) ? cksum_le : cksum_be; - // CRC the data - - for (;;) { - int len, i; - - len = read(fd, toybuf, sizeof(toybuf)); - if (len<0) { - perror_msg("%s",name); - toys.exitval = EXIT_FAILURE; - } - if (len<1) break; - - llen += len; - for (i=0; i>= 8; - } - } - - printf("%u %"PRIu64, (toys.optflags&8) ? crc : ~crc, llen2); - if (strcmp("-", name)) printf(" %s", name); - xputc('\n'); -} - -void cksum_main(void) -{ - crc_init(TT.crc_table, toys.optflags&2); - loopfiles(toys.optargs, do_cksum); -} diff -r 2d7c56913fda -r 2986aa63a021 toys/clear.c --- a/toys/clear.c Sat Aug 25 14:24:24 2012 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,23 +0,0 @@ -/* vi: set sw=4 ts=4: - * - * clear.c - clear the screen - * - * Copyright 2012 Rob Landley - * - * Not in SUSv4. - -USE_CLEAR(NEWTOY(clear, NULL, TOYFLAG_USR|TOYFLAG_BIN)) - -config CLEAR - bool "clear" - default y - help - Clear the screen. -*/ - -#include "toys.h" - -void clear_main(void) -{ - write(1, "\e[2J\e[H", 7); -} diff -r 2d7c56913fda -r 2986aa63a021 toys/cmp.c --- a/toys/cmp.c Sat Aug 25 14:24:24 2012 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,92 +0,0 @@ -/* vi: set sw=4 ts=4: - * - * cmp.c - Compare two files. - * - * Copyright 2012 Timothy Elliott - * - * See http://pubs.opengroup.org/onlinepubs/9699919799/utilities/cmp.html - -USE_CMP(NEWTOY(cmp, "<2>2ls", TOYFLAG_USR|TOYFLAG_BIN)) - -config CMP - bool "cmp" - default y - help - usage: cmp [-l] [-s] FILE1 FILE2 - - Compare the contents of two files. - - -l show all differing bytes - -s silent -*/ - -#include "toys.h" - -#define FLAG_s 1 -#define FLAG_l 2 - -DEFINE_GLOBALS( - int fd; - char *name; -) - -#define TT this.cmp - -// This handles opening the file and - -void do_cmp(int fd, char *name) -{ - int i, len1, len2, min_len, size = sizeof(toybuf)/2; - long byte_no = 1, line_no = 1; - char *buf2 = toybuf+size; - - // First time through, cache the data and return. - if (!TT.fd) { - TT.name = name; - // On return the old filehandle is closed, and this assures that even - // if we were called with stdin closed, the new filehandle != 0. - TT.fd = dup(fd); - return; - } - - for (;;) { - len1 = readall(TT.fd, toybuf, size); - len2 = readall(fd, buf2, size); - - min_len = len1 < len2 ? len1 : len2; - for (i=0; i - * - * See http://pubs.opengroup.org/onlinepubs/009695399/utilities/comm.html - -// <# and ># take single digit, so 321 define flags -USE_COMM(NEWTOY(comm, "<2>2321", TOYFLAG_USR|TOYFLAG_BIN)) - -config COMM - bool "comm" - default y - help - usage: comm [-123] FILE1 FILE2 - - Reads FILE1 and FILE2, which should be ordered, and produces three text - columns as output: lines only in FILE1; lines only in FILE2; and lines - in both files. Filename "-" is a synonym for stdin. - - -1 suppress the output column of lines unique to FILE1 - -2 suppress the output column of lines unique to FILE2 - -3 suppress the output column of lines duplicated in FILE1 and FILE2 -*/ - -#include "toys.h" - -#define FLAG_1 1 -#define FLAG_2 2 -#define FLAG_3 4 - -static void writeline(const char *line, int col) -{ - if (col == 0 && toys.optflags & FLAG_1) return; - else if (col == 1) { - if (toys.optflags & FLAG_2) return; - if (!(toys.optflags & FLAG_1)) putchar('\t'); - } else if (col == 2) { - if (toys.optflags & FLAG_3) return; - if (!(toys.optflags & FLAG_1)) putchar('\t'); - if (!(toys.optflags & FLAG_2)) putchar('\t'); - } - puts(line); -} - -void comm_main(void) -{ - int file[2]; - char *line[2]; - int i; - - if (toys.optflags == 7) return; - - for (i = 0; i < 2; i++) { - file[i] = strcmp("-", toys.optargs[i]) ? xopen(toys.optargs[i], O_RDONLY) : 0; - line[i] = get_line(file[i]); - } - - while (line[0] && line[1]) { - int order = strcmp(line[0], line[1]); - - if (order == 0) { - writeline(line[0], 2); - for (i = 0; i < 2; i++) { - free(line[i]); - line[i] = get_line(file[i]); - } - } else { - i = order < 0 ? 0 : 1; - writeline(line[i], i); - free(line[i]); - line[i] = get_line(file[i]); - } - } - - /* print rest of the longer file */ - for (i = line[0] ? 0 : 1; line[i];) { - writeline(line[i], i); - free(line[i]); - line[i] = get_line(file[i]); - } - - if (CFG_TOYBOX_FREE) for (i = 0; i < 2; i--) xclose(file[i]); -} diff -r 2d7c56913fda -r 2986aa63a021 toys/count.c --- a/toys/count.c Sat Aug 25 14:24:24 2012 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,36 +0,0 @@ -/* vi: set sw=4 ts=4: - * - * count.c - Progress indicator from stdin to stdout - * - * Copyright 2002 Rob Landley - * - * Not in SUSv3. - -USE_COUNT(NEWTOY(count, NULL, TOYFLAG_USR|TOYFLAG_BIN)) - -config COUNT - bool "count" - default y - help - usage: count - - Copy stdin to stdout, displaying simple progress indicator to stderr. -*/ - -#include "toys.h" - -void count_main(void) -{ - uint64_t size = 0; - int len; - char buf[32]; - - for (;;) { - len = xread(0, toybuf, sizeof(toybuf)); - if (!len) break; - size += len; - xwrite(1, toybuf, len); - xwrite(2, buf, sprintf(buf, "%"PRIu64" bytes\r", size)); - } - xwrite(2, "\n", 1); -} diff -r 2d7c56913fda -r 2986aa63a021 toys/cp.c --- a/toys/cp.c Sat Aug 25 14:24:24 2012 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,224 +0,0 @@ -/* vi: set sw=4 ts=4: - * - * cp.c - Copy files. - * - * Copyright 2008 Rob Landley - * - * See http://www.opengroup.org/onlinepubs/009695399/utilities/cp.html - * - * "R+ra+d+p+r" -USE_CP(NEWTOY(cp, "<2vslrRdpaHLPif", TOYFLAG_BIN)) - -config CP - bool "cp (broken by dirtree changes)" - default n - help - usage: cp -fiprdal SOURCE... DEST - - Copy files from SOURCE to DEST. If more than one SOURCE, DEST must - be a directory. - - -f force copy by deleting destination file - -i interactive, prompt before overwriting existing DEST - -p preserve timestamps, ownership, and permissions - -r recurse into subdirectories (DEST must be a directory) - -d don't dereference symlinks - -a same as -dpr - -l hard link instead of copying - -v verbose -*/ - -#include "toys.h" - -#define FLAG_f 1 -#define FLAG_i 2 -#define FLAG_P 4 // todo -#define FLAG_L 8 // todo -#define FLAG_H 16 // todo -#define FLAG_a 32 -#define FLAG_p 64 -#define FLAG_d 128 // todo -#define FLAG_R 256 -#define FLAG_r 512 -#define FLAG_l 1024 // todo -#define FLAG_s 2048 // todo -#define FLAG_v 4098 - -DEFINE_GLOBALS( - char *destname; - int destisdir; - int destisnew; - int keep_symlinks; -) - -#define TT this.cp - -// Copy an individual file or directory to target. - -void cp_file(char *src, char *dst, struct stat *srcst) -{ - int fdout = -1; - - // -i flag is specified and dst file exists. - if ((toys.optflags&FLAG_i) && !access(dst, R_OK) - && !yesno("cp: overwrite", 1)) - return; - - if (toys.optflags & FLAG_v) - printf("'%s' -> '%s'\n", src, dst); - - // Copy directory or file to destination. - - if (S_ISDIR(srcst->st_mode)) { - struct stat st2; - - // Always make directory writeable to us, so we can create files in it. - // - // Yes, there's a race window between mkdir() and open() so it's - // possible that -p can be made to chown a directory other than the one - // we created. The closest we can do to closing this is make sure - // that what we open _is_ a directory rather than something else. - - if ((mkdir(dst, srcst->st_mode | 0200) && errno != EEXIST) - || 0>(fdout=open(dst, 0)) || fstat(fdout, &st2) - || !S_ISDIR(st2.st_mode)) - { - perror_exit("mkdir '%s'", dst); - } - } else if (TT.keep_symlinks && S_ISLNK(srcst->st_mode)) { - char *link = xreadlink(src); - - // Note: -p currently has no effect on symlinks. How do you get a - // filehandle to them? O_NOFOLLOW causes the open to fail. - if (!link || symlink(link, dst)) perror_msg("link '%s'", dst); - free(link); - return; - } else if (toys.optflags & FLAG_l) { - if (link(src, dst)) perror_msg("link '%s'"); - return; - } else { - int fdin, i; - - fdin = xopen(src, O_RDONLY); - for (i=2 ; i; i--) { - fdout = open(dst, O_RDWR|O_CREAT|O_TRUNC, srcst->st_mode); - if (fdout>=0 || !(toys.optflags & FLAG_f)) break; - unlink(dst); - } - if (fdout<0) perror_exit("%s", dst); - xsendfile(fdin, fdout); - close(fdin); - } - - // Inability to set these isn't fatal, some require root access. - // Can't do fchmod() etc here because -p works on mkdir, too. - - if (toys.optflags & (FLAG_p|FLAG_a)) { - int mask = umask(0); - struct utimbuf ut; - - (void) fchown(fdout,srcst->st_uid, srcst->st_gid); - ut.actime = srcst->st_atime; - ut.modtime = srcst->st_mtime; - utime(dst, &ut); - umask(mask); - } - xclose(fdout); -} - -// Callback from dirtree_read() for each file/directory under a source dir. - -int cp_node(struct dirtree *node) -{ - char *path = dirtree_path(node, 0); // TODO: use openat() instead - char *s = path+strlen(path); - struct dirtree *n; - - // Find appropriate chunk of path for destination. - - n = node; - if (!TT.destisdir) n = n->parent; - for (;;n = n->parent) { - while (s!=path) { - if (*(--s)=='/') break; - } - if (!n) break; - } - if (s != path) s++; - - s = xmsprintf("%s/%s", TT.destname, s); - cp_file(path, s, &(node->st)); - free(s); - free(path); // redo this whole darn function. - - return 0; -} - -void cp_main(void) -{ - struct stat st; - int i; - - // Grab target argument. (Guaranteed to be there due to "<2" above.) - - TT.destname = toys.optargs[--toys.optc]; - - // If destination doesn't exist, are we ok with that? - - if (stat(TT.destname, &st)) { - if (toys.optc>1) goto error_notdir; - TT.destisnew++; - - // If destination exists... - - } else { - if (S_ISDIR(st.st_mode)) TT.destisdir++; - else if (toys.optc > 1) goto error_notdir; - } - - // Handle sources - - for (i=0; i - * - * See http://pubs.opengroup.org/onlinepubs/9699919799/utilities/date.html - -USE_DATE(NEWTOY(date, "r:u", TOYFLAG_BIN)) - -config DATE - bool "date" - default y - help - usage: date [-u] [-r file] [+format] | mmddhhmm[[cc]yy] - - Set/get the current date/time -*/ - -#include "toys.h" - -DEFINE_GLOBALS( - char *file; -) - -#define TT this.date - -#define FLAG_u 1 -#define FLAG_r 2 - -void date_main(void) -{ - const char *format_string = "%a %b %e %H:%M:%S %Z %Y"; - time_t now = time(NULL); - struct tm tm; - - if (TT.file) { - struct stat st; - - xstat(TT.file, &st); - now = st.st_mtim.tv_sec; - } - ((toys.optflags & FLAG_u) ? gmtime_r : localtime_r)(&now, &tm); - - // Display the date? - if (!toys.optargs[0] || toys.optargs[0][0] == '+') { - if (toys.optargs[0]) format_string = toys.optargs[0]+1; - if (!strftime(toybuf, sizeof(toybuf), format_string, &tm)) - perror_msg("bad format `%s'", format_string); - - puts(toybuf); - - // Set the date - } else { - struct timeval tv; - char *s = *toys.optargs; - int len = strlen(s); - - if (len < 8 || len > 12 || (len & 1)) error_msg("bad date `%s'", s); - - // Date format: mmddhhmm[[cc]yy] - memset(&tm, 0, sizeof(tm)); - len = sscanf(s, "%2u%2u%2u%2u", &tm.tm_mon, &tm.tm_mday, &tm.tm_hour, - &tm.tm_min); - tm.tm_mon--; - - // If year specified, overwrite one we fetched earlier - if (len > 8) { - sscanf(s, "%u", &tm.tm_year); - if (len == 12) tm.tm_year -= 1900; - /* 69-99 = 1969-1999, 0 - 68 = 2000-2068 */ - else if (tm.tm_year < 69) tm.tm_year += 100; - } - - if (toys.optflags & FLAG_u) { - // Get the UTC version of a struct tm - char *tz = CFG_TOYBOX_FREE ? getenv("TZ") : 0; - setenv("TZ", "UTC", 1); - tzset(); - tv.tv_sec = mktime(&tm); - if (CFG_TOYBOX_FREE) { - if (tz) setenv("TZ", tz, 1); - else unsetenv("TZ"); - tzset(); - } - } else tv.tv_sec = mktime(&tm); - - if (tv.tv_sec == (time_t)-1) error_msg("bad `%s'", toys.optargs[0]); - tv.tv_usec = 0; - if (!strftime(toybuf, sizeof(toybuf), format_string, &tm)) - perror_msg("bad format `%s'", format_string); - puts(toybuf); - if (settimeofday(&tv, NULL) < 0) perror_msg("cannot set date"); - } -} diff -r 2d7c56913fda -r 2986aa63a021 toys/df.c --- a/toys/df.c Sat Aug 25 14:24:24 2012 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,154 +0,0 @@ -/* vi: set sw=4 ts=4: - * - * df.c - report free disk space. - * - * Copyright 2006 Rob Landley - * - * See http://www.opengroup.org/onlinepubs/009695399/utilities/df.html - -USE_DF(NEWTOY(df, "Pkt*a", TOYFLAG_USR|TOYFLAG_SBIN)) - -config DF - bool "df (disk free)" - default y - help - usage: df [-t type] [FILESYSTEM ...] - - The "disk free" command, df shows total/used/available disk space for - each filesystem listed on the command line, or all currently mounted - filesystems. - - -t type - Display only filesystems of this type. - -config DF_PEDANTIC - bool "options -P and -k" - default y - depends on DF - help - usage: df [-Pk] - - -P The SUSv3 "Pedantic" option - - Provides a slightly less useful output format dictated by - the Single Unix Specification version 3, and sets the - units to 512 bytes instead of the default 1024 bytes. - - -k Sets units back to 1024 bytes (the default without -P) -*/ - -#include "toys.h" - -DEFINE_GLOBALS( - struct arg_list *fstype; - - long units; -) - -#define TT this.df - -static void show_mt(struct mtab_list *mt) -{ - int len; - long size, used, avail, percent; - uint64_t block; - - // Return if it wasn't found (should never happen, but with /etc/mtab...) - if (!mt) return; - - // If we have -t, skip other filesystem types - if (TT.fstype) { - struct arg_list *al; - - for (al = TT.fstype; al; al = al->next) { - if (!strcmp(mt->type, al->arg)) break; - } - if (!al) return; - } - - // If we don't have -a, skip synthetic filesystems - if (!(toys.optflags & 1) && !mt->statvfs.f_blocks) return; - - // Figure out how much total/used/free space this filesystem has, - // forcing 64-bit math because filesystems are big now. - block = mt->statvfs.f_bsize ? mt->statvfs.f_bsize : 1; - size = (long)((block * mt->statvfs.f_blocks) / TT.units); - used = (long)((block * (mt->statvfs.f_blocks-mt->statvfs.f_bfree)) - / TT.units); - avail = (long)((block - * (getuid() ? mt->statvfs.f_bavail : mt->statvfs.f_bfree)) - / TT.units); - percent = size ? 100-(long)((100*(uint64_t)avail)/size) : 0; - - // Figure out appropriate spacing - len = 25 - strlen(mt->device); - if (len < 1) len = 1; - if (CFG_DF_PEDANTIC && (toys.optflags & 8)) { - printf("%s %ld %ld %ld %ld%% %s\n", mt->device, size, used, avail, - percent, mt->dir); - } else { - printf("%s% *ld % 10ld % 9ld % 3ld%% %s\n",mt->device, len, - size, used, avail, percent, mt->dir); - } -} - -void df_main(void) -{ - struct mtab_list *mt, *mt2, *mtlist; - - // Handle -P and -k - TT.units = 1024; - if (CFG_DF_PEDANTIC && (toys.optflags & 8)) { - // Units are 512 bytes if you select "pedantic" without "kilobytes". - if ((toys.optflags&3) == 1) TT.units = 512; - printf("Filesystem %ld-blocks Used Available Capacity Mounted on\n", - TT.units); - } else puts("Filesystem\t1K-blocks\tUsed Available Use% Mounted on"); - - mtlist = getmountlist(1); - - // If we have a list of filesystems on the command line, loop through them. - if (*toys.optargs) { - char **next; - - for(next = toys.optargs; *next; next++) { - struct stat st; - - // Stat it (complain if we can't). - if(stat(*next, &st)) { - perror_msg("`%s'", *next); - toys.exitval = 1; - continue; - } - - // Find and display this filesystem. Use _last_ hit in case of - // -- bind mounts. - mt2 = NULL; - for (mt = mtlist; mt; mt = mt->next) - if (st.st_dev == mt->stat.st_dev) mt2 = mt; - show_mt(mt2); - } - } else { - // Get and loop through mount list. - - for (mt = mtlist; mt; mt = mt->next) { - struct mtab_list *mt2, *mt3; - - if (!mt->stat.st_dev) continue; - - // Filter out overmounts. - mt3 = mt; - for (mt2 = mt->next; mt2; mt2 = mt2->next) { - if (mt->stat.st_dev == mt2->stat.st_dev) { - // For --bind mounts, take last match - if (!strcmp(mt->device, mt2->device)) mt3 = mt2; - // Filter out overmounts - mt2->stat.st_dev = 0; - } - } - show_mt(mt3); - } - } - - if (CFG_TOYBOX_FREE) llist_traverse(mtlist, free); -} diff -r 2d7c56913fda -r 2986aa63a021 toys/dirname.c --- a/toys/dirname.c Sat Aug 25 14:24:24 2012 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,25 +0,0 @@ -/* vi: set sw=4 ts=4: - * - * dirname.c - show directory portion of path - * - * Copyright 2011 Rob Landley - * - * See http://opengroup.org/onlinepubs/9699919799/utilities/dirname.html - -USE_DIRNAME(NEWTOY(dirname, "<1", TOYFLAG_USR|TOYFLAG_BIN)) - -config DIRNAME - bool "dirname" - default y - help - usage: dirname PATH - - Show directory portion of path. -*/ - -#include "toys.h" - -void dirname_main(void) -{ - puts(dirname(*toys.optargs)); -} diff -r 2d7c56913fda -r 2986aa63a021 toys/dmesg.c --- a/toys/dmesg.c Sat Aug 25 14:24:24 2012 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,59 +0,0 @@ -/* vi: set sw=4 ts=4: - * - * dmesg.c - display/control kernel ring buffer. - * - * Copyright 2006, 2007 Rob Landley - * - * Not in SUSv3. - -USE_DMESG(NEWTOY(dmesg, "s#n#c", TOYFLAG_BIN)) - -config DMESG - bool "dmesg" - default y - help - usage: dmesg [-n level] [-s bufsize] | -c - - Print or control the kernel ring buffer. - - -n Set kernel logging level (1-9). - -s Size of buffer to read (in bytes), default 16384. - -c Clear the ring buffer after printing. -*/ - -#include "toys.h" -#include - -DEFINE_GLOBALS( - long level; - long size; -) - -#define TT this.dmesg - -void dmesg_main(void) -{ - // For -n just tell kernel to which messages to keep. - if (toys.optflags & 2) { - if (klogctl(8, NULL, TT.level)) - error_exit("klogctl"); - } else { - int size, i, last = '\n'; - char *data; - - // Figure out how much data we need, and fetch it. - size = TT.size; - if (size<2) size = 16384; - data = xmalloc(size); - size = klogctl(3 + (toys.optflags&1), data, size); - if (size < 0) error_exit("klogctl"); - - // Display data, filtering out level markers. - for (i=0; i - * - * No standard - -USE_DOS2UNIX(NEWTOY(dos2unix, NULL, TOYFLAG_BIN)) -USE_DOS2UNIX(OLDTOY(unix2dos, dos2unix, NULL, TOYFLAG_BIN)) - -config DOS2UNIX - bool "dos2unix/unix2dos" - default y - help - usage: dos2unix/unix2dos [file...] - - Convert newline format between dos (\r\n) and unix (just \n) - If no files listed copy from stdin, "-" is a synonym for stdin. -*/ - -#include "toys.h" - -DEFINE_GLOBALS( - char *tempfile; -) - -#define TT this.dos2unix - -static void do_dos2unix(int fd, char *name) -{ - char c = toys.which->name[0]; - int outfd = 1, catch = 0; - - if (fd) outfd = copy_tempfile(fd, name, &TT.tempfile); - - for (;;) { - int len, in, out; - - len = read(fd, toybuf+(sizeof(toybuf)/2), sizeof(toybuf)/2); - if (len<0) { - perror_msg("%s",name); - toys.exitval = 1; - } - if (len<1) break; - - for (in = out = 0; in < len; in++) { - char x = toybuf[in+sizeof(toybuf)/2]; - - // Drop \r only if followed by \n in dos2unix mode - if (catch) { - if (c == 'u' || x != '\n') toybuf[out++] = '\r'; - catch = 0; - // Add \r only if \n not after \r in unix2dos mode - } else if (c == 'u' && x == '\n') toybuf[out++] = '\r'; - - if (x == '\r') catch++; - else toybuf[out++] = x; - } - xwrite(outfd, toybuf, out); - } - if (catch) xwrite(outfd, "\r", 1); - - if (fd) replace_tempfile(-1, outfd, &TT.tempfile); -} - -void dos2unix_main(void) -{ - loopfiles(toys.optargs, do_dos2unix); -} diff -r 2d7c56913fda -r 2986aa63a021 toys/echo.c --- a/toys/echo.c Sat Aug 25 14:24:24 2012 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,97 +0,0 @@ -/* vi: set sw=4 ts=4: - * - * echo.c - echo supporting -n and -e. - * - * Copyright 2007 Rob Landley - * - * See http://www.opengroup.org/onlinepubs/009695399/utilities/echo.html - -USE_ECHO(NEWTOY(echo, "^?en", TOYFLAG_BIN)) - -config ECHO - bool "echo" - default y - help - usage: echo [-ne] [args...] - - Write each argument to stdout, with one space between each, followed - by a newline. - - -n No trailing newline. - -e Process the following escape sequences: - \\ backslash - \0NNN octal values (1 to 3 digits) - \a alert (beep/flash) - \b backspace - \c stop output here (avoids trailing newline) - \f form feed - \n newline - \r carriage return - \t horizontal tab - \v vertical tab - \xHH hexadecimal values (1 to 2 digits) -*/ - -#define THIS echo -#include "toys.h" - -#define FLAG_e (1<<1) -#define FLAG_n (1<<0) - -void echo_main(void) -{ - int i = 0, out; - char *arg, *from = "\\abfnrtv", *to = "\\\a\b\f\n\r\t\v", *c; - - for (;;) { - arg = toys.optargs[i]; - if (!arg) break; - if (i++) xputc(' '); - - // Should we output arg verbatim? - - if (!(toys.optflags&FLAG_e)) { - xprintf("%s", arg); - continue; - } - - // Handle -e - - for (c=arg;;) { - if (!(out = *(c++))) break; - - // handle \escapes - if (out == '\\' && *c) { - int n = 0, slash = *(c++); - char *found = strchr(from, slash); - if (found) out = to[found-from]; - else if (slash == 'c') goto done; - else if (slash == '0') { - out = 0; - while (*c>='0' && *c<='7' && n++<3) - out = (out*8)+*(c++)-'0'; - } else if (slash == 'x') { - out = 0; - while (n++<2) { - if (*c>='0' && *c<='9') - out = (out*16)+*(c++)-'0'; - else { - int temp = tolower(*c); - if (temp>='a' && temp<='f') { - out = (out*16)+temp-'a'+10; - c++; - } else break; - } - } - // Slash in front of unknown character, print literal. - } else c--; - } - xputc(out); - } - } - - // Output "\n" if no -n - if (!(toys.optflags&FLAG_n)) xputc('\n'); -done: - xflush(); -} diff -r 2d7c56913fda -r 2986aa63a021 toys/env.c --- a/toys/env.c Sat Aug 25 14:24:24 2012 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,52 +0,0 @@ -/* vi: set sw=4 ts=4: - * - * env.c - Set the environment for command invocation. - * - * Copyright 2012 Tryn Mirell - * env.c - -USE_ENV(NEWTOY(env, "^i", TOYFLAG_USR|TOYFLAG_BIN)) - -config ENV - bool "env" - default y - help - usage: env [-i] [NAME=VALUE...] [command [option...]] - - Set the environment for command invocation. - - -i Clear existing environment. -*/ - -#include "toys.h" - -extern char **environ; - -void env_main(void) -{ - char **ev; - char **command = NULL; - char *del = "="; - - if (toys.optflags & 1) clearenv(); - - for (ev = toys.optargs; *ev != NULL; ev++) { - char *env, *val = NULL; - - env = strtok(*ev, del); - - if (env) val = strtok(NULL, del); - - if (val) setenv(env, val, 1); - else { - command = ev; - break; - } - } - - if (!command) { - char **ep; - for (ep = environ; *ep; ep++) xputs(*ep); - return; - } else xexec(command); -} diff -r 2d7c56913fda -r 2986aa63a021 toys/false.c --- a/toys/false.c Sat Aug 25 14:24:24 2012 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,23 +0,0 @@ -/* vi: set sw=4 ts=4: - * - * false.c - Return nonzero. - * - * Copyright 2007 Rob Landley - * - * See http://www.opengroup.org/onlinepubs/009695399/utilities/false.html - -USE_FALSE(NEWTOY(false, NULL, TOYFLAG_BIN)) - -config FALSE - bool "false" - default y - help - Return nonzero. -*/ - -#include "toys.h" - -void false_main(void) -{ - toys.exitval = 1; -} diff -r 2d7c56913fda -r 2986aa63a021 toys/free.c --- a/toys/free.c Sat Aug 25 14:24:24 2012 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,60 +0,0 @@ -/* vi: set sw=4 ts=4: - * - * free.c - Display amount of free and used memory in the system. - * - * Copyright 2012 Elie De Brauwer - * - * Not in SUSv4. - -USE_FREE(NEWTOY(free, "gmkb", TOYFLAG_USR|TOYFLAG_BIN)) - -config FREE - bool "free" - default y - help - usage: free [-bkmg] - - Display the total, free and used amount of physical memory and - swap space. - - -bkmg Output in bytes (default), KB, MB or GB -*/ - -#include "toys.h" - -static unsigned long long convert(unsigned long d, unsigned int iscale, - unsigned int oscale) -{ - return ((unsigned long long)d*iscale)>>oscale; -} - -void free_main(void) -{ - struct sysinfo info; - unsigned int iscale = 1; - unsigned int oscale = 0; - - sysinfo(&info); - if (info.mem_unit) iscale = info.mem_unit; - if (toys.optflags & 1) oscale = 0; - if (toys.optflags & 2) oscale = 10; - if (toys.optflags & 4) oscale = 20; - if (toys.optflags & 8) oscale = 30; - - xprintf("\t\ttotal used free shared buffers\n"); - xprintf("Mem:%17llu%12llu%12llu%12llu%12llu\n", - convert(info.totalram, iscale, oscale), - convert(info.totalram-info.freeram, iscale, oscale), - convert(info.freeram, iscale, oscale), - convert(info.sharedram, iscale, oscale), - convert(info.bufferram, iscale, oscale)); - - xprintf("-/+ buffers/cache:%15llu%12llu\n", - convert(info.totalram - info.freeram - info.bufferram, iscale, oscale), - convert(info.freeram + info.bufferram, iscale, oscale)); - - xprintf("Swap:%16llu%12llu%12llu\n", - convert(info.totalswap, iscale, oscale), - convert(info.totalswap - info.freeswap, iscale, oscale), - convert(info.freeswap, iscale, oscale)); -} diff -r 2d7c56913fda -r 2986aa63a021 toys/head.c --- a/toys/head.c Sat Aug 25 14:24:24 2012 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,61 +0,0 @@ -/* vi: set sw=4 ts=4: - * - * head.c - copy first lines from input to stdout. - * - * Copyright 2006 Timothy Elliott - * - * See http://www.opengroup.org/onlinepubs/009695399/utilities/head.html - -USE_HEAD(NEWTOY(head, "n#<0=10", TOYFLAG_BIN)) - -config HEAD - bool "head" - default y - help - usage: head [-n number] [file...] - - Copy first lines from files to stdout. If no files listed, copy from - stdin. Filename "-" is a synonym for stdin. - - -n Number of lines to copy. -*/ - -#include "toys.h" - -DEFINE_GLOBALS( - long lines; - int file_no; -) - -#define TT this.head - -static void do_head(int fd, char *name) -{ - int i, len, lines=TT.lines, size=sizeof(toybuf); - - if (toys.optc > 1) { - // Print an extra newline for all but the first file - if (TT.file_no++) xprintf("\n"); - xprintf("==> %s <==\n", name); - xflush(); - } - - while (lines) { - len = read(fd, toybuf, size); - if (len<0) { - perror_msg("%s",name); - toys.exitval = EXIT_FAILURE; - } - if (len<1) break; - - for(i=0; i - * - * Not in SUSv4/LSB. - * See http://opengroup.org/onlinepubs/9699919799/utilities/ - * See http://refspecs.linuxfoundation.org/LSB_4.1.0/LSB-Core-generic/LSB-Core-generic/cmdbehav.html - -USE_HELLO(NEWTOY(hello, "e@d*c#b:a", TOYFLAG_USR|TOYFLAG_BIN)) - -config HELLO - bool "hello" - default n - help - usage: hello [-a] [-b string] [-c number] [-d list] [-e count] [...] - - A hello world program. You don't need this. - - Mostly used as an example/skeleton file for adding new commands, - occasionally nice to test kernel booting via "init=/bin/hello". -*/ - -#include "toys.h" - -// Hello doesn't use these globals, they're here for example/skeleton purposes. - -DEFINE_GLOBALS( - char *b_string; - long c_number; - struct arg_list *d_list; - long e_count; - - int more_globals; -) - -#define TT this.hello - -#define FLAG_a 1 -#define FLAG_b 2 -#define FLAG_c 4 -#define FLAG_d 8 -#define FLAG_e 16 - -void hello_main(void) -{ - printf("Hello world\n"); - - if (toys.optflags & FLAG_a) printf("Saw a\n"); - if (toys.optflags & FLAG_b) printf("b=%s\n", TT.b_string); - if (toys.optflags & FLAG_c) printf("c=%ld\n", TT.c_number); - while (TT.d_list) { - printf("d=%s\n", TT.d_list->arg); - TT.d_list = TT.d_list->next; - } - if (TT.e_count) printf("e was seen %ld times", TT.e_count); - - while (*toys.optargs) printf("optarg=%s\n", *(toys.optargs++)); -} diff -r 2d7c56913fda -r 2986aa63a021 toys/help.c --- a/toys/help.c Sat Aug 25 14:24:24 2012 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,48 +0,0 @@ -/* vi: set sw=4 ts=4: - * - * help.c - Show help for toybox - * - * Copyright 2007 Rob Landley - * - * Not in SUSv3, but exists as a bash builtin. - -USE_HELP(NEWTOY(help, "<1", TOYFLAG_BIN)) - -config HELP - bool "help" - default y - help - usage: help [command] - - Show usage information for toybox commands. - Run "toybox" with no arguments for a list of available commands. -*/ - - -#include "toys.h" -#include "generated/help.h" - -#undef NEWTOY -#undef OLDTOY -#define NEWTOY(name,opt,flags) help_##name "\0" -#define OLDTOY(name,oldname,opts,flags) "\xff" #oldname "\0" -static char *help_data = -#include "generated/newtoys.h" -; - -void help_main(void) -{ - struct toy_list *t = toy_find(*toys.optargs); - int i = t-toy_list; - char *s = help_data; - - if (!t) error_exit("Unknown command '%s'", *toys.optargs); - for (;;) { - while (i--) s += strlen(s) + 1; - if (*s != 255) break; - i = toy_find(++s)-toy_list; - s = help_data; - } - - fprintf(toys.exithelp ? stderr : stdout, "%s", s); -} diff -r 2d7c56913fda -r 2986aa63a021 toys/hostname.c --- a/toys/hostname.c Sat Aug 25 14:24:24 2012 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,33 +0,0 @@ -/* vi: set sw=4 ts=4: - * - * hostname.c - Get/Set the hostname - * - * Copyright 2012 Andre Renaud - * - * Not in SUSv4. - -USE_HOSTNAME(NEWTOY(hostname, NULL, TOYFLAG_BIN)) - -config HOSTNAME - bool "hostname" - default n - help - usage: hostname [newname] - - Get/Set the current hostname -*/ - -#include "toys.h" - -void hostname_main(void) -{ - const char *hostname = toys.optargs[0]; - if (hostname) { - if (sethostname(hostname, strlen(hostname))) - perror_exit("cannot set hostname to '%s'", hostname); - } else { - if (gethostname(toybuf, sizeof(toybuf))) - perror_exit("cannot get hostname"); - xputs(toybuf); - } -} diff -r 2d7c56913fda -r 2986aa63a021 toys/id.c --- a/toys/id.c Sat Aug 25 14:24:24 2012 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,119 +0,0 @@ -/* vi: set sw=4 ts=4: - * - * id.c - print real and effective user and group IDs - * - * Copyright 2012 Sony Network Entertainment, Inc. - * - * by Tim Bird - * - * See http://www.opengroup.org/onlinepubs/009695399/utilities/id.html - -USE_ID(NEWTOY(id, "nGgru", TOYFLAG_BIN)) - -config ID - bool "id" - default y - help - usage: id [-nGgru] - - Print user and group ID. - - -n print names instead of numeric IDs (to be used with -Ggu) - -G Show only the group IDs - -g Show only the effective group ID - -r Show real ID instead of effective ID - -u Show only the effective user ID -*/ - -#include "toys.h" - -#define FLAG_n (1<<4) -#define FLAG_G (1<<3) -#define FLAG_g (1<<2) -#define FLAG_r (1<<1) -#define FLAG_u 1 - -static void s_or_u(char *s, unsigned u, int done) -{ - if (toys.optflags & FLAG_n) printf("%s", s); - else printf("%u", u); - if (done) { - xputc('\n'); - exit(0); - } -} - -static void showid(char *header, unsigned u, char *s) -{ - printf("%s%u(%s)", header, u, s); -} - -struct passwd *xgetpwuid(uid_t uid) -{ - struct passwd *pwd = getpwuid(uid); - if (!pwd) error_exit(NULL); - return pwd; -} - -struct group *xgetgrgid(gid_t gid) -{ - struct group *group = getgrgid(gid); - if (!group) error_exit(NULL); - return group; -} - -void id_main(void) -{ - int flags = toys.optflags, i, ngroups; - struct passwd *pw; - struct group *grp; - uid_t uid = getuid(), euid = geteuid(); - gid_t gid = getgid(), egid = getegid(), *groups; - - /* check if a username is given */ - if (*toys.optargs) { - if (!(pw = getpwnam(*toys.optargs))) - error_exit("no such user '%s'", *toys.optargs); - uid = euid = pw->pw_uid; - gid = egid = pw->pw_gid; - } - - i = toys.optflags & FLAG_r; - pw = xgetpwuid(i ? uid : euid); - if (flags & FLAG_u) s_or_u(pw->pw_name, pw->pw_uid, 1); - - grp = xgetgrgid(i ? gid : egid); - if (flags & FLAG_g) s_or_u(grp->gr_name, grp->gr_gid, 1); - - if (!(flags & FLAG_G)) { - showid("uid=", pw->pw_uid, pw->pw_name); - showid(" gid=", grp->gr_gid, grp->gr_name); - - if (!i) { - if (uid != euid) { - pw = xgetpwuid(euid); - showid(" euid=", pw->pw_uid, pw->pw_name); - } - if (gid != egid) { - grp = xgetgrgid(egid); - showid(" egid=", grp->gr_gid, grp->gr_name); - } - } - - showid(" groups=", grp->gr_gid, grp->gr_name); - } - - - groups = (gid_t *)toybuf; - if (0 >= (ngroups = getgroups(sizeof(toybuf)/sizeof(gid_t), groups))) - perror_exit(0); - - for (i = 0; i < ngroups; i++) { - xputc(' '); - if (!(grp = getgrgid(groups[i]))) perror_msg(0); - else if (flags & FLAG_G) - s_or_u(grp->gr_name, grp->gr_gid, 0); - else if (grp->gr_gid != egid) showid("", grp->gr_gid, grp->gr_name); - } - xputc('\n'); -} diff -r 2d7c56913fda -r 2986aa63a021 toys/insmod.c --- a/toys/insmod.c Sat Aug 25 14:24:24 2012 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,47 +0,0 @@ -/* vi: set sw=4 ts=4: - * - * insmod.c - Load a module into the Linux kernel. - * - * Copyright 2012 Elie De Brauwer - * - * Not in SUSv4. - -USE_INSMOD(NEWTOY(insmod, "<1", TOYFLAG_BIN|TOYFLAG_NEEDROOT)) - -config INSMOD - bool "insmod" - default y - help - usage: insmod MODULE [MODULE_OPTIONS] - - Load the module named MODULE passing options if given. -*/ - -#include "toys.h" - -#include -#define init_module(mod, len, opts) syscall(__NR_init_module, mod, len, opts) - -void insmod_main(void) -{ - char * buf = NULL; - int len, res, i; - int fd = xopen(toys.optargs[0], O_RDONLY); - - len = fdlength(fd); - buf = xmalloc(len); - xreadall(fd, buf, len); - - i = 1; - while(toys.optargs[i] && - strlen(toybuf) + strlen(toys.optargs[i]) + 2 < sizeof(toybuf)) { - strcat(toybuf, toys.optargs[i++]); - strcat(toybuf, " "); - } - - res = init_module(buf, len, toybuf); - if (CFG_TOYBOX_FREE && buf != toybuf) free(buf); - - if (res) - perror_exit("failed to load %s", toys.optargs[0]); -} diff -r 2d7c56913fda -r 2986aa63a021 toys/kill.c --- a/toys/kill.c Sat Aug 25 14:24:24 2012 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,74 +0,0 @@ -/* vi: set sw=4 ts=4: - * - * kill.c - a program to send signals to processes - * - * Copyright 2012 Daniel Walter - * - * See http://opengroup.org/onlinepubs/9699919799/utilities/kill.html - -USE_KILL(NEWTOY(kill, "?s: l", TOYFLAG_BIN)) - -config KILL - bool "kill" - default y - help - usage: kill [-l [SIGNAL] | -s SIGNAL | -SIGNAL] pid... - - Send a signal to a process - -*/ - -#include "toys.h" - -DEFINE_GLOBALS( - char *signame; -) - -#define TT this.kill - -void kill_main(void) -{ - int signum; - char *tmp, **args = toys.optargs; - pid_t pid; - - // list signal(s) - if (toys.optflags & 1) { - if (*args) { - int signum = sig_to_num(*args); - char *s = NULL; - - if (signum>=0) s = num_to_sig(signum&127); - puts(s ? s : "UNKNOWN"); - } else sig_to_num(NULL); - return; - } - - // signal must come before pids, so "kill -9 -1" isn't confusing. - - if (!TT.signame && *args && **args=='-') TT.signame=*(args++)+1; - if (TT.signame) { - char *arg; - int i = strtol(TT.signame, &arg, 10); - if (!*arg) arg = num_to_sig(i); - else arg = TT.signame; - - if (!arg || -1 == (signum = sig_to_num(arg))) - error_exit("Unknown signal '%s'", arg); - } else signum = SIGTERM; - - if (!*args) { - toys.exithelp++; - error_exit("missing argument"); - } - - while (*args) { - char *arg = *(args++); - - pid = strtol(arg, &tmp, 10); - if (*tmp || kill(pid, signum) < 0) { - error_msg("unknown pid '%s'", arg); - toys.exitval = EXIT_FAILURE; - } - } -} diff -r 2d7c56913fda -r 2986aa63a021 toys/killall.c --- a/toys/killall.c Sat Aug 25 14:24:24 2012 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,79 +0,0 @@ -/* vi: set sw=4 ts=4: - * - * killall.c - Send signal (default: TERM) to all processes with given names. - * - * Copyright 2012 Andreas Heck - * - * Not in SUSv4. - -USE_KILLALL(NEWTOY(killall, "<1?lq", TOYFLAG_USR|TOYFLAG_BIN)) - -config KILLALL - bool "killall" - default y - help - usage: killall [-l] [-q] [-SIG] PROCESS_NAME... - - Send a signal (default: TERM) to all processes with the given names. - - -l print list of all available signals - -q don't print any warnings or error messages -*/ - -#include "toys.h" - -#define FLAG_q 1 -#define FLAG_l 2 - -DEFINE_GLOBALS( - int signum; -) -#define TT this.killall - -static void kill_process(pid_t pid) -{ - int ret; - - toys.exitval = 0; - ret = kill(pid, TT.signum); - - if (ret == -1 && !(toys.optflags & FLAG_q)) perror("kill"); -} - -void killall_main(void) -{ - char **names; - - if (toys.optflags & FLAG_l) { - sig_to_num(NULL); - return; - } - - TT.signum = SIGTERM; - toys.exitval++; - - if (!*toys.optargs) { - toys.exithelp = 1; - error_exit("Process name missing!"); - } - - names = toys.optargs; - - if (**names == '-') { - if (0 > (TT.signum = sig_to_num((*names)+1))) { - if (toys.optflags & FLAG_q) exit(1); - error_exit("Invalid signal"); - } - names++; - - if (!*names) { - toys.exithelp++; - error_exit("Process name missing!"); - } - } - - for_each_pid_with_name_in(names, kill_process); - - if (toys.exitval && !(toys.optflags & FLAG_q)) - error_exit("No such process"); -} diff -r 2d7c56913fda -r 2986aa63a021 toys/link.c --- a/toys/link.c Sat Aug 25 14:24:24 2012 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,27 +0,0 @@ -/* vi: set sw=4 ts=4: - * - * link.c - hardlink a file - * - * Copyright 2011 Rob Landley - * - * See http://opengroup.org/onlinepubs/9699919799/utilities/link.html - -USE_LINK(NEWTOY(link, "<2>2", TOYFLAG_USR|TOYFLAG_BIN)) - -config LINK - bool "link" - default y - help - usage: link FILE NEWLINK - - Create hardlink to a file. -*/ - -#include "toys.h" - -void link_main(void) -{ - if (link(toys.optargs[0], toys.optargs[1])) - perror_exit("couldn't link '%s' to '%s'", toys.optargs[1], - toys.optargs[0]); -} diff -r 2d7c56913fda -r 2986aa63a021 toys/ln.c --- a/toys/ln.c Sat Aug 25 14:24:24 2012 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,70 +0,0 @@ -/* vi: set sw=4 ts=4: - * - * ln.c - Create filesystem links - * - * Copyright 2012 Andre Renaud - * - * See http://pubs.opengroup.org/onlinepubs/9699919799/utilities/ln.html - -USE_LN(NEWTOY(ln, "<1nfs", TOYFLAG_BIN)) - -config LN - bool "ln" - default y - help - usage: ln [-sf] [FROM...] TO - - Create a link between FROM and TO. - With only one argument, create link in current directory. - - -s Create a symbolic link - -f Force the creation of the link, even if TO already exists - -n Symlink at destination treated as file -*/ - -#include "toys.h" - -#define FLAG_s 1 -#define FLAG_f 2 -#define FLAG_n 4 - -void ln_main(void) -{ - char *dest = toys.optargs[--toys.optc], *new; - struct stat buf; - int i; - - // With one argument, create link in current directory. - if (!toys.optc) { - toys.optc++; - dest="."; - } - - // Is destination a directory? - if (((toys.optflags&FLAG_n) ? lstat : stat)(dest, &buf) - || !S_ISDIR(buf.st_mode)) - { - if (toys.optc>1) error_exit("'%s' not a directory"); - buf.st_mode = 0; - } - - for (i=0; i - * - * Not in SUSv4. - * No support for PAM/securetty/selinux/login script/issue/utmp - * Relies on libcrypt for hash calculation. - -USE_LOGIN(NEWTOY(login, ">1fph:", TOYFLAG_BIN)) - -config LOGIN - bool "login" - default y - help - usage: login [-p] [-h host] [[-f] username] - - Establish a new session with the system. - -p Preserve environment - -h The name of the remote host for this login - -f Do not perform authentication -*/ - -#include "toys.h" - -#define LOGIN_TIMEOUT 60 -#define LOGIN_FAIL_TIMEOUT 3 -#define USER_NAME_MAX_SIZE 32 -#define HOSTNAME_SIZE 32 - -DEFINE_GLOBALS( - char *hostname; -) -#define TT this.login - -static void login_timeout_handler(int sig __attribute__((unused))) -{ - printf("\nLogin timed out after %d seconds.\n", LOGIN_TIMEOUT); - exit(0); -} - -static char *forbid[] = { - "BASH_ENV", - "ENV", - "HOME", - "IFS", - "LD_LIBRARY_PATH", - "LD_PRELOAD", - "LD_TRACE_LOADED_OBJECTS", - "LD_BIND_NOW", - "LD_AOUT_LIBRARY_PATH", - "LD_AOUT_PRELOAD", - "LD_NOWARN", - "LD_KEEPDIR", - "SHELL", - NULL -}; - -int verify_password(char * pwd) -{ - char *pass; - - if (read_password(toybuf, sizeof(toybuf), "Password: ")) return 1; - if (!pwd) return 1; - if (pwd[0] == '!' || pwd[0] == '*') return 1; - - pass = crypt(toybuf, pwd); - if (pass && !strcmp(pass, pwd)) return 0; - - return 1; -} - -void read_user(char * buff, int size) -{ - char hostname[HOSTNAME_SIZE+1]; - int i = 0; - hostname[HOSTNAME_SIZE] = 0; - if(!gethostname(hostname, HOSTNAME_SIZE)) fputs(hostname, stdout); - - fputs(" login: ", stdout); - fflush(stdout); - - do { - buff[0] = getchar(); - if (buff[0] == EOF) - exit(EXIT_FAILURE); - } while (isblank(buff[0])); - - if (buff[0] != '\n') - if(!fgets(&buff[1], HOSTNAME_SIZE-1, stdin)) - _exit(1); - - while(ipw_name,pwd->pw_gid)) return 1; - if (setgid(pwd->pw_uid)) return 1; - if (setuid(pwd->pw_uid)) return 1; - - return 0; -} - -void spawn_shell(const char *shell) -{ - const char * exec_name = strrchr(shell,'/'); - if (exec_name) exec_name++; - else exec_name = shell; - - snprintf(toybuf,sizeof(toybuf)-1, "-%s", shell); - execl(shell, toybuf, NULL); - error_exit("Failed to spawn shell"); -} - -void setup_environment(const struct passwd *pwd, int clear_env) -{ - if (chdir(pwd->pw_dir)) printf("bad home dir: %s\n", pwd->pw_dir); - - if (clear_env) { - const char * term = getenv("TERM"); - clearenv(); - if (term) setenv("TERM", term, 1); - } - - setenv("USER", pwd->pw_name, 1); - setenv("LOGNAME", pwd->pw_name, 1); - setenv("HOME", pwd->pw_dir, 1); - setenv("SHELL", pwd->pw_shell, 1); -} - -void login_main(void) -{ - int f_flag = (toys.optflags & 4) >> 2; - int p_flag = (toys.optflags & 2) >> 1; - int h_flag = toys.optflags & 1; - char username[USER_NAME_MAX_SIZE+1], *pass = NULL, **ss; - struct passwd * pwd = NULL; - struct spwd * spwd = NULL; - int auth_fail_cnt = 0; - - if (f_flag && toys.optc != 1) - error_exit("-f requires username"); - - if (geteuid()) error_exit("not root"); - - if (!isatty(0) || !isatty(1) || !isatty(2)) error_exit("no tty"); - - openlog("login", LOG_PID | LOG_CONS, LOG_AUTH); - signal(SIGALRM, login_timeout_handler); - alarm(LOGIN_TIMEOUT); - - for (ss = forbid; *ss; ss++) unsetenv(*ss); - - while (1) { - tcflush(0, TCIFLUSH); - - username[USER_NAME_MAX_SIZE] = 0; - if (toys.optargs[0]) - strncpy(username, toys.optargs[0], USER_NAME_MAX_SIZE); - else { - read_user(username, USER_NAME_MAX_SIZE+1); - if (username[0] == 0) continue; - } - - pwd = getpwnam(username); - if (!pwd) goto query_pass; // Non-existing user - - if (pwd->pw_passwd[0] == '!' || pwd->pw_passwd[0] == '*') - goto query_pass; // Locked account - - if (f_flag) break; // Pre-authenticated - - if (!pwd->pw_passwd[0]) break; // Password-less account - - pass = pwd->pw_passwd; - if (pwd->pw_passwd[0] == 'x') { - spwd = getspnam (username); - if (spwd) pass = spwd->sp_pwdp; - } - -query_pass: - if (!verify_password(pass)) break; - - f_flag = 0; - syslog(LOG_WARNING, "invalid password for '%s' on %s %s %s", username, - ttyname(0), (h_flag)?"from":"", (h_flag)?TT.hostname:""); - - sleep(LOGIN_FAIL_TIMEOUT); - puts("Login incorrect"); - - if (++auth_fail_cnt == 3) - error_exit("Maximum number of tries exceeded (%d)\n", auth_fail_cnt); - - username[0] = 0; - pwd = NULL; - spwd = NULL; - } - - alarm(0); - - if (pwd->pw_uid) handle_nologin(); - - if (change_identity(pwd)) error_exit("Failed to change identity"); - - setup_environment(pwd, !p_flag); - - handle_motd(); - - syslog(LOG_INFO, "%s logged in on %s %s %s", pwd->pw_name, - ttyname(0), (h_flag)?"from":"", (h_flag)?TT.hostname:""); - - spawn_shell(pwd->pw_shell); -} diff -r 2d7c56913fda -r 2986aa63a021 toys/logname.c --- a/toys/logname.c Sat Aug 25 14:24:24 2012 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,29 +0,0 @@ -/* vi: set sw=4 ts=4: - * - * logname.c - Print user's login name. - * - * Copyright 2012 Elie De Brauwer - * - * See http://pubs.opengroup.org/onlinepubs/9699919799/utilities/logname.html - -USE_LOGNAME(NEWTOY(logname, ">0", TOYFLAG_BIN)) - -config LOGNAME - bool "logname" - default y - help - usage: logname - - Prints the calling user's name or an error when this cannot be - determined. -*/ - -#include "toys.h" - -void logname_main(void) -{ - if (getlogin_r(toybuf, sizeof(toybuf))){ - error_exit("no login name"); - } - xputs(toybuf); -} diff -r 2d7c56913fda -r 2986aa63a021 toys/ls.c --- a/toys/ls.c Sat Aug 25 14:24:24 2012 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,493 +0,0 @@ -/* vi: set sw=4 ts=4: - * - * ls.c - list files - * - * Copyright 2012 Andre Renaud - * Copyright 2012 Rob Landley - * - * See http://pubs.opengroup.org/onlinepubs/9699919799/utilities/ls.html - -// "[-Cl]" -USE_LS(NEWTOY(ls, "goACFHLRSacdfiklmnpqrstux1", TOYFLAG_BIN)) - -config LS - bool "ls" - default y - help - usage: ls [-ACFHLRSacdfiklmnpqrstux1] [directory...] - list files - - what to show: - -a all files including .hidden - -c use ctime for timestamps - -d directory, not contents - -i inode number - -k block sizes in kilobytes - -p put a '/' after directory names - -q unprintable chars as '?' - -s size (in blocks) - -u use access time for timestamps - -A list all files except . and .. - -H follow command line symlinks - -L follow symlinks - -R recursively list files in subdirectories - -F append file type indicator (/=dir, *=exe, @=symlink, |=FIFO) - - output formats: - -1 list one file per line - -C columns (sorted vertically) - -g like -l but no owner - -l long (show full details for each file) - -m comma separated - -n like -l but numeric uid/gid - -o like -l but no group - -x columns (sorted horizontally) - - sorting (default is alphabetical): - -f unsorted - -r reverse - -t timestamp - -S size -*/ - -#include "toys.h" - -#define FLAG_1 (1<<0) -#define FLAG_x (1<<1) -#define FLAG_u (1<<2) -#define FLAG_t (1<<3) -#define FLAG_s (1<<4) -#define FLAG_r (1<<5) -#define FLAG_q (1<<6) -#define FLAG_p (1<<7) -#define FLAG_n (1<<8) -#define FLAG_m (1<<9) -#define FLAG_l (1<<10) -#define FLAG_k (1<<11) -#define FLAG_i (1<<12) -#define FLAG_f (1<<13) -#define FLAG_d (1<<14) -#define FLAG_c (1<<15) -#define FLAG_a (1<<16) -#define FLAG_S (1<<17) -#define FLAG_R (1<<18) -#define FLAG_L (1<<19) -#define FLAG_H (1<<20) -#define FLAG_F (1<<21) -#define FLAG_C (1<<22) -#define FLAG_A (1<<23) -#define FLAG_o (1<<24) -#define FLAG_g (1<<25) - -// test sst output (suid/sticky in ls flaglist) - -// ls -lR starts .: then ./subdir: - -DEFINE_GLOBALS( - struct dirtree *files; - - unsigned screen_width; - int nl_title; - - // group and user can make overlapping use of the utoa() buf, so move it - char uid_buf[12]; -) - -#define TT this.ls - -void dlist_to_dirtree(struct dirtree *parent) -{ - // Turn double_list into dirtree - struct dirtree *dt = parent->child; - if (dt) { - dt->parent->next = NULL; - while (dt) { - dt->parent = parent; - dt = dt->next; - } - } -} - -static char endtype(struct stat *st) -{ - mode_t mode = st->st_mode; - if ((toys.optflags&(FLAG_F|FLAG_p)) && S_ISDIR(mode)) return '/'; - if (toys.optflags & FLAG_F) { - if (S_ISLNK(mode)) return '@'; - if (S_ISREG(mode) && (mode&0111)) return '*'; - if (S_ISFIFO(mode)) return '|'; - if (S_ISSOCK(mode)) return '='; - } - return 0; -} - -static char *getusername(uid_t uid) -{ - struct passwd *pw = getpwuid(uid); - utoa_to_buf(uid, TT.uid_buf, 12); - return pw ? pw->pw_name : TT.uid_buf; -} - -static char *getgroupname(gid_t gid) -{ - struct group *gr = getgrgid(gid); - return gr ? gr->gr_name : utoa(gid); -} - -// Figure out size of printable entry fields for display indent/wrap - -static void entrylen(struct dirtree *dt, unsigned *len) -{ - struct stat *st = &(dt->st); - unsigned flags = toys.optflags; - - *len = strlen(dt->name); - if (endtype(st)) ++*len; - if (flags & FLAG_m) ++*len; - - if (flags & FLAG_i) *len += (len[1] = numlen(st->st_ino)); - if (flags & (FLAG_l|FLAG_o|FLAG_n|FLAG_g)) { - unsigned fn = flags & FLAG_n; - len[2] = numlen(st->st_nlink); - len[3] = strlen(fn ? utoa(st->st_uid) : getusername(st->st_uid)); - len[4] = strlen(fn ? utoa(st->st_gid) : getgroupname(st->st_gid)); - len[5] = numlen(st->st_size); - } - if (flags & FLAG_s) *len += (len[6] = numlen(st->st_blocks)); -} - -static int compare(void *a, void *b) -{ - struct dirtree *dta = *(struct dirtree **)a; - struct dirtree *dtb = *(struct dirtree **)b; - int ret = 0, reverse = (toys.optflags & FLAG_r) ? -1 : 1; - - if (toys.optflags & FLAG_S) { - if (dta->st.st_size > dtb->st.st_size) ret = -1; - else if (dta->st.st_size < dtb->st.st_size) ret = 1; - } - if (toys.optflags & FLAG_t) { - if (dta->st.st_mtime > dtb->st.st_mtime) ret = -1; - else if (dta->st.st_mtime < dtb->st.st_mtime) ret = 1; - } - if (!ret) ret = strcmp(dta->name, dtb->name); - return ret * reverse; -} - -// callback from dirtree_recurse() determining how to handle this entry. - -static int filter(struct dirtree *new) -{ - int flags = toys.optflags; - - // Special case to handle enormous dirs without running out of memory. - if (flags == (FLAG_1|FLAG_f)) { - xprintf("%s\n", new->name); - return 0; - } - - if (!(flags&FLAG_f)) { - if (flags & FLAG_a) return 0; - if (!(flags & FLAG_A) && new->name[0]=='.') return 0; - } - - if (flags & FLAG_u) new->st.st_mtime = new->st.st_atime; - if (flags & FLAG_c) new->st.st_mtime = new->st.st_ctime; - if (flags & FLAG_k) new->st.st_blocks = (new->st.st_blocks + 1) / 2; - return dirtree_notdotdot(new); -} - -// For column view, calculate horizontal position (for padding) and return -// index of next entry to display. - -static unsigned long next_column(unsigned long ul, unsigned long dtlen, - unsigned columns, unsigned *xpos) -{ - unsigned long transition; - unsigned height, widecols; - - // Horizontal sort is easy - if (!(toys.optflags & FLAG_C)) { - *xpos = ul % columns; - return ul; - } - - // vertical sort - - // For -x, calculate height of display, rounded up - height = (dtlen+columns-1)/columns; - - // Sanity check: does wrapping render this column count impossible - // due to the right edge wrapping eating a whole row? - if (height*columns - dtlen >= height) { - *xpos = columns; - return 0; - } - - // Uneven rounding goes along right edge - widecols = dtlen % height; - if (!widecols) widecols = height; - transition = widecols * columns; - if (ul < transition) { - *xpos = ul % columns; - return (*xpos*height) + (ul/columns); - } - - ul -= transition; - *xpos = ul % (columns-1); - - return (*xpos*height) + widecols + (ul/(columns-1)); -} - -// Display a list of dirtree entries, according to current format -// Output types -1, -l, -C, or stream - -static void listfiles(int dirfd, struct dirtree *indir) -{ - struct dirtree *dt, **sort = 0; - unsigned long dtlen = 0, ul = 0; - unsigned width, flags = toys.optflags, totals[7], len[7], - *colsizes = (unsigned *)(toybuf+260), columns = (sizeof(toybuf)-260)/4; - - memset(totals, 0, sizeof(totals)); - - // Silently descend into single directory listed by itself on command line. - // In this case only show dirname/total header when given -R. - if (!indir->parent) { - if (!(dt = indir->child)) return; - if (S_ISDIR(dt->st.st_mode) && !dt->next && !(flags & FLAG_d)) { - dt->extra = 1; - listfiles(open(dt->name, 0), dt); - return; - } - } else { - // Read directory contents. We dup() the fd because this will close it. - indir->data = dup(dirfd); - dirtree_recurse(indir, filter, (flags&FLAG_L)); - } - - // Copy linked list to array and sort it. Directories go in array because - // we visit them in sorted order. - - for (;;) { - for (dt = indir->child; dt; dt = dt->next) { - if (sort) sort[dtlen] = dt; - dtlen++; - } - if (sort) break; - sort = xmalloc(dtlen * sizeof(void *)); - dtlen = 0; - continue; - } - - // Label directory if not top of tree, or if -R - if (indir->parent && (!indir->extra || (flags & FLAG_R))) - { - char *path = dirtree_path(indir, 0); - - if (TT.nl_title++) xputc('\n'); - xprintf("%s:\n", path); - free(path); - } - - if (!(flags & FLAG_f)) qsort(sort, dtlen, sizeof(void *), (void *)compare); - - // Find largest entry in each field for display alignment - if (flags & (FLAG_C|FLAG_x)) { - - // columns can't be more than toybuf can hold, or more than files, - // or > 1/2 screen width (one char filename, one space). - if (columns > TT.screen_width/2) columns = TT.screen_width/2; - if (columns > dtlen) columns = dtlen; - - // Try to fit as many columns as we can, dropping down by one each time - for (;columns > 1; columns--) { - unsigned c, totlen = columns; - - memset(colsizes, 0, columns*sizeof(unsigned)); - for (ul=0; ul colsizes[c]) { - totlen += *len-colsizes[c]; - colsizes[c] = *len; - if (totlen > TT.screen_width) break; - } - } - // If it fit, stop here - if (ul == dtlen) break; - } - } else if (flags & (FLAG_l|FLAG_o|FLAG_n|FLAG_g|FLAG_s)) { - unsigned long blocks = 0; - - for (ul = 0; ul totals[width]) totals[width] = len[width]; - blocks += sort[ul]->st.st_blocks; - } - - if (indir->parent) xprintf("total %lu\n", blocks); - } - - // Loop through again to produce output. - memset(toybuf, ' ', 256); - width = 0; - for (ul = 0; ulst); - mode_t mode = st->st_mode; - char et = endtype(st); - - // Skip directories at the top of the tree when -d isn't set - if (S_ISDIR(mode) && !indir->parent && !(flags & FLAG_d)) continue; - TT.nl_title=1; - - // Handle padding and wrapping for display purposes - entrylen(sort[next], len); - if (ul) { - if (flags & FLAG_m) xputc(','); - if (flags & (FLAG_C|FLAG_x)) { - if (!curcol) xputc('\n'); - } else if ((flags & FLAG_1) || width+1+*len > TT.screen_width) { - xputc('\n'); - width = 0; - } else { - xputc(' '); - width++; - } - } - width += *len; - - if (flags & FLAG_i) - xprintf("% *lu ", len[1], (unsigned long)st->st_ino); - if (flags & FLAG_s) - xprintf("% *lu ", len[6], (unsigned long)st->st_blocks); - - if (flags & (FLAG_l|FLAG_o|FLAG_n|FLAG_g)) { - struct tm *tm; - char perm[11], thyme[64], c, d, *usr, *upad, *grp, *grpad; - int i, bit; - - perm[10]=0; - for (i=0; i<9; i++) { - bit = mode & (1<st_mtime)); - strftime(thyme, sizeof(thyme), "%F %H:%M", tm); - - if (flags&FLAG_o) grp = grpad = toybuf+256; - else { - grp = (flags&FLAG_n) ? utoa(st->st_gid) - : getgroupname(st->st_gid); - grpad = toybuf+256-(totals[4]-len[4]); - } - - if (flags&FLAG_g) usr = upad = toybuf+256; - else { - upad = toybuf+255-(totals[3]-len[3]); - if (flags&FLAG_n) { - usr = TT.uid_buf; - utoa_to_buf(st->st_uid, TT.uid_buf, 12); - } else usr = getusername(st->st_uid); - } - - // Coerce the st types into something we know we can print. - xprintf("%s% *ld %s%s%s%s% *"PRId64" %s ", perm, totals[2]+1, - (long)st->st_nlink, usr, upad, grp, grpad, totals[5]+1, - (int64_t)st->st_size, thyme); - } - - if (flags & FLAG_q) { - char *p; - for (p=sort[next]->name; *p; p++) xputc(isprint(*p) ? *p : '?'); - } else xprintf("%s", sort[next]->name); - if ((flags & (FLAG_l|FLAG_o|FLAG_n|FLAG_g)) && S_ISLNK(mode)) - xprintf(" -> %s", sort[next]->symlink); - - if (et) xputc(et); - - // Pad columns - if (flags & (FLAG_C|FLAG_x)) { - curcol = colsizes[curcol] - *len; - if (curcol >= 0) xprintf("%s", toybuf+255-curcol); - } - } - - if (width) xputc('\n'); - - // Free directory entries, recursing first if necessary. - - for (ul = 0; ulst.st_mode) - || !dirtree_notdotdot(sort[ul])) continue; - - // Recurse into dirs if at top of the tree or given -R - if (!indir->parent || (flags & FLAG_R)) - listfiles(openat(dirfd, sort[ul]->name, 0), sort[ul]); - } - free(sort); - if (dirfd != AT_FDCWD) close(indir->data); -} - -void ls_main(void) -{ - char **s, *noargs[] = {".", 0}; - struct dirtree *dt; - - // Do we have an implied -1 - if (!isatty(1) || (toys.optflags&(FLAG_l|FLAG_o|FLAG_n|FLAG_g))) - toys.optflags |= FLAG_1; - else { - TT.screen_width = 80; - terminal_size(&TT.screen_width, NULL); - } - // The optflags parsing infrastructure should really do this for us, - // but currently it has "switch off when this is set", so "-dR" and "-Rd" - // behave differently - if (toys.optflags & FLAG_d) toys.optflags &= ~FLAG_R; - - // Iterate through command line arguments, collecting directories and files. - // Non-absolute paths are relative to current directory. - TT.files = dirtree_add_node(0, 0, 0); - for (s = *toys.optargs ? toys.optargs : noargs; *s; s++) { - dt = dirtree_add_node(AT_FDCWD, *s, - (toys.optflags & (FLAG_L|FLAG_H|FLAG_l))^FLAG_l); - - if (!dt) { - toys.exitval = 1; - continue; - } - - // Typecast means double_list->prev temporarirly goes in dirtree->parent - dlist_add_nomalloc((struct double_list **)&TT.files->child, - (struct double_list *)dt); - } - - // Turn double_list into dirtree - dlist_to_dirtree(TT.files); - - // Display the files we collected - listfiles(AT_FDCWD, TT.files); - - if (CFG_TOYBOX_FREE) free(TT.files); -} diff -r 2d7c56913fda -r 2986aa63a021 toys/lsb/dmesg.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/toys/lsb/dmesg.c Sat Aug 25 14:25:22 2012 -0500 @@ -0,0 +1,59 @@ +/* vi: set sw=4 ts=4: + * + * dmesg.c - display/control kernel ring buffer. + * + * Copyright 2006, 2007 Rob Landley + * + * Not in SUSv3. + +USE_DMESG(NEWTOY(dmesg, "s#n#c", TOYFLAG_BIN)) + +config DMESG + bool "dmesg" + default y + help + usage: dmesg [-n level] [-s bufsize] | -c + + Print or control the kernel ring buffer. + + -n Set kernel logging level (1-9). + -s Size of buffer to read (in bytes), default 16384. + -c Clear the ring buffer after printing. +*/ + +#include "toys.h" +#include + +DEFINE_GLOBALS( + long level; + long size; +) + +#define TT this.dmesg + +void dmesg_main(void) +{ + // For -n just tell kernel to which messages to keep. + if (toys.optflags & 2) { + if (klogctl(8, NULL, TT.level)) + error_exit("klogctl"); + } else { + int size, i, last = '\n'; + char *data; + + // Figure out how much data we need, and fetch it. + size = TT.size; + if (size<2) size = 16384; + data = xmalloc(size); + size = klogctl(3 + (toys.optflags&1), data, size); + if (size < 0) error_exit("klogctl"); + + // Display data, filtering out level markers. + for (i=0; i + * + * Not in SUSv4. + +USE_HOSTNAME(NEWTOY(hostname, NULL, TOYFLAG_BIN)) + +config HOSTNAME + bool "hostname" + default n + help + usage: hostname [newname] + + Get/Set the current hostname +*/ + +#include "toys.h" + +void hostname_main(void) +{ + const char *hostname = toys.optargs[0]; + if (hostname) { + if (sethostname(hostname, strlen(hostname))) + perror_exit("cannot set hostname to '%s'", hostname); + } else { + if (gethostname(toybuf, sizeof(toybuf))) + perror_exit("cannot get hostname"); + xputs(toybuf); + } +} diff -r 2d7c56913fda -r 2986aa63a021 toys/lsb/killall.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/toys/lsb/killall.c Sat Aug 25 14:25:22 2012 -0500 @@ -0,0 +1,79 @@ +/* vi: set sw=4 ts=4: + * + * killall.c - Send signal (default: TERM) to all processes with given names. + * + * Copyright 2012 Andreas Heck + * + * Not in SUSv4. + +USE_KILLALL(NEWTOY(killall, "<1?lq", TOYFLAG_USR|TOYFLAG_BIN)) + +config KILLALL + bool "killall" + default y + help + usage: killall [-l] [-q] [-SIG] PROCESS_NAME... + + Send a signal (default: TERM) to all processes with the given names. + + -l print list of all available signals + -q don't print any warnings or error messages +*/ + +#include "toys.h" + +#define FLAG_q 1 +#define FLAG_l 2 + +DEFINE_GLOBALS( + int signum; +) +#define TT this.killall + +static void kill_process(pid_t pid) +{ + int ret; + + toys.exitval = 0; + ret = kill(pid, TT.signum); + + if (ret == -1 && !(toys.optflags & FLAG_q)) perror("kill"); +} + +void killall_main(void) +{ + char **names; + + if (toys.optflags & FLAG_l) { + sig_to_num(NULL); + return; + } + + TT.signum = SIGTERM; + toys.exitval++; + + if (!*toys.optargs) { + toys.exithelp = 1; + error_exit("Process name missing!"); + } + + names = toys.optargs; + + if (**names == '-') { + if (0 > (TT.signum = sig_to_num((*names)+1))) { + if (toys.optflags & FLAG_q) exit(1); + error_exit("Invalid signal"); + } + names++; + + if (!*names) { + toys.exithelp++; + error_exit("Process name missing!"); + } + } + + for_each_pid_with_name_in(names, kill_process); + + if (toys.exitval && !(toys.optflags & FLAG_q)) + error_exit("No such process"); +} diff -r 2d7c56913fda -r 2986aa63a021 toys/lsb/mknod.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/toys/lsb/mknod.c Sat Aug 25 14:25:22 2012 -0500 @@ -0,0 +1,51 @@ +/* vi: set sw=4 ts=4: + * + * mknod.c - make block or character special file + * + * Copyright 2012 Elie De Brauwer + * + * Not in SUSv3. + +USE_MKNOD(NEWTOY(mknod, "<2>4", TOYFLAG_BIN)) + +config MKNOD + bool "mknod" + default y + help + usage: mknod NAME TYPE [MAJOR MINOR] + + Create a special file NAME with a given type, possible types are + b create a block device with the given MAJOR/MINOR + c or u create a character device with the given MAJOR/MINOR + p create a named pipe ignoring MAJOR/MINOR +*/ + +#include "toys.h" + +static const char modes_char[] = {'p', 'c', 'u', 'b'}; +static const mode_t modes[] = {S_IFIFO, S_IFCHR, S_IFCHR, S_IFBLK}; + +void mknod_main(void) +{ + int major=0, minor=0, type; + char * tmp; + int mode = 0660; + + tmp = strchr(modes_char, toys.optargs[1][0]); + if (!tmp) + perror_exit("unknown special device type %c", toys.optargs[1][0]); + + type = modes[tmp-modes_char]; + + if (type == S_IFCHR || type == S_IFBLK) { + if (toys.optc != 4) + perror_exit("creating a block/char device requires major/minor"); + + major = atoi(toys.optargs[2]); + minor = atoi(toys.optargs[3]); + } + + if (mknod(toys.optargs[0], mode | type, makedev(major, minor))) + perror_exit("mknod %s failed", toys.optargs[0]); + +} diff -r 2d7c56913fda -r 2986aa63a021 toys/lsb/mktemp.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/toys/lsb/mktemp.c Sat Aug 25 14:25:22 2012 -0500 @@ -0,0 +1,54 @@ +/* vi: set sw=4 ts=4: + * + * mktemp.c - Create a temporary file or directory. + * + * Copyright 2012 Elie De Brauwer + * + * Not in SUSv4. + +USE_MKTEMP(NEWTOY(mktemp, ">1(directory)d(tmpdir)p:", TOYFLAG_BIN)) + +config MKTEMP + bool "mktemp" + default y + help + usage: mktemp [OPTION] [TEMPLATE] + + Safely create a temporary file or directory and print its name. + TEMPLATE should end in 6 consecutive X's, the default + template is tmp.XXXXXX and the default directory is /tmp/. + + -d, --directory Create a directory, instead of a file + -p DIR, --tmpdir=DIR Use DIR as a base path + +*/ + +#include "toys.h" + +DEFINE_GLOBALS( + char * tmpdir; +) +#define TT this.mktemp + +void mktemp_main(void) +{ + int d_flag = toys.optflags & 2; + char *tmp, *path; + + tmp = *toys.optargs; + if (!tmp) tmp = "tmp.XXXXXX"; + if (!TT.tmpdir) TT.tmpdir = "/tmp/"; + + tmp = xmsprintf("%s/%s", TT.tmpdir, tmp); + + if (d_flag ? mkdtemp(tmp) == NULL : mkstemp(tmp) == -1) + perror_exit("Failed to create temporary %s", + d_flag ? "directory" : "file"); + + xputs(path = xrealpath(tmp)); + + if (CFG_TOYBOX_FREE) { + free(path); + free(tmp); + } +} diff -r 2d7c56913fda -r 2986aa63a021 toys/lsb/passwd.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/toys/lsb/passwd.c Sat Aug 25 14:25:22 2012 -0500 @@ -0,0 +1,274 @@ +/* vi: set sw=4 ts=4: + * + * passwd.c - Program to upadte user password. + * + * Copyright 2012 Ashwini Kumar + * Modified 2012 Jason Kyungwan Han + * + * Not in SUSv4. + +USE_PASSWD(NEWTOY(passwd, ">1a:dlu", TOYFLAG_STAYROOT|TOYFLAG_USR|TOYFLAG_BIN)) + +config PASSWD + bool "passwd" + default y + help + usage: passwd [-a ALGO] [-d] [-l] [-u] + + update user’s authentication tokens. Default : current user + + -a ALGO Encryption method (des, md5, sha256, sha512) default: des + -d Set password to '' + -l Lock (disable) account + -u Unlock (enable) account + +*/ + +#include "toys.h" +#include + + +DEFINE_GLOBALS( + char *algo; +) + +#define TT this.passwd + +#define FLAG_u (1 << 0) +#define FLAG_l (1 << 1) +#define FLAG_d (1 << 2) +#define FLAG_a (1 << 3) + +#define MAX_SALT_LEN 20 //3 for id, 16 for key, 1 for '\0' +#define URANDOM_PATH "/dev/urandom" + +#ifndef _GNU_SOURCE +char *strcasestr(const char *haystack, const char *needle); +#endif + +unsigned int random_number_generator(int fd) +{ + unsigned int randnum; + xreadall(fd, &randnum, sizeof(randnum)); + return randnum; +} + + + +char inttoc(int i) +{ + // salt value uses 64 chracters in "./0-9a-zA-Z" + const char character_set[]="./0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; + i &= 0x3f; // masking for using 10 bits only + return character_set[i]; +} + +int get_salt(char *salt) +{ + int i, salt_length = 0; + int randfd; + if(!strncmp(TT.algo,"des",3)){ + // 2 bytes salt value is used in des + salt_length = 2; + } else { + *salt++ = '$'; + if(!strncmp(TT.algo,"md5",3)){ + *salt++ = '1'; + // 8 bytes salt value is used in md5 + salt_length = 8; + } else if(!strncmp(TT.algo,"sha256",6)){ + *salt++ = '5'; + // 16 bytes salt value is used in sha256 + salt_length = 16; + } else if(!strncmp(TT.algo,"sha512",6)){ + *salt++ = '6'; + // 16 bytes salt value is used in sha512 + salt_length = 16; + } else return 1; + + *salt++ = '$'; + } + + randfd = xopen(URANDOM_PATH, O_RDONLY); + for(i=0; ipw_name); + + pw = getpwnam(name); + if(!pw) error_exit("Unknown user '%s'",name); + + if(myuid != 0 && (myuid != pw->pw_uid)) + error_exit("You need to be root to change '%s' password\n", name); + + pass = pw->pw_passwd; + if(pw->pw_passwd[0] == 'x') { + /*get shadow passwd */ + sp = getspnam(name); + if(sp) + pass = sp->sp_pwdp; + } + + + if(!(toys.optflags & (FLAG_l | FLAG_u | FLAG_d))) { + printf("Changing password for %s\n",name); + if(pass[0] == '!') + error_exit("Can't change, password is locked for %s",name); + if(myuid != 0) { + /*Validate user */ + + if(read_password(toybuf, sizeof(toybuf), "Origial password:")) { + if(!toys.optargs[0]) free(name); + return; + } + orig = toybuf; + if(verify_passwd(pass)) + error_exit("Authentication failed\n"); + } + + orig = xstrdup(orig); + + /*Get new password */ + newp = new_password(orig, name); + if(!newp) { + free(orig); + if(!toys.optargs[0]) free(name); + return; //new password is not set well. + } + + /*Encrypt the passwd */ + if(!(toys.optflags & FLAG_a)) TT.algo = "des"; + + if(get_salt(salt)) + error_exit("Error: Unkown encryption algorithm\n"); + + encrypted = crypt(newp, salt); + free(newp); + free(orig); + } + else if(toys.optflags & FLAG_l) { + if(pass[0] == '!') + error_exit("password is already locked for %s",name); + printf("Locking password for %s\n",name); + encrypted = xmsprintf("!%s",pass); + } + else if(toys.optflags & FLAG_u) { + if(pass[0] != '!') + error_exit("password is already unlocked for %s",name); + + printf("Unlocking password for %s\n",name); + encrypted = xstrdup(&pass[1]); + } + else if(toys.optflags & FLAG_d) { + printf("Deleting password for %s\n",name); + encrypted = (char*)xzalloc(sizeof(char)*2); //1 = "", 2 = '\0' + } + + /*Update the passwd */ + if(pw->pw_passwd[0] == 'x') + ret = update_password("/etc/shadow", name, encrypted); + else + ret = update_password("/etc/passwd", name, encrypted); + + if((toys.optflags & (FLAG_l | FLAG_u | FLAG_d))) + free(encrypted); + + if(!toys.optargs[0]) free(name); + if(!ret) + error_msg("Success"); + else + error_msg("Failure"); +} diff -r 2d7c56913fda -r 2986aa63a021 toys/lsb/pidof.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/toys/lsb/pidof.c Sat Aug 25 14:25:22 2012 -0500 @@ -0,0 +1,32 @@ +/* vi: set sw=4 ts=4: + * + * pidof.c - Print the PIDs of all processes with the given names. + * + * Copyright 2012 Andreas Heck + * + * Not in SUSv4. + +USE_PIDOF(NEWTOY(pidof, "<1", TOYFLAG_USR|TOYFLAG_BIN)) + +config PIDOF + bool "pidof" + default y + help + usage: pidof [NAME]... + + Print the PIDs of all processes with the given names. +*/ + +#include "toys.h" + +static void print_pid(pid_t pid) { + xprintf("%s%ld", toys.exitval ? "" : " ", (long)pid); + toys.exitval = 0; +} + +void pidof_main(void) +{ + toys.exitval = 1; + for_each_pid_with_name_in(toys.optargs, print_pid); + if (!toys.exitval) xputc('\n'); +} diff -r 2d7c56913fda -r 2986aa63a021 toys/lsb/seq.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/toys/lsb/seq.c Sat Aug 25 14:25:22 2012 -0500 @@ -0,0 +1,48 @@ +/* vi: set sw=4 ts=4: + * + * seq.c - Count from first to last, by increment. + * + * Copyright 2006 Rob Landley + * + * Not in SUSv3. (Don't ask me why not.) + +USE_SEQ(NEWTOY(seq, "<1>3?", TOYFLAG_USR|TOYFLAG_BIN)) + +config SEQ + bool "seq" + depends on TOYBOX_FLOAT + default y + help + usage: seq [first] [increment] last + + Count from first to last, by increment. Omitted arguments default + to 1. Two arguments are used as first and last. Arguments can be + negative or floating point. +*/ + +#include "toys.h" + +void seq_main(void) +{ + double first, increment, last, dd; + + // Parse command line arguments, with appropriate defaults. + // Note that any non-numeric arguments are treated as zero. + first = increment = 1; + switch (toys.optc) { + case 3: + increment = atof(toys.optargs[1]); + case 2: + first = atof(*toys.optargs); + default: + last = atof(toys.optargs[toys.optc-1]); + } + + // Yes, we're looping on a double. Yes rounding errors can accumulate if + // you use a non-integer increment. Deal with it. + for (dd=first; (increment>0 && dd<=last) || (increment <0 && dd>=last); + dd+=increment) + { + printf("%g\n", dd); + } +} diff -r 2d7c56913fda -r 2986aa63a021 toys/lsb/sync.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/toys/lsb/sync.c Sat Aug 25 14:25:22 2012 -0500 @@ -0,0 +1,25 @@ +/* vi: set sw=4 ts=4: + * + * sync.c - Write all pending data to disk. + * + * Copyright 2007 Rob Landley + * + * Not in SUSv3. + +USE_SYNC(NEWTOY(sync, NULL, TOYFLAG_BIN)) + +config SYNC + bool "sync" + default y + help + usage: sync + + Write pending cached data to disk (synchronize), blocking until done. +*/ + +#include "toys.h" + +void sync_main(void) +{ + sync(); +} diff -r 2d7c56913fda -r 2986aa63a021 toys/lsmod.c --- a/toys/lsmod.c Sat Aug 25 14:24:24 2012 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,42 +0,0 @@ -/* vi: set sw=4 ts=4: - * - * lsmod.c - Show the status of modules in the kernel - * - * Copyright 2012 Elie De Brauwer - * - * Not in SUSv4. - -USE_LSMOD(NEWTOY(lsmod, NULL, TOYFLAG_BIN)) - -config LSMOD - bool "lsmod" - default y - help - usage: lsmod - - Display the currently loaded modules, their sizes and their - dependencies. -*/ - -#include "toys.h" - -void lsmod_main(void) -{ - char *modfile = "/proc/modules"; - FILE * file = xfopen(modfile, "r"); - - xprintf("%-23s Size Used by\n", "Module"); - - while (fgets(toybuf, sizeof(toybuf), file)) { - char *name = strtok(toybuf, " "), *size = strtok(NULL, " "), - *refcnt = strtok(NULL, " "), *users = strtok(NULL, " "); - - if(users) { - int len = strlen(users)-1; - if (users[len] == ',' || users[len] == '-') - users[len] = 0; - xprintf("%-19s %8s %s %s\n", name, size, refcnt, users); - } else perror_exit("bad %s", modfile); - } - fclose(file); -} diff -r 2d7c56913fda -r 2986aa63a021 toys/mdev.c --- a/toys/mdev.c Sat Aug 25 14:24:24 2012 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,213 +0,0 @@ -/* vi:set ts=4: - * - * mdev - Mini udev for busybox - * - * Copyright 2005, 2008 Rob Landley - * Copyright 2005 Frank Sorenson - * - * Not in SUSv3. - -USE_MDEV(NEWTOY(mdev, "s", TOYFLAG_USR|TOYFLAG_BIN|TOYFLAG_UMASK)) - -config MDEV - bool "mdev" - default n - help - usage: mdev [-s] - - Create devices in /dev using information from /sys. - - -s Scan all entries in /sys to populate /dev. - -config MDEV_CONF - bool "Configuration file for mdev" - default y - depends on MDEV - help - The mdev config file (/etc/mdev.conf) contains lines that look like: - hd[a-z][0-9]* 0:3 660 - - Each line must contain three whitespace separated fields. The first - field is a regular expression matching one or more device names, and - the second and third fields are uid:gid and file permissions for - matching devies. -*/ - -#include "toys.h" -#include "lib/xregcomp.h" - -// todo, open() block devices to trigger partition scanning. - -// mknod in /dev based on a path like "/sys/block/hda/hda1" -static void make_device(char *path) -{ - char *device_name, *s, *temp; - int major, minor, type, len, fd; - int mode = 0660; - uid_t uid = 0; - gid_t gid = 0; - - // Try to read major/minor string - - temp = strrchr(path, '/'); - fd = open(path, O_RDONLY); - *temp=0; - temp = toybuf; - len = read(fd, temp, 64); - close(fd); - if (len<1) return; - temp[len] = 0; - - // Determine device name, type, major and minor - - device_name = strrchr(path, '/') + 1; - type = path[5]=='c' ? S_IFCHR : S_IFBLK; - major = minor = 0; - sscanf(temp, "%u:%u", &major, &minor); - - // If we have a config file, look up permissions for this device - - if (CFG_MDEV_CONF) { - char *conf, *pos, *end; - - // mmap the config file - if (-1!=(fd = open("/etc/mdev.conf", O_RDONLY))) { - len = fdlength(fd); - conf = mmap(NULL, len, PROT_READ, MAP_PRIVATE, fd, 0); - if (conf) { - int line = 0; - - // Loop through lines in mmaped file - for (pos = conf; pos-confpw_uid; - } - s++; - // parse GID - gid = strtoul(s,&s2,10); - if (end2!=s2) { - struct group *grp; - char *str = strndup(s, end2-s); - grp = getgrnam(str); - free(str); - if (!grp) goto end_line; - gid = grp->gr_gid; - } - break; - } - // mode - case 1: - { - mode = strtoul(pos, &pos, 8); - if (pos!=end2) goto end_line; - goto found_device; - } - } - pos=end2; - } -end_line: - // Did everything parse happily? - if (field && field!=3) error_exit("Bad line %d", line); - - // Next line - pos = ++end; - } -found_device: - munmap(conf, len); - } - close(fd); - } - } - - sprintf(temp, "/dev/%s", device_name); - if (mknod(temp, mode | type, makedev(major, minor)) && errno != EEXIST) - perror_exit("mknod %s failed", temp); - - if (CFG_MDEV_CONF) mode=chown(temp, uid, gid); -} - -static int callback(struct dirtree *node) -{ - // Entries in /sys/class/block aren't char devices, so skip 'em. (We'll - // get block devices out of /sys/block.) - if(!strcmp(node->name, "block")) return 0; - - // Does this directory have a "dev" entry in it? - // This is path based because the hotplug callbacks are - if (S_ISDIR(node->st.st_mode) || S_ISLNK(node->st.st_mode)) { - int len=4; - char *dev = dirtree_path(node, &len); - strcpy(dev+len, "/dev"); - if (!access(dev, R_OK)) make_device(dev); - free(dev); - } - - // Circa 2.6.25 the entries more than 2 deep are all either redundant - // (mouse#, event#) or unnamed (every usb_* entry is called "device"). - - return (node->parent && node->parent->parent) ? 0 : DIRTREE_RECURSE; -} - -void mdev_main(void) -{ - // Handle -s - - if (toys.optflags) { - dirtree_read("/sys/class", callback); - dirtree_read("/sys/block", callback); - } - - // hotplug support goes here -} diff -r 2d7c56913fda -r 2986aa63a021 toys/mkdir.c --- a/toys/mkdir.c Sat Aug 25 14:24:24 2012 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,76 +0,0 @@ -/* vi: set sw=4 ts=4: - * - * mkdir.c - Make directories - * - * Copyright 2012 Georgi Chorbadzhiyski - * - * See http://pubs.opengroup.org/onlinepubs/009695399/utilities/mkdir.html - * - * TODO: Add -m - -USE_MKDIR(NEWTOY(mkdir, "<1p", TOYFLAG_BIN)) - -config MKDIR - bool "mkdir" - default y - help - usage: mkdir [-p] [dirname...] - Create one or more directories. - - -p make parent directories as needed. -*/ - -#include "toys.h" - -DEFINE_GLOBALS( - long mode; -) - -#define TT this.mkdir - -static int do_mkdir(char *dir) -{ - struct stat buf; - char *s; - - // mkdir -p one/two/three is not an error if the path already exists, - // but is if "three" is a file. The others we dereference and catch - // not-a-directory along the way, but the last one we must explicitly - // test for. Might as well do it up front. - - if (!stat(dir, &buf) && !S_ISDIR(buf.st_mode)) { - errno = EEXIST; - return 1; - } - - for (s=dir; ; s++) { - char save=0; - - // Skip leading / of absolute paths. - if (s!=dir && *s == '/' && toys.optflags) { - save = *s; - *s = 0; - } else if (*s) continue; - - if (mkdir(dir, TT.mode)<0 && (!toys.optflags || errno != EEXIST)) - return 1; - - if (!(*s = save)) break; - } - - return 0; -} - -void mkdir_main(void) -{ - char **s; - - TT.mode = 0777; - - for (s=toys.optargs; *s; s++) { - if (do_mkdir(*s)) { - perror_msg("cannot create directory '%s'", *s); - toys.exitval = 1; - } - } -} diff -r 2d7c56913fda -r 2986aa63a021 toys/mke2fs.c --- a/toys/mke2fs.c Sat Aug 25 14:24:24 2012 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,662 +0,0 @@ -/* vi: set ts=4: - * - * mke2fs.c - Create an ext2 filesystem image. - * - * Copyright 2006, 2007 Rob Landley - * - * Not in SUSv3. - -// Still to go: "E:jJ:L:m:O:" -USE_MKE2FS(NEWTOY(mke2fs, "<1>2g:Fnqm#N#i#b#", TOYFLAG_SBIN)) - -config MKE2FS - bool "mke2fs (unfinished and broken by dirtree changes)" - default n - help - usage: mke2fs [-Fnq] [-b ###] [-N|i ###] [-m ###] device - - Create an ext2 filesystem on a block device or filesystem image. - - -F Force to run on a mounted device - -n Don't write to device - -q Quiet (no output) - -b size Block size (1024, 2048, or 4096) - -N inodes Allocate this many inodes - -i bytes Allocate one inode for every XXX bytes of device - -m percent Reserve this percent of filesystem space for root user - -config MKE2FS_JOURNAL - bool "Journaling support (ext3)" - default n - depends on MKE2FS - help - usage: [-j] [-J size=###,device=XXX] - - -j Create journal (ext3) - -J Journal options - size: Number of blocks (1024-102400) - device: Specify an external journal - -config MKE2FS_GEN - bool "Generate (gene2fs)" - default n - depends on MKE2FS - help - usage: gene2fs [options] device filename - - The [options] are the same as mke2fs. - -config MKE2FS_LABEL - bool "Label support" - default n - depends on MKE2FS - help - usage: mke2fs [-L label] [-M path] [-o string] - - -L Volume label - -M Path to mount point - -o Created by - -config MKE2FS_EXTENDED - bool "Extended options" - default n - depends on MKE2FS - help - usage: mke2fs [-E stride=###] [-O option[,option]] - - -E stride= Set RAID stripe size (in blocks) - -O [opts] Specify fewer ext2 option flags (for old kernels) - All of these are on by default (as appropriate) - none Clear default options (all but journaling) - dir_index Use htree indexes for large directories - filetype Store file type info in directory entry - has_journal Set by -j - journal_dev Set by -J device=XXX - sparse_super Don't allocate huge numbers of redundant superblocks -*/ - -#include "toys.h" - -DEFINE_GLOBALS( - // Command line arguments. - long blocksize; - long bytes_per_inode; - long inodes; // Total inodes in filesystem. - long reserved_percent; // Integer precent of space to reserve for root. - char *gendir; // Where to read dirtree from. - - // Internal data. - struct dirtree *dt; // Tree of files to copy into the new filesystem. - unsigned treeblocks; // Blocks used by dt - unsigned treeinodes; // Inodes used by dt - - unsigned blocks; // Total blocks in the filesystem. - unsigned freeblocks; // Free blocks in the filesystem. - unsigned inodespg; // Inodes per group - unsigned groups; // Total number of block groups. - unsigned blockbits; // Bits per block. (Also blocks per group.) - - // For gene2fs - unsigned nextblock; // Next data block to allocate - unsigned nextgroup; // Next group we'll be allocating from - int fsfd; // File descriptor of filesystem (to output to). - - struct ext2_superblock sb; -) - -// Shortcut to our global data structure, since we use it so much. -#define TT this.mke2fs - -#define INODES_RESERVED 10 - -static uint32_t div_round_up(uint32_t a, uint32_t b) -{ - uint32_t c = a/b; - - if (a%b) c++; - return c; -} - -// Calculate data blocks plus index blocks needed to hold a file. - -static uint32_t file_blocks_used(uint64_t size, uint32_t *blocklist) -{ - uint32_t dblocks = (uint32_t)((size+(TT.blocksize-1))/TT.blocksize); - uint32_t idx=TT.blocksize/4, iblocks=0, diblocks=0, tiblocks=0; - - // Fill out index blocks in inode. - - if (blocklist) { - int i; - - // Direct index blocks - for (i=0; i<13 && i 13+idx) blocklist[13] = 13+idx; - // Doubly indirect index blocks - idx = 13 + idx + (idx*idx); - if (dblocks > idx) blocklist[14] = idx; - - return 0; - } - - // Account for direct, singly, doubly, and triply indirect index blocks - - if (dblocks > 12) { - iblocks = ((dblocks-13)/idx)+1; - if (iblocks > 1) { - diblocks = ((iblocks-2)/idx)+1; - if (diblocks > 1) - tiblocks = ((diblocks-2)/idx)+1; - } - } - - return dblocks + iblocks + diblocks + tiblocks; -} - -// Use the parent pointer to iterate through the tree non-recursively. -static struct dirtree *treenext(struct dirtree *this) -{ - while (this && !this->next) this = this->parent; - if (this) this = this->next; - - return this; -} - -// Recursively calculate the number of blocks used by each inode in the tree. -// Returns blocks used by this directory, assigns bytes used to *size. -// Writes total block count to TT.treeblocks and inode count to TT.treeinodes. - -static long check_treesize(struct dirtree *that, off_t *size) -{ - long blocks; - - while (that) { - *size += sizeof(struct ext2_dentry) + strlen(that->name); - - if (that->child) - that->st.st_blocks = check_treesize(that->child, &that->st.st_size); - else if (S_ISREG(that->st.st_mode)) { - that->st.st_blocks = file_blocks_used(that->st.st_size, 0); - TT.treeblocks += that->st.st_blocks; - } - that = that->next; - } - TT.treeblocks += blocks = file_blocks_used(*size, 0); - TT.treeinodes++; - - return blocks; -} - -// Calculate inode numbers and link counts. -// -// To do this right I need to copy the tree and sort it, but here's a really -// ugly n^2 way of dealing with the problem that doesn't scale well to large -// numbers of files (> 100,000) but can be done in very little code. -// This rewrites inode numbers to their final values, allocating depth first. - -static void check_treelinks(struct dirtree *tree) -{ - struct dirtree *current=tree, *that; - long inode = INODES_RESERVED; - - while (current) { - ++inode; - // Since we can't hardlink to directories, we know their link count. - if (S_ISDIR(current->st.st_mode)) current->st.st_nlink = 2; - else { - dev_t new = current->st.st_dev; - - if (!new) continue; - - // Look for other copies of current node - current->st.st_nlink = 0; - for (that = tree; that; that = treenext(that)) { - if (current->st.st_ino == that->st.st_ino && - current->st.st_dev == that->st.st_dev) - { - current->st.st_nlink++; - current->st.st_ino = inode; - } - } - } - current->st.st_ino = inode; - current = treenext(current); - } -} - -// According to http://www.opengroup.org/onlinepubs/9629399/apdxa.htm -// we should generate a uuid structure by reading a clock with 100 nanosecond -// precision, normalizing it to the start of the gregorian calendar in 1582, -// and looking up our eth0 mac address. -// -// On the other hand, we have 128 bits to come up with a unique identifier, of -// which 6 have a defined value. /dev/urandom it is. - -static void create_uuid(char *uuid) -{ - // Read 128 random bits - int fd = xopen("/dev/urandom", O_RDONLY); - xreadall(fd, uuid, 16); - close(fd); - - // Claim to be a DCE format UUID. - uuid[6] = (uuid[6] & 0x0F) | 0x40; - uuid[8] = (uuid[8] & 0x3F) | 0x80; - - // rfc2518 section 6.4.1 suggests if we're not using a macaddr, we should - // set bit 1 of the node ID, which is the mac multicast bit. This means we - // should never collide with anybody actually using a macaddr. - uuid[11] = uuid[11] | 128; -} - -// Calculate inodes per group from total inodes. -static uint32_t get_inodespg(uint32_t inodes) -{ - uint32_t temp; - - // Round up to fill complete inode blocks. - temp = (inodes + TT.groups - 1) / TT.groups; - inodes = TT.blocksize/sizeof(struct ext2_inode); - return ((temp + inodes - 1)/inodes)*inodes; -} - -// Fill out superblock and TT structures. - -static void init_superblock(struct ext2_superblock *sb) -{ - uint32_t temp; - - // Set log_block_size and log_frag_size. - - for (temp = 0; temp < 4; temp++) if (TT.blocksize == 1024<log_block_size = sb->log_frag_size = SWAP_LE32(temp); - - // Fill out blocks_count, r_blocks_count, first_data_block - - sb->blocks_count = SWAP_LE32(TT.blocks); - sb->free_blocks_count = SWAP_LE32(TT.freeblocks); - temp = (TT.blocks * (uint64_t)TT.reserved_percent) / 100; - sb->r_blocks_count = SWAP_LE32(temp); - - sb->first_data_block = SWAP_LE32(TT.blocksize == 1024 ? 1 : 0); - - // Set blocks_per_group and frags_per_group, which is the size of an - // allocation bitmap that fits in one block (I.E. how many bits per block)? - - sb->blocks_per_group = sb->frags_per_group = SWAP_LE32(TT.blockbits); - - // Set inodes_per_group and total inodes_count - sb->inodes_per_group = SWAP_LE32(TT.inodespg); - sb->inodes_count = SWAP_LE32(TT.inodespg * TT.groups); - - // Determine free inodes. - temp = TT.inodespg*TT.groups - INODES_RESERVED; - if (temp < TT.treeinodes) error_exit("Not enough inodes.\n"); - sb->free_inodes_count = SWAP_LE32(temp - TT.treeinodes); - - // Fill out the rest of the superblock. - sb->max_mnt_count=0xFFFF; - sb->wtime = sb->lastcheck = sb->mkfs_time = SWAP_LE32(time(NULL)); - sb->magic = SWAP_LE32(0xEF53); - sb->state = sb->errors = SWAP_LE16(1); - - sb->rev_level = SWAP_LE32(1); - sb->first_ino = SWAP_LE32(INODES_RESERVED+1); - sb->inode_size = SWAP_LE16(sizeof(struct ext2_inode)); - sb->feature_incompat = SWAP_LE32(EXT2_FEATURE_INCOMPAT_FILETYPE); - sb->feature_ro_compat = SWAP_LE32(EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER); - - create_uuid(sb->uuid); - - // TODO If we're called as mke3fs or mkfs.ext3, do a journal. - - //if (strchr(toys.which->name,'3')) - // sb->feature_compat |= SWAP_LE32(EXT3_FEATURE_COMPAT_HAS_JOURNAL); -} - -// Does this group contain a superblock backup (and group descriptor table)? -static int is_sb_group(uint32_t group) -{ - int i; - - // Superblock backups are on groups 0, 1, and powers of 3, 5, and 7. - if(!group || group==1) return 1; - for (i=3; i<9; i+=2) { - int j = i; - while (j sizeof(toybuf) ? sizeof(toybuf) : len; - xwrite(TT.fsfd, toybuf, out); - len -= out; - } - } -} - -// Fill out an inode structure from struct stat info in dirtree. -static void fill_inode(struct ext2_inode *in, struct dirtree *that) -{ - uint32_t fbu[15]; - int temp; - - file_blocks_used(that->st.st_size, fbu); - - // If that inode needs data blocks allocated to it. - if (that->st.st_size) { - int i, group = TT.nextblock/TT.blockbits; - - // TODO: teach this about indirect blocks. - for (i=0; i<15; i++) { - // If we just jumped into a new group, skip group overhead blocks. - while (group >= TT.nextgroup) - TT.nextblock += group_overhead(TT.nextgroup++); - } - } - // TODO : S_ISREG/DIR/CHR/BLK/FIFO/LNK/SOCK(m) - in->mode = SWAP_LE32(that->st.st_mode); - - in->uid = SWAP_LE16(that->st.st_uid & 0xFFFF); - in->uid_high = SWAP_LE16(that->st.st_uid >> 16); - in->gid = SWAP_LE16(that->st.st_gid & 0xFFFF); - in->gid_high = SWAP_LE16(that->st.st_gid >> 16); - in->size = SWAP_LE32(that->st.st_size & 0xFFFFFFFF); - - // Contortions to make the compiler not generate a warning for x>>32 - // when x is 32 bits. The optimizer should clean this up. - if (sizeof(that->st.st_size) > 4) temp = 32; - else temp = 0; - if (temp) in->dir_acl = SWAP_LE32(that->st.st_size >> temp); - - in->atime = SWAP_LE32(that->st.st_atime); - in->ctime = SWAP_LE32(that->st.st_ctime); - in->mtime = SWAP_LE32(that->st.st_mtime); - - in->links_count = SWAP_LE16(that->st.st_nlink); - in->blocks = SWAP_LE32(that->st.st_blocks); - // in->faddr -} - -// Works like an archiver. -// The first argument is the name of the file to create. If it already -// exists, that size will be used. - -void mke2fs_main(void) -{ - int i, temp; - off_t length; - uint32_t usedblocks, usedinodes, dtiblk, dtbblk; - struct dirtree *dti, *dtb; - - // Handle command line arguments. - - if (toys.optargs[1]) { - sscanf(toys.optargs[1], "%u", &TT.blocks); - temp = O_RDWR|O_CREAT; - } else temp = O_RDWR; - if (!TT.reserved_percent) TT.reserved_percent = 5; - - // TODO: Check if filesystem is mounted here - - // For mke?fs, open file. For gene?fs, create file. - TT.fsfd = xcreate(*toys.optargs, temp, 0777); - - // Determine appropriate block size and block count from file length. - // (If no length, default to 4k. They can override it on the cmdline.) - - length = fdlength(TT.fsfd); - if (!TT.blocksize) TT.blocksize = (length && length < 1<<29) ? 1024 : 4096; - TT.blockbits = 8*TT.blocksize; - if (!TT.blocks) TT.blocks = length/TT.blocksize; - - // Collect gene2fs list or lost+found, calculate requirements. - - if (TT.gendir) { - strncpy(toybuf, TT.gendir, sizeof(toybuf)); - dti = dirtree_read(toybuf, NULL, NULL); - } else { - dti = xzalloc(sizeof(struct dirtree)+11); - strcpy(dti->name, "lost+found"); - dti->st.st_mode = S_IFDIR|0755; - dti->st.st_ctime = dti->st.st_mtime = time(NULL); - } - - // Add root directory inode. This is iterated through for when finding - // blocks, but not when finding inodes. The tree's parent pointers don't - // point back into this. - - dtb = xzalloc(sizeof(struct dirtree)+1); - dtb->st.st_mode = S_IFDIR|0755; - dtb->st.st_ctime = dtb->st.st_mtime = time(NULL); - dtb->child = dti; - - // Figure out how much space is used by preset files - length = check_treesize(dtb, &(dtb->st.st_size)); - check_treelinks(dtb); - - // Figure out how many total inodes we need. - - if (!TT.inodes) { - if (!TT.bytes_per_inode) TT.bytes_per_inode = 8192; - TT.inodes = (TT.blocks * (uint64_t)TT.blocksize) / TT.bytes_per_inode; - } - - // If we're generating a filesystem and have no idea how many blocks it - // needs, start with a minimal guess, find the overhead of that many - // groups, and loop until this is enough groups to store this many blocks. - if (!TT.blocks) TT.groups = (TT.treeblocks/TT.blockbits)+1; - else TT.groups = div_round_up(TT.blocks, TT.blockbits); - - for (;;) { - temp = TT.treeblocks; - - for (i = 0; i TT.blocks) end = TT.blocks & (TT.blockbits-1); - - // Blocks used by inode table - itable = (TT.inodespg*sizeof(struct ext2_inode))/TT.blocksize; - - // If a superblock goes here, write it out. - start = group_superblock_overhead(i); - if (start) { - struct ext2_group *bg = (struct ext2_group *)toybuf; - int treeblocks = TT.treeblocks, treeinodes = TT.treeinodes; - - TT.sb.block_group_nr = SWAP_LE16(i); - - // Write superblock and pad it up to block size - xwrite(TT.fsfd, &TT.sb, sizeof(struct ext2_superblock)); - temp = TT.blocksize - sizeof(struct ext2_superblock); - if (!i && TT.blocksize > 1024) temp -= 1024; - memset(toybuf, 0, TT.blocksize); - xwrite(TT.fsfd, toybuf, temp); - - // Loop through groups to write group descriptor table. - for(j=0; j treeinodes) { - treeinodes -= temp; - temp = 0; - } else { - temp -= treeinodes; - treeinodes = 0; - } - bg[slot].free_inodes_count = SWAP_LE16(temp); - - // How many free blocks in this group? - temp = TT.inodespg/(TT.blocksize/sizeof(struct ext2_inode)) + 2; - temp = end-used-temp; - if (temp > treeblocks) { - treeblocks -= temp; - temp = 0; - } else { - temp -= treeblocks; - treeblocks = 0; - } - bg[slot].free_blocks_count = SWAP_LE32(temp); - - // Fill out rest of group structure - used += j*TT.blockbits; - bg[slot].block_bitmap = SWAP_LE32(used++); - bg[slot].inode_bitmap = SWAP_LE32(used++); - bg[slot].inode_table = SWAP_LE32(used); - bg[slot].used_dirs_count = 0; // (TODO) - } - xwrite(TT.fsfd, bg, TT.blocksize); - } - - // Now write out stuff that every block group has. - - // Write block usage bitmap - - start += 2 + itable; - memset(toybuf, 0, TT.blocksize); - bits_set(toybuf, 0, start); - bits_set(toybuf, end, TT.blockbits-end); - temp = TT.treeblocks - usedblocks; - if (temp) { - if (end-start > temp) temp = end-start; - bits_set(toybuf, start, temp); - } - xwrite(TT.fsfd, toybuf, TT.blocksize); - - // Write inode bitmap - memset(toybuf, 0, TT.blocksize); - j = 0; - if (!i) bits_set(toybuf, 0, j = INODES_RESERVED); - bits_set(toybuf, TT.inodespg, slot = TT.blockbits-TT.inodespg); - temp = TT.treeinodes - usedinodes; - if (temp) { - if (slot-j > temp) temp = slot-j; - bits_set(toybuf, j, temp); - } - xwrite(TT.fsfd, toybuf, TT.blocksize); - - // Write inode table for this group (TODO) - for (j = 0; j - * - * See http://pubs.opengroup.org/onlinepubs/009695399/utilities/mkfifo.html - * - * TODO: Add -m - -USE_MKFIFO(NEWTOY(mkfifo, "<1m:", TOYFLAG_BIN)) - -config MKFIFO - bool "mkfifo" - default y - help - usage: mkfifo [fifo_name...] - - Create FIFOs (named pipes). -*/ - -#include "toys.h" - -DEFINE_GLOBALS( - char *m_string; - mode_t mode; -) - -#define TT this.mkfifo -#define FLAG_m (1) - -void mkfifo_main(void) -{ - char **s; - - TT.mode = 0666; - if (toys.optflags & FLAG_m) { - TT.mode = string_to_mode(TT.m_string, 0); - } - - for (s = toys.optargs; *s; s++) { - if (mknod(*s, S_IFIFO | TT.mode, 0) < 0) { - perror_msg("cannot create fifo '%s'", *s); - toys.exitval = 1; - } - } -} diff -r 2d7c56913fda -r 2986aa63a021 toys/mknod.c --- a/toys/mknod.c Sat Aug 25 14:24:24 2012 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,51 +0,0 @@ -/* vi: set sw=4 ts=4: - * - * mknod.c - make block or character special file - * - * Copyright 2012 Elie De Brauwer - * - * Not in SUSv3. - -USE_MKNOD(NEWTOY(mknod, "<2>4", TOYFLAG_BIN)) - -config MKNOD - bool "mknod" - default y - help - usage: mknod NAME TYPE [MAJOR MINOR] - - Create a special file NAME with a given type, possible types are - b create a block device with the given MAJOR/MINOR - c or u create a character device with the given MAJOR/MINOR - p create a named pipe ignoring MAJOR/MINOR -*/ - -#include "toys.h" - -static const char modes_char[] = {'p', 'c', 'u', 'b'}; -static const mode_t modes[] = {S_IFIFO, S_IFCHR, S_IFCHR, S_IFBLK}; - -void mknod_main(void) -{ - int major=0, minor=0, type; - char * tmp; - int mode = 0660; - - tmp = strchr(modes_char, toys.optargs[1][0]); - if (!tmp) - perror_exit("unknown special device type %c", toys.optargs[1][0]); - - type = modes[tmp-modes_char]; - - if (type == S_IFCHR || type == S_IFBLK) { - if (toys.optc != 4) - perror_exit("creating a block/char device requires major/minor"); - - major = atoi(toys.optargs[2]); - minor = atoi(toys.optargs[3]); - } - - if (mknod(toys.optargs[0], mode | type, makedev(major, minor))) - perror_exit("mknod %s failed", toys.optargs[0]); - -} diff -r 2d7c56913fda -r 2986aa63a021 toys/mkswap.c --- a/toys/mkswap.c Sat Aug 25 14:24:24 2012 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,42 +0,0 @@ -/* vi: set sw=4 ts=4: - * - * mkswap.c - Format swap device. - * - * Copyright 2009 Rob Landley - * - * Not in SUSv4. - -USE_MKSWAP(NEWTOY(mkswap, "<1>1", TOYFLAG_SBIN)) - -config MKSWAP - bool "mkswap" - default y - help - usage: mkswap DEVICE - - Sets up a Linux swap area on a device or file. -*/ - -#include "toys.h" - -void mkswap_main(void) -{ - int fd = xopen(*toys.optargs, O_RDWR), pagesize = sysconf(_SC_PAGE_SIZE); - off_t len = fdlength(fd); - unsigned int pages = (len/pagesize)-1, *swap = (unsigned int *)toybuf; - - // Write header. Note that older kernel versions checked signature - // on disk (not in cache) during swapon, so sync after writing. - - swap[0] = 1; - swap[1] = pages; - xlseek(fd, 1024, SEEK_SET); - xwrite(fd, swap, 129*sizeof(unsigned int)); - xlseek(fd, pagesize-10, SEEK_SET); - xwrite(fd, "SWAPSPACE2", 10); - fsync(fd); - - if (CFG_TOYBOX_FREE) close(fd); - - printf("Swapspace size: %luk\n", pages*(unsigned long)(pagesize/1024)); -} diff -r 2d7c56913fda -r 2986aa63a021 toys/mktemp.c --- a/toys/mktemp.c Sat Aug 25 14:24:24 2012 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,54 +0,0 @@ -/* vi: set sw=4 ts=4: - * - * mktemp.c - Create a temporary file or directory. - * - * Copyright 2012 Elie De Brauwer - * - * Not in SUSv4. - -USE_MKTEMP(NEWTOY(mktemp, ">1(directory)d(tmpdir)p:", TOYFLAG_BIN)) - -config MKTEMP - bool "mktemp" - default y - help - usage: mktemp [OPTION] [TEMPLATE] - - Safely create a temporary file or directory and print its name. - TEMPLATE should end in 6 consecutive X's, the default - template is tmp.XXXXXX and the default directory is /tmp/. - - -d, --directory Create a directory, instead of a file - -p DIR, --tmpdir=DIR Use DIR as a base path - -*/ - -#include "toys.h" - -DEFINE_GLOBALS( - char * tmpdir; -) -#define TT this.mktemp - -void mktemp_main(void) -{ - int d_flag = toys.optflags & 2; - char *tmp, *path; - - tmp = *toys.optargs; - if (!tmp) tmp = "tmp.XXXXXX"; - if (!TT.tmpdir) TT.tmpdir = "/tmp/"; - - tmp = xmsprintf("%s/%s", TT.tmpdir, tmp); - - if (d_flag ? mkdtemp(tmp) == NULL : mkstemp(tmp) == -1) - perror_exit("Failed to create temporary %s", - d_flag ? "directory" : "file"); - - xputs(path = xrealpath(tmp)); - - if (CFG_TOYBOX_FREE) { - free(path); - free(tmp); - } -} diff -r 2d7c56913fda -r 2986aa63a021 toys/modinfo.c --- a/toys/modinfo.c Sat Aug 25 14:24:24 2012 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,103 +0,0 @@ -/* vi: set sw=4 ts=4: - * - * modinfo.c - Display module info - * - * Copyright 2012 Andre Renaud - * - -USE_MODINFO(NEWTOY(modinfo, "<1F:0", TOYFLAG_BIN)) - -config MODINFO - bool "modinfo" - default y - help - usage: modinfo [-0] [-F field] [modulename...] -*/ - -#include "toys.h" - -#define FLAG_0 (1 << 0) - -DEFINE_GLOBALS( - char *field; -) -#define TT this.modinfo - -static const char *modinfo_tags[] = { - "alias", "license", "description", "author", "vermagic", - "srcversion", "intree", "parm", "depends", -}; - -static void output_field(const char *field, const char *value) -{ - int len; - - if (TT.field && strcmp(TT.field, field) != 0) - return; - - len = strlen(field); - - if (TT.field) - xprintf("%s", value); - else - xprintf("%s:%*s%s", - field, 15 - len, "", value); - if (toys.optflags & FLAG_0) - xwrite(fileno(stdout), "\0", 1); - else - xputs(""); -} - - -static void modinfo_file(struct dirtree *dir) -{ - int fd, len, i; - char *buf, *pos; - char *full_name; - - full_name = dirtree_path(dir, NULL); - - output_field("filename", full_name); - fd = xopen(full_name, O_RDONLY); - len = fdlength(fd); - buf = xmalloc(len); - xreadall(fd, buf, len); - - for (pos = buf; pos < buf + len + 10; pos++) { - if (*pos) - continue; - - for (i = 0; i < sizeof(modinfo_tags) / sizeof(modinfo_tags[0]); i++) { - const char *str = modinfo_tags[i]; - int len = strlen(str); - if (strncmp(pos + 1, str, len) == 0 && pos[len + 1] == '=') - output_field(str, &pos[len + 2]); - } - } - - free(full_name); - free(buf); - close(fd); -} - -static int check_module(struct dirtree *new) -{ - if (S_ISREG(new->st.st_mode)) { - char **s; - for (s = toys.optargs; *s; s++) { - int len = strlen(*s); - if (!strncmp(*s, new->name, len) && !strcmp(new->name+len, ".ko")) - modinfo_file(new); - } - } - - return dirtree_notdotdot(new); -} - -void modinfo_main(void) -{ - struct utsname uts; - if (uname(&uts) < 0) perror_exit("bad uname"); - sprintf(toybuf, "/lib/modules/%s", uts.release); - dirtree_read(toybuf, check_module); -} diff -r 2d7c56913fda -r 2986aa63a021 toys/mountpoint.c --- a/toys/mountpoint.c Sat Aug 25 14:24:24 2012 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,56 +0,0 @@ -/* vi: set sw=4 ts=4: - * - * mountpoint.c - Check if a directory is a mountpoint. - * - * Copyright 2012 Elie De Brauwer - * - * Not in SUSv4. - -USE_MOUNTPOINT(NEWTOY(mountpoint, "<1qdx", TOYFLAG_BIN)) - -config MOUNTPOINT - bool "mountpoint" - default y - help - usage: mountpoint [-q] [-d] directory - mountpoint [-q] [-x] device - -q Be quiet, return zero if directory is a mountpoint - -d Print major/minor device number of the directory - -x Print major/minor device number of the block device -*/ - -#include "toys.h" - -void mountpoint_main(void) -{ - struct stat st1, st2; - int res = 0; - int quiet = toys.optflags & 0x4; - toys.exitval = 1; // be pessimistic - strncpy(toybuf, toys.optargs[0], sizeof(toybuf)); - if (((toys.optflags & 0x1) && lstat(toybuf, &st1)) || stat(toybuf, &st1)) - perror_exit("%s", toybuf); - - if (toys.optflags & 0x1){ - if (S_ISBLK(st1.st_mode)) { - if (!quiet) printf("%u:%u\n", major(st1.st_rdev), minor(st1.st_rdev)); - toys.exitval = 0; - return; - } - if (!quiet) printf("%s: not a block device\n", toybuf); - return; - } - - if(!S_ISDIR(st1.st_mode)){ - if (!quiet) printf("%s: not a directory\n", toybuf); - return; - } - strncat(toybuf, "/..", sizeof(toybuf)); - stat(toybuf, &st2); - res = (st1.st_dev != st2.st_dev) || - (st1.st_dev == st2.st_dev && st1.st_ino == st2.st_ino); - if (!quiet) printf("%s is %sa mountpoint\n", toys.optargs[0], res ? "" : "not "); - if (toys.optflags & 0x2) - printf("%u:%u\n", major(st1.st_dev), minor(st1.st_dev)); - toys.exitval = res ? 0 : 1; -} diff -r 2d7c56913fda -r 2986aa63a021 toys/netcat.c --- a/toys/netcat.c Sat Aug 25 14:24:24 2012 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,232 +0,0 @@ -/* vi: set sw=4 ts=4: - * - * nc: mini-netcat - Forward stdin/stdout to a file or network connection. - * - * Copyright 2007 Rob Landley - * - * Not in SUSv3. - -USE_NETCAT(OLDTOY(nc, netcat, USE_NETCAT_LISTEN("tl^L^")"w#p#s:q#f:", TOYFLAG_BIN)) -USE_NETCAT(NEWTOY(netcat, USE_NETCAT_LISTEN("tl^L^")"w#p#s:q#f:", TOYFLAG_BIN)) - -config NETCAT - bool "netcat" - default y - help - usage: netcat [-wpq #] [-s addr] {IPADDR PORTNUM|-f FILENAME|-let} [-e COMMAND] - - -w SECONDS timeout for connection - -p local port number - -s local ipv4 address - -q SECONDS quit this many seconds after EOF on stdin. - -f use FILENAME (ala /dev/ttyS0) instead of network - - Use "stty 115200 -F /dev/ttyS0 && stty raw -echo -ctlecho" with - netcat -f to connect to a serial port. - - -config NETCAT_LISTEN - bool "netcat sever options (-let)" - default y - depends on NETCAT - help - -t allocate tty (must come before -l or -L) - -l listen for one incoming connection. - -L listen for multiple incoming connections (server mode). - - Any additional command line arguments after -l or -L are executed - to handle each incoming connection. If none, the connection is - forwarded to stdin/stdout. - - For a quick-and-dirty server, try something like: - netcat -s 127.0.0.1 -p 1234 -tL /bin/bash -l -*/ - -#include "toys.h" -#include "toynet.h" - -DEFINE_GLOBALS( - char *filename; // -f read from filename instead of network - long quit_delay; // -q Exit after EOF from stdin after # seconds. - char *source_address; // -s Bind to a specific source address. - long port; // -p Bind to a specific source port. - long wait; // -w Wait # seconds for a connection. -) - -#define TT this.netcat - -#define FLAG_f 1 -#define FLAG_L 32 -#define FLAG_l 64 -#define FLAG_t 128 - -static void timeout(int signum) -{ - if (TT.wait) error_exit("Timeout"); - exit(0); -} - -static void set_alarm(int seconds) -{ - signal(SIGALRM, seconds ? timeout : SIG_DFL); - alarm(seconds); -} - -// Translate x.x.x.x numeric IPv4 address, or else DNS lookup an IPv4 name. -static void lookup_name(char *name, uint32_t *result) -{ - struct hostent *hostbyname; - - hostbyname = gethostbyname(name); - if (!hostbyname) error_exit("no host '%s'", name); - *result = *(uint32_t *)*hostbyname->h_addr_list; -} - -// Worry about a fancy lookup later. -static void lookup_port(char *str, uint16_t *port) -{ - *port = SWAP_BE16(atoi(str)); -} - -void netcat_main(void) -{ - int sockfd=-1, pollcount=2; - struct pollfd pollfds[2]; - - memset(pollfds, 0, 2*sizeof(struct pollfd)); - pollfds[0].events = pollfds[1].events = POLLIN; - set_alarm(TT.wait); - - // The argument parsing logic can't make "<2" conditional on other - // arguments like -f and -l, so we do it by hand here. - if (toys.optflags&FLAG_f) { - if (toys.optc) toys.exithelp++; - } else if (!(toys.optflags&(FLAG_l|FLAG_L)) && toys.optc!=2) toys.exithelp++; - - if (toys.exithelp) error_exit("Argument count wrong"); - - if (TT.filename) pollfds[0].fd = xopen(TT.filename, O_RDWR); - else { - int temp; - struct sockaddr_in address; - - // Setup socket - sockfd = socket(AF_INET, SOCK_STREAM, 0); - if (-1 == sockfd) perror_exit("socket"); - fcntl(sockfd, F_SETFD, FD_CLOEXEC); - temp = 1; - setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &temp, sizeof(temp)); - memset(&address, 0, sizeof(address)); - address.sin_family = AF_INET; - if (TT.source_address || TT.port) { - address.sin_port = SWAP_BE16(TT.port); - if (TT.source_address) - lookup_name(TT.source_address, (uint32_t *)&address.sin_addr); - if (bind(sockfd, (struct sockaddr *)&address, sizeof(address))) - perror_exit("bind"); - } - - // Dial out - - if (!CFG_NETCAT_LISTEN || !(toys.optflags&(FLAG_L|FLAG_l))) { - // Figure out where to dial out to. - lookup_name(*toys.optargs, (uint32_t *)&address.sin_addr); - lookup_port(toys.optargs[1], &address.sin_port); - temp = connect(sockfd, (struct sockaddr *)&address, sizeof(address)); - if (temp<0) perror_exit("connect"); - pollfds[0].fd = sockfd; - - // Listen for incoming connections - - } else { - socklen_t len = sizeof(address); - - if (listen(sockfd, 5)) error_exit("listen"); - if (!TT.port) { - getsockname(sockfd, (struct sockaddr *)&address, &len); - printf("%d\n", SWAP_BE16(address.sin_port)); - fflush(stdout); - } - // Do we need to return immediately because -l has arguments? - - if ((toys.optflags&FLAG_l) && toys.optc) { - if (fork()) goto cleanup; - close(0); - close(1); - close(2); - } - - for (;;) { - pid_t child = 0; - - // For -l, call accept from the _new_ thread. - - pollfds[0].fd = accept(sockfd, (struct sockaddr *)&address, - &len); - if (pollfds[0].fd<0) perror_exit("accept"); - - // Do we need a tty? - - if (toys.optflags&FLAG_t) - child = forkpty(&(pollfds[1].fd), NULL, NULL, NULL); - - // Do we need to fork and/or redirect for exec? - - else { - if (toys.optflags&FLAG_L) child = fork(); - if (!child && toys.optc) { - int fd = pollfds[0].fd; - - if (!temp) close(sockfd); - dup2(fd, 0); - dup2(fd, 1); - dup2(fd, 2); - if (fd>2) close(fd); - } - } - - if (child<0) error_msg("Fork failed\n"); - if (child<1) break; - close(pollfds[0].fd); - } - } - } - - // We have a connection. Disarm timeout. - // (Does not play well with -L, but what _should_ that do?) - set_alarm(0); - - if (CFG_NETCAT_LISTEN && (toys.optflags&(FLAG_L|FLAG_l) && toys.optc)) { - execvp(*toys.optargs, toys.optargs); - error_exit("Exec failed"); - } - - // Poll loop copying stdin->socket and socket->stdout. - for (;;) { - int i; - - if (0>poll(pollfds, pollcount, -1)) perror_exit("poll"); - - for (i=0; i - * - * See http://www.opengroup.org/onlinepubs/9699919799/utilities/nice.html - -USE_NICE(NEWTOY(nice, "^<1n#", TOYFLAG_USR|TOYFLAG_BIN)) - -config NICE - bool "nice" - default y - help - usage: nice [-n PRIORITY] command [args...] - - Run a command line at an increased or decreased scheduling priority. - - Higher numbers make a program yield more CPU time, from -20 (highest - priority) to 19 (lowest). By default processes inherit their parent's - niceness (usually 0). By default this command adds 10 to the parent's - priority. Only root can set a negative niceness level. -*/ - -#include "toys.h" - -DEFINE_GLOBALS( - long priority; -) - -#define TT this.nice - -void nice_main(void) -{ - if (!toys.optflags) TT.priority = 10; - - errno = 0; - if (nice(TT.priority)==-1 && errno) perror_exit("Can't set priority"); - - xexec(toys.optargs); -} diff -r 2d7c56913fda -r 2986aa63a021 toys/nohup.c --- a/toys/nohup.c Sat Aug 25 14:24:24 2012 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,42 +0,0 @@ -/* vi: set sw=4 ts=4: - * - * nohup.c - run commandline with SIGHUP blocked. - * - * Copyright 2011 Rob Landley - * - * See http://opengroup.org/onlinepubs/9699919799/utilities/nohup.html - -USE_NOHUP(NEWTOY(nohup, "<1", TOYFLAG_USR|TOYFLAG_BIN)) - -config NOHUP - bool "nohup" - default y - help - usage: nohup COMMAND [ARGS...] - - Run a command that survives the end of its terminal. - If stdin is a tty, redirect from /dev/null - If stdout is a tty, redirect to file "nohup.out" -*/ - -#include "toys.h" - -void nohup_main(void) -{ - signal(SIGHUP, SIG_IGN); - if (isatty(1)) { - close(1); - if (-1 == open("nohup.out", O_CREAT|O_APPEND|O_WRONLY, - S_IRUSR|S_IWUSR )) - { - char *temp = getenv("HOME"); - temp = xmsprintf("%s/%s", temp ? temp : "", "nohup.out"); - xcreate(temp, O_CREAT|O_APPEND|O_WRONLY, S_IRUSR|S_IWUSR); - } - } - if (isatty(0)) { - close(0); - open("/dev/null", O_RDONLY); - } - xexec(toys.optargs); -} diff -r 2d7c56913fda -r 2986aa63a021 toys/od.c --- a/toys/od.c Sat Aug 25 14:24:24 2012 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,274 +0,0 @@ -/* vi: set sw=4 ts=4: - * - * od.c - Provide octal/hex dumps of data - * - * Copyright 2012 Andre Renaud - * Copyright 2012 Rob Landley - * - * See http://pubs.opengroup.org/onlinepubs/9699919799/utilities/od.html - -USE_OD(NEWTOY(od, "j#vN#xsodcbA:t*", TOYFLAG_USR|TOYFLAG_BIN)) - -config OD - bool "od" - default y - help - usage: od [-bdosxv] [-j #] [-N #] [-A doxn] [-t arg] - - -A Address base (decimal, octal, hexdecimal, none) - -t output type(s) a (ascii) c (char) d (decimal) foux -*/ - -#include "toys.h" - -#define FLAG_t (1 << 0) -#define FLAG_A (1 << 1) -#define FLAG_b (1 << 2) -#define FLAG_c (1 << 3) -#define FLAG_d (1 << 4) -#define FLAG_o (1 << 5) -#define FLAG_s (1 << 6) -#define FLAG_x (1 << 7) -#define FLAG_N (1 << 8) -#define FLAG_v (1 << 9) - -DEFINE_GLOBALS( - struct arg_list *output_base; - char *address_base; - long max_count; - long jump_bytes; - - unsigned types, leftover, star, address_idx; - char *buf; - uint64_t bufs[4]; // force 64-bit alignment - off_t pos; -) - -#define TT this.od - -static char *ascii = "nulsohstxetxeotenqackbel bs ht nl vt ff cr so si" - "dledc1dc2dc3dc4naksynetbcan emsubesc fs gs rs us sp"; - -struct odtype { - int type; - int size; -}; - -static void od_outline(void) -{ - unsigned flags = toys.optflags; - char *abases[] = {"", "%07d", "%07o", "%06x"}; - struct odtype *types = (struct odtype *)toybuf, *t; - int i, len; - - if (TT.leftover<16) memset(TT.buf+TT.leftover, 0, 16-TT.leftover); - - // Handle duplciate lines as * - if (!(flags&FLAG_v) && TT.jump_bytes != TT.pos && TT.leftover - && !memcmp(TT.bufs, TT.bufs + 2, 16)) - { - if (!TT.star) { - xputs("*"); - TT.star++; - } - - // Print line position - } else { - TT.star = 0; - - xprintf(abases[TT.address_idx], TT.pos); - if (!TT.leftover) { - if (TT.address_idx) xputc('\n'); - return; - } - } - - TT.pos += len = TT.leftover; - TT.leftover = 0; - if (TT.star) return; - - // For each output type, print one line - - for (i=0; itype < 2) { - char c = TT.buf[j++]; - pad += 4; - - if (!t->type) { - c &= 127; - if (c<=32) sprintf(buf, "%.3s", ascii+(3*c)); - else if (c==127) strcpy(buf, "del"); - else sprintf(buf, "%c", c); - } else { - char *bfnrtav = "\b\f\n\r\t\a\v", *s = strchr(bfnrtav, c); - if (s) sprintf(buf, "\\%c", "bfnrtav0"[s-bfnrtav]); - else if (c < 32 || c >= 127) sprintf(buf, "%03o", c); - else { - // TODO: this should be UTF8 aware. - sprintf(buf, "%c", c); - } - } - } else if (CFG_TOYBOX_FLOAT && t->type == 6) { - long double ld; - union {float f; double d; long double ld;} fdl; - - memcpy(&fdl, TT.buf+j, t->size); - j += t->size; - if (sizeof(float) == t->size) { - ld = fdl.f; - pad += (throw = 8)+7; - } else if (sizeof(double) == t->size) { - ld = fdl.d; - pad += (throw = 17)+8; - } else if (sizeof(long double) == t->size) { - ld = fdl.ld; - pad += (throw = 21)+9; - } else error_exit("bad -tf '%d'", t->size); - - sprintf(buf, "%.*Le", throw, ld); - // Integer types - } else { - unsigned long long ll = 0, or; - char *c[] = {"%*lld", "%*llu", "%0*llo", "%0*llx"}, - *class = c[t->type-2]; - - // Work out width of field - if (t->size == 8) { - or = -1LL; - if (t->type == 2) or >>= 1; - } else or = (1LL<<(8*t->size))-1; - throw = sprintf(buf, class, 0, or); - - // Accumulate integer based on size argument - for (k=0; k < t->size; k++) { - or = TT.buf[j++]; - ll |= or << (8*(IS_BIG_ENDIAN ? t->size-k-1 : k)); - } - - // Handle negative values - if (t->type == 2) { - or = sizeof(or) - t->size; - throw++; - if (or && (ll & (1l<<((8*t->size)-1)))) - ll |= ((or<<(8*or))-1) << (8*t->size); - } - - sprintf(buf, class, throw, ll); - pad += throw+1; - } - xprintf("%*s", pad, buf); - pad = 0; - } - xputc('\n'); - } - - // buffer toggle for "same as last time" check. - TT.buf = (char *)((TT.buf == (char *)TT.bufs) ? TT.bufs+2 : TT.bufs); -} - -static void do_od(int fd, char *name) -{ - // Skip input, possibly more than one entire file. - if (TT.jump_bytes < TT.pos) { - off_t off = lskip(fd, TT.jump_bytes); - if (off > 0) TT.pos += off; - if (TT.jump_bytes < TT.pos) return; - } - - for(;;) { - char *buf = TT.buf + TT.leftover; - int len = 16 - TT.leftover; - - if (toys.optflags & FLAG_N) { - if (!TT.max_count) break; - if (TT.max_count < len) len = TT.max_count; - } - - len = readall(fd, buf, len); - if (len < 0) { - perror_msg("%s", name); - break; - } - if (TT.max_count) TT.max_count -= len; - TT.leftover += len; - if (TT.leftover < 16) break; - - od_outline(); - } -} - -static void append_base(char *base) -{ - char *s = base; - struct odtype *types = (struct odtype *)toybuf; - int type; - - for (;;) { - int size = 1; - - if (!*s) return; - if (TT.types >= sizeof(toybuf)/sizeof(struct odtype)) break; - if (-1 == (type = stridx("acduox"USE_TOYBOX_FLOAT("f"), *(s++)))) break; - - if (isdigit(*s)) { - size = strtol(s, &s, 10); - if (type < 2 && size != 1) break; - if (CFG_TOYBOX_FLOAT && type == 6 && size == sizeof(long double)); - else if (size < 0 || size > 8) break; - } else if (CFG_TOYBOX_FLOAT && type == 6) { - int sizes[] = {sizeof(float), sizeof(double), sizeof(long double)}; - if (-1 == (size = stridx("FDL", *s))) size = sizeof(double); - else { - s++; - size = sizes[size]; - } - } else if (type > 1) { - if (-1 == (size = stridx("CSIL", *s))) size = 4; - else { - s++; - size = 1 << size; - } - } - - types[TT.types].type = type; - types[TT.types].size = size; - TT.types++; - } - - error_exit("bad -t %s", base); -} - -void od_main(void) -{ - struct arg_list *arg; - - TT.buf = (char *)TT.bufs; - - if (!TT.address_base) TT.address_idx = 2; - else if (0>(TT.address_idx = stridx("ndox", *TT.address_base))) - error_exit("bad -A '%c'", *TT.address_base); - - // Collect -t entries - - for (arg = TT.output_base; arg; arg = arg->next) append_base(arg->arg); - if (toys.optflags & FLAG_b) append_base("o1"); - if (toys.optflags & FLAG_d) append_base("u2"); - if (toys.optflags & FLAG_o) append_base("o2"); - if (toys.optflags & FLAG_s) append_base("d2"); - if (toys.optflags & FLAG_x) append_base("x2"); - if (!TT.output_base) append_base("o2"); - - loopfiles(toys.optargs, do_od); - - if (TT.leftover) od_outline(); - od_outline(); -} diff -r 2d7c56913fda -r 2986aa63a021 toys/oneit.c --- a/toys/oneit.c Sat Aug 25 14:24:24 2012 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,80 +0,0 @@ -/* vi: set sw=4 ts=4: - * - * oneit.c, tiny one-process init replacement. - * - * Copyright 2005, 2007 by Rob Landley . - * - * Not in SUSv3. - -USE_ONEIT(NEWTOY(oneit, "^<1c:p", TOYFLAG_SBIN)) - -config ONEIT - bool "oneit" - default y - help - usage: oneit [-p] [-c /dev/tty0] command [...] - - A simple init program that runs a single supplied command line with a - controlling tty (so CTRL-C can kill it). - - -p Power off instead of rebooting when command exits. - -c Which console device to use. - - The oneit command runs the supplied command line as a child process - (because PID 1 has signals blocked), attached to /dev/tty0, in its - own session. Then oneit reaps zombies until the child exits, at - which point it reboots (or with -p, powers off) the system. -*/ - -#include "toys.h" -#include - -DEFINE_GLOBALS( - char *console; -) - -#define TT this.oneit - -// The minimum amount of work necessary to get ctrl-c and such to work is: -// -// - Fork a child (PID 1 is special: can't exit, has various signals blocked). -// - Do a setsid() (so we have our own session). -// - In the child, attach stdio to /dev/tty0 (/dev/console is special) -// - Exec the rest of the command line. -// -// PID 1 then reaps zombies until the child process it spawned exits, at which -// point it calls sync() and reboot(). I could stick a kill -1 in there. - - -void oneit_main(void) -{ - int i; - pid_t pid; - - // Create a new child process. - pid = vfork(); - if (pid) { - - // pid 1 just reaps zombies until it gets its child, then halts the system. - while (pid!=wait(&i)); - sync(); - - // PID 1 can't call reboot() because it kills the task that calls it, - // which causes the kernel to panic before the actual reboot happens. - if (!vfork()) reboot((toys.optflags&1) ? RB_POWER_OFF : RB_AUTOBOOT); - sleep(5); - _exit(1); - } - - // Redirect stdio to /dev/tty0, with new session ID, so ctrl-c works. - setsid(); - for (i=0; i<3; i++) { - close(i); - xopen(TT.console ? TT.console : "/dev/tty0",O_RDWR); - } - - // Can't xexec() here, because we vforked so we don't want to error_exit(). - toy_exec(toys.optargs); - execvp(*toys.optargs, toys.optargs); - _exit(127); -} diff -r 2d7c56913fda -r 2986aa63a021 toys/other/bzcat.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/toys/other/bzcat.c Sat Aug 25 14:25:22 2012 -0500 @@ -0,0 +1,30 @@ +/* vi: set sw=4 ts=4: + * + * bzcat.c - decompress stdin to stdout using bunzip2. + * + * Copyright 2007 Rob Landley + * + * Not in SUSv3. + +USE_BZCAT(NEWTOY(bzcat, NULL, TOYFLAG_USR|TOYFLAG_BIN)) + +config BZCAT + bool "bzcat" + default y + help + usage: bzcat [filename...] + + Decompress listed files to stdout. Use stdin if no files listed. +*/ + +#include "toys.h" + +static void do_bzcat(int fd, char *name) +{ + bunzipStream(fd, 1); +} + +void bzcat_main(void) +{ + loopfiles(toys.optargs, do_bzcat); +} diff -r 2d7c56913fda -r 2986aa63a021 toys/other/catv.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/toys/other/catv.c Sat Aug 25 14:25:22 2012 -0500 @@ -0,0 +1,67 @@ +/* vi: set sw=4 ts=4: + * + * cat -v implementation for toybox + * + * Copyright (C) 2006, 2007 Rob Landley + * + * Not in SUSv3, but see "Cat -v considered harmful" at + * http://cm.bell-labs.com/cm/cs/doc/84/kp.ps.gz + +USE_CATV(NEWTOY(catv, "vte", TOYFLAG_USR|TOYFLAG_BIN)) + +config CATV + bool "catv" + default y + help + usage: catv [-evt] [filename...] + + Display nonprinting characters as escape sequences. Use M-x for + high ascii characters (>127), and ^x for other nonprinting chars. + + -e Mark each newline with $ + -t Show tabs as ^I + -v Don't use ^x or M-x escapes. +*/ + +#include "toys.h" + +// Callback function for loopfiles() + +static void do_catv(int fd, char *name) +{ + for(;;) { + int i, len; + + len = read(fd, toybuf, sizeof(toybuf)); + if (len < 0) toys.exitval = EXIT_FAILURE; + if (len < 1) break; + for (i=0; i 126 && (toys.optflags & 4)) { + if (c == 127) { + printf("^?"); + continue; + } else { + printf("M-"); + c -= 128; + } + } + if (c < 32) { + if (c == 10) { + if (toys.optflags & 1) xputc('$'); + } else if (toys.optflags & (c==9 ? 2 : 4)) { + printf("^%c", c+'@'); + continue; + } + } + xputc(c); + } + } +} + +void catv_main(void) +{ + toys.optflags^=4; + loopfiles(toys.optargs, do_catv); +} diff -r 2d7c56913fda -r 2986aa63a021 toys/other/chroot.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/toys/other/chroot.c Sat Aug 25 14:25:22 2012 -0500 @@ -0,0 +1,28 @@ +/* vi: set sw=4 ts=4: + * + * chroot.c - Run command in new root directory. + * + * Copyright 2007 Rob Landley + * + * Not in SUSv3. + +USE_CHROOT(NEWTOY(chroot, "^<1", TOYFLAG_USR|TOYFLAG_SBIN)) + +config CHROOT + bool "chroot" + default y + help + usage: chroot NEWPATH [commandline...] + + Run command within a new root directory. If no command, run /bin/sh. +*/ + +#include "toys.h" + +void chroot_main(void) +{ + char *binsh[] = {"/bin/sh", "-i", 0}; + if (chdir(*toys.optargs) || chroot(".")) + perror_exit("%s", *toys.optargs); + xexec(toys.optargs[1] ? toys.optargs+1 : binsh); +} diff -r 2d7c56913fda -r 2986aa63a021 toys/other/chvt.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/toys/other/chvt.c Sat Aug 25 14:25:22 2012 -0500 @@ -0,0 +1,51 @@ +/* vi: set sw=4 ts=4: + * + * chvt.c - switch virtual terminals + * + * Copyright (C) 2008 David Anders + * + * Not in SUSv3. + +USE_CHVT(NEWTOY(chvt, "<1", TOYFLAG_USR|TOYFLAG_SBIN)) + +config CHVT + bool "chvt" + default y + help + usage: chvt N + + Change to virtual terminal number N. (This only works in text mode.) + + Virtual terminals are the Linux VGA text mode displays, ordinarily + switched between via alt-F1, alt-F2, etc. Use ctrl-alt-F1 to switch + from X to a virtual terminal, and alt-F6 (or F7, or F8) to get back. +*/ + +#include "toys.h" + +/* Note: get_console_fb() will need to be moved into a seperate lib section */ +int get_console_fd() +{ + int fd; + char *consoles[]={"/dev/console", "/dev/vc/0", "/dev/tty", NULL}, **cc; + + cc = consoles; + while (*cc) { + fd = open(*cc++, O_RDWR); + if (fd >= 0) return fd; + } + + return -1; +} + +void chvt_main(void) +{ + int vtnum, fd; + + vtnum=atoi(*toys.optargs); + + fd=get_console_fd(); + // These numbers are VT_ACTIVATE and VT_WAITACTIVE from linux/vt.h + if (fd < 0 || ioctl(fd, 0x5606, vtnum) || ioctl(fd, 0x5607, vtnum)) + perror_exit(NULL); +} diff -r 2d7c56913fda -r 2986aa63a021 toys/other/clear.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/toys/other/clear.c Sat Aug 25 14:25:22 2012 -0500 @@ -0,0 +1,23 @@ +/* vi: set sw=4 ts=4: + * + * clear.c - clear the screen + * + * Copyright 2012 Rob Landley + * + * Not in SUSv4. + +USE_CLEAR(NEWTOY(clear, NULL, TOYFLAG_USR|TOYFLAG_BIN)) + +config CLEAR + bool "clear" + default y + help + Clear the screen. +*/ + +#include "toys.h" + +void clear_main(void) +{ + write(1, "\e[2J\e[H", 7); +} diff -r 2d7c56913fda -r 2986aa63a021 toys/other/count.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/toys/other/count.c Sat Aug 25 14:25:22 2012 -0500 @@ -0,0 +1,36 @@ +/* vi: set sw=4 ts=4: + * + * count.c - Progress indicator from stdin to stdout + * + * Copyright 2002 Rob Landley + * + * Not in SUSv3. + +USE_COUNT(NEWTOY(count, NULL, TOYFLAG_USR|TOYFLAG_BIN)) + +config COUNT + bool "count" + default y + help + usage: count + + Copy stdin to stdout, displaying simple progress indicator to stderr. +*/ + +#include "toys.h" + +void count_main(void) +{ + uint64_t size = 0; + int len; + char buf[32]; + + for (;;) { + len = xread(0, toybuf, sizeof(toybuf)); + if (!len) break; + size += len; + xwrite(1, toybuf, len); + xwrite(2, buf, sprintf(buf, "%"PRIu64" bytes\r", size)); + } + xwrite(2, "\n", 1); +} diff -r 2d7c56913fda -r 2986aa63a021 toys/other/dos2unix.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/toys/other/dos2unix.c Sat Aug 25 14:25:22 2012 -0500 @@ -0,0 +1,70 @@ +/* vi: set sw=4 ts=4: + * + * dos2unix.c - convert newline format + * + * Copyright 2012 Rob Landley + * + * No standard + +USE_DOS2UNIX(NEWTOY(dos2unix, NULL, TOYFLAG_BIN)) +USE_DOS2UNIX(OLDTOY(unix2dos, dos2unix, NULL, TOYFLAG_BIN)) + +config DOS2UNIX + bool "dos2unix/unix2dos" + default y + help + usage: dos2unix/unix2dos [file...] + + Convert newline format between dos (\r\n) and unix (just \n) + If no files listed copy from stdin, "-" is a synonym for stdin. +*/ + +#include "toys.h" + +DEFINE_GLOBALS( + char *tempfile; +) + +#define TT this.dos2unix + +static void do_dos2unix(int fd, char *name) +{ + char c = toys.which->name[0]; + int outfd = 1, catch = 0; + + if (fd) outfd = copy_tempfile(fd, name, &TT.tempfile); + + for (;;) { + int len, in, out; + + len = read(fd, toybuf+(sizeof(toybuf)/2), sizeof(toybuf)/2); + if (len<0) { + perror_msg("%s",name); + toys.exitval = 1; + } + if (len<1) break; + + for (in = out = 0; in < len; in++) { + char x = toybuf[in+sizeof(toybuf)/2]; + + // Drop \r only if followed by \n in dos2unix mode + if (catch) { + if (c == 'u' || x != '\n') toybuf[out++] = '\r'; + catch = 0; + // Add \r only if \n not after \r in unix2dos mode + } else if (c == 'u' && x == '\n') toybuf[out++] = '\r'; + + if (x == '\r') catch++; + else toybuf[out++] = x; + } + xwrite(outfd, toybuf, out); + } + if (catch) xwrite(outfd, "\r", 1); + + if (fd) replace_tempfile(-1, outfd, &TT.tempfile); +} + +void dos2unix_main(void) +{ + loopfiles(toys.optargs, do_dos2unix); +} diff -r 2d7c56913fda -r 2986aa63a021 toys/other/free.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/toys/other/free.c Sat Aug 25 14:25:22 2012 -0500 @@ -0,0 +1,60 @@ +/* vi: set sw=4 ts=4: + * + * free.c - Display amount of free and used memory in the system. + * + * Copyright 2012 Elie De Brauwer + * + * Not in SUSv4. + +USE_FREE(NEWTOY(free, "gmkb", TOYFLAG_USR|TOYFLAG_BIN)) + +config FREE + bool "free" + default y + help + usage: free [-bkmg] + + Display the total, free and used amount of physical memory and + swap space. + + -bkmg Output in bytes (default), KB, MB or GB +*/ + +#include "toys.h" + +static unsigned long long convert(unsigned long d, unsigned int iscale, + unsigned int oscale) +{ + return ((unsigned long long)d*iscale)>>oscale; +} + +void free_main(void) +{ + struct sysinfo info; + unsigned int iscale = 1; + unsigned int oscale = 0; + + sysinfo(&info); + if (info.mem_unit) iscale = info.mem_unit; + if (toys.optflags & 1) oscale = 0; + if (toys.optflags & 2) oscale = 10; + if (toys.optflags & 4) oscale = 20; + if (toys.optflags & 8) oscale = 30; + + xprintf("\t\ttotal used free shared buffers\n"); + xprintf("Mem:%17llu%12llu%12llu%12llu%12llu\n", + convert(info.totalram, iscale, oscale), + convert(info.totalram-info.freeram, iscale, oscale), + convert(info.freeram, iscale, oscale), + convert(info.sharedram, iscale, oscale), + convert(info.bufferram, iscale, oscale)); + + xprintf("-/+ buffers/cache:%15llu%12llu\n", + convert(info.totalram - info.freeram - info.bufferram, iscale, oscale), + convert(info.freeram + info.bufferram, iscale, oscale)); + + xprintf("Swap:%16llu%12llu%12llu\n", + convert(info.totalswap, iscale, oscale), + convert(info.totalswap - info.freeswap, iscale, oscale), + convert(info.freeswap, iscale, oscale)); +} diff -r 2d7c56913fda -r 2986aa63a021 toys/other/hello.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/toys/other/hello.c Sat Aug 25 14:25:22 2012 -0500 @@ -0,0 +1,60 @@ +/* vi: set sw=4 ts=4: + * + * hello.c - A hello world program. + * + * Copyright 2012 Rob Landley + * + * Not in SUSv4/LSB. + * See http://opengroup.org/onlinepubs/9699919799/utilities/ + * See http://refspecs.linuxfoundation.org/LSB_4.1.0/LSB-Core-generic/LSB-Core-generic/cmdbehav.html + +USE_HELLO(NEWTOY(hello, "e@d*c#b:a", TOYFLAG_USR|TOYFLAG_BIN)) + +config HELLO + bool "hello" + default n + help + usage: hello [-a] [-b string] [-c number] [-d list] [-e count] [...] + + A hello world program. You don't need this. + + Mostly used as an example/skeleton file for adding new commands, + occasionally nice to test kernel booting via "init=/bin/hello". +*/ + +#include "toys.h" + +// Hello doesn't use these globals, they're here for example/skeleton purposes. + +DEFINE_GLOBALS( + char *b_string; + long c_number; + struct arg_list *d_list; + long e_count; + + int more_globals; +) + +#define TT this.hello + +#define FLAG_a 1 +#define FLAG_b 2 +#define FLAG_c 4 +#define FLAG_d 8 +#define FLAG_e 16 + +void hello_main(void) +{ + printf("Hello world\n"); + + if (toys.optflags & FLAG_a) printf("Saw a\n"); + if (toys.optflags & FLAG_b) printf("b=%s\n", TT.b_string); + if (toys.optflags & FLAG_c) printf("c=%ld\n", TT.c_number); + while (TT.d_list) { + printf("d=%s\n", TT.d_list->arg); + TT.d_list = TT.d_list->next; + } + if (TT.e_count) printf("e was seen %ld times", TT.e_count); + + while (*toys.optargs) printf("optarg=%s\n", *(toys.optargs++)); +} diff -r 2d7c56913fda -r 2986aa63a021 toys/other/help.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/toys/other/help.c Sat Aug 25 14:25:22 2012 -0500 @@ -0,0 +1,48 @@ +/* vi: set sw=4 ts=4: + * + * help.c - Show help for toybox + * + * Copyright 2007 Rob Landley + * + * Not in SUSv3, but exists as a bash builtin. + +USE_HELP(NEWTOY(help, "<1", TOYFLAG_BIN)) + +config HELP + bool "help" + default y + help + usage: help [command] + + Show usage information for toybox commands. + Run "toybox" with no arguments for a list of available commands. +*/ + + +#include "toys.h" +#include "generated/help.h" + +#undef NEWTOY +#undef OLDTOY +#define NEWTOY(name,opt,flags) help_##name "\0" +#define OLDTOY(name,oldname,opts,flags) "\xff" #oldname "\0" +static char *help_data = +#include "generated/newtoys.h" +; + +void help_main(void) +{ + struct toy_list *t = toy_find(*toys.optargs); + int i = t-toy_list; + char *s = help_data; + + if (!t) error_exit("Unknown command '%s'", *toys.optargs); + for (;;) { + while (i--) s += strlen(s) + 1; + if (*s != 255) break; + i = toy_find(++s)-toy_list; + s = help_data; + } + + fprintf(toys.exithelp ? stderr : stdout, "%s", s); +} diff -r 2d7c56913fda -r 2986aa63a021 toys/other/insmod.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/toys/other/insmod.c Sat Aug 25 14:25:22 2012 -0500 @@ -0,0 +1,47 @@ +/* vi: set sw=4 ts=4: + * + * insmod.c - Load a module into the Linux kernel. + * + * Copyright 2012 Elie De Brauwer + * + * Not in SUSv4. + +USE_INSMOD(NEWTOY(insmod, "<1", TOYFLAG_BIN|TOYFLAG_NEEDROOT)) + +config INSMOD + bool "insmod" + default y + help + usage: insmod MODULE [MODULE_OPTIONS] + + Load the module named MODULE passing options if given. +*/ + +#include "toys.h" + +#include +#define init_module(mod, len, opts) syscall(__NR_init_module, mod, len, opts) + +void insmod_main(void) +{ + char * buf = NULL; + int len, res, i; + int fd = xopen(toys.optargs[0], O_RDONLY); + + len = fdlength(fd); + buf = xmalloc(len); + xreadall(fd, buf, len); + + i = 1; + while(toys.optargs[i] && + strlen(toybuf) + strlen(toys.optargs[i]) + 2 < sizeof(toybuf)) { + strcat(toybuf, toys.optargs[i++]); + strcat(toybuf, " "); + } + + res = init_module(buf, len, toybuf); + if (CFG_TOYBOX_FREE && buf != toybuf) free(buf); + + if (res) + perror_exit("failed to load %s", toys.optargs[0]); +} diff -r 2d7c56913fda -r 2986aa63a021 toys/other/login.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/toys/other/login.c Sat Aug 25 14:25:22 2012 -0500 @@ -0,0 +1,246 @@ +/* vi: set sw=4 ts=4: + * + * login.c - Start a session on the system. + * + * Copyright 2012 Elie De Brauwer + * + * Not in SUSv4. + * No support for PAM/securetty/selinux/login script/issue/utmp + * Relies on libcrypt for hash calculation. + +USE_LOGIN(NEWTOY(login, ">1fph:", TOYFLAG_BIN)) + +config LOGIN + bool "login" + default y + help + usage: login [-p] [-h host] [[-f] username] + + Establish a new session with the system. + -p Preserve environment + -h The name of the remote host for this login + -f Do not perform authentication +*/ + +#include "toys.h" + +#define LOGIN_TIMEOUT 60 +#define LOGIN_FAIL_TIMEOUT 3 +#define USER_NAME_MAX_SIZE 32 +#define HOSTNAME_SIZE 32 + +DEFINE_GLOBALS( + char *hostname; +) +#define TT this.login + +static void login_timeout_handler(int sig __attribute__((unused))) +{ + printf("\nLogin timed out after %d seconds.\n", LOGIN_TIMEOUT); + exit(0); +} + +static char *forbid[] = { + "BASH_ENV", + "ENV", + "HOME", + "IFS", + "LD_LIBRARY_PATH", + "LD_PRELOAD", + "LD_TRACE_LOADED_OBJECTS", + "LD_BIND_NOW", + "LD_AOUT_LIBRARY_PATH", + "LD_AOUT_PRELOAD", + "LD_NOWARN", + "LD_KEEPDIR", + "SHELL", + NULL +}; + +int verify_password(char * pwd) +{ + char *pass; + + if (read_password(toybuf, sizeof(toybuf), "Password: ")) return 1; + if (!pwd) return 1; + if (pwd[0] == '!' || pwd[0] == '*') return 1; + + pass = crypt(toybuf, pwd); + if (pass && !strcmp(pass, pwd)) return 0; + + return 1; +} + +void read_user(char * buff, int size) +{ + char hostname[HOSTNAME_SIZE+1]; + int i = 0; + hostname[HOSTNAME_SIZE] = 0; + if(!gethostname(hostname, HOSTNAME_SIZE)) fputs(hostname, stdout); + + fputs(" login: ", stdout); + fflush(stdout); + + do { + buff[0] = getchar(); + if (buff[0] == EOF) + exit(EXIT_FAILURE); + } while (isblank(buff[0])); + + if (buff[0] != '\n') + if(!fgets(&buff[1], HOSTNAME_SIZE-1, stdin)) + _exit(1); + + while(ipw_name,pwd->pw_gid)) return 1; + if (setgid(pwd->pw_uid)) return 1; + if (setuid(pwd->pw_uid)) return 1; + + return 0; +} + +void spawn_shell(const char *shell) +{ + const char * exec_name = strrchr(shell,'/'); + if (exec_name) exec_name++; + else exec_name = shell; + + snprintf(toybuf,sizeof(toybuf)-1, "-%s", shell); + execl(shell, toybuf, NULL); + error_exit("Failed to spawn shell"); +} + +void setup_environment(const struct passwd *pwd, int clear_env) +{ + if (chdir(pwd->pw_dir)) printf("bad home dir: %s\n", pwd->pw_dir); + + if (clear_env) { + const char * term = getenv("TERM"); + clearenv(); + if (term) setenv("TERM", term, 1); + } + + setenv("USER", pwd->pw_name, 1); + setenv("LOGNAME", pwd->pw_name, 1); + setenv("HOME", pwd->pw_dir, 1); + setenv("SHELL", pwd->pw_shell, 1); +} + +void login_main(void) +{ + int f_flag = (toys.optflags & 4) >> 2; + int p_flag = (toys.optflags & 2) >> 1; + int h_flag = toys.optflags & 1; + char username[USER_NAME_MAX_SIZE+1], *pass = NULL, **ss; + struct passwd * pwd = NULL; + struct spwd * spwd = NULL; + int auth_fail_cnt = 0; + + if (f_flag && toys.optc != 1) + error_exit("-f requires username"); + + if (geteuid()) error_exit("not root"); + + if (!isatty(0) || !isatty(1) || !isatty(2)) error_exit("no tty"); + + openlog("login", LOG_PID | LOG_CONS, LOG_AUTH); + signal(SIGALRM, login_timeout_handler); + alarm(LOGIN_TIMEOUT); + + for (ss = forbid; *ss; ss++) unsetenv(*ss); + + while (1) { + tcflush(0, TCIFLUSH); + + username[USER_NAME_MAX_SIZE] = 0; + if (toys.optargs[0]) + strncpy(username, toys.optargs[0], USER_NAME_MAX_SIZE); + else { + read_user(username, USER_NAME_MAX_SIZE+1); + if (username[0] == 0) continue; + } + + pwd = getpwnam(username); + if (!pwd) goto query_pass; // Non-existing user + + if (pwd->pw_passwd[0] == '!' || pwd->pw_passwd[0] == '*') + goto query_pass; // Locked account + + if (f_flag) break; // Pre-authenticated + + if (!pwd->pw_passwd[0]) break; // Password-less account + + pass = pwd->pw_passwd; + if (pwd->pw_passwd[0] == 'x') { + spwd = getspnam (username); + if (spwd) pass = spwd->sp_pwdp; + } + +query_pass: + if (!verify_password(pass)) break; + + f_flag = 0; + syslog(LOG_WARNING, "invalid password for '%s' on %s %s %s", username, + ttyname(0), (h_flag)?"from":"", (h_flag)?TT.hostname:""); + + sleep(LOGIN_FAIL_TIMEOUT); + puts("Login incorrect"); + + if (++auth_fail_cnt == 3) + error_exit("Maximum number of tries exceeded (%d)\n", auth_fail_cnt); + + username[0] = 0; + pwd = NULL; + spwd = NULL; + } + + alarm(0); + + if (pwd->pw_uid) handle_nologin(); + + if (change_identity(pwd)) error_exit("Failed to change identity"); + + setup_environment(pwd, !p_flag); + + handle_motd(); + + syslog(LOG_INFO, "%s logged in on %s %s %s", pwd->pw_name, + ttyname(0), (h_flag)?"from":"", (h_flag)?TT.hostname:""); + + spawn_shell(pwd->pw_shell); +} diff -r 2d7c56913fda -r 2986aa63a021 toys/other/lsmod.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/toys/other/lsmod.c Sat Aug 25 14:25:22 2012 -0500 @@ -0,0 +1,42 @@ +/* vi: set sw=4 ts=4: + * + * lsmod.c - Show the status of modules in the kernel + * + * Copyright 2012 Elie De Brauwer + * + * Not in SUSv4. + +USE_LSMOD(NEWTOY(lsmod, NULL, TOYFLAG_BIN)) + +config LSMOD + bool "lsmod" + default y + help + usage: lsmod + + Display the currently loaded modules, their sizes and their + dependencies. +*/ + +#include "toys.h" + +void lsmod_main(void) +{ + char *modfile = "/proc/modules"; + FILE * file = xfopen(modfile, "r"); + + xprintf("%-23s Size Used by\n", "Module"); + + while (fgets(toybuf, sizeof(toybuf), file)) { + char *name = strtok(toybuf, " "), *size = strtok(NULL, " "), + *refcnt = strtok(NULL, " "), *users = strtok(NULL, " "); + + if(users) { + int len = strlen(users)-1; + if (users[len] == ',' || users[len] == '-') + users[len] = 0; + xprintf("%-19s %8s %s %s\n", name, size, refcnt, users); + } else perror_exit("bad %s", modfile); + } + fclose(file); +} diff -r 2d7c56913fda -r 2986aa63a021 toys/other/mdev.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/toys/other/mdev.c Sat Aug 25 14:25:22 2012 -0500 @@ -0,0 +1,213 @@ +/* vi:set ts=4: + * + * mdev - Mini udev for busybox + * + * Copyright 2005, 2008 Rob Landley + * Copyright 2005 Frank Sorenson + * + * Not in SUSv3. + +USE_MDEV(NEWTOY(mdev, "s", TOYFLAG_USR|TOYFLAG_BIN|TOYFLAG_UMASK)) + +config MDEV + bool "mdev" + default n + help + usage: mdev [-s] + + Create devices in /dev using information from /sys. + + -s Scan all entries in /sys to populate /dev. + +config MDEV_CONF + bool "Configuration file for mdev" + default y + depends on MDEV + help + The mdev config file (/etc/mdev.conf) contains lines that look like: + hd[a-z][0-9]* 0:3 660 + + Each line must contain three whitespace separated fields. The first + field is a regular expression matching one or more device names, and + the second and third fields are uid:gid and file permissions for + matching devies. +*/ + +#include "toys.h" +#include "lib/xregcomp.h" + +// todo, open() block devices to trigger partition scanning. + +// mknod in /dev based on a path like "/sys/block/hda/hda1" +static void make_device(char *path) +{ + char *device_name, *s, *temp; + int major, minor, type, len, fd; + int mode = 0660; + uid_t uid = 0; + gid_t gid = 0; + + // Try to read major/minor string + + temp = strrchr(path, '/'); + fd = open(path, O_RDONLY); + *temp=0; + temp = toybuf; + len = read(fd, temp, 64); + close(fd); + if (len<1) return; + temp[len] = 0; + + // Determine device name, type, major and minor + + device_name = strrchr(path, '/') + 1; + type = path[5]=='c' ? S_IFCHR : S_IFBLK; + major = minor = 0; + sscanf(temp, "%u:%u", &major, &minor); + + // If we have a config file, look up permissions for this device + + if (CFG_MDEV_CONF) { + char *conf, *pos, *end; + + // mmap the config file + if (-1!=(fd = open("/etc/mdev.conf", O_RDONLY))) { + len = fdlength(fd); + conf = mmap(NULL, len, PROT_READ, MAP_PRIVATE, fd, 0); + if (conf) { + int line = 0; + + // Loop through lines in mmaped file + for (pos = conf; pos-confpw_uid; + } + s++; + // parse GID + gid = strtoul(s,&s2,10); + if (end2!=s2) { + struct group *grp; + char *str = strndup(s, end2-s); + grp = getgrnam(str); + free(str); + if (!grp) goto end_line; + gid = grp->gr_gid; + } + break; + } + // mode + case 1: + { + mode = strtoul(pos, &pos, 8); + if (pos!=end2) goto end_line; + goto found_device; + } + } + pos=end2; + } +end_line: + // Did everything parse happily? + if (field && field!=3) error_exit("Bad line %d", line); + + // Next line + pos = ++end; + } +found_device: + munmap(conf, len); + } + close(fd); + } + } + + sprintf(temp, "/dev/%s", device_name); + if (mknod(temp, mode | type, makedev(major, minor)) && errno != EEXIST) + perror_exit("mknod %s failed", temp); + + if (CFG_MDEV_CONF) mode=chown(temp, uid, gid); +} + +static int callback(struct dirtree *node) +{ + // Entries in /sys/class/block aren't char devices, so skip 'em. (We'll + // get block devices out of /sys/block.) + if(!strcmp(node->name, "block")) return 0; + + // Does this directory have a "dev" entry in it? + // This is path based because the hotplug callbacks are + if (S_ISDIR(node->st.st_mode) || S_ISLNK(node->st.st_mode)) { + int len=4; + char *dev = dirtree_path(node, &len); + strcpy(dev+len, "/dev"); + if (!access(dev, R_OK)) make_device(dev); + free(dev); + } + + // Circa 2.6.25 the entries more than 2 deep are all either redundant + // (mouse#, event#) or unnamed (every usb_* entry is called "device"). + + return (node->parent && node->parent->parent) ? 0 : DIRTREE_RECURSE; +} + +void mdev_main(void) +{ + // Handle -s + + if (toys.optflags) { + dirtree_read("/sys/class", callback); + dirtree_read("/sys/block", callback); + } + + // hotplug support goes here +} diff -r 2d7c56913fda -r 2986aa63a021 toys/other/mke2fs.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/toys/other/mke2fs.c Sat Aug 25 14:25:22 2012 -0500 @@ -0,0 +1,662 @@ +/* vi: set ts=4: + * + * mke2fs.c - Create an ext2 filesystem image. + * + * Copyright 2006, 2007 Rob Landley + * + * Not in SUSv3. + +// Still to go: "E:jJ:L:m:O:" +USE_MKE2FS(NEWTOY(mke2fs, "<1>2g:Fnqm#N#i#b#", TOYFLAG_SBIN)) + +config MKE2FS + bool "mke2fs (unfinished and broken by dirtree changes)" + default n + help + usage: mke2fs [-Fnq] [-b ###] [-N|i ###] [-m ###] device + + Create an ext2 filesystem on a block device or filesystem image. + + -F Force to run on a mounted device + -n Don't write to device + -q Quiet (no output) + -b size Block size (1024, 2048, or 4096) + -N inodes Allocate this many inodes + -i bytes Allocate one inode for every XXX bytes of device + -m percent Reserve this percent of filesystem space for root user + +config MKE2FS_JOURNAL + bool "Journaling support (ext3)" + default n + depends on MKE2FS + help + usage: [-j] [-J size=###,device=XXX] + + -j Create journal (ext3) + -J Journal options + size: Number of blocks (1024-102400) + device: Specify an external journal + +config MKE2FS_GEN + bool "Generate (gene2fs)" + default n + depends on MKE2FS + help + usage: gene2fs [options] device filename + + The [options] are the same as mke2fs. + +config MKE2FS_LABEL + bool "Label support" + default n + depends on MKE2FS + help + usage: mke2fs [-L label] [-M path] [-o string] + + -L Volume label + -M Path to mount point + -o Created by + +config MKE2FS_EXTENDED + bool "Extended options" + default n + depends on MKE2FS + help + usage: mke2fs [-E stride=###] [-O option[,option]] + + -E stride= Set RAID stripe size (in blocks) + -O [opts] Specify fewer ext2 option flags (for old kernels) + All of these are on by default (as appropriate) + none Clear default options (all but journaling) + dir_index Use htree indexes for large directories + filetype Store file type info in directory entry + has_journal Set by -j + journal_dev Set by -J device=XXX + sparse_super Don't allocate huge numbers of redundant superblocks +*/ + +#include "toys.h" + +DEFINE_GLOBALS( + // Command line arguments. + long blocksize; + long bytes_per_inode; + long inodes; // Total inodes in filesystem. + long reserved_percent; // Integer precent of space to reserve for root. + char *gendir; // Where to read dirtree from. + + // Internal data. + struct dirtree *dt; // Tree of files to copy into the new filesystem. + unsigned treeblocks; // Blocks used by dt + unsigned treeinodes; // Inodes used by dt + + unsigned blocks; // Total blocks in the filesystem. + unsigned freeblocks; // Free blocks in the filesystem. + unsigned inodespg; // Inodes per group + unsigned groups; // Total number of block groups. + unsigned blockbits; // Bits per block. (Also blocks per group.) + + // For gene2fs + unsigned nextblock; // Next data block to allocate + unsigned nextgroup; // Next group we'll be allocating from + int fsfd; // File descriptor of filesystem (to output to). + + struct ext2_superblock sb; +) + +// Shortcut to our global data structure, since we use it so much. +#define TT this.mke2fs + +#define INODES_RESERVED 10 + +static uint32_t div_round_up(uint32_t a, uint32_t b) +{ + uint32_t c = a/b; + + if (a%b) c++; + return c; +} + +// Calculate data blocks plus index blocks needed to hold a file. + +static uint32_t file_blocks_used(uint64_t size, uint32_t *blocklist) +{ + uint32_t dblocks = (uint32_t)((size+(TT.blocksize-1))/TT.blocksize); + uint32_t idx=TT.blocksize/4, iblocks=0, diblocks=0, tiblocks=0; + + // Fill out index blocks in inode. + + if (blocklist) { + int i; + + // Direct index blocks + for (i=0; i<13 && i 13+idx) blocklist[13] = 13+idx; + // Doubly indirect index blocks + idx = 13 + idx + (idx*idx); + if (dblocks > idx) blocklist[14] = idx; + + return 0; + } + + // Account for direct, singly, doubly, and triply indirect index blocks + + if (dblocks > 12) { + iblocks = ((dblocks-13)/idx)+1; + if (iblocks > 1) { + diblocks = ((iblocks-2)/idx)+1; + if (diblocks > 1) + tiblocks = ((diblocks-2)/idx)+1; + } + } + + return dblocks + iblocks + diblocks + tiblocks; +} + +// Use the parent pointer to iterate through the tree non-recursively. +static struct dirtree *treenext(struct dirtree *this) +{ + while (this && !this->next) this = this->parent; + if (this) this = this->next; + + return this; +} + +// Recursively calculate the number of blocks used by each inode in the tree. +// Returns blocks used by this directory, assigns bytes used to *size. +// Writes total block count to TT.treeblocks and inode count to TT.treeinodes. + +static long check_treesize(struct dirtree *that, off_t *size) +{ + long blocks; + + while (that) { + *size += sizeof(struct ext2_dentry) + strlen(that->name); + + if (that->child) + that->st.st_blocks = check_treesize(that->child, &that->st.st_size); + else if (S_ISREG(that->st.st_mode)) { + that->st.st_blocks = file_blocks_used(that->st.st_size, 0); + TT.treeblocks += that->st.st_blocks; + } + that = that->next; + } + TT.treeblocks += blocks = file_blocks_used(*size, 0); + TT.treeinodes++; + + return blocks; +} + +// Calculate inode numbers and link counts. +// +// To do this right I need to copy the tree and sort it, but here's a really +// ugly n^2 way of dealing with the problem that doesn't scale well to large +// numbers of files (> 100,000) but can be done in very little code. +// This rewrites inode numbers to their final values, allocating depth first. + +static void check_treelinks(struct dirtree *tree) +{ + struct dirtree *current=tree, *that; + long inode = INODES_RESERVED; + + while (current) { + ++inode; + // Since we can't hardlink to directories, we know their link count. + if (S_ISDIR(current->st.st_mode)) current->st.st_nlink = 2; + else { + dev_t new = current->st.st_dev; + + if (!new) continue; + + // Look for other copies of current node + current->st.st_nlink = 0; + for (that = tree; that; that = treenext(that)) { + if (current->st.st_ino == that->st.st_ino && + current->st.st_dev == that->st.st_dev) + { + current->st.st_nlink++; + current->st.st_ino = inode; + } + } + } + current->st.st_ino = inode; + current = treenext(current); + } +} + +// According to http://www.opengroup.org/onlinepubs/9629399/apdxa.htm +// we should generate a uuid structure by reading a clock with 100 nanosecond +// precision, normalizing it to the start of the gregorian calendar in 1582, +// and looking up our eth0 mac address. +// +// On the other hand, we have 128 bits to come up with a unique identifier, of +// which 6 have a defined value. /dev/urandom it is. + +static void create_uuid(char *uuid) +{ + // Read 128 random bits + int fd = xopen("/dev/urandom", O_RDONLY); + xreadall(fd, uuid, 16); + close(fd); + + // Claim to be a DCE format UUID. + uuid[6] = (uuid[6] & 0x0F) | 0x40; + uuid[8] = (uuid[8] & 0x3F) | 0x80; + + // rfc2518 section 6.4.1 suggests if we're not using a macaddr, we should + // set bit 1 of the node ID, which is the mac multicast bit. This means we + // should never collide with anybody actually using a macaddr. + uuid[11] = uuid[11] | 128; +} + +// Calculate inodes per group from total inodes. +static uint32_t get_inodespg(uint32_t inodes) +{ + uint32_t temp; + + // Round up to fill complete inode blocks. + temp = (inodes + TT.groups - 1) / TT.groups; + inodes = TT.blocksize/sizeof(struct ext2_inode); + return ((temp + inodes - 1)/inodes)*inodes; +} + +// Fill out superblock and TT structures. + +static void init_superblock(struct ext2_superblock *sb) +{ + uint32_t temp; + + // Set log_block_size and log_frag_size. + + for (temp = 0; temp < 4; temp++) if (TT.blocksize == 1024<log_block_size = sb->log_frag_size = SWAP_LE32(temp); + + // Fill out blocks_count, r_blocks_count, first_data_block + + sb->blocks_count = SWAP_LE32(TT.blocks); + sb->free_blocks_count = SWAP_LE32(TT.freeblocks); + temp = (TT.blocks * (uint64_t)TT.reserved_percent) / 100; + sb->r_blocks_count = SWAP_LE32(temp); + + sb->first_data_block = SWAP_LE32(TT.blocksize == 1024 ? 1 : 0); + + // Set blocks_per_group and frags_per_group, which is the size of an + // allocation bitmap that fits in one block (I.E. how many bits per block)? + + sb->blocks_per_group = sb->frags_per_group = SWAP_LE32(TT.blockbits); + + // Set inodes_per_group and total inodes_count + sb->inodes_per_group = SWAP_LE32(TT.inodespg); + sb->inodes_count = SWAP_LE32(TT.inodespg * TT.groups); + + // Determine free inodes. + temp = TT.inodespg*TT.groups - INODES_RESERVED; + if (temp < TT.treeinodes) error_exit("Not enough inodes.\n"); + sb->free_inodes_count = SWAP_LE32(temp - TT.treeinodes); + + // Fill out the rest of the superblock. + sb->max_mnt_count=0xFFFF; + sb->wtime = sb->lastcheck = sb->mkfs_time = SWAP_LE32(time(NULL)); + sb->magic = SWAP_LE32(0xEF53); + sb->state = sb->errors = SWAP_LE16(1); + + sb->rev_level = SWAP_LE32(1); + sb->first_ino = SWAP_LE32(INODES_RESERVED+1); + sb->inode_size = SWAP_LE16(sizeof(struct ext2_inode)); + sb->feature_incompat = SWAP_LE32(EXT2_FEATURE_INCOMPAT_FILETYPE); + sb->feature_ro_compat = SWAP_LE32(EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER); + + create_uuid(sb->uuid); + + // TODO If we're called as mke3fs or mkfs.ext3, do a journal. + + //if (strchr(toys.which->name,'3')) + // sb->feature_compat |= SWAP_LE32(EXT3_FEATURE_COMPAT_HAS_JOURNAL); +} + +// Does this group contain a superblock backup (and group descriptor table)? +static int is_sb_group(uint32_t group) +{ + int i; + + // Superblock backups are on groups 0, 1, and powers of 3, 5, and 7. + if(!group || group==1) return 1; + for (i=3; i<9; i+=2) { + int j = i; + while (j sizeof(toybuf) ? sizeof(toybuf) : len; + xwrite(TT.fsfd, toybuf, out); + len -= out; + } + } +} + +// Fill out an inode structure from struct stat info in dirtree. +static void fill_inode(struct ext2_inode *in, struct dirtree *that) +{ + uint32_t fbu[15]; + int temp; + + file_blocks_used(that->st.st_size, fbu); + + // If that inode needs data blocks allocated to it. + if (that->st.st_size) { + int i, group = TT.nextblock/TT.blockbits; + + // TODO: teach this about indirect blocks. + for (i=0; i<15; i++) { + // If we just jumped into a new group, skip group overhead blocks. + while (group >= TT.nextgroup) + TT.nextblock += group_overhead(TT.nextgroup++); + } + } + // TODO : S_ISREG/DIR/CHR/BLK/FIFO/LNK/SOCK(m) + in->mode = SWAP_LE32(that->st.st_mode); + + in->uid = SWAP_LE16(that->st.st_uid & 0xFFFF); + in->uid_high = SWAP_LE16(that->st.st_uid >> 16); + in->gid = SWAP_LE16(that->st.st_gid & 0xFFFF); + in->gid_high = SWAP_LE16(that->st.st_gid >> 16); + in->size = SWAP_LE32(that->st.st_size & 0xFFFFFFFF); + + // Contortions to make the compiler not generate a warning for x>>32 + // when x is 32 bits. The optimizer should clean this up. + if (sizeof(that->st.st_size) > 4) temp = 32; + else temp = 0; + if (temp) in->dir_acl = SWAP_LE32(that->st.st_size >> temp); + + in->atime = SWAP_LE32(that->st.st_atime); + in->ctime = SWAP_LE32(that->st.st_ctime); + in->mtime = SWAP_LE32(that->st.st_mtime); + + in->links_count = SWAP_LE16(that->st.st_nlink); + in->blocks = SWAP_LE32(that->st.st_blocks); + // in->faddr +} + +// Works like an archiver. +// The first argument is the name of the file to create. If it already +// exists, that size will be used. + +void mke2fs_main(void) +{ + int i, temp; + off_t length; + uint32_t usedblocks, usedinodes, dtiblk, dtbblk; + struct dirtree *dti, *dtb; + + // Handle command line arguments. + + if (toys.optargs[1]) { + sscanf(toys.optargs[1], "%u", &TT.blocks); + temp = O_RDWR|O_CREAT; + } else temp = O_RDWR; + if (!TT.reserved_percent) TT.reserved_percent = 5; + + // TODO: Check if filesystem is mounted here + + // For mke?fs, open file. For gene?fs, create file. + TT.fsfd = xcreate(*toys.optargs, temp, 0777); + + // Determine appropriate block size and block count from file length. + // (If no length, default to 4k. They can override it on the cmdline.) + + length = fdlength(TT.fsfd); + if (!TT.blocksize) TT.blocksize = (length && length < 1<<29) ? 1024 : 4096; + TT.blockbits = 8*TT.blocksize; + if (!TT.blocks) TT.blocks = length/TT.blocksize; + + // Collect gene2fs list or lost+found, calculate requirements. + + if (TT.gendir) { + strncpy(toybuf, TT.gendir, sizeof(toybuf)); + dti = dirtree_read(toybuf, NULL, NULL); + } else { + dti = xzalloc(sizeof(struct dirtree)+11); + strcpy(dti->name, "lost+found"); + dti->st.st_mode = S_IFDIR|0755; + dti->st.st_ctime = dti->st.st_mtime = time(NULL); + } + + // Add root directory inode. This is iterated through for when finding + // blocks, but not when finding inodes. The tree's parent pointers don't + // point back into this. + + dtb = xzalloc(sizeof(struct dirtree)+1); + dtb->st.st_mode = S_IFDIR|0755; + dtb->st.st_ctime = dtb->st.st_mtime = time(NULL); + dtb->child = dti; + + // Figure out how much space is used by preset files + length = check_treesize(dtb, &(dtb->st.st_size)); + check_treelinks(dtb); + + // Figure out how many total inodes we need. + + if (!TT.inodes) { + if (!TT.bytes_per_inode) TT.bytes_per_inode = 8192; + TT.inodes = (TT.blocks * (uint64_t)TT.blocksize) / TT.bytes_per_inode; + } + + // If we're generating a filesystem and have no idea how many blocks it + // needs, start with a minimal guess, find the overhead of that many + // groups, and loop until this is enough groups to store this many blocks. + if (!TT.blocks) TT.groups = (TT.treeblocks/TT.blockbits)+1; + else TT.groups = div_round_up(TT.blocks, TT.blockbits); + + for (;;) { + temp = TT.treeblocks; + + for (i = 0; i TT.blocks) end = TT.blocks & (TT.blockbits-1); + + // Blocks used by inode table + itable = (TT.inodespg*sizeof(struct ext2_inode))/TT.blocksize; + + // If a superblock goes here, write it out. + start = group_superblock_overhead(i); + if (start) { + struct ext2_group *bg = (struct ext2_group *)toybuf; + int treeblocks = TT.treeblocks, treeinodes = TT.treeinodes; + + TT.sb.block_group_nr = SWAP_LE16(i); + + // Write superblock and pad it up to block size + xwrite(TT.fsfd, &TT.sb, sizeof(struct ext2_superblock)); + temp = TT.blocksize - sizeof(struct ext2_superblock); + if (!i && TT.blocksize > 1024) temp -= 1024; + memset(toybuf, 0, TT.blocksize); + xwrite(TT.fsfd, toybuf, temp); + + // Loop through groups to write group descriptor table. + for(j=0; j treeinodes) { + treeinodes -= temp; + temp = 0; + } else { + temp -= treeinodes; + treeinodes = 0; + } + bg[slot].free_inodes_count = SWAP_LE16(temp); + + // How many free blocks in this group? + temp = TT.inodespg/(TT.blocksize/sizeof(struct ext2_inode)) + 2; + temp = end-used-temp; + if (temp > treeblocks) { + treeblocks -= temp; + temp = 0; + } else { + temp -= treeblocks; + treeblocks = 0; + } + bg[slot].free_blocks_count = SWAP_LE32(temp); + + // Fill out rest of group structure + used += j*TT.blockbits; + bg[slot].block_bitmap = SWAP_LE32(used++); + bg[slot].inode_bitmap = SWAP_LE32(used++); + bg[slot].inode_table = SWAP_LE32(used); + bg[slot].used_dirs_count = 0; // (TODO) + } + xwrite(TT.fsfd, bg, TT.blocksize); + } + + // Now write out stuff that every block group has. + + // Write block usage bitmap + + start += 2 + itable; + memset(toybuf, 0, TT.blocksize); + bits_set(toybuf, 0, start); + bits_set(toybuf, end, TT.blockbits-end); + temp = TT.treeblocks - usedblocks; + if (temp) { + if (end-start > temp) temp = end-start; + bits_set(toybuf, start, temp); + } + xwrite(TT.fsfd, toybuf, TT.blocksize); + + // Write inode bitmap + memset(toybuf, 0, TT.blocksize); + j = 0; + if (!i) bits_set(toybuf, 0, j = INODES_RESERVED); + bits_set(toybuf, TT.inodespg, slot = TT.blockbits-TT.inodespg); + temp = TT.treeinodes - usedinodes; + if (temp) { + if (slot-j > temp) temp = slot-j; + bits_set(toybuf, j, temp); + } + xwrite(TT.fsfd, toybuf, TT.blocksize); + + // Write inode table for this group (TODO) + for (j = 0; j + * + * Not in SUSv4. + +USE_MKSWAP(NEWTOY(mkswap, "<1>1", TOYFLAG_SBIN)) + +config MKSWAP + bool "mkswap" + default y + help + usage: mkswap DEVICE + + Sets up a Linux swap area on a device or file. +*/ + +#include "toys.h" + +void mkswap_main(void) +{ + int fd = xopen(*toys.optargs, O_RDWR), pagesize = sysconf(_SC_PAGE_SIZE); + off_t len = fdlength(fd); + unsigned int pages = (len/pagesize)-1, *swap = (unsigned int *)toybuf; + + // Write header. Note that older kernel versions checked signature + // on disk (not in cache) during swapon, so sync after writing. + + swap[0] = 1; + swap[1] = pages; + xlseek(fd, 1024, SEEK_SET); + xwrite(fd, swap, 129*sizeof(unsigned int)); + xlseek(fd, pagesize-10, SEEK_SET); + xwrite(fd, "SWAPSPACE2", 10); + fsync(fd); + + if (CFG_TOYBOX_FREE) close(fd); + + printf("Swapspace size: %luk\n", pages*(unsigned long)(pagesize/1024)); +} diff -r 2d7c56913fda -r 2986aa63a021 toys/other/modinfo.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/toys/other/modinfo.c Sat Aug 25 14:25:22 2012 -0500 @@ -0,0 +1,103 @@ +/* vi: set sw=4 ts=4: + * + * modinfo.c - Display module info + * + * Copyright 2012 Andre Renaud + * + +USE_MODINFO(NEWTOY(modinfo, "<1F:0", TOYFLAG_BIN)) + +config MODINFO + bool "modinfo" + default y + help + usage: modinfo [-0] [-F field] [modulename...] +*/ + +#include "toys.h" + +#define FLAG_0 (1 << 0) + +DEFINE_GLOBALS( + char *field; +) +#define TT this.modinfo + +static const char *modinfo_tags[] = { + "alias", "license", "description", "author", "vermagic", + "srcversion", "intree", "parm", "depends", +}; + +static void output_field(const char *field, const char *value) +{ + int len; + + if (TT.field && strcmp(TT.field, field) != 0) + return; + + len = strlen(field); + + if (TT.field) + xprintf("%s", value); + else + xprintf("%s:%*s%s", + field, 15 - len, "", value); + if (toys.optflags & FLAG_0) + xwrite(fileno(stdout), "\0", 1); + else + xputs(""); +} + + +static void modinfo_file(struct dirtree *dir) +{ + int fd, len, i; + char *buf, *pos; + char *full_name; + + full_name = dirtree_path(dir, NULL); + + output_field("filename", full_name); + fd = xopen(full_name, O_RDONLY); + len = fdlength(fd); + buf = xmalloc(len); + xreadall(fd, buf, len); + + for (pos = buf; pos < buf + len + 10; pos++) { + if (*pos) + continue; + + for (i = 0; i < sizeof(modinfo_tags) / sizeof(modinfo_tags[0]); i++) { + const char *str = modinfo_tags[i]; + int len = strlen(str); + if (strncmp(pos + 1, str, len) == 0 && pos[len + 1] == '=') + output_field(str, &pos[len + 2]); + } + } + + free(full_name); + free(buf); + close(fd); +} + +static int check_module(struct dirtree *new) +{ + if (S_ISREG(new->st.st_mode)) { + char **s; + for (s = toys.optargs; *s; s++) { + int len = strlen(*s); + if (!strncmp(*s, new->name, len) && !strcmp(new->name+len, ".ko")) + modinfo_file(new); + } + } + + return dirtree_notdotdot(new); +} + +void modinfo_main(void) +{ + struct utsname uts; + if (uname(&uts) < 0) perror_exit("bad uname"); + sprintf(toybuf, "/lib/modules/%s", uts.release); + dirtree_read(toybuf, check_module); +} diff -r 2d7c56913fda -r 2986aa63a021 toys/other/mountpoint.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/toys/other/mountpoint.c Sat Aug 25 14:25:22 2012 -0500 @@ -0,0 +1,56 @@ +/* vi: set sw=4 ts=4: + * + * mountpoint.c - Check if a directory is a mountpoint. + * + * Copyright 2012 Elie De Brauwer + * + * Not in SUSv4. + +USE_MOUNTPOINT(NEWTOY(mountpoint, "<1qdx", TOYFLAG_BIN)) + +config MOUNTPOINT + bool "mountpoint" + default y + help + usage: mountpoint [-q] [-d] directory + mountpoint [-q] [-x] device + -q Be quiet, return zero if directory is a mountpoint + -d Print major/minor device number of the directory + -x Print major/minor device number of the block device +*/ + +#include "toys.h" + +void mountpoint_main(void) +{ + struct stat st1, st2; + int res = 0; + int quiet = toys.optflags & 0x4; + toys.exitval = 1; // be pessimistic + strncpy(toybuf, toys.optargs[0], sizeof(toybuf)); + if (((toys.optflags & 0x1) && lstat(toybuf, &st1)) || stat(toybuf, &st1)) + perror_exit("%s", toybuf); + + if (toys.optflags & 0x1){ + if (S_ISBLK(st1.st_mode)) { + if (!quiet) printf("%u:%u\n", major(st1.st_rdev), minor(st1.st_rdev)); + toys.exitval = 0; + return; + } + if (!quiet) printf("%s: not a block device\n", toybuf); + return; + } + + if(!S_ISDIR(st1.st_mode)){ + if (!quiet) printf("%s: not a directory\n", toybuf); + return; + } + strncat(toybuf, "/..", sizeof(toybuf)); + stat(toybuf, &st2); + res = (st1.st_dev != st2.st_dev) || + (st1.st_dev == st2.st_dev && st1.st_ino == st2.st_ino); + if (!quiet) printf("%s is %sa mountpoint\n", toys.optargs[0], res ? "" : "not "); + if (toys.optflags & 0x2) + printf("%u:%u\n", major(st1.st_dev), minor(st1.st_dev)); + toys.exitval = res ? 0 : 1; +} diff -r 2d7c56913fda -r 2986aa63a021 toys/other/netcat.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/toys/other/netcat.c Sat Aug 25 14:25:22 2012 -0500 @@ -0,0 +1,232 @@ +/* vi: set sw=4 ts=4: + * + * nc: mini-netcat - Forward stdin/stdout to a file or network connection. + * + * Copyright 2007 Rob Landley + * + * Not in SUSv3. + +USE_NETCAT(OLDTOY(nc, netcat, USE_NETCAT_LISTEN("tl^L^")"w#p#s:q#f:", TOYFLAG_BIN)) +USE_NETCAT(NEWTOY(netcat, USE_NETCAT_LISTEN("tl^L^")"w#p#s:q#f:", TOYFLAG_BIN)) + +config NETCAT + bool "netcat" + default y + help + usage: netcat [-wpq #] [-s addr] {IPADDR PORTNUM|-f FILENAME|-let} [-e COMMAND] + + -w SECONDS timeout for connection + -p local port number + -s local ipv4 address + -q SECONDS quit this many seconds after EOF on stdin. + -f use FILENAME (ala /dev/ttyS0) instead of network + + Use "stty 115200 -F /dev/ttyS0 && stty raw -echo -ctlecho" with + netcat -f to connect to a serial port. + + +config NETCAT_LISTEN + bool "netcat sever options (-let)" + default y + depends on NETCAT + help + -t allocate tty (must come before -l or -L) + -l listen for one incoming connection. + -L listen for multiple incoming connections (server mode). + + Any additional command line arguments after -l or -L are executed + to handle each incoming connection. If none, the connection is + forwarded to stdin/stdout. + + For a quick-and-dirty server, try something like: + netcat -s 127.0.0.1 -p 1234 -tL /bin/bash -l +*/ + +#include "toys.h" +#include "toynet.h" + +DEFINE_GLOBALS( + char *filename; // -f read from filename instead of network + long quit_delay; // -q Exit after EOF from stdin after # seconds. + char *source_address; // -s Bind to a specific source address. + long port; // -p Bind to a specific source port. + long wait; // -w Wait # seconds for a connection. +) + +#define TT this.netcat + +#define FLAG_f 1 +#define FLAG_L 32 +#define FLAG_l 64 +#define FLAG_t 128 + +static void timeout(int signum) +{ + if (TT.wait) error_exit("Timeout"); + exit(0); +} + +static void set_alarm(int seconds) +{ + signal(SIGALRM, seconds ? timeout : SIG_DFL); + alarm(seconds); +} + +// Translate x.x.x.x numeric IPv4 address, or else DNS lookup an IPv4 name. +static void lookup_name(char *name, uint32_t *result) +{ + struct hostent *hostbyname; + + hostbyname = gethostbyname(name); + if (!hostbyname) error_exit("no host '%s'", name); + *result = *(uint32_t *)*hostbyname->h_addr_list; +} + +// Worry about a fancy lookup later. +static void lookup_port(char *str, uint16_t *port) +{ + *port = SWAP_BE16(atoi(str)); +} + +void netcat_main(void) +{ + int sockfd=-1, pollcount=2; + struct pollfd pollfds[2]; + + memset(pollfds, 0, 2*sizeof(struct pollfd)); + pollfds[0].events = pollfds[1].events = POLLIN; + set_alarm(TT.wait); + + // The argument parsing logic can't make "<2" conditional on other + // arguments like -f and -l, so we do it by hand here. + if (toys.optflags&FLAG_f) { + if (toys.optc) toys.exithelp++; + } else if (!(toys.optflags&(FLAG_l|FLAG_L)) && toys.optc!=2) toys.exithelp++; + + if (toys.exithelp) error_exit("Argument count wrong"); + + if (TT.filename) pollfds[0].fd = xopen(TT.filename, O_RDWR); + else { + int temp; + struct sockaddr_in address; + + // Setup socket + sockfd = socket(AF_INET, SOCK_STREAM, 0); + if (-1 == sockfd) perror_exit("socket"); + fcntl(sockfd, F_SETFD, FD_CLOEXEC); + temp = 1; + setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &temp, sizeof(temp)); + memset(&address, 0, sizeof(address)); + address.sin_family = AF_INET; + if (TT.source_address || TT.port) { + address.sin_port = SWAP_BE16(TT.port); + if (TT.source_address) + lookup_name(TT.source_address, (uint32_t *)&address.sin_addr); + if (bind(sockfd, (struct sockaddr *)&address, sizeof(address))) + perror_exit("bind"); + } + + // Dial out + + if (!CFG_NETCAT_LISTEN || !(toys.optflags&(FLAG_L|FLAG_l))) { + // Figure out where to dial out to. + lookup_name(*toys.optargs, (uint32_t *)&address.sin_addr); + lookup_port(toys.optargs[1], &address.sin_port); + temp = connect(sockfd, (struct sockaddr *)&address, sizeof(address)); + if (temp<0) perror_exit("connect"); + pollfds[0].fd = sockfd; + + // Listen for incoming connections + + } else { + socklen_t len = sizeof(address); + + if (listen(sockfd, 5)) error_exit("listen"); + if (!TT.port) { + getsockname(sockfd, (struct sockaddr *)&address, &len); + printf("%d\n", SWAP_BE16(address.sin_port)); + fflush(stdout); + } + // Do we need to return immediately because -l has arguments? + + if ((toys.optflags&FLAG_l) && toys.optc) { + if (fork()) goto cleanup; + close(0); + close(1); + close(2); + } + + for (;;) { + pid_t child = 0; + + // For -l, call accept from the _new_ thread. + + pollfds[0].fd = accept(sockfd, (struct sockaddr *)&address, + &len); + if (pollfds[0].fd<0) perror_exit("accept"); + + // Do we need a tty? + + if (toys.optflags&FLAG_t) + child = forkpty(&(pollfds[1].fd), NULL, NULL, NULL); + + // Do we need to fork and/or redirect for exec? + + else { + if (toys.optflags&FLAG_L) child = fork(); + if (!child && toys.optc) { + int fd = pollfds[0].fd; + + if (!temp) close(sockfd); + dup2(fd, 0); + dup2(fd, 1); + dup2(fd, 2); + if (fd>2) close(fd); + } + } + + if (child<0) error_msg("Fork failed\n"); + if (child<1) break; + close(pollfds[0].fd); + } + } + } + + // We have a connection. Disarm timeout. + // (Does not play well with -L, but what _should_ that do?) + set_alarm(0); + + if (CFG_NETCAT_LISTEN && (toys.optflags&(FLAG_L|FLAG_l) && toys.optc)) { + execvp(*toys.optargs, toys.optargs); + error_exit("Exec failed"); + } + + // Poll loop copying stdin->socket and socket->stdout. + for (;;) { + int i; + + if (0>poll(pollfds, pollcount, -1)) perror_exit("poll"); + + for (i=0; i. + * + * Not in SUSv3. + +USE_ONEIT(NEWTOY(oneit, "^<1c:p", TOYFLAG_SBIN)) + +config ONEIT + bool "oneit" + default y + help + usage: oneit [-p] [-c /dev/tty0] command [...] + + A simple init program that runs a single supplied command line with a + controlling tty (so CTRL-C can kill it). + + -p Power off instead of rebooting when command exits. + -c Which console device to use. + + The oneit command runs the supplied command line as a child process + (because PID 1 has signals blocked), attached to /dev/tty0, in its + own session. Then oneit reaps zombies until the child exits, at + which point it reboots (or with -p, powers off) the system. +*/ + +#include "toys.h" +#include + +DEFINE_GLOBALS( + char *console; +) + +#define TT this.oneit + +// The minimum amount of work necessary to get ctrl-c and such to work is: +// +// - Fork a child (PID 1 is special: can't exit, has various signals blocked). +// - Do a setsid() (so we have our own session). +// - In the child, attach stdio to /dev/tty0 (/dev/console is special) +// - Exec the rest of the command line. +// +// PID 1 then reaps zombies until the child process it spawned exits, at which +// point it calls sync() and reboot(). I could stick a kill -1 in there. + + +void oneit_main(void) +{ + int i; + pid_t pid; + + // Create a new child process. + pid = vfork(); + if (pid) { + + // pid 1 just reaps zombies until it gets its child, then halts the system. + while (pid!=wait(&i)); + sync(); + + // PID 1 can't call reboot() because it kills the task that calls it, + // which causes the kernel to panic before the actual reboot happens. + if (!vfork()) reboot((toys.optflags&1) ? RB_POWER_OFF : RB_AUTOBOOT); + sleep(5); + _exit(1); + } + + // Redirect stdio to /dev/tty0, with new session ID, so ctrl-c works. + setsid(); + for (i=0; i<3; i++) { + close(i); + xopen(TT.console ? TT.console : "/dev/tty0",O_RDWR); + } + + // Can't xexec() here, because we vforked so we don't want to error_exit(). + toy_exec(toys.optargs); + execvp(*toys.optargs, toys.optargs); + _exit(127); +} diff -r 2d7c56913fda -r 2986aa63a021 toys/other/printenv.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/toys/other/printenv.c Sat Aug 25 14:25:22 2012 -0500 @@ -0,0 +1,47 @@ +/* vi: set sw=4 ts=4: + * + * printenv.c - Print environment variables. + * + * Copyright 2012 Georgi Chorbadzhiyski + * + +USE_PRINTENV(NEWTOY(printenv, "0(null)", TOYFLAG_USR|TOYFLAG_BIN)) + +config PRINTENV + bool "printenv" + default y + help + usage: printenv [-0] [env_var...] + + Print environment variables. + + -0 Use \0 as delimiter instead of \n +*/ + +#include "toys.h" + +extern char **environ; + +void printenv_main(void) +{ + char **env, **var = toys.optargs; + char delim = '\n'; + + if (toys.optflags) delim = 0; + + do { + int catch = 0, len = *var ? strlen(*var) : 0; + + for (env = environ; *env; env++) { + char *out = *env; + if (*var) { + if (!strncmp(out, *var, len) && out[len] == '=') + out += len +1; + else continue; + } + xprintf("%s%c", out, delim); + catch++; + } + if (*var && !catch) toys.exitval = 1; + } while (*var && *(++var)); +} diff -r 2d7c56913fda -r 2986aa63a021 toys/other/readlink.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/toys/other/readlink.c Sat Aug 25 14:25:22 2012 -0500 @@ -0,0 +1,45 @@ +/* vi: set sw=4 ts=4: + * + * readlink.c - Return string representation of a symbolic link. + * + * Copyright 2007 Rob Landley + * + * Not in SUSv3. + +USE_READLINK(NEWTOY(readlink, "<1f", TOYFLAG_BIN)) + +config READLINK + bool "readlink" + default n + help + usage: readlink + + Show what a symbolic link points to. + +config READLINK_F + bool "readlink -f" + default n + depends on READLINK + help + usage: readlink [-f] + + -f Show full cannonical path, with no symlinks in it. Returns + nonzero if nothing could currently exist at this location. +*/ + +#include "toys.h" + +void readlink_main(void) +{ + char *s; + + // Calculating full cannonical path? + + if (CFG_READLINK_F && toys.optflags) s = xrealpath(*toys.optargs); + else s = xreadlink(*toys.optargs); + + if (s) { + xputs(s); + if (CFG_TOYBOX_FREE) free(s); + } else toys.exitval = 1; +} diff -r 2d7c56913fda -r 2986aa63a021 toys/other/realpath.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/toys/other/realpath.c Sat Aug 25 14:25:22 2012 -0500 @@ -0,0 +1,31 @@ +/* vi: set sw=4 ts=4: + * + * realpath.c - Return the canonical version of a pathname + * + * Copyright 2012 Andre Renaud + * + * Not in SUSv4. + +USE_REALPATH(NEWTOY(realpath, "<1", TOYFLAG_USR|TOYFLAG_BIN)) + +config REALPATH + bool "realpath" + default y + help + usage: realpath FILE... + + Display the canonical absolute pathname +*/ + +#include "toys.h" + +void realpath_main(void) +{ + char **s = toys.optargs; + for (s = toys.optargs; *s; s++) { + if (!realpath(*s, toybuf)) { + perror_msg("cannot access '%s'", *s); + toys.exitval = 1; + } else xputs(toybuf); + } +} diff -r 2d7c56913fda -r 2986aa63a021 toys/other/rmmod.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/toys/other/rmmod.c Sat Aug 25 14:25:22 2012 -0500 @@ -0,0 +1,51 @@ +/* vi: set sw=4 ts=4: + * + * rmmod.c - Remove a module from the Linux kernel. + * + * Copyright 2012 Elie De Brauwer + * + * Not in SUSv4. + +USE_RMMOD(NEWTOY(rmmod, "<1wf", TOYFLAG_BIN|TOYFLAG_NEEDROOT)) + +config RMMOD + bool "rmmod" + default y + help + usage: rmmod [-wf] [MODULE] + + Unload the module named MODULE from the Linux kernel. + -f Force unload of a module + -w Wait until the module is no longer used. + +*/ + +#include "toys.h" + +#include +#define delete_module(mod, flags) syscall(__NR_delete_module, mod, flags) + +void rmmod_main(void) +{ + unsigned int flags = O_NONBLOCK|O_EXCL; + char * mod_name; + int len; + + // Basename + mod_name = strrchr(toys.optargs[0],'/'); + if (mod_name) + mod_name++; + else + mod_name = toys.optargs[0]; + + // Remove .ko if present + len = strlen(mod_name); + if (len > 3 && !strcmp(&mod_name[len-3], ".ko" )) + mod_name[len-3] = 0; + + if (toys.optflags & 1) flags |= O_TRUNC; + if (toys.optflags & 2) flags &= ~O_NONBLOCK; + + if (delete_module(mod_name, flags)) + perror_exit("failed to unload %s", mod_name); +} diff -r 2d7c56913fda -r 2986aa63a021 toys/other/setsid.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/toys/other/setsid.c Sat Aug 25 14:25:22 2012 -0500 @@ -0,0 +1,33 @@ +/* vi: set sw=4 ts=4: + * + * setsid.c - Run program in a new session ID. + * + * Copyright 2006 Rob Landley + * + * Not in SUSv4. + +USE_SETSID(NEWTOY(setsid, "^<1t", TOYFLAG_USR|TOYFLAG_BIN)) + +config SETSID + bool "setsid" + default y + help + usage: setsid [-t] command [args...] + + Run process in a new session. + + -t Grab tty (become foreground process, receiving keyboard signals) +*/ + +#include "toys.h" + +void setsid_main(void) +{ + while (setsid()<0) + if (vfork()) _exit(0); + if (toys.optflags) { + setpgid(0,0); + tcsetpgrp(0, getpid()); + } + xexec(toys.optargs); +} diff -r 2d7c56913fda -r 2986aa63a021 toys/other/sha1sum.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/toys/other/sha1sum.c Sat Aug 25 14:25:22 2012 -0500 @@ -0,0 +1,185 @@ +/* vi: set sw=4 ts=4: + * + * sha1sum.c - Calculate sha1 cryptographic hash for input. + * + * Copyright 2007 Rob Landley + * + * Based on the public domain SHA-1 in C by Steve Reid + * from http://www.mirrors.wiretapped.net/security/cryptography/hashes/sha1/ + * + * Not in SUSv3. + +USE_SHA1SUM(NEWTOY(sha1sum, NULL, TOYFLAG_USR|TOYFLAG_BIN)) + +config SHA1SUM + bool "sha1sum" + default y + help + usage: sha1sum [file...] + + Calculate sha1 hash of files (or stdin). +*/ + +#include + +struct sha1 { + uint32_t state[5]; + uint32_t oldstate[5]; + uint64_t count; + union { + unsigned char c[64]; + uint32_t i[16]; + } buffer; +}; + +static void sha1_init(struct sha1 *this); +static void sha1_transform(struct sha1 *this); +static void sha1_update(struct sha1 *this, char *data, unsigned int len); +static void sha1_final(struct sha1 *this, char digest[20]); + +#define rol(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits)))) + +// blk0() and blk() perform the initial expand. +// The idea of expanding during the round function comes from SSLeay +#if 1 +#define blk0(i) (block[i] = (rol(block[i],24)&0xFF00FF00) \ + |(rol(block[i],8)&0x00FF00FF)) +#else // big endian? +#define blk0(i) block[i] +#endif +#define blk(i) (block[i&15] = rol(block[(i+13)&15]^block[(i+8)&15] \ + ^block[(i+2)&15]^block[i&15],1)) + +static const uint32_t rconsts[]={0x5A827999,0x6ED9EBA1,0x8F1BBCDC,0xCA62C1D6}; + +// Hash a single 512-bit block. This is the core of the algorithm. + +static void sha1_transform(struct sha1 *this) +{ + int i, j, k, count; + uint32_t *block = this->buffer.i; + uint32_t *rot[5], *temp; + + // Copy context->state[] to working vars + for (i=0; i<5; i++) { + this->oldstate[i] = this->state[i]; + rot[i] = this->state + i; + } + // 4 rounds of 20 operations each. + for (i=count=0; i<4; i++) { + for (j=0; j<20; j++) { + uint32_t work; + + work = *rot[2] ^ *rot[3]; + if (!i) work = (work & *rot[1]) ^ *rot[3]; + else { + if (i==2) + work = ((*rot[1]|*rot[2])&*rot[3])|(*rot[1]&*rot[2]); + else work ^= *rot[1]; + } + if (!i && j<16) work += blk0(count); + else work += blk(count); + *rot[4] += work + rol(*rot[0],5) + rconsts[i]; + *rot[1] = rol(*rot[1],30); + + // Rotate by one for next time. + temp = rot[4]; + for (k=4; k; k--) rot[k] = rot[k-1]; + *rot = temp; + count++; + } + } + // Add the previous values of state[] + for (i=0; i<5; i++) this->state[i] += this->oldstate[i]; +} + + +// Initialize a struct sha1. + +static void sha1_init(struct sha1 *this) +{ + /* SHA1 initialization constants */ + this->state[0] = 0x67452301; + this->state[1] = 0xEFCDAB89; + this->state[2] = 0x98BADCFE; + this->state[3] = 0x10325476; + this->state[4] = 0xC3D2E1F0; + this->count = 0; +} + +// Fill the 64-byte working buffer and call sha1_transform() when full. + +void sha1_update(struct sha1 *this, char *data, unsigned int len) +{ + unsigned int i, j; + + j = this->count & 63; + this->count += len; + + // Enough data to process a frame? + if ((j + len) > 63) { + i = 64-j; + memcpy(this->buffer.c + j, data, i); + sha1_transform(this); + for ( ; i + 63 < len; i += 64) { + memcpy(this->buffer.c, data + i, 64); + sha1_transform(this); + } + j = 0; + } else i = 0; + // Grab remaining chunk + memcpy(this->buffer.c + j, data + i, len - i); +} + +// Add padding and return the message digest. + +void sha1_final(struct sha1 *this, char digest[20]) +{ + uint64_t count = this->count << 3; + unsigned int i; + char buf; + + // End the message by appending a "1" bit to the data, ending with the + // message size (in bits, big endian), and adding enough zero bits in + // between to pad to the end of the next 64-byte frame. + // + // Since our input up to now has been in whole bytes, we can deal with + // bytes here too. + + buf = 0x80; + do { + sha1_update(this, &buf, 1); + buf = 0; + } while ((this->count & 63) != 56); + for (i = 0; i < 8; i++) + this->buffer.c[56+i] = count >> (8*(7-i)); + sha1_transform(this); + + for (i = 0; i < 20; i++) + digest[i] = this->state[i>>2] >> ((3-(i & 3)) * 8); + // Wipe variables. Cryptogropher paranoia. + memset(this, 0, sizeof(struct sha1)); +} + +// Callback for loopfiles() + +static void do_sha1(int fd, char *name) +{ + struct sha1 this; + int len; + + sha1_init(&this); + for (;;) { + len = read(fd, toybuf, sizeof(toybuf)); + if (len<1) break; + sha1_update(&this, toybuf, len); + } + sha1_final(&this, toybuf); + for (len = 0; len < 20; len++) printf("%02x", toybuf[len]); + printf(" %s\n", name); +} + +void sha1sum_main(void) +{ + loopfiles(toys.optargs, do_sha1); +} diff -r 2d7c56913fda -r 2986aa63a021 toys/other/swapoff.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/toys/other/swapoff.c Sat Aug 25 14:25:22 2012 -0500 @@ -0,0 +1,26 @@ +/* vi: set sw=4 ts=4: + * + * swapoff.c - Disable region for swapping + * + * Copyright 2012 Elie De Brauwer + * + * Not in SUSv4. + +USE_SWAPOFF(NEWTOY(swapoff, "<1>1", TOYFLAG_BIN|TOYFLAG_NEEDROOT)) + +config SWAPOFF + bool "swapoff" + default y + help + usage: swapoff swapregion + + Disable swapping on a given swapregion. +*/ + +#include "toys.h" + +void swapoff_main(void) +{ + if (swapoff(toys.optargs[0])) + perror_exit("failed to remove swaparea"); +} diff -r 2d7c56913fda -r 2986aa63a021 toys/other/swapon.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/toys/other/swapon.c Sat Aug 25 14:25:22 2012 -0500 @@ -0,0 +1,37 @@ +/* vi: set sw=4 ts=4: + * + * swapon.c - Enable region for swapping + * + * Copyright 2012 Elie De Brauwer + * + * Not in SUSv4. + +USE_SWAPON(NEWTOY(swapon, "<1>1p#<0>32767", TOYFLAG_BIN|TOYFLAG_NEEDROOT)) + +config SWAPON + bool "swapon" + default y + help + usage: swapon [-p priority] filename + + Enable swapping on a given device/file. +*/ + +#include "toys.h" + +DEFINE_GLOBALS( + long priority; +) + +#define TT this.swapon + +void swapon_main(void) +{ + int flags = 0; + + if (toys.optflags & 1) + flags = SWAP_FLAG_PREFER | (TT.priority << SWAP_FLAG_PRIO_SHIFT); + + if (swapon(*toys.optargs, flags)) + perror_exit("Couldn't swapon '%s'", *toys.optargs); +} diff -r 2d7c56913fda -r 2986aa63a021 toys/other/tac.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/toys/other/tac.c Sat Aug 25 14:25:22 2012 -0500 @@ -0,0 +1,55 @@ +/* vi: set sw=4 ts=4: + * + * tac.c - output lines in reverse order + * + * Copyright 2012 Rob Landley + * + * Not in SUSv4. + +USE_TAC(NEWTOY(tac, NULL, TOYFLAG_USR|TOYFLAG_BIN)) + +config TAC + bool "tac" + default y + help + usage: tac [FILE...] + + Output lines in reverse order. +*/ + +#include "toys.h" + +void do_tac(int fd, char *name) +{ + struct arg_list *list = NULL; + char *c; + + // Read in lines + for (;;) { + struct arg_list *temp; + int len; + + if (!(c = get_line(fd))) break; + + len = strlen(c); + if (len && c[len-1]=='\n') c[len-1] = 0; + temp = xmalloc(sizeof(struct arg_list)); + temp->next = list; + temp->arg = c; + list = temp; + } + + // Play them back. + while (list) { + struct arg_list *temp = list->next; + xputs(list->arg); + free(list->arg); + free(list); + list = temp; + } +} + +void tac_main(void) +{ + loopfiles(toys.optargs, do_tac); +} diff -r 2d7c56913fda -r 2986aa63a021 toys/other/taskset.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/toys/other/taskset.c Sat Aug 25 14:25:22 2012 -0500 @@ -0,0 +1,110 @@ +/* vi: set sw=4 ts=4: + * + * taskset.c - Retrieve or set the CPU affinity of a process. + * + * Copyright 2012 Elie De Brauwer + * + * No standard. + +USE_TASKSET(NEWTOY(taskset, "<1^pa", TOYFLAG_BIN|TOYFLAG_STAYROOT)) + +config TASKSET + bool "taskset" + default y + help + usage: taskset [-ap] [mask] [PID | cmd [args...]] + + Launch a new task which may only run on certain processors, or change + the processor affinity of an exisitng PID. + + Mask is a hex string where each bit represents a processor the process + is allowed to run on. PID without a mask displays existing affinity. + + -p Set/get the affinity of given PID instead of a new command. + -a Set/get the affinity of all threads of the PID. +*/ + +#include "toys.h" + +#define FLAG_a 0x1 +#define FLAG_p 0x2 + +// Prototype for syscall wrappers sched.h refuses to give us +int sched_setaffinity(pid_t pid, size_t size, void *cpuset); +int sched_getaffinity(pid_t pid, size_t size, void *cpuset); + +// mask is an array of long, which makes the layout a bit weird on big +// endian systems but as long as it's consistent... + +static void do_taskset(pid_t pid, int quiet) +{ + unsigned long *mask = (unsigned long *)toybuf; + char *s = *toys.optargs, *failed = "failed to %s %d's affinity"; + int i, j, k; + + for (i=0; ; i++) { + if (!quiet) { + int j = sizeof(toybuf), flag = 0; + + if (sched_getaffinity(pid, sizeof(toybuf), (void *)mask)) + perror_exit(failed, "get", pid); + + printf("pid %d's %s affinity mask: ", pid, i ? "new" : "current"); + + while (j--) { + int x = 255 & (mask[j/sizeof(long)] >> (8*(j&(sizeof(long)-1)))); + + if (flag) printf("%02x", x); + else if (x) { + flag++; + printf("%x", x); + } + } + putchar('\n'); + } + + if (i || toys.optc < 2) return; + + memset(toybuf, 0, sizeof(toybuf)); + k = strlen(s = *toys.optargs); + s += k; + for (j = 0; j 9) digit = 10 + tolower(*s)-'a'; + if (digit > 15) error_exit("bad mask '%s'", *toys.optargs); + mask[j/(2*sizeof(long))] |= digit << 4*(j&((2*sizeof(long))-1)); + } + + if (sched_setaffinity(pid, sizeof(toybuf), (void *)mask)) + perror_exit(failed, "set", pid); + } +} + +static int task_callback(struct dirtree *new) +{ + if (!new->parent) return DIRTREE_RECURSE; + if (isdigit(*new->name)) do_taskset(atoi(new->name), 0); + + return 0; +} + +void taskset_main(void) +{ + if (!(toys.optflags & FLAG_p)) { + if (toys.optc < 2) error_exit("Needs 2 args"); + do_taskset(getpid(), 1); + xexec(toys.optargs+1); + } else { + char *c; + pid_t pid = strtol(toys.optargs[toys.optc-1], &c, 10); + + if (*c) error_exit("Not int %s", toys.optargs[1]); + + if (toys.optflags & FLAG_a) { + char buf[33]; + sprintf(buf, "/proc/%ld/task/", (long)pid); + dirtree_read(buf, task_callback); + } else do_taskset(pid, 0); + } +} diff -r 2d7c56913fda -r 2986aa63a021 toys/other/toysh.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/toys/other/toysh.c Sat Aug 25 14:25:22 2012 -0500 @@ -0,0 +1,382 @@ +/* vi: set sw=4 ts=4: + * + * toysh - toybox shell + * + * Copyright 2006 Rob Landley + * + * The spec for this is at: + * http://www.opengroup.org/onlinepubs/009695399/utilities/xcu_chap02.html + * and http://www.opengroup.org/onlinepubs/009695399/utilities/sh.html + * + * There are also specs for: + * http://www.opengroup.org/onlinepubs/009695399/utilities/cd.html + * http://www.opengroup.org/onlinepubs/009695399/utilities/exit.html + * + * Things like the bash man page are good to read too. + * + * TODO: // Handle embedded NUL bytes in the command line. + +USE_TOYSH(NEWTOY(cd, NULL, TOYFLAG_NOFORK)) +USE_TOYSH(NEWTOY(exit, NULL, TOYFLAG_NOFORK)) +USE_TOYSH(OLDTOY(sh, toysh, "c:i", TOYFLAG_BIN)) +USE_TOYSH(NEWTOY(toysh, "c:i", TOYFLAG_BIN)) + +config TOYSH + bool "sh (toysh)" + default n + help + usage: sh [-c command] [script] + + The toybox command shell. Runs a shell script, or else reads input + interactively and responds to it. + + -c command line to execute + +config TOYSH_TTY + bool "Interactive shell (terminal control)" + default n + depends on TOYSH + help + Add terminal control to toysh. This is necessary for interactive use, + so the shell isn't killed by CTRL-C. + +config TOYSH_PROFILE + bool "Profile support" + default n + depends on TOYSH_TTY + help + Read /etc/profile and ~/.profile when running interactively. + + Also enables the built-in command "source". + +config TOYSH_JOBCTL + bool "Job Control (fg, bg, jobs)" + default n + depends on TOYSH_TTY + help + Add job control to toysh. This lets toysh handle CTRL-Z, and enables + the built-in commands "fg", "bg", and "jobs". + + With pipe support, enable use of "&" to run background processes. + +config TOYSH_FLOWCTL + bool "Flow control (if, while, for, functions)" + default n + depends on TOYSH + help + Add flow control to toysh. This enables the if/then/else/fi, + while/do/done, and for/do/done constructs. + + With pipe support, this enables the ability to define functions + using the "function name" or "name()" syntax, plus curly brackets + "{ }" to group commands. + +config TOYSH_QUOTES + bool "Smarter argument parsing (quotes)" + default n + depends on TOYSH + help + Add support for parsing "" and '' style quotes to the toysh command + parser, with lets arguments have spaces in them. + +config TOYSH_WILDCARDS + bool "Wildcards ( ?*{,} )" + default n + depends on TOYSH_QUOTES + help + Expand wildcards in argument names, ala "ls -l *.t?z" and + "rm subdir/{one,two,three}.txt". + +config TOYSH_PROCARGS + bool "Executable arguments ( `` and $() )" + default n + depends on TOYSH_QUOTES + help + Add support for executing arguments contianing $() and ``, using + the output of the command as the new argument value(s). + + (Bash calls this "command substitution".) + +config TOYSH_ENVVARS + bool "Environment variable support" + default n + depends on TOYSH_QUOTES + help + Substitute environment variable values for $VARNAME or ${VARNAME}, + and enable the built-in command "export". + +config TOYSH_LOCALS + bool "Local variables" + default n + depends on TOYSH_ENVVARS + help + Support for local variables, fancy prompts ($PS1), the "set" command, + and $?. + +config TOYSH_ARRAYS + bool "Array variables" + default n + depends on TOYSH_LOCALS + help + Support for ${blah[blah]} style array variables. + +config TOYSH_PIPES + bool "Pipes and redirects ( | > >> < << & && | || () ; )" + default n + depends on TOYSH + help + Support multiple commands on the same command line. This includes + | pipes, > >> < redirects, << here documents, || && conditional + execution, () subshells, ; sequential execution, and (with job + control) & background processes. + +config TOYSH_BUILTINS + bool "Builtin commands" + default n + depends on TOYSH + help + Adds the commands exec, fg, bg, help, jobs, pwd, export, source, set, + unset, read, alias. + +config EXIT + bool + default n + depends on TOYSH + help + usage: exit [status] + + Exit shell. If no return value supplied on command line, use value + of most recent command, or 0 if none. + +config CD + bool + default n + depends on TOYSH + help + usage: cd [path] + + Change current directory. With no arguments, go to $HOME. + +config CD_P + bool # "-P support for cd" + default n + depends on TOYSH + help + usage: cd [-PL] + + -P Physical path: resolve symlinks in path. + -L Cancel previous -P and restore default behavior. +*/ + +#include "toys.h" + +DEFINE_GLOBALS( + char *command; +) + +#define TT this.toysh + +// A single executable, its arguments, and other information we know about it. +#define TOYSH_FLAG_EXIT 1 +#define TOYSH_FLAG_SUSPEND 2 +#define TOYSH_FLAG_PIPE 4 +#define TOYSH_FLAG_AND 8 +#define TOYSH_FLAG_OR 16 +#define TOYSH_FLAG_AMP 32 +#define TOYSH_FLAG_SEMI 64 +#define TOYSH_FLAG_PAREN 128 + +// What we know about a single process. +struct command { + struct command *next; + int flags; // exit, suspend, && || + int pid; // pid (or exit code) + int argc; + char *argv[0]; +}; + +// A collection of processes piped into/waiting on each other. +struct pipeline { + struct pipeline *next; + int job_id; + struct command *cmd; + char *cmdline; // Unparsed line for display purposes + int cmdlinelen; // How long is cmdline? +}; + +// Parse one word from the command line, appending one or more argv[] entries +// to struct command. Handles environment variable substitution and +// substrings. Returns pointer to next used byte, or NULL if it +// hit an ending token. +static char *parse_word(char *start, struct command **cmd) +{ + char *end; + + // Detect end of line (and truncate line at comment) + if (CFG_TOYSH_PIPES && strchr("><&|(;", *start)) return 0; + + // Grab next word. (Add dequote and envvar logic here) + end = start; + while (*end && !isspace(*end)) end++; + (*cmd)->argv[(*cmd)->argc++] = xstrndup(start, end-start); + + // Allocate more space if there's no room for NULL terminator. + + if (!((*cmd)->argc & 7)) + *cmd=xrealloc(*cmd, + sizeof(struct command) + ((*cmd)->argc+8)*sizeof(char *)); + (*cmd)->argv[(*cmd)->argc] = 0; + return end; +} + +// Parse a line of text into a pipeline. +// Returns a pointer to the next line. + +static char *parse_pipeline(char *cmdline, struct pipeline *line) +{ + struct command **cmd = &(line->cmd); + char *start = line->cmdline = cmdline; + + if (!cmdline) return 0; + + if (CFG_TOYSH_JOBCTL) line->cmdline = cmdline; + + // Parse command into argv[] + for (;;) { + char *end; + + // Skip leading whitespace and detect end of line. + while (isspace(*start)) start++; + if (!*start || *start=='#') { + if (CFG_TOYSH_JOBCTL) line->cmdlinelen = start-cmdline; + return 0; + } + + // Allocate next command structure if necessary + if (!*cmd) *cmd = xzalloc(sizeof(struct command)+8*sizeof(char *)); + + // Parse next argument and add the results to argv[] + end = parse_word(start, cmd); + + // If we hit the end of this command, how did it end? + if (!end) { + if (CFG_TOYSH_PIPES && *start) { + if (*start==';') { + start++; + break; + } + // handle | & < > >> << || && + } + break; + } + start = end; + } + + if (CFG_TOYSH_JOBCTL) line->cmdlinelen = start-cmdline; + + return start; +} + +// Execute the commands in a pipeline +static void run_pipeline(struct pipeline *line) +{ + struct toy_list *tl; + struct command *cmd = line->cmd; + if (!cmd || !cmd->argc) return; + + tl = toy_find(cmd->argv[0]); + // Is this command a builtin that should run in this process? + if (tl && (tl->flags & TOYFLAG_NOFORK)) { + struct toy_context temp; + + // This fakes lots of what toybox_main() does. + memcpy(&temp, &toys, sizeof(struct toy_context)); + memset(&toys, 0, sizeof(struct toy_context)); + toy_init(tl, cmd->argv); + tl->toy_main(); + cmd->pid = toys.exitval; + free(toys.optargs); + if (toys.old_umask) umask(toys.old_umask); + memcpy(&toys, &temp, sizeof(struct toy_context)); + } else { + int status; + + cmd->pid = vfork(); + if (!cmd->pid) xexec(cmd->argv); + else waitpid(cmd->pid, &status, 0); + + if (CFG_TOYSH_FLOWCTL || CFG_TOYSH_PIPES) { + if (WIFEXITED(status)) cmd->pid = WEXITSTATUS(status); + if (WIFSIGNALED(status)) cmd->pid = WTERMSIG(status); + } + } + + return; +} + +// Free the contents of a command structure +static void free_cmd(void *data) +{ + struct command *cmd=(struct command *)data; + + while(cmd->argc) free(cmd->argv[--cmd->argc]); +} + + +// Parse a command line and do what it says to do. +static void handle(char *command) +{ + struct pipeline line; + char *start = command; + + // Loop through commands in this line + + for (;;) { + + // Parse a group of connected commands + + memset(&line,0,sizeof(struct pipeline)); + start = parse_pipeline(start, &line); + if (!line.cmd) break; + + // Run those commands + + run_pipeline(&line); + llist_traverse(line.cmd, free_cmd); + } +} + +void cd_main(void) +{ + char *dest = *toys.optargs ? *toys.optargs : getenv("HOME"); + xchdir(dest); +} + +void exit_main(void) +{ + exit(*toys.optargs ? atoi(*toys.optargs) : 0); +} + +void toysh_main(void) +{ + FILE *f; + + // Set up signal handlers and grab control of this tty. + if (CFG_TOYSH_TTY) { + if (isatty(0)) toys.optflags |= 1; + } + f = *toys.optargs ? xfopen(*toys.optargs, "r") : NULL; + if (TT.command) handle(TT.command); + else { + size_t cmdlen = 0; + for (;;) { + char *command = 0; + if (!f) xputc('$'); + if (1 > getline(&command, &cmdlen, f ? f : stdin)) break; + handle(command); + free(command); + } + } + + toys.exitval = 1; +} diff -r 2d7c56913fda -r 2986aa63a021 toys/other/truncate.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/toys/other/truncate.c Sat Aug 25 14:25:22 2012 -0500 @@ -0,0 +1,47 @@ +/* vi: set sw=4 ts=4: + * + * truncate.c - set file length, extending sparsely if necessary + * + * Copyright 2011 Rob Landley + * + * Not in SUSv4 + +USE_TRUNCATE(NEWTOY(truncate, "<1s#|c", TOYFLAG_BIN)) + +config TRUNCATE + bool "truncate" + default y + help + usage: truncate [-c] -s file... + Set length of file(s), extending sparsely if necessary. + + -c Don't create file if it doesn't exist. + -s New size +*/ + +#include "toys.h" + +DEFINE_GLOBALS( + long size; +) + +#define TT this.truncate + +static void do_truncate(int fd, char *name) +{ + if (fd<0) return; + if (ftruncate(fd, TT.size)) { + perror_msg("failed to set '%s' to '%ld'", name, TT.size); + toys.exitval = EXIT_FAILURE; + } +} + +void truncate_main(void) +{ + int cr = !(toys.optflags&1); + + // Create files with mask rwrwrw. + // Nonexistent files are only an error if we're supposed to create them. + loopfiles_rw(toys.optargs, O_WRONLY|(cr ? O_CREAT : 0), 0666, cr, + do_truncate); +} diff -r 2d7c56913fda -r 2986aa63a021 toys/other/unshare.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/toys/other/unshare.c Sat Aug 25 14:25:22 2012 -0500 @@ -0,0 +1,45 @@ +/* vi: set sw=4 ts=4: + * + * unshare.c - run command in new context + * + * Copyright 2011 Rob Landley + * + * Not in SUSv4. + +USE_UNSHARE(NEWTOY(unshare, "<1^nium", TOYFLAG_USR|TOYFLAG_BIN)) + +config UNSHARE + bool "unshare" + default y + depends on TOYBOX_CONTAINER + help + usage: unshare [-muin] COMMAND... + + Create new namespace(s) for this process and its children, so some + attribute is not shared with the parent process. This is part of + Linux Containers. Each process can have its own: + + -m Mount/unmount tree + -u Host and domain names + -i SysV IPC (message queues, semaphores, shared memory) + -n Network address, sockets, routing, iptables +*/ + +#include "toys.h" +#include +extern int unshare (int __flags); + +void unshare_main(void) +{ + unsigned flags[]={CLONE_NEWNS, CLONE_NEWUTS, CLONE_NEWIPC, CLONE_NEWNET,0}; + unsigned f=0; + int i; + + for (i=0; flags[i]; i++) + if (toys.optflags & (1< + * + * Not in SUSv4. + +USE_UPTIME(NEWTOY(uptime, NULL, TOYFLAG_USR|TOYFLAG_BIN)) + +config UPTIME + bool "uptime" + default y + help + usage: uptime + + Tell how long the system has been running and the system load + averages for the past 1, 5 and 15 minutes. +*/ + +#include "toys.h" + +void uptime_main(void) +{ + struct sysinfo info; + time_t tmptime; + struct tm * now; + unsigned int days, hours, minutes; + + // Obtain the data we need. + sysinfo(&info); + time(&tmptime); + now = localtime(&tmptime); + + // Time + xprintf(" %02d:%02d:%02d up ", now->tm_hour, now->tm_min, now->tm_sec); + // Uptime + info.uptime /= 60; + minutes = info.uptime%60; + info.uptime /= 60; + hours = info.uptime%24; + days = info.uptime/24; + if (days) xprintf("%d day%s, ", days, (days!=1)?"s":""); + if (hours) + xprintf("%2d:%02d, ", hours, minutes); + else + printf("%d min, ", minutes); + + printf(" load average: %.02f %.02f %.02f\n", info.loads[0]/65536.0, + info.loads[1]/65536.0, info.loads[2]/65536.0); + +} diff -r 2d7c56913fda -r 2986aa63a021 toys/other/usleep.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/toys/other/usleep.c Sat Aug 25 14:25:22 2012 -0500 @@ -0,0 +1,32 @@ +/* vi: set sw=4 ts=4: + * + * usleep.c - Wait for a number of microseconds. + * + * Copyright 2012 Elie De Brauwer + * + * No standard. + +USE_USLEEP(NEWTOY(usleep, "<1", TOYFLAG_BIN)) + +config USLEEP + bool "usleep" + default y + help + usage: usleep MICROSECONDS + + Pause for MICROSECONDS microseconds. + +*/ + +#include "toys.h" + +void usleep_main(void) +{ + struct timespec tv; + long delay = atol(*toys.optargs); + + tv.tv_sec = delay/1000000; + tv.tv_nsec = (delay%1000000) * 1000; + toys.exitval = !!nanosleep(&tv, NULL); + +} diff -r 2d7c56913fda -r 2986aa63a021 toys/other/vmstat.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/toys/other/vmstat.c Sat Aug 25 14:25:22 2012 -0500 @@ -0,0 +1,191 @@ +/* vi: set sw=4 ts=4: + * + * vmstat.c - Report virtual memory statistics. + * + * Copyright 2012 Elie De Brauwer + * + * Not in SUSv4. + +USE_VMSTAT(NEWTOY(vmstat, ">2n", TOYFLAG_BIN)) + +config VMSTAT + bool "vmstat" + default y + help + usage: vmstat [-n] [delay [count]] + -n Display the header only once + delay The delay between updates in seconds, when not specified + the average since boot is displayed. + count Number of updates to display, the default is inifinite. +*/ + +#include "toys.h" + +void read_proc_stat(unsigned int * proc_running, unsigned int * proc_blocked, + uint64_t * sys_irq, uint64_t * sys_ctxt, + uint64_t * cpu_user, uint64_t * cpu_sys, uint64_t * cpu_idle, uint64_t * cpu_wait) +{ + char * off; + uint64_t c_user, c_nice, c_sys, c_irq, c_sirq; + int fd = xopen("/proc/stat", O_RDONLY); + size_t s = xread(fd, toybuf, sizeof(toybuf)-1); + toybuf[s] = 0; + if ( s == sizeof(toybuf)-1) + error_exit("/proc/stat is too large"); + + off = strstr(toybuf, "cpu "); + // Ignoring steal and guest fields for now. + if (off) sscanf(off, "cpu %"PRIu64" %"PRIu64" %"PRIu64" %"PRIu64 \ + " %"PRIu64" %"PRIu64" %"PRIu64, &c_user, &c_nice, &c_sys, cpu_idle, + cpu_wait, &c_irq, &c_sirq); + *cpu_user = c_user + c_nice; + *cpu_sys = c_sys + c_irq + c_sirq; + off = strstr(toybuf, "intr"); + if (off) sscanf(off, "intr %"PRIu64, sys_irq); + + off = strstr(toybuf, "ctxt"); + if (off) sscanf(off, "ctxt %"PRIu64, sys_ctxt); + + off = strstr(toybuf, "procs_running"); + if (off) sscanf(off, "procs_running %u", proc_running); + (*proc_running)--; // look, i'm invisible. + + off = strstr(toybuf, "procs_blocked"); + if (off) sscanf(off, "procs_blocked %u", proc_blocked); + + close(fd); +} + +void read_proc_meminfo(unsigned long * mem_swapped, unsigned long * mem_free, + unsigned long * mem_buff, unsigned long * mem_cache) +{ + char * off; + unsigned long swap_total, swap_free; + int fd = xopen("/proc/meminfo", O_RDONLY); + size_t s = xread(fd, toybuf, sizeof(toybuf)-1); + toybuf[s] = 0; + if ( s == sizeof(toybuf)-1) + error_exit("/proc/meminfo is too large"); + + off = strstr(toybuf, "MemFree"); + if (off) sscanf(off, "MemFree: %lu kB", mem_free); + + off = strstr(toybuf, "Buffers"); + if (off) sscanf(off, "Buffers: %lu kB", mem_buff); + + off = strstr(toybuf, "Cached"); + if (off) sscanf(off, "Cached: %lu kB", mem_cache); + + off = strstr(toybuf, "SwapFree"); + if (off) sscanf(off, "SwapFree: %lu kB", &swap_free); + + off = strstr(toybuf, "SwapTotal"); + if (off) sscanf(off, "SwapTotal: %lu kB", &swap_total); + *mem_swapped = swap_total - swap_free; + + close(fd); +} + +void read_proc_vmstat(unsigned long * io_pages_in, unsigned long * io_pages_out, + unsigned long * swap_bytes_in, unsigned long * swap_bytes_out) +{ + char * off; + unsigned long s_pages_in, s_pages_out; + unsigned long pagesize_kb = sysconf(_SC_PAGESIZE) / 1024L; + int fd = xopen("/proc/vmstat", O_RDONLY); + size_t s = xread(fd, toybuf, sizeof(toybuf)-1); + toybuf[s] = 0; + if ( s == sizeof(toybuf)-1) + error_exit("/proc/vmstat is too large"); + + off = strstr(toybuf, "pgpgin"); + if (off) sscanf(off, "pgpgin %lu", io_pages_in); + + off = strstr(toybuf, "pgpgout"); + if (off) sscanf(off, "pgpgout %lu", io_pages_out); + + off = strstr(toybuf, "pswpin"); + if (off) sscanf(off, "pswpin %lu", &s_pages_in); + *swap_bytes_in = s_pages_in * pagesize_kb; + + off = strstr(toybuf, "pswpout"); + if (off) sscanf(off, "pswpout %lu", &s_pages_out); + *swap_bytes_out = s_pages_out * pagesize_kb; + + close(fd); +} + +void vmstat_main(void) +{ + const char fmt[] = "%2u %2u %6lu %6lu %6lu %6lu %4u %4u %5u %5u %4u %4u %2u %2u %2u %2u\n"; + unsigned int loop_num = 0, loop_max_num = 0, loop_delay = 0; + unsigned int running = 0, blocked = 0; + unsigned long mem_swap = 0, mem_free = 0, mem_buff = 0, mem_cache = 0; + unsigned long io_pages_in[2], io_pages_out[2], swap_bytes_in[2], swap_bytes_out[2]; + uint64_t sys_irq[2], sys_ctxt[2], cpu_user[2], cpu_sys[2], cpu_idle[2], cpu_wait[2]; + int first_run = 1; + int no_header = toys.optflags & 0x1; + unsigned num_rows = 22; + + if (toys.optc >= 1) + loop_delay = atoi(toys.optargs[0]); + if (toys.optc >= 2) + loop_max_num = atoi(toys.optargs[1]); + + if (loop_max_num < 0 || loop_delay < 0) + error_exit("Invalid arguments"); + + while(1) { + uint64_t total_jif; + int idx = loop_num%2; + + if(first_run || (!(loop_num % num_rows) && !no_header)) { + unsigned rows = 0, cols = 0; + terminal_size(&cols, &rows); + num_rows = (rows > 3)? rows - 3 : 22; + printf("procs -----------memory---------- ---swap-- -----io---- -system-- ----cpu----\n"); + printf(" r b swpd free buff cache si so bi bo in cs us sy id wa\n"); + } + + read_proc_stat(&running, &blocked, &sys_irq[idx], &sys_ctxt[idx], &cpu_user[idx], + &cpu_sys[idx], &cpu_idle[idx], &cpu_wait[idx]); + read_proc_meminfo(&mem_swap, &mem_free, &mem_buff, &mem_cache); + read_proc_vmstat(&io_pages_in[idx], &io_pages_out[idx], &swap_bytes_in[idx], &swap_bytes_out[idx]); + + if (first_run) { + struct sysinfo inf; + sysinfo(&inf); + first_run = 0; + total_jif = cpu_user[idx] + cpu_idle[idx] + cpu_wait[idx]; + printf(fmt, running, blocked, mem_swap, mem_free, mem_buff, mem_cache, + (unsigned) (swap_bytes_in[idx]/inf.uptime), + (unsigned) (swap_bytes_out[idx]/inf.uptime), + (unsigned) (io_pages_in[idx]/inf.uptime), + (unsigned) (io_pages_out[idx]/inf.uptime), + (unsigned) (sys_irq[idx]/inf.uptime), + (unsigned) (sys_ctxt[idx]/inf.uptime), + (unsigned) (100*cpu_user[idx]/total_jif), + (unsigned) (100*cpu_sys[idx]/total_jif), + (unsigned) (100*cpu_idle[idx]/total_jif), + (unsigned) (100*cpu_wait[idx]/total_jif)); + }else{ + total_jif = cpu_user[idx] - cpu_user[!idx] + cpu_idle[idx] - cpu_idle[!idx] + cpu_wait[idx] - cpu_wait[!idx]; + printf(fmt, running, blocked, mem_swap, mem_free, mem_buff, mem_cache, + (unsigned) ((swap_bytes_in[idx] - swap_bytes_in[!idx])/loop_delay), + (unsigned) ((swap_bytes_out[idx] - swap_bytes_out[!idx])/loop_delay), + (unsigned) ((io_pages_in[idx] - io_pages_in[!idx])/loop_delay), + (unsigned) ((io_pages_out[idx] - io_pages_out[!idx])/loop_delay), + (unsigned) ((sys_irq[idx] - sys_irq[!idx])/loop_delay), + (unsigned) ((sys_ctxt[idx] - sys_ctxt[!idx])/loop_delay), + (unsigned) (100*(cpu_user[idx] - cpu_user[!idx])/total_jif), + (unsigned) (100*(cpu_sys[idx] - cpu_sys[!idx]) /total_jif), + (unsigned) (100*(cpu_idle[idx] - cpu_idle[!idx])/total_jif), + (unsigned) (100*(cpu_wait[idx] - cpu_wait[!idx])/total_jif)); + } + + loop_num++; + if (loop_delay == 0 || (loop_max_num != 0 && loop_num >= loop_max_num)) + break; + sleep(loop_delay); + } +} diff -r 2d7c56913fda -r 2986aa63a021 toys/other/w.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/toys/other/w.c Sat Aug 25 14:25:22 2012 -0500 @@ -0,0 +1,36 @@ +/* vi: set sw=4 ts=4: + * + * w.c - shows logged in users + * + * Copyright 2012 Gaurang Shastri + * + * Not in SUSv4. + +USE_W(NEWTOY(w, NULL, TOYFLAG_USR|TOYFLAG_BIN)) + +config W + bool "w" + default y + help + usage: w + + Show who is logged on and since how long they logged in. +*/ + +#include "toys.h" + +void w_main(void) +{ + struct utmpx *x; + + xprintf("USER TTY LOGIN@ FROM"); + setutxent(); + while ((x=getutxent()) != NULL) + if (x->ut_type==7) { + time_t tt = x->ut_tv.tv_sec; + + xprintf("\n%-9.8s%-9.8s %-4.24s (%-1.12s)", x->ut_user, x->ut_line, + ctime(&tt), x->ut_host); + } + xputc('\n'); +} diff -r 2d7c56913fda -r 2986aa63a021 toys/other/which.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/toys/other/which.c Sat Aug 25 14:25:22 2012 -0500 @@ -0,0 +1,71 @@ +/* vi: set sw=4 ts=4: + * + * which.c - Find executable files in $PATH. + * + * Copyright 2006 Rob landley + * + * Not in SUSv3. + +USE_WHICH(NEWTOY(which, "<1a", TOYFLAG_USR|TOYFLAG_BIN)) + +config WHICH + bool "which" + default y + help + usage: which [-a] filename ... + + Search $PATH for executable files matching filename(s). + + -a Show all matches +*/ +#include "toys.h" + +// Find an exectuable file either at a path with a slash in it (absolute or +// relative to current directory), or in $PATH. Returns absolute path to file, +// or NULL if not found. + +static int which_in_path(char *filename) +{ + struct string_list *list; + + // If they gave us a path, don't worry about $PATH or -a + + if (strchr(filename, '/')) { + // Confirm it has the executable bit set, and it's not a directory. + if (!access(filename, X_OK)) { + struct stat st; + + if (!stat(filename, &st) && S_ISREG(st.st_mode)) { + puts(filename); + return 0; + } + return 1; + } + } + + // Search $PATH for matches. + list = find_in_path(getenv("PATH"), filename); + if (!list) return 1; + + // Print out matches + while (list) { + if (!access(list->str, X_OK)) { + puts(list->str); + // If we should stop at one match, do so + if (!toys.optflags) { + llist_traverse(list, free); + break; + } + } + free(llist_pop(&list)); + } + + return 0; +} + +void which_main(void) +{ + int i; + for (i=0; toys.optargs[i]; i++) + toys.exitval |= which_in_path(toys.optargs[i]); +} diff -r 2d7c56913fda -r 2986aa63a021 toys/other/whoami.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/toys/other/whoami.c Sat Aug 25 14:25:22 2012 -0500 @@ -0,0 +1,32 @@ +/* vi: set sw=4 ts=4: + * + * whoami.c - Print effective user name + * + * Copyright 2012 Georgi Chorbadzhiyski + * + +USE_WHOAMI(NEWTOY(whoami, NULL, TOYFLAG_USR|TOYFLAG_BIN)) + +config WHOAMI + bool "whoami" + default y + help + usage: whoami + + Print effective user name. +*/ + +#include "toys.h" + +void whoami_main(void) +{ + struct passwd *pw = getpwuid(geteuid()); + + if (!pw) { + perror("getpwuid"); + toys.exitval = 1; + return; + } + + xputs(pw->pw_name); +} diff -r 2d7c56913fda -r 2986aa63a021 toys/other/yes.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/toys/other/yes.c Sat Aug 25 14:25:22 2012 -0500 @@ -0,0 +1,33 @@ +/* vi: set sw=4 ts=4: + * + * yes.c - Repeatedly output a string. + * + * Copyright 2007 Rob Landley + * + * Not in SUSv3. + +USE_YES(NEWTOY(yes, NULL, TOYFLAG_USR|TOYFLAG_BIN)) + +config YES + bool "yes" + default y + help + usage: yes [args...] + + Repeatedly output line until killed. If no args, output 'y'. +*/ + +#include "toys.h" + +void yes_main(void) +{ + for (;;) { + int i; + for (i=0; toys.optargs[i]; i++) { + if (i) xputc(' '); + xprintf("%s", toys.optargs[i]); + } + if (!i) xputc('y'); + xputc('\n'); + } +} diff -r 2d7c56913fda -r 2986aa63a021 toys/passwd.c --- a/toys/passwd.c Sat Aug 25 14:24:24 2012 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,274 +0,0 @@ -/* vi: set sw=4 ts=4: - * - * passwd.c - Program to upadte user password. - * - * Copyright 2012 Ashwini Kumar - * Modified 2012 Jason Kyungwan Han - * - * Not in SUSv4. - -USE_PASSWD(NEWTOY(passwd, ">1a:dlu", TOYFLAG_STAYROOT|TOYFLAG_USR|TOYFLAG_BIN)) - -config PASSWD - bool "passwd" - default y - help - usage: passwd [-a ALGO] [-d] [-l] [-u] - - update user’s authentication tokens. Default : current user - - -a ALGO Encryption method (des, md5, sha256, sha512) default: des - -d Set password to '' - -l Lock (disable) account - -u Unlock (enable) account - -*/ - -#include "toys.h" -#include - - -DEFINE_GLOBALS( - char *algo; -) - -#define TT this.passwd - -#define FLAG_u (1 << 0) -#define FLAG_l (1 << 1) -#define FLAG_d (1 << 2) -#define FLAG_a (1 << 3) - -#define MAX_SALT_LEN 20 //3 for id, 16 for key, 1 for '\0' -#define URANDOM_PATH "/dev/urandom" - -#ifndef _GNU_SOURCE -char *strcasestr(const char *haystack, const char *needle); -#endif - -unsigned int random_number_generator(int fd) -{ - unsigned int randnum; - xreadall(fd, &randnum, sizeof(randnum)); - return randnum; -} - - - -char inttoc(int i) -{ - // salt value uses 64 chracters in "./0-9a-zA-Z" - const char character_set[]="./0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; - i &= 0x3f; // masking for using 10 bits only - return character_set[i]; -} - -int get_salt(char *salt) -{ - int i, salt_length = 0; - int randfd; - if(!strncmp(TT.algo,"des",3)){ - // 2 bytes salt value is used in des - salt_length = 2; - } else { - *salt++ = '$'; - if(!strncmp(TT.algo,"md5",3)){ - *salt++ = '1'; - // 8 bytes salt value is used in md5 - salt_length = 8; - } else if(!strncmp(TT.algo,"sha256",6)){ - *salt++ = '5'; - // 16 bytes salt value is used in sha256 - salt_length = 16; - } else if(!strncmp(TT.algo,"sha512",6)){ - *salt++ = '6'; - // 16 bytes salt value is used in sha512 - salt_length = 16; - } else return 1; - - *salt++ = '$'; - } - - randfd = xopen(URANDOM_PATH, O_RDONLY); - for(i=0; ipw_name); - - pw = getpwnam(name); - if(!pw) error_exit("Unknown user '%s'",name); - - if(myuid != 0 && (myuid != pw->pw_uid)) - error_exit("You need to be root to change '%s' password\n", name); - - pass = pw->pw_passwd; - if(pw->pw_passwd[0] == 'x') { - /*get shadow passwd */ - sp = getspnam(name); - if(sp) - pass = sp->sp_pwdp; - } - - - if(!(toys.optflags & (FLAG_l | FLAG_u | FLAG_d))) { - printf("Changing password for %s\n",name); - if(pass[0] == '!') - error_exit("Can't change, password is locked for %s",name); - if(myuid != 0) { - /*Validate user */ - - if(read_password(toybuf, sizeof(toybuf), "Origial password:")) { - if(!toys.optargs[0]) free(name); - return; - } - orig = toybuf; - if(verify_passwd(pass)) - error_exit("Authentication failed\n"); - } - - orig = xstrdup(orig); - - /*Get new password */ - newp = new_password(orig, name); - if(!newp) { - free(orig); - if(!toys.optargs[0]) free(name); - return; //new password is not set well. - } - - /*Encrypt the passwd */ - if(!(toys.optflags & FLAG_a)) TT.algo = "des"; - - if(get_salt(salt)) - error_exit("Error: Unkown encryption algorithm\n"); - - encrypted = crypt(newp, salt); - free(newp); - free(orig); - } - else if(toys.optflags & FLAG_l) { - if(pass[0] == '!') - error_exit("password is already locked for %s",name); - printf("Locking password for %s\n",name); - encrypted = xmsprintf("!%s",pass); - } - else if(toys.optflags & FLAG_u) { - if(pass[0] != '!') - error_exit("password is already unlocked for %s",name); - - printf("Unlocking password for %s\n",name); - encrypted = xstrdup(&pass[1]); - } - else if(toys.optflags & FLAG_d) { - printf("Deleting password for %s\n",name); - encrypted = (char*)xzalloc(sizeof(char)*2); //1 = "", 2 = '\0' - } - - /*Update the passwd */ - if(pw->pw_passwd[0] == 'x') - ret = update_password("/etc/shadow", name, encrypted); - else - ret = update_password("/etc/passwd", name, encrypted); - - if((toys.optflags & (FLAG_l | FLAG_u | FLAG_d))) - free(encrypted); - - if(!toys.optargs[0]) free(name); - if(!ret) - error_msg("Success"); - else - error_msg("Failure"); -} diff -r 2d7c56913fda -r 2986aa63a021 toys/patch.c --- a/toys/patch.c Sat Aug 25 14:24:24 2012 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,412 +0,0 @@ -/* vi: set sw=4 ts=4: - * - * patch.c - Apply a "universal" diff. - * - * Copyright 2007 Rob Landley - * - * see http://www.opengroup.org/onlinepubs/009695399/utilities/patch.html - * (But only does -u, because who still cares about "ed"?) - * - * TODO: - * -b backup - * -l treat all whitespace as a single space - * -N ignore already applied - * -d chdir first - * -D define wrap #ifdef and #ifndef around changes - * -o outfile output here instead of in place - * -r rejectfile write rejected hunks to this file - * - * -E remove empty files --remove-empty-files - * -f force (no questions asked) - * -F fuzz (number, default 2) - * [file] which file to patch - -USE_PATCH(NEWTOY(patch, USE_TOYBOX_DEBUG("x")"up#i:R", TOYFLAG_USR|TOYFLAG_BIN)) - -config PATCH - bool "patch" - default y - help - usage: patch [-i file] [-p depth] [-Ru] - - Apply a unified diff to one or more files. - - -i Input file (defaults=stdin) - -p number of '/' to strip from start of file paths (default=all) - -R Reverse patch. - -u Ignored (only handles "unified" diffs) - - This version of patch only handles unified diffs, and only modifies - a file when all all hunks to that file apply. Patch prints failed - hunks to stderr, and exits with nonzero status if any hunks fail. - - A file compared against /dev/null (or with a date <= the epoch) is - created/deleted as appropriate. -*/ - -#include "toys.h" - -DEFINE_GLOBALS( - char *infile; - long prefix; - - struct double_list *current_hunk; - long oldline, oldlen, newline, newlen; - long linenum; - int context, state, filein, fileout, filepatch, hunknum; - char *tempname; -) - -#define TT this.patch - -#define FLAG_REVERSE 1 -#define FLAG_PATHLEN 4 - -// Dispose of a line of input, either by writing it out or discarding it. - -// state < 2: just free -// state = 2: write whole line to stderr -// state = 3: write whole line to fileout -// state > 3: write line+1 to fileout when *line != state - -#define PATCH_DEBUG (CFG_TOYBOX_DEBUG && (toys.optflags & 16)) - -static void do_line(void *data) -{ - struct double_list *dlist = (struct double_list *)data; - - if (TT.state>1 && *dlist->data != TT.state) { - char *s = dlist->data+(TT.state>3 ? 1 : 0); - int i = TT.state == 2 ? 2 : TT.fileout; - - xwrite(i, s, strlen(s)); - xwrite(i, "\n", 1); - } - - if (PATCH_DEBUG) fprintf(stderr, "DO %d: %s\n", TT.state, dlist->data); - - free(dlist->data); - free(data); -} - -static void finish_oldfile(void) -{ - if (TT.tempname) replace_tempfile(TT.filein, TT.fileout, &TT.tempname); - TT.fileout = TT.filein = -1; -} - -static void fail_hunk(void) -{ - if (!TT.current_hunk) return; - TT.current_hunk->prev->next = 0; - - fprintf(stderr, "Hunk %d FAILED %ld/%ld.\n", - TT.hunknum, TT.oldline, TT.newline); - toys.exitval = 1; - - // If we got to this point, we've seeked to the end. Discard changes to - // this file and advance to next file. - - TT.state = 2; - llist_traverse(TT.current_hunk, do_line); - TT.current_hunk = NULL; - delete_tempfile(TT.filein, TT.fileout, &TT.tempname); - TT.state = 0; -} - -// Given a hunk of a unified diff, make the appropriate change to the file. -// This does not use the location information, but instead treats a hunk -// as a sort of regex. Copies data from input to output until it finds -// the change to be made, then outputs the changed data and returns. -// (Finding EOF first is an error.) This is a single pass operation, so -// multiple hunks must occur in order in the file. - -static int apply_one_hunk(void) -{ - struct double_list *plist, *buf = NULL, *check; - int matcheof = 0, reverse = toys.optflags & FLAG_REVERSE, backwarn = 0; - - // Break doubly linked list so we can use singly linked traversal function. - TT.current_hunk->prev->next = NULL; - - // Match EOF if there aren't as many ending context lines as beginning - for (plist = TT.current_hunk; plist; plist = plist->next) { - if (plist->data[0]==' ') matcheof++; - else matcheof = 0; - if (PATCH_DEBUG) fprintf(stderr, "HUNK:%s\n", plist->data); - } - matcheof = matcheof < TT.context; - - if (PATCH_DEBUG) fprintf(stderr,"MATCHEOF=%c\n", matcheof ? 'Y' : 'N'); - - // Loop through input data searching for this hunk. Match all context - // lines and all lines to be removed until we've found the end of a - // complete hunk. - plist = TT.current_hunk; - buf = NULL; - if (TT.context) for (;;) { - char *data = get_line(TT.filein); - - TT.linenum++; - - // Figure out which line of hunk to compare with next. (Skip lines - // of the hunk we'd be adding.) - while (plist && *plist->data == "+-"[reverse]) { - if (data && !strcmp(data, plist->data+1)) { - if (!backwarn) backwarn = TT.linenum; - } - plist = plist->next; - } - - // Is this EOF? - if (!data) { - if (PATCH_DEBUG) fprintf(stderr, "INEOF\n"); - - // Does this hunk need to match EOF? - if (!plist && matcheof) break; - - if (backwarn) - fprintf(stderr, "Possibly reversed hunk %d at %ld\n", - TT.hunknum, TT.linenum); - - // File ended before we found a place for this hunk. - fail_hunk(); - goto done; - } else if (PATCH_DEBUG) fprintf(stderr, "IN: %s\n", data); - check = dlist_add(&buf, data); - - // Compare this line with next expected line of hunk. - // todo: teach the strcmp() to ignore whitespace. - - // A match can fail because the next line doesn't match, or because - // we hit the end of a hunk that needed EOF, and this isn't EOF. - - // If match failed, flush first line of buffered data and - // recheck buffered data for a new match until we find one or run - // out of buffer. - - for (;;) { - if (!plist || strcmp(check->data, plist->data+1)) { - // Match failed. Write out first line of buffered data and - // recheck remaining buffered data for a new match. - - if (PATCH_DEBUG) - fprintf(stderr, "NOT: %s\n", plist->data); - - TT.state = 3; - check = llist_pop(&buf); - check->prev->next = buf; - buf->prev = check->prev; - do_line(check); - plist = TT.current_hunk; - - // If we've reached the end of the buffer without confirming a - // match, read more lines. - if (check==buf) { - buf = 0; - break; - } - check = buf; - } else { - if (PATCH_DEBUG) - fprintf(stderr, "MAYBE: %s\n", plist->data); - // This line matches. Advance plist, detect successful match. - plist = plist->next; - if (!plist && !matcheof) goto out; - check = check->next; - if (check == buf) break; - } - } - } -out: - // We have a match. Emit changed data. - TT.state = "-+"[reverse]; - llist_traverse(TT.current_hunk, do_line); - TT.current_hunk = NULL; - TT.state = 1; -done: - if (buf) { - buf->prev->next = NULL; - llist_traverse(buf, do_line); - } - - return TT.state; -} - -// Read a patch file and find hunks, opening/creating/deleting files. -// Call apply_one_hunk() on each hunk. - -// state 0: Not in a hunk, look for +++. -// state 1: Found +++ file indicator, look for @@ -// state 2: In hunk: counting initial context lines -// state 3: In hunk: getting body - -void patch_main(void) -{ - int reverse = toys.optflags&FLAG_REVERSE, state = 0, patchlinenum = 0, - strip = 0; - char *oldname = NULL, *newname = NULL; - - if (TT.infile) TT.filepatch = xopen(TT.infile, O_RDONLY); - TT.filein = TT.fileout = -1; - - // Loop through the lines in the patch - for (;;) { - char *patchline; - - patchline = get_line(TT.filepatch); - if (!patchline) break; - - // Other versions of patch accept damaged patches, - // so we need to also. - if (strip || !patchlinenum++) { - int len = strlen(patchline); - if (patchline[len-1] == '\r') { - if (!strip) fprintf(stderr, "Removing DOS newlines\n"); - strip = 1; - patchline[len-1]=0; - } - } - if (!*patchline) { - free(patchline); - patchline = xstrdup(" "); - } - - // Are we assembling a hunk? - if (state >= 2) { - if (*patchline==' ' || *patchline=='+' || *patchline=='-') { - dlist_add(&TT.current_hunk, patchline); - - if (*patchline != '+') TT.oldlen--; - if (*patchline != '-') TT.newlen--; - - // Context line? - if (*patchline==' ' && state==2) TT.context++; - else state=3; - - // If we've consumed all expected hunk lines, apply the hunk. - - if (!TT.oldlen && !TT.newlen) state = apply_one_hunk(); - continue; - } - fail_hunk(); - state = 0; - continue; - } - - // Open a new file? - if (!strncmp("--- ", patchline, 4) || !strncmp("+++ ", patchline, 4)) { - char *s, **name = &oldname; - int i; - - if (*patchline == '+') { - name = &newname; - state = 1; - } - - free(*name); - finish_oldfile(); - - // Trim date from end of filename (if any). We don't care. - for (s = patchline+4; *s && *s!='\t'; s++) - if (*s=='\\' && s[1]) s++; - i = atoi(s); - if (i>1900 && i<=1970) - *name = xstrdup("/dev/null"); - else { - *s = 0; - *name = xstrdup(patchline+4); - } - - // We defer actually opening the file because svn produces broken - // patches that don't signal they want to create a new file the - // way the patch man page says, so you have to read the first hunk - // and _guess_. - - // Start a new hunk? Usually @@ -oldline,oldlen +newline,newlen @@ - // but a missing ,value means the value is 1. - } else if (state == 1 && !strncmp("@@ -", patchline, 4)) { - int i; - char *s = patchline+4; - - // Read oldline[,oldlen] +newline[,newlen] - - TT.oldlen = TT.newlen = 1; - TT.oldline = strtol(s, &s, 10); - if (*s == ',') TT.oldlen=strtol(s+1, &s, 10); - TT.newline = strtol(s+2, &s, 10); - if (*s == ',') TT.newlen = strtol(s+1, &s, 10); - - TT.context = 0; - state = 2; - - // If this is the first hunk, open the file. - if (TT.filein == -1) { - int oldsum, newsum, del = 0; - char *name; - - oldsum = TT.oldline + TT.oldlen; - newsum = TT.newline + TT.newlen; - - name = reverse ? oldname : newname; - - // We're deleting oldname if new file is /dev/null (before -p) - // or if new hunk is empty (zero context) after patching - if (!strcmp(name, "/dev/null") || !(reverse ? oldsum : newsum)) - { - name = reverse ? newname : oldname; - del++; - } - - // handle -p path truncation. - for (i = 0, s = name; *s;) { - if ((toys.optflags & FLAG_PATHLEN) && TT.prefix == i) break; - if (*s++ != '/') continue; - while (*s == '/') s++; - name = s; - i++; - } - - if (del) { - printf("removing %s\n", name); - xunlink(name); - state = 0; - // If we've got a file to open, do so. - } else if (!(toys.optflags & FLAG_PATHLEN) || i <= TT.prefix) { - // If the old file was null, we're creating a new one. - if (!strcmp(oldname, "/dev/null") || !oldsum) { - printf("creating %s\n", name); - s = strrchr(name, '/'); - if (s) { - *s = 0; - xmkpath(name, -1); - *s = '/'; - } - TT.filein = xcreate(name, O_CREAT|O_EXCL|O_RDWR, 0666); - } else { - printf("patching %s\n", name); - TT.filein = xopen(name, O_RDWR); - } - TT.fileout = copy_tempfile(TT.filein, name, &TT.tempname); - TT.linenum = 0; - TT.hunknum = 0; - } - } - - TT.hunknum++; - - continue; - } - - // If we didn't continue above, discard this line. - free(patchline); - } - - finish_oldfile(); - - if (CFG_TOYBOX_FREE) { - close(TT.filepatch); - free(oldname); - free(newname); - } -} diff -r 2d7c56913fda -r 2986aa63a021 toys/pidof.c --- a/toys/pidof.c Sat Aug 25 14:24:24 2012 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,32 +0,0 @@ -/* vi: set sw=4 ts=4: - * - * pidof.c - Print the PIDs of all processes with the given names. - * - * Copyright 2012 Andreas Heck - * - * Not in SUSv4. - -USE_PIDOF(NEWTOY(pidof, "<1", TOYFLAG_USR|TOYFLAG_BIN)) - -config PIDOF - bool "pidof" - default y - help - usage: pidof [NAME]... - - Print the PIDs of all processes with the given names. -*/ - -#include "toys.h" - -static void print_pid(pid_t pid) { - xprintf("%s%ld", toys.exitval ? "" : " ", (long)pid); - toys.exitval = 0; -} - -void pidof_main(void) -{ - toys.exitval = 1; - for_each_pid_with_name_in(toys.optargs, print_pid); - if (!toys.exitval) xputc('\n'); -} diff -r 2d7c56913fda -r 2986aa63a021 toys/posix/basename.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/toys/posix/basename.c Sat Aug 25 14:25:22 2012 -0500 @@ -0,0 +1,45 @@ +/* vi: set sw=4 ts=4: + * + * basename.c - Return non-directory portion of a pathname + * + * Copyright 2012 Tryn Mirell + * + * See http://opengroup.org/onlinepubs/9699919799/utilities/basename.html + + +USE_BASENAME(NEWTOY(basename, "<1>2", TOYFLAG_USR|TOYFLAG_BIN)) + +config BASENAME + bool "basename" + default y + help + usage: basename string [suffix] + + Return non-directory portion of a pathname removing suffix +*/ + +#include "toys.h" + +void basename_main(void) +{ + char *arg = toys.optargs[0], *suffix = toys.optargs[1], *base; + + while ((base = strrchr(arg, '/'))) { + if (base == arg) break; + if (!base[1]) *base = 0; + else { + base++; + break; + } + } + + if (!base) base = arg; + + // chop off the suffix if provided + if (suffix) { + arg = base + strlen(base) - strlen(suffix); + if (arg > base && !strcmp(arg, suffix)) *arg = 0; + } + + puts(base); +} diff -r 2d7c56913fda -r 2986aa63a021 toys/posix/cal.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/toys/posix/cal.c Sat Aug 25 14:25:22 2012 -0500 @@ -0,0 +1,134 @@ +/* vi: set sw=4 ts=4: + * + * cal.c - show calendar. + * + * Copyright 2011 Rob Landley + * + * See http://opengroup.org/onlinepubs/9699919799/utilities/cal.html + +USE_CAL(NEWTOY(cal, ">2", TOYFLAG_USR|TOYFLAG_BIN)) + +config CAL + bool "cal" + default y + help + usage: cal [[month] year] + Print a calendar. + + With one argument, prints all months of the specified year. + With two arguments, prints calendar for month and year. +*/ + +#include "toys.h" + +// Write calendar into buffer: each line is 20 chars wide, end indicated +// by empty string. + +static char *calstrings(char *buf, struct tm *tm) +{ + char temp[21]; + int wday, mday, start, len, line; + + // header + len = strftime(temp, 21, "%B %Y", tm); + len += (20-len)/2; + buf += sprintf(buf, "%*s%*s ", len, temp, 20-len, ""); + buf++; + buf += sprintf(buf, "Su Mo Tu We Th Fr Sa "); + buf++; + + // What day of the week does this month start on? + if (tm->tm_mday>1) + start = (36+tm->tm_wday-tm->tm_mday)%7; + else start = tm->tm_wday; + + // What day does this month end on? Alas, libc doesn't tell us... + len = 31; + if (tm->tm_mon == 1) { + int year = tm->tm_year; + len = 28; + if (!(year & 3) && !((year&100) && !(year&400))) len++; + } else if ((tm->tm_mon+(tm->tm_mon>6 ? 1 : 0)) & 1) len = 30; + + for (mday=line=0;line<6;line++) { + for (wday=0; wday<7; wday++) { + char *pat = " "; + if (!mday ? wday==start : mday high) error_exit(err, val, "greater", high); +} + +// Worst case scenario toybuf usage: sizeof(struct tm) plus 21 bytes/line +// plus 8 lines/month plus 12 months, comes to a bit over 2k of our 4k buffer. + +void cal_main(void) +{ + struct tm *tm; + char *buf = toybuf; + + if (toys.optc) { + // Conveniently starts zeroed + tm = (struct tm *)toybuf; + buf += sizeof(struct tm); + + // Last argument is year, one before that (if any) is month. + xcheckrange(tm->tm_year = atol(toys.optargs[--toys.optc]),1,9999); + tm->tm_year -= 1900; + tm->tm_mday = 1; + tm->tm_hour = 12; // noon to avoid timezone weirdness + if (toys.optc) { + xcheckrange(tm->tm_mon = atol(toys.optargs[--toys.optc]),1,12); + tm->tm_mon--; + + // Print 12 months of the year + + } else { + char *bufs[12]; + int i, j, k; + + for (i=0; i<12; i++) { + tm->tm_mon=i; + mktime(tm); + buf = calstrings(bufs[i]=buf, tm); + } + + // 4 rows, 6 lines each, 3 columns + for (i=0; i<4; i++) { + for (j=0; j<8; j++) { + for(k=0; k<3; k++) { + char **b = bufs+(k+i*3); + *b += printf("%s ", *b); + } + puts(""); + } + } + return; + } + + // What day of the week does that start on? + mktime(tm); + + } else { + time_t now; + time(&now); + tm = localtime(&now); + } + + calstrings(buf, tm); + while (*buf) buf += printf("%s\n", buf); +} diff -r 2d7c56913fda -r 2986aa63a021 toys/posix/cat.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/toys/posix/cat.c Sat Aug 25 14:25:22 2012 -0500 @@ -0,0 +1,42 @@ +/* vi: set sw=4 ts=4: + * + * cat.c - copy inputs to stdout. + * + * Copyright 2006 Rob Landley + * + * See http://www.opengroup.org/onlinepubs/009695399/utilities/cat.html + +USE_CAT(NEWTOY(cat, "u", TOYFLAG_BIN)) + +config CAT + bool "cat" + default y + help + usage: cat [-u] [file...] + Copy (concatenate) files to stdout. If no files listed, copy from stdin. + Filename "-" is a synonym for stdin. + + -u Copy one byte at a time (slow). +*/ + +#include "toys.h" + +static void do_cat(int fd, char *name) +{ + int len, size=toys.optflags ? 1 : sizeof(toybuf); + + for (;;) { + len = read(fd, toybuf, size); + if (len<0) { + perror_msg("%s",name); + toys.exitval = EXIT_FAILURE; + } + if (len<1) break; + xwrite(1, toybuf, len); + } +} + +void cat_main(void) +{ + loopfiles(toys.optargs, do_cat); +} diff -r 2d7c56913fda -r 2986aa63a021 toys/posix/chgrp.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/toys/posix/chgrp.c Sat Aug 25 14:25:22 2012 -0500 @@ -0,0 +1,124 @@ +/* vi: set sw=4 ts=4: + * + * chown.c - Change ownership + * + * Copyright 2012 Georgi Chorbadzhiyski + * + * See http://pubs.opengroup.org/onlinepubs/009695399/utilities/chown.html + * See http://pubs.opengroup.org/onlinepubs/009695399/utilities/chgrp.html + * + * TODO: group only one of [HLP] + +USE_CHGRP(NEWTOY(chgrp, "<2hPLHRfv", TOYFLAG_BIN)) +USE_CHGRP(OLDTOY(chown, chgrp, "<2hPLHRfv", TOYFLAG_BIN)) + +config CHGRP + bool "chgrp/chown" + default y + help + usage: chown [-RHLP] [-fvh] [owner][:group] file... + usage: chgrp [-RHLP] [-fvh] group file... + + Change ownership of one or more files. + + -f suppress most error messages. + -h change symlinks instead of what they point to + -R recurse into subdirectories (implies -h). + -H with -R change target of symlink, follow command line symlinks + -L with -R change target of symlink, follow all symlinks + -P with -R change symlink, do not follow symlinks (default) + -v verbose output. +*/ + +#include "toys.h" + +#define FLAG_v 1 +#define FLAG_f 2 +#define FLAG_R 4 +#define FLAG_H 8 +#define FLAG_L 16 +#define FLAG_P 32 +#define FLAG_h 64 + +DEFINE_GLOBALS( + uid_t owner; + gid_t group; + char *owner_name, *group_name; + int symfollow; +) + +#define TT this.chgrp + +static int do_chgrp(struct dirtree *node) +{ + int fd, ret, flags = toys.optflags; + + // Depth first search + if (!dirtree_notdotdot(node)) return 0; + if ((flags & FLAG_R) && node->data != -1 && S_ISDIR(node->st.st_mode)) + return DIRTREE_COMEAGAIN|((flags&FLAG_L) ? DIRTREE_SYMFOLLOW : 0); + + fd = dirtree_parentfd(node); + ret = fchownat(fd, node->name, TT.owner, TT.group, + (flags&(FLAG_L|FLAG_H)) || !(flags&(FLAG_h|FLAG_R)) + ? 0 : AT_SYMLINK_NOFOLLOW); + + if (ret || (flags & FLAG_v)) { + char *path = dirtree_path(node, 0); + if (flags & FLAG_v) + xprintf("%s %s%s%s %s\n", toys.which->name, + TT.owner_name ? TT.owner_name : "", + toys.which->name[2]=='o' && TT.group_name ? ":" : "", + TT.group_name ? TT.group_name : "", path); + if (ret == -1 && !(toys.optflags & FLAG_f)) + perror_msg("changing owner:group of '%s' to '%s:%s'", path, + TT.owner_name, TT.group_name); + free(path); + } + toys.exitval |= ret; + + return 0; +} + +void chgrp_main(void) +{ + int ischown = toys.which->name[2] == 'o'; + char **s, *own; + + // Distinguish chown from chgrp + if (ischown) { + char *grp; + struct passwd *p; + + own = xstrdup(*toys.optargs); + if ((grp = strchr(own, ':')) || (grp = strchr(own, '.'))) { + *(grp++) = 0; + TT.group_name = grp; + } + if (*own) { + TT.owner_name = own; + p = getpwnam(own); + // TODO: trailing garbage? + if (!p && isdigit(*own)) p=getpwuid(atoi(own)); + if (!p) error_exit("no user '%s'", own); + TT.owner = p->pw_uid; + } + } else TT.group_name = *toys.optargs; + + if (TT.group_name) { + struct group *g; + g = getgrnam(TT.group_name); + if (!g) g=getgrgid(atoi(TT.group_name)); + if (!g) error_exit("no group '%s'", TT.group_name); + TT.group = g->gr_gid; + } + + for (s=toys.optargs+1; *s; s++) { + struct dirtree *new = dirtree_add_node(AT_FDCWD, *s, + toys.optflags&(FLAG_H|FLAG_L)); + if (new) handle_callback(new, do_chgrp); + else toys.exitval = 1; + } + + if (CFG_TOYBOX_FREE) free(own); +} diff -r 2d7c56913fda -r 2986aa63a021 toys/posix/chmod.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/toys/posix/chmod.c Sat Aug 25 14:25:22 2012 -0500 @@ -0,0 +1,72 @@ +/* vi: set sw=4 ts=4: + * + * chmod.c - Change file mode bits + * + * Copyright 2012 Rob Landley + * + * See http://pubs.opengroup.org/onlinepubs/009695399/utilities/chmod.html + * + +USE_CHMOD(NEWTOY(chmod, "<2?vR", TOYFLAG_BIN)) + +config CHMOD + bool "chmod" + default y + help + usage: chmod [-R] MODE FILE... + + Change mode of listed file[s] (recursively with -R). + + MODE can be (comma-separated) stanzas: [ugoa][+-=][rwxstXugo] + + Stanzas are applied in order: For each category (u = user, + g = group, o = other, a = all three, if none specified default is a), + set (+), clear (-), or copy (=), r = read, w = write, x = execute. + s = u+s = suid, g+s = sgid, o+s = sticky. (+t is an alias for o+s). + suid/sgid: execute as the user/group who owns the file. + sticky: can't delete files you don't own out of this directory + X = x for directories or if any category already has x set. + + Or MODE can be an octal value up to 7777 ug uuugggooo top + + bit 1 = o+x, bit 1<<8 = u+w, 1<<11 = g+1 sstrwxrwxrwx bottom + + Examples: + chmod u+w file - allow owner of "file" to write to it. + chmod 744 file - user can read/write/execute, everyone else read only +*/ + +#include "toys.h" + +DEFINE_GLOBALS( + char *mode; +) + +#define TT this.chmod + +#define FLAG_R 1 +#define FLAG_v 2 + +int do_chmod(struct dirtree *try) +{ + mode_t mode; + + if (!dirtree_notdotdot(try)) return 0; + + mode = string_to_mode(TT.mode, try->st.st_mode); + if (toys.optflags & FLAG_v) { + char *s = dirtree_path(try, 0); + printf("chmod '%s' to %04o\n", s, mode); + free(s); + } + wfchmodat(dirtree_parentfd(try), try->name, mode); + + return (toys.optflags & FLAG_R) ? DIRTREE_RECURSE : 0; +} + +void chmod_main(void) +{ + TT.mode = *toys.optargs; + char **file; + + for (file = toys.optargs+1; *file; file++) dirtree_read(*file, do_chmod); +} diff -r 2d7c56913fda -r 2986aa63a021 toys/posix/cksum.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/toys/posix/cksum.c Sat Aug 25 14:25:22 2012 -0500 @@ -0,0 +1,87 @@ +/* vi: set sw=4 ts=4: + * + * cksum.c - produce crc32 checksum value for each input + * + * Copyright 2008 Rob Landley + * + * See http://www.opengroup.org/onlinepubs/009695399/utilities/cksum.html + +USE_CKSUM(NEWTOY(cksum, "IPLN", TOYFLAG_BIN)) + +config CKSUM + bool "cksum" + default y + help + usage: cksum [-IPLN] [file...] + + For each file, output crc32 checksum value, length and name of file. + If no files listed, copy from stdin. Filename "-" is a synonym for stdin. + + -L Little endian (defaults to big endian) + -P Pre-inversion + -I Skip post-inversion + -N Do not include length in CRC calculation +*/ + +#include "toys.h" + +DEFINE_GLOBALS( + unsigned crc_table[256]; +) + +#define TT this.cksum + +static unsigned cksum_be(unsigned crc, unsigned char c) +{ + return (crc<<8)^TT.crc_table[(crc>>24)^c]; +} + +static unsigned cksum_le(unsigned crc, unsigned char c) +{ + return TT.crc_table[(crc^c)&0xff] ^ (crc>>8); +} + +static void do_cksum(int fd, char *name) +{ + unsigned crc = (toys.optflags&4) ? 0xffffffff : 0; + uint64_t llen = 0, llen2; + unsigned (*cksum)(unsigned crc, unsigned char c); + + + cksum = (toys.optflags&2) ? cksum_le : cksum_be; + // CRC the data + + for (;;) { + int len, i; + + len = read(fd, toybuf, sizeof(toybuf)); + if (len<0) { + perror_msg("%s",name); + toys.exitval = EXIT_FAILURE; + } + if (len<1) break; + + llen += len; + for (i=0; i>= 8; + } + } + + printf("%u %"PRIu64, (toys.optflags&8) ? crc : ~crc, llen2); + if (strcmp("-", name)) printf(" %s", name); + xputc('\n'); +} + +void cksum_main(void) +{ + crc_init(TT.crc_table, toys.optflags&2); + loopfiles(toys.optargs, do_cksum); +} diff -r 2d7c56913fda -r 2986aa63a021 toys/posix/cmp.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/toys/posix/cmp.c Sat Aug 25 14:25:22 2012 -0500 @@ -0,0 +1,92 @@ +/* vi: set sw=4 ts=4: + * + * cmp.c - Compare two files. + * + * Copyright 2012 Timothy Elliott + * + * See http://pubs.opengroup.org/onlinepubs/9699919799/utilities/cmp.html + +USE_CMP(NEWTOY(cmp, "<2>2ls", TOYFLAG_USR|TOYFLAG_BIN)) + +config CMP + bool "cmp" + default y + help + usage: cmp [-l] [-s] FILE1 FILE2 + + Compare the contents of two files. + + -l show all differing bytes + -s silent +*/ + +#include "toys.h" + +#define FLAG_s 1 +#define FLAG_l 2 + +DEFINE_GLOBALS( + int fd; + char *name; +) + +#define TT this.cmp + +// This handles opening the file and + +void do_cmp(int fd, char *name) +{ + int i, len1, len2, min_len, size = sizeof(toybuf)/2; + long byte_no = 1, line_no = 1; + char *buf2 = toybuf+size; + + // First time through, cache the data and return. + if (!TT.fd) { + TT.name = name; + // On return the old filehandle is closed, and this assures that even + // if we were called with stdin closed, the new filehandle != 0. + TT.fd = dup(fd); + return; + } + + for (;;) { + len1 = readall(TT.fd, toybuf, size); + len2 = readall(fd, buf2, size); + + min_len = len1 < len2 ? len1 : len2; + for (i=0; i + * + * See http://pubs.opengroup.org/onlinepubs/009695399/utilities/comm.html + +// <# and ># take single digit, so 321 define flags +USE_COMM(NEWTOY(comm, "<2>2321", TOYFLAG_USR|TOYFLAG_BIN)) + +config COMM + bool "comm" + default y + help + usage: comm [-123] FILE1 FILE2 + + Reads FILE1 and FILE2, which should be ordered, and produces three text + columns as output: lines only in FILE1; lines only in FILE2; and lines + in both files. Filename "-" is a synonym for stdin. + + -1 suppress the output column of lines unique to FILE1 + -2 suppress the output column of lines unique to FILE2 + -3 suppress the output column of lines duplicated in FILE1 and FILE2 +*/ + +#include "toys.h" + +#define FLAG_1 1 +#define FLAG_2 2 +#define FLAG_3 4 + +static void writeline(const char *line, int col) +{ + if (col == 0 && toys.optflags & FLAG_1) return; + else if (col == 1) { + if (toys.optflags & FLAG_2) return; + if (!(toys.optflags & FLAG_1)) putchar('\t'); + } else if (col == 2) { + if (toys.optflags & FLAG_3) return; + if (!(toys.optflags & FLAG_1)) putchar('\t'); + if (!(toys.optflags & FLAG_2)) putchar('\t'); + } + puts(line); +} + +void comm_main(void) +{ + int file[2]; + char *line[2]; + int i; + + if (toys.optflags == 7) return; + + for (i = 0; i < 2; i++) { + file[i] = strcmp("-", toys.optargs[i]) ? xopen(toys.optargs[i], O_RDONLY) : 0; + line[i] = get_line(file[i]); + } + + while (line[0] && line[1]) { + int order = strcmp(line[0], line[1]); + + if (order == 0) { + writeline(line[0], 2); + for (i = 0; i < 2; i++) { + free(line[i]); + line[i] = get_line(file[i]); + } + } else { + i = order < 0 ? 0 : 1; + writeline(line[i], i); + free(line[i]); + line[i] = get_line(file[i]); + } + } + + /* print rest of the longer file */ + for (i = line[0] ? 0 : 1; line[i];) { + writeline(line[i], i); + free(line[i]); + line[i] = get_line(file[i]); + } + + if (CFG_TOYBOX_FREE) for (i = 0; i < 2; i--) xclose(file[i]); +} diff -r 2d7c56913fda -r 2986aa63a021 toys/posix/cp.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/toys/posix/cp.c Sat Aug 25 14:25:22 2012 -0500 @@ -0,0 +1,224 @@ +/* vi: set sw=4 ts=4: + * + * cp.c - Copy files. + * + * Copyright 2008 Rob Landley + * + * See http://www.opengroup.org/onlinepubs/009695399/utilities/cp.html + * + * "R+ra+d+p+r" +USE_CP(NEWTOY(cp, "<2vslrRdpaHLPif", TOYFLAG_BIN)) + +config CP + bool "cp (broken by dirtree changes)" + default n + help + usage: cp -fiprdal SOURCE... DEST + + Copy files from SOURCE to DEST. If more than one SOURCE, DEST must + be a directory. + + -f force copy by deleting destination file + -i interactive, prompt before overwriting existing DEST + -p preserve timestamps, ownership, and permissions + -r recurse into subdirectories (DEST must be a directory) + -d don't dereference symlinks + -a same as -dpr + -l hard link instead of copying + -v verbose +*/ + +#include "toys.h" + +#define FLAG_f 1 +#define FLAG_i 2 +#define FLAG_P 4 // todo +#define FLAG_L 8 // todo +#define FLAG_H 16 // todo +#define FLAG_a 32 +#define FLAG_p 64 +#define FLAG_d 128 // todo +#define FLAG_R 256 +#define FLAG_r 512 +#define FLAG_l 1024 // todo +#define FLAG_s 2048 // todo +#define FLAG_v 4098 + +DEFINE_GLOBALS( + char *destname; + int destisdir; + int destisnew; + int keep_symlinks; +) + +#define TT this.cp + +// Copy an individual file or directory to target. + +void cp_file(char *src, char *dst, struct stat *srcst) +{ + int fdout = -1; + + // -i flag is specified and dst file exists. + if ((toys.optflags&FLAG_i) && !access(dst, R_OK) + && !yesno("cp: overwrite", 1)) + return; + + if (toys.optflags & FLAG_v) + printf("'%s' -> '%s'\n", src, dst); + + // Copy directory or file to destination. + + if (S_ISDIR(srcst->st_mode)) { + struct stat st2; + + // Always make directory writeable to us, so we can create files in it. + // + // Yes, there's a race window between mkdir() and open() so it's + // possible that -p can be made to chown a directory other than the one + // we created. The closest we can do to closing this is make sure + // that what we open _is_ a directory rather than something else. + + if ((mkdir(dst, srcst->st_mode | 0200) && errno != EEXIST) + || 0>(fdout=open(dst, 0)) || fstat(fdout, &st2) + || !S_ISDIR(st2.st_mode)) + { + perror_exit("mkdir '%s'", dst); + } + } else if (TT.keep_symlinks && S_ISLNK(srcst->st_mode)) { + char *link = xreadlink(src); + + // Note: -p currently has no effect on symlinks. How do you get a + // filehandle to them? O_NOFOLLOW causes the open to fail. + if (!link || symlink(link, dst)) perror_msg("link '%s'", dst); + free(link); + return; + } else if (toys.optflags & FLAG_l) { + if (link(src, dst)) perror_msg("link '%s'"); + return; + } else { + int fdin, i; + + fdin = xopen(src, O_RDONLY); + for (i=2 ; i; i--) { + fdout = open(dst, O_RDWR|O_CREAT|O_TRUNC, srcst->st_mode); + if (fdout>=0 || !(toys.optflags & FLAG_f)) break; + unlink(dst); + } + if (fdout<0) perror_exit("%s", dst); + xsendfile(fdin, fdout); + close(fdin); + } + + // Inability to set these isn't fatal, some require root access. + // Can't do fchmod() etc here because -p works on mkdir, too. + + if (toys.optflags & (FLAG_p|FLAG_a)) { + int mask = umask(0); + struct utimbuf ut; + + (void) fchown(fdout,srcst->st_uid, srcst->st_gid); + ut.actime = srcst->st_atime; + ut.modtime = srcst->st_mtime; + utime(dst, &ut); + umask(mask); + } + xclose(fdout); +} + +// Callback from dirtree_read() for each file/directory under a source dir. + +int cp_node(struct dirtree *node) +{ + char *path = dirtree_path(node, 0); // TODO: use openat() instead + char *s = path+strlen(path); + struct dirtree *n; + + // Find appropriate chunk of path for destination. + + n = node; + if (!TT.destisdir) n = n->parent; + for (;;n = n->parent) { + while (s!=path) { + if (*(--s)=='/') break; + } + if (!n) break; + } + if (s != path) s++; + + s = xmsprintf("%s/%s", TT.destname, s); + cp_file(path, s, &(node->st)); + free(s); + free(path); // redo this whole darn function. + + return 0; +} + +void cp_main(void) +{ + struct stat st; + int i; + + // Grab target argument. (Guaranteed to be there due to "<2" above.) + + TT.destname = toys.optargs[--toys.optc]; + + // If destination doesn't exist, are we ok with that? + + if (stat(TT.destname, &st)) { + if (toys.optc>1) goto error_notdir; + TT.destisnew++; + + // If destination exists... + + } else { + if (S_ISDIR(st.st_mode)) TT.destisdir++; + else if (toys.optc > 1) goto error_notdir; + } + + // Handle sources + + for (i=0; i + * + * See http://pubs.opengroup.org/onlinepubs/9699919799/utilities/date.html + +USE_DATE(NEWTOY(date, "r:u", TOYFLAG_BIN)) + +config DATE + bool "date" + default y + help + usage: date [-u] [-r file] [+format] | mmddhhmm[[cc]yy] + + Set/get the current date/time +*/ + +#include "toys.h" + +DEFINE_GLOBALS( + char *file; +) + +#define TT this.date + +#define FLAG_u 1 +#define FLAG_r 2 + +void date_main(void) +{ + const char *format_string = "%a %b %e %H:%M:%S %Z %Y"; + time_t now = time(NULL); + struct tm tm; + + if (TT.file) { + struct stat st; + + xstat(TT.file, &st); + now = st.st_mtim.tv_sec; + } + ((toys.optflags & FLAG_u) ? gmtime_r : localtime_r)(&now, &tm); + + // Display the date? + if (!toys.optargs[0] || toys.optargs[0][0] == '+') { + if (toys.optargs[0]) format_string = toys.optargs[0]+1; + if (!strftime(toybuf, sizeof(toybuf), format_string, &tm)) + perror_msg("bad format `%s'", format_string); + + puts(toybuf); + + // Set the date + } else { + struct timeval tv; + char *s = *toys.optargs; + int len = strlen(s); + + if (len < 8 || len > 12 || (len & 1)) error_msg("bad date `%s'", s); + + // Date format: mmddhhmm[[cc]yy] + memset(&tm, 0, sizeof(tm)); + len = sscanf(s, "%2u%2u%2u%2u", &tm.tm_mon, &tm.tm_mday, &tm.tm_hour, + &tm.tm_min); + tm.tm_mon--; + + // If year specified, overwrite one we fetched earlier + if (len > 8) { + sscanf(s, "%u", &tm.tm_year); + if (len == 12) tm.tm_year -= 1900; + /* 69-99 = 1969-1999, 0 - 68 = 2000-2068 */ + else if (tm.tm_year < 69) tm.tm_year += 100; + } + + if (toys.optflags & FLAG_u) { + // Get the UTC version of a struct tm + char *tz = CFG_TOYBOX_FREE ? getenv("TZ") : 0; + setenv("TZ", "UTC", 1); + tzset(); + tv.tv_sec = mktime(&tm); + if (CFG_TOYBOX_FREE) { + if (tz) setenv("TZ", tz, 1); + else unsetenv("TZ"); + tzset(); + } + } else tv.tv_sec = mktime(&tm); + + if (tv.tv_sec == (time_t)-1) error_msg("bad `%s'", toys.optargs[0]); + tv.tv_usec = 0; + if (!strftime(toybuf, sizeof(toybuf), format_string, &tm)) + perror_msg("bad format `%s'", format_string); + puts(toybuf); + if (settimeofday(&tv, NULL) < 0) perror_msg("cannot set date"); + } +} diff -r 2d7c56913fda -r 2986aa63a021 toys/posix/df.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/toys/posix/df.c Sat Aug 25 14:25:22 2012 -0500 @@ -0,0 +1,154 @@ +/* vi: set sw=4 ts=4: + * + * df.c - report free disk space. + * + * Copyright 2006 Rob Landley + * + * See http://www.opengroup.org/onlinepubs/009695399/utilities/df.html + +USE_DF(NEWTOY(df, "Pkt*a", TOYFLAG_USR|TOYFLAG_SBIN)) + +config DF + bool "df (disk free)" + default y + help + usage: df [-t type] [FILESYSTEM ...] + + The "disk free" command, df shows total/used/available disk space for + each filesystem listed on the command line, or all currently mounted + filesystems. + + -t type + Display only filesystems of this type. + +config DF_PEDANTIC + bool "options -P and -k" + default y + depends on DF + help + usage: df [-Pk] + + -P The SUSv3 "Pedantic" option + + Provides a slightly less useful output format dictated by + the Single Unix Specification version 3, and sets the + units to 512 bytes instead of the default 1024 bytes. + + -k Sets units back to 1024 bytes (the default without -P) +*/ + +#include "toys.h" + +DEFINE_GLOBALS( + struct arg_list *fstype; + + long units; +) + +#define TT this.df + +static void show_mt(struct mtab_list *mt) +{ + int len; + long size, used, avail, percent; + uint64_t block; + + // Return if it wasn't found (should never happen, but with /etc/mtab...) + if (!mt) return; + + // If we have -t, skip other filesystem types + if (TT.fstype) { + struct arg_list *al; + + for (al = TT.fstype; al; al = al->next) { + if (!strcmp(mt->type, al->arg)) break; + } + if (!al) return; + } + + // If we don't have -a, skip synthetic filesystems + if (!(toys.optflags & 1) && !mt->statvfs.f_blocks) return; + + // Figure out how much total/used/free space this filesystem has, + // forcing 64-bit math because filesystems are big now. + block = mt->statvfs.f_bsize ? mt->statvfs.f_bsize : 1; + size = (long)((block * mt->statvfs.f_blocks) / TT.units); + used = (long)((block * (mt->statvfs.f_blocks-mt->statvfs.f_bfree)) + / TT.units); + avail = (long)((block + * (getuid() ? mt->statvfs.f_bavail : mt->statvfs.f_bfree)) + / TT.units); + percent = size ? 100-(long)((100*(uint64_t)avail)/size) : 0; + + // Figure out appropriate spacing + len = 25 - strlen(mt->device); + if (len < 1) len = 1; + if (CFG_DF_PEDANTIC && (toys.optflags & 8)) { + printf("%s %ld %ld %ld %ld%% %s\n", mt->device, size, used, avail, + percent, mt->dir); + } else { + printf("%s% *ld % 10ld % 9ld % 3ld%% %s\n",mt->device, len, + size, used, avail, percent, mt->dir); + } +} + +void df_main(void) +{ + struct mtab_list *mt, *mt2, *mtlist; + + // Handle -P and -k + TT.units = 1024; + if (CFG_DF_PEDANTIC && (toys.optflags & 8)) { + // Units are 512 bytes if you select "pedantic" without "kilobytes". + if ((toys.optflags&3) == 1) TT.units = 512; + printf("Filesystem %ld-blocks Used Available Capacity Mounted on\n", + TT.units); + } else puts("Filesystem\t1K-blocks\tUsed Available Use% Mounted on"); + + mtlist = getmountlist(1); + + // If we have a list of filesystems on the command line, loop through them. + if (*toys.optargs) { + char **next; + + for(next = toys.optargs; *next; next++) { + struct stat st; + + // Stat it (complain if we can't). + if(stat(*next, &st)) { + perror_msg("`%s'", *next); + toys.exitval = 1; + continue; + } + + // Find and display this filesystem. Use _last_ hit in case of + // -- bind mounts. + mt2 = NULL; + for (mt = mtlist; mt; mt = mt->next) + if (st.st_dev == mt->stat.st_dev) mt2 = mt; + show_mt(mt2); + } + } else { + // Get and loop through mount list. + + for (mt = mtlist; mt; mt = mt->next) { + struct mtab_list *mt2, *mt3; + + if (!mt->stat.st_dev) continue; + + // Filter out overmounts. + mt3 = mt; + for (mt2 = mt->next; mt2; mt2 = mt2->next) { + if (mt->stat.st_dev == mt2->stat.st_dev) { + // For --bind mounts, take last match + if (!strcmp(mt->device, mt2->device)) mt3 = mt2; + // Filter out overmounts + mt2->stat.st_dev = 0; + } + } + show_mt(mt3); + } + } + + if (CFG_TOYBOX_FREE) llist_traverse(mtlist, free); +} diff -r 2d7c56913fda -r 2986aa63a021 toys/posix/dirname.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/toys/posix/dirname.c Sat Aug 25 14:25:22 2012 -0500 @@ -0,0 +1,25 @@ +/* vi: set sw=4 ts=4: + * + * dirname.c - show directory portion of path + * + * Copyright 2011 Rob Landley + * + * See http://opengroup.org/onlinepubs/9699919799/utilities/dirname.html + +USE_DIRNAME(NEWTOY(dirname, "<1", TOYFLAG_USR|TOYFLAG_BIN)) + +config DIRNAME + bool "dirname" + default y + help + usage: dirname PATH + + Show directory portion of path. +*/ + +#include "toys.h" + +void dirname_main(void) +{ + puts(dirname(*toys.optargs)); +} diff -r 2d7c56913fda -r 2986aa63a021 toys/posix/echo.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/toys/posix/echo.c Sat Aug 25 14:25:22 2012 -0500 @@ -0,0 +1,97 @@ +/* vi: set sw=4 ts=4: + * + * echo.c - echo supporting -n and -e. + * + * Copyright 2007 Rob Landley + * + * See http://www.opengroup.org/onlinepubs/009695399/utilities/echo.html + +USE_ECHO(NEWTOY(echo, "^?en", TOYFLAG_BIN)) + +config ECHO + bool "echo" + default y + help + usage: echo [-ne] [args...] + + Write each argument to stdout, with one space between each, followed + by a newline. + + -n No trailing newline. + -e Process the following escape sequences: + \\ backslash + \0NNN octal values (1 to 3 digits) + \a alert (beep/flash) + \b backspace + \c stop output here (avoids trailing newline) + \f form feed + \n newline + \r carriage return + \t horizontal tab + \v vertical tab + \xHH hexadecimal values (1 to 2 digits) +*/ + +#define THIS echo +#include "toys.h" + +#define FLAG_e (1<<1) +#define FLAG_n (1<<0) + +void echo_main(void) +{ + int i = 0, out; + char *arg, *from = "\\abfnrtv", *to = "\\\a\b\f\n\r\t\v", *c; + + for (;;) { + arg = toys.optargs[i]; + if (!arg) break; + if (i++) xputc(' '); + + // Should we output arg verbatim? + + if (!(toys.optflags&FLAG_e)) { + xprintf("%s", arg); + continue; + } + + // Handle -e + + for (c=arg;;) { + if (!(out = *(c++))) break; + + // handle \escapes + if (out == '\\' && *c) { + int n = 0, slash = *(c++); + char *found = strchr(from, slash); + if (found) out = to[found-from]; + else if (slash == 'c') goto done; + else if (slash == '0') { + out = 0; + while (*c>='0' && *c<='7' && n++<3) + out = (out*8)+*(c++)-'0'; + } else if (slash == 'x') { + out = 0; + while (n++<2) { + if (*c>='0' && *c<='9') + out = (out*16)+*(c++)-'0'; + else { + int temp = tolower(*c); + if (temp>='a' && temp<='f') { + out = (out*16)+temp-'a'+10; + c++; + } else break; + } + } + // Slash in front of unknown character, print literal. + } else c--; + } + xputc(out); + } + } + + // Output "\n" if no -n + if (!(toys.optflags&FLAG_n)) xputc('\n'); +done: + xflush(); +} diff -r 2d7c56913fda -r 2986aa63a021 toys/posix/env.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/toys/posix/env.c Sat Aug 25 14:25:22 2012 -0500 @@ -0,0 +1,52 @@ +/* vi: set sw=4 ts=4: + * + * env.c - Set the environment for command invocation. + * + * Copyright 2012 Tryn Mirell + * env.c + +USE_ENV(NEWTOY(env, "^i", TOYFLAG_USR|TOYFLAG_BIN)) + +config ENV + bool "env" + default y + help + usage: env [-i] [NAME=VALUE...] [command [option...]] + + Set the environment for command invocation. + + -i Clear existing environment. +*/ + +#include "toys.h" + +extern char **environ; + +void env_main(void) +{ + char **ev; + char **command = NULL; + char *del = "="; + + if (toys.optflags & 1) clearenv(); + + for (ev = toys.optargs; *ev != NULL; ev++) { + char *env, *val = NULL; + + env = strtok(*ev, del); + + if (env) val = strtok(NULL, del); + + if (val) setenv(env, val, 1); + else { + command = ev; + break; + } + } + + if (!command) { + char **ep; + for (ep = environ; *ep; ep++) xputs(*ep); + return; + } else xexec(command); +} diff -r 2d7c56913fda -r 2986aa63a021 toys/posix/false.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/toys/posix/false.c Sat Aug 25 14:25:22 2012 -0500 @@ -0,0 +1,23 @@ +/* vi: set sw=4 ts=4: + * + * false.c - Return nonzero. + * + * Copyright 2007 Rob Landley + * + * See http://www.opengroup.org/onlinepubs/009695399/utilities/false.html + +USE_FALSE(NEWTOY(false, NULL, TOYFLAG_BIN)) + +config FALSE + bool "false" + default y + help + Return nonzero. +*/ + +#include "toys.h" + +void false_main(void) +{ + toys.exitval = 1; +} diff -r 2d7c56913fda -r 2986aa63a021 toys/posix/head.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/toys/posix/head.c Sat Aug 25 14:25:22 2012 -0500 @@ -0,0 +1,61 @@ +/* vi: set sw=4 ts=4: + * + * head.c - copy first lines from input to stdout. + * + * Copyright 2006 Timothy Elliott + * + * See http://www.opengroup.org/onlinepubs/009695399/utilities/head.html + +USE_HEAD(NEWTOY(head, "n#<0=10", TOYFLAG_BIN)) + +config HEAD + bool "head" + default y + help + usage: head [-n number] [file...] + + Copy first lines from files to stdout. If no files listed, copy from + stdin. Filename "-" is a synonym for stdin. + + -n Number of lines to copy. +*/ + +#include "toys.h" + +DEFINE_GLOBALS( + long lines; + int file_no; +) + +#define TT this.head + +static void do_head(int fd, char *name) +{ + int i, len, lines=TT.lines, size=sizeof(toybuf); + + if (toys.optc > 1) { + // Print an extra newline for all but the first file + if (TT.file_no++) xprintf("\n"); + xprintf("==> %s <==\n", name); + xflush(); + } + + while (lines) { + len = read(fd, toybuf, size); + if (len<0) { + perror_msg("%s",name); + toys.exitval = EXIT_FAILURE; + } + if (len<1) break; + + for(i=0; i + * + * See http://www.opengroup.org/onlinepubs/009695399/utilities/id.html + +USE_ID(NEWTOY(id, "nGgru", TOYFLAG_BIN)) + +config ID + bool "id" + default y + help + usage: id [-nGgru] + + Print user and group ID. + + -n print names instead of numeric IDs (to be used with -Ggu) + -G Show only the group IDs + -g Show only the effective group ID + -r Show real ID instead of effective ID + -u Show only the effective user ID +*/ + +#include "toys.h" + +#define FLAG_n (1<<4) +#define FLAG_G (1<<3) +#define FLAG_g (1<<2) +#define FLAG_r (1<<1) +#define FLAG_u 1 + +static void s_or_u(char *s, unsigned u, int done) +{ + if (toys.optflags & FLAG_n) printf("%s", s); + else printf("%u", u); + if (done) { + xputc('\n'); + exit(0); + } +} + +static void showid(char *header, unsigned u, char *s) +{ + printf("%s%u(%s)", header, u, s); +} + +struct passwd *xgetpwuid(uid_t uid) +{ + struct passwd *pwd = getpwuid(uid); + if (!pwd) error_exit(NULL); + return pwd; +} + +struct group *xgetgrgid(gid_t gid) +{ + struct group *group = getgrgid(gid); + if (!group) error_exit(NULL); + return group; +} + +void id_main(void) +{ + int flags = toys.optflags, i, ngroups; + struct passwd *pw; + struct group *grp; + uid_t uid = getuid(), euid = geteuid(); + gid_t gid = getgid(), egid = getegid(), *groups; + + /* check if a username is given */ + if (*toys.optargs) { + if (!(pw = getpwnam(*toys.optargs))) + error_exit("no such user '%s'", *toys.optargs); + uid = euid = pw->pw_uid; + gid = egid = pw->pw_gid; + } + + i = toys.optflags & FLAG_r; + pw = xgetpwuid(i ? uid : euid); + if (flags & FLAG_u) s_or_u(pw->pw_name, pw->pw_uid, 1); + + grp = xgetgrgid(i ? gid : egid); + if (flags & FLAG_g) s_or_u(grp->gr_name, grp->gr_gid, 1); + + if (!(flags & FLAG_G)) { + showid("uid=", pw->pw_uid, pw->pw_name); + showid(" gid=", grp->gr_gid, grp->gr_name); + + if (!i) { + if (uid != euid) { + pw = xgetpwuid(euid); + showid(" euid=", pw->pw_uid, pw->pw_name); + } + if (gid != egid) { + grp = xgetgrgid(egid); + showid(" egid=", grp->gr_gid, grp->gr_name); + } + } + + showid(" groups=", grp->gr_gid, grp->gr_name); + } + + + groups = (gid_t *)toybuf; + if (0 >= (ngroups = getgroups(sizeof(toybuf)/sizeof(gid_t), groups))) + perror_exit(0); + + for (i = 0; i < ngroups; i++) { + xputc(' '); + if (!(grp = getgrgid(groups[i]))) perror_msg(0); + else if (flags & FLAG_G) + s_or_u(grp->gr_name, grp->gr_gid, 0); + else if (grp->gr_gid != egid) showid("", grp->gr_gid, grp->gr_name); + } + xputc('\n'); +} diff -r 2d7c56913fda -r 2986aa63a021 toys/posix/kill.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/toys/posix/kill.c Sat Aug 25 14:25:22 2012 -0500 @@ -0,0 +1,74 @@ +/* vi: set sw=4 ts=4: + * + * kill.c - a program to send signals to processes + * + * Copyright 2012 Daniel Walter + * + * See http://opengroup.org/onlinepubs/9699919799/utilities/kill.html + +USE_KILL(NEWTOY(kill, "?s: l", TOYFLAG_BIN)) + +config KILL + bool "kill" + default y + help + usage: kill [-l [SIGNAL] | -s SIGNAL | -SIGNAL] pid... + + Send a signal to a process + +*/ + +#include "toys.h" + +DEFINE_GLOBALS( + char *signame; +) + +#define TT this.kill + +void kill_main(void) +{ + int signum; + char *tmp, **args = toys.optargs; + pid_t pid; + + // list signal(s) + if (toys.optflags & 1) { + if (*args) { + int signum = sig_to_num(*args); + char *s = NULL; + + if (signum>=0) s = num_to_sig(signum&127); + puts(s ? s : "UNKNOWN"); + } else sig_to_num(NULL); + return; + } + + // signal must come before pids, so "kill -9 -1" isn't confusing. + + if (!TT.signame && *args && **args=='-') TT.signame=*(args++)+1; + if (TT.signame) { + char *arg; + int i = strtol(TT.signame, &arg, 10); + if (!*arg) arg = num_to_sig(i); + else arg = TT.signame; + + if (!arg || -1 == (signum = sig_to_num(arg))) + error_exit("Unknown signal '%s'", arg); + } else signum = SIGTERM; + + if (!*args) { + toys.exithelp++; + error_exit("missing argument"); + } + + while (*args) { + char *arg = *(args++); + + pid = strtol(arg, &tmp, 10); + if (*tmp || kill(pid, signum) < 0) { + error_msg("unknown pid '%s'", arg); + toys.exitval = EXIT_FAILURE; + } + } +} diff -r 2d7c56913fda -r 2986aa63a021 toys/posix/link.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/toys/posix/link.c Sat Aug 25 14:25:22 2012 -0500 @@ -0,0 +1,27 @@ +/* vi: set sw=4 ts=4: + * + * link.c - hardlink a file + * + * Copyright 2011 Rob Landley + * + * See http://opengroup.org/onlinepubs/9699919799/utilities/link.html + +USE_LINK(NEWTOY(link, "<2>2", TOYFLAG_USR|TOYFLAG_BIN)) + +config LINK + bool "link" + default y + help + usage: link FILE NEWLINK + + Create hardlink to a file. +*/ + +#include "toys.h" + +void link_main(void) +{ + if (link(toys.optargs[0], toys.optargs[1])) + perror_exit("couldn't link '%s' to '%s'", toys.optargs[1], + toys.optargs[0]); +} diff -r 2d7c56913fda -r 2986aa63a021 toys/posix/ln.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/toys/posix/ln.c Sat Aug 25 14:25:22 2012 -0500 @@ -0,0 +1,70 @@ +/* vi: set sw=4 ts=4: + * + * ln.c - Create filesystem links + * + * Copyright 2012 Andre Renaud + * + * See http://pubs.opengroup.org/onlinepubs/9699919799/utilities/ln.html + +USE_LN(NEWTOY(ln, "<1nfs", TOYFLAG_BIN)) + +config LN + bool "ln" + default y + help + usage: ln [-sf] [FROM...] TO + + Create a link between FROM and TO. + With only one argument, create link in current directory. + + -s Create a symbolic link + -f Force the creation of the link, even if TO already exists + -n Symlink at destination treated as file +*/ + +#include "toys.h" + +#define FLAG_s 1 +#define FLAG_f 2 +#define FLAG_n 4 + +void ln_main(void) +{ + char *dest = toys.optargs[--toys.optc], *new; + struct stat buf; + int i; + + // With one argument, create link in current directory. + if (!toys.optc) { + toys.optc++; + dest="."; + } + + // Is destination a directory? + if (((toys.optflags&FLAG_n) ? lstat : stat)(dest, &buf) + || !S_ISDIR(buf.st_mode)) + { + if (toys.optc>1) error_exit("'%s' not a directory"); + buf.st_mode = 0; + } + + for (i=0; i + * + * See http://pubs.opengroup.org/onlinepubs/9699919799/utilities/logname.html + +USE_LOGNAME(NEWTOY(logname, ">0", TOYFLAG_BIN)) + +config LOGNAME + bool "logname" + default y + help + usage: logname + + Prints the calling user's name or an error when this cannot be + determined. +*/ + +#include "toys.h" + +void logname_main(void) +{ + if (getlogin_r(toybuf, sizeof(toybuf))){ + error_exit("no login name"); + } + xputs(toybuf); +} diff -r 2d7c56913fda -r 2986aa63a021 toys/posix/ls.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/toys/posix/ls.c Sat Aug 25 14:25:22 2012 -0500 @@ -0,0 +1,493 @@ +/* vi: set sw=4 ts=4: + * + * ls.c - list files + * + * Copyright 2012 Andre Renaud + * Copyright 2012 Rob Landley + * + * See http://pubs.opengroup.org/onlinepubs/9699919799/utilities/ls.html + +// "[-Cl]" +USE_LS(NEWTOY(ls, "goACFHLRSacdfiklmnpqrstux1", TOYFLAG_BIN)) + +config LS + bool "ls" + default y + help + usage: ls [-ACFHLRSacdfiklmnpqrstux1] [directory...] + list files + + what to show: + -a all files including .hidden + -c use ctime for timestamps + -d directory, not contents + -i inode number + -k block sizes in kilobytes + -p put a '/' after directory names + -q unprintable chars as '?' + -s size (in blocks) + -u use access time for timestamps + -A list all files except . and .. + -H follow command line symlinks + -L follow symlinks + -R recursively list files in subdirectories + -F append file type indicator (/=dir, *=exe, @=symlink, |=FIFO) + + output formats: + -1 list one file per line + -C columns (sorted vertically) + -g like -l but no owner + -l long (show full details for each file) + -m comma separated + -n like -l but numeric uid/gid + -o like -l but no group + -x columns (sorted horizontally) + + sorting (default is alphabetical): + -f unsorted + -r reverse + -t timestamp + -S size +*/ + +#include "toys.h" + +#define FLAG_1 (1<<0) +#define FLAG_x (1<<1) +#define FLAG_u (1<<2) +#define FLAG_t (1<<3) +#define FLAG_s (1<<4) +#define FLAG_r (1<<5) +#define FLAG_q (1<<6) +#define FLAG_p (1<<7) +#define FLAG_n (1<<8) +#define FLAG_m (1<<9) +#define FLAG_l (1<<10) +#define FLAG_k (1<<11) +#define FLAG_i (1<<12) +#define FLAG_f (1<<13) +#define FLAG_d (1<<14) +#define FLAG_c (1<<15) +#define FLAG_a (1<<16) +#define FLAG_S (1<<17) +#define FLAG_R (1<<18) +#define FLAG_L (1<<19) +#define FLAG_H (1<<20) +#define FLAG_F (1<<21) +#define FLAG_C (1<<22) +#define FLAG_A (1<<23) +#define FLAG_o (1<<24) +#define FLAG_g (1<<25) + +// test sst output (suid/sticky in ls flaglist) + +// ls -lR starts .: then ./subdir: + +DEFINE_GLOBALS( + struct dirtree *files; + + unsigned screen_width; + int nl_title; + + // group and user can make overlapping use of the utoa() buf, so move it + char uid_buf[12]; +) + +#define TT this.ls + +void dlist_to_dirtree(struct dirtree *parent) +{ + // Turn double_list into dirtree + struct dirtree *dt = parent->child; + if (dt) { + dt->parent->next = NULL; + while (dt) { + dt->parent = parent; + dt = dt->next; + } + } +} + +static char endtype(struct stat *st) +{ + mode_t mode = st->st_mode; + if ((toys.optflags&(FLAG_F|FLAG_p)) && S_ISDIR(mode)) return '/'; + if (toys.optflags & FLAG_F) { + if (S_ISLNK(mode)) return '@'; + if (S_ISREG(mode) && (mode&0111)) return '*'; + if (S_ISFIFO(mode)) return '|'; + if (S_ISSOCK(mode)) return '='; + } + return 0; +} + +static char *getusername(uid_t uid) +{ + struct passwd *pw = getpwuid(uid); + utoa_to_buf(uid, TT.uid_buf, 12); + return pw ? pw->pw_name : TT.uid_buf; +} + +static char *getgroupname(gid_t gid) +{ + struct group *gr = getgrgid(gid); + return gr ? gr->gr_name : utoa(gid); +} + +// Figure out size of printable entry fields for display indent/wrap + +static void entrylen(struct dirtree *dt, unsigned *len) +{ + struct stat *st = &(dt->st); + unsigned flags = toys.optflags; + + *len = strlen(dt->name); + if (endtype(st)) ++*len; + if (flags & FLAG_m) ++*len; + + if (flags & FLAG_i) *len += (len[1] = numlen(st->st_ino)); + if (flags & (FLAG_l|FLAG_o|FLAG_n|FLAG_g)) { + unsigned fn = flags & FLAG_n; + len[2] = numlen(st->st_nlink); + len[3] = strlen(fn ? utoa(st->st_uid) : getusername(st->st_uid)); + len[4] = strlen(fn ? utoa(st->st_gid) : getgroupname(st->st_gid)); + len[5] = numlen(st->st_size); + } + if (flags & FLAG_s) *len += (len[6] = numlen(st->st_blocks)); +} + +static int compare(void *a, void *b) +{ + struct dirtree *dta = *(struct dirtree **)a; + struct dirtree *dtb = *(struct dirtree **)b; + int ret = 0, reverse = (toys.optflags & FLAG_r) ? -1 : 1; + + if (toys.optflags & FLAG_S) { + if (dta->st.st_size > dtb->st.st_size) ret = -1; + else if (dta->st.st_size < dtb->st.st_size) ret = 1; + } + if (toys.optflags & FLAG_t) { + if (dta->st.st_mtime > dtb->st.st_mtime) ret = -1; + else if (dta->st.st_mtime < dtb->st.st_mtime) ret = 1; + } + if (!ret) ret = strcmp(dta->name, dtb->name); + return ret * reverse; +} + +// callback from dirtree_recurse() determining how to handle this entry. + +static int filter(struct dirtree *new) +{ + int flags = toys.optflags; + + // Special case to handle enormous dirs without running out of memory. + if (flags == (FLAG_1|FLAG_f)) { + xprintf("%s\n", new->name); + return 0; + } + + if (!(flags&FLAG_f)) { + if (flags & FLAG_a) return 0; + if (!(flags & FLAG_A) && new->name[0]=='.') return 0; + } + + if (flags & FLAG_u) new->st.st_mtime = new->st.st_atime; + if (flags & FLAG_c) new->st.st_mtime = new->st.st_ctime; + if (flags & FLAG_k) new->st.st_blocks = (new->st.st_blocks + 1) / 2; + return dirtree_notdotdot(new); +} + +// For column view, calculate horizontal position (for padding) and return +// index of next entry to display. + +static unsigned long next_column(unsigned long ul, unsigned long dtlen, + unsigned columns, unsigned *xpos) +{ + unsigned long transition; + unsigned height, widecols; + + // Horizontal sort is easy + if (!(toys.optflags & FLAG_C)) { + *xpos = ul % columns; + return ul; + } + + // vertical sort + + // For -x, calculate height of display, rounded up + height = (dtlen+columns-1)/columns; + + // Sanity check: does wrapping render this column count impossible + // due to the right edge wrapping eating a whole row? + if (height*columns - dtlen >= height) { + *xpos = columns; + return 0; + } + + // Uneven rounding goes along right edge + widecols = dtlen % height; + if (!widecols) widecols = height; + transition = widecols * columns; + if (ul < transition) { + *xpos = ul % columns; + return (*xpos*height) + (ul/columns); + } + + ul -= transition; + *xpos = ul % (columns-1); + + return (*xpos*height) + widecols + (ul/(columns-1)); +} + +// Display a list of dirtree entries, according to current format +// Output types -1, -l, -C, or stream + +static void listfiles(int dirfd, struct dirtree *indir) +{ + struct dirtree *dt, **sort = 0; + unsigned long dtlen = 0, ul = 0; + unsigned width, flags = toys.optflags, totals[7], len[7], + *colsizes = (unsigned *)(toybuf+260), columns = (sizeof(toybuf)-260)/4; + + memset(totals, 0, sizeof(totals)); + + // Silently descend into single directory listed by itself on command line. + // In this case only show dirname/total header when given -R. + if (!indir->parent) { + if (!(dt = indir->child)) return; + if (S_ISDIR(dt->st.st_mode) && !dt->next && !(flags & FLAG_d)) { + dt->extra = 1; + listfiles(open(dt->name, 0), dt); + return; + } + } else { + // Read directory contents. We dup() the fd because this will close it. + indir->data = dup(dirfd); + dirtree_recurse(indir, filter, (flags&FLAG_L)); + } + + // Copy linked list to array and sort it. Directories go in array because + // we visit them in sorted order. + + for (;;) { + for (dt = indir->child; dt; dt = dt->next) { + if (sort) sort[dtlen] = dt; + dtlen++; + } + if (sort) break; + sort = xmalloc(dtlen * sizeof(void *)); + dtlen = 0; + continue; + } + + // Label directory if not top of tree, or if -R + if (indir->parent && (!indir->extra || (flags & FLAG_R))) + { + char *path = dirtree_path(indir, 0); + + if (TT.nl_title++) xputc('\n'); + xprintf("%s:\n", path); + free(path); + } + + if (!(flags & FLAG_f)) qsort(sort, dtlen, sizeof(void *), (void *)compare); + + // Find largest entry in each field for display alignment + if (flags & (FLAG_C|FLAG_x)) { + + // columns can't be more than toybuf can hold, or more than files, + // or > 1/2 screen width (one char filename, one space). + if (columns > TT.screen_width/2) columns = TT.screen_width/2; + if (columns > dtlen) columns = dtlen; + + // Try to fit as many columns as we can, dropping down by one each time + for (;columns > 1; columns--) { + unsigned c, totlen = columns; + + memset(colsizes, 0, columns*sizeof(unsigned)); + for (ul=0; ul colsizes[c]) { + totlen += *len-colsizes[c]; + colsizes[c] = *len; + if (totlen > TT.screen_width) break; + } + } + // If it fit, stop here + if (ul == dtlen) break; + } + } else if (flags & (FLAG_l|FLAG_o|FLAG_n|FLAG_g|FLAG_s)) { + unsigned long blocks = 0; + + for (ul = 0; ul totals[width]) totals[width] = len[width]; + blocks += sort[ul]->st.st_blocks; + } + + if (indir->parent) xprintf("total %lu\n", blocks); + } + + // Loop through again to produce output. + memset(toybuf, ' ', 256); + width = 0; + for (ul = 0; ulst); + mode_t mode = st->st_mode; + char et = endtype(st); + + // Skip directories at the top of the tree when -d isn't set + if (S_ISDIR(mode) && !indir->parent && !(flags & FLAG_d)) continue; + TT.nl_title=1; + + // Handle padding and wrapping for display purposes + entrylen(sort[next], len); + if (ul) { + if (flags & FLAG_m) xputc(','); + if (flags & (FLAG_C|FLAG_x)) { + if (!curcol) xputc('\n'); + } else if ((flags & FLAG_1) || width+1+*len > TT.screen_width) { + xputc('\n'); + width = 0; + } else { + xputc(' '); + width++; + } + } + width += *len; + + if (flags & FLAG_i) + xprintf("% *lu ", len[1], (unsigned long)st->st_ino); + if (flags & FLAG_s) + xprintf("% *lu ", len[6], (unsigned long)st->st_blocks); + + if (flags & (FLAG_l|FLAG_o|FLAG_n|FLAG_g)) { + struct tm *tm; + char perm[11], thyme[64], c, d, *usr, *upad, *grp, *grpad; + int i, bit; + + perm[10]=0; + for (i=0; i<9; i++) { + bit = mode & (1<st_mtime)); + strftime(thyme, sizeof(thyme), "%F %H:%M", tm); + + if (flags&FLAG_o) grp = grpad = toybuf+256; + else { + grp = (flags&FLAG_n) ? utoa(st->st_gid) + : getgroupname(st->st_gid); + grpad = toybuf+256-(totals[4]-len[4]); + } + + if (flags&FLAG_g) usr = upad = toybuf+256; + else { + upad = toybuf+255-(totals[3]-len[3]); + if (flags&FLAG_n) { + usr = TT.uid_buf; + utoa_to_buf(st->st_uid, TT.uid_buf, 12); + } else usr = getusername(st->st_uid); + } + + // Coerce the st types into something we know we can print. + xprintf("%s% *ld %s%s%s%s% *"PRId64" %s ", perm, totals[2]+1, + (long)st->st_nlink, usr, upad, grp, grpad, totals[5]+1, + (int64_t)st->st_size, thyme); + } + + if (flags & FLAG_q) { + char *p; + for (p=sort[next]->name; *p; p++) xputc(isprint(*p) ? *p : '?'); + } else xprintf("%s", sort[next]->name); + if ((flags & (FLAG_l|FLAG_o|FLAG_n|FLAG_g)) && S_ISLNK(mode)) + xprintf(" -> %s", sort[next]->symlink); + + if (et) xputc(et); + + // Pad columns + if (flags & (FLAG_C|FLAG_x)) { + curcol = colsizes[curcol] - *len; + if (curcol >= 0) xprintf("%s", toybuf+255-curcol); + } + } + + if (width) xputc('\n'); + + // Free directory entries, recursing first if necessary. + + for (ul = 0; ulst.st_mode) + || !dirtree_notdotdot(sort[ul])) continue; + + // Recurse into dirs if at top of the tree or given -R + if (!indir->parent || (flags & FLAG_R)) + listfiles(openat(dirfd, sort[ul]->name, 0), sort[ul]); + } + free(sort); + if (dirfd != AT_FDCWD) close(indir->data); +} + +void ls_main(void) +{ + char **s, *noargs[] = {".", 0}; + struct dirtree *dt; + + // Do we have an implied -1 + if (!isatty(1) || (toys.optflags&(FLAG_l|FLAG_o|FLAG_n|FLAG_g))) + toys.optflags |= FLAG_1; + else { + TT.screen_width = 80; + terminal_size(&TT.screen_width, NULL); + } + // The optflags parsing infrastructure should really do this for us, + // but currently it has "switch off when this is set", so "-dR" and "-Rd" + // behave differently + if (toys.optflags & FLAG_d) toys.optflags &= ~FLAG_R; + + // Iterate through command line arguments, collecting directories and files. + // Non-absolute paths are relative to current directory. + TT.files = dirtree_add_node(0, 0, 0); + for (s = *toys.optargs ? toys.optargs : noargs; *s; s++) { + dt = dirtree_add_node(AT_FDCWD, *s, + (toys.optflags & (FLAG_L|FLAG_H|FLAG_l))^FLAG_l); + + if (!dt) { + toys.exitval = 1; + continue; + } + + // Typecast means double_list->prev temporarirly goes in dirtree->parent + dlist_add_nomalloc((struct double_list **)&TT.files->child, + (struct double_list *)dt); + } + + // Turn double_list into dirtree + dlist_to_dirtree(TT.files); + + // Display the files we collected + listfiles(AT_FDCWD, TT.files); + + if (CFG_TOYBOX_FREE) free(TT.files); +} diff -r 2d7c56913fda -r 2986aa63a021 toys/posix/mkdir.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/toys/posix/mkdir.c Sat Aug 25 14:25:22 2012 -0500 @@ -0,0 +1,76 @@ +/* vi: set sw=4 ts=4: + * + * mkdir.c - Make directories + * + * Copyright 2012 Georgi Chorbadzhiyski + * + * See http://pubs.opengroup.org/onlinepubs/009695399/utilities/mkdir.html + * + * TODO: Add -m + +USE_MKDIR(NEWTOY(mkdir, "<1p", TOYFLAG_BIN)) + +config MKDIR + bool "mkdir" + default y + help + usage: mkdir [-p] [dirname...] + Create one or more directories. + + -p make parent directories as needed. +*/ + +#include "toys.h" + +DEFINE_GLOBALS( + long mode; +) + +#define TT this.mkdir + +static int do_mkdir(char *dir) +{ + struct stat buf; + char *s; + + // mkdir -p one/two/three is not an error if the path already exists, + // but is if "three" is a file. The others we dereference and catch + // not-a-directory along the way, but the last one we must explicitly + // test for. Might as well do it up front. + + if (!stat(dir, &buf) && !S_ISDIR(buf.st_mode)) { + errno = EEXIST; + return 1; + } + + for (s=dir; ; s++) { + char save=0; + + // Skip leading / of absolute paths. + if (s!=dir && *s == '/' && toys.optflags) { + save = *s; + *s = 0; + } else if (*s) continue; + + if (mkdir(dir, TT.mode)<0 && (!toys.optflags || errno != EEXIST)) + return 1; + + if (!(*s = save)) break; + } + + return 0; +} + +void mkdir_main(void) +{ + char **s; + + TT.mode = 0777; + + for (s=toys.optargs; *s; s++) { + if (do_mkdir(*s)) { + perror_msg("cannot create directory '%s'", *s); + toys.exitval = 1; + } + } +} diff -r 2d7c56913fda -r 2986aa63a021 toys/posix/mkfifo.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/toys/posix/mkfifo.c Sat Aug 25 14:25:22 2012 -0500 @@ -0,0 +1,47 @@ +/* vi: set sw=4 ts=4: + * + * mkfifo.c - Create FIFOs (named pipes) + * + * Copyright 2012 Georgi Chorbadzhiyski + * + * See http://pubs.opengroup.org/onlinepubs/009695399/utilities/mkfifo.html + * + * TODO: Add -m + +USE_MKFIFO(NEWTOY(mkfifo, "<1m:", TOYFLAG_BIN)) + +config MKFIFO + bool "mkfifo" + default y + help + usage: mkfifo [fifo_name...] + + Create FIFOs (named pipes). +*/ + +#include "toys.h" + +DEFINE_GLOBALS( + char *m_string; + mode_t mode; +) + +#define TT this.mkfifo +#define FLAG_m (1) + +void mkfifo_main(void) +{ + char **s; + + TT.mode = 0666; + if (toys.optflags & FLAG_m) { + TT.mode = string_to_mode(TT.m_string, 0); + } + + for (s = toys.optargs; *s; s++) { + if (mknod(*s, S_IFIFO | TT.mode, 0) < 0) { + perror_msg("cannot create fifo '%s'", *s); + toys.exitval = 1; + } + } +} diff -r 2d7c56913fda -r 2986aa63a021 toys/posix/nice.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/toys/posix/nice.c Sat Aug 25 14:25:22 2012 -0500 @@ -0,0 +1,41 @@ +/* vi: set sw=4 ts=4: + * + * nice.c - Run a program at a different niceness level. + * + * Copyright 2010 Rob Landley + * + * See http://www.opengroup.org/onlinepubs/9699919799/utilities/nice.html + +USE_NICE(NEWTOY(nice, "^<1n#", TOYFLAG_USR|TOYFLAG_BIN)) + +config NICE + bool "nice" + default y + help + usage: nice [-n PRIORITY] command [args...] + + Run a command line at an increased or decreased scheduling priority. + + Higher numbers make a program yield more CPU time, from -20 (highest + priority) to 19 (lowest). By default processes inherit their parent's + niceness (usually 0). By default this command adds 10 to the parent's + priority. Only root can set a negative niceness level. +*/ + +#include "toys.h" + +DEFINE_GLOBALS( + long priority; +) + +#define TT this.nice + +void nice_main(void) +{ + if (!toys.optflags) TT.priority = 10; + + errno = 0; + if (nice(TT.priority)==-1 && errno) perror_exit("Can't set priority"); + + xexec(toys.optargs); +} diff -r 2d7c56913fda -r 2986aa63a021 toys/posix/nohup.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/toys/posix/nohup.c Sat Aug 25 14:25:22 2012 -0500 @@ -0,0 +1,42 @@ +/* vi: set sw=4 ts=4: + * + * nohup.c - run commandline with SIGHUP blocked. + * + * Copyright 2011 Rob Landley + * + * See http://opengroup.org/onlinepubs/9699919799/utilities/nohup.html + +USE_NOHUP(NEWTOY(nohup, "<1", TOYFLAG_USR|TOYFLAG_BIN)) + +config NOHUP + bool "nohup" + default y + help + usage: nohup COMMAND [ARGS...] + + Run a command that survives the end of its terminal. + If stdin is a tty, redirect from /dev/null + If stdout is a tty, redirect to file "nohup.out" +*/ + +#include "toys.h" + +void nohup_main(void) +{ + signal(SIGHUP, SIG_IGN); + if (isatty(1)) { + close(1); + if (-1 == open("nohup.out", O_CREAT|O_APPEND|O_WRONLY, + S_IRUSR|S_IWUSR )) + { + char *temp = getenv("HOME"); + temp = xmsprintf("%s/%s", temp ? temp : "", "nohup.out"); + xcreate(temp, O_CREAT|O_APPEND|O_WRONLY, S_IRUSR|S_IWUSR); + } + } + if (isatty(0)) { + close(0); + open("/dev/null", O_RDONLY); + } + xexec(toys.optargs); +} diff -r 2d7c56913fda -r 2986aa63a021 toys/posix/od.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/toys/posix/od.c Sat Aug 25 14:25:22 2012 -0500 @@ -0,0 +1,274 @@ +/* vi: set sw=4 ts=4: + * + * od.c - Provide octal/hex dumps of data + * + * Copyright 2012 Andre Renaud + * Copyright 2012 Rob Landley + * + * See http://pubs.opengroup.org/onlinepubs/9699919799/utilities/od.html + +USE_OD(NEWTOY(od, "j#vN#xsodcbA:t*", TOYFLAG_USR|TOYFLAG_BIN)) + +config OD + bool "od" + default y + help + usage: od [-bdosxv] [-j #] [-N #] [-A doxn] [-t arg] + + -A Address base (decimal, octal, hexdecimal, none) + -t output type(s) a (ascii) c (char) d (decimal) foux +*/ + +#include "toys.h" + +#define FLAG_t (1 << 0) +#define FLAG_A (1 << 1) +#define FLAG_b (1 << 2) +#define FLAG_c (1 << 3) +#define FLAG_d (1 << 4) +#define FLAG_o (1 << 5) +#define FLAG_s (1 << 6) +#define FLAG_x (1 << 7) +#define FLAG_N (1 << 8) +#define FLAG_v (1 << 9) + +DEFINE_GLOBALS( + struct arg_list *output_base; + char *address_base; + long max_count; + long jump_bytes; + + unsigned types, leftover, star, address_idx; + char *buf; + uint64_t bufs[4]; // force 64-bit alignment + off_t pos; +) + +#define TT this.od + +static char *ascii = "nulsohstxetxeotenqackbel bs ht nl vt ff cr so si" + "dledc1dc2dc3dc4naksynetbcan emsubesc fs gs rs us sp"; + +struct odtype { + int type; + int size; +}; + +static void od_outline(void) +{ + unsigned flags = toys.optflags; + char *abases[] = {"", "%07d", "%07o", "%06x"}; + struct odtype *types = (struct odtype *)toybuf, *t; + int i, len; + + if (TT.leftover<16) memset(TT.buf+TT.leftover, 0, 16-TT.leftover); + + // Handle duplciate lines as * + if (!(flags&FLAG_v) && TT.jump_bytes != TT.pos && TT.leftover + && !memcmp(TT.bufs, TT.bufs + 2, 16)) + { + if (!TT.star) { + xputs("*"); + TT.star++; + } + + // Print line position + } else { + TT.star = 0; + + xprintf(abases[TT.address_idx], TT.pos); + if (!TT.leftover) { + if (TT.address_idx) xputc('\n'); + return; + } + } + + TT.pos += len = TT.leftover; + TT.leftover = 0; + if (TT.star) return; + + // For each output type, print one line + + for (i=0; itype < 2) { + char c = TT.buf[j++]; + pad += 4; + + if (!t->type) { + c &= 127; + if (c<=32) sprintf(buf, "%.3s", ascii+(3*c)); + else if (c==127) strcpy(buf, "del"); + else sprintf(buf, "%c", c); + } else { + char *bfnrtav = "\b\f\n\r\t\a\v", *s = strchr(bfnrtav, c); + if (s) sprintf(buf, "\\%c", "bfnrtav0"[s-bfnrtav]); + else if (c < 32 || c >= 127) sprintf(buf, "%03o", c); + else { + // TODO: this should be UTF8 aware. + sprintf(buf, "%c", c); + } + } + } else if (CFG_TOYBOX_FLOAT && t->type == 6) { + long double ld; + union {float f; double d; long double ld;} fdl; + + memcpy(&fdl, TT.buf+j, t->size); + j += t->size; + if (sizeof(float) == t->size) { + ld = fdl.f; + pad += (throw = 8)+7; + } else if (sizeof(double) == t->size) { + ld = fdl.d; + pad += (throw = 17)+8; + } else if (sizeof(long double) == t->size) { + ld = fdl.ld; + pad += (throw = 21)+9; + } else error_exit("bad -tf '%d'", t->size); + + sprintf(buf, "%.*Le", throw, ld); + // Integer types + } else { + unsigned long long ll = 0, or; + char *c[] = {"%*lld", "%*llu", "%0*llo", "%0*llx"}, + *class = c[t->type-2]; + + // Work out width of field + if (t->size == 8) { + or = -1LL; + if (t->type == 2) or >>= 1; + } else or = (1LL<<(8*t->size))-1; + throw = sprintf(buf, class, 0, or); + + // Accumulate integer based on size argument + for (k=0; k < t->size; k++) { + or = TT.buf[j++]; + ll |= or << (8*(IS_BIG_ENDIAN ? t->size-k-1 : k)); + } + + // Handle negative values + if (t->type == 2) { + or = sizeof(or) - t->size; + throw++; + if (or && (ll & (1l<<((8*t->size)-1)))) + ll |= ((or<<(8*or))-1) << (8*t->size); + } + + sprintf(buf, class, throw, ll); + pad += throw+1; + } + xprintf("%*s", pad, buf); + pad = 0; + } + xputc('\n'); + } + + // buffer toggle for "same as last time" check. + TT.buf = (char *)((TT.buf == (char *)TT.bufs) ? TT.bufs+2 : TT.bufs); +} + +static void do_od(int fd, char *name) +{ + // Skip input, possibly more than one entire file. + if (TT.jump_bytes < TT.pos) { + off_t off = lskip(fd, TT.jump_bytes); + if (off > 0) TT.pos += off; + if (TT.jump_bytes < TT.pos) return; + } + + for(;;) { + char *buf = TT.buf + TT.leftover; + int len = 16 - TT.leftover; + + if (toys.optflags & FLAG_N) { + if (!TT.max_count) break; + if (TT.max_count < len) len = TT.max_count; + } + + len = readall(fd, buf, len); + if (len < 0) { + perror_msg("%s", name); + break; + } + if (TT.max_count) TT.max_count -= len; + TT.leftover += len; + if (TT.leftover < 16) break; + + od_outline(); + } +} + +static void append_base(char *base) +{ + char *s = base; + struct odtype *types = (struct odtype *)toybuf; + int type; + + for (;;) { + int size = 1; + + if (!*s) return; + if (TT.types >= sizeof(toybuf)/sizeof(struct odtype)) break; + if (-1 == (type = stridx("acduox"USE_TOYBOX_FLOAT("f"), *(s++)))) break; + + if (isdigit(*s)) { + size = strtol(s, &s, 10); + if (type < 2 && size != 1) break; + if (CFG_TOYBOX_FLOAT && type == 6 && size == sizeof(long double)); + else if (size < 0 || size > 8) break; + } else if (CFG_TOYBOX_FLOAT && type == 6) { + int sizes[] = {sizeof(float), sizeof(double), sizeof(long double)}; + if (-1 == (size = stridx("FDL", *s))) size = sizeof(double); + else { + s++; + size = sizes[size]; + } + } else if (type > 1) { + if (-1 == (size = stridx("CSIL", *s))) size = 4; + else { + s++; + size = 1 << size; + } + } + + types[TT.types].type = type; + types[TT.types].size = size; + TT.types++; + } + + error_exit("bad -t %s", base); +} + +void od_main(void) +{ + struct arg_list *arg; + + TT.buf = (char *)TT.bufs; + + if (!TT.address_base) TT.address_idx = 2; + else if (0>(TT.address_idx = stridx("ndox", *TT.address_base))) + error_exit("bad -A '%c'", *TT.address_base); + + // Collect -t entries + + for (arg = TT.output_base; arg; arg = arg->next) append_base(arg->arg); + if (toys.optflags & FLAG_b) append_base("o1"); + if (toys.optflags & FLAG_d) append_base("u2"); + if (toys.optflags & FLAG_o) append_base("o2"); + if (toys.optflags & FLAG_s) append_base("d2"); + if (toys.optflags & FLAG_x) append_base("x2"); + if (!TT.output_base) append_base("o2"); + + loopfiles(toys.optargs, do_od); + + if (TT.leftover) od_outline(); + od_outline(); +} diff -r 2d7c56913fda -r 2986aa63a021 toys/posix/patch.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/toys/posix/patch.c Sat Aug 25 14:25:22 2012 -0500 @@ -0,0 +1,412 @@ +/* vi: set sw=4 ts=4: + * + * patch.c - Apply a "universal" diff. + * + * Copyright 2007 Rob Landley + * + * see http://www.opengroup.org/onlinepubs/009695399/utilities/patch.html + * (But only does -u, because who still cares about "ed"?) + * + * TODO: + * -b backup + * -l treat all whitespace as a single space + * -N ignore already applied + * -d chdir first + * -D define wrap #ifdef and #ifndef around changes + * -o outfile output here instead of in place + * -r rejectfile write rejected hunks to this file + * + * -E remove empty files --remove-empty-files + * -f force (no questions asked) + * -F fuzz (number, default 2) + * [file] which file to patch + +USE_PATCH(NEWTOY(patch, USE_TOYBOX_DEBUG("x")"up#i:R", TOYFLAG_USR|TOYFLAG_BIN)) + +config PATCH + bool "patch" + default y + help + usage: patch [-i file] [-p depth] [-Ru] + + Apply a unified diff to one or more files. + + -i Input file (defaults=stdin) + -p number of '/' to strip from start of file paths (default=all) + -R Reverse patch. + -u Ignored (only handles "unified" diffs) + + This version of patch only handles unified diffs, and only modifies + a file when all all hunks to that file apply. Patch prints failed + hunks to stderr, and exits with nonzero status if any hunks fail. + + A file compared against /dev/null (or with a date <= the epoch) is + created/deleted as appropriate. +*/ + +#include "toys.h" + +DEFINE_GLOBALS( + char *infile; + long prefix; + + struct double_list *current_hunk; + long oldline, oldlen, newline, newlen; + long linenum; + int context, state, filein, fileout, filepatch, hunknum; + char *tempname; +) + +#define TT this.patch + +#define FLAG_REVERSE 1 +#define FLAG_PATHLEN 4 + +// Dispose of a line of input, either by writing it out or discarding it. + +// state < 2: just free +// state = 2: write whole line to stderr +// state = 3: write whole line to fileout +// state > 3: write line+1 to fileout when *line != state + +#define PATCH_DEBUG (CFG_TOYBOX_DEBUG && (toys.optflags & 16)) + +static void do_line(void *data) +{ + struct double_list *dlist = (struct double_list *)data; + + if (TT.state>1 && *dlist->data != TT.state) { + char *s = dlist->data+(TT.state>3 ? 1 : 0); + int i = TT.state == 2 ? 2 : TT.fileout; + + xwrite(i, s, strlen(s)); + xwrite(i, "\n", 1); + } + + if (PATCH_DEBUG) fprintf(stderr, "DO %d: %s\n", TT.state, dlist->data); + + free(dlist->data); + free(data); +} + +static void finish_oldfile(void) +{ + if (TT.tempname) replace_tempfile(TT.filein, TT.fileout, &TT.tempname); + TT.fileout = TT.filein = -1; +} + +static void fail_hunk(void) +{ + if (!TT.current_hunk) return; + TT.current_hunk->prev->next = 0; + + fprintf(stderr, "Hunk %d FAILED %ld/%ld.\n", + TT.hunknum, TT.oldline, TT.newline); + toys.exitval = 1; + + // If we got to this point, we've seeked to the end. Discard changes to + // this file and advance to next file. + + TT.state = 2; + llist_traverse(TT.current_hunk, do_line); + TT.current_hunk = NULL; + delete_tempfile(TT.filein, TT.fileout, &TT.tempname); + TT.state = 0; +} + +// Given a hunk of a unified diff, make the appropriate change to the file. +// This does not use the location information, but instead treats a hunk +// as a sort of regex. Copies data from input to output until it finds +// the change to be made, then outputs the changed data and returns. +// (Finding EOF first is an error.) This is a single pass operation, so +// multiple hunks must occur in order in the file. + +static int apply_one_hunk(void) +{ + struct double_list *plist, *buf = NULL, *check; + int matcheof = 0, reverse = toys.optflags & FLAG_REVERSE, backwarn = 0; + + // Break doubly linked list so we can use singly linked traversal function. + TT.current_hunk->prev->next = NULL; + + // Match EOF if there aren't as many ending context lines as beginning + for (plist = TT.current_hunk; plist; plist = plist->next) { + if (plist->data[0]==' ') matcheof++; + else matcheof = 0; + if (PATCH_DEBUG) fprintf(stderr, "HUNK:%s\n", plist->data); + } + matcheof = matcheof < TT.context; + + if (PATCH_DEBUG) fprintf(stderr,"MATCHEOF=%c\n", matcheof ? 'Y' : 'N'); + + // Loop through input data searching for this hunk. Match all context + // lines and all lines to be removed until we've found the end of a + // complete hunk. + plist = TT.current_hunk; + buf = NULL; + if (TT.context) for (;;) { + char *data = get_line(TT.filein); + + TT.linenum++; + + // Figure out which line of hunk to compare with next. (Skip lines + // of the hunk we'd be adding.) + while (plist && *plist->data == "+-"[reverse]) { + if (data && !strcmp(data, plist->data+1)) { + if (!backwarn) backwarn = TT.linenum; + } + plist = plist->next; + } + + // Is this EOF? + if (!data) { + if (PATCH_DEBUG) fprintf(stderr, "INEOF\n"); + + // Does this hunk need to match EOF? + if (!plist && matcheof) break; + + if (backwarn) + fprintf(stderr, "Possibly reversed hunk %d at %ld\n", + TT.hunknum, TT.linenum); + + // File ended before we found a place for this hunk. + fail_hunk(); + goto done; + } else if (PATCH_DEBUG) fprintf(stderr, "IN: %s\n", data); + check = dlist_add(&buf, data); + + // Compare this line with next expected line of hunk. + // todo: teach the strcmp() to ignore whitespace. + + // A match can fail because the next line doesn't match, or because + // we hit the end of a hunk that needed EOF, and this isn't EOF. + + // If match failed, flush first line of buffered data and + // recheck buffered data for a new match until we find one or run + // out of buffer. + + for (;;) { + if (!plist || strcmp(check->data, plist->data+1)) { + // Match failed. Write out first line of buffered data and + // recheck remaining buffered data for a new match. + + if (PATCH_DEBUG) + fprintf(stderr, "NOT: %s\n", plist->data); + + TT.state = 3; + check = llist_pop(&buf); + check->prev->next = buf; + buf->prev = check->prev; + do_line(check); + plist = TT.current_hunk; + + // If we've reached the end of the buffer without confirming a + // match, read more lines. + if (check==buf) { + buf = 0; + break; + } + check = buf; + } else { + if (PATCH_DEBUG) + fprintf(stderr, "MAYBE: %s\n", plist->data); + // This line matches. Advance plist, detect successful match. + plist = plist->next; + if (!plist && !matcheof) goto out; + check = check->next; + if (check == buf) break; + } + } + } +out: + // We have a match. Emit changed data. + TT.state = "-+"[reverse]; + llist_traverse(TT.current_hunk, do_line); + TT.current_hunk = NULL; + TT.state = 1; +done: + if (buf) { + buf->prev->next = NULL; + llist_traverse(buf, do_line); + } + + return TT.state; +} + +// Read a patch file and find hunks, opening/creating/deleting files. +// Call apply_one_hunk() on each hunk. + +// state 0: Not in a hunk, look for +++. +// state 1: Found +++ file indicator, look for @@ +// state 2: In hunk: counting initial context lines +// state 3: In hunk: getting body + +void patch_main(void) +{ + int reverse = toys.optflags&FLAG_REVERSE, state = 0, patchlinenum = 0, + strip = 0; + char *oldname = NULL, *newname = NULL; + + if (TT.infile) TT.filepatch = xopen(TT.infile, O_RDONLY); + TT.filein = TT.fileout = -1; + + // Loop through the lines in the patch + for (;;) { + char *patchline; + + patchline = get_line(TT.filepatch); + if (!patchline) break; + + // Other versions of patch accept damaged patches, + // so we need to also. + if (strip || !patchlinenum++) { + int len = strlen(patchline); + if (patchline[len-1] == '\r') { + if (!strip) fprintf(stderr, "Removing DOS newlines\n"); + strip = 1; + patchline[len-1]=0; + } + } + if (!*patchline) { + free(patchline); + patchline = xstrdup(" "); + } + + // Are we assembling a hunk? + if (state >= 2) { + if (*patchline==' ' || *patchline=='+' || *patchline=='-') { + dlist_add(&TT.current_hunk, patchline); + + if (*patchline != '+') TT.oldlen--; + if (*patchline != '-') TT.newlen--; + + // Context line? + if (*patchline==' ' && state==2) TT.context++; + else state=3; + + // If we've consumed all expected hunk lines, apply the hunk. + + if (!TT.oldlen && !TT.newlen) state = apply_one_hunk(); + continue; + } + fail_hunk(); + state = 0; + continue; + } + + // Open a new file? + if (!strncmp("--- ", patchline, 4) || !strncmp("+++ ", patchline, 4)) { + char *s, **name = &oldname; + int i; + + if (*patchline == '+') { + name = &newname; + state = 1; + } + + free(*name); + finish_oldfile(); + + // Trim date from end of filename (if any). We don't care. + for (s = patchline+4; *s && *s!='\t'; s++) + if (*s=='\\' && s[1]) s++; + i = atoi(s); + if (i>1900 && i<=1970) + *name = xstrdup("/dev/null"); + else { + *s = 0; + *name = xstrdup(patchline+4); + } + + // We defer actually opening the file because svn produces broken + // patches that don't signal they want to create a new file the + // way the patch man page says, so you have to read the first hunk + // and _guess_. + + // Start a new hunk? Usually @@ -oldline,oldlen +newline,newlen @@ + // but a missing ,value means the value is 1. + } else if (state == 1 && !strncmp("@@ -", patchline, 4)) { + int i; + char *s = patchline+4; + + // Read oldline[,oldlen] +newline[,newlen] + + TT.oldlen = TT.newlen = 1; + TT.oldline = strtol(s, &s, 10); + if (*s == ',') TT.oldlen=strtol(s+1, &s, 10); + TT.newline = strtol(s+2, &s, 10); + if (*s == ',') TT.newlen = strtol(s+1, &s, 10); + + TT.context = 0; + state = 2; + + // If this is the first hunk, open the file. + if (TT.filein == -1) { + int oldsum, newsum, del = 0; + char *name; + + oldsum = TT.oldline + TT.oldlen; + newsum = TT.newline + TT.newlen; + + name = reverse ? oldname : newname; + + // We're deleting oldname if new file is /dev/null (before -p) + // or if new hunk is empty (zero context) after patching + if (!strcmp(name, "/dev/null") || !(reverse ? oldsum : newsum)) + { + name = reverse ? newname : oldname; + del++; + } + + // handle -p path truncation. + for (i = 0, s = name; *s;) { + if ((toys.optflags & FLAG_PATHLEN) && TT.prefix == i) break; + if (*s++ != '/') continue; + while (*s == '/') s++; + name = s; + i++; + } + + if (del) { + printf("removing %s\n", name); + xunlink(name); + state = 0; + // If we've got a file to open, do so. + } else if (!(toys.optflags & FLAG_PATHLEN) || i <= TT.prefix) { + // If the old file was null, we're creating a new one. + if (!strcmp(oldname, "/dev/null") || !oldsum) { + printf("creating %s\n", name); + s = strrchr(name, '/'); + if (s) { + *s = 0; + xmkpath(name, -1); + *s = '/'; + } + TT.filein = xcreate(name, O_CREAT|O_EXCL|O_RDWR, 0666); + } else { + printf("patching %s\n", name); + TT.filein = xopen(name, O_RDWR); + } + TT.fileout = copy_tempfile(TT.filein, name, &TT.tempname); + TT.linenum = 0; + TT.hunknum = 0; + } + } + + TT.hunknum++; + + continue; + } + + // If we didn't continue above, discard this line. + free(patchline); + } + + finish_oldfile(); + + if (CFG_TOYBOX_FREE) { + close(TT.filepatch); + free(oldname); + free(newname); + } +} diff -r 2d7c56913fda -r 2986aa63a021 toys/posix/pwd.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/toys/posix/pwd.c Sat Aug 25 14:25:22 2012 -0500 @@ -0,0 +1,30 @@ +/* vi: set sw=4 ts=4: + * + * pwd.c - Print working directory. + * + * Copyright 2006 Rob Landley + * + * See http://www.opengroup.org/onlinepubs/009695399/utilities/echo.html + * + * TODO: add -L -P + +USE_PWD(NEWTOY(pwd, NULL, TOYFLAG_BIN)) + +config PWD + bool "pwd" + default y + help + usage: pwd + + The print working directory command prints the current directory. +*/ + +#include "toys.h" + +void pwd_main(void) +{ + char *pwd = xgetcwd(); + + xprintf("%s\n", pwd); + if (CFG_TOYBOX_FREE) free(pwd); +} diff -r 2d7c56913fda -r 2986aa63a021 toys/posix/rmdir.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/toys/posix/rmdir.c Sat Aug 25 14:25:22 2012 -0500 @@ -0,0 +1,43 @@ +/* vi: set sw=4 ts=4: + * + * rmdir.c - remove directory/path + * + * Copyright 2008 Rob Landley + * + * See http://opengroup.org/onlinepubs/9699919799/utilities/rmdir.html + +USE_RMDIR(NEWTOY(rmdir, "<1p", TOYFLAG_BIN)) + +config RMDIR + bool "rmdir" + default y + help + usage: rmdir [-p] [dirname...] + Remove one or more directories. + + -p Remove path. +*/ + +#include "toys.h" + +static void do_rmdir(char *name) +{ + for (;;) { + char *temp; + + if (rmdir(name)) { + perror_msg("%s",name); + return; + } + if (!toys.optflags) return; + if (!(temp=strrchr(name,'/'))) return; + *temp=0; + } +} + +void rmdir_main(void) +{ + char **s; + + for (s=toys.optargs; *s; s++) do_rmdir(*s); +} diff -r 2d7c56913fda -r 2986aa63a021 toys/posix/sed.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/toys/posix/sed.c Sat Aug 25 14:25:22 2012 -0500 @@ -0,0 +1,63 @@ +/* vi: set sw=4 ts=4: + * + * sed.c - Stream editor. + * + * Copyright 2008 Rob Landley + * + * See http://www.opengroup.org/onlinepubs/009695399/utilities/sed.c + +USE_SED(NEWTOY(sed, "irne*", TOYFLAG_BIN)) + +config SED + bool "sed" + default n + help + usage: sed [-irn] {command | [-e command]...} [FILE...] + + Stream EDitor, transforms text by appling commands to each line + of input. +*/ + +#include "toys.h" +#include "lib/xregcomp.h" + +DEFINE_GLOBALS( + struct arg_list *commands; +) + +#define TT this.sed + +struct sed_command { + // Doubly linked list of commands. + struct sed_command *next, *prev; + + // Regexes for s/match/data/ and /match_begin/,/match_end/command + regex_t *match, *match_begin, *match_end; + + // For numeric ranges ala 10,20command + int first_line, last_line; + + // Which match to replace, 0 for all. + int which; + + // s and w commands can write to a file. Slight optimization: we use 0 + // instead of -1 to mean no file here, because even when there's no stdin + // our input file would take fd 0. + int outfd; + + // Data string for (saicytb) + char *data; + + // Which command letter is this? + char command; +}; + +void sed_main(void) +{ + struct arg_list *test; + + for (test = TT.commands; test; test = test->next) + dprintf(2,"command=%s\n",test->arg); + + printf("Hello world\n"); +} diff -r 2d7c56913fda -r 2986aa63a021 toys/posix/sleep.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/toys/posix/sleep.c Sat Aug 25 14:25:22 2012 -0500 @@ -0,0 +1,51 @@ +/* vi: set sw=4 ts=4: + * + * sleep.c - Wait for a number of seconds. + * + * Copyright 2007 Rob Landley + * Copyright 2012 Georgi Chorbadzhiyski + * + * See http://www.opengroup.org/onlinepubs/009695399/utilities/sleep.html + +USE_SLEEP(NEWTOY(sleep, "<1", TOYFLAG_BIN)) + +config SLEEP + bool "sleep" + default y + help + usage: sleep SECONDS + + Wait before exiting. + +config SLEEP_FLOAT + bool + default y + depends on SLEEP && TOYBOX_FLOAT + help + The delay can be a decimal fraction. An optional suffix can be "m" + (minutes), "h" (hours), "d" (days), or "s" (seconds, the default). +*/ + +#include "toys.h" + +void sleep_main(void) +{ + + if (!CFG_TOYBOX_FLOAT) toys.exitval = sleep(atol(*toys.optargs)); + else { + char *arg; + double d = strtod(*toys.optargs, &arg); + struct timespec tv; + + // Parse suffix + if (*arg) { + int ismhd[]={1,60,3600,86400}; + char *smhd = "smhd", *c = strchr(smhd, *arg); + if (!c) error_exit("Unknown suffix '%c'", *arg); + d *= ismhd[c-smhd]; + } + + tv.tv_nsec=1000000000*(d-(tv.tv_sec = (unsigned long)d)); + toys.exitval = !!nanosleep(&tv, NULL); + } +} diff -r 2d7c56913fda -r 2986aa63a021 toys/posix/sort.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/toys/posix/sort.c Sat Aug 25 14:25:22 2012 -0500 @@ -0,0 +1,421 @@ +/* vi: set sw=4 ts=4: + * + * sort.c - put input lines into order + * + * Copyright 2004, 2008 Rob Landley + * + * See http://www.opengroup.org/onlinepubs/007904975/utilities/sort.html + +USE_SORT(NEWTOY(sort, USE_SORT_FLOAT("g")USE_SORT_BIG("S:T:m" "o:k*t:xbMcszdfi") "run", TOYFLAG_USR|TOYFLAG_BIN)) + +config SORT + bool "sort" + default y + help + usage: sort [-run] [FILE...] + + Sort all lines of text from input files (or stdin) to stdout. + + -r reverse + -u unique lines only + -n numeric order (instead of alphabetical) + +config SORT_BIG + bool "SuSv3 options (Support -ktcsbdfiozM)" + default y + depends on SORT + help + usage: sort [-bcdfiMsz] [-k#[,#[x]] [-t X]] [-o FILE] + + -b ignore leading blanks (or trailing blanks in second part of key) + -c check whether input is sorted + -d dictionary order (use alphanumeric and whitespace chars only) + -f force uppercase (case insensitive sort) + -i ignore nonprinting characters + -M month sort (jan, feb, etc). + -x Hexadecimal numerical sort + -s skip fallback sort (only sort with keys) + -z zero (null) terminated input + -k sort by "key" (see below) + -t use a key separator other than whitespace + -o output to FILE instead of stdout + + Sorting by key looks at a subset of the words on each line. -k2 + uses the second word to the end of the line, -k2,2 looks at only + the second word, -k2,4 looks from the start of the second to the end + of the fourth word. Specifying multiple keys uses the later keys as + tie breakers, in order. A type specifier appended to a sort key + (such as -2,2n) applies only to sorting that key. + +config SORT_FLOAT + bool "Floating point (-g)" + default y + depends on SORT_BIG + help + usage: sort [-g] + + This version of sort requires floating point. + + -g general numeric sort (double precision with nan and inf) + +*/ + +#include "toys.h" + +DEFINE_GLOBALS( + char *key_separator; + struct arg_list *raw_keys; + char *outfile; + char *ignore1, ignore2; // GNU compatability NOPs for -S and -T. + + void *key_list; + int linecount; + char **lines; +) + +#define TT this.sort + +// The sort types are n, g, and M. +// u, c, s, and z apply to top level only, not to keys. +// b at top level implies bb. +// The remaining options can be applied to search keys. + +#define FLAG_n (1<<0) // Sort type: numeric +#define FLAG_u (1<<1) // Unique +#define FLAG_r (1<<2) // Reverse output order + +#define FLAG_i (1<<3) // Ignore !isprint() +#define FLAG_f (1<<4) // Force uppercase +#define FLAG_d (1<<5) // Ignore !(isalnum()|isspace()) +#define FLAG_z (1<<6) // Input is null terminated, not \n +#define FLAG_s (1<<7) // Stable sort, no ascii fallback at end +#define FLAG_c (1<<8) // Check only. No output, exit(!ordered) +#define FLAG_M (1<<9) // Sort type: date +#define FLAG_b (1<<10) // Ignore leading blanks +#define FLAG_x (1<<11) // Hex sort +#define FLAG_g (1<<18) // Sort type: strtod() + +// Left off dealing with FLAG_b/FLAG_bb logic... + +#define FLAG_bb (1<<31) // Ignore trailing blanks + +struct sort_key +{ + struct sort_key *next_key; // linked list + unsigned range[4]; // start word, start char, end word, end char + int flags; +}; + +// Copy of the part of this string corresponding to a key/flags. + +static char *get_key_data(char *str, struct sort_key *key, int flags) +{ + int start=0, end, len, i, j; + + // Special case whole string, so we don't have to make a copy + + if(key->range[0]==1 && !key->range[1] && !key->range[2] && !key->range[3] + && !(flags&(FLAG_b&FLAG_d&FLAG_f&FLAG_i&FLAG_bb))) return str; + + // Find start of key on first pass, end on second pass + + len = strlen(str); + for (j=0; j<2; j++) { + if (!key->range[2*j]) end=len; + + // Loop through fields + else { + end=0; + for (i=1; i < key->range[2*j]+j; i++) { + + // Skip leading blanks + if (str[end] && !TT.key_separator) + while (isspace(str[end])) end++; + + // Skip body of key + for (; str[end]; end++) { + if (TT.key_separator) { + if (str[end]==*TT.key_separator) break; + } else if (isspace(str[end])) break; + } + } + } + if (!j) start=end; + } + + // Key with explicit separator starts after the separator + if (TT.key_separator && str[start]==*TT.key_separator) start++; + + // Strip leading and trailing whitespace if necessary + if (flags&FLAG_b) while (isspace(str[start])) start++; + if (flags&FLAG_bb) while (end>start && isspace(str[end-1])) end--; + + // Handle offsets on start and end + if (key->range[3]) { + end += key->range[3]-1; + if (end>len) end=len; + } + if (key->range[1]) { + start += key->range[1]-1; + if (start>len) start=len; + } + + // Make the copy + if (endnext_key); + return *pkey = xzalloc(sizeof(struct sort_key)); +} + +// Perform actual comparison +static int compare_values(int flags, char *x, char *y) +{ + int ff = flags & (FLAG_n|FLAG_g|FLAG_M|FLAG_x); + + // Ascii sort + if (!ff) return strcmp(x, y); + + if (CFG_SORT_FLOAT && ff == FLAG_g) { + char *xx,*yy; + double dx = strtod(x,&xx), dy = strtod(y,&yy); + int xinf, yinf; + + // not numbers < NaN < -infinity < numbers < +infinity + + if (x==xx) return y==yy ? 0 : -1; + if (y==yy) return 1; + + // Check for isnan + if (dx!=dx) return (dy!=dy) ? 0 : -1; + if (dy!=dy) return 1; + + // Check for infinity. (Could underflow, but avoids needing libm.) + xinf = (1.0/dx == 0.0); + yinf = (1.0/dy == 0.0); + if (xinf) { + if(dx<0) return (yinf && dy<0) ? 0 : -1; + return (yinf && dy>0) ? 0 : 1; + } + if (yinf) return dy<0 ? 1 : -1; + + return dx>dy ? 1 : (dxdy ? 1 : (dxnext_key) + { + flags = key->flags ? key->flags : toys.optflags; + + // Chop out and modify key chunks, handling -dfib + + x = get_key_data(xx, key, flags); + y = get_key_data(yy, key, flags); + + retval = compare_values(flags, x, y); + + // Free the copies get_key_data() made. + + if (x != xx) free(x); + if (y != yy) free(y); + + if (retval) break; + } + } else retval = compare_values(flags, xx, yy); + + // Perform fallback sort if necessary + if (!retval && !(CFG_SORT_BIG && (toys.optflags&FLAG_s))) { + retval = strcmp(xx, yy); + flags = toys.optflags; + } + + return retval * ((flags&FLAG_r) ? -1 : 1); +} + +// Callback from loopfiles to handle input files. +static void sort_read(int fd, char *name) +{ + // Read each line from file, appending to a big array. + + for (;;) { + char * line = (CFG_SORT_BIG && (toys.optflags&FLAG_z)) + ? get_rawline(fd, NULL, 0) : get_line(fd); + + if (!line) break; + + // handle -c here so we don't allocate more memory than necessary. + if (CFG_SORT_BIG && (toys.optflags&FLAG_c)) { + int j = (toys.optflags&FLAG_u) ? -1 : 0; + + if (TT.lines && compare_keys((void *)&TT.lines, &line)>j) + error_exit("%s: Check line %d\n", name, TT.linecount); + free(TT.lines); + TT.lines = (char **)line; + } else { + if (!(TT.linecount&63)) + TT.lines = xrealloc(TT.lines, sizeof(char *)*(TT.linecount+64)); + TT.lines[TT.linecount] = line; + } + TT.linecount++; + } +} + +void sort_main(void) +{ + int idx, fd = 1; + + // Open output file if necessary. + if (CFG_SORT_BIG && TT.outfile) + fd = xcreate(TT.outfile, O_CREAT|O_TRUNC|O_WRONLY, 0666); + + // Parse -k sort keys. + if (CFG_SORT_BIG && TT.raw_keys) { + struct arg_list *arg; + + for (arg = TT.raw_keys; arg; arg = arg->next) { + struct sort_key *key = add_key(); + char *temp; + int flag; + + idx = 0; + temp = arg->arg; + while (*temp) { + // Start of range + key->range[2*idx] = (unsigned)strtol(temp, &temp, 10); + if (*temp=='.') + key->range[(2*idx)+1] = (unsigned)strtol(temp+1, &temp, 10); + + // Handle flags appended to a key type. + for (;*temp;temp++) { + char *temp2, *optlist; + + // Note that a second comma becomes an "Unknown key" error. + + if (*temp==',' && !idx++) { + temp++; + break; + } + + // Which flag is this? + + optlist = toys.which->options; + temp2 = strchr(optlist, *temp); + flag = (1<<(optlist-temp2+strlen(optlist)-1)); + + // Was it a flag that can apply to a key? + + if (!temp2 || flag>FLAG_b + || (flag&(FLAG_u|FLAG_c|FLAG_s|FLAG_z))) + { + error_exit("Unknown key option."); + } + // b after , means strip _trailing_ space, not leading. + if (idx && flag==FLAG_b) flag = FLAG_bb; + key->flags |= flag; + } + } + } + } + + // global b flag strips both leading and trailing spaces + if (toys.optflags&FLAG_b) toys.optflags |= FLAG_bb; + + // If no keys, perform alphabetic sort over the whole line. + if (CFG_SORT_BIG && !TT.key_list) add_key()->range[0] = 1; + + // Open input files and read data, populating TT.lines[TT.linecount] + loopfiles(toys.optargs, sort_read); + + // The compare (-c) logic was handled in sort_read(), + // so if we got here, we're done. + if (CFG_SORT_BIG && (toys.optflags&FLAG_c)) goto exit_now; + + // Perform the actual sort + qsort(TT.lines, TT.linecount, sizeof(char *), compare_keys); + + // handle unique (-u) + if (toys.optflags&FLAG_u) { + int jdx; + + for (jdx=0, idx=1; idx + * + * See http://www.opengroup.org/onlinepubs/009695399/utilities/tail.html + +USE_TAIL(NEWTOY(tail, "fc-n-", TOYFLAG_BIN)) + +config TAIL + bool "tail" + default y + help + usage: tail [-n|c number] [-f] [file...] + + Copy last lines from files to stdout. If no files listed, copy from + stdin. Filename "-" is a synonym for stdin. + + -n output the last X lines (default 10), +X counts from start. + -c output the last X bytes, +X counts from start + -f follow file, waiting for more data to be appended + +config TAIL_SEEK + bool "tail seek support" + default y + depends on TAIL + help + This version uses lseek, which is faster on large files. +*/ + +#include "toys.h" + +DEFINE_GLOBALS( + long lines; + long bytes; + + int file_no; +) + +#define TT this.tail + +#define FLAG_n 1 +#define FLAG_c 2 +#define FLAG_f 4 + +struct line_list { + struct line_list *next, *prev; + char *data; + int len; +}; + +static struct line_list *get_chunk(int fd, int len) +{ + struct line_list *line = xmalloc(sizeof(struct line_list)+len); + + line->data = ((char *)line) + sizeof(struct line_list); + line->len = readall(fd, line->data, len); + + if (line->len < 1) { + free(line); + return 0; + } + + return line; +} + +static void dump_chunk(void *ptr) +{ + struct line_list *list = ptr; + xwrite(1, list->data, list->len); + free(list); +} + +// Reading through very large files is slow. Using lseek can speed things +// up a lot, but isn't applicable to all input (cat | tail). +// Note: bytes and lines are negative here. +static int try_lseek(int fd, long bytes, long lines) +{ + struct line_list *list = 0, *temp; + int flag = 0, chunk = sizeof(toybuf); + ssize_t pos = lseek(fd, 0, SEEK_END); + + // If lseek() doesn't work on this stream, return now. + if (pos<0) return 0; + + // Seek to the right spot, output data from there. + if (bytes) { + if (lseek(fd, bytes, SEEK_END)<0) lseek(fd, 0, SEEK_SET); + xsendfile(fd, 1); + return 1; + } + + // Read from end to find enough lines, then output them. + + bytes = pos; + while (lines && pos) { + int offset; + + // Read in next chunk from end of file + if (chunk>pos) chunk = pos; + pos -= chunk; + if (pos != lseek(fd, pos, SEEK_SET)) { + perror_msg("seek failed"); + break; + } + if (!(temp = get_chunk(fd, chunk))) break; + if (list) list->next = temp; + list = temp; + + // Count newlines in this chunk. + offset = list->len; + while (offset--) { + // If the last line ends with a newline, that one doesn't count. + if (!flag) { + flag++; + + continue; + } + + // Start outputting data right after newline + if (list->data[offset] == '\n' && !++lines) { + offset++; + list->data += offset; + list->len -= offset; + + break; + } + } + } + + // Output stored data + llist_traverse(list, dump_chunk); + + // In case of -f + lseek(fd, bytes, SEEK_SET); + return 1; +} + +// Called for each file listed on command line, and/or stdin +static void do_tail(int fd, char *name) +{ + long bytes = TT.bytes, lines = TT.lines; + + if (toys.optc > 1) { + if (TT.file_no++) xputc('\n'); + xprintf("==> %s <==\n", name); + } + + // Are we measuring from the end of the file? + + if (bytes<0 || lines<0) { + struct line_list *list = 0, *new; + + // The slow codepath is always needed, and can handle all input, + // so make lseek support optional. + if (CFG_TAIL_SEEK && try_lseek(fd, bytes, lines)); + + // Read data until we run out, keep a trailing buffer + else for (;;) { + int len, count; + char *try; + + if (!(new = get_chunk(fd, sizeof(toybuf)))) break; + // append in order + dlist_add_nomalloc((struct double_list **)&list, + (struct double_list *)new); + + // Measure new chunk, discarding extra data from buffer + len = new->len; + try = new->data; + for (count=0; countdata++); + if (!(--list->len)) { + struct line_list *next = list->next; + list->prev->next = next; + list->next->prev = list->prev; + free(list); + list = next; + } + if (c == '\n') break; + } while (lines); + } + } + + // Output/free the buffer. + llist_traverse(list, dump_chunk); + + // Measuring from the beginning of the file. + } else for (;;) { + int len, offset = 0; + + // Error while reading does not exit. Error writing does. + len = read(fd, toybuf, sizeof(toybuf)); + if (len<1) break; + while (bytes > 1 || lines > 1) { + bytes--; + if (toybuf[offset++] == '\n') lines--; + if (offset >= len) break; + } + if (offset + * + * See http://www.opengroup.org/onlinepubs/009695399/utilities/tee.html + +USE_TEE(NEWTOY(tee, "ia", TOYFLAG_BIN)) + +config TEE + bool "tee" + default y + help + usage: tee [-ai] [file...] + + Copy stdin to each listed file, and also to stdout. + Filename "-" is a synonym for stdout. + + -a append to files. + -i ignore SIGINT. +*/ + +#include "toys.h" + +DEFINE_GLOBALS( + void *outputs; +) + +#define TT this.tee + +struct fd_list { + struct fd_list *next; + int fd; +}; + +// Open each output file, saving filehandles to a linked list. + +static void do_tee_open(int fd, char *name) +{ + struct fd_list *temp; + + temp = xmalloc(sizeof(struct fd_list)); + temp->next = TT.outputs; + temp->fd = fd; + TT.outputs = temp; +} + +void tee_main(void) +{ + if (toys.optflags&2) signal(SIGINT, SIG_IGN); + + // Open output files + loopfiles_rw(toys.optargs, + O_RDWR|O_CREAT|((toys.optflags&1)?O_APPEND:O_TRUNC), 0666, 0, + do_tee_open); + + for (;;) { + struct fd_list *fdl; + int len; + + // Read data from stdin + len = xread(0, toybuf, sizeof(toybuf)); + if (len<1) break; + + // Write data to each output file, plus stdout. + fdl = TT.outputs; + for (;;) { + if(len != writeall(fdl ? fdl->fd : 1, toybuf, len)) toys.exitval=1; + if (!fdl) break; + fdl = fdl->next; + } + } + +} diff -r 2d7c56913fda -r 2986aa63a021 toys/posix/true.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/toys/posix/true.c Sat Aug 25 14:25:22 2012 -0500 @@ -0,0 +1,23 @@ +/* vi: set sw=4 ts=4: + * + * true.c - Return zero. + * + * Copyright 2007 Rob Landley + * + * See http://www.opengroup.org/onlinepubs/009695399/utilities/true.html + +USE_TRUE(NEWTOY(true, NULL, TOYFLAG_BIN)) + +config TRUE + bool "true" + default y + help + Return zero. +*/ + +#include "toys.h" + +void true_main(void) +{ + return; +} diff -r 2d7c56913fda -r 2986aa63a021 toys/posix/tty.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/toys/posix/tty.c Sat Aug 25 14:25:22 2012 -0500 @@ -0,0 +1,32 @@ +/* vi: set sw=4 ts=4: + * + * tty.c - Show stdin's terminal name + * + * Copyright 2011 Rob Landley + * + * See http://opengroup.org/onlinepubs/9699919799/utilities/tty.html + +USE_TTY(NEWTOY(tty, "s", TOYFLAG_USR|TOYFLAG_BIN)) + +config TTY + bool "tty" + default y + help + Show filename of terminal connected to stdin. + + Prints "not a tty" and exits with nonzero status if no terminal + is connected to stdin. + + -s silent mode +*/ + +#include "toys.h" + +void tty_main(void) +{ + char *tty = ttyname(0); + + if (!toys.optflags) puts(tty ? tty : "not a tty"); + + toys.exitval = !tty; +} diff -r 2d7c56913fda -r 2986aa63a021 toys/posix/uname.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/toys/posix/uname.c Sat Aug 25 14:25:22 2012 -0500 @@ -0,0 +1,74 @@ +/* vi: set sw=4 ts=4: + * + * uname.c - return system name + * + * Copyright 2008 Rob Landley + * + * See http://www.opengroup.org/onlinepubs/009695399/utilities/uname.html + +USE_UNAME(NEWTOY(uname, "amvrns", TOYFLAG_BIN)) + +config UNAME + bool "uname" + default y + help + usage: uname [-asnrvmpio] + + Print system information. + + -s System name + -n Network (domain) name + -r Release number + -v Version (build date) + -m Machine (hardware) name + -a All of the above +*/ + +#include "toys.h" + +// If a 32 bit x86 build environment working in a chroot under an x86-64 +// kernel returns x86_64 for -m it confuses ./configure. Special case it. + +#if defined(__i686__) +#define GROSS "i686" +#elif defined(__i586__) +#define GROSS "i586" +#elif defined(__i486__) +#define GROSS "i486" +#elif defined(__i386__) +#define GROSS "i386" +#endif + +#define FLAG_a (1<<5) + +void uname_main(void) +{ + int i, flags = toys.optflags, needspace=0; + + uname((void *)toybuf); + + if (!flags) flags=1; + for (i=0; i<5; i++) { + char *c = toybuf+(65*i); + + if (flags & ((1< + * + * See http://www.opengroup.org/onlinepubs/009695399/utilities/uniq.html + +USE_UNIQ(NEWTOY(uniq, "f#s#w#zicdu", TOYFLAG_BIN)) + +config UNIQ + bool "uniq" + default y + help + usage: uniq [-cduiz] [-w maxchars] [-f fields] [-s char] [input_file [output_file]] + + Report or filter out repeated lines in a file + + -c show counts before each line + -d show only lines that are repeated + -u show only lines that are unique + -i ignore case when comparing lines + -z lines end with \0 not \n + -w compare maximum X chars per line + -f ignore first X fields + -s ignore first X chars +*/ + +#include "toys.h" + +DEFINE_GLOBALS( + long maxchars; + long nchars; + long nfields; + long repeats; +) + +#define TT this.uniq + +#define FLAG_z 16 +#define FLAG_i 8 +#define FLAG_c 4 +#define FLAG_d 2 +#define FLAG_u 1 + +static char *skip(char *str) +{ + long nchars = TT.nchars, nfields; + + // Skip fields first + for (nfields = TT.nfields; nfields; str++) { + while (*str && isspace(*str)) str++; + while (*str && !isspace(*str)) str++; + nfields--; + } + // Skip chars + while (*str && nchars--) str++; + + return str; +} + +static void print_line(FILE *f, char *line) +{ + if (toys.optflags & (TT.repeats ? FLAG_u : FLAG_d)) return; + if (toys.optflags & FLAG_c) fprintf(f, "%7lu ", TT.repeats + 1); + fputs(line, f); + if (toys.optflags & FLAG_z) fputc(0, f); +} + +void uniq_main(void) +{ + FILE *infile = stdin, *outfile = stdout; + char *thisline = NULL, *prevline = NULL, *tmpline, eol = '\n'; + size_t thissize, prevsize = 0, tmpsize; + + if (toys.optc >= 1) infile = xfopen(toys.optargs[0], "r"); + if (toys.optc >= 2) outfile = xfopen(toys.optargs[1], "w"); + + if (toys.optflags & FLAG_z) eol = 0; + + // If first line can't be read + if (getdelim(&prevline, &prevsize, eol, infile) < 0) + return; + + while (getdelim(&thisline, &thissize, eol, infile) > 0) { + int diff; + char *t1, *t2; + + // If requested get the chosen fields + character offsets. + if (TT.nfields || TT.nchars) { + t1 = skip(thisline); + t2 = skip(prevline); + } else { + t1 = thisline; + t2 = prevline; + } + + if (TT.maxchars == 0) { + diff = !(toys.optflags & FLAG_i) + ? strcmp(t1, t2) + : strcasecmp(t1, t2); + } else { + diff = !(toys.optflags & FLAG_i) + ? strncmp(t1, t2, TT.maxchars) + : strncasecmp(t1, t2, TT.maxchars); + } + + if (diff == 0) { // same + TT.repeats++; + } else { + print_line(outfile, prevline); + + TT.repeats = 0; + + tmpline = prevline; + prevline = thisline; + thisline = tmpline; + + tmpsize = prevsize; + prevsize = thissize; + thissize = tmpsize; + } + } + + print_line(outfile, prevline); + + if (CFG_TOYBOX_FREE) { + free(prevline); + free(thisline); + } +} diff -r 2d7c56913fda -r 2986aa63a021 toys/posix/unlink.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/toys/posix/unlink.c Sat Aug 25 14:25:22 2012 -0500 @@ -0,0 +1,26 @@ +/* vi: set sw=4 ts=4: + * + * unlink.c - delete one file + * + * Copyright 2011 Rob Landley + * + * See http://opengroup.org/onlinepubs/9699919799/utilities/unlink.html + +USE_UNLINK(NEWTOY(unlink, "<1>1", TOYFLAG_USR|TOYFLAG_BIN)) + +config UNLINK + bool "unlink" + default y + help + usage: unlink FILE + + Deletes one file. +*/ + +#include "toys.h" + +void unlink_main(void) +{ + if (unlink(*toys.optargs)) + perror_exit("Couldn't unlink `%s'", *toys.optargs); +} diff -r 2d7c56913fda -r 2986aa63a021 toys/posix/wc.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/toys/posix/wc.c Sat Aug 25 14:25:22 2012 -0500 @@ -0,0 +1,60 @@ +/* vi: set sw=4 ts=4: + * + * wc.c - Word count + * + * Copyright 2011 Rob Landley + * + * See http://opengroup.org/onlinepubs/9699919799/utilities/wc.html + +USE_WC(NEWTOY(wc, "cwl", TOYFLAG_USR|TOYFLAG_BIN)) + +config WC + bool "wc" + default y + help + usage: wc -lwc [FILE...] + + Count lines, words, and characters in input. + + -l show lines + -w show words + -c show characters + + By default outputs lines, words, characters, and filename for each + argument (or from stdin if none). +*/ + +#include "toys.h" + +static void do_wc(int fd, char *name) +{ + int i, len; + unsigned long word=0, lengths[]={0,0,0}; + + for (;;) { + len = read(fd, toybuf, sizeof(toybuf)); + if (len<0) { + perror_msg("%s",name); + toys.exitval = EXIT_FAILURE; + } + if (len<1) break; + for (i=0; i + * + * See http://pubs.opengroup.org/onlinepubs/9699919799/utilities/who.html + +USE_WHO(NEWTOY(who, NULL, TOYFLAG_BIN)) + +config WHO + bool "who" + default n + help + usage: who + + Print logged user information on system + +*/ + +#include "toys.h" + +void who_main(void) +{ + struct utmpx *entry; + + setutxent(); + + while ((entry = getutxent())) { + if (entry->ut_type == USER_PROCESS) { + time_t time; + int time_size; + char * times; + + time = entry->ut_tv.tv_sec; + times = ctime(&time); + time_size = strlen(times) - 2; + printf("%s\t%s\t%*.*s\t(%s)\n", entry->ut_user, entry->ut_line, time_size, time_size, ctime(&time), entry->ut_host); + + } + } + + endutxent(); +} diff -r 2d7c56913fda -r 2986aa63a021 toys/posix/xargs.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/toys/posix/xargs.c Sat Aug 25 14:25:22 2012 -0500 @@ -0,0 +1,188 @@ +/* vi: set sw=4 ts=4: + * + * xargs.c - Run command with arguments taken from stdin. + * + * Copyright 2011 Rob Landley + * + * See http://opengroup.org/onlinepubs/9699919799/utilities/xargs.html + +USE_XARGS(NEWTOY(xargs, "^I:E:L#ptxrn#<1s#0", TOYFLAG_USR|TOYFLAG_BIN)) + +config XARGS + bool "xargs" + default y + help + usage: xargs [-ptxr0] [-s NUM] [-n NUM] [-L NUM] [-E STR] COMMAND... + + Run command line one or more times, appending arguments from stdin. + + If command exits with 255, don't launch another even if arguments remain. + + -s Size in bytes per command line + -n Max number of arguments per command + -0 Each argument is NULL terminated, no whitespace or quote processing + #-p Prompt for y/n from tty before running each command + #-t Trace, print command line to stderr + #-x Exit if can't fit everything in one command + #-r Don't run command with empty input + #-L Max number of lines of input per command + -E stop at line matching string +*/ + +#include "toys.h" + +DEFINE_GLOBALS( + long max_bytes; + long max_entries; + long L; + char *eofstr; + char *I; + + long entries, bytes; + char delim; +) + +#define TT this.xargs + +// If out==NULL count TT.bytes and TT.entries, stopping at max. +// Otherwise, fill out out[] + +// Returning NULL means need more data. +// Returning char * means hit data limits, start of data left over +// Returning 1 means hit data limits, but consumed all data +// Returning 2 means hit -E eofstr + +static char *handle_entries(char *data, char **entry) +{ + if (TT.delim) { + char *s = data; + + // Chop up whitespace delimited string into args + while (*s) { + char *save; + + while (isspace(*s)) { + if (entry) *s = 0; + s++; + } + + if (TT.max_entries && TT.entries >= TT.max_entries) + return *s ? s : (char *)1; + + if (!*s) break; + save = s; + + for (;;) { + if (++TT.bytes >= TT.max_bytes && TT.max_bytes) return save; + if (!*s || isspace(*s)) break; + s++; + } + if (TT.eofstr) { + int len = s-save; + if (len == strlen(TT.eofstr) && !strncmp(save, TT.eofstr, len)) + return (char *)2; + } + if (entry) entry[TT.entries] = save; + ++TT.entries; + } + + // -0 support + } else { + TT.bytes += strlen(data)+1; + if (TT.max_bytes && TT.bytes >= TT.max_bytes) return data; + if (TT.max_entries && TT.entries >= TT.max_entries) + return (char *)1; + if (entry) entry[TT.entries] = data; + TT.entries++; + } + + return NULL; +} + +void xargs_main(void) +{ + struct double_list *dlist = NULL; + int entries, bytes, done = 0, status; + char *data = NULL; + + if (!(toys.optflags&1)) TT.delim = '\n'; + + // If no optargs, call echo. + if (!toys.optc) { + free(toys.optargs); + *(toys.optargs = xzalloc(2*sizeof(char *)))="echo"; + toys.optc = 1; + } + + for (entries = 0, bytes = -1; entries < toys.optc; entries++, bytes++) + bytes += strlen(toys.optargs[entries]); + + // Loop through exec chunks. + while (data || !done) { + char **out; + + TT.entries = 0; + TT.bytes = bytes; + + // Loop reading input + for (;;) { + + // Read line + if (!data) { + ssize_t l = 0; + l = getdelim(&data, (size_t *)&l, TT.delim, stdin); + + if (l<0) { + data = 0; + done++; + break; + } + } + dlist_add(&dlist, data); + + // Count data used + data = handle_entries(data, NULL); + if (!data) continue; + if (data == (char *)2) done++; + if ((long)data <= 2) data = 0; + else data = xstrdup(data); + + break; + } + + // Accumulate cally thing + + if (data && !TT.entries) error_exit("argument too long"); + out = xzalloc((entries+TT.entries+1)*sizeof(char *)); + + if (dlist) { + struct double_list *dtemp; + + // Fill out command line to exec + memcpy(out, toys.optargs, entries*sizeof(char *)); + TT.entries = 0; + TT.bytes = bytes; + dlist->prev->next = 0; + for (dtemp = dlist; dtemp; dtemp = dtemp->next) + handle_entries(dtemp->data, out+entries); + } + pid_t pid=fork(); + if (!pid) { + xclose(0); + open("/dev/null", O_RDONLY); + xexec(out); + } + waitpid(pid, &status, 0); + status = WEXITSTATUS(status); + + // Abritrary number of execs, can't just leak memory each time... + while (dlist) { + struct double_list *dtemp = dlist->next; + + free(dlist->data); + free(dlist); + dlist = dtemp; + } + free(out); + } +} diff -r 2d7c56913fda -r 2986aa63a021 toys/printenv.c --- a/toys/printenv.c Sat Aug 25 14:24:24 2012 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,47 +0,0 @@ -/* vi: set sw=4 ts=4: - * - * printenv.c - Print environment variables. - * - * Copyright 2012 Georgi Chorbadzhiyski - * - -USE_PRINTENV(NEWTOY(printenv, "0(null)", TOYFLAG_USR|TOYFLAG_BIN)) - -config PRINTENV - bool "printenv" - default y - help - usage: printenv [-0] [env_var...] - - Print environment variables. - - -0 Use \0 as delimiter instead of \n -*/ - -#include "toys.h" - -extern char **environ; - -void printenv_main(void) -{ - char **env, **var = toys.optargs; - char delim = '\n'; - - if (toys.optflags) delim = 0; - - do { - int catch = 0, len = *var ? strlen(*var) : 0; - - for (env = environ; *env; env++) { - char *out = *env; - if (*var) { - if (!strncmp(out, *var, len) && out[len] == '=') - out += len +1; - else continue; - } - xprintf("%s%c", out, delim); - catch++; - } - if (*var && !catch) toys.exitval = 1; - } while (*var && *(++var)); -} diff -r 2d7c56913fda -r 2986aa63a021 toys/pwd.c --- a/toys/pwd.c Sat Aug 25 14:24:24 2012 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,30 +0,0 @@ -/* vi: set sw=4 ts=4: - * - * pwd.c - Print working directory. - * - * Copyright 2006 Rob Landley - * - * See http://www.opengroup.org/onlinepubs/009695399/utilities/echo.html - * - * TODO: add -L -P - -USE_PWD(NEWTOY(pwd, NULL, TOYFLAG_BIN)) - -config PWD - bool "pwd" - default y - help - usage: pwd - - The print working directory command prints the current directory. -*/ - -#include "toys.h" - -void pwd_main(void) -{ - char *pwd = xgetcwd(); - - xprintf("%s\n", pwd); - if (CFG_TOYBOX_FREE) free(pwd); -} diff -r 2d7c56913fda -r 2986aa63a021 toys/readlink.c --- a/toys/readlink.c Sat Aug 25 14:24:24 2012 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,45 +0,0 @@ -/* vi: set sw=4 ts=4: - * - * readlink.c - Return string representation of a symbolic link. - * - * Copyright 2007 Rob Landley - * - * Not in SUSv3. - -USE_READLINK(NEWTOY(readlink, "<1f", TOYFLAG_BIN)) - -config READLINK - bool "readlink" - default n - help - usage: readlink - - Show what a symbolic link points to. - -config READLINK_F - bool "readlink -f" - default n - depends on READLINK - help - usage: readlink [-f] - - -f Show full cannonical path, with no symlinks in it. Returns - nonzero if nothing could currently exist at this location. -*/ - -#include "toys.h" - -void readlink_main(void) -{ - char *s; - - // Calculating full cannonical path? - - if (CFG_READLINK_F && toys.optflags) s = xrealpath(*toys.optargs); - else s = xreadlink(*toys.optargs); - - if (s) { - xputs(s); - if (CFG_TOYBOX_FREE) free(s); - } else toys.exitval = 1; -} diff -r 2d7c56913fda -r 2986aa63a021 toys/realpath.c --- a/toys/realpath.c Sat Aug 25 14:24:24 2012 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,31 +0,0 @@ -/* vi: set sw=4 ts=4: - * - * realpath.c - Return the canonical version of a pathname - * - * Copyright 2012 Andre Renaud - * - * Not in SUSv4. - -USE_REALPATH(NEWTOY(realpath, "<1", TOYFLAG_USR|TOYFLAG_BIN)) - -config REALPATH - bool "realpath" - default y - help - usage: realpath FILE... - - Display the canonical absolute pathname -*/ - -#include "toys.h" - -void realpath_main(void) -{ - char **s = toys.optargs; - for (s = toys.optargs; *s; s++) { - if (!realpath(*s, toybuf)) { - perror_msg("cannot access '%s'", *s); - toys.exitval = 1; - } else xputs(toybuf); - } -} diff -r 2d7c56913fda -r 2986aa63a021 toys/rmdir.c --- a/toys/rmdir.c Sat Aug 25 14:24:24 2012 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,43 +0,0 @@ -/* vi: set sw=4 ts=4: - * - * rmdir.c - remove directory/path - * - * Copyright 2008 Rob Landley - * - * See http://opengroup.org/onlinepubs/9699919799/utilities/rmdir.html - -USE_RMDIR(NEWTOY(rmdir, "<1p", TOYFLAG_BIN)) - -config RMDIR - bool "rmdir" - default y - help - usage: rmdir [-p] [dirname...] - Remove one or more directories. - - -p Remove path. -*/ - -#include "toys.h" - -static void do_rmdir(char *name) -{ - for (;;) { - char *temp; - - if (rmdir(name)) { - perror_msg("%s",name); - return; - } - if (!toys.optflags) return; - if (!(temp=strrchr(name,'/'))) return; - *temp=0; - } -} - -void rmdir_main(void) -{ - char **s; - - for (s=toys.optargs; *s; s++) do_rmdir(*s); -} diff -r 2d7c56913fda -r 2986aa63a021 toys/rmmod.c --- a/toys/rmmod.c Sat Aug 25 14:24:24 2012 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,51 +0,0 @@ -/* vi: set sw=4 ts=4: - * - * rmmod.c - Remove a module from the Linux kernel. - * - * Copyright 2012 Elie De Brauwer - * - * Not in SUSv4. - -USE_RMMOD(NEWTOY(rmmod, "<1wf", TOYFLAG_BIN|TOYFLAG_NEEDROOT)) - -config RMMOD - bool "rmmod" - default y - help - usage: rmmod [-wf] [MODULE] - - Unload the module named MODULE from the Linux kernel. - -f Force unload of a module - -w Wait until the module is no longer used. - -*/ - -#include "toys.h" - -#include -#define delete_module(mod, flags) syscall(__NR_delete_module, mod, flags) - -void rmmod_main(void) -{ - unsigned int flags = O_NONBLOCK|O_EXCL; - char * mod_name; - int len; - - // Basename - mod_name = strrchr(toys.optargs[0],'/'); - if (mod_name) - mod_name++; - else - mod_name = toys.optargs[0]; - - // Remove .ko if present - len = strlen(mod_name); - if (len > 3 && !strcmp(&mod_name[len-3], ".ko" )) - mod_name[len-3] = 0; - - if (toys.optflags & 1) flags |= O_TRUNC; - if (toys.optflags & 2) flags &= ~O_NONBLOCK; - - if (delete_module(mod_name, flags)) - perror_exit("failed to unload %s", mod_name); -} diff -r 2d7c56913fda -r 2986aa63a021 toys/sed.c --- a/toys/sed.c Sat Aug 25 14:24:24 2012 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,63 +0,0 @@ -/* vi: set sw=4 ts=4: - * - * sed.c - Stream editor. - * - * Copyright 2008 Rob Landley - * - * See http://www.opengroup.org/onlinepubs/009695399/utilities/sed.c - -USE_SED(NEWTOY(sed, "irne*", TOYFLAG_BIN)) - -config SED - bool "sed" - default n - help - usage: sed [-irn] {command | [-e command]...} [FILE...] - - Stream EDitor, transforms text by appling commands to each line - of input. -*/ - -#include "toys.h" -#include "lib/xregcomp.h" - -DEFINE_GLOBALS( - struct arg_list *commands; -) - -#define TT this.sed - -struct sed_command { - // Doubly linked list of commands. - struct sed_command *next, *prev; - - // Regexes for s/match/data/ and /match_begin/,/match_end/command - regex_t *match, *match_begin, *match_end; - - // For numeric ranges ala 10,20command - int first_line, last_line; - - // Which match to replace, 0 for all. - int which; - - // s and w commands can write to a file. Slight optimization: we use 0 - // instead of -1 to mean no file here, because even when there's no stdin - // our input file would take fd 0. - int outfd; - - // Data string for (saicytb) - char *data; - - // Which command letter is this? - char command; -}; - -void sed_main(void) -{ - struct arg_list *test; - - for (test = TT.commands; test; test = test->next) - dprintf(2,"command=%s\n",test->arg); - - printf("Hello world\n"); -} diff -r 2d7c56913fda -r 2986aa63a021 toys/seq.c --- a/toys/seq.c Sat Aug 25 14:24:24 2012 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,48 +0,0 @@ -/* vi: set sw=4 ts=4: - * - * seq.c - Count from first to last, by increment. - * - * Copyright 2006 Rob Landley - * - * Not in SUSv3. (Don't ask me why not.) - -USE_SEQ(NEWTOY(seq, "<1>3?", TOYFLAG_USR|TOYFLAG_BIN)) - -config SEQ - bool "seq" - depends on TOYBOX_FLOAT - default y - help - usage: seq [first] [increment] last - - Count from first to last, by increment. Omitted arguments default - to 1. Two arguments are used as first and last. Arguments can be - negative or floating point. -*/ - -#include "toys.h" - -void seq_main(void) -{ - double first, increment, last, dd; - - // Parse command line arguments, with appropriate defaults. - // Note that any non-numeric arguments are treated as zero. - first = increment = 1; - switch (toys.optc) { - case 3: - increment = atof(toys.optargs[1]); - case 2: - first = atof(*toys.optargs); - default: - last = atof(toys.optargs[toys.optc-1]); - } - - // Yes, we're looping on a double. Yes rounding errors can accumulate if - // you use a non-integer increment. Deal with it. - for (dd=first; (increment>0 && dd<=last) || (increment <0 && dd>=last); - dd+=increment) - { - printf("%g\n", dd); - } -} diff -r 2d7c56913fda -r 2986aa63a021 toys/setsid.c --- a/toys/setsid.c Sat Aug 25 14:24:24 2012 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,33 +0,0 @@ -/* vi: set sw=4 ts=4: - * - * setsid.c - Run program in a new session ID. - * - * Copyright 2006 Rob Landley - * - * Not in SUSv4. - -USE_SETSID(NEWTOY(setsid, "^<1t", TOYFLAG_USR|TOYFLAG_BIN)) - -config SETSID - bool "setsid" - default y - help - usage: setsid [-t] command [args...] - - Run process in a new session. - - -t Grab tty (become foreground process, receiving keyboard signals) -*/ - -#include "toys.h" - -void setsid_main(void) -{ - while (setsid()<0) - if (vfork()) _exit(0); - if (toys.optflags) { - setpgid(0,0); - tcsetpgrp(0, getpid()); - } - xexec(toys.optargs); -} diff -r 2d7c56913fda -r 2986aa63a021 toys/sha1sum.c --- a/toys/sha1sum.c Sat Aug 25 14:24:24 2012 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,185 +0,0 @@ -/* vi: set sw=4 ts=4: - * - * sha1sum.c - Calculate sha1 cryptographic hash for input. - * - * Copyright 2007 Rob Landley - * - * Based on the public domain SHA-1 in C by Steve Reid - * from http://www.mirrors.wiretapped.net/security/cryptography/hashes/sha1/ - * - * Not in SUSv3. - -USE_SHA1SUM(NEWTOY(sha1sum, NULL, TOYFLAG_USR|TOYFLAG_BIN)) - -config SHA1SUM - bool "sha1sum" - default y - help - usage: sha1sum [file...] - - Calculate sha1 hash of files (or stdin). -*/ - -#include - -struct sha1 { - uint32_t state[5]; - uint32_t oldstate[5]; - uint64_t count; - union { - unsigned char c[64]; - uint32_t i[16]; - } buffer; -}; - -static void sha1_init(struct sha1 *this); -static void sha1_transform(struct sha1 *this); -static void sha1_update(struct sha1 *this, char *data, unsigned int len); -static void sha1_final(struct sha1 *this, char digest[20]); - -#define rol(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits)))) - -// blk0() and blk() perform the initial expand. -// The idea of expanding during the round function comes from SSLeay -#if 1 -#define blk0(i) (block[i] = (rol(block[i],24)&0xFF00FF00) \ - |(rol(block[i],8)&0x00FF00FF)) -#else // big endian? -#define blk0(i) block[i] -#endif -#define blk(i) (block[i&15] = rol(block[(i+13)&15]^block[(i+8)&15] \ - ^block[(i+2)&15]^block[i&15],1)) - -static const uint32_t rconsts[]={0x5A827999,0x6ED9EBA1,0x8F1BBCDC,0xCA62C1D6}; - -// Hash a single 512-bit block. This is the core of the algorithm. - -static void sha1_transform(struct sha1 *this) -{ - int i, j, k, count; - uint32_t *block = this->buffer.i; - uint32_t *rot[5], *temp; - - // Copy context->state[] to working vars - for (i=0; i<5; i++) { - this->oldstate[i] = this->state[i]; - rot[i] = this->state + i; - } - // 4 rounds of 20 operations each. - for (i=count=0; i<4; i++) { - for (j=0; j<20; j++) { - uint32_t work; - - work = *rot[2] ^ *rot[3]; - if (!i) work = (work & *rot[1]) ^ *rot[3]; - else { - if (i==2) - work = ((*rot[1]|*rot[2])&*rot[3])|(*rot[1]&*rot[2]); - else work ^= *rot[1]; - } - if (!i && j<16) work += blk0(count); - else work += blk(count); - *rot[4] += work + rol(*rot[0],5) + rconsts[i]; - *rot[1] = rol(*rot[1],30); - - // Rotate by one for next time. - temp = rot[4]; - for (k=4; k; k--) rot[k] = rot[k-1]; - *rot = temp; - count++; - } - } - // Add the previous values of state[] - for (i=0; i<5; i++) this->state[i] += this->oldstate[i]; -} - - -// Initialize a struct sha1. - -static void sha1_init(struct sha1 *this) -{ - /* SHA1 initialization constants */ - this->state[0] = 0x67452301; - this->state[1] = 0xEFCDAB89; - this->state[2] = 0x98BADCFE; - this->state[3] = 0x10325476; - this->state[4] = 0xC3D2E1F0; - this->count = 0; -} - -// Fill the 64-byte working buffer and call sha1_transform() when full. - -void sha1_update(struct sha1 *this, char *data, unsigned int len) -{ - unsigned int i, j; - - j = this->count & 63; - this->count += len; - - // Enough data to process a frame? - if ((j + len) > 63) { - i = 64-j; - memcpy(this->buffer.c + j, data, i); - sha1_transform(this); - for ( ; i + 63 < len; i += 64) { - memcpy(this->buffer.c, data + i, 64); - sha1_transform(this); - } - j = 0; - } else i = 0; - // Grab remaining chunk - memcpy(this->buffer.c + j, data + i, len - i); -} - -// Add padding and return the message digest. - -void sha1_final(struct sha1 *this, char digest[20]) -{ - uint64_t count = this->count << 3; - unsigned int i; - char buf; - - // End the message by appending a "1" bit to the data, ending with the - // message size (in bits, big endian), and adding enough zero bits in - // between to pad to the end of the next 64-byte frame. - // - // Since our input up to now has been in whole bytes, we can deal with - // bytes here too. - - buf = 0x80; - do { - sha1_update(this, &buf, 1); - buf = 0; - } while ((this->count & 63) != 56); - for (i = 0; i < 8; i++) - this->buffer.c[56+i] = count >> (8*(7-i)); - sha1_transform(this); - - for (i = 0; i < 20; i++) - digest[i] = this->state[i>>2] >> ((3-(i & 3)) * 8); - // Wipe variables. Cryptogropher paranoia. - memset(this, 0, sizeof(struct sha1)); -} - -// Callback for loopfiles() - -static void do_sha1(int fd, char *name) -{ - struct sha1 this; - int len; - - sha1_init(&this); - for (;;) { - len = read(fd, toybuf, sizeof(toybuf)); - if (len<1) break; - sha1_update(&this, toybuf, len); - } - sha1_final(&this, toybuf); - for (len = 0; len < 20; len++) printf("%02x", toybuf[len]); - printf(" %s\n", name); -} - -void sha1sum_main(void) -{ - loopfiles(toys.optargs, do_sha1); -} diff -r 2d7c56913fda -r 2986aa63a021 toys/sleep.c --- a/toys/sleep.c Sat Aug 25 14:24:24 2012 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,51 +0,0 @@ -/* vi: set sw=4 ts=4: - * - * sleep.c - Wait for a number of seconds. - * - * Copyright 2007 Rob Landley - * Copyright 2012 Georgi Chorbadzhiyski - * - * See http://www.opengroup.org/onlinepubs/009695399/utilities/sleep.html - -USE_SLEEP(NEWTOY(sleep, "<1", TOYFLAG_BIN)) - -config SLEEP - bool "sleep" - default y - help - usage: sleep SECONDS - - Wait before exiting. - -config SLEEP_FLOAT - bool - default y - depends on SLEEP && TOYBOX_FLOAT - help - The delay can be a decimal fraction. An optional suffix can be "m" - (minutes), "h" (hours), "d" (days), or "s" (seconds, the default). -*/ - -#include "toys.h" - -void sleep_main(void) -{ - - if (!CFG_TOYBOX_FLOAT) toys.exitval = sleep(atol(*toys.optargs)); - else { - char *arg; - double d = strtod(*toys.optargs, &arg); - struct timespec tv; - - // Parse suffix - if (*arg) { - int ismhd[]={1,60,3600,86400}; - char *smhd = "smhd", *c = strchr(smhd, *arg); - if (!c) error_exit("Unknown suffix '%c'", *arg); - d *= ismhd[c-smhd]; - } - - tv.tv_nsec=1000000000*(d-(tv.tv_sec = (unsigned long)d)); - toys.exitval = !!nanosleep(&tv, NULL); - } -} diff -r 2d7c56913fda -r 2986aa63a021 toys/sort.c --- a/toys/sort.c Sat Aug 25 14:24:24 2012 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,421 +0,0 @@ -/* vi: set sw=4 ts=4: - * - * sort.c - put input lines into order - * - * Copyright 2004, 2008 Rob Landley - * - * See http://www.opengroup.org/onlinepubs/007904975/utilities/sort.html - -USE_SORT(NEWTOY(sort, USE_SORT_FLOAT("g")USE_SORT_BIG("S:T:m" "o:k*t:xbMcszdfi") "run", TOYFLAG_USR|TOYFLAG_BIN)) - -config SORT - bool "sort" - default y - help - usage: sort [-run] [FILE...] - - Sort all lines of text from input files (or stdin) to stdout. - - -r reverse - -u unique lines only - -n numeric order (instead of alphabetical) - -config SORT_BIG - bool "SuSv3 options (Support -ktcsbdfiozM)" - default y - depends on SORT - help - usage: sort [-bcdfiMsz] [-k#[,#[x]] [-t X]] [-o FILE] - - -b ignore leading blanks (or trailing blanks in second part of key) - -c check whether input is sorted - -d dictionary order (use alphanumeric and whitespace chars only) - -f force uppercase (case insensitive sort) - -i ignore nonprinting characters - -M month sort (jan, feb, etc). - -x Hexadecimal numerical sort - -s skip fallback sort (only sort with keys) - -z zero (null) terminated input - -k sort by "key" (see below) - -t use a key separator other than whitespace - -o output to FILE instead of stdout - - Sorting by key looks at a subset of the words on each line. -k2 - uses the second word to the end of the line, -k2,2 looks at only - the second word, -k2,4 looks from the start of the second to the end - of the fourth word. Specifying multiple keys uses the later keys as - tie breakers, in order. A type specifier appended to a sort key - (such as -2,2n) applies only to sorting that key. - -config SORT_FLOAT - bool "Floating point (-g)" - default y - depends on SORT_BIG - help - usage: sort [-g] - - This version of sort requires floating point. - - -g general numeric sort (double precision with nan and inf) - -*/ - -#include "toys.h" - -DEFINE_GLOBALS( - char *key_separator; - struct arg_list *raw_keys; - char *outfile; - char *ignore1, ignore2; // GNU compatability NOPs for -S and -T. - - void *key_list; - int linecount; - char **lines; -) - -#define TT this.sort - -// The sort types are n, g, and M. -// u, c, s, and z apply to top level only, not to keys. -// b at top level implies bb. -// The remaining options can be applied to search keys. - -#define FLAG_n (1<<0) // Sort type: numeric -#define FLAG_u (1<<1) // Unique -#define FLAG_r (1<<2) // Reverse output order - -#define FLAG_i (1<<3) // Ignore !isprint() -#define FLAG_f (1<<4) // Force uppercase -#define FLAG_d (1<<5) // Ignore !(isalnum()|isspace()) -#define FLAG_z (1<<6) // Input is null terminated, not \n -#define FLAG_s (1<<7) // Stable sort, no ascii fallback at end -#define FLAG_c (1<<8) // Check only. No output, exit(!ordered) -#define FLAG_M (1<<9) // Sort type: date -#define FLAG_b (1<<10) // Ignore leading blanks -#define FLAG_x (1<<11) // Hex sort -#define FLAG_g (1<<18) // Sort type: strtod() - -// Left off dealing with FLAG_b/FLAG_bb logic... - -#define FLAG_bb (1<<31) // Ignore trailing blanks - -struct sort_key -{ - struct sort_key *next_key; // linked list - unsigned range[4]; // start word, start char, end word, end char - int flags; -}; - -// Copy of the part of this string corresponding to a key/flags. - -static char *get_key_data(char *str, struct sort_key *key, int flags) -{ - int start=0, end, len, i, j; - - // Special case whole string, so we don't have to make a copy - - if(key->range[0]==1 && !key->range[1] && !key->range[2] && !key->range[3] - && !(flags&(FLAG_b&FLAG_d&FLAG_f&FLAG_i&FLAG_bb))) return str; - - // Find start of key on first pass, end on second pass - - len = strlen(str); - for (j=0; j<2; j++) { - if (!key->range[2*j]) end=len; - - // Loop through fields - else { - end=0; - for (i=1; i < key->range[2*j]+j; i++) { - - // Skip leading blanks - if (str[end] && !TT.key_separator) - while (isspace(str[end])) end++; - - // Skip body of key - for (; str[end]; end++) { - if (TT.key_separator) { - if (str[end]==*TT.key_separator) break; - } else if (isspace(str[end])) break; - } - } - } - if (!j) start=end; - } - - // Key with explicit separator starts after the separator - if (TT.key_separator && str[start]==*TT.key_separator) start++; - - // Strip leading and trailing whitespace if necessary - if (flags&FLAG_b) while (isspace(str[start])) start++; - if (flags&FLAG_bb) while (end>start && isspace(str[end-1])) end--; - - // Handle offsets on start and end - if (key->range[3]) { - end += key->range[3]-1; - if (end>len) end=len; - } - if (key->range[1]) { - start += key->range[1]-1; - if (start>len) start=len; - } - - // Make the copy - if (endnext_key); - return *pkey = xzalloc(sizeof(struct sort_key)); -} - -// Perform actual comparison -static int compare_values(int flags, char *x, char *y) -{ - int ff = flags & (FLAG_n|FLAG_g|FLAG_M|FLAG_x); - - // Ascii sort - if (!ff) return strcmp(x, y); - - if (CFG_SORT_FLOAT && ff == FLAG_g) { - char *xx,*yy; - double dx = strtod(x,&xx), dy = strtod(y,&yy); - int xinf, yinf; - - // not numbers < NaN < -infinity < numbers < +infinity - - if (x==xx) return y==yy ? 0 : -1; - if (y==yy) return 1; - - // Check for isnan - if (dx!=dx) return (dy!=dy) ? 0 : -1; - if (dy!=dy) return 1; - - // Check for infinity. (Could underflow, but avoids needing libm.) - xinf = (1.0/dx == 0.0); - yinf = (1.0/dy == 0.0); - if (xinf) { - if(dx<0) return (yinf && dy<0) ? 0 : -1; - return (yinf && dy>0) ? 0 : 1; - } - if (yinf) return dy<0 ? 1 : -1; - - return dx>dy ? 1 : (dxdy ? 1 : (dxnext_key) - { - flags = key->flags ? key->flags : toys.optflags; - - // Chop out and modify key chunks, handling -dfib - - x = get_key_data(xx, key, flags); - y = get_key_data(yy, key, flags); - - retval = compare_values(flags, x, y); - - // Free the copies get_key_data() made. - - if (x != xx) free(x); - if (y != yy) free(y); - - if (retval) break; - } - } else retval = compare_values(flags, xx, yy); - - // Perform fallback sort if necessary - if (!retval && !(CFG_SORT_BIG && (toys.optflags&FLAG_s))) { - retval = strcmp(xx, yy); - flags = toys.optflags; - } - - return retval * ((flags&FLAG_r) ? -1 : 1); -} - -// Callback from loopfiles to handle input files. -static void sort_read(int fd, char *name) -{ - // Read each line from file, appending to a big array. - - for (;;) { - char * line = (CFG_SORT_BIG && (toys.optflags&FLAG_z)) - ? get_rawline(fd, NULL, 0) : get_line(fd); - - if (!line) break; - - // handle -c here so we don't allocate more memory than necessary. - if (CFG_SORT_BIG && (toys.optflags&FLAG_c)) { - int j = (toys.optflags&FLAG_u) ? -1 : 0; - - if (TT.lines && compare_keys((void *)&TT.lines, &line)>j) - error_exit("%s: Check line %d\n", name, TT.linecount); - free(TT.lines); - TT.lines = (char **)line; - } else { - if (!(TT.linecount&63)) - TT.lines = xrealloc(TT.lines, sizeof(char *)*(TT.linecount+64)); - TT.lines[TT.linecount] = line; - } - TT.linecount++; - } -} - -void sort_main(void) -{ - int idx, fd = 1; - - // Open output file if necessary. - if (CFG_SORT_BIG && TT.outfile) - fd = xcreate(TT.outfile, O_CREAT|O_TRUNC|O_WRONLY, 0666); - - // Parse -k sort keys. - if (CFG_SORT_BIG && TT.raw_keys) { - struct arg_list *arg; - - for (arg = TT.raw_keys; arg; arg = arg->next) { - struct sort_key *key = add_key(); - char *temp; - int flag; - - idx = 0; - temp = arg->arg; - while (*temp) { - // Start of range - key->range[2*idx] = (unsigned)strtol(temp, &temp, 10); - if (*temp=='.') - key->range[(2*idx)+1] = (unsigned)strtol(temp+1, &temp, 10); - - // Handle flags appended to a key type. - for (;*temp;temp++) { - char *temp2, *optlist; - - // Note that a second comma becomes an "Unknown key" error. - - if (*temp==',' && !idx++) { - temp++; - break; - } - - // Which flag is this? - - optlist = toys.which->options; - temp2 = strchr(optlist, *temp); - flag = (1<<(optlist-temp2+strlen(optlist)-1)); - - // Was it a flag that can apply to a key? - - if (!temp2 || flag>FLAG_b - || (flag&(FLAG_u|FLAG_c|FLAG_s|FLAG_z))) - { - error_exit("Unknown key option."); - } - // b after , means strip _trailing_ space, not leading. - if (idx && flag==FLAG_b) flag = FLAG_bb; - key->flags |= flag; - } - } - } - } - - // global b flag strips both leading and trailing spaces - if (toys.optflags&FLAG_b) toys.optflags |= FLAG_bb; - - // If no keys, perform alphabetic sort over the whole line. - if (CFG_SORT_BIG && !TT.key_list) add_key()->range[0] = 1; - - // Open input files and read data, populating TT.lines[TT.linecount] - loopfiles(toys.optargs, sort_read); - - // The compare (-c) logic was handled in sort_read(), - // so if we got here, we're done. - if (CFG_SORT_BIG && (toys.optflags&FLAG_c)) goto exit_now; - - // Perform the actual sort - qsort(TT.lines, TT.linecount, sizeof(char *), compare_keys); - - // handle unique (-u) - if (toys.optflags&FLAG_u) { - int jdx; - - for (jdx=0, idx=1; idx - * - * Not in SUSv4. - -USE_SWAPOFF(NEWTOY(swapoff, "<1>1", TOYFLAG_BIN|TOYFLAG_NEEDROOT)) - -config SWAPOFF - bool "swapoff" - default y - help - usage: swapoff swapregion - - Disable swapping on a given swapregion. -*/ - -#include "toys.h" - -void swapoff_main(void) -{ - if (swapoff(toys.optargs[0])) - perror_exit("failed to remove swaparea"); -} diff -r 2d7c56913fda -r 2986aa63a021 toys/swapon.c --- a/toys/swapon.c Sat Aug 25 14:24:24 2012 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,37 +0,0 @@ -/* vi: set sw=4 ts=4: - * - * swapon.c - Enable region for swapping - * - * Copyright 2012 Elie De Brauwer - * - * Not in SUSv4. - -USE_SWAPON(NEWTOY(swapon, "<1>1p#<0>32767", TOYFLAG_BIN|TOYFLAG_NEEDROOT)) - -config SWAPON - bool "swapon" - default y - help - usage: swapon [-p priority] filename - - Enable swapping on a given device/file. -*/ - -#include "toys.h" - -DEFINE_GLOBALS( - long priority; -) - -#define TT this.swapon - -void swapon_main(void) -{ - int flags = 0; - - if (toys.optflags & 1) - flags = SWAP_FLAG_PREFER | (TT.priority << SWAP_FLAG_PRIO_SHIFT); - - if (swapon(*toys.optargs, flags)) - perror_exit("Couldn't swapon '%s'", *toys.optargs); -} diff -r 2d7c56913fda -r 2986aa63a021 toys/sync.c --- a/toys/sync.c Sat Aug 25 14:24:24 2012 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,25 +0,0 @@ -/* vi: set sw=4 ts=4: - * - * sync.c - Write all pending data to disk. - * - * Copyright 2007 Rob Landley - * - * Not in SUSv3. - -USE_SYNC(NEWTOY(sync, NULL, TOYFLAG_BIN)) - -config SYNC - bool "sync" - default y - help - usage: sync - - Write pending cached data to disk (synchronize), blocking until done. -*/ - -#include "toys.h" - -void sync_main(void) -{ - sync(); -} diff -r 2d7c56913fda -r 2986aa63a021 toys/tac.c --- a/toys/tac.c Sat Aug 25 14:24:24 2012 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,55 +0,0 @@ -/* vi: set sw=4 ts=4: - * - * tac.c - output lines in reverse order - * - * Copyright 2012 Rob Landley - * - * Not in SUSv4. - -USE_TAC(NEWTOY(tac, NULL, TOYFLAG_USR|TOYFLAG_BIN)) - -config TAC - bool "tac" - default y - help - usage: tac [FILE...] - - Output lines in reverse order. -*/ - -#include "toys.h" - -void do_tac(int fd, char *name) -{ - struct arg_list *list = NULL; - char *c; - - // Read in lines - for (;;) { - struct arg_list *temp; - int len; - - if (!(c = get_line(fd))) break; - - len = strlen(c); - if (len && c[len-1]=='\n') c[len-1] = 0; - temp = xmalloc(sizeof(struct arg_list)); - temp->next = list; - temp->arg = c; - list = temp; - } - - // Play them back. - while (list) { - struct arg_list *temp = list->next; - xputs(list->arg); - free(list->arg); - free(list); - list = temp; - } -} - -void tac_main(void) -{ - loopfiles(toys.optargs, do_tac); -} diff -r 2d7c56913fda -r 2986aa63a021 toys/tail.c --- a/toys/tail.c Sat Aug 25 14:24:24 2012 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,232 +0,0 @@ -/* vi: set sw=4 ts=4: - * - * tail.c - copy last lines from input to stdout. - * - * Copyright 2012 Timothy Elliott - * - * See http://www.opengroup.org/onlinepubs/009695399/utilities/tail.html - -USE_TAIL(NEWTOY(tail, "fc-n-", TOYFLAG_BIN)) - -config TAIL - bool "tail" - default y - help - usage: tail [-n|c number] [-f] [file...] - - Copy last lines from files to stdout. If no files listed, copy from - stdin. Filename "-" is a synonym for stdin. - - -n output the last X lines (default 10), +X counts from start. - -c output the last X bytes, +X counts from start - -f follow file, waiting for more data to be appended - -config TAIL_SEEK - bool "tail seek support" - default y - depends on TAIL - help - This version uses lseek, which is faster on large files. -*/ - -#include "toys.h" - -DEFINE_GLOBALS( - long lines; - long bytes; - - int file_no; -) - -#define TT this.tail - -#define FLAG_n 1 -#define FLAG_c 2 -#define FLAG_f 4 - -struct line_list { - struct line_list *next, *prev; - char *data; - int len; -}; - -static struct line_list *get_chunk(int fd, int len) -{ - struct line_list *line = xmalloc(sizeof(struct line_list)+len); - - line->data = ((char *)line) + sizeof(struct line_list); - line->len = readall(fd, line->data, len); - - if (line->len < 1) { - free(line); - return 0; - } - - return line; -} - -static void dump_chunk(void *ptr) -{ - struct line_list *list = ptr; - xwrite(1, list->data, list->len); - free(list); -} - -// Reading through very large files is slow. Using lseek can speed things -// up a lot, but isn't applicable to all input (cat | tail). -// Note: bytes and lines are negative here. -static int try_lseek(int fd, long bytes, long lines) -{ - struct line_list *list = 0, *temp; - int flag = 0, chunk = sizeof(toybuf); - ssize_t pos = lseek(fd, 0, SEEK_END); - - // If lseek() doesn't work on this stream, return now. - if (pos<0) return 0; - - // Seek to the right spot, output data from there. - if (bytes) { - if (lseek(fd, bytes, SEEK_END)<0) lseek(fd, 0, SEEK_SET); - xsendfile(fd, 1); - return 1; - } - - // Read from end to find enough lines, then output them. - - bytes = pos; - while (lines && pos) { - int offset; - - // Read in next chunk from end of file - if (chunk>pos) chunk = pos; - pos -= chunk; - if (pos != lseek(fd, pos, SEEK_SET)) { - perror_msg("seek failed"); - break; - } - if (!(temp = get_chunk(fd, chunk))) break; - if (list) list->next = temp; - list = temp; - - // Count newlines in this chunk. - offset = list->len; - while (offset--) { - // If the last line ends with a newline, that one doesn't count. - if (!flag) { - flag++; - - continue; - } - - // Start outputting data right after newline - if (list->data[offset] == '\n' && !++lines) { - offset++; - list->data += offset; - list->len -= offset; - - break; - } - } - } - - // Output stored data - llist_traverse(list, dump_chunk); - - // In case of -f - lseek(fd, bytes, SEEK_SET); - return 1; -} - -// Called for each file listed on command line, and/or stdin -static void do_tail(int fd, char *name) -{ - long bytes = TT.bytes, lines = TT.lines; - - if (toys.optc > 1) { - if (TT.file_no++) xputc('\n'); - xprintf("==> %s <==\n", name); - } - - // Are we measuring from the end of the file? - - if (bytes<0 || lines<0) { - struct line_list *list = 0, *new; - - // The slow codepath is always needed, and can handle all input, - // so make lseek support optional. - if (CFG_TAIL_SEEK && try_lseek(fd, bytes, lines)); - - // Read data until we run out, keep a trailing buffer - else for (;;) { - int len, count; - char *try; - - if (!(new = get_chunk(fd, sizeof(toybuf)))) break; - // append in order - dlist_add_nomalloc((struct double_list **)&list, - (struct double_list *)new); - - // Measure new chunk, discarding extra data from buffer - len = new->len; - try = new->data; - for (count=0; countdata++); - if (!(--list->len)) { - struct line_list *next = list->next; - list->prev->next = next; - list->next->prev = list->prev; - free(list); - list = next; - } - if (c == '\n') break; - } while (lines); - } - } - - // Output/free the buffer. - llist_traverse(list, dump_chunk); - - // Measuring from the beginning of the file. - } else for (;;) { - int len, offset = 0; - - // Error while reading does not exit. Error writing does. - len = read(fd, toybuf, sizeof(toybuf)); - if (len<1) break; - while (bytes > 1 || lines > 1) { - bytes--; - if (toybuf[offset++] == '\n') lines--; - if (offset >= len) break; - } - if (offset - * - * No standard. - -USE_TASKSET(NEWTOY(taskset, "<1^pa", TOYFLAG_BIN|TOYFLAG_STAYROOT)) - -config TASKSET - bool "taskset" - default y - help - usage: taskset [-ap] [mask] [PID | cmd [args...]] - - Launch a new task which may only run on certain processors, or change - the processor affinity of an exisitng PID. - - Mask is a hex string where each bit represents a processor the process - is allowed to run on. PID without a mask displays existing affinity. - - -p Set/get the affinity of given PID instead of a new command. - -a Set/get the affinity of all threads of the PID. -*/ - -#include "toys.h" - -#define FLAG_a 0x1 -#define FLAG_p 0x2 - -// Prototype for syscall wrappers sched.h refuses to give us -int sched_setaffinity(pid_t pid, size_t size, void *cpuset); -int sched_getaffinity(pid_t pid, size_t size, void *cpuset); - -// mask is an array of long, which makes the layout a bit weird on big -// endian systems but as long as it's consistent... - -static void do_taskset(pid_t pid, int quiet) -{ - unsigned long *mask = (unsigned long *)toybuf; - char *s = *toys.optargs, *failed = "failed to %s %d's affinity"; - int i, j, k; - - for (i=0; ; i++) { - if (!quiet) { - int j = sizeof(toybuf), flag = 0; - - if (sched_getaffinity(pid, sizeof(toybuf), (void *)mask)) - perror_exit(failed, "get", pid); - - printf("pid %d's %s affinity mask: ", pid, i ? "new" : "current"); - - while (j--) { - int x = 255 & (mask[j/sizeof(long)] >> (8*(j&(sizeof(long)-1)))); - - if (flag) printf("%02x", x); - else if (x) { - flag++; - printf("%x", x); - } - } - putchar('\n'); - } - - if (i || toys.optc < 2) return; - - memset(toybuf, 0, sizeof(toybuf)); - k = strlen(s = *toys.optargs); - s += k; - for (j = 0; j 9) digit = 10 + tolower(*s)-'a'; - if (digit > 15) error_exit("bad mask '%s'", *toys.optargs); - mask[j/(2*sizeof(long))] |= digit << 4*(j&((2*sizeof(long))-1)); - } - - if (sched_setaffinity(pid, sizeof(toybuf), (void *)mask)) - perror_exit(failed, "set", pid); - } -} - -static int task_callback(struct dirtree *new) -{ - if (!new->parent) return DIRTREE_RECURSE; - if (isdigit(*new->name)) do_taskset(atoi(new->name), 0); - - return 0; -} - -void taskset_main(void) -{ - if (!(toys.optflags & FLAG_p)) { - if (toys.optc < 2) error_exit("Needs 2 args"); - do_taskset(getpid(), 1); - xexec(toys.optargs+1); - } else { - char *c; - pid_t pid = strtol(toys.optargs[toys.optc-1], &c, 10); - - if (*c) error_exit("Not int %s", toys.optargs[1]); - - if (toys.optflags & FLAG_a) { - char buf[33]; - sprintf(buf, "/proc/%ld/task/", (long)pid); - dirtree_read(buf, task_callback); - } else do_taskset(pid, 0); - } -} diff -r 2d7c56913fda -r 2986aa63a021 toys/tee.c --- a/toys/tee.c Sat Aug 25 14:24:24 2012 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,75 +0,0 @@ -/* vi: set sw=4 ts=4: - * - * tee.c - cat to multiple outputs. - * - * Copyright 2008 Rob Landley - * - * See http://www.opengroup.org/onlinepubs/009695399/utilities/tee.html - -USE_TEE(NEWTOY(tee, "ia", TOYFLAG_BIN)) - -config TEE - bool "tee" - default y - help - usage: tee [-ai] [file...] - - Copy stdin to each listed file, and also to stdout. - Filename "-" is a synonym for stdout. - - -a append to files. - -i ignore SIGINT. -*/ - -#include "toys.h" - -DEFINE_GLOBALS( - void *outputs; -) - -#define TT this.tee - -struct fd_list { - struct fd_list *next; - int fd; -}; - -// Open each output file, saving filehandles to a linked list. - -static void do_tee_open(int fd, char *name) -{ - struct fd_list *temp; - - temp = xmalloc(sizeof(struct fd_list)); - temp->next = TT.outputs; - temp->fd = fd; - TT.outputs = temp; -} - -void tee_main(void) -{ - if (toys.optflags&2) signal(SIGINT, SIG_IGN); - - // Open output files - loopfiles_rw(toys.optargs, - O_RDWR|O_CREAT|((toys.optflags&1)?O_APPEND:O_TRUNC), 0666, 0, - do_tee_open); - - for (;;) { - struct fd_list *fdl; - int len; - - // Read data from stdin - len = xread(0, toybuf, sizeof(toybuf)); - if (len<1) break; - - // Write data to each output file, plus stdout. - fdl = TT.outputs; - for (;;) { - if(len != writeall(fdl ? fdl->fd : 1, toybuf, len)) toys.exitval=1; - if (!fdl) break; - fdl = fdl->next; - } - } - -} diff -r 2d7c56913fda -r 2986aa63a021 toys/toysh.c --- a/toys/toysh.c Sat Aug 25 14:24:24 2012 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,382 +0,0 @@ -/* vi: set sw=4 ts=4: - * - * toysh - toybox shell - * - * Copyright 2006 Rob Landley - * - * The spec for this is at: - * http://www.opengroup.org/onlinepubs/009695399/utilities/xcu_chap02.html - * and http://www.opengroup.org/onlinepubs/009695399/utilities/sh.html - * - * There are also specs for: - * http://www.opengroup.org/onlinepubs/009695399/utilities/cd.html - * http://www.opengroup.org/onlinepubs/009695399/utilities/exit.html - * - * Things like the bash man page are good to read too. - * - * TODO: // Handle embedded NUL bytes in the command line. - -USE_TOYSH(NEWTOY(cd, NULL, TOYFLAG_NOFORK)) -USE_TOYSH(NEWTOY(exit, NULL, TOYFLAG_NOFORK)) -USE_TOYSH(OLDTOY(sh, toysh, "c:i", TOYFLAG_BIN)) -USE_TOYSH(NEWTOY(toysh, "c:i", TOYFLAG_BIN)) - -config TOYSH - bool "sh (toysh)" - default n - help - usage: sh [-c command] [script] - - The toybox command shell. Runs a shell script, or else reads input - interactively and responds to it. - - -c command line to execute - -config TOYSH_TTY - bool "Interactive shell (terminal control)" - default n - depends on TOYSH - help - Add terminal control to toysh. This is necessary for interactive use, - so the shell isn't killed by CTRL-C. - -config TOYSH_PROFILE - bool "Profile support" - default n - depends on TOYSH_TTY - help - Read /etc/profile and ~/.profile when running interactively. - - Also enables the built-in command "source". - -config TOYSH_JOBCTL - bool "Job Control (fg, bg, jobs)" - default n - depends on TOYSH_TTY - help - Add job control to toysh. This lets toysh handle CTRL-Z, and enables - the built-in commands "fg", "bg", and "jobs". - - With pipe support, enable use of "&" to run background processes. - -config TOYSH_FLOWCTL - bool "Flow control (if, while, for, functions)" - default n - depends on TOYSH - help - Add flow control to toysh. This enables the if/then/else/fi, - while/do/done, and for/do/done constructs. - - With pipe support, this enables the ability to define functions - using the "function name" or "name()" syntax, plus curly brackets - "{ }" to group commands. - -config TOYSH_QUOTES - bool "Smarter argument parsing (quotes)" - default n - depends on TOYSH - help - Add support for parsing "" and '' style quotes to the toysh command - parser, with lets arguments have spaces in them. - -config TOYSH_WILDCARDS - bool "Wildcards ( ?*{,} )" - default n - depends on TOYSH_QUOTES - help - Expand wildcards in argument names, ala "ls -l *.t?z" and - "rm subdir/{one,two,three}.txt". - -config TOYSH_PROCARGS - bool "Executable arguments ( `` and $() )" - default n - depends on TOYSH_QUOTES - help - Add support for executing arguments contianing $() and ``, using - the output of the command as the new argument value(s). - - (Bash calls this "command substitution".) - -config TOYSH_ENVVARS - bool "Environment variable support" - default n - depends on TOYSH_QUOTES - help - Substitute environment variable values for $VARNAME or ${VARNAME}, - and enable the built-in command "export". - -config TOYSH_LOCALS - bool "Local variables" - default n - depends on TOYSH_ENVVARS - help - Support for local variables, fancy prompts ($PS1), the "set" command, - and $?. - -config TOYSH_ARRAYS - bool "Array variables" - default n - depends on TOYSH_LOCALS - help - Support for ${blah[blah]} style array variables. - -config TOYSH_PIPES - bool "Pipes and redirects ( | > >> < << & && | || () ; )" - default n - depends on TOYSH - help - Support multiple commands on the same command line. This includes - | pipes, > >> < redirects, << here documents, || && conditional - execution, () subshells, ; sequential execution, and (with job - control) & background processes. - -config TOYSH_BUILTINS - bool "Builtin commands" - default n - depends on TOYSH - help - Adds the commands exec, fg, bg, help, jobs, pwd, export, source, set, - unset, read, alias. - -config EXIT - bool - default n - depends on TOYSH - help - usage: exit [status] - - Exit shell. If no return value supplied on command line, use value - of most recent command, or 0 if none. - -config CD - bool - default n - depends on TOYSH - help - usage: cd [path] - - Change current directory. With no arguments, go to $HOME. - -config CD_P - bool # "-P support for cd" - default n - depends on TOYSH - help - usage: cd [-PL] - - -P Physical path: resolve symlinks in path. - -L Cancel previous -P and restore default behavior. -*/ - -#include "toys.h" - -DEFINE_GLOBALS( - char *command; -) - -#define TT this.toysh - -// A single executable, its arguments, and other information we know about it. -#define TOYSH_FLAG_EXIT 1 -#define TOYSH_FLAG_SUSPEND 2 -#define TOYSH_FLAG_PIPE 4 -#define TOYSH_FLAG_AND 8 -#define TOYSH_FLAG_OR 16 -#define TOYSH_FLAG_AMP 32 -#define TOYSH_FLAG_SEMI 64 -#define TOYSH_FLAG_PAREN 128 - -// What we know about a single process. -struct command { - struct command *next; - int flags; // exit, suspend, && || - int pid; // pid (or exit code) - int argc; - char *argv[0]; -}; - -// A collection of processes piped into/waiting on each other. -struct pipeline { - struct pipeline *next; - int job_id; - struct command *cmd; - char *cmdline; // Unparsed line for display purposes - int cmdlinelen; // How long is cmdline? -}; - -// Parse one word from the command line, appending one or more argv[] entries -// to struct command. Handles environment variable substitution and -// substrings. Returns pointer to next used byte, or NULL if it -// hit an ending token. -static char *parse_word(char *start, struct command **cmd) -{ - char *end; - - // Detect end of line (and truncate line at comment) - if (CFG_TOYSH_PIPES && strchr("><&|(;", *start)) return 0; - - // Grab next word. (Add dequote and envvar logic here) - end = start; - while (*end && !isspace(*end)) end++; - (*cmd)->argv[(*cmd)->argc++] = xstrndup(start, end-start); - - // Allocate more space if there's no room for NULL terminator. - - if (!((*cmd)->argc & 7)) - *cmd=xrealloc(*cmd, - sizeof(struct command) + ((*cmd)->argc+8)*sizeof(char *)); - (*cmd)->argv[(*cmd)->argc] = 0; - return end; -} - -// Parse a line of text into a pipeline. -// Returns a pointer to the next line. - -static char *parse_pipeline(char *cmdline, struct pipeline *line) -{ - struct command **cmd = &(line->cmd); - char *start = line->cmdline = cmdline; - - if (!cmdline) return 0; - - if (CFG_TOYSH_JOBCTL) line->cmdline = cmdline; - - // Parse command into argv[] - for (;;) { - char *end; - - // Skip leading whitespace and detect end of line. - while (isspace(*start)) start++; - if (!*start || *start=='#') { - if (CFG_TOYSH_JOBCTL) line->cmdlinelen = start-cmdline; - return 0; - } - - // Allocate next command structure if necessary - if (!*cmd) *cmd = xzalloc(sizeof(struct command)+8*sizeof(char *)); - - // Parse next argument and add the results to argv[] - end = parse_word(start, cmd); - - // If we hit the end of this command, how did it end? - if (!end) { - if (CFG_TOYSH_PIPES && *start) { - if (*start==';') { - start++; - break; - } - // handle | & < > >> << || && - } - break; - } - start = end; - } - - if (CFG_TOYSH_JOBCTL) line->cmdlinelen = start-cmdline; - - return start; -} - -// Execute the commands in a pipeline -static void run_pipeline(struct pipeline *line) -{ - struct toy_list *tl; - struct command *cmd = line->cmd; - if (!cmd || !cmd->argc) return; - - tl = toy_find(cmd->argv[0]); - // Is this command a builtin that should run in this process? - if (tl && (tl->flags & TOYFLAG_NOFORK)) { - struct toy_context temp; - - // This fakes lots of what toybox_main() does. - memcpy(&temp, &toys, sizeof(struct toy_context)); - memset(&toys, 0, sizeof(struct toy_context)); - toy_init(tl, cmd->argv); - tl->toy_main(); - cmd->pid = toys.exitval; - free(toys.optargs); - if (toys.old_umask) umask(toys.old_umask); - memcpy(&toys, &temp, sizeof(struct toy_context)); - } else { - int status; - - cmd->pid = vfork(); - if (!cmd->pid) xexec(cmd->argv); - else waitpid(cmd->pid, &status, 0); - - if (CFG_TOYSH_FLOWCTL || CFG_TOYSH_PIPES) { - if (WIFEXITED(status)) cmd->pid = WEXITSTATUS(status); - if (WIFSIGNALED(status)) cmd->pid = WTERMSIG(status); - } - } - - return; -} - -// Free the contents of a command structure -static void free_cmd(void *data) -{ - struct command *cmd=(struct command *)data; - - while(cmd->argc) free(cmd->argv[--cmd->argc]); -} - - -// Parse a command line and do what it says to do. -static void handle(char *command) -{ - struct pipeline line; - char *start = command; - - // Loop through commands in this line - - for (;;) { - - // Parse a group of connected commands - - memset(&line,0,sizeof(struct pipeline)); - start = parse_pipeline(start, &line); - if (!line.cmd) break; - - // Run those commands - - run_pipeline(&line); - llist_traverse(line.cmd, free_cmd); - } -} - -void cd_main(void) -{ - char *dest = *toys.optargs ? *toys.optargs : getenv("HOME"); - xchdir(dest); -} - -void exit_main(void) -{ - exit(*toys.optargs ? atoi(*toys.optargs) : 0); -} - -void toysh_main(void) -{ - FILE *f; - - // Set up signal handlers and grab control of this tty. - if (CFG_TOYSH_TTY) { - if (isatty(0)) toys.optflags |= 1; - } - f = *toys.optargs ? xfopen(*toys.optargs, "r") : NULL; - if (TT.command) handle(TT.command); - else { - size_t cmdlen = 0; - for (;;) { - char *command = 0; - if (!f) xputc('$'); - if (1 > getline(&command, &cmdlen, f ? f : stdin)) break; - handle(command); - free(command); - } - } - - toys.exitval = 1; -} diff -r 2d7c56913fda -r 2986aa63a021 toys/true.c --- a/toys/true.c Sat Aug 25 14:24:24 2012 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,23 +0,0 @@ -/* vi: set sw=4 ts=4: - * - * true.c - Return zero. - * - * Copyright 2007 Rob Landley - * - * See http://www.opengroup.org/onlinepubs/009695399/utilities/true.html - -USE_TRUE(NEWTOY(true, NULL, TOYFLAG_BIN)) - -config TRUE - bool "true" - default y - help - Return zero. -*/ - -#include "toys.h" - -void true_main(void) -{ - return; -} diff -r 2d7c56913fda -r 2986aa63a021 toys/truncate.c --- a/toys/truncate.c Sat Aug 25 14:24:24 2012 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,47 +0,0 @@ -/* vi: set sw=4 ts=4: - * - * truncate.c - set file length, extending sparsely if necessary - * - * Copyright 2011 Rob Landley - * - * Not in SUSv4 - -USE_TRUNCATE(NEWTOY(truncate, "<1s#|c", TOYFLAG_BIN)) - -config TRUNCATE - bool "truncate" - default y - help - usage: truncate [-c] -s file... - Set length of file(s), extending sparsely if necessary. - - -c Don't create file if it doesn't exist. - -s New size -*/ - -#include "toys.h" - -DEFINE_GLOBALS( - long size; -) - -#define TT this.truncate - -static void do_truncate(int fd, char *name) -{ - if (fd<0) return; - if (ftruncate(fd, TT.size)) { - perror_msg("failed to set '%s' to '%ld'", name, TT.size); - toys.exitval = EXIT_FAILURE; - } -} - -void truncate_main(void) -{ - int cr = !(toys.optflags&1); - - // Create files with mask rwrwrw. - // Nonexistent files are only an error if we're supposed to create them. - loopfiles_rw(toys.optargs, O_WRONLY|(cr ? O_CREAT : 0), 0666, cr, - do_truncate); -} diff -r 2d7c56913fda -r 2986aa63a021 toys/tty.c --- a/toys/tty.c Sat Aug 25 14:24:24 2012 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,32 +0,0 @@ -/* vi: set sw=4 ts=4: - * - * tty.c - Show stdin's terminal name - * - * Copyright 2011 Rob Landley - * - * See http://opengroup.org/onlinepubs/9699919799/utilities/tty.html - -USE_TTY(NEWTOY(tty, "s", TOYFLAG_USR|TOYFLAG_BIN)) - -config TTY - bool "tty" - default y - help - Show filename of terminal connected to stdin. - - Prints "not a tty" and exits with nonzero status if no terminal - is connected to stdin. - - -s silent mode -*/ - -#include "toys.h" - -void tty_main(void) -{ - char *tty = ttyname(0); - - if (!toys.optflags) puts(tty ? tty : "not a tty"); - - toys.exitval = !tty; -} diff -r 2d7c56913fda -r 2986aa63a021 toys/uname.c --- a/toys/uname.c Sat Aug 25 14:24:24 2012 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,74 +0,0 @@ -/* vi: set sw=4 ts=4: - * - * uname.c - return system name - * - * Copyright 2008 Rob Landley - * - * See http://www.opengroup.org/onlinepubs/009695399/utilities/uname.html - -USE_UNAME(NEWTOY(uname, "amvrns", TOYFLAG_BIN)) - -config UNAME - bool "uname" - default y - help - usage: uname [-asnrvmpio] - - Print system information. - - -s System name - -n Network (domain) name - -r Release number - -v Version (build date) - -m Machine (hardware) name - -a All of the above -*/ - -#include "toys.h" - -// If a 32 bit x86 build environment working in a chroot under an x86-64 -// kernel returns x86_64 for -m it confuses ./configure. Special case it. - -#if defined(__i686__) -#define GROSS "i686" -#elif defined(__i586__) -#define GROSS "i586" -#elif defined(__i486__) -#define GROSS "i486" -#elif defined(__i386__) -#define GROSS "i386" -#endif - -#define FLAG_a (1<<5) - -void uname_main(void) -{ - int i, flags = toys.optflags, needspace=0; - - uname((void *)toybuf); - - if (!flags) flags=1; - for (i=0; i<5; i++) { - char *c = toybuf+(65*i); - - if (flags & ((1< - * - * See http://www.opengroup.org/onlinepubs/009695399/utilities/uniq.html - -USE_UNIQ(NEWTOY(uniq, "f#s#w#zicdu", TOYFLAG_BIN)) - -config UNIQ - bool "uniq" - default y - help - usage: uniq [-cduiz] [-w maxchars] [-f fields] [-s char] [input_file [output_file]] - - Report or filter out repeated lines in a file - - -c show counts before each line - -d show only lines that are repeated - -u show only lines that are unique - -i ignore case when comparing lines - -z lines end with \0 not \n - -w compare maximum X chars per line - -f ignore first X fields - -s ignore first X chars -*/ - -#include "toys.h" - -DEFINE_GLOBALS( - long maxchars; - long nchars; - long nfields; - long repeats; -) - -#define TT this.uniq - -#define FLAG_z 16 -#define FLAG_i 8 -#define FLAG_c 4 -#define FLAG_d 2 -#define FLAG_u 1 - -static char *skip(char *str) -{ - long nchars = TT.nchars, nfields; - - // Skip fields first - for (nfields = TT.nfields; nfields; str++) { - while (*str && isspace(*str)) str++; - while (*str && !isspace(*str)) str++; - nfields--; - } - // Skip chars - while (*str && nchars--) str++; - - return str; -} - -static void print_line(FILE *f, char *line) -{ - if (toys.optflags & (TT.repeats ? FLAG_u : FLAG_d)) return; - if (toys.optflags & FLAG_c) fprintf(f, "%7lu ", TT.repeats + 1); - fputs(line, f); - if (toys.optflags & FLAG_z) fputc(0, f); -} - -void uniq_main(void) -{ - FILE *infile = stdin, *outfile = stdout; - char *thisline = NULL, *prevline = NULL, *tmpline, eol = '\n'; - size_t thissize, prevsize = 0, tmpsize; - - if (toys.optc >= 1) infile = xfopen(toys.optargs[0], "r"); - if (toys.optc >= 2) outfile = xfopen(toys.optargs[1], "w"); - - if (toys.optflags & FLAG_z) eol = 0; - - // If first line can't be read - if (getdelim(&prevline, &prevsize, eol, infile) < 0) - return; - - while (getdelim(&thisline, &thissize, eol, infile) > 0) { - int diff; - char *t1, *t2; - - // If requested get the chosen fields + character offsets. - if (TT.nfields || TT.nchars) { - t1 = skip(thisline); - t2 = skip(prevline); - } else { - t1 = thisline; - t2 = prevline; - } - - if (TT.maxchars == 0) { - diff = !(toys.optflags & FLAG_i) - ? strcmp(t1, t2) - : strcasecmp(t1, t2); - } else { - diff = !(toys.optflags & FLAG_i) - ? strncmp(t1, t2, TT.maxchars) - : strncasecmp(t1, t2, TT.maxchars); - } - - if (diff == 0) { // same - TT.repeats++; - } else { - print_line(outfile, prevline); - - TT.repeats = 0; - - tmpline = prevline; - prevline = thisline; - thisline = tmpline; - - tmpsize = prevsize; - prevsize = thissize; - thissize = tmpsize; - } - } - - print_line(outfile, prevline); - - if (CFG_TOYBOX_FREE) { - free(prevline); - free(thisline); - } -} diff -r 2d7c56913fda -r 2986aa63a021 toys/unlink.c --- a/toys/unlink.c Sat Aug 25 14:24:24 2012 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,26 +0,0 @@ -/* vi: set sw=4 ts=4: - * - * unlink.c - delete one file - * - * Copyright 2011 Rob Landley - * - * See http://opengroup.org/onlinepubs/9699919799/utilities/unlink.html - -USE_UNLINK(NEWTOY(unlink, "<1>1", TOYFLAG_USR|TOYFLAG_BIN)) - -config UNLINK - bool "unlink" - default y - help - usage: unlink FILE - - Deletes one file. -*/ - -#include "toys.h" - -void unlink_main(void) -{ - if (unlink(*toys.optargs)) - perror_exit("Couldn't unlink `%s'", *toys.optargs); -} diff -r 2d7c56913fda -r 2986aa63a021 toys/unshare.c --- a/toys/unshare.c Sat Aug 25 14:24:24 2012 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,45 +0,0 @@ -/* vi: set sw=4 ts=4: - * - * unshare.c - run command in new context - * - * Copyright 2011 Rob Landley - * - * Not in SUSv4. - -USE_UNSHARE(NEWTOY(unshare, "<1^nium", TOYFLAG_USR|TOYFLAG_BIN)) - -config UNSHARE - bool "unshare" - default y - depends on TOYBOX_CONTAINER - help - usage: unshare [-muin] COMMAND... - - Create new namespace(s) for this process and its children, so some - attribute is not shared with the parent process. This is part of - Linux Containers. Each process can have its own: - - -m Mount/unmount tree - -u Host and domain names - -i SysV IPC (message queues, semaphores, shared memory) - -n Network address, sockets, routing, iptables -*/ - -#include "toys.h" -#include -extern int unshare (int __flags); - -void unshare_main(void) -{ - unsigned flags[]={CLONE_NEWNS, CLONE_NEWUTS, CLONE_NEWIPC, CLONE_NEWNET,0}; - unsigned f=0; - int i; - - for (i=0; flags[i]; i++) - if (toys.optflags & (1< - * - * Not in SUSv4. - -USE_UPTIME(NEWTOY(uptime, NULL, TOYFLAG_USR|TOYFLAG_BIN)) - -config UPTIME - bool "uptime" - default y - help - usage: uptime - - Tell how long the system has been running and the system load - averages for the past 1, 5 and 15 minutes. -*/ - -#include "toys.h" - -void uptime_main(void) -{ - struct sysinfo info; - time_t tmptime; - struct tm * now; - unsigned int days, hours, minutes; - - // Obtain the data we need. - sysinfo(&info); - time(&tmptime); - now = localtime(&tmptime); - - // Time - xprintf(" %02d:%02d:%02d up ", now->tm_hour, now->tm_min, now->tm_sec); - // Uptime - info.uptime /= 60; - minutes = info.uptime%60; - info.uptime /= 60; - hours = info.uptime%24; - days = info.uptime/24; - if (days) xprintf("%d day%s, ", days, (days!=1)?"s":""); - if (hours) - xprintf("%2d:%02d, ", hours, minutes); - else - printf("%d min, ", minutes); - - printf(" load average: %.02f %.02f %.02f\n", info.loads[0]/65536.0, - info.loads[1]/65536.0, info.loads[2]/65536.0); - -} diff -r 2d7c56913fda -r 2986aa63a021 toys/usleep.c --- a/toys/usleep.c Sat Aug 25 14:24:24 2012 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,32 +0,0 @@ -/* vi: set sw=4 ts=4: - * - * usleep.c - Wait for a number of microseconds. - * - * Copyright 2012 Elie De Brauwer - * - * No standard. - -USE_USLEEP(NEWTOY(usleep, "<1", TOYFLAG_BIN)) - -config USLEEP - bool "usleep" - default y - help - usage: usleep MICROSECONDS - - Pause for MICROSECONDS microseconds. - -*/ - -#include "toys.h" - -void usleep_main(void) -{ - struct timespec tv; - long delay = atol(*toys.optargs); - - tv.tv_sec = delay/1000000; - tv.tv_nsec = (delay%1000000) * 1000; - toys.exitval = !!nanosleep(&tv, NULL); - -} diff -r 2d7c56913fda -r 2986aa63a021 toys/vmstat.c --- a/toys/vmstat.c Sat Aug 25 14:24:24 2012 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,191 +0,0 @@ -/* vi: set sw=4 ts=4: - * - * vmstat.c - Report virtual memory statistics. - * - * Copyright 2012 Elie De Brauwer - * - * Not in SUSv4. - -USE_VMSTAT(NEWTOY(vmstat, ">2n", TOYFLAG_BIN)) - -config VMSTAT - bool "vmstat" - default y - help - usage: vmstat [-n] [delay [count]] - -n Display the header only once - delay The delay between updates in seconds, when not specified - the average since boot is displayed. - count Number of updates to display, the default is inifinite. -*/ - -#include "toys.h" - -void read_proc_stat(unsigned int * proc_running, unsigned int * proc_blocked, - uint64_t * sys_irq, uint64_t * sys_ctxt, - uint64_t * cpu_user, uint64_t * cpu_sys, uint64_t * cpu_idle, uint64_t * cpu_wait) -{ - char * off; - uint64_t c_user, c_nice, c_sys, c_irq, c_sirq; - int fd = xopen("/proc/stat", O_RDONLY); - size_t s = xread(fd, toybuf, sizeof(toybuf)-1); - toybuf[s] = 0; - if ( s == sizeof(toybuf)-1) - error_exit("/proc/stat is too large"); - - off = strstr(toybuf, "cpu "); - // Ignoring steal and guest fields for now. - if (off) sscanf(off, "cpu %"PRIu64" %"PRIu64" %"PRIu64" %"PRIu64 \ - " %"PRIu64" %"PRIu64" %"PRIu64, &c_user, &c_nice, &c_sys, cpu_idle, - cpu_wait, &c_irq, &c_sirq); - *cpu_user = c_user + c_nice; - *cpu_sys = c_sys + c_irq + c_sirq; - off = strstr(toybuf, "intr"); - if (off) sscanf(off, "intr %"PRIu64, sys_irq); - - off = strstr(toybuf, "ctxt"); - if (off) sscanf(off, "ctxt %"PRIu64, sys_ctxt); - - off = strstr(toybuf, "procs_running"); - if (off) sscanf(off, "procs_running %u", proc_running); - (*proc_running)--; // look, i'm invisible. - - off = strstr(toybuf, "procs_blocked"); - if (off) sscanf(off, "procs_blocked %u", proc_blocked); - - close(fd); -} - -void read_proc_meminfo(unsigned long * mem_swapped, unsigned long * mem_free, - unsigned long * mem_buff, unsigned long * mem_cache) -{ - char * off; - unsigned long swap_total, swap_free; - int fd = xopen("/proc/meminfo", O_RDONLY); - size_t s = xread(fd, toybuf, sizeof(toybuf)-1); - toybuf[s] = 0; - if ( s == sizeof(toybuf)-1) - error_exit("/proc/meminfo is too large"); - - off = strstr(toybuf, "MemFree"); - if (off) sscanf(off, "MemFree: %lu kB", mem_free); - - off = strstr(toybuf, "Buffers"); - if (off) sscanf(off, "Buffers: %lu kB", mem_buff); - - off = strstr(toybuf, "Cached"); - if (off) sscanf(off, "Cached: %lu kB", mem_cache); - - off = strstr(toybuf, "SwapFree"); - if (off) sscanf(off, "SwapFree: %lu kB", &swap_free); - - off = strstr(toybuf, "SwapTotal"); - if (off) sscanf(off, "SwapTotal: %lu kB", &swap_total); - *mem_swapped = swap_total - swap_free; - - close(fd); -} - -void read_proc_vmstat(unsigned long * io_pages_in, unsigned long * io_pages_out, - unsigned long * swap_bytes_in, unsigned long * swap_bytes_out) -{ - char * off; - unsigned long s_pages_in, s_pages_out; - unsigned long pagesize_kb = sysconf(_SC_PAGESIZE) / 1024L; - int fd = xopen("/proc/vmstat", O_RDONLY); - size_t s = xread(fd, toybuf, sizeof(toybuf)-1); - toybuf[s] = 0; - if ( s == sizeof(toybuf)-1) - error_exit("/proc/vmstat is too large"); - - off = strstr(toybuf, "pgpgin"); - if (off) sscanf(off, "pgpgin %lu", io_pages_in); - - off = strstr(toybuf, "pgpgout"); - if (off) sscanf(off, "pgpgout %lu", io_pages_out); - - off = strstr(toybuf, "pswpin"); - if (off) sscanf(off, "pswpin %lu", &s_pages_in); - *swap_bytes_in = s_pages_in * pagesize_kb; - - off = strstr(toybuf, "pswpout"); - if (off) sscanf(off, "pswpout %lu", &s_pages_out); - *swap_bytes_out = s_pages_out * pagesize_kb; - - close(fd); -} - -void vmstat_main(void) -{ - const char fmt[] = "%2u %2u %6lu %6lu %6lu %6lu %4u %4u %5u %5u %4u %4u %2u %2u %2u %2u\n"; - unsigned int loop_num = 0, loop_max_num = 0, loop_delay = 0; - unsigned int running = 0, blocked = 0; - unsigned long mem_swap = 0, mem_free = 0, mem_buff = 0, mem_cache = 0; - unsigned long io_pages_in[2], io_pages_out[2], swap_bytes_in[2], swap_bytes_out[2]; - uint64_t sys_irq[2], sys_ctxt[2], cpu_user[2], cpu_sys[2], cpu_idle[2], cpu_wait[2]; - int first_run = 1; - int no_header = toys.optflags & 0x1; - unsigned num_rows = 22; - - if (toys.optc >= 1) - loop_delay = atoi(toys.optargs[0]); - if (toys.optc >= 2) - loop_max_num = atoi(toys.optargs[1]); - - if (loop_max_num < 0 || loop_delay < 0) - error_exit("Invalid arguments"); - - while(1) { - uint64_t total_jif; - int idx = loop_num%2; - - if(first_run || (!(loop_num % num_rows) && !no_header)) { - unsigned rows = 0, cols = 0; - terminal_size(&cols, &rows); - num_rows = (rows > 3)? rows - 3 : 22; - printf("procs -----------memory---------- ---swap-- -----io---- -system-- ----cpu----\n"); - printf(" r b swpd free buff cache si so bi bo in cs us sy id wa\n"); - } - - read_proc_stat(&running, &blocked, &sys_irq[idx], &sys_ctxt[idx], &cpu_user[idx], - &cpu_sys[idx], &cpu_idle[idx], &cpu_wait[idx]); - read_proc_meminfo(&mem_swap, &mem_free, &mem_buff, &mem_cache); - read_proc_vmstat(&io_pages_in[idx], &io_pages_out[idx], &swap_bytes_in[idx], &swap_bytes_out[idx]); - - if (first_run) { - struct sysinfo inf; - sysinfo(&inf); - first_run = 0; - total_jif = cpu_user[idx] + cpu_idle[idx] + cpu_wait[idx]; - printf(fmt, running, blocked, mem_swap, mem_free, mem_buff, mem_cache, - (unsigned) (swap_bytes_in[idx]/inf.uptime), - (unsigned) (swap_bytes_out[idx]/inf.uptime), - (unsigned) (io_pages_in[idx]/inf.uptime), - (unsigned) (io_pages_out[idx]/inf.uptime), - (unsigned) (sys_irq[idx]/inf.uptime), - (unsigned) (sys_ctxt[idx]/inf.uptime), - (unsigned) (100*cpu_user[idx]/total_jif), - (unsigned) (100*cpu_sys[idx]/total_jif), - (unsigned) (100*cpu_idle[idx]/total_jif), - (unsigned) (100*cpu_wait[idx]/total_jif)); - }else{ - total_jif = cpu_user[idx] - cpu_user[!idx] + cpu_idle[idx] - cpu_idle[!idx] + cpu_wait[idx] - cpu_wait[!idx]; - printf(fmt, running, blocked, mem_swap, mem_free, mem_buff, mem_cache, - (unsigned) ((swap_bytes_in[idx] - swap_bytes_in[!idx])/loop_delay), - (unsigned) ((swap_bytes_out[idx] - swap_bytes_out[!idx])/loop_delay), - (unsigned) ((io_pages_in[idx] - io_pages_in[!idx])/loop_delay), - (unsigned) ((io_pages_out[idx] - io_pages_out[!idx])/loop_delay), - (unsigned) ((sys_irq[idx] - sys_irq[!idx])/loop_delay), - (unsigned) ((sys_ctxt[idx] - sys_ctxt[!idx])/loop_delay), - (unsigned) (100*(cpu_user[idx] - cpu_user[!idx])/total_jif), - (unsigned) (100*(cpu_sys[idx] - cpu_sys[!idx]) /total_jif), - (unsigned) (100*(cpu_idle[idx] - cpu_idle[!idx])/total_jif), - (unsigned) (100*(cpu_wait[idx] - cpu_wait[!idx])/total_jif)); - } - - loop_num++; - if (loop_delay == 0 || (loop_max_num != 0 && loop_num >= loop_max_num)) - break; - sleep(loop_delay); - } -} diff -r 2d7c56913fda -r 2986aa63a021 toys/w.c --- a/toys/w.c Sat Aug 25 14:24:24 2012 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,36 +0,0 @@ -/* vi: set sw=4 ts=4: - * - * w.c - shows logged in users - * - * Copyright 2012 Gaurang Shastri - * - * Not in SUSv4. - -USE_W(NEWTOY(w, NULL, TOYFLAG_USR|TOYFLAG_BIN)) - -config W - bool "w" - default y - help - usage: w - - Show who is logged on and since how long they logged in. -*/ - -#include "toys.h" - -void w_main(void) -{ - struct utmpx *x; - - xprintf("USER TTY LOGIN@ FROM"); - setutxent(); - while ((x=getutxent()) != NULL) - if (x->ut_type==7) { - time_t tt = x->ut_tv.tv_sec; - - xprintf("\n%-9.8s%-9.8s %-4.24s (%-1.12s)", x->ut_user, x->ut_line, - ctime(&tt), x->ut_host); - } - xputc('\n'); -} diff -r 2d7c56913fda -r 2986aa63a021 toys/wc.c --- a/toys/wc.c Sat Aug 25 14:24:24 2012 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,60 +0,0 @@ -/* vi: set sw=4 ts=4: - * - * wc.c - Word count - * - * Copyright 2011 Rob Landley - * - * See http://opengroup.org/onlinepubs/9699919799/utilities/wc.html - -USE_WC(NEWTOY(wc, "cwl", TOYFLAG_USR|TOYFLAG_BIN)) - -config WC - bool "wc" - default y - help - usage: wc -lwc [FILE...] - - Count lines, words, and characters in input. - - -l show lines - -w show words - -c show characters - - By default outputs lines, words, characters, and filename for each - argument (or from stdin if none). -*/ - -#include "toys.h" - -static void do_wc(int fd, char *name) -{ - int i, len; - unsigned long word=0, lengths[]={0,0,0}; - - for (;;) { - len = read(fd, toybuf, sizeof(toybuf)); - if (len<0) { - perror_msg("%s",name); - toys.exitval = EXIT_FAILURE; - } - if (len<1) break; - for (i=0; i - * - * Not in SUSv3. - -USE_WHICH(NEWTOY(which, "<1a", TOYFLAG_USR|TOYFLAG_BIN)) - -config WHICH - bool "which" - default y - help - usage: which [-a] filename ... - - Search $PATH for executable files matching filename(s). - - -a Show all matches -*/ -#include "toys.h" - -// Find an exectuable file either at a path with a slash in it (absolute or -// relative to current directory), or in $PATH. Returns absolute path to file, -// or NULL if not found. - -static int which_in_path(char *filename) -{ - struct string_list *list; - - // If they gave us a path, don't worry about $PATH or -a - - if (strchr(filename, '/')) { - // Confirm it has the executable bit set, and it's not a directory. - if (!access(filename, X_OK)) { - struct stat st; - - if (!stat(filename, &st) && S_ISREG(st.st_mode)) { - puts(filename); - return 0; - } - return 1; - } - } - - // Search $PATH for matches. - list = find_in_path(getenv("PATH"), filename); - if (!list) return 1; - - // Print out matches - while (list) { - if (!access(list->str, X_OK)) { - puts(list->str); - // If we should stop at one match, do so - if (!toys.optflags) { - llist_traverse(list, free); - break; - } - } - free(llist_pop(&list)); - } - - return 0; -} - -void which_main(void) -{ - int i; - for (i=0; toys.optargs[i]; i++) - toys.exitval |= which_in_path(toys.optargs[i]); -} diff -r 2d7c56913fda -r 2986aa63a021 toys/who.c --- a/toys/who.c Sat Aug 25 14:24:24 2012 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,46 +0,0 @@ -/* vi: set sw=4 ts=4: - * - * who.c - display who is on the system - * - * Copyright 2012 ProFUSION Embedded Systems - * - * by Luis Felipe Strano Moraes - * - * See http://pubs.opengroup.org/onlinepubs/9699919799/utilities/who.html - -USE_WHO(NEWTOY(who, NULL, TOYFLAG_BIN)) - -config WHO - bool "who" - default n - help - usage: who - - Print logged user information on system - -*/ - -#include "toys.h" - -void who_main(void) -{ - struct utmpx *entry; - - setutxent(); - - while ((entry = getutxent())) { - if (entry->ut_type == USER_PROCESS) { - time_t time; - int time_size; - char * times; - - time = entry->ut_tv.tv_sec; - times = ctime(&time); - time_size = strlen(times) - 2; - printf("%s\t%s\t%*.*s\t(%s)\n", entry->ut_user, entry->ut_line, time_size, time_size, ctime(&time), entry->ut_host); - - } - } - - endutxent(); -} diff -r 2d7c56913fda -r 2986aa63a021 toys/whoami.c --- a/toys/whoami.c Sat Aug 25 14:24:24 2012 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,32 +0,0 @@ -/* vi: set sw=4 ts=4: - * - * whoami.c - Print effective user name - * - * Copyright 2012 Georgi Chorbadzhiyski - * - -USE_WHOAMI(NEWTOY(whoami, NULL, TOYFLAG_USR|TOYFLAG_BIN)) - -config WHOAMI - bool "whoami" - default y - help - usage: whoami - - Print effective user name. -*/ - -#include "toys.h" - -void whoami_main(void) -{ - struct passwd *pw = getpwuid(geteuid()); - - if (!pw) { - perror("getpwuid"); - toys.exitval = 1; - return; - } - - xputs(pw->pw_name); -} diff -r 2d7c56913fda -r 2986aa63a021 toys/xargs.c --- a/toys/xargs.c Sat Aug 25 14:24:24 2012 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,188 +0,0 @@ -/* vi: set sw=4 ts=4: - * - * xargs.c - Run command with arguments taken from stdin. - * - * Copyright 2011 Rob Landley - * - * See http://opengroup.org/onlinepubs/9699919799/utilities/xargs.html - -USE_XARGS(NEWTOY(xargs, "^I:E:L#ptxrn#<1s#0", TOYFLAG_USR|TOYFLAG_BIN)) - -config XARGS - bool "xargs" - default y - help - usage: xargs [-ptxr0] [-s NUM] [-n NUM] [-L NUM] [-E STR] COMMAND... - - Run command line one or more times, appending arguments from stdin. - - If command exits with 255, don't launch another even if arguments remain. - - -s Size in bytes per command line - -n Max number of arguments per command - -0 Each argument is NULL terminated, no whitespace or quote processing - #-p Prompt for y/n from tty before running each command - #-t Trace, print command line to stderr - #-x Exit if can't fit everything in one command - #-r Don't run command with empty input - #-L Max number of lines of input per command - -E stop at line matching string -*/ - -#include "toys.h" - -DEFINE_GLOBALS( - long max_bytes; - long max_entries; - long L; - char *eofstr; - char *I; - - long entries, bytes; - char delim; -) - -#define TT this.xargs - -// If out==NULL count TT.bytes and TT.entries, stopping at max. -// Otherwise, fill out out[] - -// Returning NULL means need more data. -// Returning char * means hit data limits, start of data left over -// Returning 1 means hit data limits, but consumed all data -// Returning 2 means hit -E eofstr - -static char *handle_entries(char *data, char **entry) -{ - if (TT.delim) { - char *s = data; - - // Chop up whitespace delimited string into args - while (*s) { - char *save; - - while (isspace(*s)) { - if (entry) *s = 0; - s++; - } - - if (TT.max_entries && TT.entries >= TT.max_entries) - return *s ? s : (char *)1; - - if (!*s) break; - save = s; - - for (;;) { - if (++TT.bytes >= TT.max_bytes && TT.max_bytes) return save; - if (!*s || isspace(*s)) break; - s++; - } - if (TT.eofstr) { - int len = s-save; - if (len == strlen(TT.eofstr) && !strncmp(save, TT.eofstr, len)) - return (char *)2; - } - if (entry) entry[TT.entries] = save; - ++TT.entries; - } - - // -0 support - } else { - TT.bytes += strlen(data)+1; - if (TT.max_bytes && TT.bytes >= TT.max_bytes) return data; - if (TT.max_entries && TT.entries >= TT.max_entries) - return (char *)1; - if (entry) entry[TT.entries] = data; - TT.entries++; - } - - return NULL; -} - -void xargs_main(void) -{ - struct double_list *dlist = NULL; - int entries, bytes, done = 0, status; - char *data = NULL; - - if (!(toys.optflags&1)) TT.delim = '\n'; - - // If no optargs, call echo. - if (!toys.optc) { - free(toys.optargs); - *(toys.optargs = xzalloc(2*sizeof(char *)))="echo"; - toys.optc = 1; - } - - for (entries = 0, bytes = -1; entries < toys.optc; entries++, bytes++) - bytes += strlen(toys.optargs[entries]); - - // Loop through exec chunks. - while (data || !done) { - char **out; - - TT.entries = 0; - TT.bytes = bytes; - - // Loop reading input - for (;;) { - - // Read line - if (!data) { - ssize_t l = 0; - l = getdelim(&data, (size_t *)&l, TT.delim, stdin); - - if (l<0) { - data = 0; - done++; - break; - } - } - dlist_add(&dlist, data); - - // Count data used - data = handle_entries(data, NULL); - if (!data) continue; - if (data == (char *)2) done++; - if ((long)data <= 2) data = 0; - else data = xstrdup(data); - - break; - } - - // Accumulate cally thing - - if (data && !TT.entries) error_exit("argument too long"); - out = xzalloc((entries+TT.entries+1)*sizeof(char *)); - - if (dlist) { - struct double_list *dtemp; - - // Fill out command line to exec - memcpy(out, toys.optargs, entries*sizeof(char *)); - TT.entries = 0; - TT.bytes = bytes; - dlist->prev->next = 0; - for (dtemp = dlist; dtemp; dtemp = dtemp->next) - handle_entries(dtemp->data, out+entries); - } - pid_t pid=fork(); - if (!pid) { - xclose(0); - open("/dev/null", O_RDONLY); - xexec(out); - } - waitpid(pid, &status, 0); - status = WEXITSTATUS(status); - - // Abritrary number of execs, can't just leak memory each time... - while (dlist) { - struct double_list *dtemp = dlist->next; - - free(dlist->data); - free(dlist); - dlist = dtemp; - } - free(out); - } -} diff -r 2d7c56913fda -r 2986aa63a021 toys/yes.c --- a/toys/yes.c Sat Aug 25 14:24:24 2012 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,33 +0,0 @@ -/* vi: set sw=4 ts=4: - * - * yes.c - Repeatedly output a string. - * - * Copyright 2007 Rob Landley - * - * Not in SUSv3. - -USE_YES(NEWTOY(yes, NULL, TOYFLAG_USR|TOYFLAG_BIN)) - -config YES - bool "yes" - default y - help - usage: yes [args...] - - Repeatedly output line until killed. If no args, output 'y'. -*/ - -#include "toys.h" - -void yes_main(void) -{ - for (;;) { - int i; - for (i=0; toys.optargs[i]; i++) { - if (i) xputc(' '); - xprintf("%s", toys.optargs[i]); - } - if (!i) xputc('y'); - xputc('\n'); - } -}