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