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