default n
help
Enable extra checks for debugging purposes. All of them catch
- things that can only go wrong at development time, not runtime.
+ things that can only go wrong at development time, not runtime.
config TOYBOX_UID_SYS
int "First system UID"
return off-haystack;
}
-char *strlower(char *s)
-{
- char *try, *new;
-
- if (!CFG_TOYBOX_I18N) {
- try = new = xstrdup(s);
- for (; *s; s++) *(new++) = tolower(*s);
- } else {
- // I can't guarantee the string _won't_ expand during reencoding, so...?
- try = new = xmalloc(strlen(s)*2+1);
-
- while (*s) {
- wchar_t c;
- int len = mbrtowc(&c, s, MB_CUR_MAX, 0);
-
- if (len < 1) *(new++) = *(s++);
- else {
- s += len;
- // squash title case too
- c = towlower(c);
-
- // if we had a valid utf8 sequence, convert it to lower case, and can't
- // encode back to utf8, something is wrong with your libc. But just
- // in case somebody finds an exploit...
- len = wcrtomb(new, c, 0);
- if (len < 1) error_exit("bad utf8 %x", (int)c);
- new += len;
- }
- }
- *new = 0;
- }
-
- return try;
-}
-
int unescape(char c)
{
char *from = "\\abefnrtv", *to = "\\\a\b\033\f\n\r\t\v";
{
close(fdin);
close(fdout);
- if (*tempname) unlink(*tempname);
+ unlink(*tempname);
tempfile2zap = (char *)1;
free(*tempname);
*tempname = NULL;
// display first few digits of number with power of two units, except we're
// actually just counting decimal digits and showing mil/bil/trillions.
-int human_readable(char *buf, unsigned long long num, int style)
+int human_readable(char *buf, unsigned long long num)
{
int end, len;
buf[1] = '.';
end = 3;
}
- if (style & HR_SPACE) buf[end++] = ' ';
+ buf[end++] = ' ';
if (len) buf[end++] = " KMGTPE"[len];
- if (style & HR_B) buf[end++] = 'B';
+ buf[end++] = 'B';
buf[end++] = 0;
return end;
long atolx(char *c);
long atolx_range(char *numstr, long low, long high);
int stridx(char *haystack, char needle);
-char *strlower(char *s);
int unescape(char c);
int strstart(char **a, char *b);
off_t fdlength(int fd);
void crc_init(unsigned int *crc_table, int little_endian);
void base64_init(char *p);
int yesno(char *prompt, int def);
-#define HR_SPACE 1
-#define HR_B 2
-int human_readable(char *buf, unsigned long long num, int style);
+int human_readable(char *buf, unsigned long long num);
int qstrcmp(const void *a, const void *b);
int xpoll(struct pollfd *fds, int nfds, int timeout);
// net.c
int xsocket(int domain, int type, int protocol);
void xsetsockopt(int fd, int level, int opt, void *val, socklen_t len);
-int xconnect(char *host, char *port, int family, int socktype, int protocol,
- int flags);
// password.c
int get_salt(char *salt, char * algo);
{
if (-1 == setsockopt(fd, level, opt, val, len)) perror_exit("setsockopt");
}
-
-int xconnect(char *host, char *port, int family, int socktype, int protocol,
- int flags)
-{
- struct addrinfo info, *ai, *ai2;
- int fd;
-
- memset(&info, 0, sizeof(struct addrinfo));
- info.ai_family = family;
- info.ai_socktype = socktype;
- info.ai_protocol = protocol;
- info.ai_flags = flags;
-
- fd = getaddrinfo(host, port, &info, &ai);
- if (fd || !ai)
- error_exit("Connect '%s%s%s': %s", host, port ? ":" : "", port ? port : "",
- fd ? gai_strerror(fd) : "not found");
-
- // Try all the returned addresses. Report errors if last entry can't connect.
- for (ai2 = ai; ai; ai = ai->ai_next) {
- fd = (ai->ai_next ? socket : xsocket)(ai->ai_family, ai->ai_socktype,
- ai->ai_protocol);
- if (!connect(fd, ai->ai_addr, ai->ai_addrlen)) break;
- else if (!ai2->ai_next) perror_exit("connect");
- close(fd);
- }
- freeaddrinfo(ai2);
-
- return fd;
-}
void xexit(void)
{
- if (toys.rebound) longjmp(*toys.rebound, 1);
if (fflush(NULL) || ferror(stdout))
if (!toys.exitval) perror_msg("write");
- exit(toys.exitval);
+ if (toys.rebound) longjmp(*toys.rebound, 1);
+ else exit(toys.exitval);
}
// Die unless we can allocate memory.
if (CFG_TOYBOX && !CFG_TOYBOX_NORECURSE) toy_exec(argv);
execvp(argv[0], argv);
- perror_msg("exec %s", argv[0]);
- toys.exitval = 127;
- if (!CFG_TOYBOX_FORK) _exit(toys.exitval);
- xexit();
+ perror_exit("exec %s", argv[0]);
}
// Spawn child process, capturing stdin/stdout.
xputs(TOYBOX_VERSION);
xexit();
}
- if (toys.argv[1][0] != '-') {
- toys.exitval = 127;
- error_exit("Unknown command %s", toys.argv[1]);
- }
+ if (toys.argv[1][0] != '-') error_exit("Unknown command %s", toys.argv[1]);
}
// Output list of command.
+++ /dev/null
-ping
-ping6
CONFIG_TOYBOX_FORK=y
#
-# Samsung developed commands
-#
-# CONFIG_NSLOOKUP is not set
-
-#
# Posix commands
#
# CONFIG_BASENAME is not set
# CONFIG_CAL is not set
# CONFIG_CAT is not set
# CONFIG_CAT_V is not set
-CONFIG_CATV=y
+# CONFIG_CATV is not set
# CONFIG_CHGRP is not set
# CONFIG_CHOWN is not set
# CONFIG_CHMOD is not set
# CONFIG_CKSUM is not set
# CONFIG_CMP is not set
# CONFIG_COMM is not set
-CONFIG_CP=y
-CONFIG_CP_MORE=y
-CONFIG_CP_PRESERVE=y
-CONFIG_CP_Z=y
-CONFIG_MV=y
-CONFIG_MV_MORE=y
-CONFIG_INSTALL=y
-CONFIG_INSTALL_Z=y
+# CONFIG_CP is not set
+# CONFIG_CP_MORE is not set
+# CONFIG_CP_PRESERVE is not set
+# CONFIG_CP_Z is not set
+# CONFIG_MV is not set
+# CONFIG_MV_MORE is not set
+# CONFIG_INSTALL is not set
+# CONFIG_INSTALL_Z is not set
# CONFIG_CPIO is not set
# CONFIG_CUT is not set
# CONFIG_DATE is not set
# CONFIG_KILLALL5 is not set
# CONFIG_LINK is not set
# CONFIG_LN is not set
-CONFIG_LS=y
-CONFIG_LS_COLOR=y
-CONFIG_MKDIR=y
-CONFIG_MKDIR_Z=y
-CONFIG_MKFIFO=y
-CONFIG_MKFIFO_Z=y
+# CONFIG_LS is not set
+# CONFIG_LS_COLOR is not set
+# CONFIG_MKDIR is not set
+# CONFIG_MKDIR_Z is not set
+# CONFIG_MKFIFO is not set
+# CONFIG_MKFIFO_Z is not set
# CONFIG_NICE is not set
# CONFIG_NL is not set
# CONFIG_NOHUP is not set
# CONFIG_PRINTF is not set
# CONFIG_PWD is not set
# CONFIG_RENICE is not set
-CONFIG_RM=y
+# CONFIG_RM is not set
# CONFIG_RMDIR is not set
# CONFIG_SED is not set
# CONFIG_SLEEP is not set
# CONFIG_IP is not set
# CONFIG_IPCRM is not set
# CONFIG_IPCS is not set
-CONFIG_KLOGD=y
-CONFIG_KLOGD_SOURCE_RING_BUFFER=y
+# CONFIG_KLOGD is not set
+# CONFIG_KLOGD_SOURCE_RING_BUFFER is not set
# CONFIG_LAST is not set
-CONFIG_LOGGER=y
+# CONFIG_LOGGER is not set
# CONFIG_MDEV is not set
# CONFIG_MDEV_CONF is not set
# CONFIG_MKE2FS is not set
# CONFIG_EXIT is not set
# CONFIG_CD is not set
# CONFIG_SULOGIN is not set
-CONFIG_SYSLOGD=y
+# CONFIG_SYSLOGD is not set
# CONFIG_TAR is not set
# CONFIG_TCPSVD is not set
# CONFIG_TELNET is not set
# CONFIG_BASE64 is not set
# CONFIG_BLKID is not set
# CONFIG_FSTYPE is not set
-CONFIG_BLOCKDEV=y
+# CONFIG_BLOCKDEV is not set
# CONFIG_BUNZIP2 is not set
# CONFIG_BZCAT is not set
# CONFIG_CHCON is not set
# CONFIG_FREERAMDISK is not set
# CONFIG_FSFREEZE is not set
# CONFIG_FSYNC is not set
-CONFIG_HELP=y
-CONFIG_HELP_EXTRAS=y
+# CONFIG_HELP is not set
+# CONFIG_HELP_EXTRAS is not set
# CONFIG_HEXEDIT is not set
# CONFIG_HOSTID is not set
# CONFIG_HWCLOCK is not set
# CONFIG_IFCONFIG is not set
# CONFIG_INOTIFYD is not set
-CONFIG_INSMOD=y
+# CONFIG_INSMOD is not set
# CONFIG_IONICE is not set
# CONFIG_IORENICE is not set
# CONFIG_LOGIN is not set
# CONFIG_RMMOD is not set
# CONFIG_SETSID is not set
# CONFIG_SHRED is not set
-CONFIG_STAT=y
-CONFIG_STAT_C=y
+# CONFIG_STAT is not set
+# CONFIG_STAT_C is not set
# CONFIG_SWAPOFF is not set
# CONFIG_SWAPON is not set
# CONFIG_SWITCH_ROOT is not set
# CONFIG_KILLALL is not set
# CONFIG_MD5SUM is not set
# CONFIG_SHA1SUM is not set
-CONFIG_MKNOD=y
-CONFIG_MKNOD_Z=y
-CONFIG_MKTEMP=y
-CONFIG_MOUNT=y
+# CONFIG_MKNOD is not set
+# CONFIG_MKNOD_Z is not set
+# CONFIG_MKTEMP is not set
+# CONFIG_MOUNT is not set
# CONFIG_PASSWD is not set
# CONFIG_PIDOF is not set
# CONFIG_SEQ is not set
# CONFIG_SU is not set
# CONFIG_SYNC is not set
-CONFIG_UMOUNT=y
+# CONFIG_UMOUNT is not set
#
# Example commands
+++ /dev/null
-<manifest>
- <request>
- <domain name="_"/>
- </request>
-</manifest>
+++ /dev/null
-[Unit]
-Description=Run syslog
-DefaultDependencies=no
-After=syslogd.service
-ConditionKernelCommandLine=|!sec_debug.enable=0
-ConditionKernelCommandLine=|!sec_debug.enable_user=0
-
-[Service]
-Type=forking
-ExecStart=/sbin/klogd
-OOMScoreAdjust=-1000
-Restart=always
-RestartSec=0
-
-[Install]
-WantedBy=basic.target
+++ /dev/null
-klogd
-syslogd
-ping
-ping6
+++ /dev/null
-<manifest>
- <request>
- <domain name="_"/>
- </request>
-</manifest>
+++ /dev/null
-[Unit]
-Description=Run syslog
-DefaultDependencies=no
-After=local-fs.target
-ConditionKernelCommandLine=|!sec_debug.enable=0
-ConditionKernelCommandLine=|!sec_debug.enable_user=0
-
-[Service]
-Type=forking
-ExecStart=/sbin/syslogd -b 5 -B 99
-OOMScoreAdjust=-1000
-Restart=always
-RestartSec=0
-
-[Install]
-WantedBy=basic.target
URL: http://www.landley.net/toybox/
Source: %{name}-%{version}.tar.bz2
Source1: config
-%if "%{?profile}"=="tv"
-Source2: bin_tv.links
-Source3: sbin_tv.links
-%else
Source2: bin.links
Source3: sbin.links
-%endif
Source4: usrbin.links
Source5: usrsbin.links
-Source101: klogd.service
-Source102: syslogd.service
Source1001: toybox.manifest
-Source1002: syslogd.manifest
-Source1003: klogd.manifest
BuildRequires : smack-devel
BuildRequires : libattr-devel
useful for recovering from certain types of system failures,
particularly those involving broken shared libraries.
-%package symlinks-klogd
-Group: tools
-Summary: ToyBox symlinks to provide 'klogd'
-Requires: %{name} = %{version}-%{release}
-
-%description symlinks-klogd
-ToyBox symlinks for utilities corresponding to 'klogd' package.
-
-%package symlinks-sysklogd
-Group: tools
-Summary: ToyBox symlinks to provide 'sysklogd'
-Requires: %{name} = %{version}-%{release}
-
-%description symlinks-sysklogd
-ToyBox symlinks for utilities corresponding to 'sysklogd' package.
-
%package symlinks-dhcp
Group: tools
Summary: ToyBox symlinks to provide 'dhcp'
%build
cp %{SOURCE1001} .
-cp %{SOURCE1002} .
-cp %{SOURCE1003} .
# create dynamic toybox - the executable is toybox
cp %{SOURCE1} .config
make -j 4 CC="gcc $RPM_OPT_FLAGS" CFLAGS="$CFLAGS -fPIE" LDOPTIMIZE="-Wl,--gc-sections -pie"
for f in `cat %SOURCE5` ; do ln -s ../../bin/toybox $f ; done
popd
-# install systemd service files for syslogd and klogd
-#mkdir -p %{buildroot}%{_unitdir}/basic.target.wants
-#install -m 644 %SOURCE101 %{buildroot}%{_unitdir}/klogd.service
-#ln -s ../klogd.service %{buildroot}%{_unitdir}/basic.target.wants/klogd.service
-#install -m 644 %SOURCE102 %{buildroot}%{_unitdir}/syslogd.service
-#ln -s ../syslogd.service %{buildroot}%{_unitdir}/basic.target.wants/syslogd.service
-#rm -rf $RPM_BUILD_ROOT/sbin/syslogd
-#cp -f $RPM_BUILD_ROOT/bin/toybox $RPM_BUILD_ROOT/sbin/syslogd
-#rm -rf $RPM_BUILD_ROOT/sbin/klogd
-#cp -f $RPM_BUILD_ROOT/bin/toybox $RPM_BUILD_ROOT/sbin/klogd
-
-mkdir -p $RPM_BUILD_ROOT%{_datadir}/license
-cat LICENSE > $RPM_BUILD_ROOT%{_datadir}/license/toybox
-cat LICENSE > $RPM_BUILD_ROOT%{_datadir}/license/toybox-symlinks-klogd
-cat LICENSE > $RPM_BUILD_ROOT%{_datadir}/license/toybox-symlinks-sysklogd
-cat LICENSE > $RPM_BUILD_ROOT%{_datadir}/license/toybox-symlinks-dhcp
-cat LICENSE > $RPM_BUILD_ROOT%{_datadir}/license/toybox-symlinks-dhcpd
-
%files
-%defattr(-,root,root,-)
-%doc LICENSE
-%{_datadir}/license/toybox
-/bin/toybox
-/usr/bin/nslookup
-%if "%{?profile}"=="tv"
-/sbin/ping
-/bin/ping
-/sbin/ping6
-/bin/ping6
-%endif
%manifest toybox.manifest
-
-%files symlinks-klogd
-%defattr(-,root,root,-)
-%{_datadir}/license/toybox-symlinks-klogd
-/sbin/klogd
-#%{_unitdir}/klogd.service
-#%{_unitdir}/basic.target.wants/klogd.service
-%manifest klogd.manifest
-
-%files symlinks-sysklogd
+%license LICENSE
%defattr(-,root,root,-)
-%{_datadir}/license/toybox-symlinks-sysklogd
-/sbin/syslogd
-#%{_unitdir}/syslogd.service
-#%{_unitdir}/basic.target.wants/syslogd.service
-%manifest syslogd.manifest
+/bin/toybox
%files symlinks-dhcp
+%manifest toybox.manifest
+%license LICENSE
%defattr(-,root,root,-)
-%{_datadir}/license/toybox-symlinks-dhcp
%{_bindir}/dhcp
-%manifest toybox.manifest
%files symlinks-dhcpd
+%manifest toybox.manifest
+%license LICENSE
%defattr(-,root,root,-)
-%{_datadir}/license/toybox-symlinks-dhcpd
%{_bindir}/dumpleases
%{_sbindir}/dhcpd
-%manifest toybox.manifest
dumpleases
dhcp
-nslookup
scripts/single.sh $i > /dev/null 2>$PREFIX/${i}.bad &&
rm $PREFIX/${i}.bad || echo -n '*'
done
-echo
// This is intentionally crappy code because we control the inputs. It leaks
// memory like a sieve and segfaults if malloc returns null, but does the job.
-#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
-#include <ctype.h>
struct flag {
struct flag *next;
+++ /dev/null
-#!/bin/bash
-
-[ -f testing.sh ] && . testing.sh
-
-#testing "name" "command" "result" "infile" "stdin"
-
-# Test Unix date parsing.
-testing "date -d @0" "TZ=UTC date -d @0 2>&1" "Thu Jan 1 00:00:00 GMT 1970\n" "" ""
-testing "date -d @0x123" "TZ=UTC date -d @0x123 2>&1" "date: bad date '@0x123'\n" "" ""
-
-# Test basic date parsing.
-# Note that toybox's -d format is not the same as coreutils'.
-testing "date -d 06021234" "TZ=UTC date -d 06021234 2>&1" "Sun Jun 2 12:34:00 UTC 1900\n" "" ""
-testing "date -d 060212341982" "TZ=UTC date -d 060212341982 2>&1" "Sun Jun 2 12:34:00 UTC 1982\n" "" ""
-testing "date -d 123" "TZ=UTC date -d 123 2>&1" "date: bad date '123'\n" "" ""
-
-# Accidentally given a Unix time, we should trivially reject that.
-testing "date Unix time missing @" "TZ=UTC date 1438053157 2>&1" \
- "date: bad date '1438053157'; Tue February 38 05:31:00 UTC 2057 != Sun Mar 10 05:31:00 UTC 2058\n" "" ""
-# But some invalid dates are more subtle, like Febuary 29th in a non-leap year.
-testing "date Feb 29th" "TZ=UTC date 022900001975 2>&1" \
- "date: bad date '022900001975'; Tue Feb 29 00:00:00 UTC 2075 != Fri Mar 1 00:00:00 UTC 2075\n" "" ""
#include "toys.h"
GLOBALS(
- int ac, bat, therm, cool;
+ int ac;
+ int bat;
+ int therm;
+ int cool;
char *cpath;
)
return ret;
}
-static int acpi_callback(struct dirtree *tree)
+int acpi_callback(struct dirtree *tree)
{
int dfd, fd, len, on;
return 0;
}
-static int temp_callback(struct dirtree *tree)
+int temp_callback(struct dirtree *tree)
{
int dfd, temp;
- if (*tree->name=='.') return 0;
+ if (tree->name[0]=='.') return 0;
if (!tree->parent || !tree->parent->parent)
return DIRTREE_RECURSE|DIRTREE_SYMFOLLOW;
errno = 0;
if ((0 < (temp = read_int_at(dfd, "temp"))) || !errno) {
//some tempertures are in milli-C, some in deci-C
//reputedly some are in deci-K, but I have not seen them
- if (((temp >= 1000) || (temp <= -1000)) && (temp%100 == 0)) temp /= 100;
+ if (((temp >= 1000) || (temp <= -1000)) && (temp%100 == 0))
+ temp /= 100;
printf("Thermal %d: %d.%d degrees C\n", TT.therm++, temp/10, temp%10);
}
close(dfd);
}
free(TT.cpath);
-
return 0;
}
-static int cool_callback(struct dirtree *tree)
+int cool_callback(struct dirtree *tree)
{
int dfd=5, cur, max;
*
* See ftp://ftp.kernel.org/pub/linux/utils/util-linux/v2.24/libblkid-docs/api-index-full.html
-USE_BLKID(NEWTOY(blkid, 0, TOYFLAG_BIN))
+USE_BLKID(NEWTOY(blkid, "<1", TOYFLAG_BIN))
USE_FSTYPE(NEWTOY(fstype, "<1", TOYFLAG_BIN))
config BLKID
};
static const struct fstype fstypes[] = {
- {"swap", 0x4341505350415753, 8, 4086, 1036, 15, 1052},
{"ext2", 0xEF53, 2, 1080, 1128, 16, 1144}, // keep this first for ext3/4 check
// NTFS label actually 8/16 0x4d80 but horrible: 16 bit wide characters via
// codepage, something called a uuid that's only 8 bytes long...
{"vfat", 0x31544146, 4, 54, 39+(4<<24), 11, 43} // fat1
};
-static void do_blkid(int fd, char *name)
+/* TODO if no args use proc/partitions */
+void do_blkid(int fd, char *name)
{
int off, i, j;
char *type;
if (test == fstypes[i].magic) break;
}
- if (i == ARRAY_LEN(fstypes)) {
+ if (i == sizeof(fstypes)/sizeof(struct fstype)) {
off += len;
if (pass) continue;
return;
void blkid_main(void)
{
- if (*toys.optargs) loopfiles(toys.optargs, do_blkid);
- else {
- unsigned int ma, mi, sz, fd;
- char *name = toybuf, *buffer = toybuf+1024, device[32];
- FILE *fp = xfopen("/proc/partitions", "r");
-
- while (fgets(buffer, 1024, fp)) {
- *name = 0;
- if (sscanf(buffer, " %u %u %u %[^\n ]", &ma, &mi, &sz, name) != 4)
- continue;
-
- sprintf(device, "/dev/%.20s", name);
- if (-1 == (fd = open(device, O_RDONLY))) {
- if (errno != ENOMEDIUM) perror_msg("%s", device);
- } else {
- do_blkid(fd, device);
- close(fd);
- }
- }
- if (CFG_TOYBOX_FREE) fclose(fp);
- }
+ loopfiles(toys.optargs, do_blkid);
}
void fstype_main(void)
{
- loopfiles(toys.optargs, do_blkid);
+ blkid_main();
}
-/* bzcat.c - bzip2 decompression
+/* bzcat.c - decompress stdin to stdout using bunzip2.
*
* Copyright 2003, 2007 Rob Landley <rob@landley.net>
*
USE_BZCAT(NEWTOY(bzcat, NULL, TOYFLAG_USR|TOYFLAG_BIN))
-USE_BUNZIP2(NEWTOY(bunzip2, "cftkv", TOYFLAG_USR|TOYFLAG_BIN))
-
-config BUNZIP2
- bool "bunzip2"
- default y
- help
- usage: bunzip2 [-cftkv] [FILE...]
-
- Decompress listed files (file.bz becomes file) deleting archive file(s).
- Read from stdin if no files listed.
-
- -c force output to stdout
- -f force decompression. (If FILE doesn't end in .bz, replace original.)
- -k keep input files (-c and -t imply this)
- -t test integrity
- -v verbose
config BZCAT
bool "bzcat"
default y
help
- usage: bzcat [FILE...]
+ usage: bzcat [filename...]
Decompress listed files to stdout. Use stdin if no files listed.
*/
-#define FOR_bunzip2
#include "toys.h"
#define THREADS 1
}
// Flush output buffer to disk
-static void flush_bunzip_outbuf(struct bunzip_data *bd, int out_fd)
+void flush_bunzip_outbuf(struct bunzip_data *bd, int out_fd)
{
if (bd->outbufPos) {
if (write(out_fd, bd->outbuf, bd->outbufPos) != bd->outbufPos)
}
}
-static void burrows_wheeler_prep(struct bunzip_data *bd, struct bwdata *bw)
+void burrows_wheeler_prep(struct bunzip_data *bd, struct bwdata *bw)
{
int ii, jj;
unsigned int *dbuf = bw->dbuf;
}
// Decompress a block of text to intermediate buffer
-static int read_bunzip_data(struct bunzip_data *bd)
+int read_bunzip_data(struct bunzip_data *bd)
{
int rc = read_block_header(bd, bd->bwdata);
if (!rc) rc=read_huffman_data(bd, bd->bwdata);
// http://dogma.net/markn/articles/bwt/bwt.htm
// http://marknelson.us/1996/09/01/bwt/
-static int write_bunzip_data(struct bunzip_data *bd, struct bwdata *bw,
- int out_fd, char *outbuf, int len)
+int write_bunzip_data(struct bunzip_data *bd, struct bwdata *bw, int out_fd, char *outbuf, int len)
{
unsigned int *dbuf = bw->dbuf;
int count, pos, current, run, copies, outbyte, previous, gotcount = 0;
// Allocate the structure, read file header. If !len, src_fd contains
// filehandle to read from. Else inbuf contains data.
-static int start_bunzip(struct bunzip_data **bdp, int src_fd, char *inbuf,
- int len)
+int start_bunzip(struct bunzip_data **bdp, int src_fd, char *inbuf, int len)
{
struct bunzip_data *bd;
unsigned int i;
// Example usage: decompress src_fd to dst_fd. (Stops at end of bzip data,
// not end of file.)
-static char *bunzipStream(int src_fd, int dst_fd)
+void bunzipStream(int src_fd, int dst_fd)
{
struct bunzip_data *bd;
- char *bunzip_errors[] = {0, "not bzip", "bad data", "old format"};
+ char *bunzip_errors[]={NULL, "not bzip", "bad data", "old format"};
int i, j;
if (!(i = start_bunzip(&bd,src_fd, 0, 0))) {
for (j=0; j<THREADS; j++) free(bd->bwdata[j].dbuf);
free(bd);
-
- return bunzip_errors[-i];
+ if (i) error_exit(bunzip_errors[-i]);
}
static void do_bzcat(int fd, char *name)
{
- char *err = bunzipStream(fd, 1);
-
- if (err) error_exit(err);
+ bunzipStream(fd, 1);
}
void bzcat_main(void)
{
loopfiles(toys.optargs, do_bzcat);
}
-
-static void do_bunzip2(int fd, char *name)
-{
- int outfd = 1, rename = 0, len = strlen(name);
- char *tmp, *err, *dotbz = 0;
-
- // Trim off .bz or .bz2 extension
- dotbz = name+len-3;
- if ((len>3 && !strcmp(dotbz, ".bz")) || (len>4 && !strcmp(--dotbz, ".bz2")))
- dotbz = 0;
-
- // For - no replace
- if (toys.optflags&FLAG_t) outfd = xopen("/dev/null", O_WRONLY);
- else if ((fd || strcmp(name, "-")) && !(toys.optflags&FLAG_c)) {
- if (toys.optflags&FLAG_k) {
- if (!dotbz || !access(name, X_OK)) {
- error_msg("%s exists", name);
-
- return;
- }
- }
- outfd = copy_tempfile(fd, name, &tmp);
- rename++;
- }
-
- if (toys.optflags&FLAG_v) printf("%s:", name);
- err = bunzipStream(fd, outfd);
- if (toys.optflags&FLAG_v) {
- printf("%s\n", err ? err : "ok");
- toys.exitval |= !!err;
- } else if (err) error_msg(err);
-
- // can't test outfd==1 because may have been called with stdin+stdout closed
- if (rename) {
- if (toys.optflags&FLAG_k) {
- free(tmp);
- tmp = 0;
- } else {
- if (dotbz) *dotbz = '.';
- if (!unlink(name)) perror_msg("%s", name);
- }
- (err ? delete_tempfile : replace_tempfile)(-1, outfd, &tmp);
- }
-}
-
-void bunzip2_main(void)
-{
- loopfiles(toys.optargs, do_bunzip2);
-}
#define FOR_chcon
#include "toys.h"
-static int do_chcon(struct dirtree *try)
+int do_chcon(struct dirtree *try)
{
char *path, *con = *toys.optargs;
+++ /dev/null
-/* fsync.c - Synchronize a file's in-core state with storage device.
- *
- * Copyright 2015 Ranjan Kumar <ranjankumar.bth@gmail.comi>
- *
- * No Standard.
-
-USE_FSYNC(NEWTOY(fsync, "<1d", TOYFLAG_BIN))
-
-config FSYNC
- bool "fsync"
- default y
- help
- usage: fsync [-d] [FILE...]
-
- Synchronize a file's in-core state with storage device.
-
- -d Avoid syncing metadata.
-*/
-
-#define FOR_fsync
-#include "toys.h"
-
-static void do_fsync(int fd, char *name)
-{
- if (((toys.optflags & FLAG_d) ? fdatasync(fd) : fsync(fd)))
- perror_msg("can't sync '%s'", name);
-}
-
-void fsync_main(void)
-{
- loopfiles_rw(toys.optargs, O_RDONLY|O_NOATIME|O_NOCTTY|O_CLOEXEC,
- 0, 0, do_fsync);
-}
fd = xopen(*toys.optargs, ro ? O_RDONLY : O_RDWR);
char keybuf[16];
- *keybuf = 0;
-
// Terminal setup
TT.height = 25;
terminal_size(0, &TT.height);
+++ /dev/null
-/* hostid.c - Print the numeric identifier for the current host.
- *
- * Copyright 2015 Ranjan Kumar <ranjankumar.bth@gmail.com>
- *
- * No Standard.
-
-USE_HOSTID(NEWTOY(hostid, ">0", TOYFLAG_USR|TOYFLAG_BIN))
-
-config HOSTID
- bool "hostid"
- default y
- help
- usage: hostid
-
- Print the numeric identifier for the current host.
-*/
-#define FOR_hostid
-#include "toys.h"
-
-void hostid_main(void)
-{
- xprintf("%08lx\n", gethostid());
-}
* TODO: this command predates "pending" but needs cleanup. It #defines
* random stuff, calls exit() form a signal handler... yeah.
-USE_LOGIN(NEWTOY(login, ">1f:ph:", TOYFLAG_BIN|TOYFLAG_NEEDROOT))
+USE_LOGIN(NEWTOY(login, ">1fph:", TOYFLAG_BIN))
config LOGIN
bool "login"
default y
depends on TOYBOX_SHADOW
help
- usage: login [-p] [-h host] [-f USERNAME] [USERNAME]
+ usage: login [-p] [-h host] [[-f] username]
- Log in as a user, prompting for username and password if necessary.
+ Establish a new session with the system.
-p Preserve environment
-h The name of the remote host for this login
- -f login as USERNAME without authentication
+ -f Do not perform authentication
*/
#define FOR_login
#include "toys.h"
+#define USER_NAME_MAX_SIZE 32
+#define HOSTNAME_SIZE 32
+
GLOBALS(
char *hostname;
- char *username;
int login_timeout, login_fail_timeout;
)
exit(0);
}
+static char *forbid[] = {
+ "BASH_ENV", "ENV", "HOME", "IFS", "LD_LIBRARY_PATH", "LD_PRELOAD",
+ "LD_TRACE_LOADED_OBJECTS", "LD_BIND_NOW", "LD_AOUT_LIBRARY_PATH",
+ "LD_AOUT_PRELOAD", "LD_NOWARN", "LD_KEEPDIR", "SHELL", NULL
+};
+
+int verify_password(char * pwd)
+{
+ char *pass;
+
+ if (read_password(toybuf, sizeof(toybuf), "Password: ")) return 1;
+ if (!pwd) return 1;
+ if (pwd[0] == '!' || pwd[0] == '*') return 1;
+
+ pass = crypt(toybuf, pwd);
+ if (pass && !strcmp(pass, pwd)) return 0;
+
+ return 1;
+}
+
+void read_user(char * buff, int size)
+{
+ char hostname[HOSTNAME_SIZE+1];
+ int i = 0;
+
+ hostname[HOSTNAME_SIZE] = 0;
+ if (!gethostname(hostname, HOSTNAME_SIZE)) fputs(hostname, stdout);
+
+ fputs(" login: ", stdout);
+ fflush(stdout);
+
+ do {
+ int c = getchar();
+ if (c == EOF) exit(EXIT_FAILURE);
+ *buff = c;
+ } while (isblank(*buff));
+
+ if (*buff != '\n') if(!fgets(&buff[1], HOSTNAME_SIZE-1, stdin)) _exit(1);
+
+ while(i<HOSTNAME_SIZE-1 && isgraph(buff[i])) i++;
+ buff[i] = 0;
+}
+
+void handle_nologin(void)
+{
+ int fd = open("/etc/nologin", O_RDONLY);
+ int size;
+
+ if (fd == -1) return;
+
+ size = readall(fd, toybuf,sizeof(toybuf)-1);
+ toybuf[size] = 0;
+ if (!size) puts("System closed for routine maintenance\n");
+ else puts(toybuf);
+
+ close(fd);
+ fflush(stdout);
+ exit(1);
+}
+
+void handle_motd(void)
+{
+ int fd = open("/etc/motd", O_RDONLY);
+ int size;
+ if (fd == -1) return;
+
+ size = readall(fd, toybuf,sizeof(toybuf)-1);
+ toybuf[size] = 0;
+ puts(toybuf);
+
+ close(fd);
+ fflush(stdout);
+}
+
+void spawn_shell(const char *shell)
+{
+ const char * exec_name = strrchr(shell,'/');
+ if (exec_name) exec_name++;
+ else exec_name = shell;
+
+ snprintf(toybuf,sizeof(toybuf)-1, "-%s", shell);
+ execl(shell, toybuf, NULL);
+ error_exit("Failed to spawn shell");
+}
+
+void setup_environment(const struct passwd *pwd, int clear_env)
+{
+ if (chdir(pwd->pw_dir)) printf("bad home dir: %s\n", pwd->pw_dir);
+
+ if (clear_env) {
+ const char *term = getenv("TERM");
+ clearenv();
+ if (term) setenv("TERM", term, 1);
+ }
+
+ setenv("USER", pwd->pw_name, 1);
+ setenv("LOGNAME", pwd->pw_name, 1);
+ setenv("HOME", pwd->pw_dir, 1);
+ setenv("SHELL", pwd->pw_shell, 1);
+}
+
void login_main(void)
{
- char *forbid[] = {
- "BASH_ENV", "ENV", "HOME", "IFS", "LD_LIBRARY_PATH", "LD_PRELOAD",
- "LD_TRACE_LOADED_OBJECTS", "LD_BIND_NOW", "LD_AOUT_LIBRARY_PATH",
- "LD_AOUT_PRELOAD", "LD_NOWARN", "LD_KEEPDIR", "SHELL"
- };
- int hh = toys.optflags&FLAG_h, count, tty;
- char uu[33], *username, *pass = 0, *ss;
- struct passwd *pwd = 0;
+ int f_flag = toys.optflags & FLAG_f;
+ int h_flag = toys.optflags & FLAG_h;
+ char username[33], *pass = NULL, **ss;
+ struct passwd * pwd = NULL;
+ struct spwd * spwd = NULL;
+ int auth_fail_cnt = 0;
+
+ if (f_flag && toys.optc != 1) error_exit("-f requires username");
- for (tty=0; tty<3; tty++) if (isatty(tty)) break;
- if (tty == 3) error_exit("no tty");
+ if (geteuid()) error_exit("not root");
- for (count = 0; count < ARRAY_LEN(forbid); count++) unsetenv(forbid[count]);
+ if (!isatty(0) || !isatty(1) || !isatty(2)) error_exit("no tty");
openlog("login", LOG_PID | LOG_CONS, LOG_AUTH);
xsignal(SIGALRM, login_timeout_handler);
+ alarm(TT.login_timeout = 60);
- if (TT.username) username = TT.username;
- else username = *toys.optargs;
- for (count = 0; count < 3; count++) {
- alarm(TT.login_timeout = 60);
- tcflush(0, TCIFLUSH);
-
- if (!username) {
- int i;
+ for (ss = forbid; *ss; ss++) unsetenv(*ss);
- memset(username = uu, 0, sizeof(uu));
- gethostname(uu, sizeof(uu)-1);
- printf("%s%slogin: ", *uu ? uu : "", *uu ? " " : "");
- fflush(stdout);
-
- if(!fgets(uu, sizeof(uu)-1, stdin)) _exit(1);
+ while (1) {
+ tcflush(0, TCIFLUSH);
- // Remove trailing \n and so on
- for (i = 0; i<sizeof(uu); i++) if (uu[i]<=' ' || uu[i]==':') uu[i]=0;
- if (!*uu) {
- username = 0;
- continue;
- }
+ username[sizeof(username)-1] = 0;
+ if (*toys.optargs) xstrncpy(username, *toys.optargs, sizeof(username));
+ else {
+ read_user(username, sizeof(username));
+ if (!*username) continue;
}
- // If user exists and isn't locked
pwd = getpwnam(username);
- if (pwd && *pwd->pw_passwd != '!' && *pwd->pw_passwd != '*') {
+ if (!pwd) goto query_pass; // Non-existing user
- // Pre-authenticated or passwordless
- if (TT.username || !*pwd->pw_passwd) break;
+ if (pwd->pw_passwd[0] == '!' || pwd->pw_passwd[0] == '*')
+ goto query_pass; // Locked account
- // fetch shadow password if necessary
- if (*(pass = pwd->pw_passwd) == 'x') {
- struct spwd *spwd = getspnam (username);
+ if (f_flag) break; // Pre-authenticated
- if (spwd) pass = spwd->sp_pwdp;
- }
- } else if (TT.username) error_exit("bad -f '%s'", TT.username);
+ if (!pwd->pw_passwd[0]) break; // Password-less account
- // Verify password. (Prompt for password _before_ checking disable state.)
- if (!read_password(toybuf, sizeof(toybuf), "Password: ")) {
- int x = pass && (ss = crypt(toybuf, pass)) && !strcmp(pass, ss);
-
- // password go bye-bye now.
- memset(toybuf, 0, sizeof(toybuf));
- if (x) break;
+ pass = pwd->pw_passwd;
+ if (pwd->pw_passwd[0] == 'x') {
+ spwd = getspnam (username);
+ if (spwd) pass = spwd->sp_pwdp;
}
- syslog(LOG_WARNING, "invalid password for '%s' on %s %s%s", pwd->pw_name,
- ttyname(tty), hh ? "from " : "", hh ? TT.hostname : "");
+query_pass:
+ if (!verify_password(pass)) break;
+
+ f_flag = 0;
+ syslog(LOG_WARNING, "invalid password for '%s' on %s %s %s", username,
+ ttyname(0), h_flag?"from":"", h_flag?TT.hostname:"");
sleep(3);
puts("Login incorrect");
- username = 0;
+ if (++auth_fail_cnt == 3)
+ error_exit("Maximum number of tries exceeded (3)\n");
+
+ *username = 0;
pwd = 0;
+ spwd = 0;
}
alarm(0);
- // This had password data in it, and we reuse for motd below
- memset(toybuf, 0, sizeof(toybuf));
-
- if (!pwd) error_exit("max retries (3)");
- // Check twice because "this file exists" is a security test, and in
- // theory filehandle exhaustion or other error could make open/read fail.
- if (pwd->pw_uid && !access("/etc/nologin", R_OK)) {
- ss = readfile("/etc/nologin", toybuf, sizeof(toybuf));
- puts ((ss && *ss) ? ss : "nologin");
- free(ss);
- toys.exitval = 1;
-
- return;
- }
+ if (pwd->pw_uid) handle_nologin();
xsetuser(pwd);
- if (chdir(pwd->pw_dir)) printf("bad $HOME: %s\n", pwd->pw_dir);
-
- if (!(toys.optflags&FLAG_p)) {
- char *term = getenv("TERM");
-
- clearenv();
- if (term) setenv("TERM", term, 1);
- }
-
- setenv("USER", pwd->pw_name, 1);
- setenv("LOGNAME", pwd->pw_name, 1);
- setenv("HOME", pwd->pw_dir, 1);
- setenv("SHELL", pwd->pw_shell, 1);
+ setup_environment(pwd, !(toys.optflags & FLAG_p));
- // Message of the day
- if ((ss = readfile("/etc/motd", 0, 0))) {
- puts(ss);
- free(ss);
- }
+ handle_motd();
syslog(LOG_INFO, "%s logged in on %s %s %s", pwd->pw_name,
- ttyname(tty), hh ? "from" : "", hh ? TT.hostname : "");
+ ttyname(0), h_flag?"from":"", h_flag?TT.hostname:"");
- // can't xexec here because name doesn't match argv[0]
- snprintf(toybuf, sizeof(toybuf)-1, "-%s", basename_r(pwd->pw_shell));
- toy_exec((char *[]){toybuf, 0});
- execl(pwd->pw_shell, toybuf, NULL);
- error_exit("Failed to spawn shell");
+ spawn_shell(pwd->pw_shell);
}
FILE *db;
)
-static int do_lspci(struct dirtree *new)
+int do_lspci(struct dirtree *new)
{
char *p = toybuf, *vendor = toybuf+9, *device = toybuf+18,
driver[256], *vbig = 0, *dbig = 0, **fields;
{
int sock = -1, nbd, flags;
unsigned long timeout = 0;
+ struct addrinfo *addr, *p;
char *host=toys.optargs[0], *port=toys.optargs[1], *device=toys.optargs[2];
uint64_t devsize;
nbd = xopen(device, O_RDWR);
for (;;) {
int temp;
+ struct addrinfo hints;
// Find and connect to server
- sock = xconnect(host, port, AF_UNSPEC, SOCK_STREAM, 0, 0);
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_family = PF_UNSPEC;
+ hints.ai_socktype = SOCK_STREAM;
+ if (getaddrinfo(host, port, &hints, &addr)) addr = 0;
+ for (p = addr; p; p = p->ai_next) {
+ sock = socket(p->ai_family, p->ai_socktype, p->ai_protocol);
+ if (-1 != connect(sock, p->ai_addr, p->ai_addrlen)) break;
+ close(sock);
+ }
+ freeaddrinfo(addr);
+
+ if (!p) perror_exit("%s:%s", host, port);
+
temp = 1;
setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, &temp, sizeof(int));
*
* Copyright 2013 Elie De Brauwer <eliedebrauwer@gmail.com>
-USE_REBOOT(NEWTOY(reboot, "fn", TOYFLAG_SBIN|TOYFLAG_NEEDROOT))
+USE_REBOOT(NEWTOY(reboot, "n", TOYFLAG_SBIN|TOYFLAG_NEEDROOT))
USE_REBOOT(OLDTOY(halt, reboot, TOYFLAG_SBIN|TOYFLAG_NEEDROOT))
USE_REBOOT(OLDTOY(poweroff, reboot, TOYFLAG_SBIN|TOYFLAG_NEEDROOT))
bool "reboot"
default y
help
- usage: reboot/halt/poweroff [-fn]
+ usage: reboot/halt/poweroff [-n]
Restart, halt or powerdown the system.
- -f Don't signal init
-n Don't sync before stopping the system.
*/
void reboot_main(void)
{
- int types[] = {RB_AUTOBOOT, RB_HALT_SYSTEM, RB_POWER_OFF},
- sigs[] = {SIGINT, SIGUSR1, SIGUSR2}, idx;
+ int types[] = {RB_AUTOBOOT, RB_HALT_SYSTEM, RB_POWER_OFF};
if (!(toys.optflags & FLAG_n)) sync();
- idx = stridx("hp", *toys.which->name)+1;
- if (toys.optflags & FLAG_f) toys.exitval = reboot(types[idx]);
- else toys.exitval = kill(1, sigs[idx]);
+ toys.exitval = reboot(types[stridx("hp", *toys.which->name)+1]);
}
#include "toys.h"
-static void do_rev(int fd, char *name)
+void do_rev(int fd, char *name)
{
char *c;
-f display filesystem status instead of file status
-c Output specified FORMAT string instead of default
- 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 Fragment size
- %S Best transfer size |%t File system type |%T Type in human readable form
-
The valid format escape sequences for files:
%a Access bits (octal) |%A Access bits (flags)|%b Blocks allocated
%B Bytes per block |%d Device ID (dec) |%D Device ID (hex)
%x Access time |%X Access unix time |%y File write time
%Y File write unix time|%z Dir change time |%Z Dir change unix time
-config STAT_C
- bool
- default y
- depends on STAT && !TOYBOX_LSM_NONE
- help
- usage: stat
-
- %C Security context
+ 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 Fragment size
+ %S Best transfer size |%t File system type
*/
#define FOR_stat
struct group *group_name;
)
-static char* ftype_to_string(uint64_t ftype)
-{
- switch (ftype) {
- case 0xADFF: return "affs";
- case 0x5346544e: return "ntfs";
- case 0x1Cd1: return "devpts";
- case 0x137D: return "ext";
- case 0xEF51: return "ext2";
- case 0xEF53: return "ext2/ext3";
- case 0x1BADFACE: return "bfs";
- case 0x9123683E: return "btrfs";
- case 0x28cd3d45: return "cramfs";
- case 0x3153464a: return "jfs";
- case 0x7275: return "romfs";
- case 0x01021994: return "tmpfs";
- case 0x3434: return "nilfs";
- case 0x6969: return "nfs";
- case 0x9fa0: return "proc";
- case 0x534F434B: return "sockfs";
- case 0x62656572: return "sysfs";
- case 0x517B: return "smb";
- case 0x4d44: return "msdos";
- case 0x4006: return "fat";
- case 0x43415d53: return "smackfs";
- case 0x73717368: return "squashfs";
- default: return "unknown";
- }
-}
-
// Note: the atime, mtime, and ctime fields in struct stat are the start
// of embedded struct timespec, but posix won't let them use that
xprintf("%s", str);
} else if (type == 'b') xprintf("%llu", stat->st_blocks);
else if (type == 'B') xprintf("%lu", stat->st_blksize);
- else if (CFG_STAT_C && type == 'C') {
- char *label = NULL;
- if ((lsm_lget_context(*toys.optargs, (char **)&label) > 0) && label) {
- xprintf("%s", label);
- free(label);
- }
- }
else if (type == 'd') xprintf("%ldd", stat->st_dev);
else if (type == 'D') xprintf("%llxh", stat->st_dev);
else if (type == 'f') xprintf("%lx", stat->st_mode);
else if (type == 'f') xprintf("%llu", statfs->f_bfree);
else if (type == 'l') xprintf("%ld", statfs->f_namelen);
else if (type == 't') xprintf("%lx", statfs->f_type);
- else if (type == 'T') xprintf("%s", ftype_to_string(statfs->f_type));
else if (type == 'i')
xprintf("%08x%08x", statfs->f_fsid.__val[0], statfs->f_fsid.__val[1]);
else if (type == 's') xprintf("%d", statfs->f_frsize);
{
int flagf = toys.optflags & FLAG_f;
char *format = flagf
- ? " File: \"%n\"\n ID: %i Namelen: %l Type: %T\n"
+ ? " 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"
}
TT.rootdev=st2.st_dev;
- // trim any / characters from the init cmdline, as we want to test it with
- // stat(), relative to newroot. *cmdline is also used below, but by that
- // point we are in the chroot, so a relative path is still OK.
- while (**cmdline == '/') (*cmdline)++;
-
// init program must exist and be an executable file
- if (stat(*cmdline, &st1) || !S_ISREG(st1.st_mode) || !(st1.st_mode&0100)) {
+ if (stat("init", &st1) || !S_ISREG(st1.st_mode) || !(st1.st_mode&0100)) {
error_msg("bad init");
goto panic;
}
// Ok, enough safety checks: wipe root partition.
dirtree_read("/", del_node);
- // Fix the appearance of the mount table in the newroot chroot
- if (mount(".", "/", NULL, MS_MOVE, NULL)) {
- perror_msg("mount");
- goto panic;
- }
-
- // Enter the new root before starting init
- if (chroot(".")) {
- perror_msg("chroot");
- goto panic;
- }
-
- // Make sure cwd does not point outside of the chroot
- if (chdir("/")) {
- perror_msg("chdir");
- goto panic;
- }
-
if (TT.console) {
int i;
for (i=0; i<3; i++) if (console != i) dup2(console, i);
#include "toys.h"
-static void do_tac(int fd, char *name)
+void do_tac(int fd, char *name)
{
struct arg_list *list = NULL;
char *c;
}
}
-static int do_nproc(struct dirtree *new)
+int do_nproc(struct dirtree *new)
{
if (!new->parent) return DIRTREE_RECURSE;
if (!strncmp(new->name, "cpu", 3) && isdigit(new->name[3])) TT.nproc++;
// All the elements of vmstat_proc are the same size, so we can populate it as
// a big array, then read the elements back out by name
-static void get_vmstat_proc(struct vmstat_proc *vmstat_proc)
+void get_vmstat_proc(struct vmstat_proc *vmstat_proc)
{
char *vmstuff[] = { "/proc/stat", "cpu ", 0, 0, 0, 0, 0, 0,
"intr ", "ctxt ", "procs_running ", "procs_blocked ", "/proc/meminfo",
//out to STDERR
fprintf(stderr,"%llu+%llu records in\n%llu+%llu records out\n", st.in_full, st.in_part,
st.out_full, st.out_part);
- human_readable(toybuf, st.bytes, HR_SPACE|HR_B);
+ human_readable(toybuf, st.bytes);
fprintf(stderr, "%llu bytes (%s) copied, ",st.bytes, toybuf);
- human_readable(toybuf, st.bytes/seconds, HR_SPACE|HR_B);
+ human_readable(toybuf, st.bytes/seconds);
fprintf(stderr, "%f s, %s/s\n", seconds, toybuf);
}
reboot_magic_no=RB_POWER_OFF;
break;
case SIGTERM:
- case SIGINT:
error_msg("Requesting system reboot");
reboot_magic_no=RB_AUTOBOOT;
break;
errno_backup = errno;
signal_backup = caught_signal;
- xsignal(SIGCONT, catch_signal);
+ signal(SIGCONT, catch_signal);
while(1) {
if (caught_signal == SIGCONT) break;
putenv("USER=root");
inittab_parsing();
- xsignal(SIGUSR1, halt_poweroff_reboot_handler);//halt
- xsignal(SIGUSR2, halt_poweroff_reboot_handler);//poweroff
- xsignal(SIGTERM, halt_poweroff_reboot_handler);//reboot
- xsignal(SIGINT, halt_poweroff_reboot_handler);//reboot
- xsignal(SIGQUIT, restart_init_handler);//restart init
+ signal(SIGUSR1, halt_poweroff_reboot_handler);//halt
+ signal(SIGUSR2, halt_poweroff_reboot_handler);//poweroff
+ signal(SIGTERM, halt_poweroff_reboot_handler);//reboot
+ signal(SIGQUIT, restart_init_handler);//restart init
memset(&sig_act, 0, sizeof(sig_act));
sigfillset(&sig_act.sa_mask);
sigdelset(&sig_act.sa_mask, SIGCONT);
sigaction(SIGTSTP, &sig_act, NULL);
memset(&sig_act, 0, sizeof(sig_act));
sig_act.sa_handler = catch_signal;
+ sigaction(SIGINT, &sig_act, NULL);
sigaction(SIGHUP, &sig_act, NULL);
run_action_from_list(SYSINIT);
check_if_pending_signals();
static void make_device(char *path)
{
char *device_name = NULL, *s, *temp;
- int major = 0, minor = 0, type, len, fd;
+ int major, minor, type, len, fd;
int mode = 0660;
uid_t uid = 0;
gid_t gid = 0;
temp = strrchr(path, '/');
fd = open(path, O_RDONLY);
*temp=0;
- len = read(fd, toybuf, 64);
+ temp = toybuf;
+ len = read(fd, temp, 64);
close(fd);
if (len<1) return;
- toybuf[len] = 0;
+ temp[len] = 0;
// Determine device type, major and minor
type = path[5]=='c' ? S_IFCHR : S_IFBLK;
- sscanf(toybuf, "%u:%u", &major, &minor);
+ major = minor = 0;
+ sscanf(temp, "%u:%u", &major, &minor);
} else {
// if (!path), do hotplug
if (!(temp = getenv("SUBSYSTEM")))
return;
type = strcmp(temp, "block") ? S_IFCHR : S_IFBLK;
+ major = minor = 0;
if (!(temp = getenv("MAJOR")))
return;
sscanf(temp, "%u", &major);
device_name = getenv("DEVNAME");
if (!path)
return;
+ temp = toybuf;
}
if (!device_name)
device_name = strrchr(path, '/') + 1;
- // as in linux/drivers/base/core.c, device_get_devnode()
- while ((temp = strchr(device_name, '!'))) {
- *temp = '/';
- }
-
// If we have a config file, look up permissions for this device
if (CFG_MDEV_CONF) {
}
}
- sprintf(toybuf, "/dev/%s", device_name);
+ sprintf(temp, "/dev/%s", device_name);
- if ((temp=getenv("ACTION")) && !strcmp(temp, "remove")) {
- unlink(toybuf);
+ if (getenv("ACTION") && !strcmp(getenv("ACTION"), "remove")) {
+ unlink(temp);
return;
}
if (strchr(device_name, '/'))
- mkpathat(AT_FDCWD, toybuf, 0, 2);
- if (mknod(toybuf, mode | type, makedev(major, minor)) && errno != EEXIST)
- perror_exit("mknod %s failed", toybuf);
+ mkpathat(AT_FDCWD, temp, 0, 2);
+ if (mknod(temp, mode | type, makedev(major, minor)) && errno != EEXIST)
+ perror_exit("mknod %s failed", temp);
- if (type == S_IFBLK) close(open(toybuf, O_RDONLY)); // scan for partitions
+ if (type == S_IFBLK) close(open(temp, O_RDONLY)); // scan for partitions
- if (CFG_MDEV_CONF) mode=chown(toybuf, uid, gid);
+ if (CFG_MDEV_CONF) mode=chown(temp, uid, gid);
}
static int callback(struct dirtree *node)
static char *path2mod(char *file, char *mod)
{
int i;
- char *from;
+ char *from, *lslash;
if (!file) return NULL;
if (!mod) mod = xmalloc(MODNAME_LEN);
- from = basename_r(file);
+ lslash = strrchr(file, '/');
+ if (!lslash || (lslash == file && !lslash[1])) from = file;
+ else from = lslash + 1;
for (i = 0; i < (MODNAME_LEN-1) && from[i] && from[i] != '.'; i++)
mod[i] = (from[i] == '-') ? '_' : from[i];
get_mod(tokens[1], 1)->flags |= MOD_BLACKLIST;
else if (!strcmp(tokens[0], "install")) continue;
else if (!strcmp(tokens[0], "remove")) continue;
- else if (toys.optflags & FLAG_q)
- error_msg("Invalid option %s found in file %s", tokens[0], filename);
+ else error_msg("Invalid option %s found in file %s", tokens[0], filename);
}
fclose(fc);
free(filename);
}
res = syscall(__NR_init_module, buf, len, toybuf);
if (CFG_TOYBOX_FREE && buf != toybuf) free(buf);
+ if (res) perror_exit("failed to load %s ", toys.optargs[0]);
return res;
}
int rc = 0, first = 1;
if (!(m->flags & MOD_FNDDEPMOD)) {
- if (!(toys.optflags & FLAG_q))
+ if (!(toys.optflags & FLAG_s))
error_msg("module %s not found in modules.dep", m->name);
return -ENOENT;
}
*
* No Standard
-USE_SYSLOGD(NEWTOY(syslogd,">0l#<1>8=8R:b#<0>99=1B#<0>99=0s#<0=2000m#<0>71582787=20O:p:f:a:nSKLD", TOYFLAG_SBIN|TOYFLAG_STAYROOT))
+USE_SYSLOGD(NEWTOY(syslogd,">0l#<1>8=8R:b#<0>99=1s#<0=200m#<0>71582787=20O:p:f:a:nSKLD", TOYFLAG_SBIN|TOYFLAG_STAYROOT))
config SYSLOGD
bool "syslogd"
- default y
+ default n
help
usage: syslogd [-a socket] [-O logfile] [-f config file] [-m interval]
- [-p socket] [-s SIZE] [-b N] [-B N][-R HOST] [-l N] [-nSLKD]
+ [-p socket] [-s SIZE] [-b N] [-R HOST] [-l N] [-nSLKD]
System logging utility
-L Log locally and via network (default is network only if -R)"
-s SIZE Max size (KB) before rotation (default:200KB, 0=off)
-b N rotated logs to keep (default:1, max=99, 0=purge)
- -B N Set number of logs to keep logs in memory buffer before write (default:0, max=99, 0=purge)
-K Log to kernel printk buffer (use dmesg to read it)
-l N Log only messages more urgent than prio(default:8 max:8 min:1)
-D Drop duplicates
struct sockaddr_in saddr;
};
-// Log buffer
-struct logbuffer {
- int len;
- char buf[1024];
-};
-
GLOBALS(
char *socket;
char *config_file;
char *logfile;
long interval;
long rot_size;
- long buf_count;
long rot_count;
char *remote_log;
long log_prio;
//write to file with rotation
static int write_rotate(struct logfile *tf, int len)
{
- int size, isreg, idx;
- static int buf_idx = 0;
- static struct logbuffer buffer[100];
+ int size, isreg;
struct stat statf;
isreg = (!fstat(tf->logfd, &statf) && S_ISREG(statf.st_mode));
size = statf.st_size;
ftruncate(tf->logfd, 0);
}
}
- if (TT.buf_count && (toys.optflags & FLAG_B)) {
- if (buf_idx < TT.buf_count) {
- memcpy(buffer[buf_idx].buf, toybuf, len);
- buffer[buf_idx].buf[len + 1] = '\0';
- buffer[buf_idx].len = len;
- buf_idx++;
- return len;
- } else {
- for (idx = 0; idx < TT.buf_count; idx++) write(tf->logfd, buffer[idx].buf, buffer[idx].len);
- buf_idx = 0;
- }
- }
return write(tf->logfd, toybuf, len);
}
#define UF_ECHO 0x01
#define UF_SGA 0x02
+/*
+ * creates a socket of family INET/INET6 and protocol TCP and connects
+ * it to HOST at PORT.
+ * if successful then returns SOCK othrwise error
+ */
+static int xconnect_inet_tcp(char *host, int port)
+{
+ int ret;
+ struct addrinfo *info, *rp;
+ char buf[32];
+
+ rp = xzalloc(sizeof(struct addrinfo));
+ rp->ai_family = AF_UNSPEC;
+ rp->ai_socktype = SOCK_STREAM;
+ rp->ai_protocol = IPPROTO_TCP;
+ sprintf(buf, "%d", port);
+
+ ret = getaddrinfo(host, buf, rp, &info);
+ if(ret || !info) perror_exit("BAD ADDRESS: can't find : %s ", host);
+ free(rp);
+
+ for (rp = info; rp; rp = rp->ai_next)
+ if ( (rp->ai_family == AF_INET) || (rp->ai_family == AF_INET6)) break;
+
+ if (!rp) error_exit("Invalid IP %s", host);
+
+ ret = xsocket(rp->ai_family, SOCK_STREAM, IPPROTO_TCP);
+ if(connect(ret, rp->ai_addr, rp->ai_addrlen) == -1) perror_exit("connect");
+
+ freeaddrinfo(info);
+ return ret;
+}
+
// sets terminal mode: LINE or CHARACTER based om internal stat.
static char const es[] = "\r\nEscape character is ";
static void set_mode(void)
char input;
if(toys.signal && TT.term_ok) tcsetattr(0, TCSADRAIN, &TT.raw_term);
- xwrite(1,"\r\nConsole escape. Commands are:\r\n\n"
+ write(1,"\r\nConsole escape. Commands are:\r\n\n"
" l go to line mode\r\n"
" c go to character mode\r\n"
" z suspend telnet\r\n"
default: break;
}
- xwrite(1, "continuing...\r\n", 15);
+ write(1, "continuing...\r\n", 15);
if (toys.signal && TT.term_ok) tcsetattr(0, TCSADRAIN, &TT.def_term);
ret:
}
} while (TT.pbuff < len);
- if (i) xwrite(STDIN_FILENO, toybuf, i);
+ if (i) write(STDIN_FILENO, toybuf, i);
return 0;
}
if (*c == IAC) toybuf[i++] = *c; /* IAC -> IAC IAC */
else if (*c == '\r') toybuf[i++] = '\0'; /* CR -> CR NUL */
}
- if(i) xwrite(TT.sfd, toybuf, i);
+ if(i) write(TT.sfd, toybuf, i);
}
void telnet_main(void)
{
- char *port = "23";
int set = 1, len;
struct pollfd pfds[2];
+ TT.port = 23; //TELNET_PORT
TT.win_width = 80; //columns
TT.win_height = 24; //rows
- if (toys.optc == 2) port = toys.optargs[1];
+ if(toys.optc == 2) TT.port = atoi(toys.optargs[1]);
+ if(TT.port <= 0 || TT.port > 65535) error_exit("bad PORT (1-65535)");
TT.ttype = getenv("TERM");
if(!TT.ttype) TT.ttype = "";
}
terminal_size(&TT.win_width, &TT.win_height);
- TT.sfd = xconnect(*toys.optargs, port, 0, SOCK_STREAM, IPPROTO_TCP, 0);
+ TT.sfd = xconnect_inet_tcp(toys.optargs[0], TT.port);
setsockopt(TT.sfd, SOL_SOCKET, SO_REUSEADDR, &set, sizeof(set));
setsockopt(TT.sfd, SOL_SOCKET, SO_KEEPALIVE, &set, sizeof(set));
+++ /dev/null
-/* tftp.c - TFTP client.
- *
- * Copyright 2012 Madhur Verma <mad.flexi@gmail.com>
- * Copyright 2015 Sameer Prakash Pradhan <sameer.p.pradhan@gmail.com>
- *
- * No Standard.
-
-USE_TFTP(NEWTOY(tftp, "<1b#<8>65464r:l:g|p|[!gp]", TOYFLAG_USR|TOYFLAG_BIN))
-
-config TFTP
- bool "tftp"
- default n
- help
- usage: tftp [OPTIONS] HOST [PORT]
-
- Transfer file from/to tftp server.
-
- -l FILE Local FILE
- -r FILE Remote FILE
- -g Get file
- -p Put file
- -b SIZE Transfer blocks of SIZE octets(8 <= SIZE <= 65464)
-*/
-#define FOR_tftp
-#include "toys.h"
-
-GLOBALS(
- char *local_file;
- char *remote_file;
- long block_size;
-
- struct sockaddr_storage inaddr;
- int af;
-)
-
-#define TFTP_BLKSIZE 512
-#define TFTP_RETRIES 3
-#define TFTP_DATAHEADERSIZE 4
-#define TFTP_MAXPACKETSIZE (TFTP_DATAHEADERSIZE + TFTP_BLKSIZE)
-#define TFTP_PACKETSIZE TFTP_MAXPACKETSIZE
-#define TFTP_DATASIZE (TFTP_PACKETSIZE-TFTP_DATAHEADERSIZE)
-#define TFTP_IOBUFSIZE (TFTP_PACKETSIZE+8)
-
-#define TFTP_OP_RRQ 1 /* Read Request RFC 1350, RFC 2090 */
-#define TFTP_OP_WRQ 2 /* Write Request RFC 1350 */
-#define TFTP_OP_DATA 3 /* Data chunk RFC 1350 */
-#define TFTP_OP_ACK 4 /* Acknowledgement RFC 1350 */
-#define TFTP_OP_ERR 5 /* Error Message RFC 1350 */
-#define TFTP_OP_OACK 6 /* Option acknowledgment RFC 2347 */
-
-#define TFTP_ER_ILLEGALOP 4 /* Illegal TFTP operation */
-#define TFTP_ER_UNKID 5 /* Unknown transfer ID */
-
-#define TFTP_ES_NOSUCHFILE "File not found"
-#define TFTP_ES_ACCESS "Access violation"
-#define TFTP_ES_FULL "Disk full or allocation exceeded"
-#define TFTP_ES_ILLEGALOP "Illegal TFTP operation"
-#define TFTP_ES_UNKID "Unknown transfer ID"
-#define TFTP_ES_EXISTS "File already exists"
-#define TFTP_ES_UNKUSER "No such user"
-#define TFTP_ES_NEGOTIATE "Terminate transfer due to option negotiation"
-
-// Initializes SERVER with ADDR and returns socket.
-static int init_tftp(struct sockaddr_storage *server)
-{
- struct timeval to = { .tv_sec = 10, //Time out
- .tv_usec = 0 };
- const int set = 1;
- int port = 69, sd = xsocket(TT.af, SOCK_DGRAM, IPPROTO_UDP);
-
- xsetsockopt(sd, SOL_SOCKET, SO_RCVTIMEO, (void *)&to, sizeof(struct timeval));
- xsetsockopt(sd, SOL_SOCKET, SO_REUSEADDR, (void *)&set, sizeof(set));
-
- if(toys.optc == 2) port = atolx_range(toys.optargs[1], 1, 65535);
- memset(server, 0, sizeof(struct sockaddr_storage));
- if (TT.af == AF_INET6) {
- ((struct sockaddr_in6 *)server)->sin6_family = AF_INET6;
- ((struct sockaddr_in6 *)server)->sin6_addr =
- ((struct sockaddr_in6 *)&TT.inaddr)->sin6_addr;
- ((struct sockaddr_in6 *)server)->sin6_port = htons(port);
- }
- else {
- ((struct sockaddr_in *)server)->sin_family = AF_INET;
- ((struct sockaddr_in *)server)->sin_addr.s_addr =
- ((struct sockaddr_in *)&TT.inaddr)->sin_addr.s_addr;
- ((struct sockaddr_in *)server)->sin_port = htons(port);
- }
- return sd;
-}
-
-/*
- * Makes a request packet in BUFFER with OPCODE and file PATH of MODE
- * and returns length of packet.
- */
-static int mkpkt_request(uint8_t *buffer, int opcode, char *path, int mode)
-{
- buffer[0] = opcode >> 8;
- buffer[1] = opcode & 0xff;
- if(strlen(path) > TFTP_BLKSIZE) error_exit("path too long");
- return sprintf((char*) &buffer[2], "%s%c%s", path, 0,
- (mode ? "octet" : "netascii")) + 3;
-}
-
-/*
- * Makes an acknowledgement packet in BUFFER of BLOCNO
- * and returns packet length.
- */
-static int mkpkt_ack(uint8_t *buffer, uint16_t blockno)
-{
- buffer[0] = TFTP_OP_ACK >> 8;
- buffer[1] = TFTP_OP_ACK & 0xff;
- buffer[2] = blockno >> 8;
- buffer[3] = blockno & 0xff;
- return 4;
-}
-
-/*
- * Makes an error packet in BUFFER with ERRORCODE and ERRORMSG.
- * and returns packet length.
- */
-static int mkpkt_err(uint8_t *buffer, uint16_t errorcode, char *errormsg)
-{
- buffer[0] = TFTP_OP_ERR >> 8;
- buffer[1] = TFTP_OP_ERR & 0xff;
- buffer[2] = errorcode >> 8;
- buffer[3] = errorcode & 0xff;
- strcpy((char*) &buffer[4], errormsg);
- return strlen(errormsg) + 5;
-}
-
-/*
- * Recieves data from server in BUFF with socket SD and updates FROM
- * and returns read length.
- */
-static ssize_t read_server(int sd, void *buf, size_t len,
- struct sockaddr_storage *from)
-{
- socklen_t alen;
- ssize_t nb;
-
- for (;;) {
- memset(buf, 0, len);
- alen = sizeof(struct sockaddr_storage);
- nb = recvfrom(sd, buf, len, 0, (struct sockaddr *) from, &alen);
- if (nb < 0) {
- if (errno == EAGAIN) {
- perror_msg("server read timed out");
- return nb;
- }else if (errno != EINTR) {
- perror_msg("server read failed");
- return nb;
- }
- }else return nb;
- }
- return nb;
-}
-
-/*
- * sends data to server TO from BUFF of length LEN through socket SD
- * and returns successfully send bytes number.
- */
-static ssize_t write_server(int sd, void *buf, size_t len,
- struct sockaddr_storage *to)
-{
- ssize_t nb;
-
- for (;;) {
- nb = sendto(sd, buf, len, 0, (struct sockaddr *)to,
- sizeof(struct sockaddr_storage));
- if (nb < 0) {
- if (errno != EINTR) {
- perror_msg("server write failed");
- return nb;
- }
- } else return nb;
- }
- return nb;
-}
-
-// checks packet for data and updates block no
-static inline int check_data( uint8_t *packet, uint16_t *opcode,
- uint16_t *blockno)
-{
- *opcode = (uint16_t) packet[0] << 8 | (uint16_t) packet[1];
- if (*opcode == TFTP_OP_DATA) {
- *blockno = (uint16_t) packet[2] << 8 | (uint16_t) packet[3];
- return 0;
- }
- return -1;
-}
-
-// Makes data packet through FD from file OFFSET in buffer PACKET of BLOCKNO
-static int mkpkt_data(int fd, off_t offset, uint8_t *packet, uint16_t blockno)
-{
- off_t tmp;
- int nbytesread;
-
- packet[0] = TFTP_OP_DATA >> 8;
- packet[1] = TFTP_OP_DATA & 0xff;
- packet[2] = blockno >> 8;
- packet[3] = blockno & 0xff;
- tmp = lseek(fd, offset, SEEK_SET);
- if (tmp == (off_t) -1) {
- perror_msg("lseek failed");
- return -1;
- }
- nbytesread = readall(fd, &packet[TFTP_DATAHEADERSIZE], TFTP_DATASIZE);
- if (nbytesread < 0) return -1;
- return nbytesread + TFTP_DATAHEADERSIZE;
-}
-
-// Receives ACK responses from server and updates blockno
-static int read_ack(int sd, uint8_t *packet, struct sockaddr_storage *server,
- uint16_t *port, uint16_t *blockno)
-{
- struct sockaddr_storage from;
- ssize_t nbytes;
- uint16_t opcode, rblockno;
- int packetlen, retry;
-
- for (retry = 0; retry < TFTP_RETRIES; retry++) {
- for (;;) {
- nbytes = read_server(sd, packet, TFTP_IOBUFSIZE, &from);
- if (nbytes < 4) { // Ack headersize = 4
- if (nbytes == 0) error_msg("Connection lost.");
- else if (nbytes > 0) error_msg("Short packet: %d bytes", nbytes);
- else error_msg("Server read ACK failure.");
- break;
- } else {
- if (!*port) {
- *port = ((struct sockaddr_in *)&from)->sin_port;
- ((struct sockaddr_in *)server)->sin_port =
- ((struct sockaddr_in *)&from)->sin_port;
- }
- if (((struct sockaddr_in *)server)->sin_addr.s_addr !=
- ((struct sockaddr_in *)&from)->sin_addr.s_addr) {
- error_msg("Invalid address in DATA.");
- continue;
- }
- if (*port != ((struct sockaddr_in *)server)->sin_port) {
- error_msg("Invalid port in DATA.");
- packetlen = mkpkt_err(packet, TFTP_ER_UNKID, TFTP_ES_UNKID);
- (void) write_server(sd, packet, packetlen, server);
- continue;
- }
- opcode = (uint16_t) packet[0] << 8 | (uint16_t) packet[1];
- rblockno = (uint16_t) packet[2] << 8 | (uint16_t) packet[3];
-
- if (opcode != TFTP_OP_ACK) {
- error_msg("Bad opcode.");
- if (opcode > 5) {
- packetlen = mkpkt_err(packet, TFTP_ER_ILLEGALOP, TFTP_ES_ILLEGALOP);
- (void) write_server(sd, packet, packetlen, server);
- }
- break;
- }
- if (blockno) *blockno = rblockno;
- return 0;
- }
- }
- }
- error_msg("Timeout, Waiting for ACK.");
- return -1;
-}
-
-// receives file from server.
-static int file_get(void)
-{
- struct sockaddr_storage server, from;
- uint8_t *packet;
- uint16_t blockno = 0, opcode, rblockno = 0;
- int len, sd, fd, retry, nbytesrecvd = 0, ndatabytes, ret, result = -1;
-
- sd = init_tftp(&server);
-
- packet = (uint8_t*) xzalloc(TFTP_IOBUFSIZE);
- fd = xcreate(TT.local_file, O_WRONLY | O_CREAT | O_TRUNC, 0666);
-
- len = mkpkt_request(packet, TFTP_OP_RRQ, TT.remote_file, 1);
- ret = write_server(sd, packet, len, &server);
- if (ret != len){
- unlink(TT.local_file);
- goto errout_with_sd;
- }
- if (TT.af == AF_INET6) ((struct sockaddr_in6 *)&server)->sin6_port = 0;
- else ((struct sockaddr_in *)&server)->sin_port = 0;
-
- do {
- blockno++;
- for (retry = 0 ; retry < TFTP_RETRIES; retry++) {
- nbytesrecvd = read_server(sd, packet, TFTP_IOBUFSIZE, &from);
- if (nbytesrecvd > 0) {
- if ( ((TT.af == AF_INET) &&
- memcmp(&((struct sockaddr_in *)&server)->sin_addr,
- &((struct sockaddr_in *)&from)->sin_addr,
- sizeof(struct in_addr))) ||
- ((TT.af == AF_INET6) &&
- memcmp(&((struct sockaddr_in6 *)&server)->sin6_addr,
- &((struct sockaddr_in6 *)&from)->sin6_addr,
- sizeof(struct in6_addr)))) {
- error_msg("Invalid address in DATA.");
- retry--;
- continue;
- }
- if ( ((TT.af == AF_INET) && ((struct sockaddr_in *)&server)->sin_port
- && (((struct sockaddr_in *)&server)->sin_port !=
- ((struct sockaddr_in *)&from)->sin_port)) ||
- ((TT.af == AF_INET6) && ((struct sockaddr_in6 *)&server)->sin6_port
- && (((struct sockaddr_in6 *)&server)->sin6_port !=
- ((struct sockaddr_in6 *)&from)->sin6_port))) {
- error_msg("Invalid port in DATA.");
- len = mkpkt_err(packet, TFTP_ER_UNKID, TFTP_ES_UNKID);
- ret = write_server(sd, packet, len, &from);
- retry--;
- continue;
- }
- if (nbytesrecvd < TFTP_DATAHEADERSIZE) {
- error_msg("Tiny data packet ignored.");
- continue;
- }
- if (check_data(packet, &opcode, &rblockno) != 0
- || blockno != rblockno) {
-
- if (opcode == TFTP_OP_ERR) {
- char *message = "DATA Check failure.";
- char *arr[] = {TFTP_ES_NOSUCHFILE, TFTP_ES_ACCESS,
- TFTP_ES_FULL, TFTP_ES_ILLEGALOP,
- TFTP_ES_UNKID, TFTP_ES_EXISTS,
- TFTP_ES_UNKUSER, TFTP_ES_NEGOTIATE};
- if (rblockno && (rblockno < 9)) message = arr[rblockno - 1];
- error_msg(message);
- }
- if (opcode > 5) {
- len = mkpkt_err(packet, TFTP_ER_ILLEGALOP, TFTP_ES_ILLEGALOP);
- ret = write_server(sd, packet, len, &from);
- }
- continue;
- }
- if ((TT.af == AF_INET6) && !((struct sockaddr_in6 *)&server)->sin6_port)
- ((struct sockaddr_in6 *)&server)->sin6_port =
- ((struct sockaddr_in6 *)&from)->sin6_port;
- else if ((TT.af == AF_INET) && !((struct sockaddr_in *)&server)->sin_port)
- ((struct sockaddr_in *)&server)->sin_port =
- ((struct sockaddr_in *)&from)->sin_port;
- break;
- }
- }
- if (retry == TFTP_RETRIES) {
- error_msg("Retry limit exceeded.");
- unlink(TT.local_file);
- goto errout_with_sd;
- }
- ndatabytes = nbytesrecvd - TFTP_DATAHEADERSIZE;
- if (writeall(fd, packet + TFTP_DATAHEADERSIZE, ndatabytes) < 0){
- unlink(TT.local_file);
- goto errout_with_sd;
- }
- len = mkpkt_ack(packet, blockno);
- ret = write_server(sd, packet, len, &server);
- if (ret != len){
- unlink(TT.local_file);
- goto errout_with_sd;
- }
- } while (ndatabytes >= TFTP_DATASIZE);
-
- result = 0;
-
-errout_with_sd: xclose(sd);
- free(packet);
- return result;
-}
-
-// Sends file to server.
-int file_put(void)
-{
- struct sockaddr_storage server;
- uint8_t *packet;
- off_t offset = 0;
- uint16_t blockno = 1, rblockno, port = 0;
- int packetlen, sd, fd, retry = 0, ret, result = -1;
-
- sd = init_tftp(&server);
- packet = (uint8_t*)xzalloc(TFTP_IOBUFSIZE);
- fd = xopen(TT.local_file, O_RDONLY);
-
- for (;;) { //first loop for request send and confirmation from server.
- packetlen = mkpkt_request(packet, TFTP_OP_WRQ, TT.remote_file, 1);
- ret = write_server(sd, packet, packetlen, &server);
- if (ret != packetlen) goto errout_with_sd;
- if (read_ack(sd, packet, &server, &port, NULL) == 0) break;
- if (++retry > TFTP_RETRIES) {
- error_msg("Retry count exceeded.");
- goto errout_with_sd;
- }
- }
- for (;;) { // loop for data sending and receving ack from server.
- packetlen = mkpkt_data(fd, offset, packet, blockno);
- if (packetlen < 0) goto errout_with_sd;
-
- ret = write_server(sd, packet, packetlen, &server);
- if (ret != packetlen) goto errout_with_sd;
-
- if (read_ack(sd, packet, &server, &port, &rblockno) == 0) {
- if (rblockno == blockno) {
- if (packetlen < TFTP_PACKETSIZE) break;
- blockno++;
- offset += TFTP_DATASIZE;
- retry = 0;
- continue;
- }
- }
- if (++retry > TFTP_RETRIES) {
- error_msg("Retry count exceeded.");
- goto errout_with_sd;
- }
- }
- result = 0;
-
-errout_with_sd: close(sd);
- free(packet);
- return result;
-}
-
-void tftp_main(void)
-{
- struct addrinfo *info, rp, *res=0;
- int ret;
-
- if (toys.optflags & FLAG_r) {
- if (!(toys.optflags & FLAG_l)) {
- char *slash = strrchr(TT.remote_file, '/');
- TT.local_file = (slash) ? slash + 1 : TT.remote_file;
- }
- } else if (toys.optflags & FLAG_l) TT.remote_file = TT.local_file;
- else error_exit("Please provide some files.");
-
- memset(&rp, 0, sizeof(rp));
- rp.ai_family = AF_UNSPEC;
- rp.ai_socktype = SOCK_STREAM;
- ret = getaddrinfo(toys.optargs[0], toys.optargs[1], &rp, &info);
- if (!ret) {
- for (res = info; res; res = res->ai_next)
- if ( (res->ai_family == AF_INET) || (res->ai_family == AF_INET6)) break;
- }
- if (!res)
- error_exit("bad address '%s' : %s", toys.optargs[0], gai_strerror(ret));
- TT.af = info->ai_family;
-
- memcpy((void *)&TT.inaddr, info->ai_addr, info->ai_addrlen);
- freeaddrinfo(info);
-
- if (toys.optflags & FLAG_g) file_get();
- if (toys.optflags & FLAG_p) file_put();
-}
return buf;
}
+void xcheckrange(long val, long low, long high)
+{
+ char *err = "%ld %s than %ld";
+
+ if (val < low) error_exit(err, val, "less", low);
+ if (val > high) error_exit(err, val, "greater", high);
+}
+
// Worst case scenario toybuf usage: sizeof(struct tm) plus 21 bytes/line
// plus 8 lines/month plus 12 months, comes to a bit over 2k of our 4k buffer.
buf += sizeof(struct tm);
// Last argument is year, one before that (if any) is month.
- tm->tm_year = atolx_range(toys.optargs[--toys.optc], 1, 9999);
+ xcheckrange(tm->tm_year = atol(toys.optargs[--toys.optc]),1,9999);
tm->tm_year -= 1900;
tm->tm_mday = 1;
tm->tm_hour = 12; // noon to avoid timezone weirdness
if (toys.optc) {
- tm->tm_mon = atolx_range(toys.optargs[--toys.optc], 1, 12);
+ xcheckrange(tm->tm_mon = atol(toys.optargs[--toys.optc]),1,12);
tm->tm_mon--;
// Print 12 months of the year
char *mode;
)
-static int do_chmod(struct dirtree *try)
+int do_chmod(struct dirtree *try)
{
mode_t mode;
// This handles opening the file and
-static void do_cmp(int fd, char *name)
+void do_cmp(int fd, char *name)
{
int i, len1, len2, min_len, size = sizeof(toybuf)/2;
long byte_no = 1, line_no = 1;
// options shared between mv/cp must be in same order (right to left)
// for FLAG macros to work out right in shared infrastructure.
-USE_CP(NEWTOY(cp, "<2"USE_CP_PRESERVE("(preserve):;")"RHLPp"USE_CP_MORE("rdasl"USE_CP_Z("Z")"vnF(remove-destination)")"fi[-HLP"USE_CP_MORE("d")"]"USE_CP_MORE("[-ni]"), TOYFLAG_BIN))
-USE_MV(NEWTOY(mv, "<2"USE_CP_Z("Z")""USE_CP_MORE("vnF")"fi"USE_CP_MORE("[-ni]"), TOYFLAG_BIN))
-USE_INSTALL(NEWTOY(install, "<1"USE_INSTALL_Z("Z:")"cdDpsvm:o:g:", TOYFLAG_USR|TOYFLAG_BIN))
+USE_CP(NEWTOY(cp, "<2"USE_CP_PRESERVE("(preserve):;")"RHLPp"USE_CP_MORE("rdaslvnF(remove-destination)")"fi[-HLP"USE_CP_MORE("d")"]"USE_CP_MORE("[-ni]"), TOYFLAG_BIN))
+USE_MV(NEWTOY(mv, "<2"USE_CP_MORE("vnF")"fi"USE_CP_MORE("[-ni]"), TOYFLAG_BIN))
+USE_INSTALL(NEWTOY(install, "<1cdDpsvm:o:g:", TOYFLAG_USR|TOYFLAG_BIN))
config CP
bool "cp"
default y
depends on CP_MORE
help
- usage: cp [--preserve=motca]
+ usage: cp [--preserve=mota]
--preserve takes either a comma separated list of attributes, or the first
letter(s) of:
mode - permissions (ignore umask for rwx, copy suid and sticky bit)
ownership - user and group
timestamps - file creation, modification, and access times.
- context - preserve src's context.
all - all of the above
-config CP_Z
- bool
- default y
- depends on CP_MORE && !TOYBOX_LSM_NONE
- help
- usage: cp [-Z]
-
- set security context of destination file to default type
-
config MV
bool "mv"
default y
-p Preserve timestamps
-s Call "strip -p"
-v Verbose
-
-config INSTALL_Z
- bool
- default y
- depends on INSTALL && !TOYBOX_LSM_NONE
- help
- usage: [-Z context]
-
- -Z set security context
*/
#define FOR_cp
char *group;
char *user;
char *mode;
- char *context;
} i;
struct {
char *preserve;
- char *context;
} c;
};
xclose(fdout);
}
- if (CFG_MV && toys.which->name[0] == 'm') {
+ if (CFG_MV && toys.which->name[0] == 'm')
if (unlinkat(tfd, try->name, S_ISDIR(try->st.st_mode) ? AT_REMOVEDIR :0))
err = "%s";
- if (CFG_CP_Z) {
- if (0>lsm_lset_context(catch, TT.c.context))
- perror_exit("-Z '%s' failed", TT.c.context);
- }
- }
}
if (err) perror_msg(err, catch);
void cp_main(void)
{
char *destname = toys.optargs[--toys.optc],
- *preserve[] = {"mode", "ownership", "timestamps", "context"};
+ *preserve[] = {"mode", "ownership", "timestamps"};
int i, destdir = !stat(destname, &TT.top) && S_ISDIR(TT.top.st_mode);
if (toys.optc>1 && !destdir) error_exit("'%s' not directory", destname);
if (destdir) TT.destname = xmprintf("%s/%s", destname, basename(src));
else TT.destname = destname;
- // Preserve Context
- if (TT.pflags & 8) {
- TT.c.context = NULL;
- if (!CFG_TOYBOX_LSM_NONE && lsm_enabled()) {
- if (0>lsm_lget_context(src, &TT.c.context))
- perror_exit("unknown security context for '%s'", src);
- if (0>lsm_set_create(TT.c.context))
- perror_exit("preserve context '%s' failed", TT.c.context);
- free(TT.c.context);
- } else error_exit("%s disabled", lsm_name());
- }
-
errno = EXDEV;
if (CFG_MV && toys.which->name[0] == 'm') {
- if (CFG_CP_Z) {
- if (lsm_enabled()) {
- TT.c.context = NULL;
- if (toys.optflags & FLAG_Z) TT.c.context = lsm_context();
- else {
- if (0>lsm_lget_context(src, &TT.c.context))
- perror_exit("unknown security context for '%s'", src);
- }
- } else error_exit("%s disabled", lsm_name());
- }
if (!(toys.optflags & FLAG_f)) {
struct stat st;
}
}
- if (rc) {
- rc = rename(src, TT.destname);
- if (CFG_CP_Z) {
- if (!rc && (toys.optflags&FLAG_Z)
- && (0>lsm_lset_context(TT.destname, TT.c.context)))
- perror_exit("-Z '%s' failed", TT.c.context);
- }
- }
+ if (rc) rc = rename(src, TT.destname);
}
// Skip nonexistent sources
else dirtree_handle_callback(new, TT.callback);
}
if (destdir) free(TT.destname);
- if (CFG_CP_Z && CFG_MV && toys.which->name[0] == 'm'
- && (toys.optflags & FLAG_Z))
- free(TT.c.context);
}
}
char **ss;
int flags = toys.optflags;
- if (CFG_INSTALL_Z && (toys.optflags&FLAG_Z)) {
- if (lsm_enabled()) {
- if (0>lsm_set_create(TT.i.context))
- perror_exit("bad -Z '%s'", TT.i.context);
- } else error_msg("%s disabled", lsm_name());
- }
-
if (flags & FLAG_d) {
for (ss = toys.optargs; *ss; ss++) {
if (mkpathat(AT_FDCWD, *ss, 0777, 3)) perror_msg("%s", *ss);
* Note: setting a 2 year date is 50 years back/forward from today,
* not posix's hardwired magic dates.
-USE_DATE(NEWTOY(date, "d:D:r:u[!dr]", TOYFLAG_BIN))
+USE_DATE(NEWTOY(date, "d:s:r:u[!dr]", TOYFLAG_BIN))
config DATE
bool "date"
default y
help
- usage: date [-u] [-r FILE] [-d DATE] [+DISPLAY_FORMAT] [-D SET_FORMAT] [SET]
+ usage: date [-u] [-r FILE] [-d DATE] [+DISPLAY_FORMAT] [-s SET_FORMAT] [SET]
Set/get the current date/time. With no SET shows the current date.
Default SET format is "MMDDhhmm[[CC]YY][.ss]", that's (2 digits each)
month, day, hour (0-23), and minute. Optionally century, year, and second.
- Also accepts "@UNIXTIME[.FRACTION]" as seconds since midnight Jan 1 1970.
-d Show DATE instead of current time (convert date format)
- -D +FORMAT for SET or -d (instead of MMDDhhmm[[CC]YY][.ss])
-r Use modification time of FILE instead of current date
+ -s +FORMAT for SET or -d (instead of MMDDhhmm[[CC]YY][.ss])
-u Use UTC instead of current timezone
+FORMAT specifies display format string using these escapes:
char *file;
char *setfmt;
char *showdate;
-
- char *tz;
- unsigned nano;
)
-// mktime(3) normalizes the struct tm fields, but date(1) shouldn't.
-static time_t chkmktime(struct tm *tm, const char *str, const char* fmt)
-{
- struct tm tm0 = *tm;
- struct tm tm1;
- time_t t = mktime(tm);
-
- if (t == -1 || !localtime_r(&t, &tm1) ||
- tm0.tm_sec != tm1.tm_sec || tm0.tm_min != tm1.tm_min ||
- tm0.tm_hour != tm1.tm_hour || tm0.tm_mday != tm1.tm_mday ||
- tm0.tm_mon != tm1.tm_mon) {
- int len;
-
- strftime(toybuf, sizeof(toybuf), fmt, &tm0);
- len = strlen(toybuf) + 1;
- strftime(toybuf + len, sizeof(toybuf) - len, fmt, &tm1);
- error_exit("bad date '%s'; %s != %s", str, toybuf, toybuf + len);
- }
- return t;
-}
-
-static void utzset(void)
-{
- if (!(TT.tz = getenv("TZ"))) TT.tz = (char *)1;
- setenv("TZ", "UTC", 1);
- tzset();
-}
-
-static void utzreset(void)
-{
- if (TT.tz) {
- if (TT.tz != (char *)1) setenv("TZ", TT.tz, 1);
- else unsetenv("TZ");
- tzset();
- }
-}
-
-// Handle default posix date format (mmddhhmm[[cc]yy]) or @UNIX[.FRAC]
+// Handle default posix date format: mmddhhmm[[cc]yy]
// returns 0 success, nonzero for error
-static int parse_default(char *str, struct tm *tm)
+int parse_posixdate(char *str, struct tm *tm)
{
- int len = 0;
-
- // Parse @UNIXTIME[.FRACTION]
- if (*str == '@') {
- long long ll;
- time_t tt;
-
- // Collect seconds and nanoseconds
- // Note: struct tm hasn't got a fractional seconds field, thus strptime()
- // doesn't support it, so store nanoseconds out of band (in globals).
- // tt and ll are separate because we can't guarantee time_t is 64 bit (yet).
- sscanf(str, "@%lld%n", &ll, &len);
- if (str[len]=='.') {
- str += len+1;
- for (len = 0; len<9; len++) {
- TT.nano *= 10;
- if (isdigit(str[len])) TT.nano += str[len]-'0';
- }
- }
- if (str[len]) return 1;
- tt = ll;
- gmtime_r(&tt, tm);
-
- return 0;
- }
+ int len;
- // Posix format
+ len = 0;
sscanf(str, "%2u%2u%2u%2u%n", &tm->tm_mon, &tm->tm_mday, &tm->tm_hour,
&tm->tm_min, &len);
if (len != 8) return 1;
// 2 digit years, next 50 years are "future", last 50 years are "past".
// A "future" date in past is a century ahead.
// A non-future date in the future is a century behind.
- if (len == 2) {
- if ((r1 < r2) ? (r1 < year && year < r2) : (year < r1 || year > r2)) {
- if (year < r1) year += 100;
- } else if (year > r1) year -= 100;
- }
+ if ((r1 < r2) ? (r1 < year && year < r2) : (year < r1 || year > r2)) {
+ if (year < r1) year += 100;
+ } else if (year > r1) year -= 100;
tm->tm_year = year + century;
}
if (*str == '.') {
len = 0;
sscanf(str, ".%u%n", &tm->tm_sec, &len);
str += len;
- } else tm->tm_sec = 0;
+ }
return *str;
}
void date_main(void)
{
- char *setdate = *toys.optargs, *format_string = "%a %b %e %H:%M:%S %Z %Y";
+ char *setdate = *toys.optargs, *format_string = "%a %b %e %H:%M:%S %Z %Y",
+ *tz = 0;
struct tm tm;
- memset(&tm, 0, sizeof(struct tm));
-
// We can't just pass a timezone to mktime because posix.
- if (toys.optflags & FLAG_u) utzset();
+ if (toys.optflags & FLAG_u) {
+ if (CFG_TOYBOX_FREE) tz = getenv("TZ");
+ setenv("TZ", "UTC", 1);
+ tzset();
+ }
if (TT.showdate) {
+ setdate = TT.showdate;
if (TT.setfmt) {
char *s = strptime(TT.showdate, TT.setfmt+(*TT.setfmt=='+'), &tm);
- if (!s || *s) goto bad_showdate;
- } else if (parse_default(TT.showdate, &tm)) goto bad_showdate;
+ if (!s || *s) goto bad_date;
+ } else if (parse_posixdate(TT.showdate, &tm)) goto bad_date;
} else {
time_t now;
((toys.optflags & FLAG_u) ? gmtime_r : localtime_r)(&now, &tm);
}
+ setdate = *toys.optargs;
// Fall through if no arguments
if (!setdate);
// Display the date?
} else if (setdate) {
struct timeval tv;
- if (parse_default(setdate, &tm)) error_exit("bad date '%s'", setdate);
+ if (parse_posixdate(setdate, &tm)) goto bad_date;
if (toys.optflags & FLAG_u) {
+ char *tz = CFG_TOYBOX_FREE ? getenv("TZ") : 0;
+
// We can't just pass a timezone to mktime because posix.
- utzset();
- tv.tv_sec = chkmktime(&tm, setdate, format_string);
- utzreset();
- } else tv.tv_sec = chkmktime(&tm, setdate, format_string);
+ setenv("TZ", "UTC", 1);
+ tzset();
+ tv.tv_sec = mktime(&tm);
+ if (CFG_TOYBOX_FREE) {
+ if (tz) setenv("TZ", tz, 1);
+ else unsetenv("TZ");
+ tzset();
+ }
+ } else tv.tv_sec = mktime(&tm);
+ if (tv.tv_sec == (time_t)-1) goto bad_date;
- tv.tv_usec = TT.nano/1000;
+ tv.tv_usec = 0;
if (settimeofday(&tv, NULL) < 0) perror_msg("cannot set date");
}
- utzreset();
+ if (toys.optflags & FLAG_u) {
+ if (tz) setenv("TZ", tz, 1);
+ else unsetenv("TZ");
+ tzset();
+ }
+
if (!strftime(toybuf, sizeof(toybuf), format_string, &tm))
perror_exit("bad format '%s'", format_string);
puts(toybuf);
return;
-bad_showdate:
- error_exit("bad date '%s'", TT.showdate);
+bad_date:
+ error_exit("bad date '%s'", setdate);
}
if (TT.maxdepth && TT.depth > TT.maxdepth) return;
if (toys.optflags & FLAG_h) {
- human_readable(toybuf, size, 0);
+ human_readable(toybuf, size);
printf("%s", toybuf);
} else {
int bits = 10;
free(s);
}
+char *strlower(char *s)
+{
+ char *try, *new;
+
+ if (!CFG_TOYBOX_I18N) {
+ try = new = xstrdup(s);
+ for (; *s; s++) *(new++) = tolower(*s);
+ } else {
+ // I can't guarantee the string _won't_ expand during reencoding, so...?
+ try = new = xmalloc(strlen(s)*2+1);
+
+ while (*s) {
+ wchar_t c;
+ int len = mbrtowc(&c, s, MB_CUR_MAX, 0);
+
+ if (len < 1) *(new++) = *(s++);
+ else {
+ s += len;
+ // squash title case too
+ c = towlower(c);
+
+ // if we had a valid utf8 sequence, convert it to lower case, and can't
+ // encode back to utf8, something is wrong with your libc. But just
+ // in case somebody finds an exploit...
+ len = wcrtomb(new, c, 0);
+ if (len < 1) error_exit("bad utf8 %x", (int)c);
+ new += len;
+ }
+ }
+ *new = 0;
+ }
+
+ return try;
+}
+
// Call this with 0 for first pass argument parsing and syntax checking (which
// populates argdata). Later commands traverse argdata (in order) when they
// need "do once" results.
printf("%s%u(%s)", header, u, s);
}
-static void do_id(char *username)
+void do_id(char *username)
{
int flags, i, ngroups;
struct passwd *pw;
mode_to_string(mode, perm);
printf("%s% *ld", perm, totals[2]+1, (long)st->st_nlink);
- // print user
- if (!(flags&FLAG_g)) {
- if (flags&FLAG_n) sprintf(ss = thyme, "%u", (unsigned)st->st_uid);
- else strwidth(ss = getusername(st->st_uid));
- printf(" %*s", (int)totals[3], ss);
- }
-
// print group
if (!(flags&FLAG_o)) {
if (flags&FLAG_n) sprintf(ss = thyme, "%u", (unsigned)st->st_gid);
printf(" %*s", (int)totals[4], ss);
}
+ if (!(flags&FLAG_g)) {
+ if (flags&FLAG_n) sprintf(ss = thyme, "%u", (unsigned)st->st_uid);
+ else strwidth(ss = getusername(st->st_uid));
+ printf(" %*s", (int)totals[3], ss);
+ }
+
if (flags & FLAG_Z)
printf(" %*s", -(int)totals[7], (char *)sort[next]->extra);
long lcount;
)
-static void do_nl(int fd, char *name)
+void do_nl(int fd, char *name)
{
FILE *f = xfdopen(fd, "r");
int w = TT.w, slen = strlen(TT.s);
char *outfile;
)
-static void do_split(int infd, char *in)
+void do_split(int infd, char *in)
{
unsigned long bytesleft, linesleft, filenum, len, pos;
int outfd = -1;
long num;
)
-static void do_strings(int fd, char *filename)
+void do_strings(int fd, char *filename)
{
int nread, i, wlen = TT.num, count = 0;
off_t offset = 0;
+++ /dev/null
-Samsung developed commands
-
-These are commands developed at Samsung Electrnocis Co. Ltd.
+++ /dev/null
-/* nslookup.c - query Internet name servers
- *
- * Copyright 2013 Ashwini Kumar <ak.ashwini@gmail.com>
- * Copyright 2015 Rajni Kant <rajnikant12345@gmail.com>
- *
-
-USE_NSLOOKUP(NEWTOY(nslookup, "<1?", TOYFLAG_USR|TOYFLAG_BIN))
-
-config NSLOOKUP
- bool "nslookup"
- default y
- help
- usage: nslookup [HOST] [SERVER]
-
- Query the nameserver for the IP address of the given HOST
- optionally using a specified DNS server.
-
- Note:- Only non-interactive mode is supported.
-*/
-
-#define FOR_nslookup
-#include "toys.h"
-#include <resolv.h>
-
-static char *address_to_name(struct sockaddr *sock)
-{
- //man page of getnameinfo.
- char hbuf[NI_MAXHOST] = {0,}, sbuf[NI_MAXSERV] = {0,};
- int status = 0;
- if (sock->sa_family == AF_INET) {
- socklen_t len = sizeof(struct sockaddr_in);
- if ((status = getnameinfo(sock, len, hbuf, sizeof(hbuf), sbuf, sizeof(sbuf),
- NI_NUMERICHOST | NI_NUMERICSERV)) == 0)
- return xmprintf("%s:%s", hbuf, sbuf);
- else {
- fprintf(stderr, "getnameinfo: %s\n", gai_strerror(status));
- return NULL;
- }
- }
- else if (sock->sa_family == AF_INET6) {
- socklen_t len = sizeof(struct sockaddr_in6);
- if ((status = getnameinfo(sock, len, hbuf, sizeof(hbuf), sbuf,
- sizeof(sbuf), NI_NUMERICHOST | NI_NUMERICSERV)) == 0) {
- //verification for resolved hostname.
- if (strchr(hbuf, ':')) return xmprintf("[%s]:%s", hbuf, sbuf);
- else return xmprintf("%s:%s", hbuf, sbuf);
- }
- else {
- fprintf(stderr, "getnameinfo: %s\n", gai_strerror(status));
- return NULL;
- }
- }
- else if (sock->sa_family == AF_UNIX) {
- struct sockaddr_un *sockun = (void*)sock;
- return xmprintf("local:%.*s", (int) sizeof(sockun->sun_path), sockun->sun_path);
- }
- return NULL;
-}
-
-static void print_addrs(char *hostname, char *msg)
-{
- struct addrinfo hints, *res = NULL, *cur = NULL;
- int ret_ga;
- char *n = xstrdup(hostname), *p, *tmp;
- tmp = n;
- if ((*n == '[') && (p = strrchr(n, ']')) != NULL ) {
- n++;
- *p = '\0';
- }
-
- memset(&hints, 0, sizeof(struct addrinfo));
- hints.ai_socktype = SOCK_STREAM;
-
- ret_ga = getaddrinfo(n, NULL, &hints, &res);
- if (ret_ga) perror_exit("Hostname %s", gai_strerror(ret_ga));
-
- cur = res;
- while(cur) {
- char *colon = NULL;
- char *name = address_to_name(cur->ai_addr);
- if (name) {
- colon = strrchr(name, ':');
- if (colon) *colon = '\0';
- xprintf("%-8s %s\n",msg, hostname);
- xprintf("Address: %s\n", name);
- free(name);
- }
- cur = cur->ai_next;
- }
- if (!res->ai_addr) error_exit("getaddrinfo failed");
-
- freeaddrinfo(res);
- free(tmp);
-}
-
-static void resolve_addr(char *host, void *addr, char* port)
-{
- struct addrinfo *info, hint;
- int ret = atolx(port);
-
- if(ret <0 || ret > 65535 ) error_exit("bad port: %s", port);
- if (strncmp(host, "local:", 6) == 0) {
- struct sockaddr *sockun = (struct sockaddr *)addr;
- sockun->sa_family = AF_UNIX;
- strncpy(((struct sockaddr_un *)sockun)->sun_path, host + 6,
- sizeof(((struct sockaddr_un *)sockun)->sun_path));
- return ;
- }
- memset(&hint, 0, sizeof(hint));
-
- ret = getaddrinfo(host, port , &hint, &info);
-
- if (ret || !info) error_exit("bad address: %s", host);
-
- memcpy(addr, info->ai_addr, info->ai_addrlen);
- freeaddrinfo(info);
-}
-
-void nslookup_main(void)
-{
- struct sockaddr* sock;
- char *args[2] = {0,0}, *colon = NULL, *name = NULL;
-
- res_init(); //initialize the _res struct, for DNS name.
-
- for (;*toys.optargs; toys.optargs++) {
- if (**toys.optargs == '-') {
- if (!strncmp(&toys.optargs[0][1], "retry=", 6)) {
- _res.retry = atolx(toys.optargs[0]+7);
- } else if (!strncmp(&toys.optargs[0][1], "timeout=", 8)) {
- _res.retrans = atolx(toys.optargs[0]+9);
- } else error_msg("invalid option '%s'", *toys.optargs);
- } else if (!args[0]) args[0] = *toys.optargs;
- else if (!args[1]) args[1] = *toys.optargs;
- else error_exit("bad arg '%s'",*toys.optargs);
- }
-
- if ( !*args) {
- toys.exithelp++;
- error_exit("Needs 1 args minimum");
- }
- if (args[1]) { //set the default DNS
- struct sockaddr_storage addr;
- char* port = NULL ;
-
- if (args[1][0] == '[') {
- int len = strchr(args[1],']') - &args[1][0];
- if (len > 45|| len <= 0 ) error_exit("bad address: %s", args[1]);
- strncpy(toybuf,&args[1][1], len-1);
- args[1] += len;
- }
- if ((port = strchr(args[1],':'))) {
- *port = '\0';
- port++;
- }
- else port = "53";
-
- resolve_addr((toybuf[0])?toybuf:args[1], &addr, port );
-
- if (addr.ss_family == AF_INET) {
- _res.nscount = 1;
- _res.nsaddr_list[0] = *((struct sockaddr_in*)&addr);
- }
- else if (addr.ss_family == AF_INET6) {
- _res._u._ext.nscount = 1;
- _res._u._ext.nsaddrs[0] = ((struct sockaddr_in6*)&addr);
- }
- }
-
- sock = (struct sockaddr*)_res._u._ext.nsaddrs[0];
- if (!sock) sock = (struct sockaddr*)&_res.nsaddr_list[0];
- if ((name = address_to_name(sock))) {
- colon = strrchr(name, ':');
- if (colon) *colon = '\0';
- print_addrs(name, "Server:");
- free(name);
- }
- puts("");
-
- print_addrs(args[0], "Name:");
-}
<h2>News</h2>
-<a name="23-07-2015" /><a href="#23-07-2015"><hr><h2><b>July 23, 2015</b></h2></a>
-<p>I recreated the <a href=downloads/toybox-0.6.0.tar.gz>0.6.0 source tarball</a>
-(new sha1sum 08fb1c23f520c25a15f262a8a95ea5b676a98d54)
-because I forgot to add --prefix to the git archive command when I updated
-my release script from mercurial, so the files weren't in an enclosing
-directory. (Ooops.)</p>
-
-<a name="19-07-2015" /><a href="#19-07-2015"><hr><h2><b>July 19, 2015</b></h2></a>
-<blockquote><p>
-The reason why it was published in the form of a micro sub meson electronic
-component is that if it were printed in normal book form, an interstellar
-hitchhiker would require several inconveniently large buildings to carry it
-around in." - The Hitchhiker's Guide to the Galaxy </p></blockquote>
-
-<p><a href=downloads/toybox-0.6.0.tar.gz>Toybox 0.6.0</a>
-(<a href=https://github.com/landley/toybox/releases/tag/0.6.0>git commit</a>)
-is out. (Yes, git. See the <a href=#05-04-2015>previous news entry</a>.)</p>
-
-<p>Sorry for the unusually long gap between releases. Since last release Ye
-Olde Project Maintainer traveled to japan twice and had two more "once
-a century" floods at home. (Probably a coincidence.) Still catching up.</p>
-
-<h3><b>CELF/ELC talk and Wikipedia[citation needed] article</b></h3>
-
-<p>I gave another State Of The Toybox talk
-(<a href=https://www.youtube.com/watch?v=04XwAbtPmAg>video</a>
-<a href=http://landley.net/talks/celf-2015.txt>outline</a>), in which I
-repeat my <a href=http://landley.net/notes-2013.html#07-11-2013>perennial</a>
-<a href=https://twitter.com/landley/status/557309224535851009>complaint</a>
-that Wikipedia[citation needed]
-<a href=http://en.wikipedia.org/wiki/Toybox>still</a>
-<a href=https://en.wikipedia.org/wiki/BusyBox#Controversy_over_Toybox>says</a>
-toybox was relicensed before its hiatus, when relicensing was why
-the hiatus ended.</p>
-
-<p>Since Wikipedia[citation needed] seems unable to do the
-<a href=#15-11-2011>most</a>
-<a href=http://landley.net/hg/toybox/log/tip/LICENSE>basic</a>
-<a href=http://landley.net/notes-2011.html#13-11-2011>research</a> on
-this point, and has stuck to an incorrect sequence of events for years,
-I've been gradually escalating my attempts to correct them. Toybox
-came out of mothballs in November 2011 <b>because</b> it could be
-relicensed. That's what opened up a new niche busybox wasn't already
-filling with a 10 year headstart.</p>
-
-<a name="asterisk_back" />
-<p>The article has plenty of smaller issues<a href=#asterisk>*</a>, but
-given that I gave an entire talk at Ohio LinuxFest in 2013
-(<a href=http://landley.net/talks/ohio-2013.txt>outline</a>,
-<a href=https://archive.org/download/OhioLinuxfest2013/24-Rob_Landley-The_Rise_and_Fall_of_Copyleft.mp3>audio</a>) on why I switched away from GPL for
-my projects, that one bugs me.</p>
-
-<h3><b>New stuff this release</b></h3>
-
-<p>There's a new android menu in menuconfig, and rather a lot of Linux
-Security Module support (Smack for Tizen from Xavier Roche and José Bollo,
-and SELinux for Android from Elliott Hughes; see
-the Security Blanket menu under global settings in menuconfig) has
-trickled in, although there's still more to come.</p>
-
-<p><b>New commands:</b> Added reset, nproc, ionice, and iorenice.
-Elliott Hughes contributed xxd, runcon,
-restorecon, load_policy, getenforce, setenforce, getprop, and setprop.
-Promoted shred, nsenter, and hwclock.</p>
-
-<p>You can once again build catv now the flag infrastructure's been updated to
-let it coexist with cat -v.
-And on a long plane flight I wrote
-hexedit, an interactive hex editor that implements the start of
-cursor control infrastructure (for eventual use by less and vi and shell
-command history and so on).</p>
-
-<p><b>New options:</b> Added sed -E as a BSD-compatible synonym for -r.
-Upgraded oneit with -r (restart), -3 (send exiting PID values to child),
-and signal handling. Added -v option to timeout, -m to mknod, -u to shred,
--t to dmesg, and -123 to head and tail. Added implicit "." to grep -r without
-any files to work on. Hyejin Kim requested prefix support for truncate -s.
-Greg Hackman added -inum to find.
-Jan Cybulski added the smack side of ls -Z support. Various patches also
-added -Z to mkdir, mknod, and mkfifo.
-Basic cp --preserve support went in, but not yet the xattr/LSM parts.</p>
-
-<p>The toybox command now has a --version option,
-which uses "git describe" if available.</p>
-
-<p><b>Build infrastructure:</b>
-The "make change" target now saves the output of each failed standalone
-command build in a .bad file, and "make defconfig" is quieter now.</p>
-
-<p>Paul Barker submitted a large patch changing command install paths so
-"toybox can be installed alongside busybox without confusing
-update-alternatives". (There's some argument over
-what the right paths should be, and I'm waiting for
-people to tell me what else needs fixing because I have no idea. I've
-been symlinking /bin to /usr/bin since 2002
-<a href=http://landley.net/writing/hackermonthly-issue022-pg33.pdf>for
-historical reasons</a>.)</p>
-
-<p><b>Docs:</b> The repository link now goes to github, with another link
-to the commit rss feed.</p>
-
-<p>Elliott Hughes updated the Android section of the roadmap
-(and he would know). Redid bits of scripts/mkstatus.py to make updating
-status.html easier, and the README is larger.</p>
-
-<p>More description of option parsing in code.html, which now describes the
-FLAG_x macros, switching flag macro sets with FOR_newcommand, how
-configuration zeroes flag macros and using FORCE_FLAGS to suppress the
-zeroing of options shared between commands. Also added description of ";"
-to make --longopts take an optional =value part, and more about TOYBOX_DEBUG
-to check NEWTOY() option strings (otherwise a bad option string makes
-lib/args.c obviously segfault, but doesn't explain why).</p>
-
-<p>Added a "Why 0BSD?" section to license.html when submitting zero clause bsd
-to SPDX (according to the pending license spreadsheet, it's been approved for
-SPDX 2.2).</p>
-
-<p>The old list of commands needing cleanup but not in pending was
-removed from toys/pending/README and instead the issues were added
-as TODO comments in the individual commands.</p>
-
-<p><b>Bugfixes:</b>
-Fixed mount -a segfaulting without -O (reported by Janus Troelsen),
-and made it try a "become rw" ioctl() on the block device before falling
-back to mounting read only (because Android expects that).
-Fixed printf -- and printf ---. Lots of tweaks to ls -l spacing with
-different options. Make touch -d and -t actually set time when you don't
-specify nanoseconds.
-Fixed a subtle bug where recursive calls (toybox commands that run other
-toybox commands) weren't resetting all their state. (This manifested as
-a "no }" error from "find | xargs sed", but could cause other problems.)
-And David Halls reported another sed bug trying to compile libiconv (which
-left extra \ at the start of lines in a generated shell script, breaking
-the build). Output an error message for "cat /mnt".</p>
-
-<p>Kylie McClain reported that mktemp broke when $TMPDIR was set to an empty
-string (which is not the same as unset), that install/find didn't support
-numeric uid/gids, and that sort -z affects both input and output.
-Isabella Parakiss fixed a printf.c bug.
-David Halls fixed bugs in install -D and find -exec. Samuel Holland
-fixed unshare -r. Hyejin Kim fixed makedevs with a count of 1, fold -w
-range checking, an error path in scripts/mkflags.c, added -i to dhcpd,
-and stopped su from prompting the root user for the new user's password.
-Jan Cybulski spotted wrong indentation when combining ls -s and -i with -C and
--x. José Bollo fixed stat %G. Sameer Pradhan fixed a bug in mkfifo -Z.</p>
-
-<p>Elliott Hughes asked for a default SIGPIPE handler to disable
-the signal handler bionic's dynamic loader installs (yes really). Still not
-100% sure what the correct behavior is there. (Posix is
-(<a href=http://permalink.gmane.org/gmane.comp.standards.posix.austin.general/10915>actively unhelpful</a>, but at least they're taking
-<a href=http://austingroupbugs.net/view.php?id=789#c1976>years to
-make up their mind</a>. Elliott also sent patches to fix a typo in
-useradd.test, add missing arguments to error_exit() calls and clean up
-printf() format strings, fix an off by one error in human_readable(),
-fix dmesg -c error reporting, fix a segfault in comma_scan where the option
-was the last item in optlist (triggered by mount -o ro,remount), fix
-hwclock -w, made ifconfig print lowercase MAC addresses (it was bothering
-him), and make terminal_size() read the right environment variable
-(LINES, not ROWS). And he suggested the test suite notice high command exit
-values (corresponding to segfault or other signals).</p>
-
-<p>People are apparently using toys/pending commands, despite the police tape
-and flashing lights, so added louder warnings to toys/pending/README.
-Elliott Hughes fixed various problems with tar, dd, more, and top.
-Hyejin Kim cleaned up syslogd and dumpleases. Isaac Dunham added hotplug
-support to mdev. Yeongdeok Suh added RFC-3315 ipv6 support to dhcpd.</p>
-
-<p>I rewrote ps.c from scratch (in pending), but it's not ready for real use
-yet.</p>
-
-<p><b>Portability:</b>
-On the portability front Bernhard Rosenkranzer fixed a problem where the
-menuconfig code wouldn't compile in C99 mode. (This led to me documenting
-the craptacular nature of kconfig in a README, and the plan to replace it
-sometime before 1.0.) Some extra flags to shut up overzealous llvm warnings
-were added (and have to be probed for because gcc complains about
-arguments it doesn't recognize even when they switch stuff _off_ using
-a standard syntax). Don't depend on malloc(0) to return non-null in ls.
-David Halls fixed some mac/ios portability issues,
-implying somebody's built at least part of toybox on a mac.</p>
-
-<p>Added basename_r() to lib/lib.c because the posix semantics for basename()
-are stupid but what the gnu guys did to it was appalling.
-Turns out bionic already had a basename_r(), but posix still doesn't.
-Fixed it up in portability.h, but this
-could break more stuff in future. (Correct fix is to lobby posix to add it,
-which would probably take about 15 years...)</p>
-
-<p><b>Infrastructure:</b>
-The build now checks $LDFLAGS for linker-only flags, and allows the strip
-command to fail (binflt toolchains provide a strip that doesn't work).
-Since time.c uses floating point, added TOYBOX_FLOAT dependency in config.</p>
-
-<p>There's a lib/lsm.h defining varous inline functions for linux
-security modules stuff, if (lsm_enabled()) should turn into a compile-time
-constant 0 and let code drop out when TOYBOX_LSM_NONE selected, but
-testing against CFG_TOYBOX_LSM_NONE or derived symbols is still useful
-becuase when it _is_ enabled the probe turns into a system call you
-don't want to repeat too much.</p>
-
-<p>Switched a bunch of commands from signal() to xsignal(). Factored out
-xgetgrnamid() and xgetpwnamid() into xwrap.c. Make time.c depend on
-TOYBOX_FLOAT (since it always uses float so shouldn't be available on
-build targets without even software float). Added readfileat() to lib/lib.c.</p>
-
-<p>The dirtree infrastructure now passes in full flags for the old symlink
-field, and the new DIRTREE_SHUTUP flag disables warnings if a file vanishes
-out from under you during traverse. New dirtree_start() wrapper to
-create dirtree root with only two arguments.</p>
-
-<p>The not-curses infrastructure introduced by hexedit mostly moved to
-lib/interestingtimes.c.</p>
-
-<a name="asterisk" />
-<a href="#asterisk_back" />Asterisk:</a> such when
-Tim contacted me (my blog says a couple days before nov 13, 2011, I.E.
-11/11/11 not some specific day 2 months later) to ask if I wanted to work
-on a new project he was proposing called
-<a href=http://www.elinux.org/Busybox_replacement_project>BentoBox</a>
-(because I used to do busybox, he'd forgotten toybox existed
-until I brought it up). And don't ask me what "focuses not on compatibility
-with its GNU counterparts" means when CP_MORE adds 7 non-posix options
-and toys/other has 84 commands in neither posix nor LSB. I think they're
-struggling to explain the difference having dismissed "licensing" as being
-the reason it started up again after a long hiatus? The reason I don't think
-GNU is special is there are a half-dozen other independent
-implementations of the same unix command tools out there (AT&T,
-BSD, Coherent, Minix, plan 9, busybox, toybox, and several more analyzed in
-the <a href=roadmap.html>roadmap</a>, and that's ignoring the implementations
-written for DOS or in assembly over the years). But I do care what
-Linux From Scratch expects, and if it's
-<a href=http://archive.linuxfromscratch.org/lfs-museum/7.6/LFS-BOOK-7.6-NOCHUNKS.html#ch-tools-gcc-pass1>calling mv -v</a>
-then I impelement mv -v
-even if <a href=http://landley.net/toybox/roadmap.html>posix hasn't got
-it</a>. And I don't know why "gnu counterparts" would describe this when
-util-linux isn't a gnu package, nor are info-zip, e2fsprogs, kmod, less,
-procps, shadow, sysklogd, vim, zlib, sudo, dhcpcd...</p>
-
-<a name="05-04-2015" /><a href="#05-04-2015"><hr><h2><b>April 5, 2015</b></h2></a>
+<hr><b>April 5, 2015</b>
<p>Since <a href=https://android.googlesource.com/platform/external/toybox/>android</a> and
<a href=https://git.tizen.org/cgit/platform/upstream/toybox.git>tizen</a>
and <a href=https://github.com/kraj/meta-musl/tree/master/recipes-core/toybox>openembedded</a>
<a href=https://github.com/landley/toybox>to git</a>. Georgi's
<a href=https://github.com/gfto/toybox>mirror</a> is now pulling from that.</p>
-<a name="25-02-2015" /><a href="#25-02-2015"><hr><h2><b>February 25, 2015</b></h2></a>
+<hr><b>February 25, 2015</b>
<blockquote><p>"A common mistake that people make when trying to design
something completely foolproof is to underestimate the ingenuity of
complete fools."</p><p>- The Hitchhiker's Guide to the Galaxy.</p></blockquote>
<p>Fixed toy_exec() to detect when argc is in optargs, so we don't
need a separate xexec_optargs().</p>
-<a name="18-02-2015" /><a href="#18-02-2015"><hr><h2><b>February 18, 2015</b></h2></a>
+<hr><b>February 18, 2015</b>
<p>Dreamhost continues to be unable to make mailing list archives work, so
here's <a href=http://www.mail-archive.com/toybox@lists.landley.net/>another
list archive</a> with a less awkward interface than gmane.</p>
The relevant messages are in both of the other archives. Here's hoping
the chronic archive constipation problem won't happen a sixth time.</p>
-<a name="30-12-2014" /><a href="#30-12-2014"><hr><h2><b>December 30, 2014</b></h2></a>
+<hr><b>December 30, 2014</b>
<p>Due to Dreamhost's <a href=http://landley.net/dreamhost.txt>ongoing</a>
<a href=http://landley.net/dreamhost2.txt>inability</a> to make mailman
work reliably, I've added a link to a backup web archive at
<p>Update (January 27, 2015): they're <a href=https://twitter.com/landley/status/558428839462703104>still working on it</a>.</p>
-<a name="19-11-2014" /><a href="#19-11-2014"><hr><h2><b>November 19, 2014</b></h2></a>
+<hr><b>November 19, 2014</b>
<blockquote><p>"This time it was right, it would work, and no one would have to get nailed to anything." - The Hitchhiker's Guide to the Galaxy.</p></blockquote>
<p>The printf-style escape parsing ("\n" and friends) got factored out into
a new unescape() function.</p>
-<a name="02-10-2014" /><a href="#02-10-2014"><hr><h2><b>October 2, 2014</b></h2></a>
+<hr><b>October 2, 2014</b>
<blockquote><p>"There is an art, it says, or rather, a knack to flying.
The knack lies in learning how to throw yourself at the ground and miss...
Clearly, it is this second part, the missing, which presents the
<p>Divya Kothari submitted tests for chmod, link, tar, bzcat, xzcat, zcat,
and hostname. (And more, but that's all that's merged so far.)</p>
-<a name="07-07-2014" /><a href="#07-07-2014"><hr><h2><b>July 7, 2014</b></h2></a>
+<hr><b>July 7, 2014</b>
<blockquote><p>"This planet has - or rather had - a problem, which was this:
most of the people living on it were unhappy for pretty much of the time. Many
solutions were suggested for this problem, but most of these were largely
cp toys/pending/command.c toys/other/command.c and forget to delete the
first one, the build break is now more informative).</p>
-<a name="20-04-2014" /><a href="#20-04-2014"><hr><h2><b>April 20, 2014</b></h2></a>
+<hr><b>April 20, 2014</b>
<blockquote><p>And to this end they built themselves a stupendous supercomputer
which was so amazingly intelligent that even before the data banks
had been connected up it had started from "I think therefore I am" and got as
good code. The README no longer trails off into obvious unfinished confusion
at the end. Each page on the website should now have its own title.</p>
-<a name="18-11-2013" /><a href="#18-11-2013"><hr><h2><b>November 18, 2013</b></h2></a>
+<hr><b>November 18, 2013</b>
<blockquote><p>"Space," it says, "is big. Really big. You just won't believe how vastly, hugely, mindbogglingly big it is. I mean, you may think it's a long way down the street to the chemist's, but that's just peanuts to space." -
The Hitchhiker's Guide to the Galaxy.</p></blockquote>
micromanging uClibc options isn't very interesting anymore. The test suite
now uses scripts/single.sh when testing a single command.</p>
-<a name="17-09-2013" /><a href="#17-09-2013"><hr><h2><b>September 17, 2013</b></h2></a>
+<hr><b>September 17, 2013</b>
<blockquote><p>"Think of a number," said the computer, "any number."
Arthur told the computer the telephone number of King's Cross railway
station passenger inquiries, on the grounds that it must have some function,
should now be fixed.</p>
<p>
-<a name="26-07-2013" /><a href="#26-07-2013"><hr><h2><b>July 26, 2013</b></h2></a>
+<hr><b>July 26, 2013</b>
<p>Georgi Chorbadzhiyski maintains a <a href=https://github.com/gfto/toybox>git
mirror</a> of the repository on github, automatically updated from the
mercurial every 6 hours. The mirror is read only, but you can generate patches
against it and post them to the list.</p>
-<a name="02-07-2013" /><a href="#02-07-2013"><hr><h2><b>July 2, 2013</b></h2></a>
+<hr><b>July 2, 2013</b>
<blockquote><p>"Time is an illusion. Lunchtime doubly so." "Very deep. You
should send that in to the Reader's Digest. They've got a page for people
like you." -
or less public domain with a liability disclaimer, but we're still calling it
BSD (sometimes "0 clause BSD") to avoid explaining.</p>
-<a name="21-03-2013" /><a href="#21-03-2013"><hr><h2><b>March 21, 2013</b></h2></a>
+<hr><b>March 21, 2013</b>
<p>Video of my ELC talk
"<a href=http://youtu.be/SGmtP5Lg_t0>Why is Toybox?</a>"
is up on youtube. Related materials include the
</span>
-<a name="14-03-2013" /><a href="#14-03-2013"><hr><h2><b>March 14, 2013</b></h2></a>
+<hr><b>March 14, 2013</b>
<blockquote><p>"Ford, you're turning into a penguin. Stop it." -
The Hitchhiker's Guide to the Galaxy.</p></blockquote>
<p>Significant roadmap updates, checking several other multicall binaries
(klibc, sash, sbase, s6...) to see what commands they include.</p>
-<a name="18-01-2013" /><a href="#18-01-2013"><hr><h2><b>January 18, 2013</b></h2></a>
+<hr><b>January 18, 2013</b>
<blockquote><p>This must be Thursday. I never could get the hang of Thursdays. - The Hitchhiker's Guide to the Galaxy.</p></blockquote>
<p><a href=downloads/toybox-0.4.3.tar.bz2>Toybox 0.4.3</a> is based on
disabled compiler optimization, so the binary size bloated a bit. It's back
to -Os by default now.</p>
-<a name="15-12-2012" /><a href="#15-12-2012"><hr><h2><b>December 15, 2012</b></h2></a>
+<hr><b>December 15, 2012</b>
<blockquote><p>"The major difference between a thing that might go wrong and a
thing that cannot possibly go wrong is that when a thing that cannot possibly
go wrong goes wrong it usually turns out to be impossible to get at or repair."
but am waiting for somebody to complain first. The default "ulimit -n" is 1024
filehandles, so drilling down over 1000 nested subdirectories).</p>
-<a name="13-11-2012" /><a href="#13-11-2012"><hr><h2><b>November 13, 2012</b></h2></a>
+<hr><b>November 13, 2012</b>
<blockquote><p>"Rule Six: The winning team shall be the first team that wins."
- The Hitchhiker's Guide to the Galaxy.</p></blockquote>
back now.</p>
</span>
-<a name="23-07-2012" /><a href="#23-07-2012"><hr><h2><b>July 23, 2012</b></h2></a>
+<hr><b>July 23, 2012</b>
<blockquote><p>"Ford", Arthur said. "There's an infinite number of monkeys
out here who want to talk to us about this script for Hamlet they've worked
out." - The Hitchhiker's Guide to the Galaxy.</p></blockquote>
glibc bug where static linking prevents stdout from automatically flushing
pending output on exit.</p>
-<a name="25-06-2012" /><a href="#25-06-2012"><hr><h2><b>June 25, 2012</b></h2></a>
+<hr><b>June 25, 2012</b>
<blockquote><p>"For a moment, nothing happened. Then, after a second or so, nothing continued to happen." - The Hitchhiker's Guide to the Galaxy.</p></blockquote>
<p><a href=downloads/toybox-0.3.1.tar.bz2>Toybox 0.3.1</a> is based on commit
pending submissions to review. I need to catch up...</p>
</span>
-<a name="12-06-2012" /><a href="#12-06-2012"><hr><h2><b>June 12, 2012</b></h2></a>
+<hr><b>June 12, 2012</b>
<blockquote><p>"For instance, on the planet Earth, man had always assumed that
he was more intelligent than dolphins because he had achieved so much - the
wheel, New York, wars and so on - whilst all the dolphins had ever done was
1.0, so here's a checkpoint.)</p>
-<a name="03-03-2012" /><a href="#03-03-2012"><hr><h2><b>March 3, 2012</b></h2></a>
+<hr><b>March 3, 2012</b>
<blockquote><p>"They went unnoticed at Goonhilly, passed over Cape Canaveral
without a blip, and Woomera and Jodrell Bank looked straight through them.
and those guys did their stuff in a week or so.)</p>
-<a name="12-02-2012" /><a href="#12-02-2012"><hr><h2><b>February 12, 2012</b></h2></a>
+<hr><b>February 12, 2012</b>
<blockquote><p>
"for though it has many omissions and contains much that is apocryphal, or at
least wildly inaccurate, it scores over the older, more pedestrian work in two
<p>More to come...</p>
<hr>
-<a name="15-11-2011" /><a href="#15-11-2011"><hr><h2><b>November 15, 2011</b></h2></a>
-- Back from the dead, Toybox is now under a 2
+<p><b>November 15, 2011</b> - Back from the dead, Toybox is now under a 2
clause BSD license, and aiming to become the default command line
implementation of Android systems everywhere.</p>
<h3>Other Android core commands</h3>
<p>Other than the toolbox directory, the currently interesting
-subdirectories in the core repository are init,
-logcat, logwrapper, reboot, and run-as.</p>
+subdirectories in the core repository are gpttool, init,
+logcat, logwrapper, mkbootimg, reboot, and run-as.</p>
<ul>
+<li><b>gpttool</b> - subset of fdisk</li>
<li><b>init</b> - Android's PID 1</li>
<li><b>logcat</b> - read android log format</li>
<li><b>logwrapper</b> - redirect stdio to android log</li>
+<li><b>mkbootimg</b> - create signed boot image</li>
<li><b>reboot</b> - Android's reboot(1)</li>
<li><b>run-as</b> - subset of sudo</li>
</ul>
different user interface. We may want to provide that interface, but
implementing the full commands (fdisk, init, and sudo) come first.</p>
+<p>Also, gpttool and mkbootimg are install tools.
+These aren't a priority if android wants to use its own
+bespoke code to install itself.</p>
+
<h3>Analysis</h3>
<p>For reference, combining everything listed above, we get:</p>
<blockquote><b>
-dd du df getevent iftop init ioctl ionice
-log logcat logwrapper ls lsof mount nandread
+dd du df getevent gpttool iftop init ioctl ionice
+log logcat logwrapper ls lsof mkbootimg mount nandread
newfs_msdos ps prlimit reboot renice run-as
sendevent start stop top uptime watchprops
</b></blockquote>