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