aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorElliott Hughes <enh@google.com>2019-06-10 14:20:24 -0700
committerElliott Hughes <enh@google.com>2019-06-10 14:24:52 -0700
commitf6a7ebff99ad39ece814bf67c8c3c36e88b2a9d0 (patch)
tree1e4c31a0333f553c9824243ec6898bd18608343b
parent8dd06211ecb29e9f25c8db28bfcd69ce0b3131e9 (diff)
parentebc2c400763d0a2cbf092534150b3cd6744d51f9 (diff)
downloadtoybox-f6a7ebff99ad39ece814bf67c8c3c36e88b2a9d0.tar.gz
Merge remote-tracking branch 'toybox/master' into HEAD
Change-Id: I69b44717c4b9b7933325bd01a3392be25854eeb1
-rw-r--r--.config4
-rw-r--r--generated/config.h8
-rw-r--r--generated/flags.h58
-rw-r--r--generated/globals.h9
-rw-r--r--generated/help.h8
-rw-r--r--generated/newtoys.h4
-rw-r--r--lib/lib.c81
-rw-r--r--lib/lib.h2
-rw-r--r--lib/lsm.h1
-rw-r--r--lib/portability.c162
-rw-r--r--lib/portability.h28
-rwxr-xr-xscripts/make.sh2
-rwxr-xr-xtests/cp.test10
-rw-r--r--tests/kill.test8
-rw-r--r--toys/android/getprop.c119
-rw-r--r--toys/android/setprop.c44
-rw-r--r--toys/android/start.c59
-rw-r--r--toys/lsb/killall.c2
-rw-r--r--toys/other/stat.c14
-rw-r--r--toys/posix/cp.c10
-rw-r--r--toys/posix/kill.c5
21 files changed, 282 insertions, 356 deletions
diff --git a/.config b/.config
index 1a8e3968..108f4dcf 100644
--- a/.config
+++ b/.config
@@ -127,7 +127,6 @@ CONFIG_FSYNC=y
CONFIG_GETCONF=y
CONFIG_GETENFORCE=y
CONFIG_GETFATTR=y
-# CONFIG_GETPROP is not set
# CONFIG_GETTY is not set
CONFIG_GREP=y
# CONFIG_GROUPADD is not set
@@ -263,7 +262,6 @@ CONFIG_SENDEVENT=y
CONFIG_SEQ=y
CONFIG_SETENFORCE=y
CONFIG_SETFATTR=y
-# CONFIG_SETPROP is not set
CONFIG_SETSID=y
CONFIG_SHA1SUM=y
CONFIG_SHA224SUM=y
@@ -281,9 +279,7 @@ CONFIG_SORT_BIG=y
CONFIG_SORT_FLOAT=y
CONFIG_SORT=y
CONFIG_SPLIT=y
-# CONFIG_START is not set
CONFIG_STAT=y
-# CONFIG_STOP is not set
CONFIG_STRINGS=y
CONFIG_STTY=y
# CONFIG_SU is not set
diff --git a/generated/config.h b/generated/config.h
index 86757e21..c5e2cda5 100644
--- a/generated/config.h
+++ b/generated/config.h
@@ -228,8 +228,6 @@
#define USE_GETENFORCE(...) __VA_ARGS__
#define CFG_GETFATTR 1
#define USE_GETFATTR(...) __VA_ARGS__
-#define CFG_GETPROP 0
-#define USE_GETPROP(...)
#define CFG_GETTY 0
#define USE_GETTY(...)
#define CFG_GREP 1
@@ -500,8 +498,6 @@
#define USE_SETENFORCE(...) __VA_ARGS__
#define CFG_SETFATTR 1
#define USE_SETFATTR(...) __VA_ARGS__
-#define CFG_SETPROP 0
-#define USE_SETPROP(...)
#define CFG_SETSID 1
#define USE_SETSID(...) __VA_ARGS__
#define CFG_SHA1SUM 1
@@ -536,12 +532,8 @@
#define USE_SORT(...) __VA_ARGS__
#define CFG_SPLIT 1
#define USE_SPLIT(...) __VA_ARGS__
-#define CFG_START 0
-#define USE_START(...)
#define CFG_STAT 1
#define USE_STAT(...) __VA_ARGS__
-#define CFG_STOP 0
-#define USE_STOP(...)
#define CFG_STRINGS 1
#define USE_STRINGS(...) __VA_ARGS__
#define CFG_STTY 1
diff --git a/generated/flags.h b/generated/flags.h
index c7efb83b..ee070ae8 100644
--- a/generated/flags.h
+++ b/generated/flags.h
@@ -996,15 +996,6 @@
#undef FLAG_only_values
#endif
-// getprop >2Z
-#undef OPTSTR_getprop
-#define OPTSTR_getprop ">2Z"
-#ifdef CLEANUP_getprop
-#undef CLEANUP_getprop
-#undef FOR_getprop
-#undef FLAG_Z
-#endif
-
// getty <2t#<0H:I:l:f:iwnmLh
#undef OPTSTR_getty
#define OPTSTR_getty "<2t#<0H:I:l:f:iwnmLh"
@@ -2442,14 +2433,6 @@
#undef FLAG_h
#endif
-// setprop <2>2
-#undef OPTSTR_setprop
-#define OPTSTR_setprop "<2>2"
-#ifdef CLEANUP_setprop
-#undef CLEANUP_setprop
-#undef FOR_setprop
-#endif
-
// setsid ^<1t ^<1t
#undef OPTSTR_setsid
#define OPTSTR_setsid "^<1t"
@@ -2587,14 +2570,6 @@
#undef FLAG_a
#endif
-// start
-#undef OPTSTR_start
-#define OPTSTR_start 0
-#ifdef CLEANUP_start
-#undef CLEANUP_start
-#undef FOR_start
-#endif
-
// stat <1c:(format)fLt <1c:(format)fLt
#undef OPTSTR_stat
#define OPTSTR_stat "<1c:(format)fLt"
@@ -2607,14 +2582,6 @@
#undef FLAG_c
#endif
-// stop
-#undef OPTSTR_stop
-#define OPTSTR_stop 0
-#ifdef CLEANUP_stop
-#undef CLEANUP_stop
-#undef FOR_stop
-#endif
-
// strings t:an#=4<1fo t:an#=4<1fo
#undef OPTSTR_strings
#define OPTSTR_strings "t:an#=4<1fo"
@@ -4199,13 +4166,6 @@
#define FLAG_only_values (1<<3)
#endif
-#ifdef FOR_getprop
-#ifndef TT
-#define TT this.getprop
-#endif
-#define FLAG_Z (FORCED_FLAG<<0)
-#endif
-
#ifdef FOR_getty
#ifndef TT
#define TT this.getty
@@ -5409,12 +5369,6 @@
#define FLAG_h (1<<3)
#endif
-#ifdef FOR_setprop
-#ifndef TT
-#define TT this.setprop
-#endif
-#endif
-
#ifdef FOR_setsid
#ifndef TT
#define TT this.setsid
@@ -5532,12 +5486,6 @@
#define FLAG_a (1<<2)
#endif
-#ifdef FOR_start
-#ifndef TT
-#define TT this.start
-#endif
-#endif
-
#ifdef FOR_stat
#ifndef TT
#define TT this.stat
@@ -5548,12 +5496,6 @@
#define FLAG_c (1<<3)
#endif
-#ifdef FOR_stop
-#ifndef TT
-#define TT this.stop
-#endif
-#endif
-
#ifdef FOR_strings
#ifndef TT
#define TT this.strings
diff --git a/generated/globals.h b/generated/globals.h
index ac142729..ac945a16 100644
--- a/generated/globals.h
+++ b/generated/globals.h
@@ -1,11 +1,3 @@
-// toys/android/getprop.c
-
-struct getprop_data {
- size_t size;
- char **nv; // name/value pairs: even=name, odd=value
- struct selabel_handle *handle;
-};
-
// toys/android/log.c
struct log_data {
@@ -1378,7 +1370,6 @@ struct xargs_data {
};
extern union global_union {
- struct getprop_data getprop;
struct log_data log;
struct demo_number_data demo_number;
struct hello_data hello;
diff --git a/generated/help.h b/generated/help.h
index 7b99f3fe..5ee5f7d8 100644
--- a/generated/help.h
+++ b/generated/help.h
@@ -34,12 +34,6 @@
#define HELP_toybox "usage: toybox [--long | --help | --version | [command] [arguments...]]\n\nWith no arguments, shows available commands. First argument is\nname of a command to run, followed by any arguments to that command.\n\n--long Show path to each command\n\nTo install command symlinks, try:\n for i in $(/bin/toybox --long); do ln -s /bin/toybox $i; done\n\nMost toybox commands also understand the following arguments:\n\n--help Show command help (only)\n--version Show toybox version (only)\n\nThe filename \"-\" means stdin/stdout, and \"--\" stops argument parsing.\n\nNumerical arguments accept a single letter suffix for\nkilo, mega, giga, tera, peta, and exabytes, plus an additional\n\"d\" to indicate decimal 1000's instead of 1024.\n\nDurations can be decimal fractions and accept minute (\"m\"), hour (\"h\"),\nor day (\"d\") suffixes (so 0.1m = 6s)."
-#define HELP_stop "usage: stop [SERVICE...]\n\nStop the given system service, or netd/surfaceflinger/zygotes."
-
-#define HELP_start "usage: start [SERVICE...]\n\nStarts the given system service, or netd/surfaceflinger/zygotes."
-
-#define HELP_setprop "usage: setprop NAME VALUE\n\nSets an Android system property."
-
#define HELP_setenforce "usage: setenforce [enforcing|permissive|1|0]\n\nSets whether SELinux is enforcing (1) or permissive (0)."
#define HELP_sendevent "usage: sendevent DEVICE TYPE CODE VALUE\n\nSends a Linux input event."
@@ -52,8 +46,6 @@
#define HELP_load_policy "usage: load_policy FILE\n\nLoad the specified SELinux policy file."
-#define HELP_getprop "usage: getprop [NAME [DEFAULT]]\n\nGets an Android system property, or lists them all."
-
#define HELP_getenforce "usage: getenforce\n\nShows whether SELinux is disabled, enforcing, or permissive."
#define HELP_skeleton_alias "usage: skeleton_alias [-dq] [-b NUMBER]\n\nExample of a second command with different arguments in the same source\nfile as the first. This allows shared infrastructure not added to lib/."
diff --git a/generated/newtoys.h b/generated/newtoys.h
index 4a525301..931a6ce2 100644
--- a/generated/newtoys.h
+++ b/generated/newtoys.h
@@ -88,7 +88,6 @@ USE_FTPPUT(OLDTOY(ftpput, ftpget, TOYFLAG_USR|TOYFLAG_BIN))
USE_GETCONF(NEWTOY(getconf, ">2al", TOYFLAG_USR|TOYFLAG_BIN))
USE_GETENFORCE(NEWTOY(getenforce, ">0", TOYFLAG_USR|TOYFLAG_SBIN))
USE_GETFATTR(NEWTOY(getfattr, "(only-values)dhn:", TOYFLAG_USR|TOYFLAG_BIN))
-USE_GETPROP(NEWTOY(getprop, ">2Z", TOYFLAG_USR|TOYFLAG_SBIN))
USE_GETTY(NEWTOY(getty, "<2t#<0H:I:l:f:iwnmLh",TOYFLAG_SBIN))
USE_GREP(NEWTOY(grep, "(line-buffered)(color):;(exclude-dir)*S(exclude)*M(include)*ZzEFHIab(byte-offset)h(no-filename)ino(only-matching)rsvwcl(files-with-matches)q(quiet)(silent)e*f*C#B#A#m#x[!wx][!EFw]", TOYFLAG_BIN|TOYFLAG_ARGFAIL(2)))
USE_GROUPADD(NEWTOY(groupadd, "<1>2g#<0S", TOYFLAG_NEEDROOT|TOYFLAG_SBIN))
@@ -217,7 +216,6 @@ USE_SENDEVENT(NEWTOY(sendevent, "<4>4", TOYFLAG_USR|TOYFLAG_SBIN))
USE_SEQ(NEWTOY(seq, "<1>3?f:s:w[!fw]", TOYFLAG_USR|TOYFLAG_BIN))
USE_SETENFORCE(NEWTOY(setenforce, "<1>1", TOYFLAG_USR|TOYFLAG_SBIN))
USE_SETFATTR(NEWTOY(setfattr, "hn:|v:x:|[!xv]", TOYFLAG_USR|TOYFLAG_BIN))
-USE_SETPROP(NEWTOY(setprop, "<2>2", TOYFLAG_USR|TOYFLAG_SBIN))
USE_SETSID(NEWTOY(setsid, "^<1t", TOYFLAG_USR|TOYFLAG_BIN))
USE_SH(NEWTOY(sh, "c:i", TOYFLAG_BIN))
USE_SHA1SUM(NEWTOY(sha1sum, "bc(check)s(status)[!bc]", TOYFLAG_USR|TOYFLAG_BIN))
@@ -232,9 +230,7 @@ USE_SLEEP(NEWTOY(sleep, "<1", TOYFLAG_BIN))
USE_SNTP(NEWTOY(sntp, "M:m:Sp:asdDqr#<4>17=10[!as]", TOYFLAG_USR|TOYFLAG_BIN))
USE_SORT(NEWTOY(sort, USE_SORT_FLOAT("g")"S:T:m" "o:k*t:" "xVbMcszdfirun", TOYFLAG_USR|TOYFLAG_BIN|TOYFLAG_ARGFAIL(2)))
USE_SPLIT(NEWTOY(split, ">2a#<1=2>9b#<1l#<1[!bl]", TOYFLAG_USR|TOYFLAG_BIN))
-USE_START(NEWTOY(start, "", TOYFLAG_USR|TOYFLAG_SBIN))
USE_STAT(NEWTOY(stat, "<1c:(format)fLt", TOYFLAG_BIN))
-USE_STOP(NEWTOY(stop, "", TOYFLAG_USR|TOYFLAG_SBIN))
USE_STRINGS(NEWTOY(strings, "t:an#=4<1fo", TOYFLAG_USR|TOYFLAG_BIN))
USE_STTY(NEWTOY(stty, "?aF:g[!ag]", TOYFLAG_BIN))
USE_SU(NEWTOY(su, "^lmpu:g:c:s:[!lmp]", TOYFLAG_BIN|TOYFLAG_ROOTONLY))
diff --git a/lib/lib.c b/lib/lib.c
index ffb24f65..17af3c35 100644
--- a/lib/lib.c
+++ b/lib/lib.c
@@ -454,6 +454,16 @@ int strstart(char **a, char *b)
return i;
}
+// If *a starts with b, advance *a past it and return 1, else return 0;
+int strcasestart(char **a, char *b)
+{
+ int len = strlen(b), i = !strncasecmp(*a, b, len);
+
+ if (i) *a += len;
+
+ return i;
+}
+
// Return how long the file at fd is, if there's any way to determine it.
off_t fdlength(int fd)
{
@@ -843,21 +853,22 @@ struct signame {
#define SIGNIFY(x) {SIG##x, #x}
static struct signame signames[] = {
+ // POSIX
SIGNIFY(ABRT), SIGNIFY(ALRM), SIGNIFY(BUS),
SIGNIFY(FPE), SIGNIFY(HUP), SIGNIFY(ILL), SIGNIFY(INT), SIGNIFY(KILL),
SIGNIFY(PIPE), SIGNIFY(QUIT), SIGNIFY(SEGV), SIGNIFY(TERM),
SIGNIFY(USR1), SIGNIFY(USR2), SIGNIFY(SYS), SIGNIFY(TRAP),
SIGNIFY(VTALRM), SIGNIFY(XCPU), SIGNIFY(XFSZ),
+ // Non-POSIX terminal signals
+ SIGNIFY(STKFLT), SIGNIFY(PROF), SIGNIFY(POLL), SIGNIFY(IO), SIGNIFY(PWR),
- // Start of non-terminal signals
-
+ // POSIX non-terminal signals
SIGNIFY(CHLD), SIGNIFY(CONT), SIGNIFY(STOP), SIGNIFY(TSTP),
- SIGNIFY(TTIN), SIGNIFY(TTOU), SIGNIFY(URG)
+ SIGNIFY(TTIN), SIGNIFY(TTOU), SIGNIFY(URG),
+ // Non-POSIX non-terminal signals
+ SIGNIFY(WINCH),
};
-// not in posix: SIGNIFY(STKFLT), SIGNIFY(WINCH), SIGNIFY(IO), SIGNIFY(PWR)
-// obsolete: SIGNIFY(PROF) SIGNIFY(POLL)
-
// Handler that sets toys.signal, and writes to toys.signalfd if set
void generic_signal(int sig)
{
@@ -898,22 +909,35 @@ void sigatexit(void *handler)
}
}
-// Convert name to signal number. If name == NULL print names.
+// Convert a string like "9", "KILL", "SIGHUP", or "SIGRTMIN+2" to a number.
int sig_to_num(char *pidstr)
{
- int i;
+ int i, offset;
+ char *s;
- if (pidstr) {
- char *s;
+ // Numeric?
+ i = estrtol(pidstr, &s, 10);
+ if (!errno && !*s) return i;
- i = estrtol(pidstr, &s, 10);
- if (!errno && !*s) return i;
+ // Skip leading "SIG".
+ strcasestart(&pidstr, "sig");
- if (!strncasecmp(pidstr, "sig", 3)) pidstr+=3;
- }
+ // Named signal?
for (i=0; i<ARRAY_LEN(signames); i++)
- if (!pidstr) xputs(signames[i].name);
- else if (!strcasecmp(pidstr, signames[i].name)) return signames[i].num;
+ if (!strcasecmp(pidstr, signames[i].name)) return signames[i].num;
+
+ // Real-time signal?
+ if (strcasestart(&pidstr, "rtmin")) i = SIGRTMIN;
+ else if (strcasestart(&pidstr, "rtmax")) i = SIGRTMAX;
+ else return -1;
+ // No offset?
+ if (!*pidstr) return i;
+ // We allow any offset that's still a real-time signal: SIGRTMIN+20 is fine.
+ // Others are more restrictive, only accepting what they show with -l.
+ offset = estrtol(pidstr, &s, 10);
+ if (errno || *s) return -1;
+ i += offset;
+ if (i >= SIGRTMIN && i <= SIGRTMAX) return i;
return -1;
}
@@ -922,11 +946,36 @@ char *num_to_sig(int sig)
{
int i;
+ // A named signal?
for (i=0; i<ARRAY_LEN(signames); i++)
if (signames[i].num == sig) return signames[i].name;
+
+ // A real-time signal?
+ if (sig == SIGRTMIN) return "RTMIN";
+ if (sig == SIGRTMAX) return "RTMAX";
+ if (sig > SIGRTMIN && sig < SIGRTMAX) {
+ if (sig-SIGRTMIN <= SIGRTMAX-sig) sprintf(libbuf, "RTMIN+%d", sig-SIGRTMIN);
+ else sprintf(libbuf, "RTMAX-%d", SIGRTMAX-sig);
+ return libbuf;
+ }
return NULL;
}
+// Output a nicely formatted 80-column table of all the signals.
+void list_signals()
+{
+ int i = 0, count = 0;
+ char *name;
+
+ for (; i<=SIGRTMAX; i++) {
+ if ((name = num_to_sig(i))) {
+ printf("%2d) SIG%-9s", i, name);
+ if (++count % 5 == 0) putchar('\n');
+ }
+ }
+ putchar('\n');
+}
+
// premute mode bits based on posix mode strings.
mode_t string_to_mode(char *modestr, mode_t mode)
{
diff --git a/lib/lib.h b/lib/lib.h
index 080c533f..7f79bdb8 100644
--- a/lib/lib.h
+++ b/lib/lib.h
@@ -229,6 +229,7 @@ char *chomp(char *s);
int unescape(char c);
char *strend(char *str, char *suffix);
int strstart(char **a, char *b);
+int strcasestart(char **a, char *b);
off_t fdlength(int fd);
void loopfiles_rw(char **argv, int flags, int permissions,
void (*function)(int fd, char *name));
@@ -388,6 +389,7 @@ void generic_signal(int signal);
void exit_signal(int signal);
void sigatexit(void *handler);
int sig_to_num(char *pidstr);
+void list_signals();
char *num_to_sig(int sig);
mode_t string_to_mode(char *mode_str, mode_t base);
diff --git a/lib/lsm.h b/lib/lsm.h
index 556700ce..88bf3470 100644
--- a/lib/lsm.h
+++ b/lib/lsm.h
@@ -24,7 +24,6 @@
#ifndef XATTR_NAME_SMACK
#define XATTR_NAME_SMACK 0
#endif
-//ssize_t fgetxattr (int fd, char *name, void *value, size_t size);
#define smack_smackfs_path(...) (-1)
#define smack_new_label_from_self(...) (-1)
#define smack_new_label_from_path(...) (-1)
diff --git a/lib/portability.c b/lib/portability.c
index 7f81685f..088b90e1 100644
--- a/lib/portability.c
+++ b/lib/portability.c
@@ -46,11 +46,47 @@ int xgetrandom(void *buf, unsigned buflen, unsigned flags)
return 1;
}
-// Get a linked list of mount points, with stat information.
+// Get list of mounted filesystems, including stat and statvfs info.
+// Returns a reversed list, which is good for finding overmounts and such.
+
#if defined(__APPLE__) || defined(__FreeBSD__)
-// Not implemented for macOS.
-// See <sys/mount.h>'s getmntinfo(3) for the BSD API.
+#include <sys/mount.h>
+
+struct mtab_list *xgetmountlist(char *path)
+{
+ struct mtab_list *mtlist = 0, *mt;
+ struct statfs *entries;
+ int i, count;
+
+ if (path) error_exit("xgetmountlist");
+ if ((count = getmntinfo(&entries, 0)) == 0) perror_exit("getmntinfo");
+
+ // The "test" part of the loop is done before the first time through and
+ // again after each "increment", so putting the actual load there avoids
+ // duplicating it. If the load was NULL, the loop stops.
+
+ for (i = 0; i < count; ++i) {
+ struct statfs *me = &entries[i];
+
+ mt = xzalloc(sizeof(struct mtab_list) + strlen(me->f_fstypename) +
+ strlen(me->f_mntonname) + strlen(me->f_mntfromname) + strlen("") + 4);
+ dlist_add_nomalloc((void *)&mtlist, (void *)mt);
+
+ // Collect details about mounted filesystem.
+ // Don't report errors, just leave data zeroed.
+ stat(me->f_mntonname, &(mt->stat));
+ statvfs(me->f_mntonname, &(mt->statvfs));
+
+ // Remember information from struct statfs.
+ mt->dir = stpcpy(mt->type, me->f_fstypename)+1;
+ mt->device = stpcpy(mt->dir, me->f_mntonname)+1;
+ mt->opts = stpcpy(mt->device, me->f_mntfromname)+1;
+ strcpy(mt->opts, ""); /* TODO: reverse from f_flags? */
+ }
+
+ return mtlist;
+}
#else
@@ -110,9 +146,6 @@ int mountlist_istype(struct mtab_list *ml, char *typelist)
return !skip;
}
-// Get list of mounted filesystems, including stat and statvfs info.
-// Returns a reversed list, which is good for finding overmounts and such.
-
struct mtab_list *xgetmountlist(char *path)
{
struct mtab_list *mtlist = 0, *mt;
@@ -247,3 +280,120 @@ int xnotify_wait(struct xnotify *not, char **path)
}
#endif
+
+#ifdef __APPLE__
+
+ssize_t xattr_get(const char *path, const char *name, void *value, size_t size)
+{
+ return getxattr(path, name, value, size, 0, 0);
+}
+
+ssize_t xattr_lget(const char *path, const char *name, void *value, size_t size)
+{
+ return getxattr(path, name, value, size, 0, XATTR_NOFOLLOW);
+}
+
+ssize_t xattr_fget(int fd, const char *name, void *value, size_t size)
+{
+ return fgetxattr(fd, name, value, size, 0, 0);
+}
+
+ssize_t xattr_list(const char *path, char *list, size_t size)
+{
+ return listxattr(path, list, size, 0);
+}
+
+ssize_t xattr_llist(const char *path, char *list, size_t size)
+{
+ return listxattr(path, list, size, XATTR_NOFOLLOW);
+}
+
+ssize_t xattr_flist(int fd, char *list, size_t size)
+{
+ return flistxattr(fd, list, size, 0);
+}
+
+ssize_t xattr_set(const char* path, const char* name,
+ const void* value, size_t size, int flags)
+{
+ return setxattr(path, name, value, size, 0, flags);
+}
+
+ssize_t xattr_lset(const char* path, const char* name,
+ const void* value, size_t size, int flags)
+{
+ return setxattr(path, name, value, size, 0, flags | XATTR_NOFOLLOW);
+}
+
+ssize_t xattr_fset(int fd, const char* name,
+ const void* value, size_t size, int flags)
+{
+ return fsetxattr(fd, name, value, size, 0, flags);
+}
+
+#else
+
+ssize_t xattr_get(const char *path, const char *name, void *value, size_t size)
+{
+ return getxattr(path, name, value, size);
+}
+
+ssize_t xattr_lget(const char *path, const char *name, void *value, size_t size)
+{
+ return lgetxattr(path, name, value, size);
+}
+
+ssize_t xattr_fget(int fd, const char *name, void *value, size_t size)
+{
+ return fgetxattr(fd, name, value, size);
+}
+
+ssize_t xattr_list(const char *path, char *list, size_t size)
+{
+ return listxattr(path, list, size);
+}
+
+ssize_t xattr_llist(const char *path, char *list, size_t size)
+{
+ return llistxattr(path, list, size);
+}
+
+ssize_t xattr_flist(int fd, char *list, size_t size)
+{
+ return flistxattr(fd, list, size);
+}
+
+ssize_t xattr_set(const char* path, const char* name,
+ const void* value, size_t size, int flags)
+{
+ return setxattr(path, name, value, size, flags);
+}
+
+ssize_t xattr_lset(const char* path, const char* name,
+ const void* value, size_t size, int flags)
+{
+ return lsetxattr(path, name, value, size, flags);
+}
+
+ssize_t xattr_fset(int fd, const char* name,
+ const void* value, size_t size, int flags)
+{
+ return fsetxattr(fd, name, value, size, flags);
+}
+
+
+#endif
+
+#ifdef __APPLE__
+// In the absence of a mknodat system call, fchdir to dirfd and back
+// around a regular mknod call...
+int mknodat(int dirfd, const char *path, mode_t mode, dev_t dev)
+{
+ int old_dirfd = open(".", O_RDONLY), result;
+
+ if (old_dirfd == -1 || fchdir(dirfd) == -1) return -1;
+ result = mknod(path, mode, dev);
+ if (fchdir(old_dirfd) == -1) perror_exit("mknodat couldn't return");
+ return result;
+}
+#endif
diff --git a/lib/portability.h b/lib/portability.h
index f5f8352a..c955eddf 100644
--- a/lib/portability.h
+++ b/lib/portability.h
@@ -186,8 +186,24 @@ char *strcasestr(const char *haystack, const char *needle);
#endif
#endif
-#ifndef __FreeBSD__
+#if defined(__APPLE__) || defined(__linux__)
+// Linux and macOS has both have getxattr and friends in <sys/xattr.h>, but
+// they aren't compatible.
#include <sys/xattr.h>
+ssize_t xattr_get(const char *, const char *, void *, size_t);
+ssize_t xattr_lget(const char *, const char *, void *, size_t);
+ssize_t xattr_fget(int fd, const char *, void *, size_t);
+ssize_t xattr_list(const char *, char *, size_t);
+ssize_t xattr_llist(const char *, char *, size_t);
+ssize_t xattr_flist(int, char *, size_t);
+ssize_t xattr_set(const char*, const char*, const void*, size_t, int);
+ssize_t xattr_lset(const char*, const char*, const void*, size_t, int);
+ssize_t xattr_fset(int, const char*, const void*, size_t, int);
+#endif
+
+// macOS doesn't have mknodat, but we can fake it.
+#ifdef __APPLE__
+int mknodat(int, const char*, mode_t, dev_t);
#endif
// Android is missing some headers and functions
@@ -251,7 +267,6 @@ pid_t xfork(void);
// use toybox before they're ready to switch to host bionic.
#ifdef __BIONIC__
#include <android/log.h>
-#include <sys/system_properties.h>
#else
typedef enum android_LogPriority {
ANDROID_LOG_UNKNOWN = 0,
@@ -268,11 +283,6 @@ static inline int __android_log_write(int pri, const char *tag, const char *msg)
{
return -1;
}
-#define PROP_VALUE_MAX 92
-static inline int __system_property_set(const char *key, const char *value)
-{
- return -1;
-}
#endif
// libprocessgroup is an Android platform library not included in the NDK.
@@ -318,3 +328,7 @@ struct xnotify {
struct xnotify *xnotify_init(int max);
int xnotify_add(struct xnotify *not, int fd, char *path);
int xnotify_wait(struct xnotify *not, char **path);
+
+#ifdef __APPLE__
+#define f_frsize f_iosize
+#endif
diff --git a/scripts/make.sh b/scripts/make.sh
index bd550b91..6649999e 100755
--- a/scripts/make.sh
+++ b/scripts/make.sh
@@ -297,7 +297,7 @@ do
# $LIBFILES doesn't need to be rebuilt if older than .config, $TOYFILES does
# ($TOYFILES contents can depend on CONFIG symbols, lib/*.c never should.)
- [ "$OUT" -nt "$i" ] && [ -z "$CLICK" -o "$OUT" -ot "$KCONFIG_CONFIG" ] &&
+ [ "$OUT" -nt "$i" ] && [ -z "$CLICK" -o "$OUT" -nt "$KCONFIG_CONFIG" ] &&
continue
do_loudly $BUILD -c $i -o $OUT &
diff --git a/tests/cp.test b/tests/cp.test
index a720d1f5..c7d445c0 100755
--- a/tests/cp.test
+++ b/tests/cp.test
@@ -89,6 +89,15 @@ testing "-r dir1/* dir2" \
"cp -r one/* dir2 && diff -r one dir2 && echo yes" "yes\n" "" ""
rm -rf one dir dir2
+mkdir one; touch one/two; cp one/two one/three
+cp -r one/ one_ # Succeeds twice in a row
+testing "-r dir/." "cp -r one/. one_ && echo yes" "yes\n" "" ""
+rm -rf one one_
+mkdir one; touch one/two; ln -s two one/three
+cp -r one/ one_ # First time ok, but second will fail with "File exists"
+testing "-r dir/. symlink child" "cp -r one/. one_ && echo yes" "yes\n" "" ""
+rm -rf one one_
+
touch walrus
chmod 644 walrus
ln -s walrus woot
@@ -99,7 +108,6 @@ testing "symlink dest permissions" "cp woot carpenter && stat -c %A carpenter" \
# cp -r ../source destdir
# cp -r one/two/three missing
# cp -r one/two/three two
-# mkdir one; touch one/two; ln -s two one/three
# cp file1 file2 dir
# cp file1 missing file2 -> dir
diff --git a/tests/kill.test b/tests/kill.test
new file mode 100644
index 00000000..a91dd55a
--- /dev/null
+++ b/tests/kill.test
@@ -0,0 +1,8 @@
+#!/bin/bash
+
+[ -f testing.sh ] && . testing.sh
+
+#testing "name" "command" "result" "infile" "stdin"
+
+testing "-l HUP" "kill -l HUP" "1\n" "" ""
+testing "-l 1" "kill -l 1" "HUP\n" "" ""
diff --git a/toys/android/getprop.c b/toys/android/getprop.c
deleted file mode 100644
index 51ef7f6b..00000000
--- a/toys/android/getprop.c
+++ /dev/null
@@ -1,119 +0,0 @@
-/* getprop.c - Get an Android system property
- *
- * Copyright 2015 The Android Open Source Project
-
-USE_GETPROP(NEWTOY(getprop, ">2Z", TOYFLAG_USR|TOYFLAG_SBIN))
-
-config GETPROP
- bool "getprop"
- default y
- depends on TOYBOX_ON_ANDROID && TOYBOX_SELINUX
- help
- usage: getprop [NAME [DEFAULT]]
-
- Gets an Android system property, or lists them all.
-*/
-
-#define FOR_getprop
-#include "toys.h"
-
-#include <sys/system_properties.h>
-
-#include <selinux/android.h>
-#include <selinux/label.h>
-#include <selinux/selinux.h>
-
-GLOBALS(
- size_t size;
- char **nv; // name/value pairs: even=name, odd=value
- struct selabel_handle *handle;
-)
-
-static char *get_property_context(const char *property)
-{
- char *context = NULL;
-
- if (selabel_lookup(TT.handle, &context, property, 1)) {
- perror_exit("unable to lookup label for \"%s\"", property);
- }
- return context;
-}
-
-static void read_callback(void *unused, const char *name, const char *value,
- unsigned serial)
-{
- if (!(TT.size&31)) TT.nv = xrealloc(TT.nv, (TT.size+32)*2*sizeof(char *));
-
- TT.nv[2*TT.size] = xstrdup((char *)name);
- if (toys.optflags & FLAG_Z) {
- TT.nv[1+2*TT.size++] = get_property_context(name);
- } else {
- TT.nv[1+2*TT.size++] = xstrdup((char *)value);
- }
-}
-
-static void add_property(const prop_info *pi, void *unused)
-{
- __system_property_read_callback(pi, read_callback, NULL);
-}
-
-static void print_callback(void *unused, const char *unused_name, const char *value,
- unsigned unused_serial)
-{
- puts(value);
-}
-
-// Needed to supress extraneous "Loaded property_contexts from" message
-static int selinux_log_callback_local(int type, const char *fmt, ...)
-{
- va_list ap;
-
- if (type == SELINUX_INFO) return 0;
- va_start(ap, fmt);
- verror_msg((char *)fmt, 0, ap);
- va_end(ap);
- return 0;
-}
-
-void getprop_main(void)
-{
- if (toys.optflags & FLAG_Z) {
- union selinux_callback cb;
-
- cb.func_log = selinux_log_callback_local;
- selinux_set_callback(SELINUX_CB_LOG, cb);
- TT.handle = selinux_android_prop_context_handle();
- if (!TT.handle) error_exit("unable to get selinux property context handle");
- }
-
- if (*toys.optargs) {
- if (toys.optflags & FLAG_Z) {
- char *context = get_property_context(*toys.optargs);
-
- puts(context);
- if (CFG_TOYBOX_FREE) free(context);
- } else {
- const prop_info* pi = __system_property_find(*toys.optargs);
- if (pi == NULL) {
- puts(toys.optargs[1] ? toys.optargs[1] : "");
- } else {
- __system_property_read_callback(pi, print_callback, NULL);
- }
- }
- } else {
- size_t i;
-
- if (__system_property_foreach(add_property, NULL))
- error_exit("property_list");
- qsort(TT.nv, TT.size, 2*sizeof(char *), qstrcmp);
- for (i = 0; i<TT.size; i++) printf("[%s]: [%s]\n", TT.nv[i*2],TT.nv[1+i*2]);
- if (CFG_TOYBOX_FREE) {
- for (i = 0; i<TT.size; i++) {
- free(TT.nv[i*2]);
- free(TT.nv[1+i*2]);
- }
- free(TT.nv);
- }
- }
- if (CFG_TOYBOX_FREE && (toys.optflags & FLAG_Z)) selabel_close(TT.handle);
-}
diff --git a/toys/android/setprop.c b/toys/android/setprop.c
deleted file mode 100644
index cda34a5d..00000000
--- a/toys/android/setprop.c
+++ /dev/null
@@ -1,44 +0,0 @@
-/* setprop.c - Set an Android system property
- *
- * Copyright 2015 The Android Open Source Project
-
-USE_SETPROP(NEWTOY(setprop, "<2>2", TOYFLAG_USR|TOYFLAG_SBIN))
-
-config SETPROP
- bool "setprop"
- default y
- depends on TOYBOX_ON_ANDROID
- help
- usage: setprop NAME VALUE
-
- Sets an Android system property.
-*/
-
-#define FOR_setprop
-#include "toys.h"
-
-void setprop_main(void)
-{
- char *name = toys.optargs[0], *value = toys.optargs[1];
- char *p;
- size_t name_len = strlen(name), value_len = strlen(value);
-
- // property_set doesn't tell us why it failed, and actually can't
- // recognize most failures (because it doesn't wait for init), so
- // we duplicate all of init's checks here to help the user.
-
- if (value_len >= PROP_VALUE_MAX && !strncmp(value, "ro.", 3))
- error_exit("value '%s' too long; try '%.*s'",
- value, PROP_VALUE_MAX - 1, value);
-
- if (*name == '.' || name[name_len - 1] == '.')
- error_exit("property names must not start or end with '.'");
- if (strstr(name, ".."))
- error_exit("'..' is not allowed in a property name");
- for (p = name; *p; ++p)
- if (!isalnum(*p) && !strchr(":@_.-", *p))
- error_exit("invalid character '%c' in name '%s'", *p, name);
-
- if (__system_property_set(name, value))
- error_msg("failed to set property '%s' to '%s'", name, value);
-}
diff --git a/toys/android/start.c b/toys/android/start.c
deleted file mode 100644
index 5df847a9..00000000
--- a/toys/android/start.c
+++ /dev/null
@@ -1,59 +0,0 @@
-/* start.c - Start/stop system services.
- *
- * Copyright 2016 The Android Open Source Project
-
-USE_START(NEWTOY(start, "", TOYFLAG_USR|TOYFLAG_SBIN))
-USE_STOP(NEWTOY(stop, "", TOYFLAG_USR|TOYFLAG_SBIN))
-
-config START
- bool "start"
- depends on TOYBOX_ON_ANDROID
- default y
- help
- usage: start [SERVICE...]
-
- Starts the given system service, or netd/surfaceflinger/zygotes.
-
-config STOP
- bool "stop"
- depends on TOYBOX_ON_ANDROID
- default y
- help
- usage: stop [SERVICE...]
-
- Stop the given system service, or netd/surfaceflinger/zygotes.
-*/
-
-#define FOR_start
-#include "toys.h"
-
-static void start_stop(int start)
-{
- char *property = start ? "ctl.start" : "ctl.stop";
- // null terminated in both directions
- char *services[] = {0,"netd","surfaceflinger","zygote","zygote_secondary",0},
- **ss = toys.optargs;
- int direction = 1;
-
- if (getuid()) error_exit("must be root");
-
- if (!*ss) {
- // If we don't have optargs, iterate through services forward/backward.
- ss = services+1;
- if (!start) ss = services+ARRAY_LEN(services)-2, direction = -1;
- }
-
- for (; *ss; ss += direction)
- if (__system_property_set(property, *ss))
- error_exit("failed to set property '%s' to '%s'", property, *ss);
-}
-
-void start_main(void)
-{
- start_stop(1);
-}
-
-void stop_main(void)
-{
- start_stop(0);
-}
diff --git a/toys/lsb/killall.c b/toys/lsb/killall.c
index 8870618b..119e01fa 100644
--- a/toys/lsb/killall.c
+++ b/toys/lsb/killall.c
@@ -68,7 +68,7 @@ void killall_main(void)
TT.signum = SIGTERM;
if (toys.optflags & FLAG_l) {
- sig_to_num(NULL);
+ list_signals();
return;
}
diff --git a/toys/other/stat.c b/toys/other/stat.c
index 054e2ee7..c4c1bf42 100644
--- a/toys/other/stat.c
+++ b/toys/other/stat.c
@@ -141,8 +141,15 @@ static void print_statfs(char type) {
else if (type == 'c') out('u', statfs->f_files);
else if (type == 'd') out('u', statfs->f_ffree);
else if (type == 'f') out('u', statfs->f_bfree);
- else if (type == 'l') out('d', statfs->f_namelen);
- else if (type == 't') out('x', statfs->f_type);
+ else if (type == 'l') {
+#ifdef __APPLE__
+ // TODO: move this into portability.c somehow, or just use this everywhere?
+ // (glibc and bionic will just re-do the statfs and return f_namelen.)
+ out('d', pathconf(TT.file, _PC_NAME_MAX));
+#else
+ out('d', statfs->f_namelen);
+#endif
+ } else if (type == 't') out('x', statfs->f_type);
else if (type == 'T') {
char *s = "unknown";
struct {unsigned num; char *name;} nn[] = {
@@ -161,9 +168,10 @@ static void print_statfs(char type) {
if (nn[i].num == statfs->f_type) s = nn[i].name;
strout(s);
} else if (type == 'i') {
+ int *val = (int *) &statfs->f_fsid;
char buf[32];
- sprintf(buf, "%08x%08x", statfs->f_fsid.__val[0], statfs->f_fsid.__val[1]);
+ sprintf(buf, "%08x%08x", val[0], val[1]);
strout(buf);
} else if (type == 's') out('d', statfs->f_frsize);
else if (type == 'S') out('d', statfs->f_bsize);
diff --git a/toys/posix/cp.c b/toys/posix/cp.c
index 751a718c..e37b360d 100644
--- a/toys/posix/cp.c
+++ b/toys/posix/cp.c
@@ -278,20 +278,20 @@ static int cp_node(struct dirtree *try)
// We only copy xattrs for files because there's no flistxattrat()
if (TT.pflags&(_CP_xattr|_CP_context)) {
- ssize_t listlen = flistxattr(fdin, 0, 0), len;
+ ssize_t listlen = xattr_flist(fdin, 0, 0), len;
char *name, *value, *list;
if (listlen>0) {
list = xmalloc(listlen);
- flistxattr(fdin, list, listlen);
+ xattr_flist(fdin, list, listlen);
list[listlen-1] = 0; // I do not trust this API.
for (name = list; name-list < listlen; name += strlen(name)+1) {
if (!(TT.pflags&_CP_xattr) && strncmp(name, "security.", 9))
continue;
- if ((len = fgetxattr(fdin, name, 0, 0))>0) {
+ if ((len = xattr_fget(fdin, name, 0, 0))>0) {
value = xmalloc(len);
- if (len == fgetxattr(fdin, name, value, len))
- if (fsetxattr(fdout, name, value, len, 0))
+ if (len == xattr_fget(fdin, name, value, len))
+ if (xattr_fset(fdout, name, value, len, 0))
perror_msg("%s setxattr(%s=%s)", catch, name, value);
free(value);
}
diff --git a/toys/posix/kill.c b/toys/posix/kill.c
index f8e86b67..ee68980b 100644
--- a/toys/posix/kill.c
+++ b/toys/posix/kill.c
@@ -67,8 +67,9 @@ void kill_main(void)
char *s = NULL;
if (signum>=0) s = num_to_sig(signum&127);
- puts(s ? s : "UNKNOWN");
- } else sig_to_num(NULL);
+ if (isdigit(**args)) puts(s ? s : "UNKNOWN");
+ else printf("%d\n", signum);
+ } else list_signals();
return;
}