10f66f451Sopenharmony_ci/* portability.c - code to workaround the deficiencies of various platforms. 20f66f451Sopenharmony_ci * 30f66f451Sopenharmony_ci * Copyright 2012 Rob Landley <rob@landley.net> 40f66f451Sopenharmony_ci * Copyright 2012 Georgi Chorbadzhiyski <gf@unixsol.org> 50f66f451Sopenharmony_ci */ 60f66f451Sopenharmony_ci 70f66f451Sopenharmony_ci#include "toys.h" 80f66f451Sopenharmony_ci 90f66f451Sopenharmony_ci// We can't fork() on nommu systems, and vfork() requires an exec() or exit() 100f66f451Sopenharmony_ci// before resuming the parent (because they share a heap until then). And no, 110f66f451Sopenharmony_ci// we can't implement our own clone() call that does the equivalent of fork() 120f66f451Sopenharmony_ci// because nommu heaps use physical addresses so if we copy the heap all our 130f66f451Sopenharmony_ci// pointers are wrong. (You need an mmu in order to map two heaps to the same 140f66f451Sopenharmony_ci// address range without interfering with each other.) In the absence of 150f66f451Sopenharmony_ci// a portable way to tell malloc() to start a new heap without freeing the old 160f66f451Sopenharmony_ci// one, you pretty much need the exec().) 170f66f451Sopenharmony_ci 180f66f451Sopenharmony_ci// So we exec ourselves (via /proc/self/exe, if anybody knows a way to 190f66f451Sopenharmony_ci// re-exec self without depending on the filesystem, I'm all ears), 200f66f451Sopenharmony_ci// and use the arguments to signal reentry. 210f66f451Sopenharmony_ci 220f66f451Sopenharmony_ci#if CFG_TOYBOX_FORK 230f66f451Sopenharmony_cipid_t xfork(void) 240f66f451Sopenharmony_ci{ 250f66f451Sopenharmony_ci pid_t pid = fork(); 260f66f451Sopenharmony_ci 270f66f451Sopenharmony_ci if (pid < 0) perror_exit("fork"); 280f66f451Sopenharmony_ci 290f66f451Sopenharmony_ci return pid; 300f66f451Sopenharmony_ci} 310f66f451Sopenharmony_ci#endif 320f66f451Sopenharmony_ci 330f66f451Sopenharmony_ciint xgetrandom(void *buf, unsigned buflen, unsigned flags) 340f66f451Sopenharmony_ci{ 350f66f451Sopenharmony_ci int fd; 360f66f451Sopenharmony_ci 370f66f451Sopenharmony_ci#if CFG_TOYBOX_GETRANDOM 380f66f451Sopenharmony_ci if (buflen == getrandom(buf, buflen, flags&~WARN_ONLY)) return 1; 390f66f451Sopenharmony_ci if (errno!=ENOSYS && !(flags&WARN_ONLY)) perror_exit("getrandom"); 400f66f451Sopenharmony_ci#endif 410f66f451Sopenharmony_ci fd = xopen(flags ? "/dev/random" : "/dev/urandom",O_RDONLY|(flags&WARN_ONLY)); 420f66f451Sopenharmony_ci if (fd == -1) return 0; 430f66f451Sopenharmony_ci xreadall(fd, buf, buflen); 440f66f451Sopenharmony_ci close(fd); 450f66f451Sopenharmony_ci 460f66f451Sopenharmony_ci return 1; 470f66f451Sopenharmony_ci} 480f66f451Sopenharmony_ci 490f66f451Sopenharmony_ci// Get list of mounted filesystems, including stat and statvfs info. 500f66f451Sopenharmony_ci// Returns a reversed list, which is good for finding overmounts and such. 510f66f451Sopenharmony_ci 520f66f451Sopenharmony_ci#if defined(__APPLE__) || defined(__FreeBSD__) 530f66f451Sopenharmony_ci 540f66f451Sopenharmony_ci#include <sys/mount.h> 550f66f451Sopenharmony_ci 560f66f451Sopenharmony_cistruct mtab_list *xgetmountlist(char *path) 570f66f451Sopenharmony_ci{ 580f66f451Sopenharmony_ci struct mtab_list *mtlist = 0, *mt; 590f66f451Sopenharmony_ci struct statfs *entries; 600f66f451Sopenharmony_ci int i, count; 610f66f451Sopenharmony_ci 620f66f451Sopenharmony_ci if (path) error_exit("xgetmountlist"); 630f66f451Sopenharmony_ci if ((count = getmntinfo(&entries, 0)) == 0) perror_exit("getmntinfo"); 640f66f451Sopenharmony_ci 650f66f451Sopenharmony_ci // The "test" part of the loop is done before the first time through and 660f66f451Sopenharmony_ci // again after each "increment", so putting the actual load there avoids 670f66f451Sopenharmony_ci // duplicating it. If the load was NULL, the loop stops. 680f66f451Sopenharmony_ci 690f66f451Sopenharmony_ci for (i = 0; i < count; ++i) { 700f66f451Sopenharmony_ci struct statfs *me = &entries[i]; 710f66f451Sopenharmony_ci 720f66f451Sopenharmony_ci mt = xzalloc(sizeof(struct mtab_list) + strlen(me->f_fstypename) + 730f66f451Sopenharmony_ci strlen(me->f_mntonname) + strlen(me->f_mntfromname) + strlen("") + 4); 740f66f451Sopenharmony_ci dlist_add_nomalloc((void *)&mtlist, (void *)mt); 750f66f451Sopenharmony_ci 760f66f451Sopenharmony_ci // Collect details about mounted filesystem. 770f66f451Sopenharmony_ci // Don't report errors, just leave data zeroed. 780f66f451Sopenharmony_ci stat(me->f_mntonname, &(mt->stat)); 790f66f451Sopenharmony_ci statvfs(me->f_mntonname, &(mt->statvfs)); 800f66f451Sopenharmony_ci 810f66f451Sopenharmony_ci // Remember information from struct statfs. 820f66f451Sopenharmony_ci mt->dir = stpcpy(mt->type, me->f_fstypename)+1; 830f66f451Sopenharmony_ci mt->device = stpcpy(mt->dir, me->f_mntonname)+1; 840f66f451Sopenharmony_ci mt->opts = stpcpy(mt->device, me->f_mntfromname)+1; 850f66f451Sopenharmony_ci strcpy(mt->opts, ""); /* TODO: reverse from f_flags? */ 860f66f451Sopenharmony_ci } 870f66f451Sopenharmony_ci 880f66f451Sopenharmony_ci return mtlist; 890f66f451Sopenharmony_ci} 900f66f451Sopenharmony_ci 910f66f451Sopenharmony_ci#else 920f66f451Sopenharmony_ci 930f66f451Sopenharmony_ci#include <mntent.h> 940f66f451Sopenharmony_ci 950f66f451Sopenharmony_cistatic void octal_deslash(char *s) 960f66f451Sopenharmony_ci{ 970f66f451Sopenharmony_ci char *o = s; 980f66f451Sopenharmony_ci 990f66f451Sopenharmony_ci while (*s) { 1000f66f451Sopenharmony_ci if (*s == '\\') { 1010f66f451Sopenharmony_ci int i, oct = 0; 1020f66f451Sopenharmony_ci 1030f66f451Sopenharmony_ci for (i = 1; i < 4; i++) { 1040f66f451Sopenharmony_ci if (!isdigit(s[i])) break; 1050f66f451Sopenharmony_ci oct = (oct<<3)+s[i]-'0'; 1060f66f451Sopenharmony_ci } 1070f66f451Sopenharmony_ci if (i == 4) { 1080f66f451Sopenharmony_ci *o++ = oct; 1090f66f451Sopenharmony_ci s += i; 1100f66f451Sopenharmony_ci continue; 1110f66f451Sopenharmony_ci } 1120f66f451Sopenharmony_ci } 1130f66f451Sopenharmony_ci *o++ = *s++; 1140f66f451Sopenharmony_ci } 1150f66f451Sopenharmony_ci 1160f66f451Sopenharmony_ci *o = 0; 1170f66f451Sopenharmony_ci} 1180f66f451Sopenharmony_ci 1190f66f451Sopenharmony_ci// Check if this type matches list. 1200f66f451Sopenharmony_ci// Odd syntax: typelist all yes = if any, typelist all no = if none. 1210f66f451Sopenharmony_ci 1220f66f451Sopenharmony_ciint mountlist_istype(struct mtab_list *ml, char *typelist) 1230f66f451Sopenharmony_ci{ 1240f66f451Sopenharmony_ci int len, skip; 1250f66f451Sopenharmony_ci char *t; 1260f66f451Sopenharmony_ci 1270f66f451Sopenharmony_ci if (!typelist) return 1; 1280f66f451Sopenharmony_ci 1290f66f451Sopenharmony_ci skip = strncmp(typelist, "no", 2); 1300f66f451Sopenharmony_ci 1310f66f451Sopenharmony_ci for (;;) { 1320f66f451Sopenharmony_ci if (!(t = comma_iterate(&typelist, &len))) break; 1330f66f451Sopenharmony_ci if (!skip) { 1340f66f451Sopenharmony_ci // If one -t starts with "no", the rest must too 1350f66f451Sopenharmony_ci if (strncmp(t, "no", 2)) error_exit("bad typelist"); 1360f66f451Sopenharmony_ci if (!strncmp(t+2, ml->type, len-2)) { 1370f66f451Sopenharmony_ci skip = 1; 1380f66f451Sopenharmony_ci break; 1390f66f451Sopenharmony_ci } 1400f66f451Sopenharmony_ci } else if (!strncmp(t, ml->type, len) && !ml->type[len]) { 1410f66f451Sopenharmony_ci skip = 0; 1420f66f451Sopenharmony_ci break; 1430f66f451Sopenharmony_ci } 1440f66f451Sopenharmony_ci } 1450f66f451Sopenharmony_ci 1460f66f451Sopenharmony_ci return !skip; 1470f66f451Sopenharmony_ci} 1480f66f451Sopenharmony_ci 1490f66f451Sopenharmony_cistruct mtab_list *xgetmountlist(char *path) 1500f66f451Sopenharmony_ci{ 1510f66f451Sopenharmony_ci struct mtab_list *mtlist = 0, *mt; 1520f66f451Sopenharmony_ci struct mntent *me; 1530f66f451Sopenharmony_ci FILE *fp; 1540f66f451Sopenharmony_ci char *p = path ? path : "/proc/mounts"; 1550f66f451Sopenharmony_ci 1560f66f451Sopenharmony_ci if (!(fp = setmntent(p, "r"))) perror_exit("bad %s", p); 1570f66f451Sopenharmony_ci 1580f66f451Sopenharmony_ci // The "test" part of the loop is done before the first time through and 1590f66f451Sopenharmony_ci // again after each "increment", so putting the actual load there avoids 1600f66f451Sopenharmony_ci // duplicating it. If the load was NULL, the loop stops. 1610f66f451Sopenharmony_ci 1620f66f451Sopenharmony_ci while ((me = getmntent(fp))) { 1630f66f451Sopenharmony_ci mt = xzalloc(sizeof(struct mtab_list) + strlen(me->mnt_fsname) + 1640f66f451Sopenharmony_ci strlen(me->mnt_dir) + strlen(me->mnt_type) + strlen(me->mnt_opts) + 4); 1650f66f451Sopenharmony_ci dlist_add_nomalloc((void *)&mtlist, (void *)mt); 1660f66f451Sopenharmony_ci 1670f66f451Sopenharmony_ci // Collect details about mounted filesystem 1680f66f451Sopenharmony_ci // Don't report errors, just leave data zeroed 1690f66f451Sopenharmony_ci if (!path) { 1700f66f451Sopenharmony_ci stat(me->mnt_dir, &(mt->stat)); 1710f66f451Sopenharmony_ci statvfs(me->mnt_dir, &(mt->statvfs)); 1720f66f451Sopenharmony_ci } 1730f66f451Sopenharmony_ci 1740f66f451Sopenharmony_ci // Remember information from /proc/mounts 1750f66f451Sopenharmony_ci mt->dir = stpcpy(mt->type, me->mnt_type)+1; 1760f66f451Sopenharmony_ci mt->device = stpcpy(mt->dir, me->mnt_dir)+1; 1770f66f451Sopenharmony_ci mt->opts = stpcpy(mt->device, me->mnt_fsname)+1; 1780f66f451Sopenharmony_ci strcpy(mt->opts, me->mnt_opts); 1790f66f451Sopenharmony_ci 1800f66f451Sopenharmony_ci octal_deslash(mt->dir); 1810f66f451Sopenharmony_ci octal_deslash(mt->device); 1820f66f451Sopenharmony_ci } 1830f66f451Sopenharmony_ci endmntent(fp); 1840f66f451Sopenharmony_ci 1850f66f451Sopenharmony_ci return mtlist; 1860f66f451Sopenharmony_ci} 1870f66f451Sopenharmony_ci 1880f66f451Sopenharmony_ci#endif 1890f66f451Sopenharmony_ci 1900f66f451Sopenharmony_ci#ifdef __APPLE__ 1910f66f451Sopenharmony_ci 1920f66f451Sopenharmony_ci#include <sys/event.h> 1930f66f451Sopenharmony_ci 1940f66f451Sopenharmony_cistruct xnotify *xnotify_init(int max) 1950f66f451Sopenharmony_ci{ 1960f66f451Sopenharmony_ci struct xnotify *not = xzalloc(sizeof(struct xnotify)); 1970f66f451Sopenharmony_ci 1980f66f451Sopenharmony_ci not->max = max; 1990f66f451Sopenharmony_ci if ((not->kq = kqueue()) == -1) perror_exit("kqueue"); 2000f66f451Sopenharmony_ci not->paths = xmalloc(max * sizeof(char *)); 2010f66f451Sopenharmony_ci not->fds = xmalloc(max * sizeof(int)); 2020f66f451Sopenharmony_ci 2030f66f451Sopenharmony_ci return not; 2040f66f451Sopenharmony_ci} 2050f66f451Sopenharmony_ci 2060f66f451Sopenharmony_ciint xnotify_add(struct xnotify *not, int fd, char *path) 2070f66f451Sopenharmony_ci{ 2080f66f451Sopenharmony_ci struct kevent event; 2090f66f451Sopenharmony_ci 2100f66f451Sopenharmony_ci if (not->count == not->max) error_exit("xnotify_add overflow"); 2110f66f451Sopenharmony_ci EV_SET(&event, fd, EVFILT_VNODE, EV_ADD|EV_CLEAR, NOTE_WRITE, 0, NULL); 2120f66f451Sopenharmony_ci if (kevent(not->kq, &event, 1, NULL, 0, NULL) == -1 || event.flags & EV_ERROR) 2130f66f451Sopenharmony_ci return -1; 2140f66f451Sopenharmony_ci not->paths[not->count] = path; 2150f66f451Sopenharmony_ci not->fds[not->count++] = fd; 2160f66f451Sopenharmony_ci 2170f66f451Sopenharmony_ci return 0; 2180f66f451Sopenharmony_ci} 2190f66f451Sopenharmony_ci 2200f66f451Sopenharmony_ciint xnotify_wait(struct xnotify *not, char **path) 2210f66f451Sopenharmony_ci{ 2220f66f451Sopenharmony_ci struct kevent event; 2230f66f451Sopenharmony_ci int i; 2240f66f451Sopenharmony_ci 2250f66f451Sopenharmony_ci for (;;) { 2260f66f451Sopenharmony_ci if (kevent(not->kq, NULL, 0, &event, 1, NULL) != -1) { 2270f66f451Sopenharmony_ci // We get the fd for free, but still have to search for the path. 2280f66f451Sopenharmony_ci for (i = 0; i<not->count; i++) if (not->fds[i]==event.ident) { 2290f66f451Sopenharmony_ci *path = not->paths[i]; 2300f66f451Sopenharmony_ci 2310f66f451Sopenharmony_ci return event.ident; 2320f66f451Sopenharmony_ci } 2330f66f451Sopenharmony_ci } 2340f66f451Sopenharmony_ci } 2350f66f451Sopenharmony_ci} 2360f66f451Sopenharmony_ci 2370f66f451Sopenharmony_ci#else 2380f66f451Sopenharmony_ci 2390f66f451Sopenharmony_ci#include <sys/inotify.h> 2400f66f451Sopenharmony_ci 2410f66f451Sopenharmony_cistruct xnotify *xnotify_init(int max) 2420f66f451Sopenharmony_ci{ 2430f66f451Sopenharmony_ci struct xnotify *not = xzalloc(sizeof(struct xnotify)); 2440f66f451Sopenharmony_ci 2450f66f451Sopenharmony_ci not->max = max; 2460f66f451Sopenharmony_ci if ((not->kq = inotify_init()) < 0) perror_exit("inotify_init"); 2470f66f451Sopenharmony_ci not->paths = xmalloc(max * sizeof(char *)); 2480f66f451Sopenharmony_ci not->fds = xmalloc(max * 2 * sizeof(int)); 2490f66f451Sopenharmony_ci 2500f66f451Sopenharmony_ci return not; 2510f66f451Sopenharmony_ci} 2520f66f451Sopenharmony_ci 2530f66f451Sopenharmony_ciint xnotify_add(struct xnotify *not, int fd, char *path) 2540f66f451Sopenharmony_ci{ 2550f66f451Sopenharmony_ci int i = 2*not->count; 2560f66f451Sopenharmony_ci 2570f66f451Sopenharmony_ci if (not->max == not->count) error_exit("xnotify_add overflow"); 2580f66f451Sopenharmony_ci if ((not->fds[i] = inotify_add_watch(not->kq, path, IN_MODIFY))==-1) 2590f66f451Sopenharmony_ci return -1; 2600f66f451Sopenharmony_ci not->fds[i+1] = fd; 2610f66f451Sopenharmony_ci not->paths[not->count++] = path; 2620f66f451Sopenharmony_ci 2630f66f451Sopenharmony_ci return 0; 2640f66f451Sopenharmony_ci} 2650f66f451Sopenharmony_ci 2660f66f451Sopenharmony_ciint xnotify_wait(struct xnotify *not, char **path) 2670f66f451Sopenharmony_ci{ 2680f66f451Sopenharmony_ci struct inotify_event ev; 2690f66f451Sopenharmony_ci int i; 2700f66f451Sopenharmony_ci 2710f66f451Sopenharmony_ci for (;;) { 2720f66f451Sopenharmony_ci if (sizeof(ev)!=read(not->kq, &ev, sizeof(ev))) perror_exit("inotify"); 2730f66f451Sopenharmony_ci 2740f66f451Sopenharmony_ci for (i = 0; i<not->count; i++) if (ev.wd==not->fds[2*i]) { 2750f66f451Sopenharmony_ci *path = not->paths[i]; 2760f66f451Sopenharmony_ci 2770f66f451Sopenharmony_ci return not->fds[2*i+1]; 2780f66f451Sopenharmony_ci } 2790f66f451Sopenharmony_ci } 2800f66f451Sopenharmony_ci} 2810f66f451Sopenharmony_ci 2820f66f451Sopenharmony_ci#endif 2830f66f451Sopenharmony_ci 2840f66f451Sopenharmony_ci#ifdef __APPLE__ 2850f66f451Sopenharmony_ci 2860f66f451Sopenharmony_cissize_t xattr_get(const char *path, const char *name, void *value, size_t size) 2870f66f451Sopenharmony_ci{ 2880f66f451Sopenharmony_ci return getxattr(path, name, value, size, 0, 0); 2890f66f451Sopenharmony_ci} 2900f66f451Sopenharmony_ci 2910f66f451Sopenharmony_cissize_t xattr_lget(const char *path, const char *name, void *value, size_t size) 2920f66f451Sopenharmony_ci{ 2930f66f451Sopenharmony_ci return getxattr(path, name, value, size, 0, XATTR_NOFOLLOW); 2940f66f451Sopenharmony_ci} 2950f66f451Sopenharmony_ci 2960f66f451Sopenharmony_cissize_t xattr_fget(int fd, const char *name, void *value, size_t size) 2970f66f451Sopenharmony_ci{ 2980f66f451Sopenharmony_ci return fgetxattr(fd, name, value, size, 0, 0); 2990f66f451Sopenharmony_ci} 3000f66f451Sopenharmony_ci 3010f66f451Sopenharmony_cissize_t xattr_list(const char *path, char *list, size_t size) 3020f66f451Sopenharmony_ci{ 3030f66f451Sopenharmony_ci return listxattr(path, list, size, 0); 3040f66f451Sopenharmony_ci} 3050f66f451Sopenharmony_ci 3060f66f451Sopenharmony_cissize_t xattr_llist(const char *path, char *list, size_t size) 3070f66f451Sopenharmony_ci{ 3080f66f451Sopenharmony_ci return listxattr(path, list, size, XATTR_NOFOLLOW); 3090f66f451Sopenharmony_ci} 3100f66f451Sopenharmony_ci 3110f66f451Sopenharmony_cissize_t xattr_flist(int fd, char *list, size_t size) 3120f66f451Sopenharmony_ci{ 3130f66f451Sopenharmony_ci return flistxattr(fd, list, size, 0); 3140f66f451Sopenharmony_ci} 3150f66f451Sopenharmony_ci 3160f66f451Sopenharmony_cissize_t xattr_set(const char* path, const char* name, 3170f66f451Sopenharmony_ci const void* value, size_t size, int flags) 3180f66f451Sopenharmony_ci{ 3190f66f451Sopenharmony_ci return setxattr(path, name, value, size, 0, flags); 3200f66f451Sopenharmony_ci} 3210f66f451Sopenharmony_ci 3220f66f451Sopenharmony_cissize_t xattr_lset(const char* path, const char* name, 3230f66f451Sopenharmony_ci const void* value, size_t size, int flags) 3240f66f451Sopenharmony_ci{ 3250f66f451Sopenharmony_ci return setxattr(path, name, value, size, 0, flags | XATTR_NOFOLLOW); 3260f66f451Sopenharmony_ci} 3270f66f451Sopenharmony_ci 3280f66f451Sopenharmony_cissize_t xattr_fset(int fd, const char* name, 3290f66f451Sopenharmony_ci const void* value, size_t size, int flags) 3300f66f451Sopenharmony_ci{ 3310f66f451Sopenharmony_ci return fsetxattr(fd, name, value, size, 0, flags); 3320f66f451Sopenharmony_ci} 3330f66f451Sopenharmony_ci 3340f66f451Sopenharmony_ci#else 3350f66f451Sopenharmony_ci 3360f66f451Sopenharmony_cissize_t xattr_get(const char *path, const char *name, void *value, size_t size) 3370f66f451Sopenharmony_ci{ 3380f66f451Sopenharmony_ci return getxattr(path, name, value, size); 3390f66f451Sopenharmony_ci} 3400f66f451Sopenharmony_ci 3410f66f451Sopenharmony_cissize_t xattr_lget(const char *path, const char *name, void *value, size_t size) 3420f66f451Sopenharmony_ci{ 3430f66f451Sopenharmony_ci return lgetxattr(path, name, value, size); 3440f66f451Sopenharmony_ci} 3450f66f451Sopenharmony_ci 3460f66f451Sopenharmony_cissize_t xattr_fget(int fd, const char *name, void *value, size_t size) 3470f66f451Sopenharmony_ci{ 3480f66f451Sopenharmony_ci return fgetxattr(fd, name, value, size); 3490f66f451Sopenharmony_ci} 3500f66f451Sopenharmony_ci 3510f66f451Sopenharmony_cissize_t xattr_list(const char *path, char *list, size_t size) 3520f66f451Sopenharmony_ci{ 3530f66f451Sopenharmony_ci return listxattr(path, list, size); 3540f66f451Sopenharmony_ci} 3550f66f451Sopenharmony_ci 3560f66f451Sopenharmony_cissize_t xattr_llist(const char *path, char *list, size_t size) 3570f66f451Sopenharmony_ci{ 3580f66f451Sopenharmony_ci return llistxattr(path, list, size); 3590f66f451Sopenharmony_ci} 3600f66f451Sopenharmony_ci 3610f66f451Sopenharmony_cissize_t xattr_flist(int fd, char *list, size_t size) 3620f66f451Sopenharmony_ci{ 3630f66f451Sopenharmony_ci return flistxattr(fd, list, size); 3640f66f451Sopenharmony_ci} 3650f66f451Sopenharmony_ci 3660f66f451Sopenharmony_cissize_t xattr_set(const char* path, const char* name, 3670f66f451Sopenharmony_ci const void* value, size_t size, int flags) 3680f66f451Sopenharmony_ci{ 3690f66f451Sopenharmony_ci return setxattr(path, name, value, size, flags); 3700f66f451Sopenharmony_ci} 3710f66f451Sopenharmony_ci 3720f66f451Sopenharmony_cissize_t xattr_lset(const char* path, const char* name, 3730f66f451Sopenharmony_ci const void* value, size_t size, int flags) 3740f66f451Sopenharmony_ci{ 3750f66f451Sopenharmony_ci return lsetxattr(path, name, value, size, flags); 3760f66f451Sopenharmony_ci} 3770f66f451Sopenharmony_ci 3780f66f451Sopenharmony_cissize_t xattr_fset(int fd, const char* name, 3790f66f451Sopenharmony_ci const void* value, size_t size, int flags) 3800f66f451Sopenharmony_ci{ 3810f66f451Sopenharmony_ci return fsetxattr(fd, name, value, size, flags); 3820f66f451Sopenharmony_ci} 3830f66f451Sopenharmony_ci 3840f66f451Sopenharmony_ci 3850f66f451Sopenharmony_ci#endif 3860f66f451Sopenharmony_ci 3870f66f451Sopenharmony_ci#ifdef __APPLE__ 3880f66f451Sopenharmony_ci// In the absence of a mknodat system call, fchdir to dirfd and back 3890f66f451Sopenharmony_ci// around a regular mknod call... 3900f66f451Sopenharmony_ciint mknodat(int dirfd, const char *path, mode_t mode, dev_t dev) 3910f66f451Sopenharmony_ci{ 3920f66f451Sopenharmony_ci int old_dirfd = open(".", O_RDONLY), result; 3930f66f451Sopenharmony_ci 3940f66f451Sopenharmony_ci if (old_dirfd == -1 || fchdir(dirfd) == -1) return -1; 3950f66f451Sopenharmony_ci result = mknod(path, mode, dev); 3960f66f451Sopenharmony_ci if (fchdir(old_dirfd) == -1) perror_exit("mknodat couldn't return"); 3970f66f451Sopenharmony_ci return result; 3980f66f451Sopenharmony_ci} 3990f66f451Sopenharmony_ci#endif 4000f66f451Sopenharmony_ci 4010f66f451Sopenharmony_ci// Signals required by POSIX 2008: 4020f66f451Sopenharmony_ci// http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/signal.h.html 4030f66f451Sopenharmony_ci 4040f66f451Sopenharmony_ci#define SIGNIFY(x) {SIG##x, #x} 4050f66f451Sopenharmony_ci 4060f66f451Sopenharmony_cistatic const struct signame signames[] = { 4070f66f451Sopenharmony_ci // POSIX 4080f66f451Sopenharmony_ci SIGNIFY(ABRT), SIGNIFY(ALRM), SIGNIFY(BUS), 4090f66f451Sopenharmony_ci SIGNIFY(FPE), SIGNIFY(HUP), SIGNIFY(ILL), SIGNIFY(INT), SIGNIFY(KILL), 4100f66f451Sopenharmony_ci SIGNIFY(PIPE), SIGNIFY(QUIT), SIGNIFY(SEGV), SIGNIFY(TERM), 4110f66f451Sopenharmony_ci SIGNIFY(USR1), SIGNIFY(USR2), SIGNIFY(SYS), SIGNIFY(TRAP), 4120f66f451Sopenharmony_ci SIGNIFY(VTALRM), SIGNIFY(XCPU), SIGNIFY(XFSZ), 4130f66f451Sopenharmony_ci // Non-POSIX signals that cause termination 4140f66f451Sopenharmony_ci SIGNIFY(PROF), SIGNIFY(IO), 4150f66f451Sopenharmony_ci#ifdef __linux__ 4160f66f451Sopenharmony_ci SIGNIFY(STKFLT), SIGNIFY(POLL), SIGNIFY(PWR), 4170f66f451Sopenharmony_ci#elif defined(__APPLE__) 4180f66f451Sopenharmony_ci SIGNIFY(EMT), SIGNIFY(INFO), 4190f66f451Sopenharmony_ci#endif 4200f66f451Sopenharmony_ci 4210f66f451Sopenharmony_ci // Note: sigatexit relies on all the signals with a default disposition that 4220f66f451Sopenharmony_ci // terminates the process coming *before* SIGCHLD. 4230f66f451Sopenharmony_ci 4240f66f451Sopenharmony_ci // POSIX signals that don't cause termination 4250f66f451Sopenharmony_ci SIGNIFY(CHLD), SIGNIFY(CONT), SIGNIFY(STOP), SIGNIFY(TSTP), 4260f66f451Sopenharmony_ci SIGNIFY(TTIN), SIGNIFY(TTOU), SIGNIFY(URG), 4270f66f451Sopenharmony_ci // Non-POSIX signals that don't cause termination 4280f66f451Sopenharmony_ci SIGNIFY(WINCH), 4290f66f451Sopenharmony_ci}; 4300f66f451Sopenharmony_ciint signames_len = ARRAY_LEN(signames); 4310f66f451Sopenharmony_ci 4320f66f451Sopenharmony_ci#undef SIGNIFY 4330f66f451Sopenharmony_ci 4340f66f451Sopenharmony_civoid xsignal_all_killers(void *handler) 4350f66f451Sopenharmony_ci{ 4360f66f451Sopenharmony_ci int i; 4370f66f451Sopenharmony_ci 4380f66f451Sopenharmony_ci for (i=0; signames[i].num != SIGCHLD; i++) 4390f66f451Sopenharmony_ci if (signames[i].num != SIGKILL) 4400f66f451Sopenharmony_ci xsignal(signames[i].num, handler ? exit_signal : SIG_DFL); 4410f66f451Sopenharmony_ci} 4420f66f451Sopenharmony_ci 4430f66f451Sopenharmony_ci// Convert a string like "9", "KILL", "SIGHUP", or "SIGRTMIN+2" to a number. 4440f66f451Sopenharmony_ciint sig_to_num(char *sigstr) 4450f66f451Sopenharmony_ci{ 4460f66f451Sopenharmony_ci int i, offset; 4470f66f451Sopenharmony_ci char *s; 4480f66f451Sopenharmony_ci 4490f66f451Sopenharmony_ci // Numeric? 4500f66f451Sopenharmony_ci i = estrtol(sigstr, &s, 10); 4510f66f451Sopenharmony_ci if (!errno && !*s) return i; 4520f66f451Sopenharmony_ci 4530f66f451Sopenharmony_ci // Skip leading "SIG". 4540f66f451Sopenharmony_ci strcasestart(&sigstr, "sig"); 4550f66f451Sopenharmony_ci 4560f66f451Sopenharmony_ci // Named signal? 4570f66f451Sopenharmony_ci for (i=0; i<ARRAY_LEN(signames); i++) 4580f66f451Sopenharmony_ci if (!strcasecmp(sigstr, signames[i].name)) return signames[i].num; 4590f66f451Sopenharmony_ci 4600f66f451Sopenharmony_ci // Real-time signal? 4610f66f451Sopenharmony_ci#ifdef SIGRTMIN 4620f66f451Sopenharmony_ci if (strcasestart(&sigstr, "rtmin")) i = SIGRTMIN; 4630f66f451Sopenharmony_ci else if (strcasestart(&sigstr, "rtmax")) i = SIGRTMAX; 4640f66f451Sopenharmony_ci else return -1; 4650f66f451Sopenharmony_ci 4660f66f451Sopenharmony_ci // No offset? 4670f66f451Sopenharmony_ci if (!*sigstr) return i; 4680f66f451Sopenharmony_ci 4690f66f451Sopenharmony_ci // We allow any offset that's still a real-time signal: SIGRTMIN+20 is fine. 4700f66f451Sopenharmony_ci // Others are more restrictive, only accepting what they show with -l. 4710f66f451Sopenharmony_ci offset = estrtol(sigstr, &s, 10); 4720f66f451Sopenharmony_ci if (errno || *s) return -1; 4730f66f451Sopenharmony_ci i += offset; 4740f66f451Sopenharmony_ci if (i >= SIGRTMIN && i <= SIGRTMAX) return i; 4750f66f451Sopenharmony_ci#endif 4760f66f451Sopenharmony_ci 4770f66f451Sopenharmony_ci return -1; 4780f66f451Sopenharmony_ci} 4790f66f451Sopenharmony_ci 4800f66f451Sopenharmony_cichar *num_to_sig(int sig) 4810f66f451Sopenharmony_ci{ 4820f66f451Sopenharmony_ci int i; 4830f66f451Sopenharmony_ci 4840f66f451Sopenharmony_ci // A named signal? 4850f66f451Sopenharmony_ci for (i=0; i<signames_len; i++) 4860f66f451Sopenharmony_ci if (signames[i].num == sig) return signames[i].name; 4870f66f451Sopenharmony_ci 4880f66f451Sopenharmony_ci // A real-time signal? 4890f66f451Sopenharmony_ci#ifdef SIGRTMIN 4900f66f451Sopenharmony_ci if (sig == SIGRTMIN) return "RTMIN"; 4910f66f451Sopenharmony_ci if (sig == SIGRTMAX) return "RTMAX"; 4920f66f451Sopenharmony_ci if (sig > SIGRTMIN && sig < SIGRTMAX) { 4930f66f451Sopenharmony_ci if (sig-SIGRTMIN <= SIGRTMAX-sig) sprintf(libbuf, "RTMIN+%d", sig-SIGRTMIN); 4940f66f451Sopenharmony_ci else sprintf(libbuf, "RTMAX-%d", SIGRTMAX-sig); 4950f66f451Sopenharmony_ci return libbuf; 4960f66f451Sopenharmony_ci } 4970f66f451Sopenharmony_ci#endif 4980f66f451Sopenharmony_ci 4990f66f451Sopenharmony_ci return NULL; 5000f66f451Sopenharmony_ci} 5010f66f451Sopenharmony_ci 5020f66f451Sopenharmony_cichar *fs_type_name(struct statfs *statfs) 5030f66f451Sopenharmony_ci{ 5040f66f451Sopenharmony_ci#if defined(__APPLE__) || defined(__OpenBSD__) 5050f66f451Sopenharmony_ci // macOS has an `f_type` field, but assigns values dynamically as filesystems 5060f66f451Sopenharmony_ci // are registered. They do give you the name directly though, so use that. 5070f66f451Sopenharmony_ci return statfs->f_fstypename; 5080f66f451Sopenharmony_ci#else 5090f66f451Sopenharmony_ci char *s = NULL; 5100f66f451Sopenharmony_ci struct {unsigned num; char *name;} nn[] = { 5110f66f451Sopenharmony_ci {0xADFF, "affs"}, {0x5346544e, "ntfs"}, {0x1Cd1, "devpts"}, 5120f66f451Sopenharmony_ci {0x137D, "ext"}, {0xEF51, "ext2"}, {0xEF53, "ext3"}, 5130f66f451Sopenharmony_ci {0x1BADFACE, "bfs"}, {0x9123683E, "btrfs"}, {0x28cd3d45, "cramfs"}, 5140f66f451Sopenharmony_ci {0x3153464a, "jfs"}, {0x7275, "romfs"}, {0x01021994, "tmpfs"}, 5150f66f451Sopenharmony_ci {0x3434, "nilfs"}, {0x6969, "nfs"}, {0x9fa0, "proc"}, 5160f66f451Sopenharmony_ci {0x534F434B, "sockfs"}, {0x62656572, "sysfs"}, {0x517B, "smb"}, 5170f66f451Sopenharmony_ci {0x4d44, "msdos"}, {0x4006, "fat"}, {0x43415d53, "smackfs"}, 5180f66f451Sopenharmony_ci {0x73717368, "squashfs"} 5190f66f451Sopenharmony_ci }; 5200f66f451Sopenharmony_ci int i; 5210f66f451Sopenharmony_ci 5220f66f451Sopenharmony_ci for (i=0; i<ARRAY_LEN(nn); i++) 5230f66f451Sopenharmony_ci if (nn[i].num == statfs->f_type) s = nn[i].name; 5240f66f451Sopenharmony_ci if (!s) sprintf(s = libbuf, "0x%x", (unsigned)statfs->f_type); 5250f66f451Sopenharmony_ci return s; 5260f66f451Sopenharmony_ci#endif 5270f66f451Sopenharmony_ci} 5280f66f451Sopenharmony_ci 5290f66f451Sopenharmony_cistatic int check_copy_file_range(void) 5300f66f451Sopenharmony_ci{ 5310f66f451Sopenharmony_ci#if defined(__ANDROID__) 5320f66f451Sopenharmony_ci // Android's had the constant for years, but seccomp means you'll get 5330f66f451Sopenharmony_ci // SIGSYS if you try the system call before 2023's Android U. 5340f66f451Sopenharmony_ci return (android_api_level() >= __ANDROID_API_U__) ? __NR_copy_file_range : 0; 5350f66f451Sopenharmony_ci#elif defined(__NR_copy_file_range) 5360f66f451Sopenharmony_ci // glibc added this constant in git at the end of 2017, shipped 2018-02. 5370f66f451Sopenharmony_ci return __NR_copy_file_range; 5380f66f451Sopenharmony_ci#else 5390f66f451Sopenharmony_ci return 0; 5400f66f451Sopenharmony_ci#endif 5410f66f451Sopenharmony_ci} 5420f66f451Sopenharmony_ci 5430f66f451Sopenharmony_ci// Return bytes copied from in to out. If bytes <0 copy all of in to out. 5440f66f451Sopenharmony_ci// If consumed isn't null, amount read saved there (return is written or error) 5450f66f451Sopenharmony_cilong long sendfile_len(int in, int out, long long bytes, long long *consumed) 5460f66f451Sopenharmony_ci{ 5470f66f451Sopenharmony_ci long long total = 0, len, ww; 5480f66f451Sopenharmony_ci int try_cfr = check_copy_file_range(); 5490f66f451Sopenharmony_ci 5500f66f451Sopenharmony_ci if (consumed) *consumed = 0; 5510f66f451Sopenharmony_ci if (in>=0) while (bytes != total) { 5520f66f451Sopenharmony_ci ww = 0; 5530f66f451Sopenharmony_ci len = bytes-total; 5540f66f451Sopenharmony_ci 5550f66f451Sopenharmony_ci errno = 0; 5560f66f451Sopenharmony_ci if (try_cfr) { 5570f66f451Sopenharmony_ci if (bytes<0 || bytes>(1<<30)) len = (1<<30); 5580f66f451Sopenharmony_ci len = syscall(try_cfr, in, 0, out, 0, len, 0); 5590f66f451Sopenharmony_ci if (len < 0) { 5600f66f451Sopenharmony_ci try_cfr = 0; 5610f66f451Sopenharmony_ci 5620f66f451Sopenharmony_ci continue; 5630f66f451Sopenharmony_ci } 5640f66f451Sopenharmony_ci } else { 5650f66f451Sopenharmony_ci if (bytes<0 || len>sizeof(libbuf)) len = sizeof(libbuf); 5660f66f451Sopenharmony_ci ww = len = read(in, libbuf, len); 5670f66f451Sopenharmony_ci } 5680f66f451Sopenharmony_ci if (len<1 && errno==EAGAIN) continue; 5690f66f451Sopenharmony_ci if (len<1) break; 5700f66f451Sopenharmony_ci if (consumed) *consumed += len; 5710f66f451Sopenharmony_ci if (ww && writeall(out, libbuf, len) != len) return -1; 5720f66f451Sopenharmony_ci total += len; 5730f66f451Sopenharmony_ci } 5740f66f451Sopenharmony_ci 5750f66f451Sopenharmony_ci return total; 5760f66f451Sopenharmony_ci} 5770f66f451Sopenharmony_ci 578