diff --git a/.gitignore b/.gitignore index 625c162..2b74ad1 100644 --- a/.gitignore +++ b/.gitignore @@ -1,17 +1,10 @@ syntax: glob -/.config.old -.single* -change/ -/generated/build.sh -/generated/cflags -/generated/config2help -/generated/Config.in -/generated/Config.probed -/generated/flags.raw -/generated/mkflags -/generated/mktags -/generated/obj -/generated/optlibs.dat -/kconfig -toybox -toybox_unstripped +/.config* +/.single* +/change/ +/generated/ +/kconfig/mconf +/kconfig/conf +/kconfig/*.c +/toybox +/toybox_unstripped diff --git a/kconfig/android_miniconfig b/kconfig/android_miniconfig new file mode 100644 index 0000000..4428a2b --- /dev/null +++ b/kconfig/android_miniconfig @@ -0,0 +1,198 @@ +CONFIG_BASENAME=y +CONFIG_CAL=y +CONFIG_CAT=y +CONFIG_CHGRP=y +CONFIG_CHOWN=y +CONFIG_CHMOD=y +CONFIG_CKSUM=y +CONFIG_CMP=y +CONFIG_COMM=y +CONFIG_CP=y +CONFIG_MV=y +CONFIG_INSTALL=y +CONFIG_CPIO=y +CONFIG_CUT=y +CONFIG_DATE=y +CONFIG_DF=y +CONFIG_DIRNAME=y +CONFIG_DU=y +CONFIG_ECHO=y +CONFIG_ENV=y +CONFIG_EXPAND=y +CONFIG_FALSE=y +CONFIG_FILE=y +CONFIG_FIND=y +CONFIG_GETCONF=y +CONFIG_GREP=y +CONFIG_HEAD=y +CONFIG_ICONV=y +CONFIG_ID=y +CONFIG_GROUPS=y +CONFIG_LOGNAME=y +CONFIG_WHOAMI=y +CONFIG_KILL=y +CONFIG_LN=y +CONFIG_LS=y +CONFIG_MKDIR=y +CONFIG_MKFIFO=y +CONFIG_NICE=y +CONFIG_NL=y +CONFIG_NOHUP=y +CONFIG_OD=y +CONFIG_PASTE=y +CONFIG_PATCH=y +CONFIG_PRINTF=y +CONFIG_PS=y +CONFIG_TOP=y +CONFIG_IOTOP=y +CONFIG_PGREP=y +CONFIG_PKILL=y +CONFIG_PWD=y +CONFIG_RENICE=y +CONFIG_RM=y +CONFIG_RMDIR=y +CONFIG_SED=y +CONFIG_SLEEP=y +CONFIG_SORT=y +CONFIG_SPLIT=y +CONFIG_STRINGS=y +CONFIG_TAIL=y +CONFIG_TAR=y +CONFIG_TEE=y +CONFIG_TEST=y +CONFIG_TIME=y +CONFIG_TOUCH=y +CONFIG_TRUE=y +CONFIG_TTY=y +CONFIG_ULIMIT=y +CONFIG_UNAME=y +CONFIG_UNIQ=y +CONFIG_UNLINK=y +CONFIG_UUDECODE=y +CONFIG_UUENCODE=y +CONFIG_WC=y +CONFIG_XARGS=y +CONFIG_DD=y +CONFIG_DIFF=y +CONFIG_EXPR=y +CONFIG_GETFATTR=y +CONFIG_GETOPT=y +CONFIG_LSOF=y +CONFIG_MODPROBE=y +CONFIG_MORE=y +CONFIG_STTY=y +CONFIG_TR=y +CONFIG_TRACEROUTE=y +CONFIG_VI=y +CONFIG_ACPI=y +CONFIG_BASE64=y +CONFIG_BLKDISCARD=y +CONFIG_BLKID=y +CONFIG_BLOCKDEV=y +CONFIG_CHCON=y +CONFIG_CHROOT=y +CONFIG_CHRT=y +CONFIG_CLEAR=y +CONFIG_DEVMEM=y +CONFIG_DOS2UNIX=y +CONFIG_UNIX2DOS=y +CONFIG_FALLOCATE=y +CONFIG_FLOCK=y +CONFIG_FMT=y +CONFIG_FREE=y +CONFIG_FREERAMDISK=y +CONFIG_FSFREEZE=y +CONFIG_FSYNC=y +CONFIG_HELP=y +CONFIG_HWCLOCK=y +CONFIG_I2CDETECT=y +CONFIG_I2CDUMP=y +CONFIG_I2CGET=y +CONFIG_I2CSET=y +CONFIG_INOTIFYD=y +CONFIG_INSMOD=y +CONFIG_IONICE=y +CONFIG_IORENICE=y +CONFIG_LOSETUP=y +CONFIG_LSATTR=y +CONFIG_CHATTR=y +CONFIG_LSMOD=y +CONFIG_LSPCI=y +CONFIG_LSUSB=y +CONFIG_MAKEDEVS=y +CONFIG_MKSWAP=y +CONFIG_MODINFO=y +CONFIG_MOUNTPOINT=y +CONFIG_NBD_CLIENT=y +CONFIG_UNSHARE=y +CONFIG_NSENTER=y +CONFIG_PARTPROBE=y +CONFIG_PIVOT_ROOT=y +CONFIG_PMAP=y +CONFIG_PRINTENV=y +CONFIG_PWDX=y +CONFIG_READELF=y +CONFIG_READLINK=y +CONFIG_REALPATH=y +CONFIG_REV=y +CONFIG_RMMOD=y +CONFIG_RTCWAKE=y +CONFIG_SETFATTR=y +CONFIG_SETSID=y +CONFIG_STAT=y +CONFIG_SWAPOFF=y +CONFIG_SWAPON=y +CONFIG_SYSCTL=y +CONFIG_TAC=y +CONFIG_NPROC=y +CONFIG_TASKSET=y +CONFIG_TIMEOUT=y +CONFIG_TRUNCATE=y +CONFIG_UCLAMPSET=y +CONFIG_UPTIME=y +CONFIG_USLEEP=y +CONFIG_UUIDGEN=y +CONFIG_VCONFIG=y +CONFIG_VMSTAT=y +CONFIG_WATCH=y +CONFIG_WHICH=y +CONFIG_XXD=y +CONFIG_YES=y +CONFIG_IFCONFIG=y +CONFIG_MICROCOM=y +CONFIG_NETCAT=y +CONFIG_NETSTAT=y +CONFIG_PING=y +CONFIG_RFKILL=y +CONFIG_TUNCTL=y +CONFIG_DMESG=y +CONFIG_GZIP=y +CONFIG_GUNZIP=y +CONFIG_ZCAT=y +CONFIG_HOSTNAME=y +CONFIG_KILLALL=y +CONFIG_MD5SUM=y +CONFIG_SHA1SUM=y +CONFIG_SHA224SUM=y +CONFIG_SHA256SUM=y +CONFIG_SHA384SUM=y +CONFIG_SHA512SUM=y +CONFIG_MKNOD=y +CONFIG_MKTEMP=y +CONFIG_MOUNT=y +CONFIG_PIDOF=y +CONFIG_SEQ=y +CONFIG_SYNC=y +CONFIG_UMOUNT=y +CONFIG_GETENFORCE=y +CONFIG_LOAD_POLICY=y +CONFIG_RESTORECON=y +CONFIG_RUNCON=y +CONFIG_SETENFORCE=y +CONFIG_TOYBOX_SELINUX=y +CONFIG_TOYBOX_LIBCRYPTO=y +CONFIG_TOYBOX_LIBZ=y +CONFIG_TOYBOX_FLOAT=y +CONFIG_TOYBOX_HELP=y +CONFIG_TOYBOX_HELP_DASHDASH=y +CONFIG_TOYBOX_NORECURSE=y diff --git a/kconfig/kconfig-language.txt b/kconfig/kconfig-language.txt new file mode 100644 index 0000000..d821369 --- /dev/null +++ b/kconfig/kconfig-language.txt @@ -0,0 +1,284 @@ +Linux 2.6.12 Documentation/kbuild/kconfig-language.txt + +Introduction +------------ + +The configuration database is collection of configuration options +organized in a tree structure: + + +- Code maturity level options + | +- Prompt for development and/or incomplete code/drivers + +- General setup + | +- Networking support + | +- System V IPC + | +- BSD Process Accounting + | +- Sysctl support + +- Loadable module support + | +- Enable loadable module support + | +- Set version information on all module symbols + | +- Kernel module loader + +- ... + +Every entry has its own dependencies. These dependencies are used +to determine the visibility of an entry. Any child entry is only +visible if its parent entry is also visible. + +Menu entries +------------ + +Most entries define a config option, all other entries help to organize +them. A single configuration option is defined like this: + +config MODVERSIONS + bool "Set version information on all module symbols" + depends MODULES + help + Usually, modules have to be recompiled whenever you switch to a new + kernel. ... + +Every line starts with a key word and can be followed by multiple +arguments. "config" starts a new config entry. The following lines +define attributes for this config option. Attributes can be the type of +the config option, input prompt, dependencies, help text and default +values. A config option can be defined multiple times with the same +name, but every definition can have only a single input prompt and the +type must not conflict. + +Menu attributes +--------------- + +A menu entry can have a number of attributes. Not all of them are +applicable everywhere (see syntax). + +- type definition: "bool"/"tristate"/"string"/"hex"/"int" + Every config option must have a type. There are only two basic types: + tristate and string, the other types are based on these two. The type + definition optionally accepts an input prompt, so these two examples + are equivalent: + + bool "Networking support" + and + bool + prompt "Networking support" + +- input prompt: "prompt" ["if" ] + Every menu entry can have at most one prompt, which is used to display + to the user. Optionally dependencies only for this prompt can be added + with "if". + +- default value: "default" ["if" ] + A config option can have any number of default values. If multiple + default values are visible, only the first defined one is active. + Default values are not limited to the menu entry, where they are + defined, this means the default can be defined somewhere else or be + overridden by an earlier definition. + The default value is only assigned to the config symbol if no other + value was set by the user (via the input prompt above). If an input + prompt is visible the default value is presented to the user and can + be overridden by him. + Optionally dependencies only for this default value can be added with + "if". + +- dependencies: "depends on"/"requires" + This defines a dependency for this menu entry. If multiple + dependencies are defined they are connected with '&&'. Dependencies + are applied to all other options within this menu entry (which also + accept an "if" expression), so these two examples are equivalent: + + bool "foo" if BAR + default y if BAR + and + depends on BAR + bool "foo" + default y + +- reverse dependencies: "select" ["if" ] + While normal dependencies reduce the upper limit of a symbol (see + below), reverse dependencies can be used to force a lower limit of + another symbol. The value of the current menu symbol is used as the + minimal value can be set to. If is selected multiple + times, the limit is set to the largest selection. + Reverse dependencies can only be used with boolean or tristate + symbols. + +- numerical ranges: "range" ["if" ] + This allows to limit the range of possible input values for int + and hex symbols. The user can only input a value which is larger than + or equal to the first symbol and smaller than or equal to the second + symbol. + +- help text: "help" or "---help---" + This defines a help text. The end of the help text is determined by + the indentation level, this means it ends at the first line which has + a smaller indentation than the first line of the help text. + "---help---" and "help" do not differ in behaviour, "---help---" is + used to help visually seperate configuration logic from help within + the file as an aid to developers. + + +Menu dependencies +----------------- + +Dependencies define the visibility of a menu entry and can also reduce +the input range of tristate symbols. The tristate logic used in the +expressions uses one more state than normal boolean logic to express the +module state. Dependency expressions have the following syntax: + + ::= (1) + '=' (2) + '!=' (3) + '(' ')' (4) + '!' (5) + '&&' (6) + '||' (7) + +Expressions are listed in decreasing order of precedence. + +(1) Convert the symbol into an expression. Boolean and tristate symbols + are simply converted into the respective expression values. All + other symbol types result in 'n'. +(2) If the values of both symbols are equal, it returns 'y', + otherwise 'n'. +(3) If the values of both symbols are equal, it returns 'n', + otherwise 'y'. +(4) Returns the value of the expression. Used to override precedence. +(5) Returns the result of (2-/expr/). +(6) Returns the result of min(/expr/, /expr/). +(7) Returns the result of max(/expr/, /expr/). + +An expression can have a value of 'n', 'm' or 'y' (or 0, 1, 2 +respectively for calculations). A menu entry becomes visible when it's +expression evaluates to 'm' or 'y'. + +There are two types of symbols: constant and nonconstant symbols. +Nonconstant symbols are the most common ones and are defined with the +'config' statement. Nonconstant symbols consist entirely of alphanumeric +characters or underscores. +Constant symbols are only part of expressions. Constant symbols are +always surrounded by single or double quotes. Within the quote any +other character is allowed and the quotes can be escaped using '\'. + +Menu structure +-------------- + +The position of a menu entry in the tree is determined in two ways. First +it can be specified explicitly: + +menu "Network device support" + depends NET + +config NETDEVICES + ... + +endmenu + +All entries within the "menu" ... "endmenu" block become a submenu of +"Network device support". All subentries inherit the dependencies from +the menu entry, e.g. this means the dependency "NET" is added to the +dependency list of the config option NETDEVICES. + +The other way to generate the menu structure is done by analyzing the +dependencies. If a menu entry somehow depends on the previous entry, it +can be made a submenu of it. First, the previous (parent) symbol must +be part of the dependency list and then one of these two conditions +must be true: +- the child entry must become invisible, if the parent is set to 'n' +- the child entry must only be visible, if the parent is visible + +config MODULES + bool "Enable loadable module support" + +config MODVERSIONS + bool "Set version information on all module symbols" + depends MODULES + +comment "module support disabled" + depends !MODULES + +MODVERSIONS directly depends on MODULES, this means it's only visible if +MODULES is different from 'n'. The comment on the other hand is always +visible when MODULES is visible (the (empty) dependency of MODULES is +also part of the comment dependencies). + + +Kconfig syntax +-------------- + +The configuration file describes a series of menu entries, where every +line starts with a keyword (except help texts). The following keywords +end a menu entry: +- config +- menuconfig +- choice/endchoice +- comment +- menu/endmenu +- if/endif +- source +The first five also start the definition of a menu entry. + +config: + + "config" + + +This defines a config symbol and accepts any of above +attributes as options. + +menuconfig: + "menuconfig" + + +This is similiar to the simple config entry above, but it also gives a +hint to front ends, that all suboptions should be displayed as a +separate list of options. + +choices: + + "choice" + + + "endchoice" + +This defines a choice group and accepts any of above attributes as +options. A choice can only be of type bool or tristate, while a boolean +choice only allows a single config entry to be selected, a tristate +choice also allows any number of config entries to be set to 'm'. This +can be used if multiple drivers for a single hardware exists and only a +single driver can be compiled/loaded into the kernel, but all drivers +can be compiled as modules. +A choice accepts another option "optional", which allows to set the +choice to 'n' and no entry needs to be selected. + +comment: + + "comment" + + +This defines a comment which is displayed to the user during the +configuration process and is also echoed to the output files. The only +possible options are dependencies. + +menu: + + "menu" + + + "endmenu" + +This defines a menu block, see "Menu structure" above for more +information. The only possible options are dependencies. + +if: + + "if" + + "endif" + +This defines an if block. The dependency expression is appended +to all enclosed menu entries. + +source: + + "source" + +This reads the specified configuration file. This file is always parsed. diff --git a/lib/lib.c b/lib/lib.c index 6c7456a..142c7e3 100644 --- a/lib/lib.c +++ b/lib/lib.c @@ -1565,6 +1565,7 @@ int smemcmp(char *one, char *two, unsigned long len) return ii; } +// patch.c used // Slow, but small. char *get_line(int fd) { diff --git a/lib/lib.h b/lib/lib.h index b4a39b2..fe0cac3 100644 --- a/lib/lib.h +++ b/lib/lib.h @@ -121,7 +121,10 @@ void xputsl(char *s, int len); void xputsn(char *s); void xputs(char *s); void xputc(char c); +#ifdef TOYBOX_OH_ADAPT +// watch.c used. fix exit with abnormal char '' void xflush(int flush); +#endif void xvdaemon(void); void xexec(char **argv); pid_t xpopen_setup(char **argv, int *pipes, void (*callback)(char **argv)); @@ -442,4 +445,5 @@ pid_t __attribute__((returns_twice)) xvforkwrap(pid_t pid); #define minof(a, b) ({typeof(a) aa = (a); typeof(b) bb = (b); aabb ? aa : bb;}) +// patch.c used char *get_line(int fd); diff --git a/lib/xwrap.c b/lib/xwrap.c index a5552fc..f79ab0b 100644 --- a/lib/xwrap.c +++ b/lib/xwrap.c @@ -147,12 +147,15 @@ void xferror(FILE *fp) if (ferror(fp)) perror_exit(fp==stdout ? "stdout" : "write"); } +#ifdef TOYBOX_OH_ADAPT +// watch.c used. fix exit with abnormal char '' // if !flush just check for error on stdout without flushing void xflush(int flush) { if ((flush && fflush(0)) || ferror(stdout)) if (!toys.exitval) perror_msg("write"); } +#endif void xprintf(char *format, ...) { @@ -729,7 +732,11 @@ struct group *xgetgrgid(gid_t gid) { struct group *group = getgrgid(gid); +#ifdef TOYBOX_OH_ADAPT if (!group) perror_exit("bad gid %ld", (long)gid); +#else + if (!group) perror_exit("gid %ld", (long)gid); +#endif return group; } @@ -765,7 +772,11 @@ struct passwd *xgetpwnam(char *name) { struct passwd *up = getpwnam(name); +#ifdef TOYBOX_OH_ADAPT if (!up) perror_exit("bad user '%s'", name); +#else + if (!up) perror_exit("user '%s'", name); +#endif return up; } @@ -773,7 +784,11 @@ struct group *xgetgrnam(char *name) { struct group *gr = getgrnam(name); +#ifdef TOYBOX_OH_ADAPT if (!gr) perror_exit("bad group '%s'", name); +#else + if (!gr) perror_exit("group '%s'", name); +#endif return gr; } diff --git a/tests/sha224sum.test b/tests/sha224sum.test deleted file mode 100644 index bc02ebe..0000000 --- a/tests/sha224sum.test +++ /dev/null @@ -1 +0,0 @@ -sha1sum.test \ No newline at end of file diff --git a/tests/sha224sum.test b/tests/sha224sum.test new file mode 120000 index 0000000..bc02ebe --- /dev/null +++ b/tests/sha224sum.test @@ -0,0 +1 @@ +sha1sum.test \ No newline at end of file diff --git a/tests/sha256sum.test b/tests/sha256sum.test deleted file mode 100644 index bc02ebe..0000000 --- a/tests/sha256sum.test +++ /dev/null @@ -1 +0,0 @@ -sha1sum.test \ No newline at end of file diff --git a/tests/sha256sum.test b/tests/sha256sum.test new file mode 120000 index 0000000..bc02ebe --- /dev/null +++ b/tests/sha256sum.test @@ -0,0 +1 @@ +sha1sum.test \ No newline at end of file diff --git a/tests/sha384sum.test b/tests/sha384sum.test deleted file mode 100644 index bc02ebe..0000000 --- a/tests/sha384sum.test +++ /dev/null @@ -1 +0,0 @@ -sha1sum.test \ No newline at end of file diff --git a/tests/sha384sum.test b/tests/sha384sum.test new file mode 120000 index 0000000..bc02ebe --- /dev/null +++ b/tests/sha384sum.test @@ -0,0 +1 @@ +sha1sum.test \ No newline at end of file diff --git a/tests/sha3sum.test b/tests/sha3sum.test deleted file mode 100644 index bc02ebe..0000000 --- a/tests/sha3sum.test +++ /dev/null @@ -1 +0,0 @@ -sha1sum.test \ No newline at end of file diff --git a/tests/sha3sum.test b/tests/sha3sum.test new file mode 120000 index 0000000..bc02ebe --- /dev/null +++ b/tests/sha3sum.test @@ -0,0 +1 @@ +sha1sum.test \ No newline at end of file diff --git a/tests/sha512sum.test b/tests/sha512sum.test deleted file mode 100644 index bc02ebe..0000000 --- a/tests/sha512sum.test +++ /dev/null @@ -1 +0,0 @@ -sha1sum.test \ No newline at end of file diff --git a/tests/sha512sum.test b/tests/sha512sum.test new file mode 120000 index 0000000..bc02ebe --- /dev/null +++ b/tests/sha512sum.test @@ -0,0 +1 @@ +sha1sum.test \ No newline at end of file diff --git a/toys.h b/toys.h index e781669..ae9d34a 100644 --- a/toys.h +++ b/toys.h @@ -11,7 +11,9 @@ // General posix-2008 headers #include #include +#ifdef TOYBOX_OH_ADAPT #include +#endif #include #include #include diff --git a/toys/android/README b/toys/android/README index 5c643c5..b1b627c 100644 --- a/toys/android/README +++ b/toys/android/README @@ -3,4 +3,4 @@ Android commands Commands primarily used by Android, not present in vanilla Linux. (Mostly SELinux stuff.) -Bug Elliott Hughes about this. \ No newline at end of file +Bug Elliott Hughes about this. diff --git a/toys/example/README b/toys/example/README index 3b0deac..6e73fa1 100644 --- a/toys/example/README +++ b/toys/example/README @@ -20,4 +20,4 @@ Some of the commands in here are test infrastructure: regression test library functions directly. hostid.c is an obsolete command still in posix and present on some recent -Linux systems, but not really useful on modern systems. \ No newline at end of file +Linux systems, but not really useful on modern systems. diff --git a/toys/example/logwrapper.c b/toys/example/logwrapper.c deleted file mode 100644 index 036fcd3..0000000 --- a/toys/example/logwrapper.c +++ /dev/null @@ -1,75 +0,0 @@ -/* logwrapper.c - Record commands called out of $PATH to a log - * - * Copyright 2019 Rob Landley - * - * I made it up. Must be built standalone to work. (Is its own multiplexer.) - -USE_LOGWRAPPER(NEWTOY(logwrapper, 0, TOYFLAG_NOHELP|TOYFLAG_USR|TOYFLAG_BIN)) - -config LOGWRAPPER - bool "logwrapper" - default n - help - usage: logwrapper ... - - Append command line to $WRAPLOG, then call second instance - of command in $PATH. -*/ - -#define FOR_logwrapper -#include "toys.h" - -void logwrapper_main(void) -{ - char *log = getenv("WRAPLOG"), *omnom = basename(*toys.argv), - *s, *ss, *sss; - struct string_list *list; - int i, len; - - // Log the command line - if (!log) error_exit("no $WRAPLOG"); - len = strlen(omnom)+2; - for (i = 0; istr, *toys.argv)) break; - free(llist_pop(&list)); - } - } - - // Skip first instance and try to run next one, until out of instances. - for (;;) { - if (list) free(llist_pop(&list)); - if (!list) - error_exit("no %s after %s in $PATH=%s", omnom, - **toys.argv == '/' ? *toys.argv : "logwrapper", getenv("PATH")); - *toys.argv = list->str; - execve(list->str, toys.argv, environ); - } -} diff --git a/toys/net/README b/toys/net/README index 7a16262..49259ca 100644 --- a/toys/net/README +++ b/toys/net/README @@ -3,4 +3,4 @@ Networking commands The Internet Engineering Task Force publishes standards drafts at https://www.ietf.org/rfc/rfc-index.txt (ala https://www.ietf.org/rfc/rfc3.txt) and the commands tend to be documented in manual page section 8 -https://man7.org/linux/man-pages/dir_section_8.html \ No newline at end of file +https://man7.org/linux/man-pages/dir_section_8.html diff --git a/toys/net/netcat.c b/toys/net/netcat.c index ef94cf9..557380a 100644 --- a/toys/net/netcat.c +++ b/toys/net/netcat.c @@ -255,4 +255,4 @@ cleanup: close(in1); close(sockfd); } -} \ No newline at end of file +} diff --git a/toys/net/ping.c b/toys/net/ping.c index 3b73023..f71ab82 100644 --- a/toys/net/ping.c +++ b/toys/net/ping.c @@ -13,7 +13,7 @@ // -s > 4064 = sizeof(toybuf)-sizeof(struct icmphdr)-CMSG_SPACE(sizeof(uint8_t)), then kernel adds 20 bytes USE_PING(NEWTOY(ping, "<1>1m#t#<0>255=64c#<0=3s#<0>4064=56i%W#<0=3w#<0qf46I:[-46]", TOYFLAG_USR|TOYFLAG_BIN|TOYFLAG_LINEBUF)) USE_PING(OLDTOY(ping6, ping, TOYFLAG_USR|TOYFLAG_BIN|TOYFLAG_LINEBUF)) - + config PING bool "ping" default y @@ -40,7 +40,7 @@ config PING -w SEC Exit after this many seconds */ -#define FOR_ping +#define FOR_ping #include "toys.h" #include @@ -215,7 +215,7 @@ void ping_main(void) memset(&msg, 0, sizeof(msg)); // left enought space to store ttl value - + #ifdef TOYBOX_OH_ADAPT /* fix "ping -s 65500" fail problem*/ char *mybuff = malloc(65536); @@ -338,9 +338,7 @@ void ping_main(void) toys.exitval = 0; } - sigatexit(0); - summary(0); - + // summary(0) gets called for us atexit. if (CFG_TOYBOX_FREE) { freeaddrinfo(ai2); if (ifa2) freeifaddrs(ifa2); diff --git a/toys/other/bzcat.c b/toys/other/bzcat.c index df8bd87..c27324d 100644 --- a/toys/other/bzcat.c +++ b/toys/other/bzcat.c @@ -723,7 +723,7 @@ static void do_bunzip2(int fd, char *name) free(tmp); tmp = 0; #endif - } else { + } else if (!err) { if (dotbz) *dotbz = '.'; // unlink success return 0, fail return -1 #ifdef TOYBOX_OH_ADAPT diff --git a/toys/other/pwgen.c b/toys/other/pwgen.c index c69eef9..4980335 100644 --- a/toys/other/pwgen.c +++ b/toys/other/pwgen.c @@ -1,6 +1,6 @@ /* pwgen.c - A password generator. * - * Copyright 2020 Moritz R�hrich + * Copyright 2020 Moritz Röhrich 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)) diff --git a/toys/other/watch.c b/toys/other/watch.c index 99e817b..2399826 100644 --- a/toys/other/watch.c +++ b/toys/other/watch.c @@ -58,7 +58,7 @@ static void watch_child(int sig) static int watch_escape(FILE *out, int cols, int wc) { if (wc==27 || (wc>=7 && wc<=13)) return -1; - if (wc < 32) return 0; + if (wc<32) return 0; return crunch_escape(out, cols, wc); } @@ -106,8 +106,8 @@ void watch_main(void) // Get and measure time string, trimming gratuitous \n ctimelen = strlen(ss = ctime(&t)); if (ss[ctimelen-1]=='\n') ss[--ctimelen] = 0; - - // print cmdline, then * or ' ' (showing truncation), then ctime + + // print cmdline, then * or ' ' (showing truncation), then ctime pad = width-++ctimelen; if (pad>0) draw_trim(cmd, -pad, pad); printf("%c", pad - * Copyright 2014 Kyungwan Han + * Copyright 2014 Kyungwan Han * * No Standard - + USE_BOOTCHARTD(NEWTOY(bootchartd, 0, TOYFLAG_STAYROOT|TOYFLAG_USR|TOYFLAG_BIN)) config BOOTCHARTD @@ -157,7 +157,7 @@ static void start_logging() (int) (ts.tv_nsec/10000000)); dump_data_in_file("/proc/stat", sfd); dump_data_in_file("/proc/diskstats", dfd); - // stop proc dumping in 2 secs if getty or gdm, kdm, xdm found + // stop proc dumping in 2 secs if getty or gdm, kdm, xdm found if (dump_proc_data(proc_ps_fp)) if (tcnt > 2 * 1000 / TT.msec) tcnt = 2 * 1000 / TT.msec; fflush(0); @@ -203,7 +203,7 @@ static void stop_logging(char *tmp_dir, char *prog) close(kcmd_line_fd); fclose(hdr_fp); memset(toybuf, 0, sizeof(toybuf)); - snprintf(toybuf, sizeof(toybuf), "tar -zcf /var/log/bootlog.tgz header %s *.log", + snprintf(toybuf, sizeof(toybuf), "tar -zcf /var/log/bootlog.tgz header %s *.log", TT.proc_accounting ? "kernel_procs_acct" : ""); system(toybuf); @@ -246,7 +246,7 @@ void bootchartd_main() } } else if (TT.pid != 1) error_exit("not PID 1"); - // Execute the code below for start or init or PID1 + // Execute the code below for start or init or PID1 if (!parse_config_file("bootchartd.conf")) parse_config_file("/etc/bootchartd.conf"); @@ -256,23 +256,23 @@ void bootchartd_main() sigatexit(generic_signal); raise(SIGSTOP); - if (!bchartd_opt && !getenv("PATH")) + if (!bchartd_opt && !getenv("PATH")) putenv("PATH=/sbin:/usr/sbin:/bin:/usr/bin"); start_logging(); stop_logging(tmp_dir, bchartd_opt == 1 ? toys.optargs[1] : NULL); return; - } + } waitpid(lgr_pid, NULL, WUNTRACED); kill(lgr_pid, SIGCONT); - if (!bchartd_opt) { + if (!bchartd_opt) { char *pbchart_init = getenv("bootchart_init"); if (pbchart_init) execl(pbchart_init, pbchart_init, NULL); execl("/init", "init", (void *)0); execl("/sbin/init", "init", (void *)0); } - if (bchartd_opt == 1 && toys.optargs[1]) { + if (bchartd_opt == 1 && toys.optargs[1]) { pid_t prog_pid; if (!(prog_pid = xfork())) xexec(toys.optargs+1); diff --git a/toys/pending/ipcs.c b/toys/pending/ipcs.c index 8ad7c73..3e7129b 100644 --- a/toys/pending/ipcs.c +++ b/toys/pending/ipcs.c @@ -276,7 +276,7 @@ static void sem_array(void) "allocated semaphores = %d\n", info_buf.semusz, info_buf.semaem); return; - } + } if (flag(l)) { printf("------ Semaphore Limits --------\n"); u.array = (unsigned short *)&info_buf; diff --git a/toys/pending/mke2fs.c b/toys/pending/mke2fs.c deleted file mode 100644 index ee0a5b1..0000000 --- a/toys/pending/mke2fs.c +++ /dev/null @@ -1,768 +0,0 @@ -/* mke2fs.c - Create an ext2 filesystem image. - * - * Copyright 2006, 2007 Rob Landley - -// Still to go: "E:jJ:L:m:O:" -USE_MKE2FS(NEWTOY(mke2fs, "<1>2g:Fnqm#N#i#b#", TOYFLAG_SBIN)) - -config MKE2FS - bool "mke2fs" - default n - help - usage: mke2fs [-Fnq] [-b ###] [-N|i ###] [-m ###] device - - Create an ext2 filesystem on a block device or filesystem image. - - -F Force to run on a mounted device - -n Don't write to device - -q Quiet (no output) - -b size Block size (1024, 2048, or 4096) - -N inodes Allocate this many inodes - -i bytes Allocate one inode for every XXX bytes of device - -m percent Reserve this percent of filesystem space for root user - -config MKE2FS_JOURNAL - bool "Journaling support (ext3)" - default n - depends on MKE2FS - help - usage: mke2fs [-j] [-J size=###,device=XXX] - - -j Create journal (ext3) - -J Journal options - size: Number of blocks (1024-102400) - device: Specify an external journal - -config MKE2FS_GEN - bool "Generate (gene2fs)" - default n - depends on MKE2FS - help - usage: gene2fs [options] device filename - - The [options] are the same as mke2fs. - -config MKE2FS_LABEL - bool "Label support" - default n - depends on MKE2FS - help - usage: mke2fs [-L label] [-M path] [-o string] - - -L Volume label - -M Path to mount point - -o Created by - -config MKE2FS_EXTENDED - bool "Extended options" - default n - depends on MKE2FS - help - usage: mke2fs [-E stride=###] [-O option[,option]] - - -E stride= Set RAID stripe size (in blocks) - -O [opts] Specify fewer ext2 option flags (for old kernels) - All of these are on by default (as appropriate) - none Clear default options (all but journaling) - dir_index Use htree indexes for large directories - filetype Store file type info in directory entry - has_journal Set by -j - journal_dev Set by -J device=XXX - sparse_super Don't allocate huge numbers of redundant superblocks -*/ - -#define FOR_mke2fs -#include "toys.h" - -GLOBALS( - // Command line arguments. - long blocksize; - long bytes_per_inode; - long inodes; // Total inodes in filesystem. - long reserved_percent; // Integer precent of space to reserve for root. - char *gendir; // Where to read dirtree from. - - // Internal data. - struct dirtree *dt; // Tree of files to copy into the new filesystem. - unsigned treeblocks; // Blocks used by dt - unsigned treeinodes; // Inodes used by dt - - unsigned blocks; // Total blocks in the filesystem. - unsigned freeblocks; // Free blocks in the filesystem. - unsigned inodespg; // Inodes per group - unsigned groups; // Total number of block groups. - unsigned blockbits; // Bits per block. (Also blocks per group.) - - // For gene2fs - unsigned nextblock; // Next data block to allocate - unsigned nextgroup; // Next group we'll be allocating from - int fsfd; // File descriptor of filesystem (to output to). -) - -// Stuff defined in linux/ext2_fs.h - -#define EXT2_SUPER_MAGIC 0xEF53 - -struct ext2_superblock { - uint32_t inodes_count; // Inodes count - uint32_t blocks_count; // Blocks count - uint32_t r_blocks_count; // Reserved blocks count - uint32_t free_blocks_count; // Free blocks count - uint32_t free_inodes_count; // Free inodes count - uint32_t first_data_block; // First Data Block - uint32_t log_block_size; // Block size - uint32_t log_frag_size; // Fragment size - uint32_t blocks_per_group; // Blocks per group - uint32_t frags_per_group; // Fragments per group - uint32_t inodes_per_group; // Inodes per group - uint32_t mtime; // Mount time - uint32_t wtime; // Write time - uint16_t mnt_count; // Mount count - uint16_t max_mnt_count; // Maximal mount count - uint16_t magic; // Magic signature - uint16_t state; // File system state - uint16_t errors; // Behaviour when detecting errors - uint16_t minor_rev_level; // minor revision level - uint32_t lastcheck; // time of last check - uint32_t checkinterval; // max. time between checks - uint32_t creator_os; // OS - uint32_t rev_level; // Revision level - uint16_t def_resuid; // Default uid for reserved blocks - uint16_t def_resgid; // Default gid for reserved blocks - uint32_t first_ino; // First non-reserved inode - uint16_t inode_size; // size of inode structure - uint16_t block_group_nr; // block group # of this superblock - uint32_t feature_compat; // compatible feature set - uint32_t feature_incompat; // incompatible feature set - uint32_t feature_ro_compat; // readonly-compatible feature set - char uuid[16]; // 128-bit uuid for volume - char volume_name[16]; // volume name - char last_mounted[64]; // directory where last mounted - uint32_t alg_usage_bitmap; // For compression - // For EXT2_COMPAT_PREALLOC - uint8_t prealloc_blocks; // Nr of blocks to try to preallocate - uint8_t prealloc_dir_blocks; //Nr to preallocate for dirs - uint16_t padding1; - // For EXT3_FEATURE_COMPAT_HAS_JOURNAL - uint8_t journal_uuid[16]; // uuid of journal superblock - uint32_t journal_inum; // inode number of journal file - uint32_t journal_dev; // device number of journal file - uint32_t last_orphan; // start of list of inodes to delete - uint32_t hash_seed[4]; // HTREE hash seed - uint8_t def_hash_version; // Default hash version to use - uint8_t padding2[3]; - uint32_t default_mount_opts; - uint32_t first_meta_bg; // First metablock block group - uint32_t mkfs_time; // Creation timestamp - uint32_t jnl_blocks[17]; // Backup of journal inode - // uint32_t reserved[172]; // Padding to the end of the block -}; - -struct ext2_group -{ - uint32_t block_bitmap; // Block number of block bitmap - uint32_t inode_bitmap; // Block number of inode bitmap - uint32_t inode_table; // Block number of inode table - uint16_t free_blocks_count; // How many free blocks in this group? - uint16_t free_inodes_count; // How many free inodes in this group? - uint16_t used_dirs_count; // How many directories? - uint16_t reserved[7]; // pad to 32 bytes -}; - -struct ext2_dentry { - uint32_t inode; // Inode number - uint16_t rec_len; // Directory entry length - uint8_t name_len; // Name length - uint8_t file_type; - char name[0]; // File name -}; - -struct ext2_inode { - uint16_t mode; // File mode - uint16_t uid; // Low 16 bits of Owner Uid - uint32_t size; // Size in bytes - uint32_t atime; // Access time - uint32_t ctime; // Creation time - uint32_t mtime; // Modification time - uint32_t dtime; // Deletion Time - uint16_t gid; // Low 16 bits of Group Id - uint16_t links_count; // Links count - uint32_t blocks; // Blocks count - uint32_t flags; // File flags - uint32_t reserved1; - uint32_t block[15]; // Pointers to blocks - uint32_t generation; // File version (for NFS) - uint32_t file_acl; // File ACL - uint32_t dir_acl; // Directory ACL (or top bits of file length) - uint32_t faddr; // Last block in file - uint8_t frag; // Fragment number - uint8_t fsize; // Fragment size - uint16_t pad1; - uint16_t uid_high; // High bits of uid - uint16_t gid_high; // High bits of gid - uint32_t reserved2; -}; - -#define EXT2_FEATURE_COMPAT_DIR_PREALLOC 0x0001 -#define EXT2_FEATURE_COMPAT_IMAGIC_INODES 0x0002 -#define EXT3_FEATURE_COMPAT_HAS_JOURNAL 0x0004 -#define EXT2_FEATURE_COMPAT_EXT_ATTR 0x0008 -#define EXT2_FEATURE_COMPAT_RESIZE_INO 0x0010 -#define EXT2_FEATURE_COMPAT_DIR_INDEX 0x0020 - -#define EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER 0x0001 -#define EXT2_FEATURE_RO_COMPAT_LARGE_FILE 0x0002 -#define EXT2_FEATURE_RO_COMPAT_BTREE_DIR 0x0004 - -#define EXT2_FEATURE_INCOMPAT_COMPRESSION 0x0001 -#define EXT2_FEATURE_INCOMPAT_FILETYPE 0x0002 -#define EXT3_FEATURE_INCOMPAT_RECOVER 0x0004 -#define EXT3_FEATURE_INCOMPAT_JOURNAL_DEV 0x0008 -#define EXT2_FEATURE_INCOMPAT_META_BG 0x0010 - -#define EXT2_NAME_LEN 255 - -// Ext2 directory file types. Only the low 3 bits are used. The -// other bits are reserved for now. - -enum { - EXT2_FT_UNKNOWN, - EXT2_FT_REG_FILE, - EXT2_FT_DIR, - EXT2_FT_CHRDEV, - EXT2_FT_BLKDEV, - EXT2_FT_FIFO, - EXT2_FT_SOCK, - EXT2_FT_SYMLINK, - EXT2_FT_MAX -}; - -#define INODES_RESERVED 10 - -static uint32_t div_round_up(uint32_t a, uint32_t b) -{ - uint32_t c = a/b; - - if (a%b) c++; - return c; -} - -// Calculate data blocks plus index blocks needed to hold a file. - -static uint32_t file_blocks_used(uint64_t size, uint32_t *blocklist) -{ - uint32_t dblocks = (uint32_t)((size+(TT.blocksize-1))/TT.blocksize); - uint32_t idx=TT.blocksize/4, iblocks=0, diblocks=0, tiblocks=0; - - // Fill out index blocks in inode. - - if (blocklist) { - int i; - - // Direct index blocks - for (i=0; i<13 && i 13+idx) blocklist[13] = 13+idx; - // Doubly indirect index blocks - idx = 13 + idx + (idx*idx); - if (dblocks > idx) blocklist[14] = idx; - - return 0; - } - - // Account for direct, singly, doubly, and triply indirect index blocks - - if (dblocks > 12) { - iblocks = ((dblocks-13)/idx)+1; - if (iblocks > 1) { - diblocks = ((iblocks-2)/idx)+1; - if (diblocks > 1) - tiblocks = ((diblocks-2)/idx)+1; - } - } - - return dblocks + iblocks + diblocks + tiblocks; -} - -// Use the parent pointer to iterate through the tree non-recursively. -static struct dirtree *treenext(struct dirtree *this) -{ - while (this && !this->next) this = this->parent; - if (this) this = this->next; - - return this; -} - -// Recursively calculate the number of blocks used by each inode in the tree. -// Returns blocks used by this directory, assigns bytes used to *size. -// Writes total block count to TT.treeblocks and inode count to TT.treeinodes. - -static long check_treesize(struct dirtree *that, off_t *size) -{ - long blocks; - - while (that) { - *size += sizeof(struct ext2_dentry) + strlen(that->name); - - if (that->child) - that->st.st_blocks = check_treesize(that->child, &that->st.st_size); - else if (S_ISREG(that->st.st_mode)) { - that->st.st_blocks = file_blocks_used(that->st.st_size, 0); - TT.treeblocks += that->st.st_blocks; - } - that = that->next; - } - TT.treeblocks += blocks = file_blocks_used(*size, 0); - TT.treeinodes++; - - return blocks; -} - -// Calculate inode numbers and link counts. -// -// To do this right I need to copy the tree and sort it, but here's a really -// ugly n^2 way of dealing with the problem that doesn't scale well to large -// numbers of files (> 100,000) but can be done in very little code. -// This rewrites inode numbers to their final values, allocating depth first. - -static void check_treelinks(struct dirtree *tree) -{ - struct dirtree *current=tree, *that; - long inode = INODES_RESERVED; - - while (current) { - ++inode; - // Since we can't hardlink to directories, we know their link count. - if (S_ISDIR(current->st.st_mode)) current->st.st_nlink = 2; - else { - dev_t new = current->st.st_dev; - - if (!new) continue; - - // Look for other copies of current node - current->st.st_nlink = 0; - for (that = tree; that; that = treenext(that)) { - if (current->st.st_ino == that->st.st_ino && - current->st.st_dev == that->st.st_dev) - { - current->st.st_nlink++; - current->st.st_ino = inode; - } - } - } - current->st.st_ino = inode; - current = treenext(current); - } -} - -// Calculate inodes per group from total inodes. -static uint32_t get_inodespg(uint32_t inodes) -{ - uint32_t temp; - - // Round up to fill complete inode blocks. - temp = (inodes + TT.groups - 1) / TT.groups; - inodes = TT.blocksize/sizeof(struct ext2_inode); - return ((temp + inodes - 1)/inodes)*inodes; -} - -// Fill out superblock and TT structures. - -static void init_superblock(struct ext2_superblock *sb) -{ - uint32_t temp; - - // Set log_block_size and log_frag_size. - - for (temp = 0; temp < 4; temp++) if (TT.blocksize == 1024<log_block_size = sb->log_frag_size = SWAP_LE32(temp); - - // Fill out blocks_count, r_blocks_count, first_data_block - - sb->blocks_count = SWAP_LE32(TT.blocks); - sb->free_blocks_count = SWAP_LE32(TT.freeblocks); - temp = (TT.blocks * (uint64_t)TT.reserved_percent) / 100; - sb->r_blocks_count = SWAP_LE32(temp); - - sb->first_data_block = SWAP_LE32(TT.blocksize == 1024 ? 1 : 0); - - // Set blocks_per_group and frags_per_group, which is the size of an - // allocation bitmap that fits in one block (I.E. how many bits per block)? - - sb->blocks_per_group = sb->frags_per_group = SWAP_LE32(TT.blockbits); - - // Set inodes_per_group and total inodes_count - sb->inodes_per_group = SWAP_LE32(TT.inodespg); - sb->inodes_count = SWAP_LE32(TT.inodespg * TT.groups); - - // Determine free inodes. - temp = TT.inodespg*TT.groups - INODES_RESERVED; - if (temp < TT.treeinodes) error_exit("Not enough inodes.\n"); - sb->free_inodes_count = SWAP_LE32(temp - TT.treeinodes); - - // Fill out the rest of the superblock. - sb->max_mnt_count=0xFFFF; - sb->wtime = sb->lastcheck = sb->mkfs_time = SWAP_LE32(time(NULL)); - sb->magic = SWAP_LE32(0xEF53); - sb->state = sb->errors = SWAP_LE16(1); - - sb->rev_level = SWAP_LE32(1); - sb->first_ino = SWAP_LE32(INODES_RESERVED+1); - sb->inode_size = SWAP_LE16(sizeof(struct ext2_inode)); - sb->feature_incompat = SWAP_LE32(EXT2_FEATURE_INCOMPAT_FILETYPE); - sb->feature_ro_compat = SWAP_LE32(EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER); - - create_uuid(sb->uuid); - - // TODO If we're called as mke3fs or mkfs.ext3, do a journal. - - //if (strchr(toys.which->name,'3')) - // sb->feature_compat |= SWAP_LE32(EXT3_FEATURE_COMPAT_HAS_JOURNAL); -} - -// Does this group contain a superblock backup (and group descriptor table)? -static int is_sb_group(uint32_t group) -{ - int i; - - // Superblock backups are on groups 0, 1, and powers of 3, 5, and 7. - if(!group || group==1) return 1; - for (i=3; i<9; i+=2) { - int j = i; - while (j sizeof(toybuf) ? sizeof(toybuf) : len; - xwrite(TT.fsfd, toybuf, out); - len -= out; - } - } -} - -// Fill out an inode structure from struct stat info in dirtree. -static void fill_inode(struct ext2_inode *in, struct dirtree *that) -{ - uint32_t fbu[15]; - int temp; - - file_blocks_used(that->st.st_size, fbu); - - // If that inode needs data blocks allocated to it. - if (that->st.st_size) { - int i, group = TT.nextblock/TT.blockbits; - - // TODO: teach this about indirect blocks. - for (i=0; i<15; i++) { - // If we just jumped into a new group, skip group overhead blocks. - while (group >= TT.nextgroup) - TT.nextblock += group_overhead(TT.nextgroup++); - } - } - // TODO : S_ISREG/DIR/CHR/BLK/FIFO/LNK/SOCK(m) - in->mode = SWAP_LE32(that->st.st_mode); - - in->uid = SWAP_LE16(that->st.st_uid & 0xFFFF); - in->uid_high = SWAP_LE16(that->st.st_uid >> 16); - in->gid = SWAP_LE16(that->st.st_gid & 0xFFFF); - in->gid_high = SWAP_LE16(that->st.st_gid >> 16); - in->size = SWAP_LE32(that->st.st_size & 0xFFFFFFFF); - - // Contortions to make the compiler not generate a warning for x>>32 - // when x is 32 bits. The optimizer should clean this up. - if (sizeof(that->st.st_size) > 4) temp = 32; - else temp = 0; - if (temp) in->dir_acl = SWAP_LE32(that->st.st_size >> temp); - - in->atime = SWAP_LE32(that->st.st_atime); - in->ctime = SWAP_LE32(that->st.st_ctime); - in->mtime = SWAP_LE32(that->st.st_mtime); - - in->links_count = SWAP_LE16(that->st.st_nlink); - in->blocks = SWAP_LE32(that->st.st_blocks); - // in->faddr -} - -// Works like an archiver. -// The first argument is the name of the file to create. If it already -// exists, that size will be used. - -void mke2fs_main(void) -{ - int i, temp; - off_t length; - uint32_t usedblocks, usedinodes, dtbblk; - struct dirtree *dti, *dtb; - struct ext2_superblock sb; - - // Handle command line arguments. - - if (toys.optargs[1]) { - sscanf(toys.optargs[1], "%u", &TT.blocks); - temp = O_RDWR|O_CREAT; - } else temp = O_RDWR; - if (!TT.reserved_percent) TT.reserved_percent = 5; - - // TODO: Check if filesystem is mounted here - - // For mke?fs, open file. For gene?fs, create file. - TT.fsfd = xcreate(*toys.optargs, temp, 0777); - - // Determine appropriate block size and block count from file length. - // (If no length, default to 4k. They can override it on the cmdline.) - - length = fdlength(TT.fsfd); - if (!TT.blocksize) TT.blocksize = (length && length < 1<<29) ? 1024 : 4096; - TT.blockbits = 8*TT.blocksize; - if (!TT.blocks) TT.blocks = length/TT.blocksize; - - // Collect gene2fs list or lost+found, calculate requirements. - - if (TT.gendir) { - strncpy(toybuf, TT.gendir, sizeof(toybuf)); - dti = dirtree_read(toybuf, dirtree_notdotdot); - } else { - dti = xzalloc(sizeof(struct dirtree)+11); - strcpy(dti->name, "lost+found"); - dti->st.st_mode = S_IFDIR|0755; - dti->st.st_ctime = dti->st.st_mtime = time(NULL); - } - - // Add root directory inode. This is iterated through for when finding - // blocks, but not when finding inodes. The tree's parent pointers don't - // point back into this. - - dtb = xzalloc(sizeof(struct dirtree)+1); - dtb->st.st_mode = S_IFDIR|0755; - dtb->st.st_ctime = dtb->st.st_mtime = time(NULL); - dtb->child = dti; - - // Figure out how much space is used by preset files - length = check_treesize(dtb, &(dtb->st.st_size)); - check_treelinks(dtb); - - // Figure out how many total inodes we need. - - if (!TT.inodes) { - if (!TT.bytes_per_inode) TT.bytes_per_inode = 8192; - TT.inodes = (TT.blocks * (uint64_t)TT.blocksize) / TT.bytes_per_inode; - } - - // If we're generating a filesystem and have no idea how many blocks it - // needs, start with a minimal guess, find the overhead of that many - // groups, and loop until this is enough groups to store this many blocks. - if (!TT.blocks) TT.groups = (TT.treeblocks/TT.blockbits)+1; - else TT.groups = div_round_up(TT.blocks, TT.blockbits); - - for (;;) { - temp = TT.treeblocks; - - for (i = 0; i TT.blocks) end = TT.blocks & (TT.blockbits-1); - - // Blocks used by inode table - itable = (TT.inodespg*sizeof(struct ext2_inode))/TT.blocksize; - - // If a superblock goes here, write it out. - start = group_superblock_overhead(i); - if (start) { - struct ext2_group *bg = (struct ext2_group *)toybuf; - int treeblocks = TT.treeblocks, treeinodes = TT.treeinodes; - - sb.block_group_nr = SWAP_LE16(i); - - // Write superblock and pad it up to block size - xwrite(TT.fsfd, &sb, sizeof(struct ext2_superblock)); - temp = TT.blocksize - sizeof(struct ext2_superblock); - if (!i && TT.blocksize > 1024) temp -= 1024; - memset(toybuf, 0, TT.blocksize); - xwrite(TT.fsfd, toybuf, temp); - - // Loop through groups to write group descriptor table. - for(j=0; j treeinodes) { - treeinodes -= temp; - temp = 0; - } else { - temp -= treeinodes; - treeinodes = 0; - } - bg[slot].free_inodes_count = SWAP_LE16(temp); - - // How many free blocks in this group? - temp = TT.inodespg/(TT.blocksize/sizeof(struct ext2_inode)) + 2; - temp = end-used-temp; - if (temp > treeblocks) { - treeblocks -= temp; - temp = 0; - } else { - temp -= treeblocks; - treeblocks = 0; - } - bg[slot].free_blocks_count = SWAP_LE32(temp); - - // Fill out rest of group structure - used += j*TT.blockbits; - bg[slot].block_bitmap = SWAP_LE32(used++); - bg[slot].inode_bitmap = SWAP_LE32(used++); - bg[slot].inode_table = SWAP_LE32(used); - bg[slot].used_dirs_count = 0; // (TODO) - } - xwrite(TT.fsfd, bg, TT.blocksize); - } - - // Now write out stuff that every block group has. - - // Write block usage bitmap - - start += 2 + itable; - memset(toybuf, 0, TT.blocksize); - bits_set(toybuf, 0, start); - bits_set(toybuf, end, TT.blockbits-end); - temp = TT.treeblocks - usedblocks; - if (temp) { - if (end-start > temp) temp = end-start; - bits_set(toybuf, start, temp); - } - xwrite(TT.fsfd, toybuf, TT.blocksize); - - // Write inode bitmap - memset(toybuf, 0, TT.blocksize); - j = 0; - if (!i) bits_set(toybuf, 0, j = INODES_RESERVED); - bits_set(toybuf, TT.inodespg, slot = TT.blockbits-TT.inodespg); - temp = TT.treeinodes - usedinodes; - if (temp) { - if (slot-j > temp) temp = slot-j; - bits_set(toybuf, j, temp); - } - xwrite(TT.fsfd, toybuf, TT.blocksize); - - // Write inode table for this group (TODO) - for (j = 0; j> 16) + (sum & 0xffff); sum += (sum >> 16); return (~sum); @@ -133,7 +133,7 @@ static void send_probe4(int seq, int ttl) if (res < 0) perror_exit("setsockopt ttl %d", ttl); len = TT.msg_len; - res = sendto(TT.snd_sock, out, len, 0, (struct sockaddr *) &dest, + res = sendto(TT.snd_sock, out, len, 0, (struct sockaddr *) &dest, sizeof(struct sockaddr_in)); if (res != len) perror_exit(" sendto"); } @@ -148,7 +148,7 @@ static void send_probe6(int seq, int ttl) send_data6->ident = TT.ident; ((struct sockaddr_in6 *)&dest)->sin6_port = TT.port; - if (setsockopt(TT.snd_sock, SOL_IPV6, IPV6_UNICAST_HOPS, &ttl, + if (setsockopt(TT.snd_sock, SOL_IPV6, IPV6_UNICAST_HOPS, &ttl, sizeof(ttl)) < 0) error_exit("setsockopt ttl %d", ttl); out = send_data6; @@ -225,12 +225,12 @@ static void do_trace() gettimeofday(&t1, NULL); t2 = t1; - while ((tleft = (int)(tv - ((unsigned long long)(t2.tv_sec * 1000ULL + while ((tleft = (int)(tv - ((unsigned long long)(t2.tv_sec * 1000ULL + t2.tv_usec/1000) - (unsigned long long)(t1.tv_sec * 1000ULL + t1.tv_usec/1000)))) >= 0) { unsigned delta = 0; - if (!(res = poll(pfd, 1, tleft))) { - xprintf(" *"); + if (!(res = poll(pfd, 1, tleft))) { + xprintf(" *"); break; } gettimeofday(&t2, NULL); @@ -276,28 +276,28 @@ static void do_trace() ricmp->icmp_code); } else { hicmp = (struct icmp *) ((char*)hip + (hip->ip_hl << 2)); - if (ricmp->icmp_type == ICMP_ECHOREPLY + if (ricmp->icmp_type == ICMP_ECHOREPLY && ricmp->icmp_id == ntohs(TT.ident) && ricmp->icmp_seq == ntohs(seq)) icmp_res = ICMP_UNREACH_PORT; - else if ((hip->ip_hl << 2) + ICMP_HD_SIZE4 + else if ((hip->ip_hl << 2) + ICMP_HD_SIZE4 <= (rcv_len - (rcv_pkt->ip_hl << 2)) && hip->ip_p == IPPROTO_ICMP && hicmp->icmp_id == htons(TT.ident) && hicmp->icmp_seq == htons(seq)) - icmp_res = (ricmp->icmp_type == ICMP_TIMXCEED ? -1 : + icmp_res = (ricmp->icmp_type == ICMP_TIMXCEED ? -1 : ricmp->icmp_code); } } if (!icmp_res) continue; if (addrlen > 0) { - if (memcmp(&((struct sockaddr_in *)&last_addr)->sin_addr, - &((struct sockaddr_in *)&from)->sin_addr, + if (memcmp(&((struct sockaddr_in *)&last_addr)->sin_addr, + &((struct sockaddr_in *)&from)->sin_addr, sizeof(struct in_addr))) { if (!(toys.optflags & FLAG_n)) { char host[NI_MAXHOST]; - if (!getnameinfo((struct sockaddr *) &from, + if (!getnameinfo((struct sockaddr *) &from, sizeof(struct sockaddr_in), host, NI_MAXHOST, NULL, 0, 0)) xprintf(" %s (", host); else xprintf(" %s (", inet_ntoa( @@ -359,7 +359,7 @@ static void do_trace() xprintf(" !C"); ++fexit; break; - case ICMP_UNREACH_NET_UNKNOWN: + case ICMP_UNREACH_NET_UNKNOWN: case ICMP_UNREACH_HOST_UNKNOWN: xprintf(" !U"); ++fexit; @@ -407,8 +407,8 @@ static void do_trace() if (!icmp_res) continue; if (addrlen > 0) { - if (memcmp(&((struct sockaddr_in6 *)&last_addr)->sin6_addr, - &((struct sockaddr_in6 *)&from)->sin6_addr, + if (memcmp(&((struct sockaddr_in6 *)&last_addr)->sin6_addr, + &((struct sockaddr_in6 *)&from)->sin6_addr, sizeof(struct in6_addr))) { if (!(toys.optflags & FLAG_n)) { char host[NI_MAXHOST]; @@ -467,7 +467,7 @@ static void do_trace() } xputc('\n'); if(!TT.istraceroute6) { - if (!memcmp(&((struct sockaddr_in *)&from)->sin_addr, + if (!memcmp(&((struct sockaddr_in *)&from)->sin_addr, &((struct sockaddr_in *)&dest)->sin_addr, sizeof(struct in_addr)) || dest_reach || (fexit && fexit >= TT.ttl_probes -1)) break; @@ -479,8 +479,8 @@ void traceroute_main(void) { unsigned pack_size = 0, tyser = 0; int lsrr = 0, set = 1; - - if(!(toys.optflags & FLAG_4) && + + if(!(toys.optflags & FLAG_4) && (inet_pton(AF_INET6, toys.optargs[0], &dest))) toys.optflags |= FLAG_6; @@ -511,29 +511,29 @@ void traceroute_main(void) if (TT.istraceroute6) { int two = 2; #ifdef IPV6_RECVPKTINFO - setsockopt(TT.recv_sock, SOL_IPV6, IPV6_RECVPKTINFO, &set, + setsockopt(TT.recv_sock, SOL_IPV6, IPV6_RECVPKTINFO, &set, sizeof(set)); - setsockopt(TT.recv_sock, SOL_IPV6, IPV6_2292PKTINFO, &set, + setsockopt(TT.recv_sock, SOL_IPV6, IPV6_2292PKTINFO, &set, sizeof(set)); #else setsockopt(TT.recv_sock, SOL_IPV6, IPV6_PKTINFO, &set, sizeof(set)); #endif - if (setsockopt(TT.recv_sock, SOL_RAW, IPV6_CHECKSUM, &two, + if (setsockopt(TT.recv_sock, SOL_RAW, IPV6_CHECKSUM, &two, sizeof(two)) < 0) perror_exit("setsockopt RAW_CHECKSUM"); } set_flag_dr(TT.recv_sock); if (!TT.istraceroute6) { - if (toys.optflags & FLAG_U) + if (toys.optflags & FLAG_U) TT.snd_sock = xsocket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); else TT.snd_sock = xsocket(AF_INET, SOCK_RAW, IPPROTO_ICMP); if (toys.optflags & FLAG_i) bind_to_interface(TT.snd_sock); - resolve_addr(toys.optargs[0], AF_INET, ((toys.optflags & FLAG_U) ? - SOCK_DGRAM : SOCK_RAW), ((toys.optflags & FLAG_U) ? IPPROTO_UDP : + resolve_addr(toys.optargs[0], AF_INET, ((toys.optflags & FLAG_U) ? + SOCK_DGRAM : SOCK_RAW), ((toys.optflags & FLAG_U) ? IPPROTO_UDP : IPPROTO_ICMP), &dest); if (lsrr > 0) { unsigned char optlist[MAX_IPOPTLEN]; @@ -543,7 +543,7 @@ void traceroute_main(void) ++lsrr; optlist[0] = IPOPT_NOP; - optlist[1] = IPOPT_LSRR;// loose source route option + optlist[1] = IPOPT_LSRR;// loose source route option size = lsrr * sizeof(TT.gw_list[0]); optlist[2] = size + 3; optlist[3] = IPOPT_MINOFF; @@ -555,17 +555,17 @@ void traceroute_main(void) } } else TT.snd_sock = xsocket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP); - if (setsockopt(TT.snd_sock, SOL_SOCKET, SO_SNDBUF, &TT.msg_len, + if (setsockopt(TT.snd_sock, SOL_SOCKET, SO_SNDBUF, &TT.msg_len, sizeof(TT.msg_len)) < 0) perror_exit("SO_SNDBUF failed "); if (!TT.istraceroute6) { - if ((toys.optflags & FLAG_t) && + if ((toys.optflags & FLAG_t) && setsockopt(TT.snd_sock, IPPROTO_IP, IP_TOS, &tyser, sizeof(tyser)) < 0) perror_exit("IP_TOS %ld failed ", TT.tos); #ifdef IP_DONTFRAG if ((toys.optflags & FLAG_F) && - (setsockopt(TT.snd_sock, IPPROTO_IP, IP_DONTFRAG, &set, + (setsockopt(TT.snd_sock, IPPROTO_IP, IP_DONTFRAG, &set, sizeof(set)) < 0)) perror_exit("IP_DONTFRAG failed "); #endif } else if (setsockopt(TT.snd_sock, IPPROTO_IPV6, IPV6_TCLASS, &TT.tos, @@ -593,10 +593,10 @@ void traceroute_main(void) xbind(TT.snd_sock,(struct sockaddr*)&source, sizeof(struct sockaddr_in)); } - if(TT.first_ttl > TT.max_ttl) + if(TT.first_ttl > TT.max_ttl) error_exit("ERROR :Range for -f is 1 to %ld (max ttl)", TT.max_ttl); - xprintf("traceroute to %s(%s)", toys.optargs[0], + xprintf("traceroute to %s(%s)", toys.optargs[0], inet_ntoa(((struct sockaddr_in *)&dest)->sin_addr)); } else { if (toys.optflags & FLAG_i) bind_to_interface(TT.snd_sock); @@ -622,7 +622,7 @@ void traceroute_main(void) ((struct sockaddr_in6 *)&dest)->sin6_port = htons(1025); xconnect(p_fd, (struct sockaddr *)&dest, sizeof(struct sockaddr_in6)); - if(getsockname(p_fd, (struct sockaddr *)&prb, &len)) + if(getsockname(p_fd, (struct sockaddr *)&prb, &len)) error_exit("probe addr failed"); close(p_fd); prb.sin6_port = 0; @@ -634,7 +634,7 @@ void traceroute_main(void) xbind(TT.recv_sock, (struct sockaddr*)&prb, sizeof(struct sockaddr_in6)); } - inet_ntop(AF_INET6, &((struct sockaddr_in6 *)&dest)->sin6_addr, + inet_ntop(AF_INET6, &((struct sockaddr_in6 *)&dest)->sin6_addr, addr_str, INET6_ADDRSTRLEN); xprintf("traceroute6 to %s(%s)", toys.optargs[0], addr_str); } diff --git a/toys/posix/ps.c b/toys/posix/ps.c index 78925f8..efe8160 100644 --- a/toys/posix/ps.c +++ b/toys/posix/ps.c @@ -557,7 +557,7 @@ static char *string_field(struct procpid *tb, struct ofields *field) // Clock displays } else if (which <= PS_TIME_) { - int unit = 60, pad = 2, j = TT.ticks; + int unit = 60, pad = 2, j = TT.ticks; time_t seconds; if (which!=PS_TIME_) unit *= 60*24; @@ -620,7 +620,7 @@ static char *string_field(struct procpid *tb, struct ofields *field) if (slot[SLOT_sid]==*slot) *s++ = 's'; if (slot[SLOT_vmlck]) *s++ = 'L'; if (slot[SLOT_ttypgrp]==*slot) *s++ = '+'; - } + } *s = 0; } else if (which==PS_STIME) { time_t t = time(0)-slot[SLOT_uptime]+slot[SLOT_starttime]/TT.ticks; @@ -1284,7 +1284,7 @@ static int ksort(void *aa, void *bb) // Collect ->extra field from leaf nodes DIRTREE_SAVEd by get_ps() into array // (recursion because tree from get_thread() isn't flat list of siblings) -static struct procpid **collate_leaves(struct procpid **tb, struct dirtree *dt) +static struct procpid **collate_leaves(struct procpid **tb, struct dirtree *dt) { while (dt) { struct dirtree *next = dt->next; @@ -1307,7 +1307,7 @@ static struct procpid **collate(int count, struct dirtree *dt) collate_leaves(tbsort, dt); return tbsort; -} +} // parse command line arguments (ala -k -o) with a comma separated FIELD list static void default_ko(char *s, void *fields, char *err, struct arg_list *arg) @@ -1660,10 +1660,10 @@ static void top_common( /* fix "iotop -m 10" show 13 lines problem*/ if (TT.top.m) { if (toys.which->name[0] == 'i') { - // iotop 鍛戒护 + // iotop 命令 TT.height = TT.top.m + 2; } else { - // top 鍛戒护 + // top 命令 TT.height = TT.top.m + 5; } } diff --git a/update/toys/net/netcat.c b/update/toys/net/netcat.c deleted file mode 100644 index 557380a..0000000 --- a/update/toys/net/netcat.c +++ /dev/null @@ -1,258 +0,0 @@ -/* netcat.c - Forward stdin/stdout to a file or network connection. - * - * Copyright 2007 Rob Landley - * - * TODO: genericize for telnet/microcom/tail-f, fix -t with login_tty() - -USE_NETCAT(NEWTOY(netcat, "^tElLw#<1W#<1p#<1>65535q#<1O:o:s:f:46uUnz[!tlL][!Lw][!Lu][!46U][!oO]", TOYFLAG_BIN)) -USE_NETCAT(OLDTOY(nc, netcat, TOYFLAG_USR|TOYFLAG_BIN)) - -config NETCAT - bool "netcat" - default y - help - usage: netcat [-46ELlntUu] [-pqWw #] [-s addr] [-o FILE] {IPADDR PORTNUM|-f FILENAME|COMMAND...} - - Forward stdin/stdout to a file or network connection. - - -4 Force IPv4 - -6 Force IPv6 - -E Forward stderr - -f Use FILENAME (ala /dev/ttyS0) instead of network - -L Listen and background each incoming connection (server mode) - -l Listen for one incoming connection, then exit - -n No DNS lookup - -o Hex dump to FILE (show packets, -o- writes hex only to stdout) - -O Hex dump to FILE (streaming mode) - -p Local port number - -q Quit SECONDS after EOF on stdin, even if stdout hasn't closed yet - -s Local source address - -t Allocate tty - -u Use UDP - -U Use a UNIX domain socket - -W SECONDS timeout for more data on an idle connection - -w SECONDS timeout to establish connection - -z zero-I/O mode [used for scanning] - - When listening the COMMAND line is executed as a child process to handle - an incoming connection. With no COMMAND -l forwards the connection - to stdin/stdout. If no -p specified, -l prints the port it bound to and - backgrounds itself (returning immediately). - - For a quick-and-dirty server, try something like: - netcat -s 127.0.0.1 -p 1234 -tL sh -l - - Or use "stty 115200 -F /dev/ttyS0 && stty raw -echo -ctlecho" with - netcat -f to connect to a serial port. -*/ - -#define FOR_netcat -#include "toys.h" - -GLOBALS( - char *f, *s, *o, *O; - long q, p, W, w; - - unsigned ofd, olast, opos, ocount[2]; - char obuf[16]; -) - -static void timeout(int signum) -{ - if (TT.w) error_exit("Timeout"); - xexit(); -} - -// open AF_UNIX socket -static int usock(char *name, int type, int out) -{ - int sockfd; - struct sockaddr_un sockaddr; - - memset(&sockaddr, 0, sizeof(struct sockaddr_un)); - - if (strlen(name) + 1 > sizeof(sockaddr.sun_path)) - error_exit("socket path too long %s", name); - strcpy(sockaddr.sun_path, name); - sockaddr.sun_family = AF_UNIX; - - sockfd = xsocket(AF_UNIX, type, 0); - (out?xconnect:xbind)(sockfd, (struct sockaddr*)&sockaddr, sizeof(sockaddr)); - - return sockfd; -} - -// Hex dump accumulated buffer data -void oflush(void) -{ - char *s = toybuf; - unsigned *oc = TT.ocount+(TT.olast==1), uu; - - if (!TT.opos) return; - s += sprintf(toybuf, "%c %08x", 60+2*(TT.olast==1), *oc); - for (uu = 0; uu<16; uu++) { - s += sprintf(s, uu95) TT.obuf[uu] = '.'; - } - dprintf(TT.ofd, "%s # %.*s\n", toybuf, TT.opos, TT.obuf); - *oc += TT.opos; - TT.opos = 0; -} - -// Write data to output, and hex dump to -o if enabled. -void ohexwrite(int fd, void *buf, size_t len) -{ - // Hex dump if -o specified. Output is always to fd 1, input != 1. - if (TT.ofd) { - int i = 0, j; - - if (TT.olast != fd) oflush(); - TT.olast = fd; - - while (isa_family == AF_INET) - port_be = ((struct sockaddr_in*)address)->sin_port; - else if (address->sa_family == AF_INET6) - port_be = ((struct sockaddr_in6*)address)->sin6_port; - else perror_exit("getsockname: bad family"); - - dprintf(1, "%d\n", SWAP_BE16(port_be)); - // Return immediately if no -p and -Ll has arguments, so wrapper - // script can use port number. - if (CFG_TOYBOX_FORK && toys.optc && xfork()) goto cleanup; - } - - do { - len = sizeof(struct sockaddr_storage); - if (FLAG(u)) { - if (-1 == recvfrom(in1 = dup(sockfd), &child, 1, MSG_PEEK, - (void *)toybuf, &len)) perror_exit("recvfrom"); - } else if ((in1 = accept(sockfd, 0, 0))<0) perror_exit("accept"); - out2 = in1; - child = 0; - - // We have a connection. Disarm timeout. - alarm(0); - - // Fork a child as necessary. Parent cleans up and continues here. - if (toys.optc && FLAG(L)) NOEXIT(child = XVFORK()); - if (child) { - close(in1); - continue; - } - - if (FLAG(u)) - xconnect(in1, (void *)toybuf, sizeof(struct sockaddr_storage)); - - // Cleanup and redirect for exec - if (toys.optc) { - // Do we need a tty? -// TODO nommu and -t only affects server mode... -// if (FLAG(t)) child = forkpty(&fdout, NULL, NULL, NULL); - - close(sockfd); - dup2(in1, 0); - dup2(in1, 1); - if (FLAG(E)) dup2(in1, 2); - if (in1>2) close(in1); - xexec(toys.optargs); - - // Copy stdin/out - } else { - pollinate(in1, in2, out1, out2, ohexwrite, TT.W, TT.q); - close(in1); - } - } while (FLAG(L)); - } - } - -cleanup: - if (CFG_TOYBOX_FREE) { - close(in1); - close(sockfd); - } -} diff --git a/update/toys/other/free.c b/update/toys/other/free.c deleted file mode 100644 index 6be1cdc..0000000 --- a/update/toys/other/free.c +++ /dev/null @@ -1,58 +0,0 @@ -/* free.c - Display amount of free and used memory in the system. - * - * Copyright 2012 Elie De Brauwer - -// Flag order is signifcant: b-g are units in order, FLAG_h-1 is unit mask -USE_FREE(NEWTOY(free, "hgmkb[!hgmkb]", TOYFLAG_USR|TOYFLAG_BIN)) - -config FREE - bool "free" - default y - help - usage: free [-bkmgt] - - Display the total, free and used amount of physical memory and swap space. - - -bkmg Output units (default is bytes) - -h Human readable (K=1024) -*/ - -#define FOR_free -#include "toys.h" - -GLOBALS( - unsigned bits; - unsigned long long units; - char *buf; -) - -static char *convert(unsigned long d) -{ - long long ll = d*TT.units; - char *s = TT.buf; - - if (FLAG(h)) human_readable(s, ll, 0); - else sprintf(s, "%llu",ll>>TT.bits); - TT.buf += strlen(TT.buf)+1; - - return s; -} - -void free_main(void) -{ - struct sysinfo in; - - sysinfo(&in); - TT.units = in.mem_unit ? in.mem_unit : 1; - while ((toys.optflags&(FLAG_h-1)) && !(toys.optflags&(1< - * Copyright 2013 Kyungwan Han - * - * No Standard. - * - * TODO cleanup - -USE_LSATTR(NEWTOY(lsattr, "ldapvR", TOYFLAG_BIN)) -USE_CHATTR(NEWTOY(chattr, "?p#v#R", TOYFLAG_BIN)) - -config LSATTR - bool "lsattr" - default y - help - usage: lsattr [-Radlpv] [FILE...] - - List file attributes on a Linux file system. - Flag letters are defined in chattr help. - - -R Recursively list attributes of directories and their contents - -a List all files in directories, including files that start with '.' - -d List directories like other files, rather than listing their contents - -l List long flag names - -p List the file's project number - -v List the file's version/generation number - -config CHATTR - bool "chattr" - default y - help - usage: chattr [-R] [-+=AacDdijsStTu] [-p PROJID] [-v VERSION] [FILE...] - - Change file attributes on a Linux file system. - - -R Recurse - -p Set the file's project number - -v Set the file's version/generation number - - Operators: - '-' Remove attributes - '+' Add attributes - '=' Set attributes - - Attributes: - A No atime a Append only - C No COW c Compression - D Synchronous dir updates d No dump - E Encrypted e Extents - F Case-insensitive (casefold) - I Indexed directory i Immutable - j Journal data - N Inline data in inode - P Project hierarchy - S Synchronous file updates s Secure delete - T Top of dir hierarchy t No tail-merging - u Allow undelete - V Verity -*/ -#define FOR_lsattr -#include "toys.h" -#include - -GLOBALS( - long v, p; - - unsigned add, rm, set; - // !add and !rm tell us whether they were used, but `chattr =` is meaningful. - int have_set; -) - -// Added more recently than the 7 year support horizon. TODO: remove -#ifndef FS_CASEFOLD_FL -#define FS_CASEFOLD_FL 0x40000000 // commit 71e90b4654a92 2019-07-23 -#endif -#ifndef FS_VERITY_FL -#define FS_VERITY_FL 0x00100000 // commit fe9918d3b228b 2019-07-22 -#endif - -static struct ext2_attr { - char *name; - unsigned flag; - char opt; -} e2attrs[] = { - // Do not sort! These are in the order that lsattr outputs them. - {"Secure_Deletion", FS_SECRM_FL, 's'}, - {"Undelete", FS_UNRM_FL, 'u'}, - {"Synchronous_Updates", FS_SYNC_FL, 'S'}, - {"Synchronous_Directory_Updates", FS_DIRSYNC_FL, 'D'}, - {"Immutable", FS_IMMUTABLE_FL, 'i'}, - {"Append_Only", FS_APPEND_FL, 'a'}, - {"No_Dump", FS_NODUMP_FL, 'd'}, - {"No_Atime", FS_NOATIME_FL, 'A'}, - {"Compression_Requested", FS_COMPR_FL, 'c'}, - {"Encrypted", FS_ENCRYPT_FL, 'E'}, - {"Journaled_Data", FS_JOURNAL_DATA_FL, 'j'}, - {"Indexed_directory", FS_INDEX_FL, 'I'}, - {"No_Tailmerging", FS_NOTAIL_FL, 't'}, - {"Top_of_Directory_Hierarchies", FS_TOPDIR_FL, 'T'}, - {"Extents", FS_EXTENT_FL, 'e'}, - {"No_COW", FS_NOCOW_FL, 'C'}, - {"Casefold", FS_CASEFOLD_FL, 'F'}, - {"Inline_Data", FS_INLINE_DATA_FL, 'N'}, - {"Project_Hierarchy", FS_PROJINHERIT_FL, 'P'}, - {"Verity", FS_VERITY_FL, 'V'}, - {NULL, 0, 0}, -}; - -// Get file flags on a Linux second extended file system. -static int ext2_getflag(int fd, struct stat *sb, unsigned *flag) -{ - if(!S_ISREG(sb->st_mode) && !S_ISDIR(sb->st_mode)) { - errno = EOPNOTSUPP; - return -1; - } - return ioctl(fd, FS_IOC_GETFLAGS, flag); -} - -static char *attrstr(unsigned attrs, int full) -{ - struct ext2_attr *a = e2attrs; - char *s = toybuf; - - for (; a->name; a++) - if (attrs & a->flag) *s++ = a->opt; - else if (full) *s++ = '-'; - *s = 0; - - return toybuf; -} - -static void print_file_attr(char *path) -{ - unsigned flag = 0, version = 0; - int fd = -1; - struct stat sb; - - if (!stat(path, &sb) && !S_ISREG(sb.st_mode) && !S_ISDIR(sb.st_mode)) { - errno = EOPNOTSUPP; - goto error; - } - if (-1 == (fd=open(path, O_RDONLY | O_NONBLOCK))) goto error; - - if (FLAG(p)) { - struct fsxattr fsx; - - if (ioctl(fd, FS_IOC_FSGETXATTR, &fsx)) goto error; - xprintf("%5u ", fsx.fsx_projid); - } - if (FLAG(v)) { - if (ioctl(fd, FS_IOC_GETVERSION, (void*)&version) < 0) goto error; - xprintf("%-10u ", version); - } - - if (ext2_getflag(fd, &sb, &flag) < 0) perror_msg("reading flags '%s'", path); - else { - struct ext2_attr *ptr = e2attrs; - int name_found = 0; - - if (FLAG(l)) { - xprintf("%-50s ", path); - for (; ptr->name; ptr++) { - if (flag & ptr->flag) { - if (name_found) xprintf(", "); //for formatting. - xprintf("%s", ptr->name); - name_found = 1; - } - } - if (!name_found) xprintf("---"); - xputc('\n'); - } else xprintf("%s %s\n", attrstr(flag, 1), path); - } - path = 0; -error: - xclose(fd); - if (path) perror_msg("reading '%s'", path); -} - -// Get directory information. -static int retell_dir(struct dirtree *root) -{ - char *fpath = 0; - - if (root->again) { - xputc('\n'); - - return 0; - } - if (S_ISDIR(root->st.st_mode) && !root->parent) - return DIRTREE_RECURSE|DIRTREE_COMEAGAIN; - - fpath = dirtree_path(root, NULL); - if (*root->name != '.' || FLAG(a)) { - print_file_attr(fpath); - if (S_ISDIR(root->st.st_mode) && FLAG(R) && dirtree_notdotdot(root)) { - xprintf("\n%s:\n", fpath); - free(fpath); - return DIRTREE_RECURSE|DIRTREE_COMEAGAIN; - } - } - free(fpath); - - return 0; -} - -void lsattr_main(void) -{ - if (!*toys.optargs) dirtree_read(".", retell_dir); - else for (; *toys.optargs; toys.optargs++) { - struct stat sb; - - if (lstat(*toys.optargs, &sb)) perror_msg("stat '%s'", *toys.optargs); - else if (S_ISDIR(sb.st_mode) && !FLAG(d)) - dirtree_read(*toys.optargs, retell_dir); - else print_file_attr(*toys.optargs);// to handle "./Filename" or "./Dir" - } -} - -// Switch gears from lsattr to chattr. -#define FOR_chattr -#include "generated/flags.h" - -// Set file flags on a Linux second extended file system. -static inline int ext2_setflag(int fd, struct stat *sb, unsigned flag) -{ - if (!S_ISREG(sb->st_mode) && !S_ISDIR(sb->st_mode)) { - errno = EOPNOTSUPP; - return -1; - } - return ioctl(fd, FS_IOC_SETFLAGS, &flag); -} - -static unsigned get_flag_val(char ch) -{ - struct ext2_attr *ptr = e2attrs; - - for (; ptr->name; ptr++) if (ptr->opt == ch) return ptr->flag; - help_exit("bad '%c'", ch); -} - -// Parse command line argument and fill the chattr structure. -static void parse_cmdline_arg(char ***argv) -{ - char *arg = **argv, *ptr; - - while (arg) { - if (*arg=='-') for (ptr = ++arg; *ptr; ptr++) TT.rm |= get_flag_val(*ptr); - else if (*arg=='+') - for (ptr = ++arg; *ptr; ptr++) TT.add |= get_flag_val(*ptr); - else if (*arg=='=') { - TT.have_set = 1; - for (ptr = ++arg; *ptr; ptr++) TT.set |= get_flag_val(*ptr); - } else return; - arg = *(*argv += 1); - } -} - -// Update attribute of given file. -static int update_attr(struct dirtree *root) -{ - char *fpath = 0; - int vv = TT.v, fd; - - if (!dirtree_notdotdot(root)) return 0; - - // if file is a link and recursive is set or file is not regular+link+dir - // (like fifo or dev file) then escape the file. - if ((S_ISLNK(root->st.st_mode) && FLAG(R)) - || (!S_ISREG(root->st.st_mode) && !S_ISLNK(root->st.st_mode) - && !S_ISDIR(root->st.st_mode))) - return 0; - - fpath = dirtree_path(root, NULL); - if (-1 == (fd=open(fpath, O_RDONLY | O_NONBLOCK))) { - free(fpath); - return DIRTREE_ABORT; - } - - // Any potential flag changes? - if (TT.have_set | TT.add | TT.rm) { - unsigned orig, new; - - // Read current flags. - if (ext2_getflag(fd, &(root->st), &orig) < 0) { - perror_msg("read flags of '%s'", fpath); - free(fpath); - xclose(fd); - return DIRTREE_ABORT; - } - // Apply the requested changes. - if (TT.have_set) new = TT.set; // '='. - else { // '-' and/or '+'. - new = orig; - new &= ~(TT.rm); - new |= TT.add; - if (!S_ISDIR(root->st.st_mode)) new &= ~FS_DIRSYNC_FL; - } - // Write them back if there was any change. - if (orig != new && ext2_setflag(fd, &(root->st), new)<0) - perror_msg("%s: setting flags to =%s failed", fpath, attrstr(new, 0)); - } - - // (FS_IOC_SETVERSION works all the way back to 2.6, but FS_IOC_FSSETXATTR - // isn't available until 4.5.) - if (FLAG(v) && (ioctl(fd, FS_IOC_SETVERSION, &vv)<0)) - perror_msg("%s: setting version to %d failed", fpath, vv); - - if (FLAG(p)) { - struct fsxattr fsx; - int fail = ioctl(fd, FS_IOC_FSGETXATTR, &fsx); - - fsx.fsx_projid = TT.p; - if (fail || ioctl(fd, FS_IOC_FSSETXATTR, &fsx)) - perror_msg("%s: setting projid to %u failed", fpath, fsx.fsx_projid); - } - - free(fpath); - xclose(fd); - return (FLAG(R) && S_ISDIR(root->st.st_mode)) ? DIRTREE_RECURSE : 0; -} - -void chattr_main(void) -{ - char **argv = toys.optargs; - - parse_cmdline_arg(&argv); - if (TT.p < 0 || TT.p > UINT_MAX) error_exit("bad projid %lu", TT.p); - if (TT.v < 0 || TT.v > UINT_MAX) error_exit("bad version %ld", TT.v); - if (!*argv) help_exit("no file"); - if (TT.have_set && (TT.add || TT.rm)) - error_exit("no '=' with '-' or '+'"); - if (TT.rm & TT.add) error_exit("set/unset same flag"); - if (!(TT.add || TT.rm || TT.have_set || FLAG(p) || FLAG(v))) - error_exit("need '-p', '-v', '=', '-', or '+'"); - for (; *argv; argv++) dirtree_read(*argv, update_attr); -} diff --git a/update/toys/other/lsusb.c b/update/toys/other/lsusb.c deleted file mode 100644 index 3abbe47..0000000 --- a/update/toys/other/lsusb.c +++ /dev/null @@ -1,261 +0,0 @@ -/* lsusb.c - list available USB devices - * - * Copyright 2013 Andre Renaud - * Copyright 2013 Isaac Dunham - -USE_LSUSB(NEWTOY(lsusb, "i:", TOYFLAG_USR|TOYFLAG_BIN)) -USE_LSPCI(NEWTOY(lspci, "eDmkn@x@i:", TOYFLAG_USR|TOYFLAG_BIN)) - -config LSPCI - bool "lspci" - default y - help - usage: lspci [-ekmn] [-i FILE] - - List PCI devices. - - -e Extended (6 digit) class - -i ID database (default /etc/pci.ids[.gz]) - -k Show kernel driver - -m Machine readable - -n Numeric output (-nn for both) - -D Print domain numbers - -x Hex dump of config space (64 bytes; -xxx for 256, -xxxx for 4096) - -config LSUSB - bool "lsusb" - default y - help - usage: lsusb [-i] - - List USB hosts/devices. - - -i ID database (default /etc/usb.ids[.gz]) -*/ - -#define FOR_lsusb -#include "toys.h" - -GLOBALS( - char *i; - long x, n; - - void *ids, *class; - int count; -) - -struct dev_ids { - struct dev_ids *next, *child; - int id; - char name[]; -}; - -struct scanloop { - char *pattern; - void *d1, *d2; -}; - -// Common function to read uevent file under /proc for both pci and usb -// note that %s is omitted (because pointer is into toybuf, avoiding copy). -static int scan_uevent(struct dirtree *new, int len, struct scanloop *sl) -{ - int ii, saw = 0; - off_t flen = sizeof(toybuf); - char *ss, *yy; - - // Read data - if (*new->name == '.') return 0; - sprintf(toybuf, "%s/uevent", new->name); - if (!readfileat(dirtree_parentfd(new), ss = toybuf, toybuf, &flen)) return 0; - - // Loop over lines - while ((flen = strcspn(ss, "\n"))) { - if (ss[flen]) ss[flen++] = 0; - yy = ss+flen; - - // Try each pattern - for (ii = 0; iinext) { - if (id1 != ids->id) continue; - *name1 = ids->name; - for (ids = ids->child; ids; ids = ids->next) { - if (id2 != ids->id) continue; - *name2 = ids->name; - return; - } - return; - } -} - -// Search for pci.ids or usb.ids and return parsed structure or NULL -struct dev_ids *parse_dev_ids(char *name, struct dev_ids **and) -{ - char *path = "/etc:/vendor:/usr/share/hwdata:/usr/share/misc"; - struct string_list *sl = 0; - FILE *fp; - char *s, *ss, *sss; - struct dev_ids *ids = 0, *new; - int fd = -1; - - // Open compressed or uncompressed file - signal(SIGCHLD, SIG_IGN); - s = TT.i; - if (!s) { - sprintf(toybuf, "%s.gz", name); - if ((sl = find_in_path(path, toybuf)) || (sl = find_in_path(path, name))) - s = sl->str; - } - if (s && strend(s, ".gz")) xpopen((char *[]){"zcat", sl->str, 0}, &fd, 1); - else if (s) fd = xopen(s, O_RDONLY); - llist_traverse(sl, free); - if (fd == -1) return 0; - - for (fp = fdopen(fd, "r"); (s = ss = xgetline(fp)); free(s)) { - // TODO parse and use third level instead of skipping it here - if (s[strspn(s, " \t")]=='#' || strstart(&ss, "\t\t")) continue; - - // Switch to device class list? - if (strstart(&ss, "C ") && and) { - *and = ids; - and = 0; - } - fd = estrtol(sss = ss, &ss, 16); - if (ss>sss && *ss++==' ') { - while (isspace(*ss)) ss++; - new = xmalloc(sizeof(*new)+strlen(ss)+1); - new->child = 0; - new->id = fd; - strcpy(new->name, ss); - if (!ids || *s!='\t') { - new->next = ids; - ids = new; - } else { - new->next = ids->child; - ids->child = new; - } - } - } - fclose(fp); - - return ids; -} - -static int list_usb(struct dirtree *new) -{ - int busnum = 0, devnum = 0, pid = 0, vid = 0; - char *n1, *n2; - - if (!new->parent) return DIRTREE_RECURSE; - if (7 == scan_uevent(new, 3, (struct scanloop[]){{"BUSNUM=%u", &busnum, 0}, - {"DEVNUM=%u", &devnum, 0}, {"PRODUCT=%x/%x", &pid, &vid}})) - { - get_names(TT.ids, pid, vid, &n1, &n2); - printf("Bus %03d Device %03d: ID %04x:%04x %s %s\n", - busnum, devnum, pid, vid, n1, n2); - } - - return 0; -} - -void lsusb_main(void) -{ - // Parse http://www.linux-usb.org/usb.ids file (if available) - TT.ids = parse_dev_ids("usb.ids", 0); - dirtree_read("/sys/bus/usb/devices/", list_usb); -} - -#define FOR_lspci -#include "generated/flags.h" - -// TODO: -v -static int list_pci(struct dirtree *new) -{ - char *driver = 0, buf[16], *ss, *names[3]; - int cvd[3] = {0}, ii, revision = 0; - off_t len = sizeof(toybuf); - /* skip 0000: part by default */ - char *bus = strchr(new->name, ':') + 1; - -// Output formats: -n, -nn, -m, -nm, -nnm, -k - - if (!new->parent) return DIRTREE_RECURSE; - if (!bus || strlen(new->name)<6) return 0; - TT.count = 0; - - // Load revision - sprintf(toybuf, "%s/revision", new->name); - if (readfileat(dirtree_parentfd(new), ss = toybuf, toybuf, &len)) { - strstart(&ss, "0x"); - sscanf(ss, "%x", &revision); - } - - // Load uevent data, look up names in database - if (6>scan_uevent(new, 3, (struct scanloop[]){{"DRIVER=", &driver, 0}, - {"PCI_CLASS=%x", cvd, 0}, {"PCI_ID=%x:%x", cvd+1, cvd+2}})) return 0; - get_names(TT.class, 255&(cvd[0]>>16), 255&(cvd[0]>>8), names, names); - get_names(TT.ids, cvd[1], cvd[2], names+1, names+2); - if (!FLAG(e)) cvd[0] >>= 8; - - // Output line according to flags - if (FLAG(D) || strncmp(new->name, "0000:", bus-new->name)) bus = new->name; - printf("%s", bus); - for (ii = 0; ii<3; ii++) { - sprintf(buf, "%0*x", 6-2*(ii||!FLAG(e)), cvd[ii]); - if (!TT.n) printf(FLAG(m) ? " \"%s\"" : ": %s"+(ii!=1), names[ii] ? : buf); - else if (TT.n==1) printf(FLAG(m) ? " \"%s\"" : (ii==2)?"%s ":" %s:", buf); - else if (!FLAG(m)) { - // This one permutes the order, so do it all first time and abort loop - printf(" %s [%s]: %s %s [%04x:%04x]", names[0], buf, names[1], names[2], - cvd[1], cvd[2]); - break; - } else printf(" \"%s [%s]\"", names[ii], buf); - } - if (revision) printf(FLAG(m) ? " -r%02x" : " (rev %02x)", revision); - if (FLAG(k) && driver) printf(FLAG(m) ? " \"%s\"" : " %s", driver); - xputc('\n'); - - if (TT.x) { - FILE *fp; - int b, col = 0, max = (TT.x >= 4) ? 4096 : ((TT.x >= 3) ? 256 : 64); - - snprintf(toybuf, sizeof(toybuf), "/sys/bus/pci/devices/%s/config", new->name); - fp = xfopen(toybuf, "r"); - while ((b = fgetc(fp)) != EOF) { - if ((col % 16) == 0) printf("%02x: ", col & 0xf0); - printf("%02x ", (b & 0xff)); - if ((++col % 16) == 0) xputc('\n'); - if (col == max) break; - } - xputc('\n'); - fclose(fp); - } - - return 0; -} - -void lspci_main(void) -{ - // Parse https://pci-ids.ucw.cz/v2.2/pci.ids (if available) - if (TT.n != 1) TT.class = parse_dev_ids("pci.ids", (void *)&TT.ids); - dirtree_read("/sys/bus/pci/devices/", list_pci); -} diff --git a/update/toys/other/nsenter.c b/update/toys/other/nsenter.c deleted file mode 100644 index bafed47..0000000 --- a/update/toys/other/nsenter.c +++ /dev/null @@ -1,166 +0,0 @@ -/* nsenter.c - Enter existing namespaces - * - * Copyright 2014 Andy Lutomirski - * - * See http://man7.org/linux/man-pages/man1/nsenter.1.html - * - * unshare.c - run command in new context - * - * Copyright 2011 Rob Landley - * - * See http://man7.org/linux/man-pages/man1/unshare.1.html - * - -// Note: flags go in same order (right to left) for shared subset -USE_NSENTER(NEWTOY(nsenter, "<1a(all)F(no-fork)t#<1(target)C(cgroup):; i(ipc):; m(mount):; n(net):; p(pid):; u(uts):; U(user):; ", TOYFLAG_USR|TOYFLAG_BIN|TOYFLAG_STAYROOT)) -USE_UNSHARE(NEWTOY(unshare, "<1^a(all)f(fork)r(map-root-user)C(cgroup):; i(ipc):; m(mount):; n(net):; p(pid):; u(uts):; U(user):; ", TOYFLAG_USR|TOYFLAG_BIN|TOYFLAG_STAYROOT)) - -config UNSHARE - bool "unshare" - default y - help - usage: unshare [-imnpuUr] COMMAND... - - Create new container namespace(s) for this process and its children, allowing - the new set of processes to have a different view of the system than the - parent process. - - -a Unshare all supported namespaces - -f Fork command in the background (--fork) - -r Become root (map current euid/egid to 0/0, implies -U) (--map-root-user) - - Available namespaces: - -C Control groups (--cgroup) - -i SysV IPC (message queues, semaphores, shared memory) (--ipc) - -m Mount/unmount tree (--mount) - -n Network address, sockets, routing, iptables (--net) - -p Process IDs and init (--pid) - -u Host and domain names (--uts) - -U UIDs, GIDs, capabilities (--user) - - Each namespace can take an optional argument, a persistent mountpoint usable - by the nsenter command to add new processes to that the namespace. (Specify - multiple namespaces to unshare separately, ala -c -i -m because -cim is -c - with persistent mount "im".) - -config NSENTER - bool "nsenter" - default y - help - usage: nsenter [-t pid] [-F] [-i] [-m] [-n] [-p] [-u] [-U] COMMAND... - - Run COMMAND in an existing (set of) namespace(s). - - -a Enter all supported namespaces (--all) - -F don't fork, even if -p is used (--no-fork) - -t PID to take namespaces from (--target) - - The namespaces to switch are: - - -C Control groups (--cgroup) - -i SysV IPC: message queues, semaphores, shared memory (--ipc) - -m Mount/unmount tree (--mount) - -n Network address, sockets, routing, iptables (--net) - -p Process IDs and init, will fork unless -F is used (--pid) - -u Host and domain names (--uts) - -U UIDs, GIDs, capabilities (--user) - - If -t isn't specified, each namespace argument must provide a path - to a namespace file, ala "-i=/proc/$PID/ns/ipc" -*/ - -#define FOR_nsenter -#include "toys.h" -#include - -#define unshare(flags) syscall(SYS_unshare, flags) -#define setns(fd, nstype) syscall(SYS_setns, fd, nstype) - -GLOBALS( - char *UupnmiC[7]; - long t; -) - -// Code that must run in unshare's flag context -#define FOR_unshare -#include - -static void write_ugid_map(char *map, unsigned eugid) -{ - int fd = xopen(map, O_WRONLY); - - dprintf(fd, "0 %u 1", eugid); - xclose(fd); -} - -static int test_a() { return FLAG(a); } -static int test_r() { return FLAG(r); } -static int test_f() { return FLAG(f); } - -// Shift back to the context GLOBALS lives in (I.E. matching the filename). -#define FOR_nsenter -#include - -void unshare_main(void) -{ - char *nsnames = "user\0uts\0pid\0net\0mnt\0ipc\0cgroup"; - unsigned flags[]={CLONE_NEWUSER, CLONE_NEWUTS, CLONE_NEWPID, CLONE_NEWNET, - CLONE_NEWNS, CLONE_NEWIPC, CLONE_NEWCGROUP}, f = 0; - int i, fd; - - // Create new namespace(s)? - if (CFG_UNSHARE && *toys.which->name=='u') { - // For -r, we have to save our original [ug]id before calling unshare() - int euid = geteuid(), egid = getegid(); - - // unshare -U does not imply -r, so we cannot use [+rU] - if (test_r()) toys.optflags |= FLAG_U; - - for (i = 0; i= 0) { - xwrite(fd, "deny", 4); - close(fd); - } - - write_ugid_map("/proc/self/uid_map", euid); - write_ugid_map("/proc/self/gid_map", egid); - } - - if (test_f()) { - toys.exitval = xrun(toys.optargs); - - return; - } - // Bind to existing namespace(s)? - } else if (CFG_NSENTER) { - for (i = 0; i - * Copyright 2013 Kyungwan Han - * - * No Standard. - * - * TODO: two passes so we can auto-size the columns? - -USE_PMAP(NEWTOY(pmap, "<1pqx", TOYFLAG_USR|TOYFLAG_BIN)) - -config PMAP - bool "pmap" - default y - help - usage: pmap [-pqx] PID... - - Report the memory map of a process or processes. - - -p Show full paths - -q Do not show header or footer - -x Show the extended format -*/ - -#define FOR_pmap -#include "toys.h" - -void pmap_main(void) -{ - char **optargs, *line = 0; - size_t len = 0; - - for (optargs = toys.optargs; *optargs; optargs++) { - long long start, end, pss, tpss=0, dirty, tdirty=0, swap, tswap=0, total=0; - char *name = 0, *k = "K"+FLAG(x), mode[5]; - pid_t pid = atolx(*optargs); - int extras = 0, off, count; - FILE *fp; - - sprintf(toybuf, "/proc/%u/cmdline", pid); - if (!(name = readfile(toybuf, 0, 0))) { - error_msg("no %s", toybuf); - continue; - } - xprintf("%d: %s\n", pid, name); - free(name); - - // Only bother scanning the more verbose smaps file in -x mode. - sprintf(toybuf, "/proc/%u/%smaps", pid, "s"+!FLAG(x)); - if (!(fp = fopen(toybuf, "r"))) { - error_msg("no %s", toybuf); - continue; - } - - if (FLAG(x) && !FLAG(q)) - xprintf("Address%*cKbytes PSS Dirty Swap Mode Mapping\n", - (int)(sizeof(long)*2)-5, ' '); - - while (getline(&line, &len, fp) > 0) { - count = sscanf(line, "%llx-%llx %4s %*s %*s %*s %n", &start, &end, mode, - &off); - if (count == 3) { - name = line[off] ? line+off : " [anon]\n"; - if (mode[3] == 'p') mode[3] = '-'; - total += end = (end-start)/1024; - printf("%0*llx % *lld%s ", (int)(2*sizeof(long)), start, 6+FLAG(x), - end, k); - if (FLAG(x)) { - strcpy(toybuf, name); - name = toybuf; - continue; - } - } else { - if (sscanf(line, "Pss: %lld", &pss) || - sscanf(line, "Private_Dirty: %lld", &dirty) || - sscanf(line, "Swap: %lld", &swap)) extras++; - if (extras==3) { - printf("% 7lld %7lld %7lld ", pss, dirty, swap); - tpss += pss; - tdirty += dirty; - tswap += swap; - extras = 0; - } else continue; - } - - xprintf("%s- %s%s", mode, *name == '[' ? " " : "", - FLAG(p) ? name : basename(name)); - } - - if (!FLAG(q)) { - if (FLAG(x)) { - xprintf("---------------- ------ ------ ------ ------\n" + - ((sizeof(long)==4)?8:0)); - } - printf("total% *lld%s", 2*(int)(sizeof(long)+1)+FLAG(x), total, k); - if (FLAG(x)) printf("% 8lld% 8lld% 8lld", tpss, tdirty, tswap); - xputc('\n'); - } - - fclose(fp); - } - free(line); -} diff --git a/update/toys/other/setsid.c b/update/toys/other/setsid.c deleted file mode 100644 index c6e0c53..0000000 --- a/update/toys/other/setsid.c +++ /dev/null @@ -1,58 +0,0 @@ -/* setsid.c - Run program in a new session ID. - * - * Copyright 2006 Rob Landley - -USE_SETSID(NEWTOY(setsid, "^<1wc@d[!dc]", TOYFLAG_USR|TOYFLAG_BIN)) - -config SETSID - bool "setsid" - default y - help - usage: setsid [-cdw] command [args...] - - Run process in a new session. - - -d Detach from tty - -c Control tty (repeat to steal) - -w Wait for child (and exit with its status) -*/ - -#define FOR_setsid -#include "toys.h" - -GLOBALS( - long c; -) - -void setsid_main(void) -{ - int i; - - // setsid() fails if we're already session leader, ala "exec setsid" from sh. - // Second call can't fail, so loop won't continue endlessly. - while (setsid()<0) { - pid_t pid; - - // This must be before vfork() or tcsetpgrp() will hang waiting for parent. - setpgid(0, 0); - - pid = XVFORK(); - if (pid) { - i = 0; - if (FLAG(w)) { - i = 127; - if (pid>0) i = xwaitpid(pid); - } - _exit(i); - } - } - - if (FLAG(c)) { - ioctl(0, TIOCSCTTY, TT.c>1); - tcsetpgrp(0, getpid()); - } if (FLAG(d) && (i = open("/dev/tty", O_RDONLY)) != -1) { - ioctl(i, TIOCNOTTY); - close(i); - } - xexec(toys.optargs); -} diff --git a/update/toys/other/stat.c b/update/toys/other/stat.c deleted file mode 100644 index 463aa46..0000000 --- a/update/toys/other/stat.c +++ /dev/null @@ -1,204 +0,0 @@ -/* stat.c : display file or file system status - * Copyright 2012 - * Copyright 2013 - -USE_STAT(NEWTOY(stat, "<1c:(format)fLt", TOYFLAG_BIN)) - -config STAT - bool stat - default y - help - usage: stat [-tfL] [-c FORMAT] FILE... - - Display status of files or filesystems. - - -c Output specified FORMAT string instead of default - -f Display filesystem status instead of file status - -L Follow symlinks - -t terse (-c "%n %s %b %f %u %g %D %i %h %t %T %X %Y %Z %o") - (with -f = -c "%n %i %l %t %s %S %b %f %a %c %d") - - The valid format escape sequences for files: - %a Access bits (octal) |%A Access bits (flags)|%b Size/512 - %B Bytes per %b (512) |%C Security context |%d Device ID (dec) - %D Device ID (hex) |%f All mode bits (hex)|%F File type - %g Group ID |%G Group name |%h Hard links - %i Inode |%m Mount point |%n Filename - %N Long filename |%o I/O block size |%s Size (bytes) - %t Devtype major (hex) |%T Devtype minor (hex)|%u User ID - %U User name |%x Access time |%X Access unix time - %y Modification time |%Y Mod unix time |%z Creation time - %Z Creation unix time - - The valid format escape sequences for filesystems: - %a Available blocks |%b Total blocks |%c Total inodes - %d Free inodes |%f Free blocks |%i File system ID - %l Max filename length |%n File name |%s Best transfer size - %S Actual block size |%t FS type (hex) |%T FS type (driver name) -*/ - -#define FOR_stat -#include "toys.h" - -GLOBALS( - char *c; - - union { - struct stat st; - struct statfs sf; - } stat; - char *file, *pattern; - int patlen; -) - -// Force numeric output to long long instead of manually typecasting everything -// and safely parse length prefix -static void out(char c, long long val) -{ - sprintf(toybuf, "%.*sll%c", TT.patlen, TT.pattern, c); - printf(toybuf, val); -} - -// Output string with parsed length prefix -static void strout(char *val) -{ - sprintf(toybuf, "%.*ss", TT.patlen, TT.pattern); - printf(toybuf, val); -} - -static void date_stat_format(struct timespec *ts) -{ - strout(format_iso_time(toybuf+128, sizeof(toybuf)-128, ts)); -} - -static void print_stat(char type) -{ - struct stat *stat = (struct stat *)&TT.stat; - - if (type == 'a') out('o', stat->st_mode&~S_IFMT); - else if (type == 'A') { - char str[11]; - - mode_to_string(stat->st_mode, str); - strout(str); - } else if (type == 'b') out('u', stat->st_blocks); - else if (type == 'B') out('d', 512); - else if (type == 'C') { - char *context = NULL; - - strout(lsm_get_context(TT.file, &context) != -1 ? context : "?"); - free(context); - } else if (type == 'd') out('d', stat->st_dev); - else if (type == 'D') out('x', stat->st_dev); - else if (type == 'f') out('x', stat->st_mode); - else if (type == 'F') { - char *t = "character device\0directory\0block device\0" \ - "regular file\0symbolic link\0socket\0FIFO (named pipe)"; - int i, filetype = stat->st_mode & S_IFMT; - - for (i = 1; filetype != (i*8192) && i < 7; i++) t += strlen(t)+1; - if (!stat->st_size && filetype == S_IFREG) t = "regular empty file"; - strout(t); - } else if (type == 'g') out('u', stat->st_gid); - else if (type == 'G') strout(getgroupname(stat->st_gid)); - else if (type == 'h') out('u', stat->st_nlink); - else if (type == 'i') out('u', stat->st_ino); - else if (type == 'm') { - struct mtab_list *mt = xgetmountlist(0); - dev_t dev = stat->st_rdev ? stat->st_rdev : stat->st_dev; - - // This mount point could exist multiple times, so show oldest. - for (dlist_terminate(mt); mt; mt = mt->next) if (mt->stat.st_dev == dev) { - strout(mt->dir); - break; - } - llist_traverse(mt, free); - } else if (type == 'N') { - printf("%s", TT.file); - if (S_ISLNK(stat->st_mode)) - if (readlink0(TT.file, toybuf, sizeof(toybuf))) - printf(" -> '%s'", toybuf); - } else if (type == 'o') out('u', stat->st_blksize); - else if (type == 's') out('u', stat->st_size); - else if (type == 't') out('x', dev_major(stat->st_rdev)); - else if (type == 'T') out('x', dev_minor(stat->st_rdev)); - else if (type == 'u') out('u', stat->st_uid); - else if (type == 'U') strout(getusername(stat->st_uid)); - else if (type == 'x') date_stat_format(&stat->st_atim); - else if (type == 'X') out('u', stat->st_atime); - else if (type == 'y') date_stat_format(&stat->st_mtim); - else if (type == 'Y') out('u', stat->st_mtime); - else if (type == 'z') date_stat_format(&stat->st_ctim); - else if (type == 'Z') out('u', stat->st_ctime); - else putchar('?'); -} - -static void print_statfs(char type) { - struct statfs *statfs = (struct statfs *)&TT.stat; - - if (type == 'a') out('u', statfs->f_bavail); - else if (type == 'b') out('u', statfs->f_blocks); - else if (type == 'c') out('u', statfs->f_files); - else if (type == 'd') out('u', statfs->f_ffree); - else if (type == 'f') out('u', statfs->f_bfree); - else if (type == 'l') out('d', pathconf(TT.file, _PC_NAME_MAX)); - else if (type == 't') out('x', statfs->f_type); - else if (type == 'T') strout(fs_type_name(statfs)); - else if (type == 'i') { - int *val = (int *) &statfs->f_fsid; - char buf[32]; - - sprintf(buf, "%08x%08x", val[0], val[1]); - strout(buf); - } else if (type == 's') out('d', statfs_bsize(statfs)); - else if (type == 'S') out('d', statfs_frsize(statfs)); - else strout("?"); -} - -void stat_main(void) -{ - int i; - char *format, *f; - - if (FLAG(t)) format = FLAG(f) - ? "%n %i %l %t %s %S %b %f %a %c %d" - : "%n %s %b %f %u %g %D %i %h %t %T %X %Y %Z %o"; - else format = FLAG(f) - ? " File: \"%n\"\n ID: %i Namelen: %l Type: %T\n" - "Block Size: %s Fundamental block size: %S\n" - "Blocks: Total: %b\tFree: %f\tAvailable: %a\n" - "Inodes: Total: %c\tFree: %d" - : " File: %N\n Size: %s\t Blocks: %b\t IO Blocks: %B\t %F\n" - "Device: %Dh/%dd\t Inode: %i\t Links: %h\t Device type: %t,%T\n" - "Access: (%04a/%A)\tUid: (%5u/%8U)\tGid: (%5g/%8G)\n" - "Access: %x\nModify: %y\nChange: %z"; - - if (FLAG(c)) format = TT.c; - - // loop through files listed on command line - for (i = 0; toys.optargs[i]; i++) { - - // stat the file or filesystem - TT.file = toys.optargs[i]; - if (FLAG(f) && !statfs(TT.file, (void *)&TT.stat)); - else if (FLAG(f) || (FLAG(L) ? stat : lstat)(TT.file, (void *)&TT.stat)) { - perror_msg("'%s'", TT.file); - continue; - } - - // parse format and print what it says - for (f = format; *f; f++) { - if (*f != '%' || !f[1]) putchar(*f); - else if (f[1]=='%') putchar(*f++); - else { - f = next_printf(f, &TT.pattern); - TT.patlen = f-TT.pattern; - if (!*f || TT.patlen>99) error_exit("bad %s", TT.pattern); - if (*f == 'n') strout(TT.file); - else if (FLAG(f)) print_statfs(*f); - else print_stat(*f); - } - } - xputc('\n'); - } -} diff --git a/update/toys/other/sysctl.c b/update/toys/other/sysctl.c deleted file mode 100644 index 7a2cba6..0000000 --- a/update/toys/other/sysctl.c +++ /dev/null @@ -1,149 +0,0 @@ -/* sysctl.c - A utility to read and manipulate the sysctl parameters. - * - * Copyright 2014 Bilal Qureshi - * Copyright 2014 Kyungwan Han - * - * No Standard - -USE_SYSCTL(NEWTOY(sysctl, "^neNqwpaA[!ap][!aq][!aw][+aA]", TOYFLAG_SBIN)) - -config SYSCTL - bool "sysctl" - default y - help - usage: sysctl [-aeNnqw] [-p [FILE] | KEY[=VALUE]...] - - Read/write system control data (under /proc/sys). - - -a Show all values - -e Don't warn about unknown keys - -N Don't print key values - -n Don't print key names - -p Read values from FILE (default /etc/sysctl.conf) - -q Don't show value after write - -w Only write values (object to reading) -*/ -#define FOR_sysctl -#include "toys.h" - -// Null terminate at =, return value -static char *split_key(char *key) -{ - char *value = strchr(key, '='); - - if (value) *(value++)=0; - - return value; -} - -static void replace_char(char *str, char old, char new) -{ - for (; *str; str++) if (*str == old) *str = new; -} - -static void key_error(char *key) -{ - if (errno != ENOENT) perror_msg("key '%s'", key); - else if (!FLAG(e)) error_msg("unknown key '%s'", key); -} - -static int write_key(char *path, char *key, char *value) -{ - int fd = open(path, O_WRONLY); - - if (fd < 0) { - key_error(key); - - return 0; - } - xwrite(fd, value, strlen(value)); - xclose(fd); - - return 1; -} - -// Display all keys under a path -static int do_show_keys(struct dirtree *dt) -{ - char *path, *data, *key; - - if (!dirtree_notdotdot(dt)) return 0; // Skip . and .. - if (S_ISDIR(dt->st.st_mode)) return DIRTREE_RECURSE; - - path = dirtree_path(dt, 0); - data = readfile(path, 0, 0); - replace_char(key = path + 10, '/', '.'); // skip "/proc/sys/" - if (!data) key_error(key); - else { - // Print the parts that aren't switched off by flags. - if (!FLAG(n)) xprintf("%s", key); - if (!FLAG(N) && !FLAG(n)) xprintf(" = "); - for (key = data+strlen(data); key > data && isspace(*--key); *key = 0); - if (!FLAG(N)) xprintf("%s", data); - if (!FLAG(N) || !FLAG(n)) xputc('\n'); - } - - free(data); - free(path); - - return 0; -} - -// Read/write entries under a key. Accepts "key=value" in key if !value -static void process_key(char *key, char *value) -{ - char *path; - - if (!value) value = split_key(key); - if (FLAG(w) && !value) return error_msg("'%s' not key=value", key); - path = xmprintf("/proc/sys/%s", key); - replace_char(path, '.', '/'); - // Note: failure to assign to a non-leaf node suppresses the display. - if (!(value && (!write_key(path, key, value) || FLAG(q)))) { - if (!access(path, R_OK)) dirtree_read(path, do_show_keys); - else key_error(key); - } - free(path); -} - -void sysctl_main() -{ - char **args = 0; - - // Display all keys - if (FLAG(a)) dirtree_read("/proc/sys", do_show_keys); - - // read file - else if (FLAG(p)) { - FILE *fp = xfopen(*toys.optargs ? *toys.optargs : "/etc/sysctl.conf", "r"); - size_t len; - - for (;;) { - char *line = 0, *key, *val; - - if (-1 == (len = getline(&line, &len, fp))) break; - key = line; - while (isspace(*key)) key++; - if (*key == '#' || *key == ';' || !*key) continue; - while (len && isspace(line[len-1])) line[--len] = 0; - if (!(val = split_key(line))) { - error_msg("'%s' not key=value", line); - continue; - } - - // Trim whitespace around = - len = (val-line)-1; - while (len && isspace(line[len-1])) line[--len] = 0; - while (isspace(*val)) val++;; - - process_key(key, val); - free(line); - } - fclose(fp); - - // Loop through arguments, displaying or assigning as appropriate - } else { - if (!*toys.optargs) help_exit("Needs 1 arg"); - for (args = toys.optargs; *args; args++) process_key(*args, 0); - } -} diff --git a/update/toys/other/timeout.c b/update/toys/other/timeout.c deleted file mode 100644 index 4c4288e..0000000 --- a/update/toys/other/timeout.c +++ /dev/null @@ -1,107 +0,0 @@ -/* timeout.c - Run command line with a timeout - * - * Copyright 2013 Rob Landley - * - * No standard - -USE_TIMEOUT(NEWTOY(timeout, "<2^(foreground)(preserve-status)vk:s(signal):i", TOYFLAG_USR|TOYFLAG_BIN|TOYFLAG_ARGFAIL(125))) - -config TIMEOUT - bool "timeout" - default y - help - usage: timeout [-iv] [-k DURATION] [-s SIGNAL] DURATION COMMAND... - - Run command line as a child process, sending child a signal if the - command doesn't exit soon enough. - - DURATION can be a decimal fraction. An optional suffix can be "m" - (minutes), "h" (hours), "d" (days), or "s" (seconds, the default). - - -i Only kill for inactivity (restart timeout when command produces output) - -k Send KILL signal if child still running this long after first signal - -s Send specified signal (default TERM) - -v Verbose - --foreground Don't create new process group - --preserve-status Exit with the child's exit status -*/ - -#define FOR_timeout -#include "toys.h" - -GLOBALS( - char *s, *k; - - struct pollfd pfd; - sigjmp_buf sj; - int fds[2], pid, rc; -) - -static void handler(int sig, siginfo_t *si) -{ - TT.rc = si->si_status + ((si->si_code!=CLD_EXITED)<<7); - siglongjmp(TT.sj, 1); -} - -static long nantomil(struct timespec *ts) -{ - return ts->tv_sec*1000+ts->tv_nsec/1000000; -} - -static void callback(char *argv[]) -{ - if (!FLAG(foreground)) setpgid(0, 0); -} - -void timeout_main(void) -{ - int ii, ms, nextsig = SIGTERM; - struct timespec tts, kts; - - // Use same ARGFAIL value for any remaining parsing errors - toys.exitval = 125; - xparsetimespec(*toys.optargs, &tts); - if (TT.k) xparsetimespec(TT.k, &kts); - if (TT.s && -1==(nextsig = sig_to_num(TT.s))) error_exit("bad -s: '%s'",TT.s); - - toys.exitval = 0; - TT.pfd.events = POLLIN; - TT.fds[1] = -1; - if (sigsetjmp(TT.sj, 1)) goto done; - xsignal_flags(SIGCHLD, handler, SA_NOCLDSTOP|SA_SIGINFO); - - TT.pid = xpopen_setup(toys.optargs+1, FLAG(i) ? TT.fds : 0, callback); - xsignal(SIGTTIN, SIG_IGN); - xsignal(SIGTTOU, SIG_IGN); - xsignal(SIGTSTP, SIG_IGN); - if (!FLAG(i)) xpipe(TT.fds); - TT.pfd.fd = TT.fds[1]; - ms = nantomil(&tts); - for (;;) { - if (1 != xpoll(&TT.pfd, 1, ms)) { - if (FLAG(v)) - perror_msg("sending signal %s to command %s", num_to_sig(nextsig), - toys.optargs[1]); - toys.exitval = (nextsig==9) ? 137 : 124; - kill(FLAG(foreground) ? TT.pid : -TT.pid, nextsig); - if (!TT.k || nextsig==SIGKILL) break; - nextsig = SIGKILL; - ms = nantomil(&kts); - - continue; - } - if (TT.pfd.revents&POLLIN) { - errno = 0; - if (1>(ii = read(TT.fds[1], toybuf, sizeof(toybuf)))) { - if (errno==EINTR) continue; - break; - } - writeall(1, toybuf, ii); - } - if (TT.pfd.revents&POLLHUP) break; - } -done: - xpclose_both(TT.pid, TT.fds); - - if (FLAG(preserve_status) || !toys.exitval) toys.exitval = TT.rc; -} diff --git a/update/toys/pending/route.c b/update/toys/pending/route.c deleted file mode 100644 index 3b0e5be..0000000 --- a/update/toys/pending/route.c +++ /dev/null @@ -1,383 +0,0 @@ -/* route.c - Display/edit network routing table. - * - * Copyright 2012 Ranjan Kumar - * Copyright 2013 Kyungwan Han - * Copyright 2020 Eric Molitor - * - * No Standard - * - * route add -net target 10.0.0.0 netmask 255.0.0.0 dev eth0 - * route del delete - * delete net route, must match netmask, informative error message - * - * mod dyn reinstate metric netmask gw mss window irtt dev - -USE_ROUTE(NEWTOY(route, "?neA:", TOYFLAG_SBIN)) -config ROUTE - bool "route" - default n - help - usage: route [-ne] [-A [inet|inet6]] [add|del TARGET [OPTIONS]] - - Display, add or delete network routes in the "Forwarding Information Base", - which send packets out a network interface to an address. - - -n Show numerical addresses (no DNS lookups) - -e display netstat fields - - Assigning an address to an interface automatically creates an appropriate - network route ("ifconfig eth0 10.0.2.15/8" does "route add 10.0.0.0/8 eth0" - for you), although some devices (such as loopback) won't show it in the - table. For machines more than one hop away, you need to specify a gateway - (ala "route add default gw 10.0.2.2"). - - The address "default" is a wildcard address (0.0.0.0/0) matching all - packets without a more specific route. - - Available OPTIONS include: - reject - blocking route (force match failure) - dev NAME - force matching packets out this interface (ala "eth0") - netmask - old way of saying things like ADDR/24 - gw ADDR - forward packets to gateway ADDR -*/ - -#define FOR_route -#include "toys.h" -#define _LINUX_SYSINFO_H // workaround for musl bug -#include - -GLOBALS( - char *A; -) - -struct _arglist { - char *arg; - int action; -}; - -static struct _arglist arglist1[] = { - { "add", 1 }, { "del", 2 }, - { "delete", 2 }, { NULL, 0 } -}; - -static struct _arglist arglist2[] = { - { "-net", 1 }, { "-host", 2 }, - { NULL, 0 } -}; - -void xsend(int sockfd, void *buf, size_t len) -{ - if (send(sockfd, buf, len, 0) != len) perror_exit("xsend"); -} - -int xrecv(int sockfd, void *buf, size_t len) -{ - int msg_len = recv(sockfd, buf, len, 0); - if (msg_len < 0) perror_exit("xrecv"); - - return msg_len; -} - -void addAttr(struct nlmsghdr *nl, int maxlen, void *attr, int type, int len) -{ - struct rtattr *rt; - int rtlen = RTA_LENGTH(len); - if (NLMSG_ALIGN(nl->nlmsg_len) + rtlen > maxlen) perror_exit("addAttr"); - rt = (struct rtattr*)((char *)nl + NLMSG_ALIGN(nl->nlmsg_len)); - rt->rta_type = type; - rt->rta_len = rtlen; - memcpy(RTA_DATA(rt), attr, len); - nl->nlmsg_len = NLMSG_ALIGN(nl->nlmsg_len) + rtlen; -} - -static void get_hostname(sa_family_t f, void *a, char *dst, size_t len) { - size_t a_len = (AF_INET6 == f) ? sizeof(struct in6_addr) : sizeof(struct in_addr); - - struct hostent *host = gethostbyaddr(a, a_len, f); - if (host) xstrncpy(dst, host->h_name, len); -} - -static void display_routes(sa_family_t f) -{ - int fd, msg_hdr_len, route_protocol; - struct { - struct nlmsghdr nl; - struct rtmsg rt; - } req; - struct nlmsghdr buf[8192 / sizeof(struct nlmsghdr)]; - struct nlmsghdr *msg_hdr_ptr; - struct rtmsg *route_entry; - struct rtattr *rteattr; - - fd = xsocket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE); - - memset(&req, 0, sizeof(req)); - req.nl.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg)); - req.nl.nlmsg_type = RTM_GETROUTE; - req.nl.nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP; - req.nl.nlmsg_pid = getpid(); - req.nl.nlmsg_seq = 1; - req.rt.rtm_family = f; - req.rt.rtm_table = RT_TABLE_MAIN; - xsend(fd, &req, sizeof(req)); - - if (f == AF_INET) { - xprintf("Kernel IP routing table\n" - "Destination Gateway Genmask Flags %s Iface\n", - FLAG(e) ? " MSS Window irtt" : "Metric Ref Use"); - } else { - xprintf("Kernel IPv6 routing table\n" - "%-31s%-26s Flag Metric Ref Use If\n", "Destination", "Next Hop"); - } - - msg_hdr_len = xrecv(fd, buf, sizeof(buf)); - msg_hdr_ptr = buf; - while (msg_hdr_ptr->nlmsg_type != NLMSG_DONE) { - while (NLMSG_OK(msg_hdr_ptr, msg_hdr_len)) { - route_entry = NLMSG_DATA(msg_hdr_ptr); - route_protocol = route_entry->rtm_protocol; - - // Annoyingly NLM_F_MATCH is not yet implemented so even if we pass in - // RT_TABLE_MAIN with RTM_GETROUTE it still returns everything so we - // have to filter here. - if (route_entry->rtm_table == RT_TABLE_MAIN) { - int route_attribute_len; - char dest[INET6_ADDRSTRLEN], gate[INET6_ADDRSTRLEN], netmask[32], - flags[10] = "U", if_name[IF_NAMESIZE] = "-"; - unsigned priority = 0, mss = 0, win = 0, irtt = 0, ref = 0, use = 0, - route_netmask, metric_len; - struct in_addr netmask_addr; - struct rtattr *metric; - struct rta_cacheinfo *cache_info; - - if (f == AF_INET) { - strcpy(dest, FLAG(n) ? "0.0.0.0" : "default"); - strcpy(gate, FLAG(n) ? "*" : "0.0.0.0"); - strcpy(netmask, "0.0.0.0"); - } else { - strcpy(dest, "::"); - strcpy(gate, "::"); - } - - route_netmask = route_entry->rtm_dst_len; - if (route_netmask == 0) netmask_addr.s_addr = ~((in_addr_t) -1); - else netmask_addr.s_addr = htonl(~((1 << (32 - route_netmask)) - 1)); - inet_ntop(AF_INET, &netmask_addr, netmask, sizeof(netmask)); - - rteattr = RTM_RTA(route_entry); - route_attribute_len = RTM_PAYLOAD(msg_hdr_ptr); - while (RTA_OK(rteattr, route_attribute_len)) { - switch (rteattr->rta_type) { - case RTA_DST: - if (FLAG(n)) inet_ntop(f, RTA_DATA(rteattr), dest, sizeof(dest)); - else get_hostname(f, RTA_DATA(rteattr), dest, sizeof(dest)); - break; - - case RTA_GATEWAY: - if (FLAG(n)) inet_ntop(f, RTA_DATA(rteattr), gate, sizeof(dest)); - else get_hostname(f, RTA_DATA(rteattr), gate, sizeof(dest)); - strcat(flags, "G"); - break; - - case RTA_PRIORITY: - priority = *(unsigned *)RTA_DATA(rteattr); - break; - - case RTA_OIF: - if_indextoname(*(int *)RTA_DATA(rteattr), if_name); - break; - - case RTA_METRICS: - metric_len = RTA_PAYLOAD(rteattr); - for (metric = RTA_DATA(rteattr); RTA_OK(metric, metric_len); - metric = RTA_NEXT(metric, metric_len)) - if (metric->rta_type == RTAX_ADVMSS) - mss = *(unsigned *)RTA_DATA(metric); - else if (metric->rta_type == RTAX_WINDOW) - win = *(unsigned *)RTA_DATA(metric); - else if (metric->rta_type == RTAX_RTT) - irtt = (*(unsigned *)RTA_DATA(metric))/8; - break; - - case RTA_CACHEINFO: - cache_info = RTA_DATA(rteattr); - ref = cache_info->rta_clntref; - use = cache_info->rta_used; - break; - } - - rteattr = RTA_NEXT(rteattr, route_attribute_len); - } - - if (route_entry->rtm_type == RTN_UNREACHABLE) flags[0] = '!'; - if (route_netmask == 32) strcat(flags, "H"); - if (route_protocol == RTPROT_REDIRECT) strcat(flags, "D"); - - if (f == AF_INET) { - xprintf("%-15.15s %-15.15s %-16s%-6s", dest, gate, netmask, flags); - if (FLAG(e)) xprintf("%5d %-5d %6d %s\n", mss, win, irtt, if_name); - else xprintf("%-6d %-2d %7d %s\n", priority, ref, use, if_name); - } else { - char *dest_with_mask = xmprintf("%s/%u", dest, route_netmask); - xprintf("%-30s %-26s %-4s %-6d %-4d %2d %-8s\n", - dest_with_mask, gate, flags, priority, ref, use, if_name); - free(dest_with_mask); - } - } - msg_hdr_ptr = NLMSG_NEXT(msg_hdr_ptr, msg_hdr_len); - } - - msg_hdr_len = xrecv(fd, buf, sizeof(buf)); - msg_hdr_ptr = buf; - } - - xclose(fd); -} - -// find parameter (add/del/net/host) in list, return appropriate action or 0. -static int get_action(char ***argv, struct _arglist *list) -{ - struct _arglist *alist; - - if (!**argv) return 0; - for (alist = list; alist->arg; alist++) { //find the given parameter in list - if (!strcmp(**argv, alist->arg)) { - *argv += 1; - return alist->action; - } - } - return 0; -} - -// add/del a route. -static void setroute(sa_family_t f, char **argv) -{ - char *tgtip; - int sockfd, arg2_action; - int action = get_action(&argv, arglist1); //verify the arg for add/del. - struct nlmsghdr buf[8192 / sizeof(struct nlmsghdr)]; - struct nlmsghdr *nlMsg; - struct rtmsg *rtMsg; - - if (!action || !*argv) help_exit("setroute"); - arg2_action = get_action(&argv, arglist2); //verify the arg for -net or -host - if (!*argv) help_exit("setroute"); - tgtip = *argv++; - sockfd = xsocket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE); - memset(buf, 0, sizeof(buf)); - nlMsg = (struct nlmsghdr *) buf; - rtMsg = (struct rtmsg *) NLMSG_DATA(nlMsg); - - nlMsg->nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg)); - - //TODO(emolitor): Improve action and arg2_action handling - if (action == 1) { // Add - nlMsg->nlmsg_type = RTM_NEWROUTE; - nlMsg->nlmsg_flags = NLM_F_REQUEST | NLM_F_CREATE | NLM_F_EXCL; - } else { // Delete - nlMsg->nlmsg_type = RTM_DELROUTE; - nlMsg->nlmsg_flags = NLM_F_REQUEST; - } - - nlMsg->nlmsg_pid = getpid(); - nlMsg->nlmsg_seq = 1; - rtMsg->rtm_family = f; - rtMsg->rtm_table = RT_TABLE_UNSPEC; - rtMsg->rtm_type = RTN_UNICAST; - rtMsg->rtm_protocol = RTPROT_UNSPEC; - rtMsg->rtm_flags = RTM_F_NOTIFY; - rtMsg->rtm_dst_len = rtMsg->rtm_src_len = (f == AF_INET) ? 32 : 128; - - if (arg2_action == 2) rtMsg->rtm_scope = RT_SCOPE_HOST; - - size_t addr_len = sizeof(struct in_addr); - if (f == AF_INET6) addr_len = sizeof(struct in6_addr); - unsigned char addr[sizeof(struct in6_addr)] = {0,}; - - for (; *argv; argv++) { - if (!strcmp(*argv, "mod")) continue; - else if (!strcmp(*argv, "dyn")) continue; - else if (!strcmp(*argv, "reinstate")) continue; - else if (!strcmp(*argv, "reject")) rtMsg->rtm_type = RTN_UNREACHABLE; - else { - if (!argv[1]) show_help(stdout, 1); - - if (!strcmp(*argv, "metric")) { - unsigned int priority = atolx_range(argv[1], 0, UINT_MAX); - addAttr(nlMsg, sizeof(toybuf), &priority, RTA_PRIORITY, sizeof(unsigned int)); - } else if (!strcmp(*argv, "netmask")) { - uint32_t netmask; - char *ptr; - uint32_t naddr[4] = {0,}; - uint64_t plen; - - netmask = (f == AF_INET6) ? 128 : 32; // set default netmask - plen = strtoul(argv[1], &ptr, 0); - - if (!ptr || ptr == argv[1] || *ptr || !plen || plen > netmask) { - if (!inet_pton(f, argv[1], &naddr)) error_exit("invalid netmask"); - if (f == AF_INET) { - uint32_t mask = htonl(*naddr), host = ~mask; - if (host & (host + 1)) error_exit("invalid netmask"); - for (plen = 0; mask; mask <<= 1) ++plen; - if (plen > 32) error_exit("invalid netmask"); - } - } - netmask = plen; - rtMsg->rtm_dst_len = netmask; - } else if (!strcmp(*argv, "gw")) { - if (!inet_pton(f, argv[1], &addr)) error_exit("invalid gw"); - addAttr(nlMsg, sizeof(toybuf), &addr, RTA_GATEWAY, addr_len); - } else if (!strcmp(*argv, "mss")) { - // TODO(emolitor): Add RTA_METRICS support - //set the TCP Maximum Segment Size for connections over this route. - //rt->rt_mtu = atolx_range(argv[1], 64, 65536); - //rt->rt_flags |= RTF_MSS; - } else if (!strcmp(*argv, "window")) { - // TODO(emolitor): Add RTA_METRICS support - //set the TCP window size for connections over this route to W bytes. - //rt->rt_window = atolx_range(argv[1], 128, INT_MAX); //win low - //rt->rt_flags |= RTF_WINDOW; - } else if (!strcmp(*argv, "irtt")) { - // TODO(emolitor): Add RTA_METRICS support - //rt->rt_irtt = atolx_range(argv[1], 0, INT_MAX); - //rt->rt_flags |= RTF_IRTT; - } else if (!strcmp(*argv, "dev")) { - unsigned int if_idx = if_nametoindex(argv[1]); - if (!if_idx) perror_exit("dev"); - addAttr(nlMsg, sizeof(toybuf), &if_idx, RTA_OIF, sizeof(unsigned int)); - } else help_exit("no '%s'", *argv); - argv++; - } - } - - if (strcmp(tgtip, "default") != 0) { - char *prefix = strtok(0, "/"); - - if (prefix) rtMsg->rtm_dst_len = strtoul(prefix, &prefix, 0); - if (!inet_pton(f, strtok(tgtip, "/"), &addr)) error_exit("invalid target"); - addAttr(nlMsg, sizeof(toybuf), &addr, RTA_DST, addr_len); - } else rtMsg->rtm_dst_len = 0; - - xsend(sockfd, nlMsg, nlMsg->nlmsg_len); - xclose(sockfd); -} - -void route_main(void) -{ - if (!*toys.optargs) { - if (!TT.A || !strcmp(TT.A, "inet")) display_routes(AF_INET); - else if (!strcmp(TT.A, "inet6")) display_routes(AF_INET6); - else show_help(stdout, 1); - } else { - if (!TT.A) { - if (toys.optc>1 && strchr(toys.optargs[1], ':')) { - xprintf("WARNING: Implicit IPV6 address using -Ainet6\n"); - TT.A = "inet6"; - } else TT.A = "inet"; - } - - if (!strcmp(TT.A, "inet")) setroute(AF_INET, toys.optargs); - else setroute(AF_INET6, toys.optargs); - } -} diff --git a/update/toys/posix/cpio.c b/update/toys/posix/cpio.c deleted file mode 100644 index 321bbfd..0000000 --- a/update/toys/posix/cpio.c +++ /dev/null @@ -1,324 +0,0 @@ -/* cpio.c - a basic cpio - * - * Copyright 2013 Isaac Dunham - * Copyright 2015 Frontier Silicon Ltd. - * - * see https://www.kernel.org/doc/Documentation/early-userspace/buffer-format.txt - * and http://refspecs.linuxfoundation.org/LSB_4.1.0/LSB-Core-generic/LSB-Core-generic/cpio.html - * and http://pubs.opengroup.org/onlinepubs/7908799/xcu/cpio.html - * - * Yes, that's SUSv2, newer versions removed it, but RPM and initramfs use - * this archive format. We implement (only) the modern "-H newc" variant which - * expanded headers to 110 bytes (first field 6 bytes, rest are 8). - * In order: magic ino mode uid gid nlink mtime filesize devmajor devminor - * rdevmajor rdevminor namesize check - * This is the equivalent of mode -H newc in other implementations. - * We always do --quiet, but accept it as a compatibility NOP. - * - * TODO: export/import linux file list text format ala gen_initramfs_list.sh - * TODO: hardlink support, -A, -0, -a, -L, --sparse - * TODO: --renumber-archives (probably always?) --ignore-devno --reproducible - -USE_CPIO(NEWTOY(cpio, "(ignore-devno)(renumber-inodes)(quiet)(no-preserve-owner)R(owner):md(make-directories)uLH:p|i|t|F:v(verbose)o|[!pio][!pot][!pF]", TOYFLAG_BIN)) - -config CPIO - bool "cpio" - default y - help - usage: cpio -{o|t|i|p DEST} [-dLtuv] [--verbose] [-F FILE] [-R [USER][:GROUP] [--no-preserve-owner] - - Copy files into and out of a "newc" format cpio archive. - - -d Create directories if needed - -F FILE Use archive FILE instead of stdin/stdout - -i Extract from archive into file system (stdin=archive) - -L Follow symlinks - -o Create archive (stdin=list of files, stdout=archive) - -p DEST Copy-pass mode, copy stdin file list to directory DEST - -R USER Replace owner with USER[:GROUP] - -t Test files (list only, stdin=archive, stdout=list of files) - -u Unlink existing files when extracting - -v Verbose - --no-preserve-owner Don't set ownership during extract -*/ - -#define FOR_cpio -#include "toys.h" - -GLOBALS( - char *F, *H, *R; -) - -// Read strings, tail padded to 4 byte alignment. Argument "align" is amount -// by which start of string isn't aligned (usually 0, but header is 110 bytes -// which is 2 bytes off because the first field wasn't expanded from 6 to 8). -static char *strpad(int fd, unsigned len, unsigned align) -{ - char *str; - - align = (align + len) & 3; - if (align) len += (4-align); - xreadall(fd, str = xmalloc(len+1), len); - str[len]=0; // redundant, in case archive is bad - - return str; -} - -//convert hex to uint; mostly to allow using bits of non-terminated strings -static unsigned x8u(char *hex) -{ - unsigned val, inpos = 8, outpos; - char pattern[6]; - - while (*hex == '0') { - hex++; - if (!--inpos) return 0; - } - // Because scanf gratuitously treats %*X differently than printf does. - sprintf(pattern, "%%%dX%%n", inpos); - sscanf(hex, pattern, &val, &outpos); - if (inpos != outpos) error_exit("bad hex"); - - return val; -} - -void cpio_main(void) -{ - int pipe, afd = FLAG(o), reown = !geteuid() && !FLAG(no_preserve_owner), - empty = 1; - pid_t pid = 0; - long Ruid = -1, Rgid = -1; - char *tofree = 0; - - if (TT.R) { - char *group = TT.R+strcspn(TT.R, ":."); - - if (*group) { - Rgid = xgetgid(group+1); - *group = 0; - } - if (group != TT.R) Ruid = xgetuid(TT.R); - } - - // In passthrough mode, parent stays in original dir and generates archive - // to pipe, child does chdir to new dir and reads archive from stdin (pipe). - if (FLAG(p)) { - if (FLAG(d)) { - if (!*toys.optargs) error_exit("need directory for -p"); - if (mkdir(*toys.optargs, 0700) == -1 && errno != EEXIST) - perror_msg("mkdir %s", *toys.optargs); - } - if (toys.stacktop) { - // xpopen() doesn't return from child due to vfork(), instead restarts - // with !toys.stacktop - pid = xpopen(0, &pipe, 0); - afd = pipe; - } else { - // child - toys.optflags |= FLAG_i; - xchdir(*toys.optargs); - } - } - - if (TT.F) { - int perm = FLAG(o) ? O_CREAT|O_WRONLY|O_TRUNC : O_RDONLY; - - afd = xcreate(TT.F, perm, 0644); - } - - // read cpio archive - - if (FLAG(i) || FLAG(t)) for (;; empty = 0) { - char *name, *data; - unsigned mode, uid, gid, timestamp; - int test = FLAG(t), err = 0, size = 0, len; - - free(tofree); - tofree = 0; - // read header, skipping arbitrary leading NUL bytes (concatenated archives) - for (;;) { - if (1>(len = readall(afd, toybuf+size, 110-size))) break; - if (size || *toybuf) { - size += len; - break; - } - for (size = 0; size=0) ? Ruid : x8u(toybuf+22); - gid = (Rgid>=0) ? Rgid : x8u(toybuf+30); - timestamp = x8u(toybuf+46); // unsigned 32 bit, so year 2100 problem - - // (This output is unaffected by --quiet.) - if (FLAG(t) || FLAG(v)) puts(name); - - if (FLAG(u) && !test) if (unlink(name) && errno == EISDIR) rmdir(name); - - if (!test && FLAG(d) && strrchr(name, '/') && mkpath(name)) { - perror_msg("mkpath '%s'", name); - test++; - } - - // Consume entire record even if it couldn't create file, so we're - // properly aligned with next file. - - if (S_ISDIR(mode)) { - if (test) continue; - err = mkdir(name, mode) && (errno != EEXIST && !FLAG(u)); - - // Creading dir/dev doesn't give us a filehandle, we have to refer to it - // by name to chown/utime, but how do we know it's the same item? - // Check that we at least have the right type of entity open, and do - // NOT restore dropped suid bit in this case. - if (S_ISDIR(mode) && reown) { - int fd = open(name, O_RDONLY|O_NOFOLLOW); - struct stat st; - - if (fd != -1 && !fstat(fd, &st) && (st.st_mode&S_IFMT) == (mode&S_IFMT)) - err = fchown(fd, uid, gid); - else err = 1; - - close(fd); - } - } else if (S_ISREG(mode)) { - int fd = test ? 0 : open(name, O_CREAT|O_WRONLY|O_EXCL|O_NOFOLLOW, mode); - - // If write fails, we still need to read/discard data to continue with - // archive. Since doing so overwrites errno, report error now - if (fd < 0) { - perror_msg("create %s", name); - test++; - } - - data = toybuf; - while (size) { - if (size < sizeof(toybuf)) data = strpad(afd, size, 0); - else xreadall(afd, toybuf, sizeof(toybuf)); - if (!test) xwrite(fd, data, data == toybuf ? sizeof(toybuf) : size); - if (data != toybuf) { - free(data); - break; - } - size -= sizeof(toybuf); - } - - if (!test) { - // set owner, restore dropped suid bit - if (reown) err = fchown(fd, uid, gid) && fchmod(fd, mode); - close(fd); - } - } else { - data = S_ISLNK(mode) ? strpad(afd, size, 0) : 0; - if (!test) { - err = data ? symlink(data, name) - : mknod(name, mode, dev_makedev(x8u(toybuf+78), x8u(toybuf+86))); - - // Can't get a filehandle to a symlink or a node on nodev mount, - // so do special chown that at least doesn't follow symlinks. - // We also don't chmod after, so dropped suid bit isn't restored - if (!err && reown) err = lchown(name, uid, gid); - } - free(data); - } - - // Set timestamp. - if (!test && !err) { - struct timespec times[2]; - - memset(times, 0, sizeof(struct timespec)*2); - times[0].tv_sec = times[1].tv_sec = timestamp; - err = utimensat(AT_FDCWD, name, times, AT_SYMLINK_NOFOLLOW); - } - - if (err) perror_msg_raw(name); - - // Output cpio archive - - } else { - char *name = 0; - size_t size = 0; - unsigned inode = 0; - - for (;;) { - struct stat st; - unsigned nlen, error = 0, zero = 0; - int len, fd = -1; - char *link = 0; - ssize_t llen; - - len = getline(&name, &size, stdin); - if (len<1) break; - if (name[len-1] == '\n') name[--len] = 0; - if (!len) continue; - nlen = len+1; - if ((FLAG(L)?stat:lstat)(name, &st) || (S_ISREG(st.st_mode) - && st.st_size && (fd = open(name, O_RDONLY))<0) - || (S_ISLNK(st.st_mode) && !(link = xreadlink(name)))) - { - perror_msg_raw(name); - continue; - } - // encrypted filesystems can stat the wrong link size - if (link) st.st_size = strlen(link); - - if (Ruid>=0) st.st_uid = Ruid; - if (Rgid>=0) st.st_gid = Rgid; - if (FLAG(no_preserve_owner)) st.st_uid = st.st_gid = 0; - if (!S_ISREG(st.st_mode) && !S_ISLNK(st.st_mode)) st.st_size = 0; - if (st.st_size >> 32) perror_msg("skipping >2G file '%s'", name); - else { - if (FLAG(renumber_inodes)) st.st_ino = ++inode; - if (FLAG(ignore_devno)) st.st_rdev = 0; - llen = sprintf(toybuf, - "070701%08X%08X%08X%08X%08X%08X%08X%08X%08X%08X%08X%08X%08X", - (int)st.st_ino, st.st_mode, st.st_uid, st.st_gid, (int)st.st_nlink, - (int)st.st_mtime, (int)st.st_size, dev_major(st.st_dev), - dev_minor(st.st_dev), dev_major(st.st_rdev), dev_minor(st.st_rdev), - nlen, 0); - xwrite(afd, toybuf, llen); - xwrite(afd, name, nlen); - - // NUL Pad header up to 4 multiple bytes. - llen = (llen + nlen) & 3; - if (llen) xwrite(afd, &zero, 4-llen); - - // Write out body for symlink or regular file - if (link) xwrite(afd, link, st.st_size); - else for (llen = st.st_size; llen; llen -= nlen) { - nlen = llen > sizeof(toybuf) ? sizeof(toybuf) : llen; - // If read fails, write anyway (already wrote size in header) - if (nlen != readall(fd, toybuf, nlen)) - if (!error++) perror_msg("bad read from file '%s'", name); - xwrite(afd, toybuf, nlen); - } - llen = st.st_size & 3; - if (llen) xwrite(afd, &zero, 4-llen); - } - free(link); - xclose(fd); - } - if (CFG_TOYBOX_FREE) free(name); - - // nlink=1, namesize=11, with padding - dprintf(afd, "070701%040X%056X%08XTRAILER!!!%c%c%c%c", 1, 11, 0, 0, 0, 0,0); - } - if (TT.F) xclose(afd); - - if (FLAG(p) && pid) toys.exitval |= xpclose(pid, pipe); -} diff --git a/update/toys/posix/kill.c b/update/toys/posix/kill.c deleted file mode 100644 index dc4c370..0000000 --- a/update/toys/posix/kill.c +++ /dev/null @@ -1,161 +0,0 @@ -/* kill.c - a program to send signals to processes - * - * Copyright 2012 Daniel Walter - * - * See http://opengroup.org/onlinepubs/9699919799/utilities/kill.html - * - * killall5.c - Send signal to all processes outside current session. - * - * Copyright 2014 Ranjan Kumar - * Copyright 2014 Kyungwan Han - * - * No Standard - * - * TODO: toysh jobspec support, -n -L - -USE_KILL(NEWTOY(kill, "?ls: ", TOYFLAG_BIN|TOYFLAG_MAYFORK)) -USE_KILLALL5(NEWTOY(killall5, "?o*ls: [!lo][!ls]", TOYFLAG_SBIN)) - -config KILL - bool "kill" - default y - help - usage: kill [-l [SIGNAL] | -s SIGNAL | -SIGNAL] PID... - - Send signal to process(es). - - -l List signal name(s) and number(s) - -s Send SIGNAL (default SIGTERM) - -config KILLALL5 - bool "killall5" - default y - depends on KILL - help - usage: killall5 [-l [SIGNAL]] [-SIGNAL|-s SIGNAL] [-o PID]... - - Send a signal to all processes outside current session. - - -l List signal name(s) and number(s) - -o PID Omit PID - -s Send SIGNAL (default SIGTERM) -*/ - -// This has to match the filename: -#define FOR_kill -#define FORCE_FLAGS -#include "toys.h" - -GLOBALS( - char *s; - struct arg_list *o; -) - -// But kill's flags are a subset of killall5's - -#define FOR_killall5 -#include "generated/flags.h" - -void kill_main(void) -{ - int signum; - char *tmp, **args = toys.optargs; - pid_t pid; - - // list signal(s) - if (FLAG(l)) { - if (*args) { - int signum = sig_to_num(*args); - char *s = 0; - - if (signum>=0) s = num_to_sig(signum&127); - if (isdigit(**args)) puts(s ? s : "UNKNOWN"); - else printf("%d\n", signum); - } else list_signals(); - - return; - } - - // signal must come before pids, so "kill -9 -1" isn't confusing. - - if (!TT.s && *args && **args=='-') TT.s = *(args++)+1; - if (TT.s) { - char *arg; - int i = strtol(TT.s, &arg, 10); - - if (!*arg) arg = num_to_sig(i); - else arg = TT.s; - - if (!arg || -1 == (signum = sig_to_num(arg))) - error_exit("Unknown signal '%s'", arg); - } else signum = SIGTERM; - - // is it killall5? - if (CFG_KILLALL5 && toys.which->name[4]=='a') { - DIR *dp; - struct dirent *entry; - int pid, sid; - long *olist = 0, ocount = 0; - - // parse omit list - if (FLAG(o)) { - struct arg_list *ptr; - - for (ptr = TT.o; ptr; ptr = ptr->next) ocount++; - olist = xmalloc(ocount*sizeof(long)); - ocount = 0; - for (ptr = TT.o; ptr; ptr=ptr->next) olist[ocount++] = atolx(ptr->arg); - } - - sid = getsid(pid = getpid()); - - if (!(dp = opendir("/proc"))) { - free(olist); - perror_exit("/proc"); - } - while ((entry = readdir(dp))) { - int count, procpid, procsid; - - if (!(procpid = atoi(entry->d_name))) continue; - - snprintf(toybuf, sizeof(toybuf), "/proc/%d/stat", procpid); - if (!readfile(toybuf, toybuf, sizeof(toybuf))) continue; - // command name can have embedded space and/or ) - if (!(tmp = strrchr(toybuf, ')')) - || sscanf(tmp, " %*c %*d %*d %d", &procsid) != 1) continue; - if (pid == procpid || sid == procsid || procpid == 1) continue; - - // Check for kernel threads. - snprintf(toybuf, sizeof(toybuf), "/proc/%d/cmdline", procpid); - if (!readfile(toybuf, toybuf, sizeof(toybuf)) || !*toybuf) continue; - - // Check with omit list. - for (count = 0; count < ocount; count++) - if (procpid == olist[count]) break; - if (count != ocount) continue; - - kill(procpid, signum); - } - closedir(dp); - free(olist); - - // is it kill? - } else { - - // "<1" in optstr wouldn't cover this because "-SIGNAL" - if (!*args) help_exit("missing argument"); - - while (*args) { - char *arg = *(args++); - - pid = estrtol(arg, &tmp, 10); - if (!errno && *tmp) errno = ESRCH; - if (errno || kill(pid, signum)<0) perror_msg("bad pid '%s'", arg); - } - } -} - -void killall5_main(void) -{ - kill_main(); -} diff --git a/update/toys/posix/patch.c b/update/toys/posix/patch.c deleted file mode 100644 index b66d590..0000000 --- a/update/toys/posix/patch.c +++ /dev/null @@ -1,485 +0,0 @@ -/* patch.c - Apply a "universal" diff. - * - * Copyright 2007 Rob Landley - * - * see http://opengroup.org/onlinepubs/9699919799/utilities/patch.html - * (But only does -u, because who still cares about "ed"?) - * - * TODO: - * -b backup - * -N ignore already applied - * -D define wrap #ifdef and #ifndef around changes - * -o outfile output here instead of in place - * -r rejectfile write rejected hunks to this file - * -E remove empty files --remove-empty-files - * git syntax (rename, etc) - -USE_PATCH(NEWTOY(patch, ">2(no-backup-if-mismatch)(dry-run)F#g#fulp#v(verbose)@d:i:Rs(quiet)[!sv]", TOYFLAG_USR|TOYFLAG_BIN)) - -config PATCH - bool "patch" - default y - help - usage: patch [-Rlsuv] [-d DIR] [-i FILE] [-p DEPTH] [-F FUZZ] [--dry-run] [FILE [PATCH]] - - Apply a unified diff to one or more files. - - -d Modify files in DIR - -F Fuzz factor (number of non-matching context lines allowed per hunk) - -i Input patch from FILE (default=stdin) - -l Loose match (ignore whitespace) - -p Number of '/' to strip from start of file paths (default=all) - -R Reverse patch - -s Silent except for errors - -v Verbose (-vv to see decisions) - --dry-run Don't change files, just confirm patch applies - - Only handles "unified" diff format (-u is assumed and ignored). Only - modifies files when all hunks to that file apply. Prints failed hunks - to stderr, and exits with nonzero status if any hunks fail. - - Files compared against /dev/null (or with a date <= the unix epoch) are - created/deleted as appropriate. Default -F value is the number of - leading/trailing context lines minus one (usually 2). -*/ - -#define FOR_patch -#include "toys.h" - -GLOBALS( - char *i, *d; - long v, p, g, F; - - void *current_hunk; - long oldline, oldlen, newline, newlen, linenum, outnum; - int context, state, filein, fileout, filepatch, hunknum; - char *tempname; -) - -// TODO xgetline() instead, but replace_tempfile() wants fd... -char *get_line(int fd) -{ - char c, *buf = 0; - long len = 0; - - for (;;) { - if (1>read(fd, &c, 1)) break; - if (!(len & 63)) buf=xrealloc(buf, len+65); - if ((buf[len++]=c) == '\n') break; - } - if (buf) { - buf[len]=0; - if (buf[--len]=='\n') buf[len]=0; - } - - return buf; -} - -// Dispose of a line of input, either by writing it out or discarding it. - -// state < 2: just free -// state = 2: write whole line to stderr -// state = 3: write whole line to fileout -// state > 3: write line+1 to fileout when *line != state - -static void do_line(void *data) -{ - struct double_list *dlist = data; - - TT.outnum++; - if (TT.state>1) - if (0>dprintf(TT.state==2 ? 2 : TT.fileout,"%s\n",dlist->data+(TT.state>3))) - perror_exit("write"); - - llist_free_double(data); -} - -static void finish_oldfile(void) -{ - if (TT.tempname) replace_tempfile(TT.filein, TT.fileout, &TT.tempname); - TT.fileout = TT.filein = -1; -} - -static void fail_hunk(void) -{ - if (!TT.current_hunk) return; - - fprintf(stderr, "Hunk %d FAILED %ld/%ld.\n", - TT.hunknum, TT.oldline, TT.newline); - toys.exitval = 1; - - // If we got to this point, we've seeked to the end. Discard changes to - // this file and advance to next file. - - TT.state = 2; - llist_traverse(TT.current_hunk, do_line); - TT.current_hunk = 0; - if (!FLAG(dry_run)) delete_tempfile(TT.filein, TT.fileout, &TT.tempname); - TT.state = 0; -} - -// Compare ignoring whitespace. Just returns 0/1, no > or < -static int loosecmp(char *aa, char *bb) -{ - int a = 0, b = 0; - - for (;;) { - while (isspace(aa[a])) a++; - while (isspace(bb[b])) b++; - if (aa[a] != bb[b]) return 1; - if (!aa[a]) return 0; - a++, b++; - } -} - -// Given a hunk of a unified diff, make the appropriate change to the file. -// This does not use the location information, but instead treats a hunk -// as a sort of regex. Copies data from input to output until it finds -// the change to be made, then outputs the changed data and returns. -// (Finding EOF first is an error.) This is a single pass operation, so -// multiple hunks must occur in order in the file. - -static int apply_one_hunk(void) -{ - struct double_list *plist, *buf = 0, *check = 0; - int matcheof, trail = 0, allfuzz = 0, fuzz, ii; - int (*lcmp)(char *aa, char *bb) = FLAG(l) ? (void *)loosecmp : (void *)strcmp; - long backwarn = 0; - char *data = toybuf; - - if (TT.v>1) printf("START %d\n", TT.hunknum); - - // Match EOF if there aren't as many ending context lines as beginning - dlist_terminate(TT.current_hunk); - for (fuzz = 0, plist = TT.current_hunk; plist; plist = plist->next) { - char *s = plist->data, c = *s; - - if (c==' ') trail++; - else trail = 0; - - // Only allow fuzz if 2 context lines have multiple nonwhitespace chars. - // avoids the "all context was blank or } lines" issue. Removed lines - // count as context since they're matched. - if (c==' ' || c=="-+"[FLAG(R)]) { - while (isspace(*++s)); - if (*s && s[1] && !isspace(s[1])) fuzz++; - } - } - matcheof = !trail || trail < TT.context; - if (FLAG(F) && !TT.F) fuzz = 0; - if (fuzz>1) allfuzz = TT.F ? : TT.context ? TT.context-1 : 0; - - // Loop through input data searching for this hunk. Match all context - // lines and lines to be removed until we've found end of complete hunk. - plist = TT.current_hunk; - fuzz = 0; - for (;;) { - if (data) { - data = get_line(TT.filein); - check = data ? dlist_add(&buf, data) : 0; - TT.linenum++; - } - if (TT.v>1) printf("READ[%ld] %s\n", TT.linenum, data ? : "(NULL)"); - - // Compare buffered line(s) with expected lines of hunk. Match can fail - // because next line doesn't match, or because we hit end of a hunk that - // needed EOF and this isn't EOF. - for (;;) { - // Find hunk line to match (skip added lines) and detect reverse matches - while (plist && *plist->data == "+-"[FLAG(R)]) { - // TODO: proper backwarn = full hunk applies in reverse, not just 1 line - if (data) { - ii = strcspn(data, " \t"); - if (data[ii+!!data[ii]] && !lcmp(data, plist->data+1)) - backwarn = TT.linenum; - } - plist = plist->next; - } - if (TT.v>1 && plist) - printf("HUNK %s\nLINE %s\n", plist->data+1, check ? check->data : ""); - - // End of hunk? - if (!plist) { - if (TT.v>1) printf("END OF HUNK\n"); - if (matcheof == !data) goto out; - - // Compare line and handle match - } else if (check && !lcmp(check->data, plist->data+1)) { - if (TT.v>1) printf("MATCH\n"); -handle_match: - plist = plist->next; - if ((check = check->next) == buf) { - if (plist || matcheof) break; - goto out; - } else continue; - } - - // Did we hit EOF? - if (!data) { - if (TT.v>1) printf("EOF\n"); - if (backwarn && !FLAG(s)) - fprintf(stderr, "Possibly reversed hunk %d at %ld\n", - TT.hunknum, backwarn); - - // File ended before we found a place for this hunk. - fail_hunk(); - goto done; - } - if (TT.v>1) printf("NOT MATCH\n"); - - // Match failed: can we fuzz it? - if (plist && *plist->data == ' ' && fuzz1) printf("FUZZ %d %s\n", fuzz, check->data); - goto handle_match; - } - - // If this hunk must match start of file, fail if it didn't. - if (!TT.context || trail>TT.context) { - fail_hunk(); - goto done; - } - - // Write out first line of buffer and recheck rest for new match. - TT.state = 3; - if (TT.v>1) printf("WRITE %s\n", buf->data); - do_line(check = dlist_pop(&buf)); - plist = TT.current_hunk; - fuzz = 0; - - // If end of the buffer without finishing a match, read more lines. - if (!buf) break; - check = buf; - } - } -out: - if (TT.v) xprintf("Hunk #%d succeeded at %ld.\n", TT.hunknum, TT.linenum); - // We have a match. Emit changed data. - TT.state = "-+"[FLAG(R)]; - while ((plist = dlist_pop(&TT.current_hunk))) { - if (TT.state == *plist->data || *plist->data == ' ') { - if (*plist->data == ' ') dprintf(TT.fileout, "%s\n", buf->data); - llist_free_double(dlist_pop(&buf)); - } else dprintf(TT.fileout, "%s\n", plist->data+1); - llist_free_double(plist); - } - TT.current_hunk = 0; - TT.state = 1; -done: - llist_traverse(buf, do_line); - - return TT.state; -} - -// read a filename that has been quoted or escaped -static char *unquote_file(char *filename) -{ - char *s = filename, *t, *newfile; - - // Return copy of file that wasn't quoted - if (*s++ != '"' || !*s) return xstrdup(filename); - - // quoted and escaped filenames are larger than the original - for (t = newfile = xmalloc(strlen(s) + 1); *s != '"'; s++) { - if (!s[1]) error_exit("bad %s", filename); - - // don't accept escape sequences unless the filename is quoted - if (*s != '\\') *t++ = *s; - else if (*++s >= '0' && *s < '8') { - *t++ = strtoul(s, &s, 8); - s--; - } else { - if (!(*t = unescape(*s))) *t = *s;; - t++; - } - } - *t = 0; - - return newfile; -} - -// Read a patch file and find hunks, opening/creating/deleting files. -// Call apply_one_hunk() on each hunk. - -// state 0: Not in a hunk, look for +++. -// state 1: Found +++ file indicator, look for @@ -// state 2: In hunk: counting initial context lines -// state 3: In hunk: getting body - -void patch_main(void) -{ - int state = 0, patchlinenum = 0, strip = 0; - char *oldname = 0, *newname = 0; - - if (toys.optc == 2) TT.i = toys.optargs[1]; - if (TT.i) TT.filepatch = xopenro(TT.i); - TT.filein = TT.fileout = -1; - - if (TT.d) xchdir(TT.d); - - // Loop through the lines in the patch file (-i or stdin) collecting hunks - for (;;) { - char *patchline; - - if (!(patchline = get_line(TT.filepatch))) break; - - // Other versions of patch accept damaged patches, so we need to also. - if (strip || !patchlinenum++) { - int len = strlen(patchline); - if (len && patchline[len-1] == '\r') { - if (!strip && !FLAG(s)) fprintf(stderr, "Removing DOS newlines\n"); - strip = 1; - patchline[len-1] = 0; - } - } - if (!*patchline) { - free(patchline); - patchline = xstrdup(" "); - } - - // Are we assembling a hunk? - if (state >= 2) { - if (*patchline==' ' || *patchline=='+' || *patchline=='-') { - dlist_add((void *)&TT.current_hunk, patchline); - - if (*patchline != '+') TT.oldlen--; - if (*patchline != '-') TT.newlen--; - - // Context line? - if (*patchline==' ' && state==2) TT.context++; - else state=3; - - // If we've consumed all expected hunk lines, apply the hunk. - if (!TT.oldlen && !TT.newlen) state = apply_one_hunk(); - } else { - dlist_terminate(TT.current_hunk); - fail_hunk(); - state = 0; - } - continue; - } - - // Open a new file? - if (!strncmp("--- ", patchline, 4) || !strncmp("+++ ", patchline, 4)) { - char *s, **name = &oldname; - int i; - - if (*patchline == '+') { - name = &newname; - state = 1; - } - - free(*name); - finish_oldfile(); - - // Trim date from end of filename (if any). Date<=epoch means delete. - for (s = patchline+4; *s && *s!='\t'; s++); - i = atoi(s); - if (i>1900 && i<=1970) *name = xstrdup("/dev/null"); - else { - *s = 0; - *name = unquote_file(patchline+4); - } - - // We defer actually opening the file because svn produces broken - // patches that don't signal they want to create a new file the - // way the patch man page says, so you have to read the first hunk - // and _guess_. - - // Start a new hunk? Usually @@ -oldline,oldlen +newline,newlen @@ - // but a missing ,value means the value is 1. - } else if (state == 1 && !strncmp("@@ -", patchline, 4)) { - int i; - char *s = patchline+4; - - // Read oldline[,oldlen] +newline[,newlen] - - TT.oldlen = TT.newlen = 1; - TT.oldline = strtol(s, &s, 10); - if (*s == ',') TT.oldlen=strtol(s+1, &s, 10); - TT.newline = strtol(s+2, &s, 10); - if (*s == ',') TT.newlen = strtol(s+1, &s, 10); - - TT.context = 0; - state = 2; - - // If this is the first hunk, open the file. - if (TT.filein == -1) { - int oldsum, newsum, del = 0; - char *name; - - oldsum = TT.oldline + TT.oldlen; - newsum = TT.newline + TT.newlen; - - // If an original file was provided on the command line, it overrides - // *all* files mentioned in the patch, not just the first. - if (toys.optc) { - char **which = FLAG(R) ? &oldname : &newname; - - free(*which); - *which = xstrdup(toys.optargs[0]); - // The supplied path should be taken literally with or without -p. - toys.optflags |= FLAG_p; - TT.p = 0; - } - - name = FLAG(R) ? oldname : newname; - - // We're deleting oldname if new file is /dev/null (before -p) - // or if new hunk is empty (zero context) after patching - if (!strcmp(name, "/dev/null") || !(FLAG(R) ? oldsum : newsum)) { - name = FLAG(R) ? newname : oldname; - del++; - } - - // handle -p path truncation. - for (i = 0, s = name; *s;) { - if (FLAG(p) && TT.p == i) break; - if (*s++ != '/') continue; - while (*s == '/') s++; - name = s; - i++; - } - - if (del) { - if (!FLAG(s)) printf("removing %s\n", name); - if (!FLAG(dry_run)) xunlink(name); - state = 0; - // If we've got a file to open, do so. - } else if (!FLAG(p) || i <= TT.p) { - // If the old file was null, we're creating a new one. - if ((!strcmp(oldname, "/dev/null") || !oldsum) && access(name, F_OK)) - { - if (!FLAG(s)) printf("creating %s\n", name); - if (FLAG(dry_run)) TT.filein = xopen("/dev/null", O_RDWR); - else { - if (mkpath(name)) perror_exit("mkpath %s", name); - TT.filein = xcreate(name, O_CREAT|O_EXCL|O_RDWR, 0666); - } - } else { - if (!FLAG(s)) printf("patching %s\n", name); - TT.filein = xopenro(name); - } - if (FLAG(dry_run)) TT.fileout = xopen("/dev/null", O_RDWR); - else TT.fileout = copy_tempfile(TT.filein, name, &TT.tempname); - TT.linenum = TT.outnum = TT.hunknum = 0; - } - } - - TT.hunknum++; - - continue; - } - - // If we didn't continue above, discard this line. - free(patchline); - } - - finish_oldfile(); - - if (CFG_TOYBOX_FREE) { - close(TT.filepatch); - free(oldname); - free(newname); - } -} diff --git a/update/toys/posix/sort.c b/update/toys/posix/sort.c deleted file mode 100644 index d69b622..0000000 --- a/update/toys/posix/sort.c +++ /dev/null @@ -1,409 +0,0 @@ -/* sort.c - put input lines into order - * - * Copyright 2004, 2008 Rob Landley - * - * See http://opengroup.org/onlinepubs/007904975/utilities/sort.html - * - * Deviations from POSIX: Lots. - * We invented -x - -USE_SORT(NEWTOY(sort, USE_SORT_FLOAT("g")"S:T:m" "o:k*t:" "xVbMCcszdfirun", TOYFLAG_USR|TOYFLAG_BIN|TOYFLAG_ARGFAIL(2))) - -config SORT - bool "sort" - default y - help - usage: sort [-runbCcdfiMsxVz] [FILE...] [-k#[,#[x]] [-t X]] [-o FILE] - - Sort all lines of text from input files (or stdin) to stdout. - - -r Reverse - -u Unique lines only - -n Numeric order (instead of alphabetical) - - -b Ignore leading blanks (or trailing blanks in second part of key) - -C Check whether input is sorted - -c Warn if input is unsorted - -d Dictionary order (use alphanumeric and whitespace chars only) - -f Force uppercase (case insensitive sort) - -i Ignore nonprinting characters - -k Sort by "key" (see below) - -M Month sort (jan, feb, etc) - -o Output to FILE instead of stdout - -s Skip fallback sort (only sort with keys) - -t Use a key separator other than whitespace - -x Hexadecimal numerical sort - -V Version numbers (name-1.234-rc6.5b.tgz) - -z Zero (null) terminated lines - - Sorting by key looks at a subset of the words on each line. -k2 uses the - second word to the end of the line, -k2,2 looks at only the second word, - -k2,4 looks from the start of the second to the end of the fourth word. - -k2.4,5 starts from the fourth character of the second word, to the end - of the fifth word. Negative values count from the end. Specifying multiple - keys uses the later keys as tie breakers, in order. A type specifier - appended to a sort key (such as -2,2n) applies only to sorting that key. - -config SORT_FLOAT - bool - default y - depends on TOYBOX_FLOAT - help - usage: sort [-g] - - -g General numeric sort (double precision with nan and inf) -*/ - -#define FOR_sort -#include "toys.h" - -GLOBALS( - char *t; - struct arg_list *k; - char *o, *T, S; - - void *key_list; - unsigned linecount; - char **lines, *name; -) - -// The sort types are n, g, and M. -// u, c, s, and z apply to top level only, not to keys. -// b at top level implies bb. -// The remaining options can be applied to search keys. - -#define FLAG_bb (1<<31) // Ignore trailing blanks - -struct sort_key { - struct sort_key *next_key; // linked list - long range[4]; // start word, start char, end word, end char - int flags; -}; - -static int skip_key(char *str) -{ - int end = 0; - - // Skip leading blanks - if (str[end] && !TT.t) while (isspace(str[end])) end++; - - // Skip body of key - for (; str[end]; end++) { - if (TT.t) { - if (str[end]==*TT.t) { - end++; - break; - } - } else if (isspace(str[end])) break; - } - - return end; -} - -// Copy of the part of this string corresponding to a key/flags. - -static char *get_key_data(char *str, struct sort_key *key, int flags) -{ - long start = 0, end, len, h, i, j, k; - - // Special case whole string, so we don't have to make a copy - if(key->range[0]==1 && !key->range[1] && !key->range[2] && !key->range[3] - && !(flags&(FLAG_b|FLAG_d|FLAG_i|FLAG_bb))) return str; - - // Find start of key on first pass, end on second pass - len = strlen(str); - for (j=0; j<2; j++) { - if (!(k = key->range[2*j])) end=len; - - // Loop through fields - else { - if (k<1) for (end = h = 0;; end += h) { - ++k; - if (!(h = skip_key(str+end))) break; - } - if (k<1) end = len*!j; - else for (end = 0, i = 1; irange[3])) - while (isspace(str[start])) start++; - if (flags&FLAG_bb) while (end>start && isspace(str[end-1])) end--; - - // Handle offsets on start and end - if (key->range[3]>0) { - end += key->range[3]-1; - if (end>len) end=len; - } - if (key->range[1]>0) { - start += key->range[1]-1; - if (start>len) start=len; - } - - // Make the copy - if (endnext_key); - return *pkey = xzalloc(sizeof(struct sort_key)); -} - -// Perform actual comparison -static int compare_values(int flags, char *x, char *y) -{ - if (CFG_SORT_FLOAT && (flags & FLAG_g)) { - char *xx,*yy; - double dx = strtod(x,&xx), dy = strtod(y,&yy); - int xinf, yinf; - - // not numbers < NaN < -infinity < numbers < +infinity - - if (x==xx) return y==yy ? 0 : -1; - if (y==yy) return 1; - - // Check for isnan - if (dx!=dx) return (dy!=dy) ? 0 : -1; - if (dy!=dy) return 1; - - // Check for infinity. (Could underflow, but avoids needing libm.) - xinf = (1.0/dx == 0.0); - yinf = (1.0/dy == 0.0); - if (xinf) { - if(dx<0) return (yinf && dy<0) ? 0 : -1; - return (yinf && dy>0) ? 0 : 1; - } - if (yinf) return dy<0 ? 1 : -1; - - return dxdy; - } else if (flags & FLAG_M) { - struct tm thyme; - int dx; - char *xx,*yy; - - xx = strptime(x,"%b",&thyme); - dx = thyme.tm_mon; - yy = strptime(y,"%b",&thyme); - if (!xx) return !yy ? 0 : -1; - else if (!yy) return 1; - else return dx==thyme.tm_mon ? 0 : dx-thyme.tm_mon; - - } else if (flags & FLAG_x) return strtol(x, NULL, 16)-strtol(y, NULL, 16); - else if (flags & FLAG_V) { - while (*x && *y) { - while (*x && *x == *y) x++, y++; - if (isdigit(*x) && isdigit(*y)) { - long long xx = strtoll(x, &x, 10), yy = strtoll(y, &y, 10); - - if (xxyy) return 1; - } else { - char xx = *x ? *x : x[-1], yy = *y ? *y : y[-1]; - - // -rc/-pre hack so abc-123 > abc-123-rc1 (other way already - < 0-9) - if (xx != yy) { - if (xxdy; - - // Ascii sort - } else return ((flags&FLAG_f) ? strcasecmp : strcmp)(x, y); -} - -// Callback from qsort(): Iterate through key_list and perform comparisons. -static int compare_keys(const void *xarg, const void *yarg) -{ - int flags = toys.optflags, retval = 0; - char *x, *y, *xx = *(char **)xarg, *yy = *(char **)yarg; - struct sort_key *key; - - for (key=(void *)TT.key_list; !retval && key; key = key->next_key) { - flags = key->flags ? : toys.optflags; - - // Chop out and modify key chunks, handling -dfib - - x = get_key_data(xx, key, flags); - y = get_key_data(yy, key, flags); - - retval = compare_values(flags, x, y); - - // Free the copies get_key_data() made. - - if (x != xx) free(x); - if (y != yy) free(y); - - if (retval) break; - } - - // Perform fallback sort if necessary (always case insensitive, no -f, - // the point is to get a stable order even for -f sorts) - if (!retval && !FLAG(s)) { - flags = toys.optflags; - retval = strcmp(xx, yy); - } - - return retval * ((flags&FLAG_r) ? -1 : 1); -} - -// Read each line from file, appending to a big array. -static void sort_lines(char **pline, long len) -{ - char *line; - - if (!pline) return; - line = *pline; - if (!FLAG(z) && len && line[len-1]=='\n') line[--len] = 0; - *pline = 0; - - // handle -c here so we don't allocate more memory than necessary. - if (FLAG(C)||FLAG(c)) { - if (TT.lines && compare_keys((void *)&TT.lines, &line)>-FLAG(u)) { - toys.exitval = 1; - if (FLAG(C)) xexit(); - error_exit("%s: Check line %u", TT.name, TT.linecount+1); - } - free(TT.lines); - TT.lines = (void *)line; - } else { - if (!(TT.linecount&63)) - TT.lines = xrealloc(TT.lines, sizeof(char *)*(TT.linecount+64)); - TT.lines[TT.linecount] = line; - } - TT.linecount++; -} - -// Callback from loopfiles to handle input files. -static void sort_read(int fd, char *name) -{ - TT.name = name; - do_lines(fd, '\n'*!FLAG(z), sort_lines); -} - -void sort_main(void) -{ - int idx, jdx, fd = 1; - - if (FLAG(u)) toys.optflags |= FLAG_s; - - // Parse -k sort keys. - if (TT.k) { - struct arg_list *arg; - - for (arg = TT.k; arg; arg = arg->next) { - struct sort_key *key = add_key(); - char *temp, *temp2, *optlist; - int flag; - - idx = 0; - temp = arg->arg; - while (*temp) { - // Start of range - key->range[2*idx] = strtol(temp, &temp, 10); - if (*temp=='.') key->range[(2*idx)+1] = strtol(temp+1, &temp, 10); - - // Handle flags appended to a key type. - for (;*temp;temp++) { - - // Second comma becomes an "Unknown key" error. - if (*temp==',' && !idx++) { - temp++; - break; - } - - // Which flag is this? - optlist = toys.which->options; - temp2 = strchr(optlist, *temp); - flag = 1<<(optlist-temp2+strlen(optlist)-1); - - // Was it a flag that can apply to a key? - if (!temp2 || flag>FLAG_x || (flag&(FLAG_u|FLAG_c|FLAG_s|FLAG_z))) - error_exit("Unknown key option."); - - // b after , means strip _trailing_ space, not leading. - if (idx && flag==FLAG_b) flag = FLAG_bb; - key->flags |= flag; - } - } - } - } - - // global b flag strips both leading and trailing spaces - if (FLAG(b)) toys.optflags |= FLAG_bb; - - // If no keys, perform alphabetic sort over the whole line. - if (!TT.key_list) add_key()->range[0] = 1; - - // Open input files and read data, populating TT.lines[TT.linecount] - loopfiles(toys.optargs, sort_read); - - // The compare (-c) logic was handled in sort_read(), - // so if we got here, we're done. - if (FLAG(C)||FLAG(c)) goto exit_now; - - // Perform the actual sort - qsort(TT.lines, TT.linecount, sizeof(char *), compare_keys); - - // handle unique (-u) - if (FLAG(u)) { - for (jdx=0, idx=1; idx