summaryrefslogtreecommitdiff
path: root/toys
diff options
context:
space:
mode:
authorHyejin Kim <hyejin0906.kim@samsung.com>2015-08-12 11:22:10 +0900
committerHyejin Kim <hyejin0906.kim@samsung.com>2015-08-12 11:22:10 +0900
commitc55b214458bed6f6c6dc57e3fccfc8dc8558e7ee (patch)
tree393225b618c69acab92208a350c401c408fcc252 /toys
parentc353de2e55d0f64f4b11dbc242f8319674650c54 (diff)
parent05499787ca89fa4b017c2441e89020799f02e4c1 (diff)
downloadtoybox-c55b214458bed6f6c6dc57e3fccfc8dc8558e7ee.tar.gz
toybox-c55b214458bed6f6c6dc57e3fccfc8dc8558e7ee.tar.bz2
toybox-c55b214458bed6f6c6dc57e3fccfc8dc8558e7ee.zip
Merge remote-tracking branch 'toybox/master' into upstreamupstream
Diffstat (limited to 'toys')
-rw-r--r--toys/other/acpi.c17
-rw-r--r--toys/other/blkid.c32
-rw-r--r--toys/other/bzcat.c93
-rw-r--r--toys/other/chcon.c2
-rw-r--r--toys/other/fsync.c33
-rw-r--r--toys/other/hexedit.c2
-rw-r--r--toys/other/hostid.c23
-rw-r--r--toys/other/login.c246
-rw-r--r--toys/other/lspci.c2
-rw-r--r--toys/other/nbd_client.c16
-rw-r--r--toys/other/reboot.c12
-rw-r--r--toys/other/rev.c2
-rw-r--r--toys/other/switch_root.c25
-rw-r--r--toys/other/tac.c2
-rw-r--r--toys/other/taskset.c2
-rw-r--r--toys/other/vmstat.c2
-rw-r--r--toys/pending/dd.c4
-rw-r--r--toys/pending/init.c13
-rw-r--r--toys/pending/mdev.c33
-rw-r--r--toys/pending/modprobe.c12
-rw-r--r--toys/pending/ps.c2
-rw-r--r--toys/pending/telnet.c48
-rw-r--r--toys/pending/tftp.c454
-rw-r--r--toys/posix/cal.c12
-rw-r--r--toys/posix/chmod.c2
-rw-r--r--toys/posix/cmp.c2
-rw-r--r--toys/posix/date.c137
-rw-r--r--toys/posix/du.c2
-rw-r--r--toys/posix/find.c35
-rw-r--r--toys/posix/id.c2
-rw-r--r--toys/posix/ls.c13
-rw-r--r--toys/posix/nl.c2
-rw-r--r--toys/posix/split.c2
-rw-r--r--toys/posix/strings.c2
34 files changed, 908 insertions, 380 deletions
diff --git a/toys/other/acpi.c b/toys/other/acpi.c
index 44fd03b..363cfb9 100644
--- a/toys/other/acpi.c
+++ b/toys/other/acpi.c
@@ -25,10 +25,7 @@ config ACPI
#include "toys.h"
GLOBALS(
- int ac;
- int bat;
- int therm;
- int cool;
+ int ac, bat, therm, cool;
char *cpath;
)
@@ -44,7 +41,7 @@ int read_int_at(int dirfd, char *name)
return ret;
}
-int acpi_callback(struct dirtree *tree)
+static int acpi_callback(struct dirtree *tree)
{
int dfd, fd, len, on;
@@ -85,11 +82,11 @@ done:
return 0;
}
-int temp_callback(struct dirtree *tree)
+static int temp_callback(struct dirtree *tree)
{
int dfd, temp;
- if (tree->name[0]=='.') return 0;
+ if (*tree->name=='.') return 0;
if (!tree->parent || !tree->parent->parent)
return DIRTREE_RECURSE|DIRTREE_SYMFOLLOW;
errno = 0;
@@ -98,17 +95,17 @@ int temp_callback(struct dirtree *tree)
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;
}
-int cool_callback(struct dirtree *tree)
+static int cool_callback(struct dirtree *tree)
{
int dfd=5, cur, max;
diff --git a/toys/other/blkid.c b/toys/other/blkid.c
index 725f163..fad1159 100644
--- a/toys/other/blkid.c
+++ b/toys/other/blkid.c
@@ -4,7 +4,7 @@
*
* See ftp://ftp.kernel.org/pub/linux/utils/util-linux/v2.24/libblkid-docs/api-index-full.html
-USE_BLKID(NEWTOY(blkid, "<1", TOYFLAG_BIN))
+USE_BLKID(NEWTOY(blkid, 0, TOYFLAG_BIN))
USE_FSTYPE(NEWTOY(fstype, "<1", TOYFLAG_BIN))
config BLKID
@@ -34,6 +34,7 @@ struct fstype {
};
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...
@@ -56,8 +57,7 @@ static const struct fstype fstypes[] = {
{"vfat", 0x31544146, 4, 54, 39+(4<<24), 11, 43} // fat1
};
-/* TODO if no args use proc/partitions */
-void do_blkid(int fd, char *name)
+static void do_blkid(int fd, char *name)
{
int off, i, j;
char *type;
@@ -89,7 +89,7 @@ void do_blkid(int fd, char *name)
if (test == fstypes[i].magic) break;
}
- if (i == sizeof(fstypes)/sizeof(struct fstype)) {
+ if (i == ARRAY_LEN(fstypes)) {
off += len;
if (pass) continue;
return;
@@ -136,10 +136,30 @@ void do_blkid(int fd, char *name)
void blkid_main(void)
{
- loopfiles(toys.optargs, do_blkid);
+ 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);
+ }
}
void fstype_main(void)
{
- blkid_main();
+ loopfiles(toys.optargs, do_blkid);
}
diff --git a/toys/other/bzcat.c b/toys/other/bzcat.c
index 642590d..850c51c 100644
--- a/toys/other/bzcat.c
+++ b/toys/other/bzcat.c
@@ -1,4 +1,4 @@
-/* bzcat.c - decompress stdin to stdout using bunzip2.
+/* bzcat.c - bzip2 decompression
*
* Copyright 2003, 2007 Rob Landley <rob@landley.net>
*
@@ -12,16 +12,33 @@
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 [filename...]
+ usage: bzcat [FILE...]
Decompress listed files to stdout. Use stdin if no files listed.
*/
+#define FOR_bunzip2
#include "toys.h"
#define THREADS 1
@@ -421,7 +438,7 @@ static int read_huffman_data(struct bunzip_data *bd, struct bwdata *bw)
}
// Flush output buffer to disk
-void flush_bunzip_outbuf(struct bunzip_data *bd, int out_fd)
+static void flush_bunzip_outbuf(struct bunzip_data *bd, int out_fd)
{
if (bd->outbufPos) {
if (write(out_fd, bd->outbuf, bd->outbufPos) != bd->outbufPos)
@@ -430,7 +447,7 @@ void flush_bunzip_outbuf(struct bunzip_data *bd, int out_fd)
}
}
-void burrows_wheeler_prep(struct bunzip_data *bd, struct bwdata *bw)
+static void burrows_wheeler_prep(struct bunzip_data *bd, struct bwdata *bw)
{
int ii, jj;
unsigned int *dbuf = bw->dbuf;
@@ -474,7 +491,7 @@ void burrows_wheeler_prep(struct bunzip_data *bd, struct bwdata *bw)
}
// Decompress a block of text to intermediate buffer
-int read_bunzip_data(struct bunzip_data *bd)
+static 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);
@@ -493,7 +510,8 @@ int read_bunzip_data(struct bunzip_data *bd)
// http://dogma.net/markn/articles/bwt/bwt.htm
// http://marknelson.us/1996/09/01/bwt/
-int write_bunzip_data(struct bunzip_data *bd, struct bwdata *bw, int out_fd, char *outbuf, int len)
+static 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;
@@ -584,7 +602,8 @@ dataus_interruptus:
// Allocate the structure, read file header. If !len, src_fd contains
// filehandle to read from. Else inbuf contains data.
-int start_bunzip(struct bunzip_data **bdp, int src_fd, char *inbuf, int len)
+static int start_bunzip(struct bunzip_data **bdp, int src_fd, char *inbuf,
+ int len)
{
struct bunzip_data *bd;
unsigned int i;
@@ -622,10 +641,10 @@ int start_bunzip(struct bunzip_data **bdp, int src_fd, char *inbuf, int len)
// Example usage: decompress src_fd to dst_fd. (Stops at end of bzip data,
// not end of file.)
-void bunzipStream(int src_fd, int dst_fd)
+static char *bunzipStream(int src_fd, int dst_fd)
{
struct bunzip_data *bd;
- char *bunzip_errors[]={NULL, "not bzip", "bad data", "old format"};
+ char *bunzip_errors[] = {0, "not bzip", "bad data", "old format"};
int i, j;
if (!(i = start_bunzip(&bd,src_fd, 0, 0))) {
@@ -636,15 +655,67 @@ void bunzipStream(int src_fd, int dst_fd)
for (j=0; j<THREADS; j++) free(bd->bwdata[j].dbuf);
free(bd);
- if (i) error_exit(bunzip_errors[-i]);
+
+ return bunzip_errors[-i];
}
static void do_bzcat(int fd, char *name)
{
- bunzipStream(fd, 1);
+ char *err = bunzipStream(fd, 1);
+
+ if (err) error_exit(err);
}
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);
+}
diff --git a/toys/other/chcon.c b/toys/other/chcon.c
index a2bbb66..6dbdd13 100644
--- a/toys/other/chcon.c
+++ b/toys/other/chcon.c
@@ -21,7 +21,7 @@ config CHCON
#define FOR_chcon
#include "toys.h"
-int do_chcon(struct dirtree *try)
+static int do_chcon(struct dirtree *try)
{
char *path, *con = *toys.optargs;
diff --git a/toys/other/fsync.c b/toys/other/fsync.c
new file mode 100644
index 0000000..e6f6c8d
--- /dev/null
+++ b/toys/other/fsync.c
@@ -0,0 +1,33 @@
+/* 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);
+}
diff --git a/toys/other/hexedit.c b/toys/other/hexedit.c
index 1f6b42e..a52d66d 100644
--- a/toys/other/hexedit.c
+++ b/toys/other/hexedit.c
@@ -137,6 +137,8 @@ void hexedit_main(void)
fd = xopen(*toys.optargs, ro ? O_RDONLY : O_RDWR);
char keybuf[16];
+ *keybuf = 0;
+
// Terminal setup
TT.height = 25;
terminal_size(0, &TT.height);
diff --git a/toys/other/hostid.c b/toys/other/hostid.c
new file mode 100644
index 0000000..883ac3c
--- /dev/null
+++ b/toys/other/hostid.c
@@ -0,0 +1,23 @@
+/* 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());
+}
diff --git a/toys/other/login.c b/toys/other/login.c
index b728286..c727bf9 100644
--- a/toys/other/login.c
+++ b/toys/other/login.c
@@ -8,30 +8,28 @@
* TODO: this command predates "pending" but needs cleanup. It #defines
* random stuff, calls exit() form a signal handler... yeah.
-USE_LOGIN(NEWTOY(login, ">1fph:", TOYFLAG_BIN))
+USE_LOGIN(NEWTOY(login, ">1f:ph:", TOYFLAG_BIN|TOYFLAG_NEEDROOT))
config LOGIN
bool "login"
default y
depends on TOYBOX_SHADOW
help
- usage: login [-p] [-h host] [[-f] username]
+ usage: login [-p] [-h host] [-f USERNAME] [USERNAME]
- Establish a new session with the system.
+ Log in as a user, prompting for username and password if necessary.
-p Preserve environment
-h The name of the remote host for this login
- -f Do not perform authentication
+ -f login as USERNAME without 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;
)
@@ -42,184 +40,128 @@ static void login_timeout_handler(int sig __attribute__((unused)))
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)
{
- 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");
+ 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;
- if (geteuid()) error_exit("not root");
+ for (tty=0; tty<3; tty++) if (isatty(tty)) break;
+ if (tty == 3) error_exit("no tty");
- if (!isatty(0) || !isatty(1) || !isatty(2)) error_exit("no tty");
+ for (count = 0; count < ARRAY_LEN(forbid); count++) unsetenv(forbid[count]);
openlog("login", LOG_PID | LOG_CONS, LOG_AUTH);
xsignal(SIGALRM, login_timeout_handler);
- alarm(TT.login_timeout = 60);
- for (ss = forbid; *ss; ss++) unsetenv(*ss);
-
- while (1) {
+ if (TT.username) username = TT.username;
+ else username = *toys.optargs;
+ for (count = 0; count < 3; count++) {
+ alarm(TT.login_timeout = 60);
tcflush(0, TCIFLUSH);
- username[sizeof(username)-1] = 0;
- if (*toys.optargs) xstrncpy(username, *toys.optargs, sizeof(username));
- else {
- read_user(username, sizeof(username));
- if (!*username) continue;
+ if (!username) {
+ int i;
+
+ 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);
+
+ // 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;
+ }
}
+ // If user exists and isn't locked
pwd = getpwnam(username);
- if (!pwd) goto query_pass; // Non-existing user
+ if (pwd && *pwd->pw_passwd != '!' && *pwd->pw_passwd != '*') {
- if (pwd->pw_passwd[0] == '!' || pwd->pw_passwd[0] == '*')
- goto query_pass; // Locked account
+ // Pre-authenticated or passwordless
+ if (TT.username || !*pwd->pw_passwd) break;
- if (f_flag) break; // Pre-authenticated
+ // fetch shadow password if necessary
+ if (*(pass = pwd->pw_passwd) == 'x') {
+ struct spwd *spwd = getspnam (username);
- if (!pwd->pw_passwd[0]) break; // Password-less account
+ if (spwd) pass = spwd->sp_pwdp;
+ }
+ } else if (TT.username) error_exit("bad -f '%s'", TT.username);
- pass = pwd->pw_passwd;
- if (pwd->pw_passwd[0] == 'x') {
- spwd = getspnam (username);
- if (spwd) pass = spwd->sp_pwdp;
- }
+ // 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);
-query_pass:
- if (!verify_password(pass)) break;
+ // password go bye-bye now.
+ memset(toybuf, 0, sizeof(toybuf));
+ if (x) 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:"");
+ syslog(LOG_WARNING, "invalid password for '%s' on %s %s%s", pwd->pw_name,
+ ttyname(tty), hh ? "from " : "", hh ? TT.hostname : "");
sleep(3);
puts("Login incorrect");
- if (++auth_fail_cnt == 3)
- error_exit("Maximum number of tries exceeded (3)\n");
-
- *username = 0;
+ 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)");
- if (pwd->pw_uid) handle_nologin();
+ // 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;
+ }
xsetuser(pwd);
- setup_environment(pwd, !(toys.optflags & FLAG_p));
+ 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);
- handle_motd();
+ // Message of the day
+ if ((ss = readfile("/etc/motd", 0, 0))) {
+ puts(ss);
+ free(ss);
+ }
syslog(LOG_INFO, "%s logged in on %s %s %s", pwd->pw_name,
- ttyname(0), h_flag?"from":"", h_flag?TT.hostname:"");
+ ttyname(tty), hh ? "from" : "", hh ? TT.hostname : "");
- spawn_shell(pwd->pw_shell);
+ // 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");
}
diff --git a/toys/other/lspci.c b/toys/other/lspci.c
index c9b22ab..077ce75 100644
--- a/toys/other/lspci.c
+++ b/toys/other/lspci.c
@@ -37,7 +37,7 @@ GLOBALS(
FILE *db;
)
-int do_lspci(struct dirtree *new)
+static int do_lspci(struct dirtree *new)
{
char *p = toybuf, *vendor = toybuf+9, *device = toybuf+18,
driver[256], *vbig = 0, *dbig = 0, **fields;
diff --git a/toys/other/nbd_client.c b/toys/other/nbd_client.c
index c16585a..a82ff7c 100644
--- a/toys/other/nbd_client.c
+++ b/toys/other/nbd_client.c
@@ -40,7 +40,6 @@ void nbd_client_main(void)
{
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;
@@ -49,23 +48,10 @@ void nbd_client_main(void)
nbd = xopen(device, O_RDWR);
for (;;) {
int temp;
- struct addrinfo hints;
// Find and connect to server
- 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);
-
+ sock = xconnect(host, port, AF_UNSPEC, SOCK_STREAM, 0, 0);
temp = 1;
setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, &temp, sizeof(int));
diff --git a/toys/other/reboot.c b/toys/other/reboot.c
index a135888..1e8f5e9 100644
--- a/toys/other/reboot.c
+++ b/toys/other/reboot.c
@@ -2,7 +2,7 @@
*
* Copyright 2013 Elie De Brauwer <eliedebrauwer@gmail.com>
-USE_REBOOT(NEWTOY(reboot, "n", TOYFLAG_SBIN|TOYFLAG_NEEDROOT))
+USE_REBOOT(NEWTOY(reboot, "fn", TOYFLAG_SBIN|TOYFLAG_NEEDROOT))
USE_REBOOT(OLDTOY(halt, reboot, TOYFLAG_SBIN|TOYFLAG_NEEDROOT))
USE_REBOOT(OLDTOY(poweroff, reboot, TOYFLAG_SBIN|TOYFLAG_NEEDROOT))
@@ -10,10 +10,11 @@ config REBOOT
bool "reboot"
default y
help
- usage: reboot/halt/poweroff [-n]
+ usage: reboot/halt/poweroff [-fn]
Restart, halt or powerdown the system.
+ -f Don't signal init
-n Don't sync before stopping the system.
*/
@@ -23,9 +24,12 @@ config REBOOT
void reboot_main(void)
{
- int types[] = {RB_AUTOBOOT, RB_HALT_SYSTEM, RB_POWER_OFF};
+ int types[] = {RB_AUTOBOOT, RB_HALT_SYSTEM, RB_POWER_OFF},
+ sigs[] = {SIGINT, SIGUSR1, SIGUSR2}, idx;
if (!(toys.optflags & FLAG_n)) sync();
- toys.exitval = reboot(types[stridx("hp", *toys.which->name)+1]);
+ idx = stridx("hp", *toys.which->name)+1;
+ if (toys.optflags & FLAG_f) toys.exitval = reboot(types[idx]);
+ else toys.exitval = kill(1, sigs[idx]);
}
diff --git a/toys/other/rev.c b/toys/other/rev.c
index b5720a3..4cf7214 100644
--- a/toys/other/rev.c
+++ b/toys/other/rev.c
@@ -15,7 +15,7 @@ config REV
#include "toys.h"
-void do_rev(int fd, char *name)
+static void do_rev(int fd, char *name)
{
char *c;
diff --git a/toys/other/switch_root.c b/toys/other/switch_root.c
index 0861c70..acbae2b 100644
--- a/toys/other/switch_root.c
+++ b/toys/other/switch_root.c
@@ -67,8 +67,13 @@ void switch_root_main(void)
}
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("init", &st1) || !S_ISREG(st1.st_mode) || !(st1.st_mode&0100)) {
+ if (stat(*cmdline, &st1) || !S_ISREG(st1.st_mode) || !(st1.st_mode&0100)) {
error_msg("bad init");
goto panic;
}
@@ -81,6 +86,24 @@ void switch_root_main(void)
// 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);
diff --git a/toys/other/tac.c b/toys/other/tac.c
index 538d1b0..d5f72fd 100644
--- a/toys/other/tac.c
+++ b/toys/other/tac.c
@@ -15,7 +15,7 @@ config TAC
#include "toys.h"
-void do_tac(int fd, char *name)
+static void do_tac(int fd, char *name)
{
struct arg_list *list = NULL;
char *c;
diff --git a/toys/other/taskset.c b/toys/other/taskset.c
index 2851923..4ade5f1 100644
--- a/toys/other/taskset.c
+++ b/toys/other/taskset.c
@@ -120,7 +120,7 @@ void taskset_main(void)
}
}
-int do_nproc(struct dirtree *new)
+static int do_nproc(struct dirtree *new)
{
if (!new->parent) return DIRTREE_RECURSE;
if (!strncmp(new->name, "cpu", 3) && isdigit(new->name[3])) TT.nproc++;
diff --git a/toys/other/vmstat.c b/toys/other/vmstat.c
index c11e46b..9a38e45 100644
--- a/toys/other/vmstat.c
+++ b/toys/other/vmstat.c
@@ -39,7 +39,7 @@ struct vmstat_proc {
// 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
-void get_vmstat_proc(struct vmstat_proc *vmstat_proc)
+static 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",
diff --git a/toys/pending/dd.c b/toys/pending/dd.c
index 3449104..366d3c5 100644
--- a/toys/pending/dd.c
+++ b/toys/pending/dd.c
@@ -133,9 +133,9 @@ static void summary()
//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);
+ human_readable(toybuf, st.bytes, HR_SPACE|HR_B);
fprintf(stderr, "%llu bytes (%s) copied, ",st.bytes, toybuf);
- human_readable(toybuf, st.bytes/seconds);
+ human_readable(toybuf, st.bytes/seconds, HR_SPACE|HR_B);
fprintf(stderr, "%f s, %s/s\n", seconds, toybuf);
}
diff --git a/toys/pending/init.c b/toys/pending/init.c
index 529c1b9..d9e78ff 100644
--- a/toys/pending/init.c
+++ b/toys/pending/init.c
@@ -348,6 +348,7 @@ static void halt_poweroff_reboot_handler(int sig_no)
reboot_magic_no=RB_POWER_OFF;
break;
case SIGTERM:
+ case SIGINT:
error_msg("Requesting system reboot");
reboot_magic_no=RB_AUTOBOOT;
break;
@@ -415,7 +416,7 @@ static void pause_handler(int sig_no)
errno_backup = errno;
signal_backup = caught_signal;
- signal(SIGCONT, catch_signal);
+ xsignal(SIGCONT, catch_signal);
while(1) {
if (caught_signal == SIGCONT) break;
@@ -460,10 +461,11 @@ void init_main(void)
putenv("USER=root");
inittab_parsing();
- 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
+ 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
memset(&sig_act, 0, sizeof(sig_act));
sigfillset(&sig_act.sa_mask);
sigdelset(&sig_act.sa_mask, SIGCONT);
@@ -471,7 +473,6 @@ void init_main(void)
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();
diff --git a/toys/pending/mdev.c b/toys/pending/mdev.c
index 0c49633..a13a53d 100644
--- a/toys/pending/mdev.c
+++ b/toys/pending/mdev.c
@@ -35,7 +35,7 @@ config MDEV_CONF
static void make_device(char *path)
{
char *device_name = NULL, *s, *temp;
- int major, minor, type, len, fd;
+ int major = 0, minor = 0, type, len, fd;
int mode = 0660;
uid_t uid = 0;
gid_t gid = 0;
@@ -46,24 +46,21 @@ static void make_device(char *path)
temp = strrchr(path, '/');
fd = open(path, O_RDONLY);
*temp=0;
- temp = toybuf;
- len = read(fd, temp, 64);
+ len = read(fd, toybuf, 64);
close(fd);
if (len<1) return;
- temp[len] = 0;
+ toybuf[len] = 0;
// Determine device type, major and minor
type = path[5]=='c' ? S_IFCHR : S_IFBLK;
- major = minor = 0;
- sscanf(temp, "%u:%u", &major, &minor);
+ sscanf(toybuf, "%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);
@@ -74,11 +71,15 @@ static void make_device(char *path)
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) {
@@ -185,22 +186,22 @@ found_device:
}
}
- sprintf(temp, "/dev/%s", device_name);
+ sprintf(toybuf, "/dev/%s", device_name);
- if (getenv("ACTION") && !strcmp(getenv("ACTION"), "remove")) {
- unlink(temp);
+ if ((temp=getenv("ACTION")) && !strcmp(temp, "remove")) {
+ unlink(toybuf);
return;
}
if (strchr(device_name, '/'))
- mkpathat(AT_FDCWD, temp, 0, 2);
- if (mknod(temp, mode | type, makedev(major, minor)) && errno != EEXIST)
- perror_exit("mknod %s failed", temp);
+ mkpathat(AT_FDCWD, toybuf, 0, 2);
+ if (mknod(toybuf, mode | type, makedev(major, minor)) && errno != EEXIST)
+ perror_exit("mknod %s failed", toybuf);
- if (type == S_IFBLK) close(open(temp, O_RDONLY)); // scan for partitions
+ if (type == S_IFBLK) close(open(toybuf, O_RDONLY)); // scan for partitions
- if (CFG_MDEV_CONF) mode=chown(temp, uid, gid);
+ if (CFG_MDEV_CONF) mode=chown(toybuf, uid, gid);
}
static int callback(struct dirtree *node)
diff --git a/toys/pending/modprobe.c b/toys/pending/modprobe.c
index 5431cb3..07c53fc 100644
--- a/toys/pending/modprobe.c
+++ b/toys/pending/modprobe.c
@@ -65,14 +65,12 @@ struct module_s {
static char *path2mod(char *file, char *mod)
{
int i;
- char *from, *lslash;
+ char *from;
if (!file) return NULL;
if (!mod) mod = xmalloc(MODNAME_LEN);
- lslash = strrchr(file, '/');
- if (!lslash || (lslash == file && !lslash[1])) from = file;
- else from = lslash + 1;
+ from = basename_r(file);
for (i = 0; i < (MODNAME_LEN-1) && from[i] && from[i] != '.'; i++)
mod[i] = (from[i] == '-') ? '_' : from[i];
@@ -277,7 +275,8 @@ static int config_action(struct dirtree *node)
get_mod(tokens[1], 1)->flags |= MOD_BLACKLIST;
else if (!strcmp(tokens[0], "install")) continue;
else if (!strcmp(tokens[0], "remove")) continue;
- else error_msg("Invalid option %s found in file %s", tokens[0], filename);
+ else if (toys.optflags & FLAG_q)
+ error_msg("Invalid option %s found in file %s", tokens[0], filename);
}
fclose(fc);
free(filename);
@@ -381,7 +380,6 @@ static int ins_mod(char *modules, char *flags)
}
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;
}
@@ -428,7 +426,7 @@ static int go_probe(struct module_s *m)
int rc = 0, first = 1;
if (!(m->flags & MOD_FNDDEPMOD)) {
- if (!(toys.optflags & FLAG_s))
+ if (!(toys.optflags & FLAG_q))
error_msg("module %s not found in modules.dep", m->name);
return -ENOENT;
}
diff --git a/toys/pending/ps.c b/toys/pending/ps.c
index cb0f32c..29111d5 100644
--- a/toys/pending/ps.c
+++ b/toys/pending/ps.c
@@ -312,7 +312,7 @@ void ps_main(void)
if (j!=2) break;
}
if (i == ARRAY_LEN(typos)) error_exit("bad -o %.*s", end-type, type);
- if (!field->title) strcpy(field->title, typos[field->which]);
+ if (!*field->title) strcpy(field->title, typos[field->which]);
dlist_add_nomalloc((void *)&TT.fields, (void *)field);
}
}
diff --git a/toys/pending/telnet.c b/toys/pending/telnet.c
index f113cbb..dc3487a 100644
--- a/toys/pending/telnet.c
+++ b/toys/pending/telnet.c
@@ -48,39 +48,6 @@ GLOBALS(
#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)
@@ -135,7 +102,7 @@ static void handle_esc(void)
char input;
if(toys.signal && TT.term_ok) tcsetattr(0, TCSADRAIN, &TT.raw_term);
- write(1,"\r\nConsole escape. Commands are:\r\n\n"
+ xwrite(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"
@@ -178,7 +145,7 @@ static void handle_esc(void)
default: break;
}
- write(1, "continuing...\r\n", 15);
+ xwrite(1, "continuing...\r\n", 15);
if (toys.signal && TT.term_ok) tcsetattr(0, TCSADRAIN, &TT.def_term);
ret:
@@ -292,7 +259,7 @@ static int read_server(int len)
}
} while (TT.pbuff < len);
- if (i) write(STDIN_FILENO, toybuf, i);
+ if (i) xwrite(STDIN_FILENO, toybuf, i);
return 0;
}
@@ -314,20 +281,19 @@ static void write_server(int len)
if (*c == IAC) toybuf[i++] = *c; /* IAC -> IAC IAC */
else if (*c == '\r') toybuf[i++] = '\0'; /* CR -> CR NUL */
}
- if(i) write(TT.sfd, toybuf, i);
+ if(i) xwrite(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) TT.port = atoi(toys.optargs[1]);
- if(TT.port <= 0 || TT.port > 65535) error_exit("bad PORT (1-65535)");
+ if (toys.optc == 2) port = toys.optargs[1];
TT.ttype = getenv("TERM");
if(!TT.ttype) TT.ttype = "";
@@ -340,7 +306,7 @@ void telnet_main(void)
}
terminal_size(&TT.win_width, &TT.win_height);
- TT.sfd = xconnect_inet_tcp(toys.optargs[0], TT.port);
+ TT.sfd = xconnect(*toys.optargs, port, 0, SOCK_STREAM, IPPROTO_TCP, 0);
setsockopt(TT.sfd, SOL_SOCKET, SO_REUSEADDR, &set, sizeof(set));
setsockopt(TT.sfd, SOL_SOCKET, SO_KEEPALIVE, &set, sizeof(set));
diff --git a/toys/pending/tftp.c b/toys/pending/tftp.c
new file mode 100644
index 0000000..60d5f17
--- /dev/null
+++ b/toys/pending/tftp.c
@@ -0,0 +1,454 @@
+/* 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();
+}
diff --git a/toys/posix/cal.c b/toys/posix/cal.c
index bb476df..bd3afad 100644
--- a/toys/posix/cal.c
+++ b/toys/posix/cal.c
@@ -64,14 +64,6 @@ static char *calstrings(char *buf, struct tm *tm)
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.
@@ -86,12 +78,12 @@ void cal_main(void)
buf += sizeof(struct tm);
// Last argument is year, one before that (if any) is month.
- xcheckrange(tm->tm_year = atol(toys.optargs[--toys.optc]),1,9999);
+ tm->tm_year = atolx_range(toys.optargs[--toys.optc], 1, 9999);
tm->tm_year -= 1900;
tm->tm_mday = 1;
tm->tm_hour = 12; // noon to avoid timezone weirdness
if (toys.optc) {
- xcheckrange(tm->tm_mon = atol(toys.optargs[--toys.optc]),1,12);
+ tm->tm_mon = atolx_range(toys.optargs[--toys.optc], 1, 12);
tm->tm_mon--;
// Print 12 months of the year
diff --git a/toys/posix/chmod.c b/toys/posix/chmod.c
index 64369b6..4292439 100644
--- a/toys/posix/chmod.c
+++ b/toys/posix/chmod.c
@@ -39,7 +39,7 @@ GLOBALS(
char *mode;
)
-int do_chmod(struct dirtree *try)
+static int do_chmod(struct dirtree *try)
{
mode_t mode;
diff --git a/toys/posix/cmp.c b/toys/posix/cmp.c
index 2dae113..829da75 100644
--- a/toys/posix/cmp.c
+++ b/toys/posix/cmp.c
@@ -28,7 +28,7 @@ GLOBALS(
// This handles opening the file and
-void do_cmp(int fd, char *name)
+static void do_cmp(int fd, char *name)
{
int i, len1, len2, min_len, size = sizeof(toybuf)/2;
long byte_no = 1, line_no = 1;
diff --git a/toys/posix/date.c b/toys/posix/date.c
index d4c4524..a42de50 100644
--- a/toys/posix/date.c
+++ b/toys/posix/date.c
@@ -7,22 +7,23 @@
* Note: setting a 2 year date is 50 years back/forward from today,
* not posix's hardwired magic dates.
-USE_DATE(NEWTOY(date, "d:s:r:u[!dr]", TOYFLAG_BIN))
+USE_DATE(NEWTOY(date, "d:D:r:u[!dr]", TOYFLAG_BIN))
config DATE
bool "date"
default y
help
- usage: date [-u] [-r FILE] [-d DATE] [+DISPLAY_FORMAT] [-s SET_FORMAT] [SET]
+ usage: date [-u] [-r FILE] [-d DATE] [+DISPLAY_FORMAT] [-D 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:
@@ -49,15 +50,79 @@ GLOBALS(
char *file;
char *setfmt;
char *showdate;
+
+ char *tz;
+ unsigned nano;
)
-// Handle default posix date format: mmddhhmm[[cc]yy]
+// 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]
// returns 0 success, nonzero for error
-int parse_posixdate(char *str, struct tm *tm)
+static int parse_default(char *str, struct tm *tm)
{
- int len;
+ 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;
+ }
- len = 0;
+ // Posix format
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;
@@ -78,40 +143,38 @@ int parse_posixdate(char *str, struct tm *tm)
// 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 ((r1 < r2) ? (r1 < year && year < r2) : (year < r1 || year > r2)) {
- if (year < r1) year += 100;
- } else if (year > r1) year -= 100;
+ 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;
+ }
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",
- *tz = 0;
+ char *setdate = *toys.optargs, *format_string = "%a %b %e %H:%M:%S %Z %Y";
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) {
- if (CFG_TOYBOX_FREE) tz = getenv("TZ");
- setenv("TZ", "UTC", 1);
- tzset();
- }
+ if (toys.optflags & FLAG_u) utzset();
if (TT.showdate) {
- setdate = TT.showdate;
if (TT.setfmt) {
char *s = strptime(TT.showdate, TT.setfmt+(*TT.setfmt=='+'), &tm);
- if (!s || *s) goto bad_date;
- } else if (parse_posixdate(TT.showdate, &tm)) goto bad_date;
+ if (!s || *s) goto bad_showdate;
+ } else if (parse_default(TT.showdate, &tm)) goto bad_showdate;
} else {
time_t now;
@@ -125,7 +188,6 @@ void date_main(void)
((toys.optflags & FLAG_u) ? gmtime_r : localtime_r)(&now, &tm);
}
- setdate = *toys.optargs;
// Fall through if no arguments
if (!setdate);
// Display the date?
@@ -137,39 +199,26 @@ void date_main(void)
} else if (setdate) {
struct timeval tv;
- if (parse_posixdate(setdate, &tm)) goto bad_date;
+ if (parse_default(setdate, &tm)) error_exit("bad date '%s'", setdate);
if (toys.optflags & FLAG_u) {
- char *tz = CFG_TOYBOX_FREE ? getenv("TZ") : 0;
-
// We can't just pass a timezone to mktime because posix.
- 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;
+ utzset();
+ tv.tv_sec = chkmktime(&tm, setdate, format_string);
+ utzreset();
+ } else tv.tv_sec = chkmktime(&tm, setdate, format_string);
- tv.tv_usec = 0;
+ tv.tv_usec = TT.nano/1000;
if (settimeofday(&tv, NULL) < 0) perror_msg("cannot set date");
}
- if (toys.optflags & FLAG_u) {
- if (tz) setenv("TZ", tz, 1);
- else unsetenv("TZ");
- tzset();
- }
-
+ utzreset();
if (!strftime(toybuf, sizeof(toybuf), format_string, &tm))
perror_exit("bad format '%s'", format_string);
puts(toybuf);
return;
-bad_date:
- error_exit("bad date '%s'", setdate);
+bad_showdate:
+ error_exit("bad date '%s'", TT.showdate);
}
diff --git a/toys/posix/du.c b/toys/posix/du.c
index 4302997..77c7b6e 100644
--- a/toys/posix/du.c
+++ b/toys/posix/du.c
@@ -57,7 +57,7 @@ static void print(long long size, struct dirtree *node)
if (TT.maxdepth && TT.depth > TT.maxdepth) return;
if (toys.optflags & FLAG_h) {
- human_readable(toybuf, size);
+ human_readable(toybuf, size, 0);
printf("%s", toybuf);
} else {
int bits = 10;
diff --git a/toys/posix/find.c b/toys/posix/find.c
index a11a910..99cf5e2 100644
--- a/toys/posix/find.c
+++ b/toys/posix/find.c
@@ -141,41 +141,6 @@ static void do_print(struct dirtree *new, char c)
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.
diff --git a/toys/posix/id.c b/toys/posix/id.c
index aa43072..01610bc 100644
--- a/toys/posix/id.c
+++ b/toys/posix/id.c
@@ -82,7 +82,7 @@ static void showid(char *header, unsigned u, char *s)
printf("%s%u(%s)", header, u, s);
}
-void do_id(char *username)
+static void do_id(char *username)
{
int flags, i, ngroups;
struct passwd *pw;
diff --git a/toys/posix/ls.c b/toys/posix/ls.c
index 44915fa..f951198 100644
--- a/toys/posix/ls.c
+++ b/toys/posix/ls.c
@@ -422,6 +422,13 @@ static void listfiles(int dirfd, struct dirtree *indir)
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);
@@ -429,12 +436,6 @@ static void listfiles(int dirfd, struct dirtree *indir)
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);
diff --git a/toys/posix/nl.c b/toys/posix/nl.c
index c7e7b92..60c0a52 100644
--- a/toys/posix/nl.c
+++ b/toys/posix/nl.c
@@ -40,7 +40,7 @@ GLOBALS(
long lcount;
)
-void do_nl(int fd, char *name)
+static void do_nl(int fd, char *name)
{
FILE *f = xfdopen(fd, "r");
int w = TT.w, slen = strlen(TT.s);
diff --git a/toys/posix/split.c b/toys/posix/split.c
index aabf931..075a414 100644
--- a/toys/posix/split.c
+++ b/toys/posix/split.c
@@ -35,7 +35,7 @@ GLOBALS(
char *outfile;
)
-void do_split(int infd, char *in)
+static void do_split(int infd, char *in)
{
unsigned long bytesleft, linesleft, filenum, len, pos;
int outfd = -1;
diff --git a/toys/posix/strings.c b/toys/posix/strings.c
index a872cf6..e87ccde 100644
--- a/toys/posix/strings.c
+++ b/toys/posix/strings.c
@@ -29,7 +29,7 @@ GLOBALS(
long num;
)
-void do_strings(int fd, char *filename)
+static void do_strings(int fd, char *filename)
{
int nread, i, wlen = TT.num, count = 0;
off_t offset = 0;