• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* portability.c - code to workaround the deficiencies of various platforms.
2  *
3  * Copyright 2012 Rob Landley <rob@landley.net>
4  * Copyright 2012 Georgi Chorbadzhiyski <gf@unixsol.org>
5  */
6 
7 #include "toys.h"
8 
9 // We can't fork() on nommu systems, and vfork() requires an exec() or exit()
10 // before resuming the parent (because they share a heap until then). And no,
11 // we can't implement our own clone() call that does the equivalent of fork()
12 // because nommu heaps use physical addresses so if we copy the heap all our
13 // pointers are wrong. (You need an mmu in order to map two heaps to the same
14 // address range without interfering with each other.) In the absence of
15 // a portable way to tell malloc() to start a new heap without freeing the old
16 // one, you pretty much need the exec().)
17 
18 // So we exec ourselves (via /proc/self/exe, if anybody knows a way to
19 // re-exec self without depending on the filesystem, I'm all ears),
20 // and use the arguments to signal reentry.
21 
22 #if CFG_TOYBOX_FORK
xfork(void)23 pid_t xfork(void)
24 {
25   pid_t pid = fork();
26 
27   if (pid < 0) perror_exit("fork");
28 
29   return pid;
30 }
31 #endif
32 
xgetrandom(void * buf,unsigned buflen)33 void xgetrandom(void *buf, unsigned buflen)
34 {
35   int fd;
36 
37   // Linux keeps getrandom() in <sys/random.h> and getentropy() in <unistd.h>
38   // BSD/macOS only has getentropy(), but it's in <sys/random.h> (to be fair,
39   // they were there first). getrandom() and getentropy() both went into glibc
40   // in the same release (2.25 in 2017), so this test still works.
41 #if __has_include(<sys/random.h>)
42   while (buflen) {
43     if (getentropy(buf, fd = buflen>256 ? 256 : buflen)) break;
44     buflen -= fd;
45     buf += fd;
46   }
47   if (!buflen) return;
48   if (errno!=ENOSYS) perror_exit("getrandom");
49 #endif
50   xreadall(fd = xopen("/dev/urandom", O_RDONLY), buf, buflen);
51   close(fd);
52 }
53 
54 // Get list of mounted filesystems, including stat and statvfs info.
55 // Returns a reversed list, which is good for finding overmounts and such.
56 
57 #if defined(__APPLE__) || defined(__FreeBSD__) || defined(__OpenBSD__)
58 
59 #include <sys/mount.h>
60 
xgetmountlist(char * path)61 struct mtab_list *xgetmountlist(char *path)
62 {
63   struct mtab_list *mtlist = 0, *mt;
64   struct statfs *entries;
65   int i, count;
66 
67   if (path) error_exit("xgetmountlist");
68   if ((count = getmntinfo(&entries, 0)) == 0) perror_exit("getmntinfo");
69 
70   // The "test" part of the loop is done before the first time through and
71   // again after each "increment", so putting the actual load there avoids
72   // duplicating it. If the load was NULL, the loop stops.
73 
74   for (i = 0; i < count; ++i) {
75     struct statfs *me = &entries[i];
76 
77     mt = xzalloc(sizeof(struct mtab_list) + strlen(me->f_fstypename) +
78       strlen(me->f_mntonname) + strlen(me->f_mntfromname) + strlen("") + 4);
79     dlist_add_nomalloc((void *)&mtlist, (void *)mt);
80 
81     // Collect details about mounted filesystem.
82     // Don't report errors, just leave data zeroed.
83     stat(me->f_mntonname, &(mt->stat));
84     statvfs(me->f_mntonname, &(mt->statvfs));
85 
86     // Remember information from struct statfs.
87     mt->dir = stpcpy(mt->type, me->f_fstypename)+1;
88     mt->device = stpcpy(mt->dir, me->f_mntonname)+1;
89     mt->opts = stpcpy(mt->device, me->f_mntfromname)+1;
90     strcpy(mt->opts, ""); /* TODO: reverse from f_flags? */
91   }
92 
93   return mtlist;
94 }
95 
96 #else
97 
98 #include <mntent.h>
99 
100 // Check if this type matches list.
101 // Odd syntax: typelist all yes = if any, typelist all no = if none.
102 
mountlist_istype(struct mtab_list * ml,char * typelist)103 int mountlist_istype(struct mtab_list *ml, char *typelist)
104 {
105   int len, skip;
106   char *t;
107 
108   if (!typelist) return 1;
109 
110   // leading "no" indicates whether entire list is inverted
111   skip = strncmp(typelist, "no", 2);
112 
113   for (;;) {
114     if (!(t = comma_iterate(&typelist, &len))) break;
115     if (!skip) {
116       // later "no" after first are ignored
117       strstart(&t, "no");
118       if (!strncmp(t, ml->type, len-2)) {
119         skip = 1;
120         break;
121       }
122     } else if (!strncmp(t, ml->type, len) && !ml->type[len]) {
123       skip = 0;
124       break;
125     }
126   }
127 
128   return !skip;
129 }
130 
xgetmountlist(char * path)131 struct mtab_list *xgetmountlist(char *path)
132 {
133   struct mtab_list *mtlist = 0, *mt;
134   struct mntent *me;
135   FILE *fp;
136   char *p = path ? path : "/proc/mounts";
137 
138   if (!(fp = setmntent(p, "r"))) perror_exit("bad %s", p);
139 
140   // The "test" part of the loop is done before the first time through and
141   // again after each "increment", so putting the actual load there avoids
142   // duplicating it. If the load was NULL, the loop stops.
143 
144   while ((me = getmntent(fp))) {
145     mt = xzalloc(sizeof(struct mtab_list) + strlen(me->mnt_fsname) +
146       strlen(me->mnt_dir) + strlen(me->mnt_type) + strlen(me->mnt_opts) + 4);
147     dlist_add_nomalloc((void *)&mtlist, (void *)mt);
148 
149     // Collect details about mounted filesystem
150     // Don't report errors, just leave data zeroed
151     if (!path) {
152       stat(me->mnt_dir, &(mt->stat));
153       statvfs(me->mnt_dir, &(mt->statvfs));
154     }
155 
156     // Remember information from /proc/mounts
157     mt->dir = stpcpy(mt->type, me->mnt_type)+1;
158     mt->device = stpcpy(mt->dir, me->mnt_dir)+1;
159     mt->opts = stpcpy(mt->device, me->mnt_fsname)+1;
160     strcpy(mt->opts, me->mnt_opts);
161 
162     octal_deslash(mt->dir);
163     octal_deslash(mt->device);
164   }
165   endmntent(fp);
166 
167   return mtlist;
168 }
169 
170 #endif
171 
172 #if defined(__APPLE__) || defined(__FreeBSD__) || defined(__OpenBSD__)
173 
174 #include <sys/event.h>
175 
xnotify_init(int max)176 struct xnotify *xnotify_init(int max)
177 {
178   struct xnotify *not = xzalloc(sizeof(struct xnotify));
179 
180   not->max = max;
181   if ((not->kq = kqueue()) == -1) perror_exit("kqueue");
182   not->paths = xmalloc(max * sizeof(char *));
183   not->fds = xmalloc(max * sizeof(int));
184 
185   return not;
186 }
187 
xnotify_add(struct xnotify * not,int fd,char * path)188 int xnotify_add(struct xnotify *not, int fd, char *path)
189 {
190   struct kevent event;
191 
192   if (not->count == not->max) error_exit("xnotify_add overflow");
193   EV_SET(&event, fd, EVFILT_VNODE, EV_ADD|EV_CLEAR, NOTE_WRITE, 0, NULL);
194   if (kevent(not->kq, &event, 1, NULL, 0, NULL) == -1 || event.flags & EV_ERROR)
195     error_exit("xnotify_add failed on %s", path);
196   not->paths[not->count] = path;
197   not->fds[not->count++] = fd;
198 
199   return 0;
200 }
201 
xnotify_wait(struct xnotify * not,char ** path)202 int xnotify_wait(struct xnotify *not, char **path)
203 {
204   struct kevent event;
205   int i;
206 
207   for (;;) {
208     if (kevent(not->kq, NULL, 0, &event, 1, NULL) != -1) {
209       // We get the fd for free, but still have to search for the path.
210       for (i = 0; i<not->count; i++) if (not->fds[i]==event.ident) {
211         *path = not->paths[i];
212 
213         return event.ident;
214       }
215     }
216   }
217 }
218 
219 #else
220 
221 #include <sys/inotify.h>
222 
xnotify_init(int max)223 struct xnotify *xnotify_init(int max)
224 {
225   struct xnotify *not = xzalloc(sizeof(struct xnotify));
226 
227   not->max = max;
228   if ((not->kq = inotify_init()) < 0) perror_exit("inotify_init");
229   not->paths = xmalloc(max * sizeof(char *));
230   not->fds = xmalloc(max * 2 * sizeof(int));
231 
232   return not;
233 }
234 
xnotify_add(struct xnotify * not,int fd,char * path)235 int xnotify_add(struct xnotify *not, int fd, char *path)
236 {
237   int i = 2*not->count;
238 
239   if (not->max == not->count) error_exit("xnotify_add overflow");
240   if ((not->fds[i] = inotify_add_watch(not->kq, path, IN_MODIFY))==-1)
241     perror_exit("xnotify_add failed on %s", path);
242   not->fds[i+1] = fd;
243   not->paths[not->count++] = path;
244 
245   return 0;
246 }
247 
xnotify_wait(struct xnotify * not,char ** path)248 int xnotify_wait(struct xnotify *not, char **path)
249 {
250   struct inotify_event ev;
251   int i;
252 
253   for (;;) {
254     if (sizeof(ev)!=read(not->kq, &ev, sizeof(ev))) perror_exit("inotify");
255 
256     for (i = 0; i<not->count; i++) if (ev.wd==not->fds[2*i]) {
257       *path = not->paths[i];
258 
259       return not->fds[2*i+1];
260     }
261   }
262 }
263 
264 #endif
265 
266 #ifdef __APPLE__
267 
xattr_get(const char * path,const char * name,void * value,size_t size)268 ssize_t xattr_get(const char *path, const char *name, void *value, size_t size)
269 {
270   return getxattr(path, name, value, size, 0, 0);
271 }
272 
xattr_lget(const char * path,const char * name,void * value,size_t size)273 ssize_t xattr_lget(const char *path, const char *name, void *value, size_t size)
274 {
275   return getxattr(path, name, value, size, 0, XATTR_NOFOLLOW);
276 }
277 
xattr_fget(int fd,const char * name,void * value,size_t size)278 ssize_t xattr_fget(int fd, const char *name, void *value, size_t size)
279 {
280   return fgetxattr(fd, name, value, size, 0, 0);
281 }
282 
xattr_list(const char * path,char * list,size_t size)283 ssize_t xattr_list(const char *path, char *list, size_t size)
284 {
285   return listxattr(path, list, size, 0);
286 }
287 
xattr_llist(const char * path,char * list,size_t size)288 ssize_t xattr_llist(const char *path, char *list, size_t size)
289 {
290   return listxattr(path, list, size, XATTR_NOFOLLOW);
291 }
292 
xattr_flist(int fd,char * list,size_t size)293 ssize_t xattr_flist(int fd, char *list, size_t size)
294 {
295   return flistxattr(fd, list, size, 0);
296 }
297 
xattr_set(const char * path,const char * name,const void * value,size_t size,int flags)298 ssize_t xattr_set(const char* path, const char* name,
299                   const void* value, size_t size, int flags)
300 {
301   return setxattr(path, name, value, size, 0, flags);
302 }
303 
xattr_lset(const char * path,const char * name,const void * value,size_t size,int flags)304 ssize_t xattr_lset(const char* path, const char* name,
305                    const void* value, size_t size, int flags)
306 {
307   return setxattr(path, name, value, size, 0, flags | XATTR_NOFOLLOW);
308 }
309 
xattr_fset(int fd,const char * name,const void * value,size_t size,int flags)310 ssize_t xattr_fset(int fd, const char* name,
311                    const void* value, size_t size, int flags)
312 {
313   return fsetxattr(fd, name, value, size, 0, flags);
314 }
315 
316 #elif !defined(__FreeBSD__) && !defined(__OpenBSD__)
317 
xattr_get(const char * path,const char * name,void * value,size_t size)318 ssize_t xattr_get(const char *path, const char *name, void *value, size_t size)
319 {
320   return getxattr(path, name, value, size);
321 }
322 
xattr_lget(const char * path,const char * name,void * value,size_t size)323 ssize_t xattr_lget(const char *path, const char *name, void *value, size_t size)
324 {
325   return lgetxattr(path, name, value, size);
326 }
327 
xattr_fget(int fd,const char * name,void * value,size_t size)328 ssize_t xattr_fget(int fd, const char *name, void *value, size_t size)
329 {
330   return fgetxattr(fd, name, value, size);
331 }
332 
xattr_list(const char * path,char * list,size_t size)333 ssize_t xattr_list(const char *path, char *list, size_t size)
334 {
335   return listxattr(path, list, size);
336 }
337 
xattr_llist(const char * path,char * list,size_t size)338 ssize_t xattr_llist(const char *path, char *list, size_t size)
339 {
340   return llistxattr(path, list, size);
341 }
342 
xattr_flist(int fd,char * list,size_t size)343 ssize_t xattr_flist(int fd, char *list, size_t size)
344 {
345   return flistxattr(fd, list, size);
346 }
347 
xattr_set(const char * path,const char * name,const void * value,size_t size,int flags)348 ssize_t xattr_set(const char* path, const char* name,
349                   const void* value, size_t size, int flags)
350 {
351   return setxattr(path, name, value, size, flags);
352 }
353 
xattr_lset(const char * path,const char * name,const void * value,size_t size,int flags)354 ssize_t xattr_lset(const char* path, const char* name,
355                    const void* value, size_t size, int flags)
356 {
357   return lsetxattr(path, name, value, size, flags);
358 }
359 
xattr_fset(int fd,const char * name,const void * value,size_t size,int flags)360 ssize_t xattr_fset(int fd, const char* name,
361                    const void* value, size_t size, int flags)
362 {
363   return fsetxattr(fd, name, value, size, flags);
364 }
365 
366 
367 #endif
368 
369 #ifdef __APPLE__
370 // In the absence of a mknodat system call, fchdir to dirfd and back
371 // around a regular mknod call...
mknodat(int dirfd,const char * path,mode_t mode,dev_t dev)372 int mknodat(int dirfd, const char *path, mode_t mode, dev_t dev)
373 {
374   int old_dirfd = open(".", O_RDONLY), result;
375 
376   if (old_dirfd == -1 || fchdir(dirfd) == -1) return -1;
377   result = mknod(path, mode, dev);
378   if (fchdir(old_dirfd) == -1) perror_exit("mknodat couldn't return");
379   return result;
380 }
381 
382 // As of 10.15, macOS offers an fcntl F_PREALLOCATE rather than fallocate()
383 // or posix_fallocate() calls.
posix_fallocate(int fd,off_t offset,off_t length)384 int posix_fallocate(int fd, off_t offset, off_t length)
385 {
386   int e = errno, result;
387   fstore_t f;
388 
389   f.fst_flags = F_ALLOCATEALL;
390   f.fst_posmode = F_PEOFPOSMODE;
391   f.fst_offset = offset;
392   f.fst_length = length;
393   if (fcntl(fd, F_PREALLOCATE, &f) == -1) result = errno;
394   else result = ftruncate(fd, length);
395   errno = e;
396   return result;
397 }
398 #endif
399 
400 // Signals required by POSIX 2008:
401 // http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/signal.h.html
402 
403 #define SIGNIFY(x) {SIG##x, #x}
404 
405 static const struct signame signames[] = {
406   {0, "0"},
407   // POSIX
408   SIGNIFY(ABRT), SIGNIFY(ALRM), SIGNIFY(BUS),
409   SIGNIFY(FPE), SIGNIFY(HUP), SIGNIFY(ILL), SIGNIFY(INT), SIGNIFY(KILL),
410   SIGNIFY(PIPE), SIGNIFY(QUIT), SIGNIFY(SEGV), SIGNIFY(TERM),
411   SIGNIFY(USR1), SIGNIFY(USR2), SIGNIFY(SYS), SIGNIFY(TRAP),
412   SIGNIFY(VTALRM), SIGNIFY(XCPU), SIGNIFY(XFSZ),
413   // Non-POSIX signals that cause termination
414   SIGNIFY(PROF), SIGNIFY(IO),
415   // signals only present/absent on some targets (mips and macos)
416 #ifdef SIGEMT
417   SIGNIFY(EMT),
418 #endif
419 #ifdef SIGINFO
420   SIGNIFY(INFO),
421 #endif
422 #ifdef SIGPOLL
423   SIGNIFY(POLL),
424 #endif
425 #ifdef SIGPWR
426   SIGNIFY(PWR),
427 #endif
428 #ifdef SIGSTKFLT
429   SIGNIFY(STKFLT),
430 #endif
431 
432   // Note: sigatexit relies on all the signals with a default disposition that
433   // terminates the process coming *before* SIGCHLD.
434 
435   // POSIX signals that don't cause termination
436   SIGNIFY(CHLD), SIGNIFY(CONT), SIGNIFY(STOP), SIGNIFY(TSTP),
437   SIGNIFY(TTIN), SIGNIFY(TTOU), SIGNIFY(URG),
438   // Non-POSIX signals that don't cause termination
439   SIGNIFY(WINCH),
440 };
441 
442 #undef SIGNIFY
443 
xsignal_all_killers(void * handler)444 void xsignal_all_killers(void *handler)
445 {
446   int i;
447 
448   for (i = 1; signames[i].num != SIGCHLD; i++)
449     if (signames[i].num != SIGKILL) xsignal(signames[i].num, handler);
450 }
451 
452 // Convert a string like "9", "KILL", "SIGHUP", or "SIGRTMIN+2" to a number.
sig_to_num(char * sigstr)453 int sig_to_num(char *sigstr)
454 {
455   int i, offset;
456   char *s;
457 
458   // Numeric?
459   offset = estrtol(sigstr, &s, 10);
460   if (!errno && !*s) return offset;
461 
462   // Skip leading "SIG".
463   strcasestart(&sigstr, "sig");
464 
465   // Named signal?
466   for (i=0; i<ARRAY_LEN(signames); i++)
467     if (!strcasecmp(sigstr, signames[i].name)) return signames[i].num;
468 
469   // Real-time signal?
470 #ifdef SIGRTMIN
471   if (strcasestart(&sigstr, "rtmin")) i = SIGRTMIN;
472   else if (strcasestart(&sigstr, "rtmax")) i = SIGRTMAX;
473   else return -1;
474 
475   // No offset?
476   if (!*sigstr) return i;
477 
478   // We allow any offset that's still a real-time signal: SIGRTMIN+20 is fine.
479   // Others are more restrictive, only accepting what they show with -l.
480   offset = estrtol(sigstr, &s, 10);
481   if (errno || *s) return -1;
482   i += offset;
483   if (i >= SIGRTMIN && i <= SIGRTMAX) return i;
484 #endif
485 
486   return -1;
487 }
488 
num_to_sig(int sig)489 char *num_to_sig(int sig)
490 {
491   int i;
492 
493   // A named signal?
494   for (i=0; i<ARRAY_LEN(signames); i++)
495     if (signames[i].num == sig) return signames[i].name;
496 
497   // A real-time signal?
498 #ifdef SIGRTMIN
499   if (sig == SIGRTMIN) return "RTMIN";
500   if (sig == SIGRTMAX) return "RTMAX";
501   if (sig > SIGRTMIN && sig < SIGRTMAX) {
502     if (sig-SIGRTMIN <= SIGRTMAX-sig) sprintf(libbuf, "RTMIN+%d", sig-SIGRTMIN);
503     else sprintf(libbuf, "RTMAX-%d", SIGRTMAX-sig);
504     return libbuf;
505   }
506 #endif
507 
508   return NULL;
509 }
510 
dev_minor(int dev)511 int dev_minor(int dev)
512 {
513 #if defined(__linux__)
514   return ((dev&0xfff00000)>>12)|(dev&0xff);
515 #elif defined(__APPLE__)
516   return dev&0xffffff;
517 #elif defined(__FreeBSD__) || defined(__OpenBSD__)
518   return minor(dev);
519 #else
520 #error
521 #endif
522 }
523 
dev_major(int dev)524 int dev_major(int dev)
525 {
526 #if defined(__linux__)
527   return (dev&0xfff00)>>8;
528 #elif defined(__APPLE__)
529   return (dev>>24)&0xff;
530 #elif defined(__FreeBSD__) || defined(__OpenBSD__)
531   return major(dev);
532 #else
533 #error
534 #endif
535 }
536 
dev_makedev(int major,int minor)537 int dev_makedev(int major, int minor)
538 {
539 #if defined(__linux__)
540   return (minor&0xff)|((major&0xfff)<<8)|((minor&0xfff00)<<12);
541 #elif defined(__APPLE__)
542   return (minor&0xffffff)|((major&0xff)<<24);
543 #elif defined(__FreeBSD__) || defined(__OpenBSD__)
544   return makedev(major, minor);
545 #else
546 #error
547 #endif
548 }
549 
fs_type_name(struct statfs * statfs)550 char *fs_type_name(struct statfs *statfs)
551 {
552 #if defined(__APPLE__) || defined(__FreeBSD__) || defined(__OpenBSD__)
553   // macOS has an `f_type` field, but assigns values dynamically as filesystems
554   // are registered. They do give you the name directly though, so use that.
555   return statfs->f_fstypename;
556 #else
557   char *s = NULL;
558   struct {unsigned num; char *name;} nn[] = {
559     {0xADFF, "affs"}, {0x5346544e, "ntfs"}, {0x1Cd1, "devpts"},
560     {0x137D, "ext"}, {0xEF51, "ext2"}, {0xEF53, "ext3"},
561     {0x1BADFACE, "bfs"}, {0x9123683E, "btrfs"}, {0x28cd3d45, "cramfs"},
562     {0x3153464a, "jfs"}, {0x7275, "romfs"}, {0x01021994, "tmpfs"},
563     {0x3434, "nilfs"}, {0x6969, "nfs"}, {0x9fa0, "proc"},
564     {0x534F434B, "sockfs"}, {0x62656572, "sysfs"}, {0x517B, "smb"},
565     {0x4d44, "msdos"}, {0x4006, "fat"}, {0x43415d53, "smackfs"},
566     {0x73717368, "squashfs"}, {0xF2F52010, "f2fs"}, {0xE0F5E1E2, "erofs"},
567     {0x2011BAB0, "exfat"},
568   };
569   int i;
570 
571   for (i=0; i<ARRAY_LEN(nn); i++)
572     if (nn[i].num == statfs->f_type) s = nn[i].name;
573   if (!s) sprintf(s = libbuf, "0x%x", (unsigned)statfs->f_type);
574   return s;
575 #endif
576 }
577 
578 #if defined(__APPLE__)
579 #include <sys/disk.h>
get_block_device_size(int fd,unsigned long long * size)580 int get_block_device_size(int fd, unsigned long long* size)
581 {
582   unsigned long block_size, block_count;
583 
584   if (!ioctl(fd, DKIOCGETBLOCKSIZE, &block_size) &&
585       !ioctl(fd, DKIOCGETBLOCKCOUNT, &block_count)) {
586     *size = block_count * block_size;
587     return 1;
588   }
589   return 0;
590 }
591 #elif defined(__linux__)
get_block_device_size(int fd,unsigned long long * size)592 int get_block_device_size(int fd, unsigned long long* size)
593 {
594   return (ioctl(fd, BLKGETSIZE64, size) >= 0);
595 }
596 #elif defined(__OpenBSD__)
597 #include <sys/dkio.h>
598 #include <sys/disklabel.h>
get_block_device_size(int fd,unsigned long long * size)599 int get_block_device_size(int fd, unsigned long long* size)
600 {
601   struct disklabel lab;
602   int status = (ioctl(fd, DIOCGDINFO, &lab) >= 0);
603   *size = lab.d_secsize * lab.d_nsectors;
604   return status;
605 }
606 #else
get_block_device_size(int fd,unsigned long long * size)607 int get_block_device_size(int fd, unsigned long long* size)
608 {
609   return 0;
610 }
611 #endif
612 
613 // Return bytes copied from in to out. If bytes <0 copy all of in to out.
614 // If consumed isn't null, amount read saved there (return is written or error)
sendfile_len(int in,int out,long long bytes,long long * consumed)615 long long sendfile_len(int in, int out, long long bytes, long long *consumed)
616 {
617   long long total = 0, len, ww;
618   int try_cfr = 1;
619 
620   if (consumed) *consumed = 0;
621   if (in>=0) while (bytes != total) {
622     ww = 0;
623     len = bytes-total;
624 
625     errno = 0;
626     if (try_cfr) {
627       if (bytes<0 || bytes>(1<<30)) len = (1<<30);
628       // glibc added this constant in git at the end of 2017, shipped 2018-02.
629       // Android's had the constant for years, but you'll get SIGSYS if you use
630       // this system call before Android U (2023's release).
631 #if defined(__NR_copy_file_range) && !defined(__ANDROID__)
632       len = syscall(__NR_copy_file_range, in, 0, out, 0, len, 0);
633 #else
634       errno = EINVAL;
635       len = -1;
636 #endif
637       if (len < 0) {
638         try_cfr = 0;
639 
640         continue;
641       }
642     } else {
643       if (bytes<0 || len>sizeof(libbuf)) len = sizeof(libbuf);
644       ww = len = read(in, libbuf, len);
645     }
646     if (len<1 && errno==EAGAIN) continue;
647     if (len<1) break;
648     if (consumed) *consumed += len;
649     if (ww && writeall(out, libbuf, len) != len) return -1;
650     total += len;
651   }
652 
653   return total;
654 }
655 
656 #ifdef __APPLE__
657 // The absolute minimum POSIX timer implementation to build timeout(1).
658 // Note that although timeout(1) uses POSIX timers to get the monotonic clock,
659 // that doesn't seem to be an option on macOS (without using other libraries),
660 // so we just mangle that back into a regular setitimer(ITIMER_REAL) call.
timer_create(clock_t c,struct sigevent * se,timer_t * t)661 int timer_create(clock_t c, struct sigevent *se, timer_t *t)
662 {
663   if (se->sigev_notify != SIGEV_SIGNAL || se->sigev_signo != SIGALRM)
664     error_exit("unimplemented");
665   *t = 1;
666   return 0;
667 }
668 
timer_settime(timer_t t,int flags,struct itimerspec * new,void * old)669 int timer_settime(timer_t t, int flags, struct itimerspec *new, void *old)
670 {
671   struct itimerval mangled;
672 
673   if (flags != 0 || old != 0) error_exit("unimplemented");
674   memset(&mangled, 0, sizeof(mangled));
675   mangled.it_value.tv_sec = new->it_value.tv_sec;
676   mangled.it_value.tv_usec = new->it_value.tv_nsec / 1000;
677   return setitimer(ITIMER_REAL, &mangled, NULL);
678 }
679 // glibc requires -lrt for linux syscalls, which pulls in libgcc_eh.a for
680 // static linking, and gcc 9.3 leaks pthread calls from that breaking the build
681 // These are both just linux syscalls: wrap them ourselves
682 #elif defined(__GLIBC__)
timer_create_wrap(clockid_t c,struct sigevent * se,timer_t * t)683 int timer_create_wrap(clockid_t c, struct sigevent *se, timer_t *t)
684 {
685   // convert overengineered structure to what kernel actually uses
686   struct ksigevent { void *sv; int signo, notify, tid; } kk = {
687     0, se->sigev_signo, se->sigev_notify, 0
688   };
689   int timer;
690 
691   if (syscall(SYS_timer_create, c, &kk, &timer)<0) return -1;
692   *t = (timer_t)(long)timer;
693 
694   return 0;
695 }
696 
697 #if !defined(SYS_timer_settime) && defined(SYS_timer_settime64)
698 // glibc does not define defines SYS_timer_settime on 32-bit systems
699 // with 64-bit time_t defaults e.g. riscv32
700 #define SYS_timer_settime SYS_timer_settime64
701 #endif
702 
timer_settime_wrap(timer_t t,int flags,struct itimerspec * val,struct itimerspec * old)703 int timer_settime_wrap(timer_t t, int flags, struct itimerspec *val,
704   struct itimerspec *old)
705 {
706   return syscall(SYS_timer_settime, t, flags, val, old);
707 }
708 #endif
709