From 2783acaf7c52cf0f2093284c35cb0c079453005d Mon Sep 17 00:00:00 2001 From: h60047265 Date: Sat, 23 Aug 2025 18:21:58 +0800 Subject: [PATCH] =?UTF-8?q?::toybox=E5=B7=AE=E5=BC=82=E5=90=8C=E6=AD=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: h60047265 --- generated/flags.h | 95 ++--- generated/globals.h | 27 +- generated/help.h | 20 +- generated/newtoys.h | 13 +- install.py | 2 - lib/lib.c | 23 -- lib/lib.h | 19 +- lib/net.c | 83 ---- lib/xwrap.c | 16 +- porting/liteos_a/toys.h | 2 +- porting/liteos_a/toys/posix/cat.c | 61 ++- toys/lsb/dmesg.c | 22 +- toys/lsb/gzip.c | 1 - toys/lsb/mount.c | 7 +- toys/lsb/pidof.c | 12 +- toys/net/ftpget.c | 6 +- toys/other/base64.c | 52 +-- toys/other/fallocate.c | 6 +- toys/other/free.c | 2 +- toys/other/i2ctools.c | 105 +++-- toys/other/ionice.c | 31 +- toys/other/losetup.c | 15 +- toys/other/lspci.c | 18 +- toys/other/makedevs.c | 19 +- toys/other/nsenter.c | 4 +- toys/other/oneit.c | 8 +- toys/other/printenv.c | 2 +- toys/other/reboot.c | 1 - toys/other/shred.c | 3 +- toys/other/switch_root.c | 2 +- toys/other/uptime.c | 10 +- toys/pending/lsof.c | 6 +- toys/pending/modprobe.c | 170 +++++--- toys/pending/tr.c | 27 +- toys/pending/traceroute.c | 4 +- toys/posix/du.c | 37 +- toys/posix/find.c | 65 ++- toys/posix/ps.c | 2 +- toys/posix/pwd.c | 1 + toys/posix/rm.c | 2 +- toys/posix/sort.c | 13 +- toys/posix/tee.c | 27 +- www/roadmap.html | 661 +++++++----------------------- 43 files changed, 593 insertions(+), 1109 deletions(-) diff --git a/generated/flags.h b/generated/flags.h index 4910a71..2aa6ce1 100644 --- a/generated/flags.h +++ b/generated/flags.h @@ -73,17 +73,6 @@ #undef FOR_ascii #endif -// base32 diw#<0=76[!dw] diw#<0=76[!dw] -#undef OPTSTR_base32 -#define OPTSTR_base32 "diw#<0=76[!dw]" -#ifdef CLEANUP_base32 -#undef CLEANUP_base32 -#undef FOR_base32 -#undef FLAG_w -#undef FLAG_i -#undef FLAG_d -#endif - // base64 diw#<0=76[!dw] diw#<0=76[!dw] #undef OPTSTR_base64 #define OPTSTR_base64 "diw#<0=76[!dw]" @@ -745,13 +734,12 @@ #undef FOR_dos2unix #endif -// du d#<0=-1hmlcaHkKLsxb[-HL][-kKmh] d#<0=-1hmlcaHkKLsxb[-HL][-kKmh] +// du d#<0=-1hmlcaHkKLsx[-HL][-kKmh] d#<0=-1hmlcaHkKLsx[-HL][-kKmh] #undef OPTSTR_du -#define OPTSTR_du "d#<0=-1hmlcaHkKLsxb[-HL][-kKmh]" +#define OPTSTR_du "d#<0=-1hmlcaHkKLsx[-HL][-kKmh]" #ifdef CLEANUP_du #undef CLEANUP_du #undef FOR_du -#undef FLAG_b #undef FLAG_x #undef FLAG_s #undef FLAG_L @@ -1294,15 +1282,13 @@ #undef FLAG_fast #endif -// i2cdetect >3aFlqry[!qr] >3aFlqry[!qr] +// i2cdetect >3aFly >3aFly #undef OPTSTR_i2cdetect -#define OPTSTR_i2cdetect ">3aFlqry[!qr]" +#define OPTSTR_i2cdetect ">3aFly" #ifdef CLEANUP_i2cdetect #undef CLEANUP_i2cdetect #undef FOR_i2cdetect #undef FLAG_y -#undef FLAG_r -#undef FLAG_q #undef FLAG_l #undef FLAG_F #undef FLAG_a @@ -1809,7 +1795,7 @@ #undef FLAG_b #endif -// mdev s +// mdev s s #undef OPTSTR_mdev #define OPTSTR_mdev "s" #ifdef CLEANUP_mdev @@ -2012,7 +1998,7 @@ #undef FLAG_n #endif -// netcat ^tElLw#<1W#<1p#<1>65535q#<1s:f:46uU[!tlL][!Lw][!46U] ^tElLw#<1W#<1p#<1>65535q#<1s:f:46uU[!tlL][!Lw][!46U] +// netcat ^tlLw#<1W#<1p#<1>65535q#<1s:f:46uU[!tlL][!Lw][!46U] ^tlLw#<1W#<1p#<1>65535q#<1s:f:46uU[!tlL][!Lw][!46U] #undef OPTSTR_netcat #ifdef TOYBOX_OH_ADAPT /* fix "netcat -u" fail problem */ @@ -2035,7 +2021,6 @@ #undef FLAG_w #undef FLAG_L #undef FLAG_l -#undef FLAG_E #undef FLAG_t #endif @@ -2232,9 +2217,9 @@ #undef FLAG_c #endif -// pidof so:x so:x +// pidof <1so:x <1so:x #undef OPTSTR_pidof -#define OPTSTR_pidof "so:x" +#define OPTSTR_pidof "<1so:x" #ifdef CLEANUP_pidof #undef CLEANUP_pidof #undef FOR_pidof @@ -2308,14 +2293,13 @@ #undef FLAG_x #endif -// printenv (null)0 (null)0 +// printenv 0(null) 0(null) #undef OPTSTR_printenv -#define OPTSTR_printenv "(null)0" +#define OPTSTR_printenv "0(null)" #ifdef CLEANUP_printenv #undef CLEANUP_printenv #undef FOR_printenv #undef FLAG_0 -#undef FLAG_null #endif // printf <1?^ <1?^ @@ -2497,9 +2481,9 @@ #undef FLAG_f #endif -// rmdir <1(ignore-fail-on-non-empty)p(parents) <1(ignore-fail-on-non-empty)p(parents) +// rmdir <1(ignore-fail-on-non-empty)p <1(ignore-fail-on-non-empty)p #undef OPTSTR_rmdir -#define OPTSTR_rmdir "<1(ignore-fail-on-non-empty)p(parents)" +#define OPTSTR_rmdir "<1(ignore-fail-on-non-empty)p" #ifdef CLEANUP_rmdir #undef CLEANUP_rmdir #undef FOR_rmdir @@ -2729,13 +2713,12 @@ #undef FLAG_g #endif -// split >2a#<1=2>9b#<1l#<1n#<1[!bl][!bn][!ln] >2a#<1=2>9b#<1l#<1n#<1[!bl][!bn][!ln] +// split >2a#<1=2>9b#<1l#<1[!bl] >2a#<1=2>9b#<1l#<1[!bl] #undef OPTSTR_split -#define OPTSTR_split ">2a#<1=2>9b#<1l#<1n#<1[!bl][!bn][!ln]" +#define OPTSTR_split ">2a#<1=2>9b#<1l#<1[!bl]" #ifdef CLEANUP_split #undef CLEANUP_split #undef FOR_split -#undef FLAG_n #undef FLAG_l #undef FLAG_b #undef FLAG_a @@ -3589,15 +3572,6 @@ #endif #endif -#ifdef FOR_base32 -#ifndef TT -#define TT this.base32 -#endif -#define FLAG_w (1<<0) -#define FLAG_i (1<<1) -#define FLAG_d (1<<2) -#endif - #ifdef FOR_base64 #ifndef TT #define TT this.base64 @@ -4162,19 +4136,18 @@ #ifndef TT #define TT this.du #endif -#define FLAG_b (1<<0) -#define FLAG_x (1<<1) -#define FLAG_s (1<<2) -#define FLAG_L (1<<3) -#define FLAG_K (1<<4) -#define FLAG_k (1<<5) -#define FLAG_H (1<<6) -#define FLAG_a (1<<7) -#define FLAG_c (1<<8) -#define FLAG_l (1<<9) -#define FLAG_m (1<<10) -#define FLAG_h (1<<11) -#define FLAG_d (1<<12) +#define FLAG_x (1<<0) +#define FLAG_s (1<<1) +#define FLAG_L (1<<2) +#define FLAG_K (1<<3) +#define FLAG_k (1<<4) +#define FLAG_H (1<<5) +#define FLAG_a (1<<6) +#define FLAG_c (1<<7) +#define FLAG_l (1<<8) +#define FLAG_m (1<<9) +#define FLAG_h (1<<10) +#define FLAG_d (1<<11) #endif #ifdef FOR_dumpleases @@ -4625,11 +4598,9 @@ #define TT this.i2cdetect #endif #define FLAG_y (1<<0) -#define FLAG_r (1<<1) -#define FLAG_q (1<<2) -#define FLAG_l (1<<3) -#define FLAG_F (1<<4) -#define FLAG_a (1<<5) +#define FLAG_l (1<<1) +#define FLAG_F (1<<2) +#define FLAG_a (1<<3) #endif #ifdef FOR_i2cdump @@ -5468,7 +5439,6 @@ #define TT this.printenv #endif #define FLAG_0 (1<<0) -#define FLAG_null (1<<1) #endif #ifdef FOR_printf @@ -5819,10 +5789,9 @@ #ifndef TT #define TT this.split #endif -#define FLAG_n (1<<0) -#define FLAG_l (1<<1) -#define FLAG_b (1<<2) -#define FLAG_a (1<<3) +#define FLAG_l (1<<0) +#define FLAG_b (1<<1) +#define FLAG_a (1<<2) #endif #ifdef FOR_stat diff --git a/generated/globals.h b/generated/globals.h index 2358490..fef8b96 100644 --- a/generated/globals.h +++ b/generated/globals.h @@ -116,7 +116,7 @@ struct passwd_data { // toys/lsb/pidof.c struct pidof_data { - char *o; + char *omit; }; // toys/lsb/seq.c @@ -217,9 +217,8 @@ struct acpi_data { struct base64_data { long w; + unsigned total; - unsigned n; // number of bits used in encoding. 5 for base32, 6 for base64 - unsigned align; // number of bits to align to }; // toys/other/blkid.c @@ -249,7 +248,8 @@ struct dos2unix_data { // toys/other/fallocate.c struct fallocate_data { - long o, l; + long offset; + long size; }; // toys/other/fmt.c @@ -288,7 +288,9 @@ struct hwclock_data { // toys/other/ionice.c struct ionice_data { - long p, n, c; + long pid; + long level; + long class; }; // toys/other/login.c @@ -374,12 +376,6 @@ struct pwgen_data { char *r; }; -// toys/other/reboot.c - -struct reboot_data { - char *d; -}; - // toys/other/setfattr.c struct setfattr_data { @@ -1509,13 +1505,14 @@ struct sort_data { void *key_list; int linecount; - char **lines, *name; + char **lines; + char *name; }; // toys/posix/split.c struct split_data { - long n, l, b, a; + long l, b, a; char *outfile; }; @@ -1574,7 +1571,6 @@ struct tar_data { struct tee_data { void *outputs; - int out; }; // toys/posix/touch.c @@ -1671,7 +1667,6 @@ extern union global_union { struct nsenter_data nsenter; struct oneit_data oneit; struct pwgen_data pwgen; - struct reboot_data reboot; struct setfattr_data setfattr; struct sha3sum_data sha3sum; struct shred_data shred; @@ -1733,7 +1728,7 @@ extern union global_union { struct traceroute_data traceroute; struct useradd_data useradd; struct vi_data vi; - struct awk_data awk; + struct awk_data awk; struct wget_data wget; struct basename_data basename; struct chgrp_data chgrp; diff --git a/generated/help.h b/generated/help.h index 60bee05..28bd970 100644 --- a/generated/help.h +++ b/generated/help.h @@ -76,7 +76,7 @@ #define HELP_seq "usage: seq [-w|-f fmt_str] [-s sep_str] [first] [increment] last\n\nCount from first to last, by increment. Omitted arguments default\nto 1. Two arguments are used as first and last. Arguments can be\nnegative or floating point.\n\n-f Use fmt_str as a printf-style floating point format string\n-s Use sep_str as separator, default is a newline character\n-w Pad to equal width with leading zeroes" -#define HELP_pidof "usage: pidof [-s] [-o omitpid[,omitpid...]] [NAME...]\n\nPrint the PIDs of all processes with the given names.\n\n-o Omit PID(s)\n-s Single shot, only return one pid\n-x Match shell scripts too" +#define HELP_pidof "usage: pidof [-s] [-o omitpid[,omitpid...]] [NAME]...\n\nPrint the PIDs of all processes with the given names.\n\n-s Single shot, only return one pid\n-o Omit PID(s)\n-x Match shell scripts too" #define HELP_passwd_sad "Password changes are checked to make sure they're at least 6 chars long,\ndon't include the entire username (but not a subset of it), or the entire\nprevious password (but changing password1, password2, password3 is fine).\nThis heuristic accepts \"aaaaaa\" and \"123456\"." @@ -187,8 +187,6 @@ #define HELP_shred "usage: shred [-fuz] [-n COUNT] [-s SIZE] FILE...\n\nSecurely delete a file by overwriting its contents with random data.\n\n-f Force (chmod if necessary)\n-n COUNT Random overwrite iterations (default 1)\n-o OFFSET Start at OFFSET\n-s SIZE Use SIZE instead of detecting file size\n-u Unlink (actually delete file when done)\n-x Use exact size (default without -s rounds up to next 4k)\n-z Zero at end\n\nNote: data journaling filesystems render this command useless, you must\noverwrite all free space (fill up disk) to erase old data on those." -#define HELP_sha3sum "usage: sha3sum [-S] [-a BITS] [FILE...]\n\nHash function du jour.\n\n-a Produce a hash BITS long (default 224)\n-b Brief (hash only, no filename)\n-S Use SHAKE termination byte instead of SHA3 (ask FIPS why)" - #define HELP_setsid "usage: setsid [-t] command [args...]\n\nRun process in a new session.\n\n-t Grab tty (become foreground process, receiving keyboard signals)" #define HELP_setfattr "usage: setfattr [-h] [-x|-n NAME] [-v VALUE] FILE...\n\nWrite POSIX extended attributes.\n\n-h Do not dereference symlink\n-n Set given attribute\n-x Remove given attribute\n-v Set value for attribute -n (default is empty)" @@ -207,8 +205,6 @@ #define HELP_readahead "usage: readahead FILE...\n\nPreload files into disk cache." -#define HELP_pwgen "usage: pwgen [-cAn0yrsBhC1v] [LENGTH] [COUNT]\n\nGenerate human-readable random passwords. When output is to tty produces\na screenfull to defeat shoulder surfing (pick one and clear the screen).\n\n-c --capitalize Permit capital letters.\n-A --no-capitalize Don't include capital letters.\n-n --numerals Permit numbers.\n-0 --no-numerals Don't include numbers.\n-y --symbols Permit special characters ($#%...).\n-r --remove= Don't include the given characters.\n-s --secure Generate more random passwords.\n-B --ambiguous Avoid ambiguous characters (e.g. 0, O).\n-h --help Print this help message.\n-C Print the output in columns.\n-1 Print the output one line each.\n-v Don't include vowels." - #define HELP_pwdx "usage: pwdx PID...\n\nPrint working directory of processes listed on command line." #define HELP_printenv "usage: printenv [-0] [env_var...]\n\nPrint environment variables.\n\n-0 Use \\0 as delimiter instead of \\n" @@ -323,8 +319,6 @@ #define HELP_blkid "usage: blkid [-s TAG] [-UL] DEV...\n\nPrint type, label and UUID of filesystem on a block device or image.\n\n-U Show UUID only (or device with that UUID)\n-L Show LABEL only (or device with that LABEL)\n-s TAG Only show matching tags (default all)" -#define HELP_base32 "usage: base32 [-di] [-w COLUMNS] [FILE...]\n\nEncode or decode in base32.\n\n-d Decode\n-i Ignore non-alphabetic characters\n-w Wrap output at COLUMNS (default 76 or 0 for no wrap)" - #define HELP_base64 "usage: base64 [-di] [-w COLUMNS] [FILE...]\n\nEncode or decode in base64.\n\n-d Decode\n-i Ignore non-alphabetic characters\n-w Wrap output at COLUMNS (default 76 or 0 for no wrap)" #define HELP_ascii "usage: ascii\n\nDisplay ascii character set." @@ -351,7 +345,7 @@ #define HELP_telnetd "Handle incoming telnet connections\n\n-l LOGIN Exec LOGIN on connect\n-f ISSUE_FILE Display ISSUE_FILE instead of /etc/issue\n-K Close connection as soon as login exits\n-p PORT Port to listen on\n-b ADDR[:PORT] Address to bind to\n-F Run in foreground\n-i Inetd mode\n-w SEC Inetd 'wait' mode, linger time SEC\n-S Log to syslog (implied by -i or without -F and -w)" -#define HELP_telnet "usage: telnet HOST [PORT]\n\nConnect to telnet server." +#define HELP_telnet "usage: telnet HOST [PORT]\n\nConnect to telnet server" #define HELP_tcpsvd "usage: tcpsvd [-hEv] [-c N] [-C N[:MSG]] [-b N] [-u User] [-l Name] IP Port Prog\nusage: udpsvd [-hEv] [-c N] [-u User] [-l Name] IP Port Prog\n\nCreate TCP/UDP socket, bind to IP:PORT and listen for incoming connection.\nRun PROG for each connection.\n\nIP IP to listen on, 0 = all\nPORT Port to listen on\nPROG ARGS Program to run\n-l NAME Local hostname (else looks up local hostname in DNS)\n-u USER[:GRP] Change to user/group after bind\n-c N Handle up to N (> 0) connections simultaneously\n-b N (TCP Only) Allow a backlog of approximately N TCP SYNs\n-C N[:MSG] (TCP Only) Allow only up to N (> 0) connections from the same IP\n New connections from this IP address are closed\n immediately. MSG is written to the peer before close\n-h Look up peer's hostname\n-E Don't set up environment variables\n-v Verbose" @@ -361,8 +355,6 @@ #define HELP_stty "usage: stty [-ag] [-F device] SETTING...\n\nGet/set terminal configuration.\n\n-F Open device instead of stdin\n-a Show all current settings (default differences from \"sane\")\n-g Show all current settings usable as input to stty\n\nSpecial characters (syntax ^c or undef): intr quit erase kill eof eol eol2\nswtch start stop susp rprnt werase lnext discard\n\nControl/input/output/local settings as shown by -a, '-' prefix to disable\n\nCombo settings: cooked/raw, evenp/oddp/parity, nl, ek, sane\n\nN set input and output speed (ispeed N or ospeed N for just one)\ncols N set number of columns\nrows N set number of rows\nline N set line discipline\nmin N set minimum chars per read\ntime N set read timeout\nspeed show speed only\nsize show size only" -#define HELP_strace "usage: strace [-fv] [-p PID] [-s NUM] COMMAND [ARGS...]\n\nTrace systems calls made by a process.\n\n-s String length limit.\n-v Dump all of large structs/arrays." - #define HELP_exit "usage: exit [status]\n\nExit shell. If no return value supplied on command line, use value\nof most recent command, or 0 if none." #define HELP_cd "usage: cd [-PL] [path]\n\nChange current directory. With no arguments, go $HOME.\n\n-P Physical path: resolve symlinks in path\n-L Local path: .. trims directories off $PWD (default)" @@ -416,18 +408,12 @@ #define HELP_host "usage: host [-av] [-t TYPE] NAME [SERVER]\n\nPerform DNS lookup on NAME, which can be a domain name to lookup,\nor an IPv4 dotted or IPv6 colon-separated address to reverse lookup.\nSERVER (if present) is the DNS server to use.\n\n-a -v -t ANY\n-t TYPE query records of type TYPE\n-v verbose" -#define HELP_hd "usage: hd [FILE...]\n\nDisplay file(s) in cannonical hex+ASCII format." - -#define HELP_hexdump "usage: hexdump [-bcCdovx] [-n LEN] [-s SKIP] [FILE...]\n\nDump file(s) in hexadecimal format.\n\n-n LEN Show LEN bytes of output\n-s SKIP Skip bytes of input\n-v Verbose (don't combine identical lines)\n\nDisplay type:\n-b One byte octal -c One byte character -C Canonical (hex + ASCII)\n-d Two byte decimal -o Two byte octal -x Two byte hexadecimal (default)" - #define HELP_groupdel "usage: groupdel [USER] GROUP\n\nDelete a group or remove a user from a group" #define HELP_groupadd "usage: groupadd [-S] [-g GID] [USER] GROUP\n\nAdd a group or add a user to a group\n\n -g GID Group id\n -S Create a system group" #define HELP_getty "usage: getty [OPTIONS] BAUD_RATE[,BAUD_RATE]... TTY [TERMTYPE]\n\n-h Enable hardware RTS/CTS flow control\n-L Set CLOCAL (ignore Carrier Detect state)\n-m Get baud rate from modem's CONNECT status message\n-n Don't prompt for login name\n-w Wait for CR or LF before sending /etc/issue\n-i Don't display /etc/issue\n-f ISSUE_FILE Display ISSUE_FILE instead of /etc/issue\n-l LOGIN Invoke LOGIN instead of /bin/login\n-t SEC Terminate after SEC if no login name is read\n-I INITSTR Send INITSTR before anything else\n-H HOST Log HOST into the utmp file as the hostname" -#define HELP_getopt "usage: getopt [OPTIONS] [--] ARG...\n\nParse command-line options for use in shell scripts.\n\n-a Allow long options starting with a single -.\n-l OPTS Specify long options.\n-n NAME Command name for error messages.\n-o OPTS Specify short options.\n-T Test whether this is a modern getopt.\n-u Output options unquoted." - #define HELP_getfattr "usage: getfattr [-d] [-h] [-n NAME] FILE...\n\nRead POSIX extended attributes.\n\n-d Show values as well as names\n-h Do not dereference symbolic links\n-n Show only attributes with the given name\n--only-values Don't show names" #define HELP_fsck "usage: fsck [-ANPRTV] [-C FD] [-t FSTYPE] [FS_OPTS] [BLOCKDEV]...\n\nCheck and repair filesystems\n\n-A Walk /etc/fstab and check all filesystems\n-N Don't execute, just show what would be done\n-P With -A, check filesystems in parallel\n-R With -A, skip the root filesystem\n-T Don't show title on startup\n-V Verbose\n-C n Write status information to specified file descriptor\n-t TYPE List of filesystem types to check" @@ -454,8 +440,6 @@ #define HELP_crond "usage: crond [-fbS] [-l N] [-d N] [-L LOGFILE] [-c DIR]\n\nA daemon to execute scheduled commands.\n\n-b Background (default)\n-c crontab dir\n-d Set log level, log to stderr\n-f Foreground\n-l Set log level. 0 is the most verbose, default 8\n-S Log to syslog (default)\n-L Log to file" -#define HELP_chsh "usage: chsh [-s SHELL] [USER]\n\nChange user's login shell.\n\n-s Use SHELL instead of prompting\n\nNon-root users can only change their own shell to one listed in /etc/shells." - #define HELP_brctl "usage: brctl COMMAND [BRIDGE [INTERFACE]]\n\nManage ethernet bridges\n\nCommands:\nshow Show a list of bridges\naddbr BRIDGE Create BRIDGE\ndelbr BRIDGE Delete BRIDGE\naddif BRIDGE IFACE Add IFACE to BRIDGE\ndelif BRIDGE IFACE Delete IFACE from BRIDGE\nsetageing BRIDGE TIME Set ageing time\nsetfd BRIDGE TIME Set bridge forward delay\nsethello BRIDGE TIME Set hello time\nsetmaxage BRIDGE TIME Set max message age\nsetpathcost BRIDGE PORT COST Set path cost\nsetportprio BRIDGE PORT PRIO Set port priority\nsetbridgeprio BRIDGE PRIO Set bridge priority\nstp BRIDGE [1/yes/on|0/no/off] STP on/off" #define HELP_bootchartd "usage: bootchartd {start [PROG ARGS]}|stop|init\n\nCreate /var/log/bootlog.tgz with boot chart data\n\nstart: start background logging; with PROG, run PROG,\n then kill logging with USR1\nstop: send USR1 to all bootchartd processes\ninit: start background logging; stop when getty/xdm is seen\n (for init scripts)\n\nUnder PID 1: as init, then exec $bootchart_init, /init, /sbin/init" diff --git a/generated/newtoys.h b/generated/newtoys.h index d7c9e0b..2dadcaa 100644 --- a/generated/newtoys.h +++ b/generated/newtoys.h @@ -12,7 +12,6 @@ USE_ARP(NEWTOY(arp, "vi:nDsdap:A:H:[+Ap][!sd]", TOYFLAG_USR|TOYFLAG_BIN)) USE_ARPING(NEWTOY(arping, "<1>1s:I:w#<0c#<0AUDbqf[+AU][+Df]", TOYFLAG_USR|TOYFLAG_SBIN)) USE_ASCII(NEWTOY(ascii, 0, TOYFLAG_USR|TOYFLAG_BIN)) USE_AWK(NEWTOY(awk, "F:v*f*bc", TOYFLAG_USR|TOYFLAG_BIN)) -USE_BASE32(NEWTOY(base32, "diw#<0=76[!dw]", TOYFLAG_USR|TOYFLAG_BIN)) USE_BASE64(NEWTOY(base64, "diw#<0=76[!dw]", TOYFLAG_USR|TOYFLAG_BIN)) USE_BASENAME(NEWTOY(basename, "^<1as:", TOYFLAG_USR|TOYFLAG_BIN)) USE_SH(OLDTOY(bash, sh, TOYFLAG_BIN)) @@ -83,7 +82,7 @@ USE_FIND(NEWTOY(find, "?^HL[-HL]", TOYFLAG_USR|TOYFLAG_BIN)) USE_FLOCK(NEWTOY(flock, "<1>1nsux[-sux]", TOYFLAG_USR|TOYFLAG_BIN)) USE_FMT(NEWTOY(fmt, "w#<0=75", TOYFLAG_USR|TOYFLAG_BIN|TOYFLAG_LOCALE)) USE_FOLD(NEWTOY(fold, "bsuw#<1", TOYFLAG_USR|TOYFLAG_BIN)) -USE_FREE(NEWTOY(free, "hgmkb[!hgmkb]", TOYFLAG_USR|TOYFLAG_BIN)) +USE_FREE(NEWTOY(free, "htgmkb[!htgmkb]", TOYFLAG_USR|TOYFLAG_BIN)) USE_FREERAMDISK(NEWTOY(freeramdisk, "<1>1", TOYFLAG_SBIN|TOYFLAG_NEEDROOT)) USE_FSCK(NEWTOY(fsck, "?t:ANPRTVsC#", TOYFLAG_USR|TOYFLAG_BIN)) USE_FSFREEZE(NEWTOY(fsfreeze, "<1>1f|u|[!fu]", TOYFLAG_USR|TOYFLAG_SBIN)) @@ -94,8 +93,7 @@ USE_FTPPUT(OLDTOY(ftpput, ftpget, TOYFLAG_USR|TOYFLAG_BIN)) USE_GETCONF(NEWTOY(getconf, ">2al", TOYFLAG_USR|TOYFLAG_BIN)) USE_GETENFORCE(NEWTOY(getenforce, ">0", TOYFLAG_USR|TOYFLAG_SBIN)) USE_GETFATTR(NEWTOY(getfattr, "(only-values)dhn:", TOYFLAG_USR|TOYFLAG_BIN)) -USE_GETOPT(NEWTOY(getopt, "^a(alternative)n:(name)o:(options)l*(long)(longoptions)Tu", TOYFLAG_USR|TOYFLAG_BIN)) -USE_GETTY(NEWTOY(getty, "<2t#<0H:I:l:f:iwnmLh", TOYFLAG_SBIN)) +USE_GETTY(NEWTOY(getty, "<2t#<0H:I:l:f:iwnmLh",TOYFLAG_SBIN)) USE_GREP(NEWTOY(grep, "(line-buffered)(color):;(exclude-dir)*S(exclude)*M(include)*ZzEFHIab(byte-offset)h(no-filename)ino(only-matching)rRsvwc(count)L(files-without-match)l(files-with-matches)q(quiet)(silent)e*f*C#B#A#m#x[!wx][!EF]", TOYFLAG_BIN|TOYFLAG_ARGFAIL(2)|TOYFLAG_LINEBUF)) USE_GROUPADD(NEWTOY(groupadd, "<1>2g#<0S", TOYFLAG_NEEDROOT|TOYFLAG_SBIN)) USE_GROUPDEL(NEWTOY(groupdel, "<1>2", TOYFLAG_NEEDROOT|TOYFLAG_SBIN)) @@ -103,11 +101,9 @@ USE_GROUPS(NEWTOY(groups, NULL, TOYFLAG_USR|TOYFLAG_BIN)) USE_GUNZIP(NEWTOY(gunzip, "cdfk123456789[-123456789]", TOYFLAG_USR|TOYFLAG_BIN)) USE_GZIP(NEWTOY(gzip, "ncdfk123456789[-123456789]", TOYFLAG_USR|TOYFLAG_BIN)) USE_REBOOT(OLDTOY(halt, reboot, TOYFLAG_SBIN|TOYFLAG_NEEDROOT)) -USE_HD(OLDTOY(hd, hexdump, TOYFLAG_USR|TOYFLAG_BIN)) USE_HEAD(NEWTOY(head, "?n(lines)#<0=10c(bytes)#<0qv[-nc]", TOYFLAG_USR|TOYFLAG_BIN)) USE_HELLO(NEWTOY(hello, 0, TOYFLAG_USR|TOYFLAG_BIN)) USE_HELP(NEWTOY(help, ""USE_HELP_EXTRAS("ah"), TOYFLAG_BIN)) -USE_HEXDUMP(NEWTOY(hexdump, "bcCdn#<0os#<0vx[!bcCdox]", TOYFLAG_USR|TOYFLAG_BIN)) USE_HEXEDIT(NEWTOY(hexedit, "<1>1r", TOYFLAG_USR|TOYFLAG_BIN|TOYFLAG_LOCALE)) USE_HOST(NEWTOY(host, "<1>2avt:", TOYFLAG_USR|TOYFLAG_BIN)) USE_HOSTID(NEWTOY(hostid, ">0", TOYFLAG_USR|TOYFLAG_BIN)) @@ -198,7 +194,7 @@ USE_PASSWD(NEWTOY(passwd, ">1a:dlu", TOYFLAG_STAYROOT|TOYFLAG_USR|TOYFLAG_BIN)) USE_PASTE(NEWTOY(paste, "d:s", TOYFLAG_USR|TOYFLAG_BIN|TOYFLAG_LOCALE)) USE_PATCH(NEWTOY(patch, "(no-backup-if-mismatch)(dry-run)"USE_TOYBOX_DEBUG("x")"g#fulp#d:i:Rs(quiet)", TOYFLAG_USR|TOYFLAG_BIN)) USE_PGREP(NEWTOY(pgrep, "?cld:u*U*t*s*P*g*G*fnovxL:[-no]", TOYFLAG_USR|TOYFLAG_BIN)) -USE_PIDOF(NEWTOY(pidof, "so:x", TOYFLAG_BIN)) +USE_PIDOF(NEWTOY(pidof, "<1so:x", TOYFLAG_BIN)) #ifdef TOYBOX_OH_ADAPT /* fix "ping -s 65500" fail problem*/ USE_PING(NEWTOY(ping, "<1>1m#t#<0>255=64c#<0=3s#<0>65507=56i%W#<0=3w#<0qf46I:[-46]", TOYFLAG_USR|TOYFLAG_BIN)) @@ -216,7 +212,6 @@ USE_ULIMIT(OLDTOY(prlimit, ulimit, TOYFLAG_USR|TOYFLAG_BIN)) USE_PS(NEWTOY(ps, "k(sort)*P(ppid)*aAdeflMno*O*p(pid)*s*t*Tu*U*g*G*wZ[!ol][+Ae][!oO]", TOYFLAG_BIN|TOYFLAG_LOCALE)) USE_PWD(NEWTOY(pwd, ">0LP[-LP]", TOYFLAG_BIN)) USE_PWDX(NEWTOY(pwdx, "<1a", TOYFLAG_USR|TOYFLAG_BIN)) -USE_PWGEN(NEWTOY(pwgen, ">2r(remove):c(capitalize)n(numerals)y(symbols)s(secure)B(ambiguous)h(help)C1vA(no-capitalize)0(no-numerals)[-cA][-n0][-C1]", TOYFLAG_USR|TOYFLAG_BIN)) USE_READAHEAD(NEWTOY(readahead, NULL, TOYFLAG_BIN)) USE_READLINK(NEWTOY(readlink, "<1nqmef(canonicalize)[-mef]", TOYFLAG_USR|TOYFLAG_BIN)) USE_REALPATH(NEWTOY(realpath, "<1", TOYFLAG_USR|TOYFLAG_BIN)) @@ -242,7 +237,6 @@ USE_SHA1SUM(NEWTOY(sha1sum, "bc(check)s(status)[!bc]", TOYFLAG_USR|TOYFLAG_BIN)) USE_TOYBOX_LIBCRYPTO(USE_SHA224SUM(OLDTOY(sha224sum, sha1sum, TOYFLAG_USR|TOYFLAG_BIN))) USE_TOYBOX_LIBCRYPTO(USE_SHA256SUM(OLDTOY(sha256sum, sha1sum, TOYFLAG_USR|TOYFLAG_BIN))) USE_TOYBOX_LIBCRYPTO(USE_SHA384SUM(OLDTOY(sha384sum, sha1sum, TOYFLAG_USR|TOYFLAG_BIN))) -USE_SHA3SUM(NEWTOY(sha3sum, "bSa#<128>512=224", TOYFLAG_USR|TOYFLAG_BIN)) USE_TOYBOX_LIBCRYPTO(USE_SHA512SUM(OLDTOY(sha512sum, sha1sum, TOYFLAG_USR|TOYFLAG_BIN))) USE_SHRED(NEWTOY(shred, "<1zxus#<1n#<1o#<0f", TOYFLAG_USR|TOYFLAG_BIN)) USE_SKELETON(NEWTOY(skeleton, "(walrus)(blubber):;(also):e@d*c#b:a", TOYFLAG_USR|TOYFLAG_BIN)) @@ -252,7 +246,6 @@ USE_SNTP(NEWTOY(sntp, "M:m:Sp:asdDqr#<4>17=10[!as]", TOYFLAG_USR|TOYFLAG_BIN)) USE_SORT(NEWTOY(sort, USE_SORT_FLOAT("g")"S:T:m" "o:k*t:" "xVbMcszdfirun", TOYFLAG_USR|TOYFLAG_BIN|TOYFLAG_ARGFAIL(2))) USE_SPLIT(NEWTOY(split, ">2a#<1=2>9b#<1l#<1[!bl]", TOYFLAG_USR|TOYFLAG_BIN)) USE_STAT(NEWTOY(stat, "<1c:(format)fLt", TOYFLAG_BIN)) -USE_STRACE(NEWTOY(strace, "^p#s#v", TOYFLAG_USR|TOYFLAG_SBIN)) USE_STRINGS(NEWTOY(strings, "t:an#=4<1fo", TOYFLAG_USR|TOYFLAG_BIN)) USE_STTY(NEWTOY(stty, "?aF:g[!ag]", TOYFLAG_BIN)) #ifdef OHOS_LITE diff --git a/install.py b/install.py index 703333d..6c35139 100644 --- a/install.py +++ b/install.py @@ -37,8 +37,6 @@ def main(): target_link = args.long_path if os.path.exists(target_link): os.remove(target_link) - elif os.path.islink(target_link): - os.unlink(target_link) if target_link.find("usr") != -1: os.symlink("../../bin/toybox", target_link) diff --git a/lib/lib.c b/lib/lib.c index 2d928df..fa233ae 100644 --- a/lib/lib.c +++ b/lib/lib.c @@ -453,29 +453,6 @@ int unescape(char c) return (idx == -1) ? 0 : to[idx]; } -// parse next character advancing pointer. echo requires leading 0 in octal esc -int unescape2(char **c, int echo) -{ - int idx = *((*c)++), i, off; - - if (idx != '\\' || !**c) return idx; - if (**c == 'c') return 31&*(++*c); - for (i = 0; i<4; i++) { - if (sscanf(*c, (char *[]){"0%3o%n"+!echo, "x%2x%n", "u%4x%n", "U%6x%n"}[i], - &idx, &off) > 0) - { - *c += off; - - return idx; - } - } - - if (-1 == (idx = stridx("\\abeEfnrtv'\"?0", **c))) return '\\'; - ++*c; - - return "\\\a\b\033\033\f\n\r\t\v'\"?"[idx]; -} - // If string ends with suffix return pointer to start of suffix in string, // else NULL char *strend(char *str, char *suffix) diff --git a/lib/lib.h b/lib/lib.h index b99831e..e37dc34 100644 --- a/lib/lib.h +++ b/lib/lib.h @@ -79,11 +79,11 @@ void get_optflags(void); // Don't warn about failure to stat #define DIRTREE_SHUTUP 16 // Breadth first traversal, conserves filehandles at the expense of memory -#define DIRTREE_BREADTH 32 // TODO not implemented yet +#define DIRTREE_BREADTH 32 // skip non-numeric entries #define DIRTREE_PROC 64 // Return files we can't stat -#define DIRTREE_STATLESS 128 +#define DIRTREE_STATLESS 128 // Don't look at any more files in this directory. #define DIRTREE_ABORT 256 @@ -95,7 +95,8 @@ struct dirtree { char *symlink; int dirfd; struct stat st; - char again, name[]; + char again; + char name[]; }; int isdotdot(char *name); @@ -116,14 +117,7 @@ void show_help(FILE *out); // Tell xopen and friends to print warnings but return -1 as necessary // The largest O_BLAH flag so far is arch/alpha's O_PATH at 0x800000 so // plenty of headroom. -#define WARN_ONLY (1<<31) // don't exit, just warn -#define LOOPFILES_ANYWAY (1<<30) // call function with fd -1 - -// xabspath flags -#define ABS_PATH 1 // all but last path component must exist -#define ABS_FILE 2 // last path component must exist -#define ABS_KEEP 4 // don't resolve symlinks in path to last component -#define ABS_LAST 8 // don't resolve symlink in last path component +#define WARN_ONLY (1<<31) // xwrap.c void xstrncpy(char *dest, char *src, size_t size); @@ -186,11 +180,9 @@ struct group *xgetgrnam(char *name); unsigned xgetuid(char *name); unsigned xgetgid(char *name); void xsetuser(struct passwd *pwd); -char *xreadlinkat(int dir, char *name); char *xreadlink(char *name); double xstrtod(char *s); long xparsetime(char *arg, long units, long *fraction); -void xparsetimespec(char *arg, struct timespec *ts); long long xparsemillitime(char *arg); void xpidfile(char *name); void xregcomp(regex_t *preg, char *rexec, int cflags); @@ -245,7 +237,6 @@ char *strlower(char *s); char *strafter(char *haystack, char *needle); char *chomp(char *s); int unescape(char c); -int unescape2(char **c, int echo); char *strend(char *str, char *suffix); int strstart(char **a, char *b); int strcasestart(char **a, char *b); diff --git a/lib/net.c b/lib/net.c index 774e501..3710388 100644 --- a/lib/net.c +++ b/lib/net.c @@ -96,88 +96,6 @@ int xpoll(struct pollfd *fds, int nfds, int timeout) // Loop forwarding data from in1 to out1 and in2 to out2, handling // half-connection shutdown. timeouts return if no data for X ms. // Returns 0: both closed, 1 shutdown_timeout, 2 timeout -#ifdef TOYBOX_OH_ADAPT -/* fix "netcat -q" fail problem */ -int pollinate(int in1, int in2, int out1, int out2, int timeout, int shutdown_timeout) -{ - struct pollfd pollfds[2]; - int i, pollcount = 2; - long long deadline = -1; - int socket_closed = 0; - int is_server = 0; - int is_udp = 0; - - is_server = (isatty(in2) && !isatty(in1)); - - { - int type; - socklen_t len = sizeof(type); - if(getsockopt(in1, SOL_SOCKET, SO_TYPE, &type, &len) == 0) { - is_udp = (type == SOCK_DGRAM); - } - } - - memset(pollfds, 0, 2*sizeof(struct pollfd)); - pollfds[0].events = pollfds[1].events = POLLIN; - pollfds[0].fd = in1; - pollfds[1].fd = in2; - - for(;;) { - int current_timeout = timeout; - long long now = millitime(); - - if(deadline >= 0) { - current_timeout = deadline - now; - if(current_timeout < 0) current_timeout = 0; - } - - if(socket_closed && pollcount == 1) { - if(is_server) { - close(pollfds[0].fd); - return 0; - } else { - if(current_timeout <= 0) return 2; - usleep(current_timeout * 1000); - return 2; - } - } - - int poll_result = xpoll(pollfds, pollcount, current_timeout); - if(poll_result == 0) { - if(deadline >= 0) return 2; - else return 1; - } - - for(i = 0; i < pollcount; i++) { - if (i == 0 && socket_closed) continue; - - if(pollfds[i].revents & POLLIN) { - int len = read(pollfds[i].fd, libbuf, sizeof(libbuf)); - if(len < 1) { - pollfds[i].revents = POLLHUP; - } else { - xwrite(i ? out2 : out1, libbuf, len); - continue; - } - } - - if(pollfds[i].revents & POLLHUP) { - if(i) { - if(!is_udp && !socket_closed) - shutdown(pollfds[0].fd, SHUT_WR); - - pollcount--; - if(shutdown_timeout >= 0) - deadline = millitime() + shutdown_timeout; - } else { - socket_closed = 1; - pollcount--; - } - } - } - } -} -#else int pollinate(int in1, int in2, int out1, int out2, int timeout, int shutdown_timeout) { struct pollfd pollfds[2]; @@ -211,7 +129,6 @@ int pollinate(int in1, int in2, int out1, int out2, int timeout, int shutdown_ti } } } -#endif // Return converted ipv4/ipv6 numeric address in libbuf char *ntop(struct sockaddr *sa) diff --git a/lib/xwrap.c b/lib/xwrap.c index ff7b594..17ec397 100644 --- a/lib/xwrap.c +++ b/lib/xwrap.c @@ -384,7 +384,7 @@ void xpipe(int *pp) void xclose(int fd) { - if (fd != -1 && close(fd)) perror_exit("xclose"); + if (close(fd)) perror_exit("xclose"); } int xdup(int fd) @@ -723,7 +723,7 @@ void xsetuser(struct passwd *pwd) // This can return null (meaning file not found). It just won't return null // for memory allocation reasons. -char *xreadlinkat(int dir, char *name) +char *xreadlink(char *name) { int len, size = 0; char *buf = 0; @@ -732,7 +732,7 @@ char *xreadlinkat(int dir, char *name) for(;;) { size +=64; buf = xrealloc(buf, size); - len = readlinkat(dir, name, buf, size); + len = readlink(name, buf, size); if (len<0) { free(buf); @@ -745,12 +745,6 @@ char *xreadlinkat(int dir, char *name) } } -char *xreadlink(char *name) -{ - return xreadlinkat(AT_FDCWD, name); -} - - char *xreadfile(char *name, char *buf, off_t len) { if (!(buf = readfile(name, buf, len))) perror_exit("Bad '%s'", name); @@ -894,10 +888,6 @@ long long xparsemillitime(char *arg) return (l*1000LL)+ll; } -void xparsetimespec(char *arg, struct timespec *ts) -{ - ts->tv_sec = xparsetime(arg, 9, &ts->tv_nsec); -} // Compile a regular expression into a regex_t diff --git a/porting/liteos_a/toys.h b/porting/liteos_a/toys.h index db9c8eb..8297a78 100644 --- a/porting/liteos_a/toys.h +++ b/porting/liteos_a/toys.h @@ -138,4 +138,4 @@ extern char **environ; #define TOYBOX_VENDOR "" #endif #define TOYBOX_VERSION "0.8.10"TOYBOX_VENDOR -#endif +#endif \ No newline at end of file diff --git a/porting/liteos_a/toys/posix/cat.c b/porting/liteos_a/toys/posix/cat.c index 1eb15d4..decaa0e 100644 --- a/porting/liteos_a/toys/posix/cat.c +++ b/porting/liteos_a/toys/posix/cat.c @@ -3,23 +3,48 @@ * Copyright 2006 Rob Landley * * See http://opengroup.org/onlinepubs/9699919799/utilities/cat.html + * + * And "Cat -v considered harmful" at + * http://cm.bell-labs.com/cm/cs/doc/84/kp.ps.gz -USE_CAT(NEWTOY(cat, "uvte", TOYFLAG_BIN)) +USE_CAT(NEWTOY(cat, "u"USE_CAT_V("vte"), TOYFLAG_BIN)) +USE_CATV(NEWTOY(catv, USE_CATV("vte"), TOYFLAG_USR|TOYFLAG_BIN)) config CAT bool "cat" default y help - usage: cat [-etuv] [FILE...] + 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) + +config CAT_V + bool "cat -etv" + default n + depends on CAT + help + usage: cat [-evt] + -e Mark each newline with $ -t Show tabs as ^I - -u Copy one byte at a time (slow) -v Display nonprinting characters as escape sequences with M-x for high ascii characters (>127), and ^x for other nonprinting chars + +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 */ #define FOR_cat @@ -28,18 +53,21 @@ config CAT static void do_cat(int fd, char *name) { - int i, len, size = FLAG(u) ? 1 : sizeof(toybuf); + int i, len, size=(toys.optflags & FLAG_u) ? 1 : sizeof(toybuf); for(;;) { len = read(fd, toybuf, size); - if (len<0) perror_msg_raw(name); - if (len<1) break; - if (toys.optflags&~FLAG_u) { - for (i = 0; i126 && FLAG(v)) { - if (c>127) { + if (c > 126 && (toys.optflags & FLAG_v)) { + if (c > 127) { printf("M-"); c -= 128; } @@ -48,9 +76,9 @@ static void do_cat(int fd, char *name) continue; } } - if (c<32) { + if (c < 32) { if (c == 10) { - if (FLAG(e)) xputc('$'); + if (toys.optflags & FLAG_e) xputc('$'); } else if (toys.optflags & (c==9 ? FLAG_t : FLAG_v)) { printf("^%c", c+'@'); continue; @@ -64,5 +92,12 @@ static void do_cat(int fd, char *name) void cat_main(void) { + if (!*toys.optargs) help_exit("missing argument"); loopfiles(toys.optargs, do_cat); } + +void catv_main(void) +{ + toys.optflags ^= FLAG_v; + loopfiles(toys.optargs, do_cat); +} \ No newline at end of file diff --git a/toys/lsb/dmesg.c b/toys/lsb/dmesg.c index 8736a8e..a55dabf 100644 --- a/toys/lsb/dmesg.c +++ b/toys/lsb/dmesg.c @@ -69,15 +69,15 @@ static void format_message(char *msg, int new) subsystem = p ? (p-text) : 0; // To get "raw" output for /dev/kmsg we need to add priority to each line - if (FLAG(r)) { + if (toys.optflags&FLAG_r) { color(0); printf("<%d>", facpri); } // Format the time. - if (!FLAG(t)) { + if (!(toys.optflags&FLAG_t)) { color(32); - if (FLAG(T)) { + if (toys.optflags&FLAG_T) { time_t t = TT.tea+time_s; char *ts = ctime(&t); @@ -115,23 +115,23 @@ void dmesg_main(void) if (TT.use_color) sigatexit(dmesg_cleanup); // If we're displaying output, is it klogctl or /dev/kmsg? - if (FLAG(C)||FLAG(n)) goto no_output; + if (toys.optflags & (FLAG_C|FLAG_n)) goto no_output; - if (FLAG(T)) { + if (toys.optflags&FLAG_T) { struct sysinfo info; sysinfo(&info); TT.tea = time(0)-info.uptime; } - if (!FLAG(S)) { + if (!(toys.optflags&FLAG_S)) { char msg[8193]; // CONSOLE_EXT_LOG_MAX+1 ssize_t len; int fd; // Each read returns one message. By default, we block when there are no // more messages (--follow); O_NONBLOCK is needed for for usual behavior. - fd = open("/dev/kmsg", O_RDONLY|(O_NONBLOCK*!FLAG(w))); + fd = open("/dev/kmsg", O_RDONLY|(O_NONBLOCK*!(toys.optflags&FLAG_w))); if (fd == -1) goto klogctl_mode; // SYSLOG_ACTION_CLEAR(5) doesn't actually remove anything from /dev/kmsg, @@ -141,7 +141,7 @@ void dmesg_main(void) for (;;) { // why does /dev/kmesg return EPIPE instead of EAGAIN if oldest message // expires as we read it? - if (-1==(len = read(fd, msg, sizeof(msg)-1)) && errno==EPIPE) continue; + if (-1==(len = read(fd, msg, sizeof(msg))) && errno==EPIPE) continue; // read() from kmsg always fails on a pre-3.5 kernel. if (len==-1 && errno==EINVAL) goto klogctl_mode; if (len<1) break; @@ -158,7 +158,7 @@ klogctl_mode: // Figure out how much data we need, and fetch it. if (!(size = TT.s)) size = xklogctl(10, 0, 0); data = from = xmalloc(size+1); - data[size = xklogctl(3+FLAG(c), data, size)] = 0; + data[size = xklogctl(3+(toys.optflags&FLAG_c), data, size)] = 0; // Send each line to format_message. to = data + size; @@ -174,8 +174,8 @@ klogctl_mode: no_output: // Set the log level? - if (FLAG(n)) xklogctl(8, 0, TT.n); + if (toys.optflags & FLAG_n) xklogctl(8, 0, TT.n); // Clear the buffer? - if (FLAG(C)||FLAG(c)) xklogctl(5, 0, 0); + if (toys.optflags & (FLAG_C|FLAG_c)) xklogctl(5, 0, 0); } diff --git a/toys/lsb/gzip.c b/toys/lsb/gzip.c index 049285a..3038495 100644 --- a/toys/lsb/gzip.c +++ b/toys/lsb/gzip.c @@ -78,7 +78,6 @@ static int do_deflate(int in_fd, int out_fd, int dd, int level) } if (!(gz = gzdopen(dd ? in_fd : out_fd, b))) perror_exit("gzdopen"); if (dd) { - if (gzdirect(gz)) error_exit("not gzip"); while ((len = gzread(gz, toybuf, sizeof(toybuf))) > 0) if (len != writeall(out_fd, toybuf, len)) break; } else { diff --git a/toys/lsb/mount.c b/toys/lsb/mount.c index 22021ab..296d686 100644 --- a/toys/lsb/mount.c +++ b/toys/lsb/mount.c @@ -38,7 +38,7 @@ config MOUNT #config SMBMOUNT # bool "smbmount" -# default n +# deault n # helo # usage: smbmount SHARE DIR # @@ -185,7 +185,7 @@ static void mount_filesystem(char *dev, char *dir, char *type, if (strstart(&dev, "UUID=")) { char *s = tortoise(0, (char *[]){"blkid", "-U", dev, 0}); - if (!s) return error_msg("No uuid %s", dev); + if (!dev) return error_msg("No uuid %s", dev); dev = s; } @@ -215,7 +215,7 @@ static void mount_filesystem(char *dev, char *dir, char *type, if (fp && !buf) { size_t i; - if (getline(&buf, &i, fp)<1) { + if (getline(&buf, &i, fp)<0) { error_msg("%s: need -t", dev); break; } @@ -270,7 +270,6 @@ static void mount_filesystem(char *dev, char *dir, char *type, dev = tortoise(1, (char *[]){"losetup", (flags&MS_RDONLY) ? "-fsr" : "-fs", dev, 0}); if (!dev) break; - continue; } free(buf); diff --git a/toys/lsb/pidof.c b/toys/lsb/pidof.c index 791eed0..cd705a7 100644 --- a/toys/lsb/pidof.c +++ b/toys/lsb/pidof.c @@ -5,18 +5,18 @@ * * http://refspecs.linuxfoundation.org/LSB_4.1.0/LSB-Core-generic/LSB-Core-generic/pidof.html -USE_PIDOF(NEWTOY(pidof, "so:x", TOYFLAG_BIN)) +USE_PIDOF(NEWTOY(pidof, "<1so:x", TOYFLAG_BIN)) config PIDOF bool "pidof" default y help - usage: pidof [-s] [-o omitpid[,omitpid...]] [NAME...] + usage: pidof [-s] [-o omitpid[,omitpid...]] [NAME]... Print the PIDs of all processes with the given names. - -o Omit PID(s) -s Single shot, only return one pid + -o Omit PID(s) -x Match shell scripts too */ @@ -24,17 +24,17 @@ config PIDOF #include "toys.h" GLOBALS( - char *o; + char *omit; ) static int print_pid(pid_t pid, char *name) { sprintf(toybuf, "%d", (int)pid); - if (comma_scan(TT.o, toybuf, 0)) return 0; + if (comma_scan(TT.omit, toybuf, 0)) return 0; xprintf(" %s"+!!toys.exitval, toybuf); toys.exitval = 0; - return FLAG(s); + return toys.optflags & FLAG_s; } void pidof_main(void) diff --git a/toys/net/ftpget.c b/toys/net/ftpget.c index 4e4c5ba..4b176fb 100644 --- a/toys/net/ftpget.c +++ b/toys/net/ftpget.c @@ -193,10 +193,10 @@ void ftpget_main(void) port += 256*p1; break; } - } + } if (!s || port<1 || port>65535) { error_msg("ftpget_main line %d, port %d toybox buf %s\r\n", __LINE__, port, toybuf); - ftp_line("QUIT", 0, 0); + ftp_line("QUIT", 0, -1); if (TT.fd >= 0) { xclose(TT.fd); } @@ -215,7 +215,7 @@ void ftpget_main(void) sscanf(toybuf, "%*u %llu", &lenr); } else if (get) { error_msg("ftpget_main line %d, port %d get %d toybox buf %s\r\n", __LINE__, port, get, toybuf); - ftp_line("QUIT", 0, 0); + ftp_line("QUIT", 0, -1); if (TT.fd >= 0) { xclose(TT.fd); } diff --git a/toys/other/base64.c b/toys/other/base64.c index 22652fd..e8a5a11 100644 --- a/toys/other/base64.c +++ b/toys/other/base64.c @@ -4,9 +4,7 @@ * * See https://tools.ietf.org/html/rfc4648 -// These optflags have to match. Todo: cleanup and collapse together? USE_BASE64(NEWTOY(base64, "diw#<0=76[!dw]", TOYFLAG_USR|TOYFLAG_BIN)) -USE_BASE32(NEWTOY(base32, "diw#<0=76[!dw]", TOYFLAG_USR|TOYFLAG_BIN)) config BASE64 bool "base64" @@ -16,32 +14,18 @@ config BASE64 Encode or decode in base64. - -d Decode - -i Ignore non-alphabetic characters - -w Wrap output at COLUMNS (default 76 or 0 for no wrap) - -config BASE32 - bool "base32" - default y - help - usage: base32 [-di] [-w COLUMNS] [FILE...] - - Encode or decode in base32. - -d Decode -i Ignore non-alphabetic characters -w Wrap output at COLUMNS (default 76 or 0 for no wrap) */ #define FOR_base64 -#define FORCE_FLAGS #include "toys.h" GLOBALS( long w; + unsigned total; - unsigned n; // number of bits used in encoding. 5 for base32, 6 for base64 - unsigned align; // number of bits to align to ) static void wraputchar(int c, int *x) @@ -54,7 +38,7 @@ static void wraputchar(int c, int *x) }; } -static void do_base(int fd, char *name) +static void do_base64(int fd, char *name) { int out = 0, bits = 0, x = 0, i, len; char *buf = toybuf+128; @@ -64,9 +48,9 @@ static void do_base(int fd, char *name) for (;;) { // If no more data, flush buffer if (!(len = xread(fd, buf, sizeof(toybuf)-128))) { - if (!FLAG(d)) { - if (bits) wraputchar(toybuf[out<<(TT.n-bits)], &x); - while (TT.total&TT.align) wraputchar('=', &x); + if (!(toys.optflags & FLAG_d)) { + if (bits) wraputchar(toybuf[out<<(6-bits)], &x); + while (TT.total&3) wraputchar('=', &x); if (x) xputc('\n'); } @@ -74,12 +58,12 @@ static void do_base(int fd, char *name) } for (i=0; i= TT.n) { - wraputchar(toybuf[out >> (bits -= TT.n)], &x); + while (bits >= 6) { + wraputchar(toybuf[out >> (bits -= 6)], &x); out &= (1<>TT.bits); TT.buf += strlen(TT.buf)+1; diff --git a/toys/other/i2ctools.c b/toys/other/i2ctools.c index 1834159..ddfc27d 100644 --- a/toys/other/i2ctools.c +++ b/toys/other/i2ctools.c @@ -11,7 +11,7 @@ * TODO: i2cget non-byte modes? default to current read address? * TODO: i2cset -r? -m MASK? c/s modes, p mode modifier? -USE_I2CDETECT(NEWTOY(i2cdetect, ">3aFlqry[!qr]", TOYFLAG_USR|TOYFLAG_BIN)) +USE_I2CDETECT(NEWTOY(i2cdetect, ">3aFly", TOYFLAG_USR|TOYFLAG_BIN)) USE_I2CDUMP(NEWTOY(i2cdump, "<2>2fy", TOYFLAG_USR|TOYFLAG_BIN)) USE_I2CGET(NEWTOY(i2cget, "<3>3fy", TOYFLAG_USR|TOYFLAG_BIN)) USE_I2CSET(NEWTOY(i2cset, "<4fy", TOYFLAG_USR|TOYFLAG_BIN)) @@ -20,16 +20,15 @@ config I2CDETECT bool "i2cdetect" default y help - usage: i2cdetect [-aqry] BUS [FIRST LAST] + usage: i2cdetect [-ary] BUS [FIRST LAST] usage: i2cdetect -F BUS usage: i2cdetect -l Detect i2c devices. - -a All addresses (0x00-0x7f rather than 0x03-0x77 or FIRST-LAST) + -a All addresses (0x00-0x7f rather than 0x03-0x77) -F Show functionality - -l List available buses - -q Probe with SMBus Quick Write (default) + -l List all buses -r Probe with SMBus Read Byte -y Answer "yes" to confirmation prompts (for script use) @@ -68,7 +67,6 @@ config I2CSET */ #define FOR_i2cdetect -#define TT this.i2ctools #include "toys.h" #include @@ -78,7 +76,7 @@ printf_format static void confirm(const char *fmt, ...) { va_list va; - if (FLAG(y)) return; + if (toys.optflags & FLAG_y) return; va_start(va, fmt); vfprintf(stderr, fmt, va); @@ -108,26 +106,23 @@ static unsigned long i2c_get_funcs(int bus) static int i2c_read_byte(int fd, int addr, int *byte) { + struct i2c_smbus_ioctl_data ioctl_data; union i2c_smbus_data data; - struct i2c_smbus_ioctl_data ioctl_data = { .read_write = I2C_SMBUS_READ, - .size = I2C_SMBUS_BYTE_DATA, .command = addr, .data = &data }; memset(&data, 0, sizeof(data)); - if (ioctl(fd, I2C_SMBUS, &ioctl_data)==-1) return -1; + ioctl_data.read_write = I2C_SMBUS_READ; + ioctl_data.size = I2C_SMBUS_BYTE_DATA; + ioctl_data.command = addr; + ioctl_data.data = &data; + if (ioctl(fd, I2C_SMBUS, &ioctl_data) == -1) return -1; *byte = data.byte; return 0; } -static int i2c_quick_write(int fd, int addr) -{ - struct i2c_smbus_ioctl_data ioctl_data = { .read_write = I2C_SMBUS_QUICK, - .size = 0, .command = addr }; - - return ioctl(fd, I2C_SMBUS, &ioctl_data); -} - static void i2cdetect_dash_F(int bus) { + size_t i; + struct { int mask; const char *name; } funcs[] = { {I2C_FUNC_I2C, "I2C"}, {I2C_FUNC_SMBUS_QUICK, "SMBus Quick Command"}, @@ -145,12 +140,13 @@ static void i2cdetect_dash_F(int bus) {I2C_FUNC_SMBUS_WRITE_I2C_BLOCK, "I2C Write Block"}, {I2C_FUNC_SMBUS_READ_I2C_BLOCK, "I2C Read Block"}, }; - unsigned long sup = i2c_get_funcs(bus); - int i; + unsigned long supported = i2c_get_funcs(bus); printf("Functionalities implemented by %s:\n", toybuf); - for (i = 0; i < ARRAY_LEN(funcs); ++i) - printf("%-32s %s\n", funcs[i].name, (sup & funcs[i].mask) ? "yes" : "no"); + for (i = 0; i < ARRAY_LEN(funcs); ++i) { + printf("%-32s %s\n", funcs[i].name, + (supported & funcs[i].mask) ? "yes" : "no"); + } } static int i2cdetect_dash_l(struct dirtree *node) @@ -162,7 +158,7 @@ static int i2cdetect_dash_l(struct dirtree *node) if (!node->parent) return DIRTREE_RECURSE; // Skip the directory itself. - if (sscanf(node->name, "i2c-%d", &bus)!=1) return 0; + if (sscanf(node->name, "i2c-%d", &bus) != 1) return 0; funcs = i2c_get_funcs(bus); fname = dirtree_path(node, &suffix_len); @@ -171,9 +167,10 @@ static int i2cdetect_dash_l(struct dirtree *node) free(fname); if ((p = strchr(toybuf, '\n'))) *p = 0; - // "i2c-1 i2c Synopsys DesignWare I2C adapter I2C adapter" + // "i2c-1 i2c Synopsys DesignWare I2C adapter I2C adapter" printf("%s\t%-10s\t%-32s\t%s\n", node->name, - (funcs & I2C_FUNC_I2C) ? "i2c" : "?", toybuf, + (funcs & I2C_FUNC_I2C) ? "i2c" : "?", + toybuf, (funcs & I2C_FUNC_I2C) ? "I2C Adapter" : "?"); return 0; @@ -181,25 +178,25 @@ static int i2cdetect_dash_l(struct dirtree *node) void i2cdetect_main(void) { - if (FLAG(l)) { + if (toys.optflags & FLAG_l) { if (toys.optc) error_exit("-l doesn't take arguments"); - dirtree_flagread("/sys/class/i2c-dev", DIRTREE_SHUTUP, i2cdetect_dash_l); - } else if (FLAG(F)) { + dirtree_read("/sys/class/i2c-dev", i2cdetect_dash_l); + } else if (toys.optflags & FLAG_F) { if (toys.optc != 1) error_exit("-F BUS"); i2cdetect_dash_F(atolx_range(*toys.optargs, 0, INT_MAX)); } else { int bus, first = 0x03, last = 0x77, fd, row, addr, byte; - if (FLAG(a)) { + if (toys.optflags & FLAG_a) { first = 0x00; last = 0x7f; } - if (toys.optc!=1 && toys.optc!=3) help_exit("Needs 1 or 3 arguments"); + if (toys.optc != 1 && toys.optc != 3) error_exit("bad args"); bus = atolx_range(*toys.optargs, 0, INT_MAX); - if (toys.optc==3) { + if (toys.optc == 3) { first = atolx_range(toys.optargs[1], 0, 0x7f); - last = atolx_range(toys.optargs[2], 0, 0x7f); + last = atolx_range(toys.optargs[1], 0, 0x7f); if (first > last) error_exit("first > last"); } @@ -209,8 +206,8 @@ void i2cdetect_main(void) printf(" 0 1 2 3 4 5 6 7 8 9 a b c d e f\n"); for (row = 0; row <= 0x70; row += 16) { xprintf("%02x:", row & 0xf0); - for (addr = row; addrlast) printf(" "); + for (addr = row; addr < row + 16; ++addr) { + if (addr < first || addr > last) printf(" "); else { if (ioctl(fd, I2C_SLAVE, addr) == -1) { if (errno == EBUSY) { @@ -219,8 +216,7 @@ void i2cdetect_main(void) } perror_exit("ioctl(I2C_SLAVE)"); } - if ((FLAG(r) ? i2c_read_byte(fd, addr, &byte) - : i2c_quick_write(fd, addr)) == -1) xprintf(" --"); + if (i2c_read_byte(fd, addr, &byte) == -1) xprintf(" --"); else xprintf(" %02x", addr); } } @@ -242,16 +238,13 @@ void i2cdump_main(void) confirm("Dump chip 0x%02x on bus %d?", chip, bus); - fd = i2c_open(bus, FLAG(f) ? I2C_SLAVE_FORCE : I2C_SLAVE, chip); + fd = i2c_open(bus, (toys.optflags&FLAG_f)?I2C_SLAVE_FORCE:I2C_SLAVE, chip); printf(" 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef\n"); - for (row = 0; row<=0xf0; row += 16) { + for (row = 0; row <= 0xf0; row += 16) { xprintf("%02x:", row & 0xf0); - for (addr = row; addr=5) { - if (toys.optc-4>I2C_SMBUS_BLOCK_MAX) error_exit("too much data"); + } else if (*mode == 'i' && toys.optc >= 5) { + if (toys.optc - 4 > I2C_SMBUS_BLOCK_MAX) error_exit("too much data"); ioctl_data.size = I2C_SMBUS_I2C_BLOCK_DATA; - for (i = 0; i GLOBALS( - long p, n, c; + long pid; + long level; + long class; ) static int ioprio_get(void) { - return syscall(__NR_ioprio_get, 1, (int)TT.p); + return syscall(__NR_ioprio_get, 1, (int)TT.pid); } static int ioprio_set(void) { - int prio = ((int)TT.c << 13) | (int)TT.n; + int prio = ((int)TT.class << 13) | (int)TT.level; - return syscall(__NR_ioprio_set, 1, (int)TT.p, prio); + return syscall(__NR_ioprio_set, 1, (int)TT.pid, prio); } void ionice_main(void) { - if (!TT.p && !toys.optc) error_exit("Need -p or COMMAND"); + if (!TT.pid && !toys.optc) error_exit("Need -p or COMMAND"); if (toys.optflags == FLAG_p) { int p = ioprio_get(); xprintf("%s: prio %d\n", @@ -65,7 +67,7 @@ void ionice_main(void) p&7); } else { if (-1 == ioprio_set() && !(toys.optflags&FLAG_t)) perror_exit("set"); - if (!TT.p) xexec(toys.optargs); + if (!TT.pid) xexec(toys.optargs); } } @@ -73,22 +75,23 @@ void iorenice_main(void) { char *classes[] = {"none", "rt", "be", "idle"}; - TT.p = atolx(*toys.optargs); + TT.pid = atolx(*toys.optargs); if (toys.optc == 1) { int p = ioprio_get(); if (p == -1) perror_exit("read priority"); - TT.c = (p>>13)&3; + TT.class = (p>>13)&3; p &= 7; - xprintf("Pid %ld, class %s (%ld), prio %d\n", TT.p, classes[TT.c], TT.c, p); + xprintf("Pid %ld, class %s (%ld), prio %d\n", + TT.pid, classes[TT.class], TT.class, p); return; } - for (TT.c = 0; TT.c<4; TT.c++) - if (!strcmp(toys.optargs[toys.optc-1], classes[TT.c])) break; - if (toys.optc == 3 || TT.c == 4) TT.n = atolx(toys.optargs[1]); - else TT.n = 4; - TT.c &= 3; + for (TT.class = 0; TT.class<4; TT.class++) + if (!strcmp(toys.optargs[toys.optc-1], classes[TT.class])) break; + if (toys.optc == 3 || TT.class == 4) TT.level = atolx(toys.optargs[1]); + else TT.level = 4; + TT.class &= 3; if (-1 == ioprio_set()) perror_exit("set"); } diff --git a/toys/other/losetup.c b/toys/other/losetup.c index ce84c1e..917e64e 100644 --- a/toys/other/losetup.c +++ b/toys/other/losetup.c @@ -52,7 +52,7 @@ GLOBALS( static int loopback_setup(char *device, char *file) { struct loop_info64 *loop = (void *)(toybuf+32); - int lfd = -1, ffd = -1; + int lfd = -1, ffd = ffd; int racy = !device; // Open file (ffd) and loop device (lfd) @@ -103,20 +103,19 @@ static int loopback_setup(char *device, char *file) } // Associate file with this device? } else if (file) { - char *f_path = xabspath(file, ABS_PATH); + char *s = xabspath(file, 1); - if (!f_path) perror_exit("%s", file); // already opened but if deleted since + if (!s) perror_exit("file"); // already opened, but if deleted since... if (ioctl(lfd, LOOP_SET_FD, ffd)) { - free(f_path); if (racy && errno == EBUSY) return 1; perror_exit("%s=%s", device, file); } - xstrncpy((char *)loop->lo_file_name, f_path, LO_NAME_SIZE); - free(f_path); loop->lo_offset = TT.o; loop->lo_sizelimit = TT.S; + xstrncpy((char *)loop->lo_file_name, s, LO_NAME_SIZE); if (ioctl(lfd, LOOP_SET_STATUS64, loop)) perror_exit("%s=%s", device, file); if (FLAG(s)) puts(device); + free(s); } else { xprintf("%s: [%lld]:%llu (%s)", device, (long long)loop->lo_device, @@ -129,8 +128,8 @@ static int loopback_setup(char *device, char *file) } done: - xclose(ffd); - xclose(lfd); + if (file) close(ffd); + if (lfd != -1) close(lfd); return 0; } diff --git a/toys/other/lspci.c b/toys/other/lspci.c index 62df47c..c208484 100644 --- a/toys/other/lspci.c +++ b/toys/other/lspci.c @@ -13,7 +13,7 @@ config LSPCI -e Print all 6 digits in class -k Print kernel driver - -m Machine readable format + -m Machine parseable format config LSPCI_TEXT bool "lspci readable output" @@ -51,10 +51,11 @@ static int do_lspci(struct dirtree *new) return 0; *driver = 0; - if (FLAG(k)) readlinkat0(dirfd, "driver", driver, sizeof(driver)); + if (toys.optflags & FLAG_k) + readlinkat0(dirfd, "driver", driver, sizeof(driver)); for (fields = (char*[]){"class", "vendor", "device", 0}; *fields; fields++) { - int fd, size = 6 + 2*(FLAG(e) && p == toybuf); + int fd, size = 6 + 2*((toys.optflags & FLAG_e) && p == toybuf); *p = 0; if (-1 == (fd = openat(dirfd, *fields, O_RDONLY))) { @@ -94,7 +95,8 @@ static int do_lspci(struct dirtree *new) } if (TT.n > 1) { - printf(FLAG(m) ? "%s, \"%s\" \"%s [%s]\" \"%s [%s]\"" + printf((toys.optflags & FLAG_m) + ? "%s, \"%s\" \"%s [%s]\" \"%s [%s]\"" : "%s Class %s: %s [%s] %s [%s]", new->name+5, toybuf, vbig ? vbig : "", vendor, dbig ? dbig : "", device); @@ -103,11 +105,13 @@ static int do_lspci(struct dirtree *new) } } - printf(FLAG(m) ? "%s \"%s\" \"%s\" \"%s\"" : "%s Class %s: %s:%s", - new->name+5, toybuf, vbig ? vbig : vendor, dbig ? dbig : device); + printf((toys.optflags & FLAG_m) ? "%s \"%s\" \"%s\" \"%s\"" + : "%s Class %s: %s:%s", new->name+5, toybuf, + vbig ? vbig : vendor, dbig ? dbig : device); driver: - if (*driver) printf(FLAG(m) ? " \"%s\"" : " %s", basename(driver)); + if (*driver) + printf((toys.optflags & FLAG_m) ? " \"%s\"" : " %s", basename(driver)); xputc('\n'); return 0; diff --git a/toys/other/makedevs.c b/toys/other/makedevs.c index 4edd073..a6998fc 100644 --- a/toys/other/makedevs.c +++ b/toys/other/makedevs.c @@ -39,24 +39,22 @@ GLOBALS( char *d; ) -void makedevs_main(void) +void makedevs_main() { - FILE *fp = stdin; + int fd = 0, line_no, i; char *line = NULL; - size_t allocated_length = 0; - int line_no = 0, i; // Open file and chdir, verbosely xprintf("rootdir = %s\n", *toys.optargs); - if (FLAG(d) && strcmp(TT.d, "-")) { - fp = xfopen(TT.d, "r"); + if ((toys.optflags & FLAG_d) && strcmp(TT.d, "-")) { + fd = xopenro(TT.d); xprintf("table = %s\n", TT.d); } else xprintf("table = \n"); xchdir(*toys.optargs); - while (getline(&line, &allocated_length, fp) > 0) { + for (line_no = 0; (line = get_line(fd)); free(line)) { char type=0, user[64], group[64], *node, *ptr = line; - unsigned int mode = 0755, major = 0, minor = 0, cnt = 0, incr = 0, + unsigned int mode = 0755, major = 0, minor = 0, cnt = 0, incr = 0, st_val = 0; uid_t uid; gid_t gid; @@ -106,10 +104,9 @@ void makedevs_main(void) continue; } - if (chown(ptr, uid, gid) || chmod(ptr, mode)) + if (chown(ptr, uid, gid) || chmod(ptr, mode)) perror_msg("line %d: can't chown/chmod '%s'", line_no, ptr); } } - free(line); - if (fp != stdin) fclose(fp); + xclose(fd); } diff --git a/toys/other/nsenter.c b/toys/other/nsenter.c index 6546935..dfcfbe8 100644 --- a/toys/other/nsenter.c +++ b/toys/other/nsenter.c @@ -82,9 +82,9 @@ GLOBALS( static void write_ugid_map(char *map, unsigned eugid) { - int fd = xopen(map, O_WRONLY); + int bytes = sprintf(toybuf, "0 %u 1", eugid), fd = xopen(map, O_WRONLY); - dprintf(fd, "0 %u 1", eugid); + xwrite(fd, toybuf, bytes); xclose(fd); } diff --git a/toys/other/oneit.c b/toys/other/oneit.c index fca8bba..c400f6d 100644 --- a/toys/other/oneit.c +++ b/toys/other/oneit.c @@ -68,7 +68,7 @@ void oneit_main(void) // Setup signal handlers for signals of interest for (i = 0; i -USE_PRINTENV(NEWTOY(printenv, "(null)0", TOYFLAG_BIN)) +USE_PRINTENV(NEWTOY(printenv, "0(null)", TOYFLAG_BIN)) config PRINTENV bool "printenv" diff --git a/toys/other/reboot.c b/toys/other/reboot.c index f31ab00..c883e34 100644 --- a/toys/other/reboot.c +++ b/toys/other/reboot.c @@ -14,7 +14,6 @@ config REBOOT Restart, halt or powerdown the system. - -d Wait DELAY before proceeding (in seconds or m/h/d suffix: -d 1.5m = 90s) -f Don't signal init -n Don't sync before stopping the system */ diff --git a/toys/other/shred.c b/toys/other/shred.c index 964ce7d..c234c18 100644 --- a/toys/other/shred.c +++ b/toys/other/shred.c @@ -92,7 +92,8 @@ void shred_main(void) // Determine length, read random data if not zeroing, write. throw = sizeof(toybuf); - if (FLAG(x) && len-pos < throw) throw = len-pos; + if (toys.optflags & FLAG_x) + if (len-pos < throw) throw = len-pos; if (iter != TT.n) xgetrandom(toybuf, throw, 0); if (throw != writeall(fd, toybuf, throw)) perror_msg_raw(*try); diff --git a/toys/other/switch_root.c b/toys/other/switch_root.c index 9671a97..eb1e2b0 100644 --- a/toys/other/switch_root.c +++ b/toys/other/switch_root.c @@ -46,7 +46,7 @@ void switch_root_main(void) char *newroot = *toys.optargs, **cmdline = toys.optargs+1; struct stat st1, st2; struct statfs stfs; - int console = console;//gcc's "may be used" warnings are broken. + int console = console; // gcc's "may be used" warnings are broken. if (getpid() != 1) error_exit("not pid 1"); diff --git a/toys/other/uptime.c b/toys/other/uptime.c index d2f1ca7..8975df2 100644 --- a/toys/other/uptime.c +++ b/toys/other/uptime.c @@ -28,7 +28,7 @@ void uptime_main(void) struct sysinfo info; time_t t; struct tm *tm; - unsigned int weeks, days, hours, minutes; + unsigned int days, hours, minutes; struct utmpx *entry; int users = 0; @@ -37,7 +37,7 @@ void uptime_main(void) time(&t); // Just show the time of boot? - if (FLAG(s)) { + if (toys.optflags & FLAG_s) { t -= info.uptime; tm = localtime(&t); strftime(toybuf, sizeof(toybuf), "%F %T", tm); @@ -54,10 +54,10 @@ void uptime_main(void) hours = info.uptime%24; days = info.uptime/24; - if (FLAG(p)) { - weeks = days/7; + if (toys.optflags & FLAG_p) { + int weeks = days/7; days %= 7; - xprintf("up %d week%s, %d day%s, %d hour%s, %d minute%s, ", + xprintf("up %d week%s, %d day%s, %d hour%s, %d minute%s\n", weeks, (weeks!=1)?"s":"", days, (days!=1)?"s":"", hours, (hours!=1)?"s":"", diff --git a/toys/pending/lsof.c b/toys/pending/lsof.c index 0df6a79..65aeb2d 100644 --- a/toys/pending/lsof.c +++ b/toys/pending/lsof.c @@ -120,7 +120,7 @@ static void scan_proc_net_file(char *path, int family, char type, if (!fp) return; - if (getline(&line, &line_length, fp)) return; // Skip header. + if (!getline(&line, &line_length, fp)) return; // Skip header. while (getline(&line, &line_length, fp) > 0) { fn(line, family, type); @@ -335,10 +335,10 @@ static void visit_maps(struct proc_info *pi) { FILE *fp; unsigned long long offset; + char device[10]; long inode; - char *line = NULL, device[10]; + char *line = NULL; size_t line_length = 0; - struct file_info *fi; snprintf(toybuf, sizeof(toybuf), "/proc/%d/maps", pi->pid); fp = fopen(toybuf, "r"); diff --git a/toys/pending/modprobe.c b/toys/pending/modprobe.c index fcd1cc3..0f9e12d 100644 --- a/toys/pending/modprobe.c +++ b/toys/pending/modprobe.c @@ -16,14 +16,14 @@ config MODPROBE modprobe utility - inserts modules and dependencies. -a Load multiple MODULEs - -b Apply blacklist to module names too - -D Show dependencies -d Load modules from DIR, option may be used multiple times -l List (MODULE is a pattern) - -q Quiet -r Remove MODULE (stacks) or do autoclean - -s Log to syslog + -q Quiet -v Verbose + -s Log to syslog + -D Show dependencies + -b Apply blacklist to module names too */ #define FOR_modprobe #include "toys.h" @@ -32,11 +32,17 @@ config MODPROBE GLOBALS( struct arg_list *dirs; - struct arg_list *probes, *dbase[256]; + struct arg_list *probes; + struct arg_list *dbase[256]; char *cmdopts; - int nudeps, symreq; + int nudeps; + uint8_t symreq; ) +/* Note: if "#define DBASE_SIZE" modified, + * Please update GLOBALS dbase[256] accordingly. + */ +#define DBASE_SIZE 256 #define MODNAME_LEN 256 // Modules flag definations @@ -142,7 +148,7 @@ static struct module_s *get_mod(char *mod, uint8_t add) path2mod(mod, name); for (i = 0; name[i]; i++) hash = ((hash*31) + hash) + name[i]; - hash %= ARRAY_LEN(TT.dbase); + hash %= DBASE_SIZE; for (temp = TT.dbase[hash]; temp; temp = temp->next) { modentry = (struct module_s *) temp->arg; if (!strcmp(modentry->name, name)) return modentry; @@ -155,7 +161,7 @@ static struct module_s *get_mod(char *mod, uint8_t add) } /* - * Read a line from file with \ continuation and skip commented lines. + * Read a line from file with \ continuation and escape commented line. * Return the line in allocated string (*li) */ static int read_line(FILE *fl, char **li) @@ -164,7 +170,7 @@ static int read_line(FILE *fl, char **li) ssize_t len, nxtlen; size_t linelen, nxtlinelen; - for (;;) { + while (1) { line = NULL; linelen = nxtlinelen = 0; len = getline(&line, &linelen, fl); @@ -220,7 +226,7 @@ static int config_action(struct dirtree *node) free(filename); return 0; } - for (line = linecp = NULL; read_line(fc, &line) >= 0; + for (line = linecp = NULL; read_line(fc, &line) > 0; free(line), free(linecp), line = linecp = NULL) { char *tk = NULL; @@ -234,18 +240,17 @@ static int config_action(struct dirtree *node) break; } } - // Every command requires at least one argument. - if (tcount < 2) continue; + if (!tk) continue; // process the tokens[0] contains first word of config line. if (!strcmp(tokens[0], "alias")) { struct arg_list *temp; - char alias[MODNAME_LEN], *realname; + char aliase[MODNAME_LEN], *realname; if (!tokens[2]) continue; - path2mod(tokens[1], alias); + path2mod(tokens[1], aliase); for (temp = TT.probes; temp; temp = temp->next) { modent = (struct module_s *) temp->arg; - if (fnmatch(alias, modent->name, 0)) continue; + if (fnmatch(aliase, modent->name, 0)) continue; realname = path2mod(tokens[2], NULL); llist_add(&modent->rnames, realname); if (modent->flags & MOD_NDDEPS) { @@ -268,7 +273,7 @@ static int config_action(struct dirtree *node) get_mod(tokens[1], 1)->flags |= MOD_BLACKLIST; else if (!strcmp(tokens[0], "install")) continue; else if (!strcmp(tokens[0], "remove")) continue; - else if (!FLAG(q)) + else if (toys.optflags & FLAG_q) error_msg("Invalid option %s found in file %s", tokens[0], filename); } fclose(fc); @@ -279,21 +284,22 @@ static int config_action(struct dirtree *node) // Show matched modules else return -1 on failure. static int depmode_read_entry(char *cmdname) { - char *line, *name; + char *line; int ret = -1; FILE *fe = xfopen("modules.dep", "r"); - while (read_line(fe, &line) >= 0) { + while (read_line(fe, &line) > 0) { char *tmp = strchr(line, ':'); if (tmp) { *tmp = '\0'; - name = basename(line); + char *name = basename(line); + tmp = strchr(name, '.'); if (tmp) *tmp = '\0'; if (!cmdname || !fnmatch(cmdname, name, 0)) { if (tmp) *tmp = '.'; - if (FLAG(v)) puts(line); + if (toys.optflags&FLAG_v) puts(line); ret = 0; } } @@ -310,17 +316,18 @@ static void find_dep(void) struct module_s *mod; FILE *fe = xfopen("modules.dep", "r"); - for (; read_line(fe, &line) >= 0; free(line)) { + for (; read_line(fe, &line) > 0; free(line)) { char *tmp = strchr(line, ':'); if (tmp) { *tmp = '\0'; mod = get_mod(line, 0); if (!mod) continue; - if ((mod->flags & MOD_ALOADED) && !(FLAG(r)|FLAG(D))) continue; + if ((mod->flags & MOD_ALOADED) && + !(toys.optflags & (FLAG_r | FLAG_D))) continue; mod->flags |= MOD_FNDDEPMOD; - if ((mod->flags & MOD_NDDEPS) && !mod->dep) { + if ((mod->flags & MOD_NDDEPS) && (!mod->dep)) { TT.nudeps--; llist_add(&mod->dep, xstrdup(line)); tmp++; @@ -339,22 +346,50 @@ static void find_dep(void) } // Remove a module from the Linux Kernel. if !modules does auto remove. -static int rm_mod(char *modules) +static int rm_mod(char *modules, uint32_t flags) { - char *s; + if (modules) { + int len = strlen(modules); + + if (len > 3 && !strcmp(modules+len-3, ".ko" )) modules[len-3] = 0; + } - if (modules && (s = strend(modules, ".ko"))) *s = 0; - return syscall(__NR_delete_module, modules, O_NONBLOCK); + errno = 0; + syscall(__NR_delete_module, modules, flags ? flags : O_NONBLOCK|O_EXCL); + + return errno; } -// Insert module; simpler than insmod(1) because we already flattened the array -// of flags, and don't need to support loading from stdin. +// Insert module same as insmod implementation. static int ins_mod(char *modules, char *flags) { - int fd = xopenro(modules), rc = syscall(__NR_finit_module, fd, flags, 0); + char *buf = NULL; + int len, res; + int fd = xopenro(modules); + + while (flags && strlen(toybuf) + strlen(flags) + 2 < sizeof(toybuf)) { + strcat(toybuf, flags); + strcat(toybuf, " "); + } + +#ifdef __NR_finit_module + res = syscall(__NR_finit_module, fd, toybuf, 0); + if (!res || errno != ENOSYS) { + xclose(fd); + return res; + } +#endif + + // TODO xreadfile() + len = fdlength(fd); + buf = xmalloc(len); + xreadall(fd, buf, len); xclose(fd); - return rc; + + res = syscall(__NR_init_module, buf, len, toybuf); + if (CFG_TOYBOX_FREE && buf != toybuf) free(buf); + return res; } // Add module in probes list, if not loaded. @@ -362,11 +397,11 @@ static void add_mod(char *name) { struct module_s *mod = get_mod(name, 1); - if (!(FLAG(r)|FLAG(D)) && (mod->flags & MOD_ALOADED)) { - if (FLAG(v)) printf("%s already loaded\n", name); + if (!(toys.optflags & (FLAG_r | FLAG_D)) && (mod->flags & MOD_ALOADED)) { + if (toys.optflags&FLAG_v) printf("skipping %s, already loaded\n", name); return; } - if (FLAG(v)) printf("queuing %s\n", name); + if (toys.optflags&FLAG_v) printf("queuing %s\n", name); mod->cmdname = name; mod->flags |= MOD_NDDEPS; llist_add_tail(&TT.probes, mod); @@ -395,16 +430,17 @@ static char *add_cmdopt(char **argv) } // Probes a single module and loads all its dependencies. -static void go_probe(struct module_s *m) +static int go_probe(struct module_s *m) { int rc = 0, first = 1; if (!(m->flags & MOD_FNDDEPMOD)) { - if (!FLAG(q)) error_msg("module %s not found in modules.dep", m->name); - return; + if (!(toys.optflags & FLAG_q)) + error_msg("module %s not found in modules.dep", m->name); + return -ENOENT; } - if (FLAG(v)) printf("go_prob'ing %s\n", m->name); - if (!FLAG(r)) m->dep = llist_rev(m->dep); + if (toys.optflags & FLAG_v) printf("go_prob'ing %s\n", m->name); + if (!(toys.optflags & FLAG_r)) m->dep = llist_rev(m->dep); while (m->dep) { struct module_s *m2; @@ -414,9 +450,9 @@ static void go_probe(struct module_s *m) fn = llist_popme(&m->dep); m2 = get_mod(fn, 1); // are we removing ? - if (FLAG(r)) { + if (toys.optflags & FLAG_r) { if (m2->flags & MOD_ALOADED) { - if (rm_mod(m2->name)) { + if ((rc = rm_mod(m2->name, O_EXCL))) { if (first) { perror_msg("can't unload module %s", m2->name); break; @@ -426,27 +462,27 @@ static void go_probe(struct module_s *m) first = 0; continue; } -// TODO how does free work here without leaking? options = m2->opts; m2->opts = NULL; if (m == m2) options = add_opts(options, TT.cmdopts); // are we only checking dependencies ? - if (FLAG(D)) { - if (FLAG(v)) + if (toys.optflags & FLAG_D) { + if (toys.optflags & FLAG_v) printf(options ? "insmod %s %s\n" : "insmod %s\n", fn, options); if (options) free(options); continue; } if (m2->flags & MOD_ALOADED) { - if (FLAG(v)) printf("%s already loaded\n", fn); + if (toys.optflags&FLAG_v) + printf("%s is already loaded, skipping\n", fn); if (options) free(options); continue; } // none of above is true insert the module. errno = 0; rc = ins_mod(fn, options); - if (FLAG(v)) + if (toys.optflags&FLAG_v) printf("loaded %s '%s': %s\n", fn, options, strerror(errno)); if (errno == EEXIST) rc = 0; free(options); @@ -456,35 +492,40 @@ static void go_probe(struct module_s *m) } m2->flags |= MOD_ALOADED; } + return rc; } void modprobe_main(void) { + struct utsname uts; char **argv = toys.optargs, *procline = NULL; FILE *fs; struct module_s *module; + unsigned flags = toys.optflags; struct arg_list *dirs; - if (toys.optc<1 && !FLAG(r) == !FLAG(l)) help_exit("bad syntax"); + if ((toys.optc < 1) && (((flags & FLAG_r) && (flags & FLAG_l)) + ||(!((flags & FLAG_r)||(flags & FLAG_l))))) + { + help_exit("bad syntax"); + } // Check for -r flag without arg if yes then do auto remove. - if (FLAG(r) && !toys.optc) { - if (rm_mod(0)) perror_exit("rmmod"); + if ((flags & FLAG_r) && !toys.optc) { + if (rm_mod(NULL, O_NONBLOCK | O_EXCL)) perror_exit("rmmod"); return; } if (!TT.dirs) { - struct utsname uts; - uname(&uts); TT.dirs = xzalloc(sizeof(struct arg_list)); TT.dirs->arg = xmprintf("/lib/modules/%s", uts.release); } // modules.dep processing for dependency check. - if (FLAG(l)) { + if (flags & FLAG_l) { for (dirs = TT.dirs; dirs; dirs = dirs->next) { xchdir(dirs->arg); - if (!depmode_read_entry(*toys.optargs)) return; + if (!depmode_read_entry(toys.optargs[0])) return; } error_exit("no module found."); } @@ -493,19 +534,22 @@ void modprobe_main(void) fs = xfopen("/proc/modules", "r"); while (read_line(fs, &procline) > 0) { - *strchr(procline, ' ') = 0; + *(strchr(procline, ' ')) = '\0'; get_mod(procline, 1)->flags = MOD_ALOADED; free(procline); procline = NULL; } fclose(fs); - if (FLAG(a) || FLAG(r)) for (; *argv; argv++) add_mod(*argv); - else { - add_mod(*argv); + if ((flags & FLAG_a) || (flags & FLAG_r)) { + do { + add_mod(*argv++); + } while (*argv); + } else { + add_mod(argv[0]); TT.cmdopts = add_cmdopt(argv); } if (!TT.probes) { - if (FLAG(v)) puts("All modules loaded"); + if (toys.optflags&FLAG_v) puts("All modules loaded"); return; } dirtree_flagread("/etc/modprobe.conf", DIRTREE_SHUTUP, config_action); @@ -524,23 +568,23 @@ void modprobe_main(void) while ((module = llist_popme(&TT.probes))) { if (!module->rnames) { - if (FLAG(v)) puts("probing by module name"); + if (toys.optflags&FLAG_v) puts("probing by module name"); /* This is not an alias. Literal names are blacklisted * only if '-b' is given. */ - if (!FLAG(b) || !(module->flags & MOD_BLACKLIST)) + if (!(flags & FLAG_b) || !(module->flags & MOD_BLACKLIST)) go_probe(module); continue; } do { // Probe all real names for the alias. - char *real = ((struct arg_list *)llist_pop(&module->rnames))->arg; + char *real = ((struct arg_list*)llist_pop(&module->rnames))->arg; struct module_s *m2 = get_mod(real, 0); - if (FLAG(v)) + if (toys.optflags&FLAG_v) printf("probing alias %s by realname %s\n", module->name, real); if (!m2) continue; if (!(m2->flags & MOD_BLACKLIST) - && (!(m2->flags & MOD_ALOADED) || FLAG(r) || FLAG(D))) + && (!(m2->flags & MOD_ALOADED) || (flags & (FLAG_r | FLAG_D)))) go_probe(m2); free(real); } while (module->rnames); diff --git a/toys/pending/tr.c b/toys/pending/tr.c index e68ae46..9a823f6 100644 --- a/toys/pending/tr.c +++ b/toys/pending/tr.c @@ -210,21 +210,26 @@ save: static void print_map(char *set1, char *set2) { - int n, src, dst, prev = -1; + int r = 0, i, prev_char = -1; - while ((n = read(0, toybuf, sizeof(toybuf)))) { - if (!FLAG(d) && !FLAG(s)) { - for (dst = 0; dst < n; dst++) toybuf[dst] = TT.map[toybuf[dst]]; - } else { - for (src = dst = 0; src < n; src++) { - int ch = TT.map[toybuf[src]]; + while (1) + { + i = 0; + r = read(STDIN_FILENO, (toybuf), sizeof(toybuf)); + if (!r) break; + for (;r > i;i++) { - if (FLAG(d) && (ch & 0x100)) continue; - if (FLAG(s) && ((ch & 0x200) && prev == ch)) continue; - toybuf[dst++] = prev = ch; + if ((toys.optflags & FLAG_d) && (TT.map[(int)toybuf[i]] & 0x100)) continue; + if (toys.optflags & FLAG_s) { + if ((TT.map[(int)toybuf[i]] & 0x200) && + (prev_char == TT.map[(int)toybuf[i]])) { + continue; + } } + xputc(TT.map[(int)toybuf[i]] & 0xFF); + prev_char = TT.map[(int)toybuf[i]]; + fflush(stdout); } - xwrite(1, toybuf, dst); } } diff --git a/toys/pending/traceroute.c b/toys/pending/traceroute.c index 4484580..9464e0c 100644 --- a/toys/pending/traceroute.c +++ b/toys/pending/traceroute.c @@ -218,7 +218,7 @@ static void do_trace() fflush(NULL); if (!TT.istraceroute6) - if (probe && (toys.optflags & FLAG_z)) msleep(TT.pause_time); + if (probe && (toys.optflags & FLAG_z)) usleep(TT.pause_time * 1000); if (!TT.istraceroute6) send_probe4(++seq, ttl); else send_probe6(++seq, ttl); @@ -477,7 +477,7 @@ static void do_trace() void traceroute_main(void) { - unsigned opt_len = 0, tyser = 0; + unsigned opt_len = 0, pack_size = 0, tyser = 0; int lsrr = 0, set = 1; if(!(toys.optflags & FLAG_4) && diff --git a/toys/posix/du.c b/toys/posix/du.c index 8611867..73ef6db 100644 --- a/toys/posix/du.c +++ b/toys/posix/du.c @@ -4,22 +4,19 @@ * * See http://opengroup.org/onlinepubs/9699919799/utilities/du.html * - * TODO: cleanup (should seen_inode be lib?) - * 32 bit du -b maxes out at 4 gigs (instead of 2 terabytes via *512 trick) - * because dirtree->extra is a long. + * TODO: cleanup -USE_DU(NEWTOY(du, "d#<0=-1hmlcaHkKLsxb[-HL][-kKmh]", TOYFLAG_USR|TOYFLAG_BIN)) +USE_DU(NEWTOY(du, "d#<0=-1hmlcaHkKLsx[-HL][-kKmh]", TOYFLAG_USR|TOYFLAG_BIN)) config DU bool "du" default y help - usage: du [-d N] [-askxHLlmc] [FILE...] + usage: du [-d N] [-askxHLlmc] [file...] Show disk usage, space consumed by files and directories. Size in: - -b Apparent bytes (directory listing size, not space used) -k 1024 byte blocks (default) -K 512 byte blocks (posix) -m Megabytes @@ -59,17 +56,16 @@ static void print(long long size, struct dirtree *node) if (TT.depth > TT.d) return; - if (FLAG(h)) { + if (toys.optflags & FLAG_h) { human_readable(toybuf, size, 0); printf("%s", toybuf); } else { int bits = 10; - if (FLAG(K)) bits = 9; - else if (FLAG(m)) bits = 20; + if (toys.optflags & FLAG_K) bits = 9; + else if (toys.optflags & FLAG_m) bits = 20; - if (FLAG(b) && bits == 10 && !FLAG(k)) printf("%llu", size); - else printf("%llu", (size>>bits)+!!(size&((1<>bits)+!!(size&((1<st.st_dev)) + if ((toys.optflags & FLAG_x) && (TT.st_dev != node->st.st_dev)) return 0; // Don't loop endlessly on recursive directory symlink - if (FLAG(L)) { + if (toys.optflags & FLAG_L) { struct dirtree *try = node; while ((try = try->parent)) @@ -129,29 +125,30 @@ static int do_du(struct dirtree *node) } // Don't count hard links twice - if (!FLAG(l) && !node->again) + if (!(toys.optflags & FLAG_l) && !node->again) if (seen_inode(&TT.inodes, &node->st)) return 0; // Collect child info before printing directory size if (S_ISDIR(node->st.st_mode)) { if (!node->again) { TT.depth++; - return DIRTREE_COMEAGAIN|(DIRTREE_SYMFOLLOW*!!FLAG(L)); + return DIRTREE_COMEAGAIN|(DIRTREE_SYMFOLLOW*!!(toys.optflags&FLAG_L)); } else TT.depth--; } // Modern compilers' optimizers are insane and think signed overflow // behaves differently than unsigned overflow. Sigh. Big hammer. - blocks = FLAG(b) ? node->st.st_size : node->st.st_blocks; - blocks += (unsigned long)node->extra; + blocks = node->st.st_blocks + (unsigned long)node->extra; node->extra = blocks; if (node->parent) node->parent->extra = (unsigned long)node->parent->extra+blocks; else TT.total += node->extra; - if (FLAG(a) || !node->parent || (S_ISDIR(node->st.st_mode) && !FLAG(s))) { + if ((toys.optflags & FLAG_a) || !node->parent + || (S_ISDIR(node->st.st_mode) && !(toys.optflags & FLAG_s))) + { blocks = node->extra; - print(FLAG(b) ? blocks : blocks*512LL, node); + print(blocks*512LL, node); } return 0; @@ -165,7 +162,7 @@ void du_main(void) for (args = toys.optc ? toys.optargs : noargs; *args; args++) dirtree_flagread(*args, DIRTREE_SYMFOLLOW*!!(toys.optflags&(FLAG_H|FLAG_L)), do_du); - if (FLAG(c)) print(FLAG(b) ? TT.total : TT.total*512, 0); + if (toys.optflags & FLAG_c) print(TT.total*512, 0); if (CFG_TOYBOX_FREE) seen_inode(TT.inodes, 0); } diff --git a/toys/posix/find.c b/toys/posix/find.c index 0541d97..4b88edb 100644 --- a/toys/posix/find.c +++ b/toys/posix/find.c @@ -7,7 +7,6 @@ * Our "unspecified" behavior for no paths is to use "." * Parentheses can only stack 4096 deep * Not treating two {} as an error, but only using last - * TODO: -context USE_FIND(NEWTOY(find, "?^HL[-HL]", TOYFLAG_USR|TOYFLAG_BIN)) @@ -36,9 +35,8 @@ config FIND -inum N inode number N -empty empty files and dirs -type [bcdflps] type is (block, char, dir, file, symlink, pipe, socket) -true always true -false always false - -context PATTERN security context -executable access(X_OK) perm+ACL + -context PATTERN security context -newerXY FILE X=acm time > FILE's Y=acm time (Y=t: FILE is literal time) - -quit exit immediately Numbers N may be prefixed by a - (less than) or + (greater than). Units for -Xtime are d (days, default), h (hours), m (minutes), or s (seconds). @@ -307,7 +305,7 @@ static int do_find(struct dirtree *new) if (new && check) test = !unlinkat(dirtree_parentfd(new), new->name, S_ISDIR(new->st.st_mode) ? AT_REMOVEDIR : 0); - } else if (!strcmp(s, "depth") || !strcmp(s, "d")) TT.depth = 1; + } else if (!strcmp(s, "depth")) TT.depth = 1; else if (!strcmp(s, "o") || !strcmp(s, "or")) { if (not) goto error; if (active) { @@ -347,33 +345,23 @@ static int do_find(struct dirtree *new) } else test = 0; } } else if (!strcmp(s, "nouser")) { - if (check && bufgetpwuid(new->st.st_uid)) test = 0; + if (check) if (bufgetpwuid(new->st.st_uid)) test = 0; } else if (!strcmp(s, "nogroup")) { - if (check && bufgetgrgid(new->st.st_gid)) test = 0; + if (check) if (bufgetgrgid(new->st.st_gid)) test = 0; } else if (!strcmp(s, "prune")) { if (check && S_ISDIR(new->st.st_mode) && !TT.depth) recurse = 0; - } else if (!strcmp(s, "executable")) { - if (check && faccessat(dirtree_parentfd(new), new->name,X_OK,0)) test = 0; - } else if (!strcmp(s, "quit")) { - if (check) { - execdir(0, 1); - xexit(); - } // Remaining filters take an argument } else { if (!strcmp(s, "name") || !strcmp(s, "iname") || !strcmp(s, "wholename") || !strcmp(s, "iwholename") - || !strcmp(s, "path") || !strcmp(s, "ipath") - || !strcmp(s, "lname") || !strcmp(s, "ilname")) + || !strcmp(s, "path") || !strcmp(s, "ipath")) { int i = (*s == 'i'), is_path = (s[i] != 'n'); char *arg = ss[1], *path = 0, *name = new ? new->name : arg; // Handle path expansion and case flattening - if (new && s[i] == 'l') - name = path = xreadlinkat(dirtree_parentfd(new), new->name); - else if (new && is_path) name = path = dirtree_path(new, 0); + if (new && is_path) name = path = dirtree_path(new, 0); if (i) { if ((check || !new) && name) name = strlower(name); if (!new) dlist_add(&TT.argdata, name); @@ -381,7 +369,7 @@ static int do_find(struct dirtree *new) } if (check) { - test = !fnmatch(arg, path ? name : basename(name), + test = !fnmatch(arg, is_path ? name : basename(name), FNM_PATHNAME*(!is_path)); if (i) free(name); } @@ -410,16 +398,10 @@ static int do_find(struct dirtree *new) } else if (!strcmp(s, "type")) { if (check) { int types[] = {S_IFBLK, S_IFCHR, S_IFDIR, S_IFLNK, S_IFIFO, - S_IFREG, S_IFSOCK}, i; - char *t = ss[1]; - - for (; *t; t++) { - if (*t == ',') continue; - i = stridx("bcdlpfs", *t); - if (i<0) error_exit("bad -type '%c'", *t); - if ((new->st.st_mode & S_IFMT) == types[i]) break; - } - test = *t; + S_IFREG, S_IFSOCK}, i = stridx("bcdlpfs", *ss[1]); + + if (i<0) error_exit("bad -type '%c'", *ss[1]); + if ((new->st.st_mode & S_IFMT) != types[i]) test = 0; } } else if (strchr("acm", *s) @@ -603,12 +585,16 @@ static int do_find(struct dirtree *new) if (check) for (fmt = ss[1]; *fmt; fmt++) { // Print the parts that aren't escapes if (*fmt == '\\') { - unsigned u; - - if (fmt[1] == 'c') break; - if ((u = unescape2(&fmt, 0))<128) putchar(u); - else printf("%.*s", (int)wcrtomb(buf, u, 0), buf); - fmt--; + int slash = *++fmt, n = unescape(slash); + + if (n) ch = n; + else if (slash=='c') break; + else if (slash=='0') { + ch = 0; + while (*fmt>='0' && *fmt<='7' && n++<3) ch=(ch*8)+*(fmt++)-'0'; + --fmt; + } else error_exit("bad \\%c", *fmt); + putchar(ch); } else if (*fmt != '%') putchar(*fmt); else if (*++fmt == '%') putchar('%'); else { @@ -634,7 +620,10 @@ static int do_find(struct dirtree *new) else if (ch == 'g') ll = (long)getgroupname(new->st.st_gid); else if (ch == 'u') ll = (long)getusername(new->st.st_uid); else if (ch == 'l') { - ll = (long)(ff = xreadlinkat(dirtree_parentfd(new), new->name)); + char *path = dirtree_path(new, 0); + + ll = (long)(ff = xreadlink(path)); + free(path); if (!ll) ll = (long)""; } else if (ch == 'M') { mode_to_string(new->st.st_mode, buf); @@ -647,7 +636,7 @@ static int do_find(struct dirtree *new) } else if (ch == 'p') ll = (long)(ff = dirtree_path(new, 0)); else if (ch == 'T') { if (*++fmt!='@') error_exit("bad -printf %%T: %%T%c", *fmt); - sprintf(buf, "%lld.%ld", (long long)new->st.st_mtim.tv_sec, + sprintf(buf, "%ld.%ld", new->st.st_mtim.tv_sec, new->st.st_mtim.tv_nsec); ll = (long)buf; } else if (ch == 'Z') { @@ -699,7 +688,7 @@ void find_main(void) // Distinguish paths from filters for (len = 0; toys.optargs[len]; len++) - if (*toys.optargs[len] && strchr("-!(", *toys.optargs[len])) break; + if (strchr("-!(", *toys.optargs[len])) break; TT.filter = toys.optargs+len; // use "." if no paths diff --git a/toys/posix/ps.c b/toys/posix/ps.c index ed9ee02..999425c 100644 --- a/toys/posix/ps.c +++ b/toys/posix/ps.c @@ -1791,7 +1791,7 @@ static void top_common( #ifdef TOYBOX_OH_ADAPT /* fix "top -n 5" show 3 times problem*/ if (i==-3) { - if (TT.top.n != 0) { + if (TT.top.n != 0) { TT.top.n++; } continue; diff --git a/toys/posix/pwd.c b/toys/posix/pwd.c index 45ca89b..4c6ae99 100644 --- a/toys/posix/pwd.c +++ b/toys/posix/pwd.c @@ -47,6 +47,7 @@ void pwd_main(void) // If -L didn't give us a valid path, use cwd. if (!s && !(s = pwd)) perror_exit("xgetcwd"); + xprintf("%s\n", s); if (CFG_TOYBOX_FREE) free(pwd); diff --git a/toys/posix/rm.c b/toys/posix/rm.c index 03cec94..8874b54 100644 --- a/toys/posix/rm.c +++ b/toys/posix/rm.c @@ -96,7 +96,7 @@ void rm_main(void) continue; } - // Files that already don't exist aren't errors for -f. so try a quick + // Files that already don't exist aren't errors for -f, so try a quick // unlink now to see if it succeeds or reports that it didn't exist. if (FLAG(f) && (!unlink(*s) || errno == ENOENT)) continue; diff --git a/toys/posix/sort.c b/toys/posix/sort.c index 2808142..4b3fe24 100644 --- a/toys/posix/sort.c +++ b/toys/posix/sort.c @@ -62,7 +62,8 @@ GLOBALS( void *key_list; int linecount; - char **lines, *name; + char **lines; + char *name; ) // The sort types are n, g, and M. @@ -83,7 +84,7 @@ struct sort_key static char *get_key_data(char *str, struct sort_key *key, int flags) { - int start = 0, end, len, i, j; + int start=0, end, len, i, j; // Special case whole string, so we don't have to make a copy @@ -98,8 +99,8 @@ static char *get_key_data(char *str, struct sort_key *key, int flags) // Loop through fields else { - end = 0; - for (i = 1; i < key->range[2*j]+j; i++) { + end=0; + for (i=1; i < key->range[2*j]+j; i++) { // Skip leading blanks if (str[end] && !TT.t) while (isspace(str[end])) end++; @@ -137,7 +138,7 @@ static char *get_key_data(char *str, struct sort_key *key, int flags) } // Make the copy - if (endnext = TT.outputs; - if (1 == (temp->fd = fd)) TT.out++; + temp->fd = fd; TT.outputs = temp; } void tee_main(void) { - struct fd_list *fdl; - int len; - if (FLAG(i)) xsignal(SIGINT, SIG_IGN); - // Open output files (plus stdout if not already in output list) + // Open output files loopfiles_rw(toys.optargs, O_RDWR|O_CREAT|WARN_ONLY|(FLAG(a)?O_APPEND:O_TRUNC), 0666, do_tee_open); - if (!TT.out) do_tee_open(1, 0); - // Read data from stdin, write to each output file. for (;;) { - if (1>(len = xread(0, toybuf, sizeof(toybuf)))) break; - for (fdl = TT.outputs; fdl;fdl = fdl->next) - if (len != writeall(fdl->fd, toybuf, len)) toys.exitval = 1; + 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 --git a/www/roadmap.html b/www/roadmap.html index 865d951..06abb29 100644 --- a/www/roadmap.html +++ b/www/roadmap.html @@ -2,66 +2,47 @@ Toybox Roadmap -

