aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/lsm.h1
-rw-r--r--lib/portability.c162
-rw-r--r--lib/portability.h22
-rw-r--r--toys/other/stat.c14
-rw-r--r--toys/posix/cp.c10
5 files changed, 193 insertions, 16 deletions
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 f57eb026..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
@@ -312,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/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);
}