aboutsummaryrefslogtreecommitdiff
path: root/toys
diff options
context:
space:
mode:
Diffstat (limited to 'toys')
-rw-r--r--toys/android/load_policy.c4
-rw-r--r--toys/other/chroot.c9
-rw-r--r--toys/pending/bc.c15
-rw-r--r--toys/pending/diff.c18
-rw-r--r--toys/pending/tar.c462
-rw-r--r--toys/posix/cmp.c3
-rw-r--r--toys/posix/env.c4
-rw-r--r--toys/posix/grep.c8
-rw-r--r--toys/posix/nice.c8
-rw-r--r--toys/posix/nohup.c6
-rw-r--r--toys/posix/sort.c19
11 files changed, 244 insertions, 312 deletions
diff --git a/toys/android/load_policy.c b/toys/android/load_policy.c
index bc0d5640..523c68f8 100644
--- a/toys/android/load_policy.c
+++ b/toys/android/load_policy.c
@@ -1,4 +1,4 @@
-/* load_policy.c - Load a policy file
+/* load_policy.c - Load an SELinux policy file
*
* Copyright 2015 The Android Open Source Project
@@ -11,7 +11,7 @@ config LOAD_POLICY
help
usage: load_policy FILE
- Load the specified policy file.
+ Load the specified SELinux policy file.
*/
#define FOR_load_policy
diff --git a/toys/other/chroot.c b/toys/other/chroot.c
index b6ef17d6..d791f34a 100644
--- a/toys/other/chroot.c
+++ b/toys/other/chroot.c
@@ -7,13 +7,13 @@
* The container guys use pivot_root() to deal with this, which does actually
* edit mount tree. (New option? Kernel patch?)
-USE_CHROOT(NEWTOY(chroot, "^<1", TOYFLAG_USR|TOYFLAG_SBIN))
+USE_CHROOT(NEWTOY(chroot, "^<1", TOYFLAG_USR|TOYFLAG_SBIN|TOYFLAG_ARGFAIL(125)))
config CHROOT
bool "chroot"
default y
help
- usage: chroot NEWPATH [commandline...]
+ usage: chroot NEWROOT [COMMAND [ARG...]]
Run command within a new root directory. If no command, run /bin/sh.
*/
@@ -24,7 +24,10 @@ void chroot_main(void)
{
char *binsh[] = {"/bin/sh", "-i", 0};
- if (chdir(*toys.optargs) || chroot(".")) perror_exit_raw(*toys.optargs);
+ if (chdir(*toys.optargs) || chroot(".")) {
+ toys.exitval = 125;
+ perror_exit_raw(*toys.optargs);
+ }
if (toys.optargs[1]) xexec(toys.optargs+1);
else xexec(binsh);
}
diff --git a/toys/pending/bc.c b/toys/pending/bc.c
index 614cae70..142c0ce2 100644
--- a/toys/pending/bc.c
+++ b/toys/pending/bc.c
@@ -2120,21 +2120,22 @@ BcStatus bc_num_parse(BcNum *n, char *val,
BcStatus bc_num_ulong(BcNum *n, unsigned long *result) {
size_t i;
- unsigned long pow, r;
+ unsigned long r;
*result = 0;
if (n->neg) return bc_vm_err(BC_ERROR_MATH_NEGATIVE);
- for (r = 0, pow = 1, i = n->rdx; i < n->len; ++i) {
+ for (r = 0, i = n->len; i > n->rdx;) {
- unsigned long prev = r, powprev = pow;
+ unsigned long prev = r * 10;
- r += ((unsigned long) n->num[i]) * pow;
- pow *= 10;
+ if (prev == SIZE_MAX || prev / 10 != r)
+ return bc_vm_err(BC_ERROR_MATH_OVERFLOW);
- if (r < prev || pow < powprev)
- return bc_vm_verr(BC_ERROR_MATH_OVERFLOW, "number cannot fit");
+ r = prev + ((uchar) n->num[--i]);
+
+ if (r == SIZE_MAX || r < prev) return bc_vm_err(BC_ERROR_MATH_OVERFLOW);
}
*result = r;
diff --git a/toys/pending/diff.c b/toys/pending/diff.c
index ea11ba29..4a528134 100644
--- a/toys/pending/diff.c
+++ b/toys/pending/diff.c
@@ -5,7 +5,7 @@
*
* See: http://cm.bell-labs.com/cm/cs/cstr/41.pdf
-USE_DIFF(NEWTOY(diff, "<2>2(color)B(ignore-blank-lines)d(minimal)b(ignore-space-change)ut(expand-tabs)w(ignore-all-space)i(ignore-case)T(initial-tab)s(report-identical-files)q(brief)a(text)L(label)*S(starting-file):N(new-file)r(recursive)U(unified)#<0=3", TOYFLAG_USR|TOYFLAG_BIN))
+USE_DIFF(NEWTOY(diff, "<2>2(color)B(ignore-blank-lines)d(minimal)b(ignore-space-change)ut(expand-tabs)w(ignore-all-space)i(ignore-case)T(initial-tab)s(report-identical-files)q(brief)a(text)L(label)*S(starting-file):N(new-file)r(recursive)U(unified)#<0=3", TOYFLAG_USR|TOYFLAG_BIN|TOYFLAG_ARGFAIL(2)))
config DIFF
bool "diff"
@@ -791,32 +791,28 @@ void diff_main(void)
int j = 0, k = 1, start[2] = {1, 1};
char *files[2];
+ toys.exitval = 2;
+
if ((toys.optflags & FLAG_color) && !isatty(1)) toys.optflags ^= FLAG_color;
for (j = 0; j < 2; j++) {
files[j] = toys.optargs[j];
if (IS_STDIN(files[j])) {
if (fstat(0, &TT.st[j]) == -1)
- perror_exit("can fstat %s", files[j]);
+ perror_exit("can't fstat %s", files[j]);
} else {
- if (stat(files[j], &TT.st[j]) == -1)
- perror_exit("can't stat %s", files[j]);
+ xstat(files[j], &TT.st[j]);
}
}
- if (IS_STDIN(files[0]) && IS_STDIN(files[1])) { //compat :(
- show_status(files); //check ASAP
- return;
- }
-
if ((IS_STDIN(files[0]) || IS_STDIN(files[1]))
&& (S_ISDIR(TT.st[0].st_mode) || S_ISDIR(TT.st[1].st_mode)))
error_exit("can't compare stdin to directory");
if ((TT.st[0].st_ino == TT.st[1].st_ino) //physicaly same device
&& (TT.st[0].st_dev == TT.st[1].st_dev)) {
- show_status(files);
- return ;
+ toys.exitval = 0;
+ return show_status(files);
}
if (S_ISDIR(TT.st[0].st_mode) && S_ISDIR(TT.st[1].st_mode)) {
diff --git a/toys/pending/tar.c b/toys/pending/tar.c
index 6bb2b0e9..97e699b4 100644
--- a/toys/pending/tar.c
+++ b/toys/pending/tar.c
@@ -54,10 +54,20 @@ GLOBALS(
// exc is an argument but inc isn't?
struct arg_list *inc, *pass;
- void *inodes, *handle;
+ void *inodes;
char *cwd;
int fd;
- unsigned short offset; // only ever used to calculate 512 byte padding
+
+ // Parsed information about a tar header.
+ struct {
+ char *name, *link_target, *uname, *gname;
+ long long size;
+ uid_t uid;
+ gid_t gid;
+ mode_t mode;
+ time_t mtime;
+ dev_t device;
+ } hdr;
)
struct tar_hdr {
@@ -66,22 +76,6 @@ struct tar_hdr {
prefix[155], padd[12];
};
-// Parsed information about a tar header.
-struct file_header {
- char *name, *link_target, *uname, *gname;
- long long size;
- uid_t uid;
- gid_t gid;
- mode_t mode;
- time_t mtime;
- dev_t device;
-};
-
-struct archive_handler {
- struct file_header file_hdr;
- void (*extract_handler)(struct archive_handler*);
-};
-
struct inode_list {
struct inode_list *next;
char *arg;
@@ -115,11 +109,20 @@ static struct inode_list *seen_inode(void **list, struct stat *st, char *name)
return 0;
}
+// Calculate packet checksum, with cksum field treated as 8 spaces
+static unsigned cksum(void *data)
+{
+ unsigned i, cksum = 8*' ';
+
+ for (i = 0; i<500; i += (i==147) ? 9 : 1) cksum += ((char *)data)[i];
+
+ return cksum;
+}
+
static void write_longname(char *name, char type)
{
struct tar_hdr tmp[2];
- unsigned int sum = 0;
- int i, sz = strlen(name) +1;
+ int sz = strlen(name) +1;
memset(tmp, 0, sizeof(tmp));
strcpy(tmp->name, "././@LongLink");
@@ -132,10 +135,7 @@ static void write_longname(char *name, char type)
strcpy(tmp->magic, "ustar ");
// Calculate checksum
- memset(tmp->chksum, ' ', 8);
- for (i = 0; i < 512; i++) sum += ((char *)tmp)[i];
-// TODO: why is this -1 when the rest aren't?
- itoo(tmp->chksum, sizeof(tmp->chksum)-1, sum);
+ itoo(tmp->chksum, sizeof(tmp->chksum), cksum(&tmp));
// write header and name, padded with NUL to block size
xwrite(TT.fd, tmp, sizeof(*tmp));
@@ -153,13 +153,6 @@ static int filter(struct arg_list *lst, char *name)
static void skippy(long long len)
{
if (lskip(TT.fd, len)) perror_exit("EOF");
- TT.offset += len;
-}
-
-static void sendlen(int fd, long long len)
-{
- xsendfile_len(TT.fd, fd, len);
- TT.offset += len;
}
// actually void **, but automatic typecasting doesn't work with void ** :(
@@ -170,7 +163,7 @@ static void alloread(void *buf, int len)
free(*b);
*b = xmalloc(len+1);
xreadall(TT.fd, *b, len);
- TT.offset += len;
+ b[len] = 0;
}
static void add_file(char **nam, struct stat *st)
@@ -181,7 +174,6 @@ static void add_file(char **nam, struct stat *st)
struct inode_list *node = node;
int i, fd =-1;
char *c, *p, *name = *nam, *lnk, *hname, buf[512] = {0,};
- unsigned int sum = 0;
static int warn = 1;
for (p = name; *p; p++)
@@ -210,7 +202,6 @@ static void add_file(char **nam, struct stat *st)
itoo(hdr.gid, sizeof(hdr.gid), st->st_gid);
itoo(hdr.size, sizeof(hdr.size), 0); //set size later
itoo(hdr.mtime, sizeof(hdr.mtime), st->st_mtime);
- memset(hdr.chksum, ' ', sizeof(hdr.chksum));
// Hard link or symlink?
i = !!S_ISLNK(st->st_mode);
@@ -252,9 +243,7 @@ static void add_file(char **nam, struct stat *st)
snprintf(hdr.gname, sizeof(hdr.gname), "%s", gr->gr_name);
else sprintf(hdr.gname, "%d", st->st_gid);
- //calculate chksum.
- for (i = 0; i < 512; i++) sum += ((char*)&hdr)[i];
- itoo(hdr.chksum, sizeof(hdr.chksum)-1, sum);
+ itoo(hdr.chksum, sizeof(hdr.chksum)-1, cksum(&hdr));
if (FLAG(v)) printf("%s\n",hname);
xwrite(TT.fd, (void*)&hdr, 512);
@@ -288,28 +277,14 @@ static int add_to_tar(struct dirtree *node)
return ((DIRTREE_RECURSE | (FLAG(h)?DIRTREE_SYMFOLLOW:0)));
}
-static void extract_stream(struct archive_handler *tar_hdl)
-{
- int pipefd[2] = {TT.fd, -1};
-
- xpopen_both((char *[]){FLAG(z)?"gunzip":"bunzip2", "-cf", "-", NULL}, pipefd);
- close(TT.fd);
- TT.fd = pipefd[1];
-}
-
-static void extract_to_stdout(struct archive_handler *tar)
-{
- sendlen(0, tar->file_hdr.size);
-}
-
-static void extract_to_command(struct archive_handler *tar)
+// Does anybody actually use this?
+static void extract_to_command(void)
{
int pipefd[2], status = 0;
pid_t cpid;
- struct file_header *file_hdr = &tar->file_hdr;
xpipe(pipefd);
- if (!S_ISREG(file_hdr->mode)) return; //only regular files are supported.
+ if (!S_ISREG(TT.hdr.mode)) return; //only regular files are supported.
cpid = fork();
if (cpid == -1) perror_exit("fork");
@@ -318,18 +293,18 @@ static void extract_to_command(struct archive_handler *tar)
char buf[64], *argv[4] = {"sh", "-c", TT.to_command, NULL};
setenv("TAR_FILETYPE", "f", 1);
- sprintf(buf, "%0o", file_hdr->mode);
+ sprintf(buf, "%0o", TT.hdr.mode);
setenv("TAR_MODE", buf, 1);
- sprintf(buf, "%ld", (long)file_hdr->size);
+ sprintf(buf, "%ld", (long)TT.hdr.size);
setenv("TAR_SIZE", buf, 1);
- setenv("TAR_FILENAME", file_hdr->name, 1);
- setenv("TAR_UNAME", file_hdr->uname, 1);
- setenv("TAR_GNAME", file_hdr->gname, 1);
- sprintf(buf, "%0o", (int)file_hdr->mtime);
+ setenv("TAR_FILENAME", TT.hdr.name, 1);
+ setenv("TAR_UNAME", TT.hdr.uname, 1);
+ setenv("TAR_GNAME", TT.hdr.gname, 1);
+ sprintf(buf, "%0o", (int)TT.hdr.mtime);
setenv("TAR_MTIME", buf, 1);
- sprintf(buf, "%0o", file_hdr->uid);
+ sprintf(buf, "%0o", TT.hdr.uid);
setenv("TAR_UID", buf, 1);
- sprintf(buf, "%0o", file_hdr->gid);
+ sprintf(buf, "%0o", TT.hdr.gid);
setenv("TAR_GID", buf, 1);
xclose(pipefd[1]); // Close unused write
@@ -338,7 +313,7 @@ static void extract_to_command(struct archive_handler *tar)
xexec(argv);
} else {
xclose(pipefd[0]); // Close unused read end
- sendlen(pipefd[1], file_hdr->size);
+ xsendfile_len(TT.fd, pipefd[1], TT.hdr.size);
xclose(pipefd[1]);
waitpid(cpid, &status, 0);
if (WIFSIGNALED(status))
@@ -346,95 +321,89 @@ static void extract_to_command(struct archive_handler *tar)
}
}
-static void extract_to_disk(struct archive_handler *tar)
+static void extract_to_disk(void)
{
int flags, dst_fd = -1;
char *s;
struct stat ex;
- struct file_header *file_hdr = &tar->file_hdr;
// while not if
- flags = strlen(file_hdr->name);
+ flags = strlen(TT.hdr.name);
if (flags>2)
- if (strstr(file_hdr->name, "/../") || !strcmp(file_hdr->name, "../") ||
- !strcmp(file_hdr->name+flags-3, "/.."))
- error_msg("drop %s", file_hdr->name);
+ if (strstr(TT.hdr.name, "/../") || !strcmp(TT.hdr.name, "../") ||
+ !strcmp(TT.hdr.name+flags-3, "/.."))
+ error_msg("drop %s", TT.hdr.name);
- if (file_hdr->name[flags-1] == '/') file_hdr->name[flags-1] = 0;
+ if (TT.hdr.name[flags-1] == '/') TT.hdr.name[flags-1] = 0;
//Regular file with preceding path
- if ((s = strrchr(file_hdr->name, '/'))) {
- if (mkpath(file_hdr->name) && errno !=EEXIST) {
- error_msg(":%s: not created", file_hdr->name);
- return;
- }
- }
+ if ((s = strrchr(TT.hdr.name, '/')) && mkpath(TT.hdr.name) && errno !=EEXIST)
+ return error_msg(":%s: not created", TT.hdr.name);
//remove old file, if exists
- if (!FLAG(k) && !S_ISDIR(file_hdr->mode) && !lstat(file_hdr->name, &ex))
- if (unlink(file_hdr->name))
- perror_msg("can't remove: %s", file_hdr->name);
+ if (!FLAG(k) && !S_ISDIR(TT.hdr.mode) && !lstat(TT.hdr.name, &ex))
+ if (unlink(TT.hdr.name)) perror_msg("can't remove: %s", TT.hdr.name);
//hard link
- if (S_ISREG(file_hdr->mode) && file_hdr->link_target) {
- if (link(file_hdr->link_target, file_hdr->name))
- perror_msg("can't link '%s' -> '%s'",file_hdr->name, file_hdr->link_target);
+ if (S_ISREG(TT.hdr.mode) && TT.hdr.link_target) {
+ if (link(TT.hdr.link_target, TT.hdr.name))
+ perror_msg("can't link '%s' -> '%s'", TT.hdr.name, TT.hdr.link_target);
goto COPY;
}
- switch (file_hdr->mode & S_IFMT) {
+ switch (TT.hdr.mode & S_IFMT) {
case S_IFREG:
flags = O_WRONLY|O_CREAT|O_EXCL;
if (FLAG(overwrite)) flags = O_WRONLY|O_CREAT|O_TRUNC;
- dst_fd = open(file_hdr->name, flags, file_hdr->mode & 07777);
- if (dst_fd == -1) perror_msg("%s: can't open", file_hdr->name);
+ dst_fd = open(TT.hdr.name, flags, TT.hdr.mode & 07777);
+ if (dst_fd == -1) perror_msg("%s: can't open", TT.hdr.name);
break;
case S_IFDIR:
- if ((mkdir(file_hdr->name, file_hdr->mode) == -1) && errno != EEXIST)
- perror_msg("%s: can't create", file_hdr->name);
+ if ((mkdir(TT.hdr.name, TT.hdr.mode) == -1) && errno != EEXIST)
+ perror_msg("%s: can't create", TT.hdr.name);
break;
case S_IFLNK:
- if (symlink(file_hdr->link_target, file_hdr->name))
- perror_msg("can't link '%s' -> '%s'",file_hdr->name, file_hdr->link_target);
+ if (symlink(TT.hdr.link_target, TT.hdr.name))
+ perror_msg("can't link '%s' -> '%s'", TT.hdr.name, TT.hdr.link_target);
break;
case S_IFBLK:
case S_IFCHR:
case S_IFIFO:
- if (mknod(file_hdr->name, file_hdr->mode, file_hdr->device))
- perror_msg("can't create '%s'", file_hdr->name);
+ if (mknod(TT.hdr.name, TT.hdr.mode, TT.hdr.device))
+ perror_msg("can't create '%s'", TT.hdr.name);
break;
default:
- printf("type %o not supported\n", file_hdr->mode);
+ printf("type %o not supported\n", TT.hdr.mode);
break;
}
//copy file....
COPY:
- sendlen(dst_fd, file_hdr->size);
+ xsendfile_len(TT.fd, dst_fd, TT.hdr.size);
close(dst_fd);
- if (S_ISLNK(file_hdr->mode)) return;
if (!FLAG(o)) {
//set ownership..., --no-same-owner, --numeric-owner
- uid_t u = file_hdr->uid;
- gid_t g = file_hdr->gid;
+ uid_t u = TT.hdr.uid;
+ gid_t g = TT.hdr.gid;
if (!FLAG(numeric_owner)) {
- struct group *gr = getgrnam(file_hdr->gname);
- struct passwd *pw = getpwnam(file_hdr->uname);
+ struct group *gr = getgrnam(TT.hdr.gname);
+ struct passwd *pw = getpwnam(TT.hdr.uname);
if (pw) u = pw->pw_uid;
if (gr) g = gr->gr_gid;
}
- if (!geteuid() && chown(file_hdr->name, u, g))
- perror_msg("chown %d:%d '%s'", u, g, file_hdr->name);;
+ if (!geteuid() && lchown(TT.hdr.name, u, g))
+ perror_msg("chown %d:%d '%s'", u, g, TT.hdr.name);;
}
- if (FLAG(p)) // || !FLAG(no_same_permissions))
- chmod(file_hdr->name, file_hdr->mode);
+ // || !FLAG(no_same_permissions))
+ if (FLAG(p) && !S_ISLNK(TT.hdr.mode)) chmod(TT.hdr.name, TT.hdr.mode);
+// TODO: defer directory mtime until we've finished with contents
//apply mtime
if (!FLAG(m)) {
- struct timeval times[2] = {{file_hdr->mtime, 0},{file_hdr->mtime, 0}};
- utimes(file_hdr->name, times);
+ struct timeval times[2] = {{TT.hdr.mtime, 0},{TT.hdr.mtime, 0}};
+ utimes(TT.hdr.name, times);
}
}
@@ -460,203 +429,149 @@ static void file_to_list(char *file, struct arg_list **llist)
}
//convert octal to int
-static int otoi(char *str, int len)
+static unsigned long long otoi(char *str, int len)
{
- long val;
- char *endp, inp[len+1]; //1 for NUL termination
-
- memcpy(inp, str, len);
- inp[len] = '\0'; //nul-termination made sure
- val = strtol(inp, &endp, 8);
- if (*endp && *endp != ' ') error_exit("invalid param");
- return (int)val;
-}
+ unsigned long long val;
-static char *process_extended_hdr(struct archive_handler *tar, int size)
-{
- char *value = NULL, *p, *buf = 0;
-
- alloread(&buf, size);
- buf[size] = 0;
- p = buf;
-
- while (size) {
- char *key;
- int len, n;
-
- // extended records are of the format: "LEN NAME=VALUE\n"
- sscanf(p, "%d %n", &len, &n);
- key = p + n;
- p += len;
- size -= len;
- p[-1] = 0;
- if (size < 0) {
- error_msg("corrupted extended header");
- break;
- }
+// todo: base-256 encoding, just do it symmetrically for all fields
+ str[len-1] = 0;
+ val = strtoull(str, &str, 8);
+ if (*str && *str != ' ') error_exit("bad header");
- len = strlen("path=");
- if (!strncmp(key, "path=", len)) {
- value = key + strlen("path=");
- break;
- }
- }
- if (value) value = xstrdup(value);
- free(buf);
- return value;
+ return val;
}
static void unpack_tar(void)
{
- struct archive_handler *tar_hdl = TT.handle;
struct tar_hdr tar;
- struct file_header *file_hdr;
- int i, j, maj, min, sz, e = 0;
- unsigned int cksum;
+ int i;
char *s;
for (;;) {
// align to next block and read it
-// This is the only consumer of TT.offset
- if (TT.offset&511) skippy(512-TT.offset%512);
+ if (TT.hdr.size%512) skippy(512-TT.hdr.size%512);
+
i = readall(TT.fd, &tar, 512);
- if (i != 512) {
- if (i >= 2) goto CHECK_MAGIC; //may be a small (<512 byte)zipped file
- error_exit("read error");
- }
+ if (i != 512) error_exit("read error");
+ // ensure null temination even of pathological packets
+ tar.padd[0] = 0;
+ // End of tar
+ if (!*tar.name) return;
- if (!tar.name[0]) {
- if (e) return; //end of tar 2 empty blocks
- e = 1;//empty jump to next block
-// never clear e, so they don't have to be _consecutive_???
- continue;
- }
// can you append a bzip to a gzip _within_ a tarball? Nested compress?
// Or compressed data after uncompressed data?
- if (strncmp(tar.magic, "ustar", 5)) {
- // Try detecting .gz or .bz2 by looking for their magic.
-CHECK_MAGIC:
- if ((!strncmp(tar.name, "\x1f\x8b", 2) || !strncmp(tar.name, "BZh", 3))
- && !lseek(TT.fd, -i, SEEK_CUR)) {
- toys.optflags |= (*tar.name == 'B') ? FLAG_j : FLAG_z;
- extract_stream(tar_hdl);
- continue;
- }
- error_exit("invalid tar format");
- }
-// moved this down here so it doesn't have to be undone
- TT.offset += i;
-
- // Calculate checksum, with cksum field treated as eight spaces
- cksum = 8*' ';
- for (j = 0; j<500; j += (j==147) ? 9 : 1) cksum += ((char*)&tar)[j];
-
- if (cksum != otoi(tar.chksum, sizeof(tar.chksum))) error_exit("bad cksum");
-
- file_hdr = &tar_hdl->file_hdr;
- memset(file_hdr, 0, sizeof(struct file_header));
- file_hdr->mode = otoi(tar.mode, sizeof(tar.mode));
- file_hdr->uid = otoi(tar.uid, sizeof(tar.uid));
- file_hdr->gid = otoi(tar.gid, sizeof(tar.gid));
- file_hdr->size = otoi(tar.size, sizeof(tar.size));
- file_hdr->mtime = otoi(tar.mtime, sizeof(tar.mtime));
- file_hdr->uname = xstrdup(tar.uname);
- file_hdr->gname = xstrdup(tar.gname);
- maj = otoi(tar.major, sizeof(tar.major));
- min = otoi(tar.minor, sizeof(tar.minor));
- file_hdr->device = dev_makedev(maj, min);
-
- if (tar.type <= '7') {
- if (tar.link[0]) {
- sz = sizeof(tar.link);
- file_hdr->link_target = xmalloc(sz + 1);
- memcpy(file_hdr->link_target, tar.link, sz);
- file_hdr->link_target[sz] = '\0';
- }
-
- file_hdr->name = xzalloc(256);// pathname supported size
- if (tar.prefix[0]) {
- memcpy(file_hdr->name, tar.prefix, sizeof(tar.prefix));
- sz = strlen(file_hdr->name);
- if (file_hdr->name[sz-1] != '/') file_hdr->name[sz] = '/';
- }
- sz = strlen(file_hdr->name);
- memcpy(file_hdr->name + sz, tar.name, sizeof(tar.name));
-// TODO: won't the vfs tell us?
- if (file_hdr->name[255]) error_exit("filename too long");
- }
-
- // Headers that don't immediately result in creating a new node
- if (strchr("KLxDMNSVg", tar.type)) {
- if (tar.type == 'K') alloread(&file_hdr->link_target, file_hdr->size);
- else if (tar.type == 'L') alloread(&file_hdr->name, file_hdr->size);
- else if (tar.type == 'x') process_extended_hdr(tar_hdl, file_hdr->size);
- else skippy(file_hdr->size);
+ if (memcmp(tar.magic, "ustar", 5)) error_exit("bad header");
+ if (cksum(&tar) != otoi(tar.chksum, sizeof(tar.chksum)))
+ error_exit("bad cksum");
+ TT.hdr.size = otoi(tar.size, sizeof(tar.size));
+
+ // If this header isn't writing something to the filesystem
+ if (tar.type<'0' || tar.type>'7') {
+ if (tar.type == 'K') alloread(&TT.hdr.link_target, TT.hdr.size);
+ else if (tar.type == 'L') alloread(&TT.hdr.name, TT.hdr.size);
+ else if (tar.type == 'x') {
+ char *p, *buf = 0;
+ int i, len, n;
+
+ // Posix extended record "LEN NAME=VALUE\n" format
+ alloread(&buf, TT.hdr.size);
+ for (p = buf; (p-buf)<TT.hdr.size; p += len) {
+ if ((i = sscanf(p, "%u path=%n", &len, &n))<1 || len<4 ||
+ len>TT.hdr.size)
+ {
+ error_msg("corrupted extended header");
+ break;
+ }
+ p[len-1] = 0;
+ if (i == 2) {
+ TT.hdr.name = xstrdup(p+n);
+ break;
+ }
+ }
+ free(buf);
+
+ // This could be if (strchr("DMNSVg", tar.type)) but an unknown header
+ // type with trailing contents is unlikely to have a valid type & cksum
+ } else skippy(TT.hdr.size);
continue;
}
- // Specified file type?
- if (isdigit(tar.type))
- file_hdr->mode |= (char []){8,8,10,2,6,4,1,8,0,0}[tar.type-'0']<<12;
+ // At this point, we're writing something to the filesystem. Parse fields.
+ TT.hdr.mode = otoi(tar.mode, sizeof(tar.mode));
+ TT.hdr.mode |= (char []){8,8,10,2,6,4,1,8}[tar.type-'0']<<12;
+ TT.hdr.uid = otoi(tar.uid, sizeof(tar.uid));
+ TT.hdr.gid = otoi(tar.gid, sizeof(tar.gid));
+ TT.hdr.mtime = otoi(tar.mtime, sizeof(tar.mtime));
+ TT.hdr.device = dev_makedev(otoi(tar.major, sizeof(tar.major)),
+ otoi(tar.minor, sizeof(tar.minor)));
+
+ TT.hdr.uname = xstrndup(tar.uname, sizeof(tar.uname));
+ TT.hdr.gname = xstrndup(tar.gname, sizeof(tar.gname));
+ if (!TT.hdr.link_target && *tar.link)
+ TT.hdr.link_target = xstrndup(tar.link, sizeof(tar.link));
+ if (!TT.hdr.name) {
+ i = strnlen(tar.prefix, sizeof(tar.prefix));
+ TT.hdr.name = xmprintf("%.*s%s%.*s", i, tar.prefix,
+ (i && tar.prefix[i-1] != '/') ? "/" : "",
+ (int)sizeof(tar.name), tar.name);
+ }
// Directories sometimes recorded as "file with trailing slash"
- if (S_ISREG(file_hdr->mode) && (s = strend(file_hdr->name, "/"))) {
+ if (S_ISREG(TT.hdr.mode) && (s = strend(TT.hdr.name, "/"))) {
*s = 0;
- file_hdr->mode = (file_hdr->mode & ~S_IFMT) | S_IFDIR;
+ TT.hdr.mode = (TT.hdr.mode & ~S_IFMT) | S_IFDIR;
}
-// TODO: what?
- if ((file_hdr->link_target && *(file_hdr->link_target))
- || S_ISLNK(file_hdr->mode) || S_ISDIR(file_hdr->mode))
- file_hdr->size = 0;
+ // Hardlinks, symlinks, and directories do not have contents in archive
+ // (Neither do fifo, block or char devices, but not testing for that...?)
+ if ((TT.hdr.link_target && *TT.hdr.link_target)
+ || S_ISLNK(TT.hdr.mode) || S_ISDIR(TT.hdr.mode))
+ TT.hdr.size = 0;
// Skip excluded files
- if (filter(TT.exc, file_hdr->name) ||
- (TT.inc && !filter(TT.inc, file_hdr->name))) {
- skippy(file_hdr->size);
-// TODO: awkward
- goto FREE;
- }
-// TODO: wrong, shouldn't grow endlessly, mark seen TT.inc instead
- add_to_list(&TT.pass, xstrdup(file_hdr->name));
-
- if (FLAG(t)) {
- if (FLAG(v)) {
- char perm[11];
- struct tm *lc = localtime((const time_t*)&(file_hdr->mtime));
+ if (filter(TT.exc, TT.hdr.name) || (TT.inc && !filter(TT.inc, TT.hdr.name)))
+ skippy(TT.hdr.size);
+ else {
- mode_to_string(file_hdr->mode, perm);
- printf("%s %s/%s %9ld %d-%02d-%02d %02d:%02d:%02d ",perm,file_hdr->uname,
- file_hdr->gname, (long)file_hdr->size, 1900+lc->tm_year,
- 1+lc->tm_mon, lc->tm_mday, lc->tm_hour, lc->tm_min, lc->tm_sec);
+// TODO: wrong, shouldn't grow endlessly, mark seen TT.inc instead
+ add_to_list(&TT.pass, xstrdup(TT.hdr.name));
+
+ if (FLAG(t)) {
+ if (FLAG(v)) {
+ char perm[11];
+ struct tm *lc = localtime(&TT.hdr.mtime);
+
+ mode_to_string(TT.hdr.mode, perm);
+ printf("%s %s/%s %9ld %d-%02d-%02d %02d:%02d:%02d ", perm,
+ TT.hdr.uname, TT.hdr.gname, (long)TT.hdr.size, 1900+lc->tm_year,
+ 1+lc->tm_mon, lc->tm_mday, lc->tm_hour, lc->tm_min, lc->tm_sec);
+ }
+ printf("%s", TT.hdr.name);
+ if (TT.hdr.link_target) printf(" -> %s", TT.hdr.link_target);
+ xputc('\n');
+ skippy(TT.hdr.size);
+ } else {
+ if (FLAG(v)) printf("%s\n", TT.hdr.name);
+ if (FLAG(O)) xsendfile_len(TT.fd, 0, TT.hdr.size);
+ else if (FLAG(to_command)) extract_to_command();
+ else extract_to_disk();
}
- printf("%s",file_hdr->name);
- if (file_hdr->link_target) printf(" -> %s",file_hdr->link_target);
- xputc('\n');
- skippy(file_hdr->size);
- } else {
- if (FLAG(v)) printf("%s\n",file_hdr->name);
- tar_hdl->extract_handler(tar_hdl);
}
-FREE:
- free(file_hdr->name);
- free(file_hdr->link_target);
- free(file_hdr->uname);
- free(file_hdr->gname);
+
+ free(TT.hdr.name);
+ free(TT.hdr.link_target);
+ free(TT.hdr.uname);
+ free(TT.hdr.gname);
+ TT.hdr.name = TT.hdr.link_target = 0;
}
}
void tar_main(void)
{
- struct archive_handler *tar_hdl;
struct arg_list *tmp;
char *s, **args = toys.optargs;
-// TODO: zap
- TT.handle = tar_hdl = xzalloc(sizeof(struct archive_handler));
- tar_hdl->extract_handler = extract_to_disk;
-
// When extracting to command
signal(SIGPIPE, SIG_IGN);
@@ -682,11 +597,23 @@ void tar_main(void)
// Are we reading?
if (FLAG(x)||FLAG(t)) {
- if (FLAG(O)) tar_hdl->extract_handler = extract_to_stdout;
- if (FLAG(to_command)) tar_hdl->extract_handler = extract_to_command;
-
// TODO: autodtect
- if (FLAG(j)||FLAG(z)) extract_stream(tar_hdl);
+
+// Try detecting .gz or .bz2 by looking for their magic.
+// if ((!memcmp(tar.name, "\x1f\x8b", 2) || !memcmp(tar.name, "BZh", 3))
+// && !lseek(TT.fd, -i, SEEK_CUR)) {
+// toys.optflags |= (*tar.name == 'B') ? FLAG_j : FLAG_z;
+// extract_stream(tar_hdl);
+// continue;
+// }
+ if (FLAG(j)||FLAG(z)) {
+ int pipefd[2] = {TT.fd, -1};
+
+ xpopen_both((char *[]){FLAG(z)?"gunzip":"bunzip2", "-cf", "-", NULL},
+ pipefd);
+ close(TT.fd);
+ TT.fd = pipefd[1];
+ }
unpack_tar();
for (tmp = TT.inc; tmp; tmp = tmp->next)
@@ -703,7 +630,6 @@ void tar_main(void)
close(TT.fd);
TT.fd = pipefd[0];
}
-// TODO cowardly empty archive
for (tmp = TT.inc; tmp; tmp = tmp->next)
dirtree_flagread(tmp->arg, FLAG(h)?DIRTREE_SYMFOLLOW:0, add_to_tar);
diff --git a/toys/posix/cmp.c b/toys/posix/cmp.c
index 6cd410fc..c573f02e 100644
--- a/toys/posix/cmp.c
+++ b/toys/posix/cmp.c
@@ -4,7 +4,7 @@
*
* See http://opengroup.org/onlinepubs/9699919799/utilities/cmp.html
-USE_CMP(NEWTOY(cmp, "<2>2ls(silent)(quiet)[!ls]", TOYFLAG_USR|TOYFLAG_BIN))
+USE_CMP(NEWTOY(cmp, "<2>2ls(silent)(quiet)[!ls]", TOYFLAG_USR|TOYFLAG_BIN|TOYFLAG_ARGFAIL(2)))
config CMP
bool "cmp"
@@ -81,4 +81,3 @@ void cmp_main(void)
loopfiles_rw(toys.optargs, O_CLOEXEC|(WARN_ONLY*!(toys.optflags&FLAG_s)), 0,
do_cmp);
}
-
diff --git a/toys/posix/env.c b/toys/posix/env.c
index 2de8f690..5c7bb789 100644
--- a/toys/posix/env.c
+++ b/toys/posix/env.c
@@ -6,13 +6,13 @@
*
* Deviations from posix: "-" argument and -0
-USE_ENV(NEWTOY(env, "^0iu*", TOYFLAG_USR|TOYFLAG_BIN))
+USE_ENV(NEWTOY(env, "^0iu*", TOYFLAG_USR|TOYFLAG_BIN|TOYFLAG_ARGFAIL(125)))
config ENV
bool "env"
default y
help
- usage: env [-i] [-u NAME] [NAME=VALUE...] [command [option...]]
+ usage: env [-i] [-u NAME] [NAME=VALUE...] [COMMAND [ARG...]]
Set the environment for command invocation, or list environment variables.
diff --git a/toys/posix/grep.c b/toys/posix/grep.c
index c9a30882..9239614f 100644
--- a/toys/posix/grep.c
+++ b/toys/posix/grep.c
@@ -10,9 +10,9 @@
* echo hello | grep -f </dev/null
*
-USE_GREP(NEWTOY(grep, "(color):;S(exclude)*M(include)*ZzEFHIab(byte-offset)h(no-filename)ino(only-matching)rsvwcl(files-with-matches)q(quiet)(silent)e*f*C#B#A#m#x[!wx][!EFw]", TOYFLAG_BIN))
-USE_EGREP(OLDTOY(egrep, grep, TOYFLAG_BIN))
-USE_FGREP(OLDTOY(fgrep, grep, TOYFLAG_BIN))
+USE_GREP(NEWTOY(grep, "(color):;S(exclude)*M(include)*ZzEFHIab(byte-offset)h(no-filename)ino(only-matching)rsvwcl(files-with-matches)q(quiet)(silent)e*f*C#B#A#m#x[!wx][!EFw]", TOYFLAG_BIN|TOYFLAG_ARGFAIL(2)))
+USE_EGREP(OLDTOY(egrep, grep, TOYFLAG_BIN|TOYFLAG_ARGFAIL(2)))
+USE_FGREP(OLDTOY(fgrep, grep, TOYFLAG_BIN|TOYFLAG_ARGFAIL(2)))
config GREP
bool "grep"
@@ -22,7 +22,7 @@ config GREP
Show lines matching regular expressions. If no -e, first argument is
regular expression to match. With no files (or "-" filename) read stdin.
- Returns 0 if matched, 1 if no match found.
+ Returns 0 if matched, 1 if no match found, 2 for command errors.
-e Regex to match. (May be repeated.)
-f File listing regular expressions to match.
diff --git a/toys/posix/nice.c b/toys/posix/nice.c
index ca5e2224..c26f66d3 100644
--- a/toys/posix/nice.c
+++ b/toys/posix/nice.c
@@ -10,7 +10,7 @@ config NICE
bool "nice"
default y
help
- usage: nice [-n PRIORITY] command [args...]
+ usage: nice [-n PRIORITY] COMMAND [ARG...]
Run a command line at an increased or decreased scheduling priority.
@@ -32,7 +32,9 @@ void nice_main(void)
if (!toys.optflags) TT.n = 10;
errno = 0;
- if (nice(TT.n)==-1 && errno) perror_exit("Can't set priority");
-
+ if (nice(TT.n)==-1 && errno) {
+ toys.exitval = 125;
+ perror_exit("Can't set priority");
+ }
xexec(toys.optargs);
}
diff --git a/toys/posix/nohup.c b/toys/posix/nohup.c
index b302cbe4..e5b526f7 100644
--- a/toys/posix/nohup.c
+++ b/toys/posix/nohup.c
@@ -4,13 +4,13 @@
*
* See http://opengroup.org/onlinepubs/9699919799/utilities/nohup.html
-USE_NOHUP(NEWTOY(nohup, "<1^", TOYFLAG_USR|TOYFLAG_BIN))
+USE_NOHUP(NEWTOY(nohup, "<1^", TOYFLAG_USR|TOYFLAG_BIN|TOYFLAG_ARGFAIL(125)))
config NOHUP
bool "nohup"
default y
help
- usage: nohup COMMAND [ARGS...]
+ usage: nohup COMMAND [ARG...]
Run a command that survives the end of its terminal.
@@ -21,6 +21,7 @@ config NOHUP
void nohup_main(void)
{
+ toys.exitval = 125;
xsignal(SIGHUP, SIG_IGN);
if (isatty(1)) {
close(1);
@@ -38,5 +39,6 @@ void nohup_main(void)
close(0);
xopen_stdio("/dev/null", O_RDONLY);
}
+ toys.exitval = 0;
xexec(toys.optargs);
}
diff --git a/toys/posix/sort.c b/toys/posix/sort.c
index 9433aef2..9d2f2276 100644
--- a/toys/posix/sort.c
+++ b/toys/posix/sort.c
@@ -7,7 +7,7 @@
* Deviations from POSIX: Lots.
* We invented -x
-USE_SORT(NEWTOY(sort, USE_SORT_FLOAT("g")"S:T:m" "o:k*t:" "xVbMcszdfirun", TOYFLAG_USR|TOYFLAG_BIN))
+USE_SORT(NEWTOY(sort, USE_SORT_FLOAT("g")"S:T:m" "o:k*t:" "xVbMcszdfirun", TOYFLAG_USR|TOYFLAG_BIN|TOYFLAG_ARGFAIL(2)))
config SORT
bool "sort"
@@ -34,12 +34,13 @@ config SORT
-o Output to FILE instead of stdout
-V Version numbers (name-1.234-rc6.5b.tgz)
- Sorting by key looks at a subset of the words on each line. -k2
- uses the second word to the end of the line, -k2,2 looks at only
- the second word, -k2,4 looks from the start of the second to the end
- of the fourth word. Specifying multiple keys uses the later keys as
- tie breakers, in order. A type specifier appended to a sort key
- (such as -2,2n) applies only to sorting that key.
+ Sorting by key looks at a subset of the words on each line. -k2 uses the
+ second word to the end of the line, -k2,2 looks at only the second word,
+ -k2,4 looks from the start of the second to the end of the fourth word.
+ -k2.4,5 starts from the fourth character of the second word, to the end
+ of the fifth word. Specifying multiple keys uses the later keys as tie
+ breakers, in order. A type specifier appended to a sort key (such as -2,2n)
+ applies only to sorting that key.
config SORT_FLOAT
bool
@@ -121,7 +122,8 @@ static char *get_key_data(char *str, struct sort_key *key, int flags)
if (TT.t && str[start]==*TT.t) start++;
// Strip leading and trailing whitespace if necessary
- if (flags&FLAG_b) while (isspace(str[start])) start++;
+ if ((flags&FLAG_b) || (!TT.t && !key->range[3]))
+ while (isspace(str[start])) start++;
if (flags&FLAG_bb) while (end>start && isspace(str[end-1])) end--;
// Handle offsets on start and end
@@ -343,6 +345,7 @@ void sort_main(void)
if (!temp2 || flag>FLAG_x
|| (flag&(FLAG_u|FLAG_c|FLAG_s|FLAG_z)))
{
+ toys.exitval = 2;
error_exit("Unknown key option.");
}
// b after , means strip _trailing_ space, not leading.