Roadmap sections

+

Goals and use cases

+ +

We have several potential use cases for a new set of command line +utilities, and are using those to determine which commands to implement +for Toybox's 1.0 release. (Most of these have their own section in the +status page.)

+ +

The most interesting publicly available standards are POSIX-2008 +(also known as the Single +Unix Specification version 4) and the Linux Standard Base (version 4.1). +The main test harness is including toybox in Aboriginal Linux and if that can +build itself using the result to build Linux From Scratch (version 6.8). +We also aim to replace Android's Toolbox.

+ +

At a secondary level we'd like to meet other use cases. We've analyzed +the commands provided by similar projects (klibc, sash, sbase, embutils, +nash, and beastiebox), along with various vendor configurations of busybox, +and some end user requests.

+ +

Finally, we'd like to provide a good replacement for the Bash shell, +which was the first program Linux ever ran and remains the standard shell +of Linux no matter what Ubuntu says. This doesn't mean including the full +set of Bash 4.x functionality, but does involve {various,features} <(beyond) +posix.

+ +

See the status page for the combined list +and progress towards implementing it.

- -

Introduction (Goals and use cases)

- -

We have several potential use cases for a new set of command line -utilities, and are using those to determine which commands to implement -for Toybox's 1.0 release. Most of these have their own section in the -status page, showing current progress towards -commplation.

