diff options
-rw-r--r-- | lib/lsm.h | 1 | ||||
-rw-r--r-- | lib/portability.c | 162 | ||||
-rw-r--r-- | lib/portability.h | 22 | ||||
-rw-r--r-- | toys/other/stat.c | 14 | ||||
-rw-r--r-- | toys/posix/cp.c | 10 |
5 files changed, 193 insertions, 16 deletions
@@ -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); } |