1
2
3
4
5
6
7#include "toys.h"
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22#if CFG_TOYBOX_FORK
23pid_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
33int xgetrandom(void *buf, unsigned buflen, unsigned flags)
34{
35 int fd;
36
37
38
39
40
41#if __has_include(<sys/random.h>)
42 if (!getentropy(buf, buflen)) return 1;
43 if (errno!=ENOSYS && !(flags&WARN_ONLY)) perror_exit("getrandom");
44#endif
45 fd = xopen(flags ? "/dev/random" : "/dev/urandom",O_RDONLY|(flags&WARN_ONLY));
46 if (fd == -1) return 0;
47 xreadall(fd, buf, buflen);
48 close(fd);
49
50 return 1;
51}
52
53
54
55
56#if defined(__APPLE__) || defined(__FreeBSD__) || defined(__OpenBSD__)
57
58#include <sys/mount.h>
59
60struct mtab_list *xgetmountlist(char *path)
61{
62 struct mtab_list *mtlist = 0, *mt;
63 struct statfs *entries;
64 int i, count;
65
66 if (path) error_exit("xgetmountlist");
67 if ((count = getmntinfo(&entries, 0)) == 0) perror_exit("getmntinfo");
68
69
70
71
72
73 for (i = 0; i < count; ++i) {
74 struct statfs *me = &entries[i];
75
76 mt = xzalloc(sizeof(struct mtab_list) + strlen(me->f_fstypename) +
77 strlen(me->f_mntonname) + strlen(me->f_mntfromname) + strlen("") + 4);
78 dlist_add_nomalloc((void *)&mtlist, (void *)mt);
79
80
81
82 stat(me->f_mntonname, &(mt->stat));
83 statvfs(me->f_mntonname, &(mt->statvfs));
84
85
86 mt->dir = stpcpy(mt->type, me->f_fstypename)+1;
87 mt->device = stpcpy(mt->dir, me->f_mntonname)+1;
88 mt->opts = stpcpy(mt->device, me->f_mntfromname)+1;
89 strcpy(mt->opts, "");
90 }
91
92 return mtlist;
93}
94
95#else
96
97#include <mntent.h>
98
99static void octal_deslash(char *s)
100{
101 char *o = s;
102
103 while (*s) {
104 if (*s == '\\') {
105 int i, oct = 0;
106
107 for (i = 1; i < 4; i++) {
108 if (!isdigit(s[i])) break;
109 oct = (oct<<3)+s[i]-'0';
110 }
111 if (i == 4) {
112 *o++ = oct;
113 s += i;
114 continue;
115 }
116 }
117 *o++ = *s++;
118 }
119
120 *o = 0;
121}
122
123
124
125
126int mountlist_istype(struct mtab_list *ml, char *typelist)
127{
128 int len, skip;
129 char *t;
130
131 if (!typelist) return 1;
132
133
134 skip = strncmp(typelist, "no", 2);
135
136 for (;;) {
137 if (!(t = comma_iterate(&typelist, &len))) break;
138 if (!skip) {
139
140 strstart(&t, "no");
141 if (!strncmp(t, ml->type, len-2)) {
142 skip = 1;
143 break;
144 }
145 } else if (!strncmp(t, ml->type, len) && !ml->type[len]) {
146 skip = 0;
147 break;
148 }
149 }
150
151 return !skip;
152}
153
154struct mtab_list *xgetmountlist(char *path)
155{
156 struct mtab_list *mtlist = 0, *mt;
157 struct mntent *me;
158 FILE *fp;
159 char *p = path ? path : "/proc/mounts";
160
161 if (!(fp = setmntent(p, "r"))) perror_exit("bad %s", p);
162
163
164
165
166
167 while ((me = getmntent(fp))) {
168 mt = xzalloc(sizeof(struct mtab_list) + strlen(me->mnt_fsname) +
169 strlen(me->mnt_dir) + strlen(me->mnt_type) + strlen(me->mnt_opts) + 4);
170 dlist_add_nomalloc((void *)&mtlist, (void *)mt);
171
172
173
174 if (!path) {
175 stat(me->mnt_dir, &(mt->stat));
176 statvfs(me->mnt_dir, &(mt->statvfs));
177 }
178
179
180 mt->dir = stpcpy(mt->type, me->mnt_type)+1;
181 mt->device = stpcpy(mt->dir, me->mnt_dir)+1;
182 mt->opts = stpcpy(mt->device, me->mnt_fsname)+1;
183 strcpy(mt->opts, me->mnt_opts);
184
185 octal_deslash(mt->dir);
186 octal_deslash(mt->device);
187 }
188 endmntent(fp);
189
190 return mtlist;
191}
192
193#endif
194
195#if defined(__APPLE__) || defined(__FreeBSD__) || defined(__OpenBSD__)
196
197#include <sys/event.h>
198
199struct xnotify *xnotify_init(int max)
200{
201 struct xnotify *not = xzalloc(sizeof(struct xnotify));
202
203 not->max = max;
204 if ((not->kq = kqueue()) == -1) perror_exit("kqueue");
205 not->paths = xmalloc(max * sizeof(char *));
206 not->fds = xmalloc(max * sizeof(int));
207
208 return not;
209}
210
211int xnotify_add(struct xnotify *not, int fd, char *path)
212{
213 struct kevent event;
214
215 if (not->count == not->max) error_exit("xnotify_add overflow");
216 EV_SET(&event, fd, EVFILT_VNODE, EV_ADD|EV_CLEAR, NOTE_WRITE, 0, NULL);
217 if (kevent(not->kq, &event, 1, NULL, 0, NULL) == -1 || event.flags & EV_ERROR)
218 error_exit("xnotify_add failed on %s", path);
219 not->paths[not->count] = path;
220 not->fds[not->count++] = fd;
221
222 return 0;
223}
224
225int xnotify_wait(struct xnotify *not, char **path)
226{
227 struct kevent event;
228 int i;
229
230 for (;;) {
231 if (kevent(not->kq, NULL, 0, &event, 1, NULL) != -1) {
232
233 for (i = 0; i<not->count; i++) if (not->fds[i]==event.ident) {
234 *path = not->paths[i];
235
236 return event.ident;
237 }
238 }
239 }
240}
241
242#else
243
244#include <sys/inotify.h>
245
246struct xnotify *xnotify_init(int max)
247{
248 struct xnotify *not = xzalloc(sizeof(struct xnotify));
249
250 not->max = max;
251 if ((not->kq = inotify_init()) < 0) perror_exit("inotify_init");
252 not->paths = xmalloc(max * sizeof(char *));
253 not->fds = xmalloc(max * 2 * sizeof(int));
254
255 return not;
256}
257
258int xnotify_add(struct xnotify *not, int fd, char *path)
259{
260 int i = 2*not->count;
261
262 if (not->max == not->count) error_exit("xnotify_add overflow");
263 if ((not->fds[i] = inotify_add_watch(not->kq, path, IN_MODIFY))==-1)
264 perror_exit("xnotify_add failed on %s", path);
265 not->fds[i+1] = fd;
266 not->paths[not->count++] = path;
267
268 return 0;
269}
270
271int xnotify_wait(struct xnotify *not, char **path)
272{
273 struct inotify_event ev;
274 int i;
275
276 for (;;) {
277 if (sizeof(ev)!=read(not->kq, &ev, sizeof(ev))) perror_exit("inotify");
278
279 for (i = 0; i<not->count; i++) if (ev.wd==not->fds[2*i]) {
280 *path = not->paths[i];
281
282 return not->fds[2*i+1];
283 }
284 }
285}
286
287#endif
288
289#ifdef __APPLE__
290
291ssize_t xattr_get(const char *path, const char *name, void *value, size_t size)
292{
293 return getxattr(path, name, value, size, 0, 0);
294}
295
296ssize_t xattr_lget(const char *path, const char *name, void *value, size_t size)
297{
298 return getxattr(path, name, value, size, 0, XATTR_NOFOLLOW);
299}
300
301ssize_t xattr_fget(int fd, const char *name, void *value, size_t size)
302{
303 return fgetxattr(fd, name, value, size, 0, 0);
304}
305
306ssize_t xattr_list(const char *path, char *list, size_t size)
307{
308 return listxattr(path, list, size, 0);
309}
310
311ssize_t xattr_llist(const char *path, char *list, size_t size)
312{
313 return listxattr(path, list, size, XATTR_NOFOLLOW);
314}
315
316ssize_t xattr_flist(int fd, char *list, size_t size)
317{
318 return flistxattr(fd, list, size, 0);
319}
320
321ssize_t xattr_set(const char* path, const char* name,
322 const void* value, size_t size, int flags)
323{
324 return setxattr(path, name, value, size, 0, flags);
325}
326
327ssize_t xattr_lset(const char* path, const char* name,
328 const void* value, size_t size, int flags)
329{
330 return setxattr(path, name, value, size, 0, flags | XATTR_NOFOLLOW);
331}
332
333ssize_t xattr_fset(int fd, const char* name,
334 const void* value, size_t size, int flags)
335{
336 return fsetxattr(fd, name, value, size, 0, flags);
337}
338
339#elif !defined(__FreeBSD__) && !defined(__OpenBSD__)
340
341ssize_t xattr_get(const char *path, const char *name, void *value, size_t size)
342{
343 return getxattr(path, name, value, size);
344}
345
346ssize_t xattr_lget(const char *path, const char *name, void *value, size_t size)
347{
348 return lgetxattr(path, name, value, size);
349}
350
351ssize_t xattr_fget(int fd, const char *name, void *value, size_t size)
352{
353 return fgetxattr(fd, name, value, size);
354}
355
356ssize_t xattr_list(const char *path, char *list, size_t size)
357{
358 return listxattr(path, list, size);
359}
360
361ssize_t xattr_llist(const char *path, char *list, size_t size)
362{
363 return llistxattr(path, list, size);
364}
365
366ssize_t xattr_flist(int fd, char *list, size_t size)
367{
368 return flistxattr(fd, list, size);
369}
370
371ssize_t xattr_set(const char* path, const char* name,
372 const void* value, size_t size, int flags)
373{
374 return setxattr(path, name, value, size, flags);
375}
376
377ssize_t xattr_lset(const char* path, const char* name,
378 const void* value, size_t size, int flags)
379{
380 return lsetxattr(path, name, value, size, flags);
381}
382
383ssize_t xattr_fset(int fd, const char* name,
384 const void* value, size_t size, int flags)
385{
386 return fsetxattr(fd, name, value, size, flags);
387}
388
389
390#endif
391
392#ifdef __APPLE__
393
394
395int mknodat(int dirfd, const char *path, mode_t mode, dev_t dev)
396{
397 int old_dirfd = open(".", O_RDONLY), result;
398
399 if (old_dirfd == -1 || fchdir(dirfd) == -1) return -1;
400 result = mknod(path, mode, dev);
401 if (fchdir(old_dirfd) == -1) perror_exit("mknodat couldn't return");
402 return result;
403}
404
405
406
407int posix_fallocate(int fd, off_t offset, off_t length)
408{
409 int e = errno, result;
410 fstore_t f;
411
412 f.fst_flags = F_ALLOCATEALL;
413 f.fst_posmode = F_PEOFPOSMODE;
414 f.fst_offset = offset;
415 f.fst_length = length;
416 if (fcntl(fd, F_PREALLOCATE, &f) == -1) result = errno;
417 else result = ftruncate(fd, length);
418 errno = e;
419 return result;
420}
421#endif
422
423
424
425
426#define SIGNIFY(x) {SIG##x, #x}
427
428static const struct signame signames[] = {
429 {0, "0"},
430
431 SIGNIFY(ABRT), SIGNIFY(ALRM), SIGNIFY(BUS),
432 SIGNIFY(FPE), SIGNIFY(HUP), SIGNIFY(ILL), SIGNIFY(INT), SIGNIFY(KILL),
433 SIGNIFY(PIPE), SIGNIFY(QUIT), SIGNIFY(SEGV), SIGNIFY(TERM),
434 SIGNIFY(USR1), SIGNIFY(USR2), SIGNIFY(SYS), SIGNIFY(TRAP),
435 SIGNIFY(VTALRM), SIGNIFY(XCPU), SIGNIFY(XFSZ),
436
437 SIGNIFY(PROF), SIGNIFY(IO),
438
439#ifdef SIGEMT
440 SIGNIFY(EMT),
441#endif
442#ifdef SIGINFO
443 SIGNIFY(INFO),
444#endif
445#ifdef SIGPOLL
446 SIGNIFY(POLL),
447#endif
448#ifdef SIGPWR
449 SIGNIFY(PWR),
450#endif
451#ifdef SIGSTKFLT
452 SIGNIFY(STKFLT),
453#endif
454
455
456
457
458
459 SIGNIFY(CHLD), SIGNIFY(CONT), SIGNIFY(STOP), SIGNIFY(TSTP),
460 SIGNIFY(TTIN), SIGNIFY(TTOU), SIGNIFY(URG),
461
462 SIGNIFY(WINCH),
463};
464
465#undef SIGNIFY
466
467void xsignal_all_killers(void *handler)
468{
469 int i;
470
471 for (i = 1; signames[i].num != SIGCHLD; i++)
472 if (signames[i].num != SIGKILL) xsignal(signames[i].num, handler);
473}
474
475
476int sig_to_num(char *sigstr)
477{
478 int i, offset;
479 char *s;
480
481
482 offset = estrtol(sigstr, &s, 10);
483 if (!errno && !*s) return offset;
484
485
486 strcasestart(&sigstr, "sig");
487
488
489 for (i=0; i<ARRAY_LEN(signames); i++)
490 if (!strcasecmp(sigstr, signames[i].name)) return signames[i].num;
491
492
493#ifdef SIGRTMIN
494 if (strcasestart(&sigstr, "rtmin")) i = SIGRTMIN;
495 else if (strcasestart(&sigstr, "rtmax")) i = SIGRTMAX;
496 else return -1;
497
498
499 if (!*sigstr) return i;
500
501
502
503 offset = estrtol(sigstr, &s, 10);
504 if (errno || *s) return -1;
505 i += offset;
506 if (i >= SIGRTMIN && i <= SIGRTMAX) return i;
507#endif
508
509 return -1;
510}
511
512char *num_to_sig(int sig)
513{
514 int i;
515
516
517 for (i=0; i<ARRAY_LEN(signames); i++)
518 if (signames[i].num == sig) return signames[i].name;
519
520
521#ifdef SIGRTMIN
522 if (sig == SIGRTMIN) return "RTMIN";
523 if (sig == SIGRTMAX) return "RTMAX";
524 if (sig > SIGRTMIN && sig < SIGRTMAX) {
525 if (sig-SIGRTMIN <= SIGRTMAX-sig) sprintf(libbuf, "RTMIN+%d", sig-SIGRTMIN);
526 else sprintf(libbuf, "RTMAX-%d", SIGRTMAX-sig);
527 return libbuf;
528 }
529#endif
530
531 return NULL;
532}
533
534int dev_minor(int dev)
535{
536#if defined(__linux__)
537 return ((dev&0xfff00000)>>12)|(dev&0xff);
538#elif defined(__APPLE__)
539 return dev&0xffffff;
540#elif defined(__FreeBSD__) || defined(__OpenBSD__)
541 return minor(dev);
542#else
543#error
544#endif
545}
546
547int dev_major(int dev)
548{
549#if defined(__linux__)
550 return (dev&0xfff00)>>8;
551#elif defined(__APPLE__)
552 return (dev>>24)&0xff;
553#elif defined(__FreeBSD__) || defined(__OpenBSD__)
554 return major(dev);
555#else
556#error
557#endif
558}
559
560int dev_makedev(int major, int minor)
561{
562#if defined(__linux__)
563 return (minor&0xff)|((major&0xfff)<<8)|((minor&0xfff00)<<12);
564#elif defined(__APPLE__)
565 return (minor&0xffffff)|((major&0xff)<<24);
566#elif defined(__FreeBSD__) || defined(__OpenBSD__)
567 return makedev(major, minor);
568#else
569#error
570#endif
571}
572
573char *fs_type_name(struct statfs *statfs)
574{
575#if defined(__APPLE__) || defined(__FreeBSD__) || defined(__OpenBSD__)
576
577
578 return statfs->f_fstypename;
579#else
580 char *s = NULL;
581 struct {unsigned num; char *name;} nn[] = {
582 {0xADFF, "affs"}, {0x5346544e, "ntfs"}, {0x1Cd1, "devpts"},
583 {0x137D, "ext"}, {0xEF51, "ext2"}, {0xEF53, "ext3"},
584 {0x1BADFACE, "bfs"}, {0x9123683E, "btrfs"}, {0x28cd3d45, "cramfs"},
585 {0x3153464a, "jfs"}, {0x7275, "romfs"}, {0x01021994, "tmpfs"},
586 {0x3434, "nilfs"}, {0x6969, "nfs"}, {0x9fa0, "proc"},
587 {0x534F434B, "sockfs"}, {0x62656572, "sysfs"}, {0x517B, "smb"},
588 {0x4d44, "msdos"}, {0x4006, "fat"}, {0x43415d53, "smackfs"},
589 {0x73717368, "squashfs"}
590 };
591 int i;
592
593 for (i=0; i<ARRAY_LEN(nn); i++)
594 if (nn[i].num == statfs->f_type) s = nn[i].name;
595 if (!s) sprintf(s = libbuf, "0x%x", (unsigned)statfs->f_type);
596 return s;
597#endif
598}
599
600#if defined(__APPLE__)
601#include <sys/disk.h>
602int get_block_device_size(int fd, unsigned long long* size)
603{
604 unsigned long block_size, block_count;
605
606 if (!ioctl(fd, DKIOCGETBLOCKSIZE, &block_size) &&
607 !ioctl(fd, DKIOCGETBLOCKCOUNT, &block_count)) {
608 *size = block_count * block_size;
609 return 1;
610 }
611 return 0;
612}
613#elif defined(__linux__)
614int get_block_device_size(int fd, unsigned long long* size)
615{
616 return (ioctl(fd, BLKGETSIZE64, size) >= 0);
617}
618#elif defined(__OpenBSD__)
619#include <sys/dkio.h>
620#include <sys/disklabel.h>
621int get_block_device_size(int fd, unsigned long long* size)
622{
623 struct disklabel lab;
624 int status = (ioctl(fd, DIOCGDINFO, &lab) >= 0);
625 *size = lab.d_secsize * lab.d_nsectors;
626 return status;
627}
628#endif
629
630
631
632long long sendfile_len(int in, int out, long long bytes, long long *consumed)
633{
634 long long total = 0, len, ww;
635 int try_cfr = 1;
636
637 if (consumed) *consumed = 0;
638 if (in>=0) while (bytes != total) {
639 ww = 0;
640 len = bytes-total;
641
642 errno = 0;
643 if (try_cfr) {
644 if (bytes<0 || bytes>(1<<30)) len = (1<<30);
645
646
647
648#if defined(__NR_copy_file_range) && !defined(__ANDROID__)
649 len = syscall(__NR_copy_file_range, in, 0, out, 0, len, 0);
650#else
651 errno = EINVAL;
652 len = -1;
653#endif
654 if (len < 0 && errno == EINVAL) {
655 try_cfr = 0;
656
657 continue;
658 }
659 } else {
660 if (bytes<0 || len>sizeof(libbuf)) len = sizeof(libbuf);
661 ww = len = read(in, libbuf, len);
662 }
663 if (len<1 && errno==EAGAIN) continue;
664 if (len<1) break;
665 if (consumed) *consumed += len;
666 if (ww && writeall(out, libbuf, len) != len) return -1;
667 total += len;
668 }
669
670 return total;
671}
672
673#ifdef __APPLE__
674
675
676
677
678int timer_create(clock_t c, struct sigevent *se, timer_t *t)
679{
680 if (se->sigev_notify != SIGEV_SIGNAL || se->sigev_signo != SIGALRM)
681 error_exit("unimplemented");
682 *t = 1;
683 return 0;
684}
685
686int timer_settime(timer_t t, int flags, struct itimerspec *new, void *old)
687{
688 struct itimerval mangled;
689
690 if (flags != 0 || old != 0) error_exit("unimplemented");
691 memset(&mangled, 0, sizeof(mangled));
692 mangled.it_value.tv_sec = new->it_value.tv_sec;
693 mangled.it_value.tv_usec = new->it_value.tv_nsec / 1000;
694 return setitimer(ITIMER_REAL, &mangled, NULL);
695}
696
697
698
699#elif defined(__GLIBC__)
700int timer_create_wrap(clockid_t c, struct sigevent *se, timer_t *t)
701{
702
703 struct ksigevent { void *sv; int signo, notify, tid; } kk = {
704 0, se->sigev_signo, se->sigev_notify, 0
705 };
706 int timer;
707
708 if (syscall(SYS_timer_create, c, &kk, &timer)<0) return -1;
709 *t = (timer_t)(long)timer;
710
711 return 0;
712}
713
714int timer_settime_wrap(timer_t t, int flags, struct itimerspec *val,
715 struct itimerspec *old)
716{
717 return syscall(SYS_timer_settime, t, flags, val, old);
718}
719#endif
720