- -

The most interesting publicly available standards are A) POSIX-2008 (also -known as SUSv4), B) the Linux Standard Base version 4.1, and C) the official -Linux man pages. -But they include commands we've decided not implement, exclude -commands or features we have, and don't always entirely match reality.

- -

The most thorough real world test (other than a large interactive -userbase) is using toybox as the command line in a build system such as -Aboriginal -Linux, having it rebuild itself from source code, and using the result -to build Linux From Scratch. -The current "minimal native development system" goal is to use -mkroot -plus musl-cross-make to hermetically build -AOSP.

- -

We've also checked what commands were provided by similar projects -(klibc, sash, sbase, embutils, -nash, and beastiebox), looked at various vendor configurations of busybox, -and collected end user requests.

- -

Finally, we'd like to provide a good replacement for the Bash shell, -which was the first program Linux ever ran and remains the standard shell -of Linux (no matter what Ubuntu says). This doesn't necessarily mean including -every last Bash 5.x feature, but does involve {various,features} <(beyond) -posix.

- -

See the status page for the categorized command list -and progress towards implementing it. There's also a -historical todo list from the project's 2011 relaunch.

-

Use case: standards compliance.

@@ -70,79 +51,48 @@ and progress towards implementing it. There's also a

The best standards describe reality rather than attempting to impose a new one. A good standard should document, not legislate. Standards which document existing reality tend to be approved by -more than one standards body, such ANSI and ISO both approving C99. That's why IEEE 1003.1-2008, -the Single Unix Specification version 4, and the Open Group Base Specification -edition 7 are all the same standard from three sources, but most people just -call it "posix" (portable operating system derived from unix). -It's available online in full, and may be downloaded as a tarball. -Previous versions (SUSv3 and -SUSv2) -are also available. -(Note: -Posix -2008 was reissued in 2013 and 2018, the first was minor wordsmithing -with no behavioral changes, the second was to renew a ten year timeout -to still be considered a "current standard" by some government regulations. -It's still posix-2008/SUSv4/issue 7.)

- -

Why not just use posix for everything?

- -

Unfortunately, Posix describes an incomplete subset of reality, because -it was designed to. It started with proprietary unix vendors collaborating to -describe the functionality their fragmented APIs could agree on, which was then -incorporated into US federal procurement standards -as a compliance requirement -for things like navy contracts, giving large corporations -like IBM and Microsoft millions of dollars of incentive -to punch holes in the standard big enough to drive -Windows NT and -OS/360 through. -When open source projects like Linux started developing on the internet -(enabled by the 1993 relaxation of the National Science Foundation's -"Acceptable Use Policy" allowing everyone to connect to the internet, -previously restricted to approved government/military/university organizations), -Posix ignored -the upstarts and Linux eventually -returned the favor, -leaving Posix behind.

- -

The result is a "standard" that lacks any mention of commands like -"init" or "mount" required to actually boot a system. -It describes logname but not login. It provides ipcrm +more than one standards body, such ANSI and ISO both approving C. That's why +the IEEE POSIX committee's 2008 standard, the Single Unix Specification version +4, and the Open Group Base Specification edition 7 are all the same standard +from three sources, but most people just call it "posix" (portable operating +system derived from unix). It's available online in full, and may be downloaded as a tarball.

+ +

Problems with the standard

+ +

Unfortunately posix describes an incomplete subset of reality, +lacking any mention of commands such as init or mount required to +actually boot a system. It describes logname but not login. It provides ipcrm and ipcs, but not ipcmk, so you can use System V IPC resources but not create them. And widely used real-world commands such as tar and cpio (the basis of initramfs and RPM) which were present in earlier versions of the standard have been removed, while obsolete commands like -cksum, compress, sccs and uucp remain with no mention of modern counterparts -like crc32/sha1sum, gzip/xz, svn/git or scp/rsync. Meanwhile posix' description -of the commands -themselves are missing dozens of features and specify silly things like ebcdic -support in dd or that wc should use %d (not %lld) for byte counts. So +cksum, sccs and uucp remain with no mention of modern counterparts like +crc32/sha1sum, svn/git or scp/rsync. Meanwhile the commands themselves +are missing dozens of features and specify silly things like ebcdic +support in dd or that wc should use %d (not %ld) for byte counts. So we have to extensively filter posix to get a useful set of recommendations.

-

Analysis

-

Starting with the -full "utilities" list, +full "utilities" list, we first remove generally obsolete -commands (compress ed ex pr uncompress uccp uustat uux), commands for the +commands (compess ed ex pr uncompress uccp uustat uux), commands for the pre-CVS "SCCS" source control system (admin delta get prs rmdel sact sccs unget val what), fortran support (asa fort77), and batch processing support (batch qalter qdel qhold qmove qmsg qrerun qrls qselect qsig qstat qsub).

Some commands are for a compiler toolchain (ar c99 cflow ctags cxref gencat -iconv lex m4 make nm strings strip tsort yacc) which is outside of toybox's -mandate and should be supplied externally. (Again, some of these may be +iconv lex m4 make nm strings strip tsort yacc), which is outside of toybox's +mandate and should be supplied externally. (Again, some of these may be revisited later, but not for toybox 1.0.)

-

Some commands are part of a command shell, and can't be implemented as +

Some commands are part of a command shell, and cannot be implemented as separate executables (alias bg cd command fc fg getopts hash jobs kill read -type ulimit umask unalias wait). These may be revisited as part of the built-in -toybox shell, but are not exported into $PATH via symlinks. (If you fork a +type ulimit umask unalias wait). These may be revisited as part of a built-in +toybox shell, but are not exported into $PATH via symlinks. (If you fork a child process and have it "cd" then exit, you've accomplished nothing.) Again, what posix provides is incomplete: a shell also needs exit, if, while, for, case, export, set, unset, trap, exec... (And for bash compatibility -function, source, declare...)

+function, source...)

A few other commands are judgement calls, providing command-line internationalization support (iconv locale localedef), System V inter-process @@ -150,11 +100,7 @@ communication (ipcrm ipcs), and cross-tty communication from the minicomputer days (talk mesg write). The "pax" utility failed to replace tar, "mailx" is a command line email client, and "lp" submits files for printing to... what -exactly? (cups?) The standard defines crontab but not crond. What is -pathchk supposed to be portable _to_? (Linux accepts 255 byte path components -with any char except NUL or / and no max length on the total path, and -EXPLICITLY -doesn't care if it's an invalid utf8 sequence.)

+exactly? (cups?) The standard defines crontab but not crond.

Removing all of that leaves the following commands, which toybox should implement:

@@ -164,7 +110,7 @@ implement:

at awk basename bc cal cat chgrp chmod chown cksum cmp comm cp csplit cut date dd df diff dirname du echo env expand expr false file find fold fuser getconf grep head id join kill link ln logger logname ls man -mkdir mkfifo more mv newgrp nice nl nohup od paste patch printf ps +mkdir mkfifo more mv newgrp nice nl nohup od paste patch pathchk printf ps pwd renice rm rmdir sed sh sleep sort split stty tabs tail tee test time touch tput tr true tty uname unexpand uniq unlink uudecode uuencode vi wc who xargs zcat @@ -175,41 +121,37 @@ who xargs zcat

One attempt to supplement POSIX towards an actual usable system was the Linux Standard Base. Unfortunately, the quality of this "standard" is -fairly low, largely due to the Free Standards Group that maintained it -being consumed by the Linux Foundation in 2007.

+fairly low.

+ +

POSIX allowed its standards process to be compromised +by leaving things out, thus allowing IBM mainframes and Windows NT to drive +a truck through the holes and declare themselves compilant. But it means what +they DID standardize tends to be respected (if sometimes obsolete).

-

Where POSIX allowed its standards process to be compromised -by leaving things out (but what -they DID standardize tends to be respected, if sometimes obsolete), -the Linux Standard Base's failure mode is different. They respond to +

The Linux Standard Base's failure mode is different, they respond to pressure by including anything their members pay them enough to promote, such as allowing Red Hat to push RPM into the standard even though all sorts of distros (Debian, Slackware, Arch, -Gentoo, Android) don't use it and never will. This means anything in the LSB is +Gentoo) don't use it and never will. This means anything in the LSB is at best a suggestion: arbitrary portions of this standard are widely ignored.

-

The community perception -seems to be that the Linux Standard Base is +

The community perception seems to be that the Linux Standard Base is the best standard money can buy, I.E. the Linux Foundation is supported by financial donations from large companies and the LSB represents the interests -of those donors regardless of technical merit. (The Linux Foundation, which +of those donors more than technical merit. (The Linux Foundation, which maintains the LSB, isn't a 501c3. It's a 501c6, the -same kind of legal entity as the Tobacco Institute and -Microsoft's -old "Don't Copy That Floppy" program.) Debian officially -washed its hands of LSB by -refusing to adopt release 5.0 in 2015, and no longer even pretends to support -it (which affect Debian derivatives like Ubuntu and Knoppix). Toybox has -stayed on 4.1 for similar reasons: a lot of historical effort went into -producing the standard before the Linux Foundation took over.

+same kind of legal entity as the Tobacco Institute and Microsoft's old +"Don't Copy That Floppy" program.) Debian officially +washed its hands of LSB when 5.0 +came out in 2015, and no longer even pretends to support it (which may affect +Debian derivatives like Ubuntu and Knoppix). Toybox hasn't moved to 5.0 for +similar reasons.

That said, Posix by itself isn't enough, and this is the next most comprehensive standards effort for Linux so far, so we salvage what we can.

-

Analysis

-

The LSB specifies a list of command line utilities:

@@ -234,9 +176,7 @@ interested in the set of LSB tools that aren't mentioned in posix.

Of these, gettext and msgfmt are internationalization, install_initd and remove_initd weren't present in Ubuntu 10.04, lpr is out of scope, -lsb_release just reports information in /etc/os-release, and sendmail's -turned into a pile of cryptographic verification and DNS shenanigans due -to spammers.

+and lsb_release just reports information in /etc/os-release.

This leaves:

@@ -244,43 +184,11 @@ to spammers.

chfn chsh dmesg egrep fgrep groupadd groupdel groupmod groups gunzip gzip hostname install killall md5sum -mknod mktemp mount passwd pidof seq shutdown +mknod mktemp mount passwd pidof sendmail seq shutdown su sync tar umount useradd userdel usermod zcat -

IETF RFCs and Man Pages

- -

They're very nice, but there's thousands of them.

- -

Discussion of standards wouldn't be complete without the Internet -Engineering Task Force's "Request For Comments" collection and Michael Kerrisk's -Linux man-pages project. -Except these aren't standards, they're collections of documentation with -low barriers to inclusion. They're not saying "you should support -X", they're saying "if you do, here's how". -Thus neither really helps us select which commands to include.

- -

The man pages website includes the commands in git, yum, perf, postgres, -flatpack... Great for examining the features of a command you've -already decided to include, useless for deciding _what_ to include.

- -

The RFCs are more about protocols than commands. The noise level is -extremely high: there's thousands of RFCs, many describing a proposed idea -that never took off, and less than 1% of the resulting documents are -currently relevant to toybox. And the documents are numbered based on the -order they were received, with no real attempt at coherently indexing -the result. As with man pages they can be long and complicated or -terse and impenetrable, -have developed a certain amount of bureaucracy over the years, and often the easiest way to understand what -they document is to find an earlier version to read first.

- -

That said, RFC documents can be useful (especially for networking protocols) -and the four URL templates the recommended starting files -for new commands (toys/example/skeleton.c or toys/example/hello.c depending on how much -plumbing you want to start with) provide point to posix, lsb, man, and -rfc pages.

-

Use case: provide a self-hosting development environment

@@ -337,7 +245,7 @@ still needs the following busybox commands for which toybox does not yet supply adequate replacements:

-awk dd diff expr fdisk ftpd gzip less route sh tr unxz vi wget xzcat +awk dd diff expr fdisk ftpd gzip less route sh sha512sum tr unxz vi wget xzcat

All of those except awk, ftpd, and less have partial implementations @@ -396,8 +304,9 @@ getevent getprop modprobe setprop start

getprop/setprop/start were in toybox and moved back because they're so tied to non-public system interfaces. modprobe shares the implementation -used in init. getevent is a board bringup tool built with a python script -that pulls all the constants from the latest kernel headers.

+used in init. getevent probably does make sense as a toybox command, but at the +moment it's built with a python script that pulls all the constants from the +latest kernel headers, which is very convenient.

Other Android /system/bin commands

@@ -435,7 +344,7 @@ binaries in /system/bin are:

for toybox, we get:

-arping blkid e2fsck dd fsck.f2fs fsck_msdos gzip ip iptables +arping blkid e2fsck dd fsck.f2fs fsck_msdos getevent gzip ip iptables ip6tables iw logwrapper make_ext4fs make_f2fs modpobe newfs_msdos ping ping6 reboot resize2fs sh ss tc tracepath tracepath6 traceroute traceroute6
@@ -520,33 +429,21 @@ and hexdump that are actually used to build.)


Use case: Tizen Core

-

A side effect of the Linux Foundation following the money to the -exclusion of all else is they "support" their donors' myriad often -contradictory pet projects with elaborate announcements and press releases. -Long ago when Nokia's Maemo merged -with Intel's Moblin to form MeeGo, there were believable statements -about unifying fragmented vendor efforts. Then MeeGo merged with -LiMo to -form Tizen, -which became a Samsung-only project (that still ships -inside televisions, -but was otherwise subsumed into Android GO).

- -

Along the way, the Tizen project expressed a desire to eliminate GPLv3 software -from its core system, and in installing toybox as +

The Tizen project has expressed a desire to eliminate GPLv3 software +from its core system, and is installing toybox as part of this process.

-

They had a fairly long list of new commands they wanted to see in toybox:

+

They have a fairly long list of new commands they'd like to see in toybox:

- -arch base64 users unexpand shred join csplit + +arch base64 users dir vdir unexpand shred join csplit hostid nproc runcon sha224sum sha256sum sha384sum sha512sum sha3sum mkfs.vfat fsck.vfat -dosfslabel uname pinky diff3 sdiff zcmp zdiff zegrep zfgrep zless zmore +dosfslabel uname stdbuf pinky diff3 sdiff zcmp zdiff zegrep zfgrep zless zmore
-

In addition, they wanted to use several commands then in pending:

+

In addition, they'd like to use several commands currently in pending:

@@ -555,108 +452,28 @@ tar diff printf wget rsync fdisk vi less tr test stty fold expr dd

Also, tizen uses a different Linux Security Module called SMACK, so -many of the SELinux options ala ls -Z needed smack alternatives in an -if/else setup. (We added lib/lsm.h to abstract this.)

- -
-

Use case: Yocto

- -

Another project the Linux Foundation is paid to appreciate is Yocto, -which was designed to fix the ongoing proprietary fragmentation problem -(now in Linux build systems instead of vendor unix forks) by being the -build system equivalent of a glue trap. While proclaiming that having the -"minimum level of standardization" contributes to a "strong ecosystem", -Yocto uses a "layered" -design where everybody who touches it is encouraged to add more and more layers -of metadata on top of what came before, until they wind up using repo just to manage -the layers (let alone their contents). But -- and this is the -important bit -- all these dispirate forks are called "yocto" and built on -top of giant piles of code the Linux Foundation can take credit for -since they filed the serial numbers off OpenEmbedded.

- -

Yocto's "core-image-minimal" target (only 3,106 build steps in the 3.3 -release, which believe it or not is -an improvement) builds a busybox-based system with the following commands:

- -
- -addgroup adduser ascii sh awk base32 basename blkid bunzip2 bzcat bzip2 cat -chattr chgrp chmod chown chroot chvt clear cmp cp cpio crc32 cut date dc dd -deallocvt delgroup deluser depmod df diff dirname dmesg dnsdomainname du -dumpkmap dumpleases echo egrep env expr false fbset fdisk fgrep find flock -free fsck fstrim fuser getopt getty grep groups gunzip gzip head hexdump -hostname hwclock id ifconfig ifdown ifup insmod ip kill killall klogd less -ln loadfont loadkmap logger logname logread losetup ls lsmod lzcat md5sum -mesg microcom mkdir mkfifo mknod mkswap mktemp modprobe more mount mountpoint -mv nc netstat nohup nproc nslookup od openvt patch pgrep pidof pivot_root -printf ps pwd rdate readlink realpath reboot renice reset resize rev rfkill -rm rmdir rmmod route run-parts sed seq setconsole setsid sh sha1sum sha256sum -shuf sleep sort start-stop-daemon stat strings stty sulogin swapoff swapon -switch_root sync sysctl syslogd tail tar tee telnet test tftp time top touch -tr true ts tty udhcpc udhcpd umount uname uniq unlink unzip uptime users -usleep vi watch wc wget which who whoami xargs xzcat yes zcat - -
- - - - -
Filesystem Hierachy Standard -

Filesystem Hierarchy Standard:

- -

Another standard taken over by the Linux Foundation. (At least the -links to this one didn't go 404 the -instant they took it over). Of historical interest due to what it -managed to achieve before they chased away the hobbyists maintaining it. -Only one version (3.0 in 2015) has been released since the Linux Foundation -absorbed the FHS. The previous release, Version 2.3, was released in 2004. -The Linux Foundation did not retain earlier versions. The contents of -the relevant sections appear identical between the two versions, the -Linux Foundation just added section numbers.

- -

FHS 3.0 -section 3.4.2 requires commands to be in the /bin directory, and then 3.4.3 -has an optional list, -and then 3.16.2 and 3.16.3 similarly cover /sbin. There are linux -specific sections in 6.1.2 and 6.1.6 but everything in them is obsolete.

- -

The /bin options include csh but not bash, and ed but not vi. -The /sbin options have update which seems obsolete (filesystem -buffers haven't needed a userspace process to flush them for DECADES), -fastboot and fasthalt (reboot and halt have -nf), and -fsck.* and mkfs.* that don't actually specify any specific filesystems. -Removing that gives us:

- -
- -cat chgrp chmod chown cp date dd df dmesg echo false hostname kill ln -login ls mkdir mknod more mount mv ps pwd rm rmdir sed sh stty su sync true -umount uname tar cpio gzip gunzip zcat netstat ping -shutdown fdisk getty halt ifconfig init mkswap reboot route swapon swapoff - -
+many of the SELinux options ala ls -Z need smack alternatives in an +if/else setup.


buildroot:

-

If a toybox-based development environment is to support running -buildroot under it, the mandatory packages +

The mandatory packages section of the buildroot manual lists:

-

+

which sed make bash patch gzip bzip2 tar cpio unzip rsync file bc wget -

+

(It also lists binutils gcc g++ perl python, and for debian it wants build-essential. And it wants file to be in /usr/bin because libtool breaks otherwise.)

-

Oddly, buildroot can't NOT cross compile. Buildroot does not support a cross toolchain that lives in "/usr/bin" +

Buildroot does not support a cross toolchain that lives in "/usr/bin" with a prefix of "" (if you try, and chop out the test for a blank prefix, -it dies trying to run "/usr/bin/-gcc"). You can patch your way to -making it work if you try, but buildroot's developers explicitly do not -support this.

+it dies trying to run "/usr/bin/-gcc"). But you can patch your way to +making it work if you try.


klibc:

@@ -668,7 +485,7 @@ and nobody's quite sure if the license is BSD or GPL. It inexplicably
requires perl to build, and seems like an ideal candidate for replacement.

-

In addition to a C library less general-purpose than bionic (let alone +

In addition to a C library even less capable than bionic (obsoleted by musl), klibc builds a random assortment of executables to run init scripts with. There's no multiplexer command, these are individual executables:

@@ -691,20 +508,26 @@ which removes mknodes, mksyntax, sha1hash, and fixdep from the list. (And sha1hash is just an unpolished sha1sum anyway.)

The run-init command is more commonly called switch_root, nuke is just -"rm -rf -- $@", and minips is more commonly called "ps": I'm not doing aliases -for these oddball names. -The "kinit" command is another gratuitous rename, it's init running as PID 1. -The halt, poweroff, and reboot commands work with it.

+"rm -rf -- $@", and minips is more commonly called "ps". I'm not doing aliases +for the oddball names.

-

Yet more stale forks of dash and gzip got sucked in here (see "dubious -license terms" above). +

Yet more stale forks of dash and gzip sucked in here (see "dubious +license terms" above), adding nothing to the other projects we've looked at. +But we still need sh, gunzip, gzip, and zcat to replace this package.

-

In theory "blkid" or "file" handle fstype (and df for mounted filesystems), -but we could do fstype.

+

At the time I did the initial analysis toybox already had cat, chroot, dmesg, false, +kill, ln, losetup, ls, mkdir, mkfifo, readlink, rm, switch_root, sleep, sync, +true, and uname.

-

We should implement nfsmount, and probably smbmount -and p9mount even though this hasn't got one. The reason these aren't -in the base "mount" command is they interactively query login credentials.

+

The low hanging fruit is cpio, dd, ps, mv, and pivot_root.

+ +

The "kinit" command is another gratuitous rename, it's init running as PID 1. +The halt, poweroff, and reboot commands work with it.

+ +

I've got mount and umount queued up already, fstype and nfsmount go with +those. (And probably smbmount and p9mount, but this hasn't got one. Those +are all about querying for login credentials, probably workable into the +base mount command.)

The ipconfig command here has a built in dhcp client, so it's ifconfig and dhcpcd and maybe some other stuff.

@@ -718,12 +541,12 @@ still parses "resume=" on the command line). And yet various distros seem to make use of klibc for this. Given the history of swsusp/hibernate (and TuxOnIce -and kexec jump...) I've lost track +and kexec jump) I've lost track of the current state of the art here. Ah, Documentation/power/userland-swsusp.txt has the API docs, and here's a better tool...

-

This gives us a klibc command list:

+

So the list of things actually in klibc are:

@@ -750,26 +573,29 @@ catchsegv getconf getent iconv iconvconfig ldconfig ldd locale localedef mtrace nscd rpcent rpcinfo tzselect zdump zic
-

Of those, musl libc only implements ldd. Of the rest:

+

Of those, musl libc only implements ldd.

-
    -
  • catchsegv is a rudimentary debugger, probably out of scope for toybox.
  • -
  • iconv has been previously discussed.
  • -
  • iconvconfig is only relevant if iconv is user-configurable; musl uses a -non-configurable iconv.
  • -
  • getconf is a posix utility which displays several variables from -unistd.h; it probably belongs in the development toolchain.
  • -
  • getent handles retrieving entries from passwd-style databases -(in a rather lame way) and is trivially replacable by grep.
  • -
  • locale was discussed under posix. -localedef compiles locale definitions, which musl currently does not use.
  • -
  • mtrace is a perl script to use the malloc debugging that glibc has built-in; -this is not relevant for musl, and would necessarily vary with libc.
  • -
  • nscd is a name service caching daemon, which is not yet relevant for musl.
  • -
  • rpcinfo and rpcent are related to the Remote Procedure Calls -layer (an old sun technology used by some userspace NFS implementations), -which musl does not include and debian does not install by default.
  • -
+

catchsegv is a rudimentary debugger, probably out of scope for toybox.

+ +

iconv has been previously discussed.

+ +

iconvconfig is only relevant if iconv is user-configurable; musl uses a +non-configurable iconv.

+ +

getconf is a posix utility which displays several variables from +unistd.h; it probably belongs in the development toolchain.

+ +

getent handles retrieving entries from passwd-style databases +(in a rather lame way) and is trivially replacable by grep.

+ +

locale was discussed under posix. +localedef compiles locale definitions, which musl currently does not use.

+ +

mtrace is a perl script to use the malloc debugging that glibc has built-in; +this is not relevant for musl, and would necessarily vary with libc.

+ +

nscd is a name service caching daemon, which is not yet relevant for musl. +rpcinfo and rpcent are related to rpc, which musl does not include.

The remaining commands involve glibc's bundled timezone database, which seems to be derived from the IANA @@ -777,17 +603,14 @@ timezone database. Unless we want to maintain our own fork of the standards body's database like glibc does, these are of no interest, but for completeness:

-
    -
  • tzselect outputs a TZ variable correponding to user input. +

    tzselect outputs a TZ variable correponding to user input. The documentation does not indicate how to use it in a script, but it seems -that Debian may have done so.

  • -
  • zdump prints current time in each of several timezones, optionally -outputting a great deal of extra information about each timezone.
  • -
  • zic converts a description of a timezone to a file in tz format.
  • -
+that Debian may have done so. +zdump prints current time in each of several timezones, optionally +outputting a great deal of extra information about each timezone. +zic converts a description of a timezone to a file in tz format.

-

We implemented getconf, and I could see maybe arguing for ncsd. -The rest are not relevant to toybox.

+

None of glibc's bundled commands are currently of interest to toybox.

@@ -827,7 +650,7 @@ ln, ls, mkdir, mknod, printenv, pwd, rm, rmdir, sync, and touch.

ar chattr dd ed file find grep gunzip gzip lsattr more mount mv pivot_root -sh tar umount +sh sum tar umount
@@ -846,7 +669,7 @@ consistency, and yanking "sponge", "mesg", "pagesize", "respawn", and

-basename cal cat chgrp chmod chown chroot cksum cmp comm cp crond cut date +basename cal cat chgrp chmod chown chroot cksum cmp cols comm cp crond cut date dirname du echo env expand expr false find flock fold getconf grep head hostname join kill link ln logger logname ls md5sum mkdir mkfifo mktemp mv nice nl nohup od paste printenv printf pwd readlink renice rm rmdir sed seq @@ -1216,7 +1039,7 @@ by various users. I _really_ need to clean up this section.

dig freeramdisk getty halt hexdump hwclock klogd modprobe ping ping6 pivot_root poweroff readahead rev sfdisk sudo syslogd taskset telnet telnetd tracepath traceroute unzip usleep vconfig zip free login modinfo unshare netcat help w -iwconfig iwlist rdate +ntpd iwconfig iwlist rdate dos2unix unix2dos catv clear pmap realpath setsid timeout truncate mkswap swapon swapoff @@ -1227,7 +1050,7 @@ arp makedevs sysctl killall5 crond crontab deluser last mkpasswd watch blockdev rpm2cpio arping brctl dumpleases fsck tcpsvd tftpd factor fallocate fsfreeze inotifyd lspci nbd-client partprobe strings -base32 base64 mix +base64 mix reset hexedit nsenter shred fsync insmod ionice lsmod lsusb rmmod vmstat xxd top iotop lsof ionice compress dhcp dhcpd addgroup delgroup host iconv ip @@ -1236,207 +1059,7 @@ deallocvt iorenice udpsvd adduser microcom tunctl chrt getfattr setfattr kexec -ascii crc32 devmem fmt i2cdetect i2cdump i2cget i2cset mcookie prlimit sntp ulimit uuidgen dhcp6 ipaddr iplink iproute iprule iptunnel cd exit toysh bash traceroute6 -blkdiscard rtcwake -watchdog -pwgen readelf unicode -rsync -linux32 hd strace
-
- -

Other packages

- -

System administrators have asked what other Linux packages toybox commands -replace, so they can annotate alternatives in their package management system.

- -

This section uses the package definitions from Chapter 6 of -Linux From Scratch 9.0). Each package lists what we currently -replace, pending commands [in square brackets], and what we DON'T plan to -implement.

- -

Each "see also" note means the listed package also installs the listed shared -libraries. (While toybox contains equivalent functionality to a lot of these -shared libraries in its lib/ directory, it does not currently provide a shared -library interface.)

- -

Packages toybox plans to provide complete-ish replacents for:

-
    -
  • file: file (see also: libmagic)
  • -
  • m4: [m4]
  • -
  • bc: [bc] [dc]
  • -
  • bison: [yacc] (not: bison, see also: liby)
  • -
  • flex: [lex] (not: flex flex++, see also: libfl)
  • -
  • make: [make]
  • -
  • sed: sed
  • -
  • grep: grep egrep fgrep
  • -
  • bash: bash sh (not: bashbug)
  • -
  • diffutils: cmp [diff] [diff3] [sdiff]
  • -
  • gawk: [awk] (not: gawk gawk-5.0.1)
  • -
  • findutils: find xargs (not: locate updatedb)
  • -
  • less: less (not: lessecho lesskey)
  • -
  • gzip: zcat [gzip] [gunzip] [zcmp] [zdiff] [zegrep] [zfgrep] [zgrep] [zless] [zmore] -(not: gzexe uncompress zforce znew)
  • -
  • make: [make]
  • -
  • patch: patch
  • -
  • tar: tar
  • -
  • procps-ng: free pgrep pidof pkill ps sysctl top uptime vmstat w watch -[pmap] [pwdx] [slabtop] -(not: tload, see also libprocps)
  • -
  • sysklogd: [klogd] [syslogd]
  • -
  • sysvinit: [init] halt poweroff reboot killall5 [shutdown] -(not telinit runlevel fstab-decode bootlogd)
  • -
  • man: man (but not accessdb apropos catman lexgrog mandb manpath whatis, -see also libman libmandb)
  • -
  • vim: vi xxd (but not ex, rview, rvim, view, vim, vimdiff, vimtutor)
  • -
  • sysvinit: [init] halt poweroff reboot killall5 [shutdown] -(not telinit runlevel fstab-decode bootlogd)
  • -
  • kmod: insmod lsmod rmmod modinfo [modprobe] -(not: depmod kmod)
  • -
  • attr: [getfattr] setfattr (not: attr, see also: libattr)
  • -
  • shadow: [chfn] [chpasswd] [chsh] [groupadd] [groupdel] [groupmod] -[newusers] passwd [su] [useradd] [userdel] [usermod] -[lastlog] [login] [newgidmap] [newuidmap] -(not: chage expiry faillog groupmems grpck logoutd newgrp nologin pwck sg -vigr vipw, grpconv grpunconv pwconv pwunconv, chgpasswd gpasswd)
  • -
  • psmisc: killall [fuser] [pstree] [peekfd] [prtstat] -(not: pslog pstree.x11)
  • -
  • inetutils: dnsdomainname [ftp] hostname ifconfig ping ping6 [telnet] [tftp] [traceroute] (not: talk)
  • -
  • coreutils: [ base32 base64 basename cat chgrp chmod chown chroot cksum comm cp cut date -dd df dirname du echo env expand factor false fmt fold groups head hostid id install -link ln logname ls md5sum mkdir mkfifo mknod mktemp mv nice nl nohup nproc od -paste printenv printf pwd readlink realpath rm rmdir seq sha1sum shred -sleep sort split stat sync tac tail tee test timeout touch true truncate -tty uname uniq unlink wc who whoami yes -[expr] [fold] [join] [numfmt] [runcon] [sha224sum] [sha256sum] [sha384sum] -[sha512sum] [stty] [b2sum] [tr] [unexpand] -(not: basenc chcon csplit dir dircolors pathchk -pinky pr ptx shuf stdbuf sum tsort users vdir, see also libstdbuf)
  • -
  • util-linux: blkid blockdev cal chrt dmesg eject fallocate flock hwclock -ionice kill logger losetup mcookie mkswap more mount mountpoint nsenter -pivot_root prlimit rename renice rev setsid swapoff swapon switch_root taskset -umount unshare uuidgen -[addpart] [fdisk] [findfs] [findmnt] [fsck] [fsfreeze] [fstrim] [getopt] -[hexdump] [linux32] [linux64] [lsblk] [lscpu] [lsns] [setarch] -(not: agetty blkdiscard blkzone cfdisk chcpu chmem choom col -colcrt colrm column ctrlaltdel delpart fdformat fincore fsck.cramfs -fsck.minix ipcmk ipcrm ipcs isosize last lastb ldattach look lsipc -lslocks lslogins lsmem mesg mkfs mkfs.bfs mkfs.cramfs mkfs.minix namei partx -raw readprofile resizepart rfkill rtcwake script scriptreplay -setterm sfdisk sulogin swaplabel ul -uname26 utmpdump uuidd uuidparse wall wdctl whereis wipefs -i386 x86_64 zramctl)
  • -
- -

Commentary: toybox init doesn't do runlevels, man and vim are just the -relevant commands without the piles of strange overgrowth, and if you want -to call a toybox binary by another name you can create a symlink to a -symlink. If somebody really wants to argue for "gzexe" or similar, be -my guest, but there's a lot of obsolete crap in shadow, coreutils, -util-linux...

- -

No idea why LFS is installing inetutils instead of net-tools -(which contains arp route ifconfig mii-tool nameif netstat and rarp that -toybox does or might implement, and plipconfig slattach that it probably won't.)

- -

Packages toybox plans to provide partial replacents for:

- -

Toybox provides replacements for some binaries from these packages, -but there are other useful binaries which this package provides that toybox -currently considers out of scope for the project:

- -
    -
  • binutils: strings [ar] [nm] [readelf] [size] [objcopy] [strip] -(not c++filt, dwp, elfedit, gprof. The following commands belong -in qcc: addr2line as ld objdump ranlib)
  • -
  • bzip2: bunzip2 bzcat [bzcmp] [bzdiff] [bzegrep] [bzfgrep] [bzgrep] [bzless] -[bzmore] (not: bzip2, bzip2recover, see also libbz2)
  • -
  • xz: [xzcat] [lzcat] [lzcmp] [lzdiff] [lzegrep] [lzfgrep] [lzgrep] -[lzless] [lzmadec, lzmainfo] [lzmore] [unlzma] [unxz] [xzcat] -[xzcmp] [xzdec] [xzdiff] [xzegrep] [xzfgrep] [xzgrep] [xzless] [xzmore] -(not: compression side, see also: liblzma)
  • -
  • ncurses: clear reset (not: everything else, see also: libcurses)
  • -
  • e2fsprogs: chattr lsattr [e2fsck] [mkfs.ext2] [mkfs.ext3] -[fsck.ext2] [fsck.ext3] [e2label] [resize2fs] [tune2fs] -(not badblocks compile_et debugfs dumpe2fse2freefrag e2image -e2mmpstatus e2scrub e2scrub_all e2undo e4crypt e4defrag filefrag -fsck.ext4 logsave mk_cmds mkfs.ext4 mklost+found)
  • -
- -

Toybox provides several decompressors but compresses to a single format -(deflate, ala gzip/zlib). Our e2fsprogs doesn't currently plan to support -ext4 or defrag. The "qcc" reference is because someday an external project to glue -QEMU's Tiny Code Generator -to Fabrice Bellard's old Tiny C Compiler -making a multicall binary that does cc/ld/as for all the targets QEMU -supports (then use the -LLVM C Backend -to compile LLVM itself to C for use as a modern replacement for -cfront to bootstrap -C++ code) is under consideration -as a successor project to toybox. Until then things like objdump -d -(requiring target-specific disassembly for an unbounded number of architectures) -are out of scope for toybox. (This means drawing the line somewhere between -architecture-specific support in file and strace, and including a full -assembler for each architecture.)

- - -

Packages from LFS ch6 toybox does NOT plan to replace:

- -
    -
  • linux-api-headers
  • -
  • man-pages glibc
  • -
  • zlib
  • -
  • readline
  • -
  • gmp
  • -
  • mpfr
  • -
  • mpc
  • -
  • gcc
  • -
  • pkg-config
  • -
  • ncurses
  • -
  • acl
  • -
  • libcap
  • -
  • psmisc
  • -
  • iana-etc
  • -
  • libtool
  • -
  • gdbm
  • -
  • gperf
  • -
  • expat
  • -
  • perl
  • -
  • XML::Parser
  • -
  • intltool
  • -
  • autoconf
  • -
  • automake
  • -
  • gettext
  • -
  • libelf
  • -
  • libffi
  • -
  • openssl
  • -
  • python
  • -
  • ninja
  • -
  • meson
  • -
  • check
  • -
  • groff
  • -
  • grub
  • -
  • libpipeline
  • -
  • texinfo
  • -
- -

That said, we do implement our own zlib and readline replacements, and -presumably _could_ export them as library bindings. Plus we provide -our own version of a bunch of the section 1 man pages (as command help). -Possibly libcap and acl are interesting?

- -

Misc

- -

The kbd package has over a dozen commands, we only implement chvt. The -iproute2 package implements over a dozen commands, there's an "ip" in -pending but I'm not a fan (ifconfig and route and such should be extended -to work properly). We don't implement eudev, but toybox's maintainer -created busybox mdev way back when (which replaces it) and plans to do a -new one for toybox as soon as we work out what subset is still needed now that -devtmpfs is available.

- - -- Gitee