1
2
3
4
5
6#define SYSLOG_NAMES
7#include "toys.h"
8
9void verror_msg(char *msg, int err, va_list va)
10{
11 char *s = ": %s";
12
13 fprintf(stderr, "%s: ", toys.which->name);
14 if (msg) vfprintf(stderr, msg, va);
15 else s+=2;
16 if (err>0) fprintf(stderr, s, strerror(err));
17 if (err<0 && CFG_TOYBOX_HELP)
18 fprintf(stderr, " (see \"%s --help\")", toys.which->name);
19 if (msg || err) putc('\n', stderr);
20 if (!toys.exitval) toys.exitval++;
21}
22
23
24
25void error_msg(char *msg, ...)
26{
27 va_list va;
28
29 va_start(va, msg);
30 verror_msg(msg, 0, va);
31 va_end(va);
32}
33
34void perror_msg(char *msg, ...)
35{
36 va_list va;
37
38 va_start(va, msg);
39 verror_msg(msg, errno, va);
40 va_end(va);
41}
42
43
44void error_exit(char *msg, ...)
45{
46 va_list va;
47
48 va_start(va, msg);
49 verror_msg(msg, 0, va);
50 va_end(va);
51
52 xexit();
53}
54
55
56void perror_exit(char *msg, ...)
57{
58
59 if (errno != EPIPE) {
60 va_list va;
61
62 va_start(va, msg);
63 verror_msg(msg, errno, va);
64 va_end(va);
65 }
66
67 xexit();
68}
69
70
71void help_exit(char *msg, ...)
72{
73 va_list va;
74
75 if (!msg) show_help(stdout);
76 else {
77 va_start(va, msg);
78 verror_msg(msg, -1, va);
79 va_end(va);
80 }
81
82 xexit();
83}
84
85
86
87
88
89void error_msg_raw(char *msg)
90{
91 error_msg("%s", msg);
92}
93
94void perror_msg_raw(char *msg)
95{
96 perror_msg("%s", msg);
97}
98
99void error_exit_raw(char *msg)
100{
101 error_exit("%s", msg);
102}
103
104void perror_exit_raw(char *msg)
105{
106 perror_exit("%s", msg);
107}
108
109
110ssize_t readall(int fd, void *buf, size_t len)
111{
112 size_t count = 0;
113
114 while (count<len) {
115 int i = read(fd, (char *)buf+count, len-count);
116 if (!i) break;
117 if (i<0) return i;
118 count += i;
119 }
120
121 return count;
122}
123
124
125ssize_t writeall(int fd, void *buf, size_t len)
126{
127 size_t count = 0;
128
129 while (count<len) {
130 int i = write(fd, count+(char *)buf, len-count);
131 if (i<1) return i;
132 count += i;
133 }
134
135 return count;
136}
137
138
139
140off_t lskip(int fd, off_t offset)
141{
142 off_t cur = lseek(fd, 0, SEEK_CUR);
143
144 if (cur != -1) {
145 off_t end = lseek(fd, 0, SEEK_END) - cur;
146
147 if (end > 0 && end < offset) return offset - end;
148 end = offset+cur;
149 if (end == lseek(fd, end, SEEK_SET)) return 0;
150 perror_exit("lseek");
151 }
152
153 while (offset>0) {
154 int try = offset>sizeof(libbuf) ? sizeof(libbuf) : offset, or;
155
156 or = readall(fd, libbuf, try);
157 if (or < 0) perror_exit("lskip to %lld", (long long)offset);
158 else offset -= or;
159 if (or < try) break;
160 }
161
162 return offset;
163}
164
165
166
167
168
169int mkpathat(int atfd, char *dir, mode_t lastmode, int flags)
170{
171 struct stat buf;
172 char *s;
173
174
175
176
177
178
179 if (!fstatat(atfd, dir, &buf, 0) && !S_ISDIR(buf.st_mode)) {
180 errno = EEXIST;
181 return 1;
182 }
183
184 for (s = dir; ;s++) {
185 char save = 0;
186 mode_t mode = (0777&~toys.old_umask)|0300;
187
188
189 if (*s == '/' && (flags&2) && s != dir) {
190 save = *s;
191 *s = 0;
192 } else if (*s) continue;
193
194
195 if (!save) {
196 if (flags&1) mode = lastmode;
197 else break;
198 }
199
200 if (mkdirat(atfd, dir, mode)) {
201 if (!(flags&2) || errno != EEXIST) return 1;
202 } else if (flags&4)
203 fprintf(stderr, "%s: created directory '%s'\n", toys.which->name, dir);
204
205 if (!(*s = save)) break;
206 }
207
208 return 0;
209}
210
211
212int mkpath(char *dir)
213{
214 return mkpathat(AT_FDCWD, dir, 0, MKPATHAT_MAKE);
215}
216
217
218
219struct string_list **splitpath(char *path, struct string_list **list)
220{
221 char *new = path;
222
223 *list = 0;
224 do {
225 int len;
226
227 if (*path && *path != '/') continue;
228 len = path-new;
229 if (len > 0) {
230 *list = xmalloc(sizeof(struct string_list) + len + 1);
231 (*list)->next = 0;
232 memcpy((*list)->str, new, len);
233 (*list)->str[len] = 0;
234 list = &(*list)->next;
235 }
236 new = path+1;
237 } while (*path++);
238
239 return list;
240}
241
242
243
244
245
246struct string_list *find_in_path(char *path, char *filename)
247{
248 struct string_list *rlist = NULL, **prlist=&rlist;
249 char *cwd;
250
251 if (!path) return 0;
252
253 cwd = xgetcwd();
254 for (;;) {
255 char *res, *next = strchr(path, ':');
256 int len = next ? next-path : strlen(path);
257 struct string_list *rnext;
258 struct stat st;
259
260 rnext = xmalloc(sizeof(void *) + strlen(filename)
261 + (len ? len : strlen(cwd)) + 2);
262 if (!len) sprintf(rnext->str, "%s/%s", cwd, filename);
263 else {
264 memcpy(res = rnext->str, path, len);
265 res += len;
266 *(res++) = '/';
267 strcpy(res, filename);
268 }
269
270
271 if (!stat(rnext->str, &st) && S_ISREG(st.st_mode)) {
272 *prlist = rnext;
273 rnext->next = NULL;
274 prlist = &(rnext->next);
275 } else free(rnext);
276
277 if (!next) break;
278 path += len;
279 path++;
280 }
281 free(cwd);
282
283 return rlist;
284}
285
286long long estrtol(char *str, char **end, int base)
287{
288 errno = 0;
289
290 return strtoll(str, end, base);
291}
292
293long long xstrtol(char *str, char **end, int base)
294{
295 long long l = estrtol(str, end, base);
296
297 if (errno) perror_exit_raw(str);
298
299 return l;
300}
301
302
303
304long long atolx(char *numstr)
305{
306 char *c = numstr, *suffixes="cwbkmgtpe", *end;
307 long long val;
308
309 val = xstrtol(numstr, &c, 0);
310 if (c != numstr && *c && (end = strchr(suffixes, tolower(*c)))) {
311 int shift = end-suffixes-2;
312 ++c;
313 if (shift==-1) val *= 2;
314 else if (!shift) val *= 512;
315 else if (shift>0) {
316 if (*c && tolower(*c++)=='d') while (shift--) val *= 1000;
317 else val *= 1LL<<(shift*10);
318 }
319 }
320 while (isspace(*c)) c++;
321 if (c==numstr || *c) error_exit("not integer: %s", numstr);
322
323 return val;
324}
325
326long long atolx_range(char *numstr, long long low, long long high)
327{
328 long long val = atolx(numstr);
329
330 if (val < low) error_exit("%lld < %lld", val, low);
331 if (val > high) error_exit("%lld > %lld", val, high);
332
333 return val;
334}
335
336int stridx(char *haystack, char needle)
337{
338 char *off;
339
340 if (!needle) return -1;
341 off = strchr(haystack, needle);
342 if (!off) return -1;
343
344 return off-haystack;
345}
346
347
348int utf8towc(wchar_t *wc, char *str, unsigned len)
349{
350 unsigned result, mask, first;
351 char *s, c;
352
353
354 if (len && *str<128) return !!(*wc = *str);
355
356 result = first = *(s = str++);
357 if (result<0xc2 || result>0xf4) return -1;
358 for (mask = 6; (first&0xc0)==0xc0; mask += 5, first <<= 1) {
359 if (!--len) return -2;
360 if (((c = *(str++))&0xc0) != 0x80) return -1;
361 result = (result<<6)|(c&0x3f);
362 }
363 result &= (1<<mask)-1;
364 c = str-s;
365
366
367 if (result<(unsigned []){0x80,0x800,0x10000}[c-2]) return -1;
368
369
370 if (result>0x10ffff || (result>=0xd800 && result<=0xdfff)) return -1;
371 *wc = result;
372
373 return str-s;
374}
375
376char *strlower(char *s)
377{
378 char *try, *new;
379
380 if (!CFG_TOYBOX_I18N) {
381 try = new = xstrdup(s);
382 for (; *s; s++) *(new++) = tolower(*s);
383 } else {
384
385 try = new = xmalloc(strlen(s)*2+1);
386
387 while (*s) {
388 wchar_t c;
389 int len = utf8towc(&c, s, MB_CUR_MAX);
390
391 if (len < 1) *(new++) = *(s++);
392 else {
393 s += len;
394
395 c = towlower(c);
396
397
398
399
400 len = wcrtomb(new, c, 0);
401 if (len < 1) error_exit("bad utf8 %x", (int)c);
402 new += len;
403 }
404 }
405 *new = 0;
406 }
407
408 return try;
409}
410
411
412char *strafter(char *haystack, char *needle)
413{
414 char *s = strstr(haystack, needle);
415
416 return s ? s+strlen(needle) : s;
417}
418
419
420char *chomp(char *s)
421{
422 char *p = strrchr(s, '\n');
423
424 if (p && !p[1]) *p = 0;
425 return s;
426}
427
428int unescape(char c)
429{
430 char *from = "\\abefnrtv", *to = "\\\a\b\033\f\n\r\t\v";
431 int idx = stridx(from, c);
432
433 return (idx == -1) ? 0 : to[idx];
434}
435
436
437
438char *strend(char *str, char *suffix)
439{
440 long a = strlen(str), b = strlen(suffix);
441
442 if (a>b && !strcmp(str += a-b, suffix)) return str;
443
444 return 0;
445}
446
447
448int strstart(char **a, char *b)
449{
450 int len = strlen(b), i = !strncmp(*a, b, len);
451
452 if (i) *a += len;
453
454 return i;
455}
456
457
458off_t fdlength(int fd)
459{
460 struct stat st;
461 off_t base = 0, range = 1, expand = 1, old;
462
463 if (!fstat(fd, &st) && S_ISREG(st.st_mode)) return st.st_size;
464
465
466
467
468
469
470
471
472
473
474
475
476 old = lseek(fd, 0, SEEK_CUR);
477 do {
478 char temp;
479 off_t pos = base + range / 2;
480
481 if (lseek(fd, pos, 0)>=0 && read(fd, &temp, 1)==1) {
482 off_t delta = (pos + 1) - base;
483
484 base += delta;
485 if (expand) range = (expand <<= 1) - base;
486 else range -= delta;
487 } else {
488 expand = 0;
489 range = pos - base;
490 }
491 } while (range > 0);
492
493 lseek(fd, old, SEEK_SET);
494
495 return base;
496}
497
498
499
500
501
502char *readfileat(int dirfd, char *name, char *ibuf, off_t *plen)
503{
504 off_t len, rlen;
505 int fd;
506 char *buf, *rbuf;
507
508
509 if (CFG_TOYBOX_DEBUG && (ibuf ? !*plen : *plen)) error_exit("bad readfileat");
510
511 if (-1 == (fd = openat(dirfd, name, O_RDONLY))) return 0;
512
513
514 if (!*plen) {
515 if ((len = fdlength(fd))>0) *plen = len;
516 else len = 4096;
517 } else len = *plen-1;
518
519 if (!ibuf) buf = xmalloc(len+1);
520 else buf = ibuf;
521
522 for (rbuf = buf;;) {
523 rlen = readall(fd, rbuf, len);
524 if (*plen || rlen<len) break;
525
526
527 rlen += rbuf-buf;
528 buf = xrealloc(buf, len = (rlen*3)/2);
529 rbuf = buf+rlen;
530 len -= rlen;
531 }
532 *plen = len = rlen+(rbuf-buf);
533 close(fd);
534
535 if (rlen<0) {
536 if (ibuf != buf) free(buf);
537 buf = 0;
538 } else buf[len] = 0;
539
540 return buf;
541}
542
543char *readfile(char *name, char *ibuf, off_t len)
544{
545 return readfileat(AT_FDCWD, name, ibuf, &len);
546}
547
548
549void msleep(long milliseconds)
550{
551 struct timespec ts;
552
553 ts.tv_sec = milliseconds/1000;
554 ts.tv_nsec = (milliseconds%1000)*1000000;
555 nanosleep(&ts, &ts);
556}
557
558
559void nanomove(struct timespec *ts, long long offset)
560{
561 long long nano = ts->tv_nsec + offset, secs = nano/1000000000;
562
563 ts->tv_sec += secs;
564 nano %= 1000000000;
565 if (nano<0) {
566 ts->tv_sec--;
567 nano += 1000000000;
568 }
569 ts->tv_nsec = nano;
570}
571
572
573long long nanodiff(struct timespec *old, struct timespec *new)
574{
575 return (new->tv_sec - old->tv_sec)*1000000000LL+(new->tv_nsec - old->tv_nsec);
576}
577
578
579int highest_bit(unsigned long l)
580{
581 int i;
582
583 for (i = 0; l; i++) l >>= 1;
584
585 return i-1;
586}
587
588
589int64_t peek_le(void *ptr, unsigned size)
590{
591 int64_t ret = 0;
592 char *c = ptr;
593 int i;
594
595 for (i=0; i<size; i++) ret |= ((int64_t)c[i])<<(i*8);
596 return ret;
597}
598
599int64_t peek_be(void *ptr, unsigned size)
600{
601 int64_t ret = 0;
602 char *c = ptr;
603 int i;
604
605 for (i=0; i<size; i++) ret = (ret<<8)|(c[i]&0xff);
606 return ret;
607}
608
609int64_t peek(void *ptr, unsigned size)
610{
611 return (IS_BIG_ENDIAN ? peek_be : peek_le)(ptr, size);
612}
613
614void poke_le(void *ptr, long long val, unsigned size)
615{
616 char *c = ptr;
617
618 while (size--) {
619 *c++ = val&255;
620 val >>= 8;
621 }
622}
623
624void poke_be(void *ptr, long long val, unsigned size)
625{
626 char *c = ptr + size;
627
628 while (size--) {
629 *--c = val&255;
630 val >>=8;
631 }
632}
633
634void poke(void *ptr, long long val, unsigned size)
635{
636 (IS_BIG_ENDIAN ? poke_be : poke_le)(ptr, val, size);
637}
638
639
640
641
642
643
644
645
646
647
648void loopfiles_rw(char **argv, int flags, int permissions,
649 void (*function)(int fd, char *name))
650{
651 int fd, failok = !(flags&WARN_ONLY);
652
653 flags &= ~WARN_ONLY;
654
655
656 if (!*argv) function((flags & O_ACCMODE) != O_RDONLY ? 1 : 0, "-");
657 else do {
658
659
660
661 if (!strcmp(*argv, "-")) fd = 0;
662 else if (0>(fd = notstdio(open(*argv, flags, permissions))) && !failok) {
663 perror_msg_raw(*argv);
664 continue;
665 }
666 function(fd, *argv);
667 if ((flags & O_CLOEXEC) && fd) close(fd);
668 } while (*++argv);
669}
670
671
672void loopfiles(char **argv, void (*function)(int fd, char *name))
673{
674 loopfiles_rw(argv, O_RDONLY|O_CLOEXEC|WARN_ONLY, 0, function);
675}
676
677
678static void (*do_lines_bridge)(char **pline, long len);
679static void loopfile_lines_bridge(int fd, char *name)
680{
681 do_lines(fd, '\n', do_lines_bridge);
682}
683
684void loopfiles_lines(char **argv, void (*function)(char **pline, long len))
685{
686 do_lines_bridge = function;
687 loopfiles(argv, loopfile_lines_bridge);
688}
689
690
691
692char *get_rawline(int fd, long *plen, char end)
693{
694 char c, *buf = NULL;
695 long len = 0;
696
697 for (;;) {
698 if (1>read(fd, &c, 1)) break;
699 if (!(len & 63)) buf=xrealloc(buf, len+65);
700 if ((buf[len++]=c) == end) break;
701 }
702 if (buf) buf[len]=0;
703 if (plen) *plen = len;
704
705 return buf;
706}
707
708char *get_line(int fd)
709{
710 long len;
711 char *buf = get_rawline(fd, &len, '\n');
712
713 if (buf && buf[--len]=='\n') buf[len]=0;
714
715 return buf;
716}
717
718int wfchmodat(int fd, char *name, mode_t mode)
719{
720 int rc = fchmodat(fd, name, mode, 0);
721
722 if (rc) {
723 perror_msg("chmod '%s' to %04o", name, mode);
724 toys.exitval=1;
725 }
726 return rc;
727}
728
729static char *tempfile2zap;
730static void tempfile_handler(void)
731{
732 if (1 < (long)tempfile2zap) unlink(tempfile2zap);
733}
734
735
736int copy_tempfile(int fdin, char *name, char **tempname)
737{
738 struct stat statbuf;
739 int fd = xtempfile(name, tempname), ignored __attribute__((__unused__));
740
741
742 if (!tempfile2zap) sigatexit(tempfile_handler);
743 tempfile2zap = *tempname;
744
745
746 if (!fstat(fdin, &statbuf)) fchmod(fd, statbuf.st_mode);
747
748
749
750
751
752
753 ignored = fchown(fd, statbuf.st_uid, statbuf.st_gid);
754
755 return fd;
756}
757
758
759void delete_tempfile(int fdin, int fdout, char **tempname)
760{
761 close(fdin);
762 close(fdout);
763 if (*tempname) unlink(*tempname);
764 tempfile2zap = (char *)1;
765 free(*tempname);
766 *tempname = NULL;
767}
768
769
770void replace_tempfile(int fdin, int fdout, char **tempname)
771{
772 char *temp = xstrdup(*tempname);
773
774 temp[strlen(temp)-6]=0;
775 if (fdin != -1) {
776 xsendfile(fdin, fdout);
777 xclose(fdin);
778 }
779 xclose(fdout);
780 xrename(*tempname, temp);
781 tempfile2zap = (char *)1;
782 free(*tempname);
783 free(temp);
784 *tempname = NULL;
785}
786
787
788
789void crc_init(unsigned int *crc_table, int little_endian)
790{
791 unsigned int i;
792
793
794 for (i=0; i<256; i++) {
795 unsigned int j, c = little_endian ? i : i<<24;
796 for (j=8; j; j--)
797 if (little_endian) c = (c&1) ? (c>>1)^0xEDB88320 : c>>1;
798 else c=c&0x80000000 ? (c<<1)^0x04c11db7 : (c<<1);
799 crc_table[i] = c;
800 }
801}
802
803
804
805void base64_init(char *p)
806{
807 int i;
808
809 for (i = 'A'; i != ':'; i++) {
810 if (i == 'Z'+1) i = 'a';
811 if (i == 'z'+1) i = '0';
812 *(p++) = i;
813 }
814 *(p++) = '+';
815 *(p++) = '/';
816}
817
818int yesno(int def)
819{
820 char buf;
821
822 fprintf(stderr, " (%c/%c):", def ? 'Y' : 'y', def ? 'n' : 'N');
823 fflush(stderr);
824 while (fread(&buf, 1, 1, stdin)) {
825 int new;
826
827
828 if (isspace(buf)) break;
829 if (-1 != (new = stridx("ny", tolower(buf)))) def = new;
830 }
831
832 return def;
833}
834
835struct signame {
836 int num;
837 char *name;
838};
839
840
841
842
843#define SIGNIFY(x) {SIG##x, #x}
844
845static struct signame signames[] = {
846 SIGNIFY(ABRT), SIGNIFY(ALRM), SIGNIFY(BUS),
847 SIGNIFY(FPE), SIGNIFY(HUP), SIGNIFY(ILL), SIGNIFY(INT), SIGNIFY(KILL),
848 SIGNIFY(PIPE), SIGNIFY(QUIT), SIGNIFY(SEGV), SIGNIFY(TERM),
849 SIGNIFY(USR1), SIGNIFY(USR2), SIGNIFY(SYS), SIGNIFY(TRAP),
850 SIGNIFY(VTALRM), SIGNIFY(XCPU), SIGNIFY(XFSZ),
851
852
853
854 SIGNIFY(CHLD), SIGNIFY(CONT), SIGNIFY(STOP), SIGNIFY(TSTP),
855 SIGNIFY(TTIN), SIGNIFY(TTOU), SIGNIFY(URG)
856};
857
858
859
860
861
862void generic_signal(int sig)
863{
864 if (toys.signalfd) {
865 char c = sig;
866
867 writeall(toys.signalfd, &c, 1);
868 }
869 toys.signal = sig;
870}
871
872void exit_signal(int sig)
873{
874 if (sig) toys.exitval = sig|128;
875 xexit();
876}
877
878
879
880
881void sigatexit(void *handler)
882{
883 struct arg_list *al;
884 int i;
885
886 for (i=0; signames[i].num != SIGCHLD; i++)
887 if (signames[i].num != SIGKILL)
888 xsignal(signames[i].num, handler ? exit_signal : SIG_DFL);
889
890 if (handler) {
891 al = xmalloc(sizeof(struct arg_list));
892 al->next = toys.xexit;
893 al->arg = handler;
894 toys.xexit = al;
895 } else {
896 llist_traverse(toys.xexit, free);
897 toys.xexit = 0;
898 }
899}
900
901
902int sig_to_num(char *pidstr)
903{
904 int i;
905
906 if (pidstr) {
907 char *s;
908
909 i = estrtol(pidstr, &s, 10);
910 if (!errno && !*s) return i;
911
912 if (!strncasecmp(pidstr, "sig", 3)) pidstr+=3;
913 }
914 for (i=0; i<ARRAY_LEN(signames); i++)
915 if (!pidstr) xputs(signames[i].name);
916 else if (!strcasecmp(pidstr, signames[i].name)) return signames[i].num;
917
918 return -1;
919}
920
921char *num_to_sig(int sig)
922{
923 int i;
924
925 for (i=0; i<ARRAY_LEN(signames); i++)
926 if (signames[i].num == sig) return signames[i].name;
927 return NULL;
928}
929
930
931mode_t string_to_mode(char *modestr, mode_t mode)
932{
933 char *whos = "ogua", *hows = "=+-", *whats = "xwrstX", *whys = "ogu",
934 *s, *str = modestr;
935 mode_t extrabits = mode & ~(07777);
936
937
938 if (isdigit(*str)) {
939 mode = estrtol(str, &s, 8);
940 if (errno || *s || (mode & ~(07777))) goto barf;
941
942 return mode | extrabits;
943 }
944
945
946 for (;;) {
947 int i, j, dowho, dohow, dowhat, amask;
948
949 dowho = dohow = dowhat = amask = 0;
950
951
952 while (*str && (s = strchr(whos, *str))) {
953 dowho |= 1<<(s-whos);
954 str++;
955 }
956
957 if (!dowho) {
958 dowho = 8;
959 umask(amask=umask(0));
960 }
961 if (!*str || !(s = strchr(hows, *str))) goto barf;
962 dohow = *(str++);
963
964 if (!dohow) goto barf;
965 while (*str && (s = strchr(whats, *str))) {
966 dowhat |= 1<<(s-whats);
967 str++;
968 }
969
970
971 if ((dowhat&32) && (S_ISDIR(mode) || (mode&0111))) dowhat |= 1;
972
973
974 if (!dowhat && *str && (s = strchr(whys, *str))) {
975 dowhat = (mode>>(3*(s-whys)))&7;
976 str++;
977 }
978
979
980 if (*str && *(str++) != ',') goto barf;
981
982
983 for (i=0; i<4; i++) {
984 for (j=0; j<3; j++) {
985 mode_t bit = 0;
986 int where = 1<<((3*i)+j);
987
988 if (amask & where) continue;
989
990
991 if (i == 3) {
992
993 if (j) {
994 if ((dowhat & 8) && (dowho&(8|(1<<i)))) bit++;
995 } else if (dowhat & 16) bit++;
996 } else {
997 if (!(dowho&(8|(1<<i)))) continue;
998 if (dowhat&(1<<j)) bit++;
999 }
1000
1001
1002
1003 if (dohow == '=' || (bit && dohow == '-')) mode &= ~where;
1004 if (bit && dohow != '-') mode |= where;
1005 }
1006 }
1007
1008 if (!*str) break;
1009 }
1010
1011 return mode|extrabits;
1012barf:
1013 error_exit("bad mode '%s'", modestr);
1014}
1015
1016
1017void mode_to_string(mode_t mode, char *buf)
1018{
1019 char c, d;
1020 int i, bit;
1021
1022 buf[10]=0;
1023 for (i=0; i<9; i++) {
1024 bit = mode & (1<<i);
1025 c = i%3;
1026 if (!c && (mode & (1<<((d=i/3)+9)))) {
1027 c = "tss"[d];
1028 if (!bit) c &= ~0x20;
1029 } else c = bit ? "xwr"[c] : '-';
1030 buf[9-i] = c;
1031 }
1032
1033 if (S_ISDIR(mode)) c = 'd';
1034 else if (S_ISBLK(mode)) c = 'b';
1035 else if (S_ISCHR(mode)) c = 'c';
1036 else if (S_ISLNK(mode)) c = 'l';
1037 else if (S_ISFIFO(mode)) c = 'p';
1038 else if (S_ISSOCK(mode)) c = 's';
1039 else c = '-';
1040 *buf = c;
1041}
1042
1043
1044
1045char *getdirname(char *name)
1046{
1047 char *s = xstrdup(name), *ss = strrchr(s, '/');
1048
1049 while (ss && *ss && *ss == '/' && s != ss) *ss-- = 0;
1050
1051 return s;
1052}
1053
1054
1055
1056char *getbasename(char *name)
1057{
1058 char *s = strrchr(name, '/');
1059
1060 if (s) return s+1;
1061
1062 return name;
1063}
1064
1065
1066char *fileunderdir(char *file, char *dir)
1067{
1068 char *s1 = xabspath(dir, 1), *s2 = xabspath(file, -1), *ss = s2;
1069 int rc = s1 && s2 && strstart(&ss, s1) && (!s1[1] || s2[strlen(s1)] == '/');
1070
1071 free(s1);
1072 if (!rc) free(s2);
1073
1074 return rc ? s2 : 0;
1075}
1076
1077
1078void names_to_pid(char **names, int (*callback)(pid_t pid, char *name))
1079{
1080 DIR *dp;
1081 struct dirent *entry;
1082
1083 if (!(dp = opendir("/proc"))) perror_exit("no /proc");
1084
1085 while ((entry = readdir(dp))) {
1086 unsigned u = atoi(entry->d_name);
1087 char *cmd = 0, *comm, **cur;
1088 off_t len;
1089
1090 if (!u) continue;
1091
1092
1093
1094 sprintf(libbuf, "/proc/%u/comm", u);
1095 len = sizeof(libbuf);
1096 if (!(comm = readfileat(AT_FDCWD, libbuf, libbuf, &len)) || !len)
1097 continue;
1098 if (libbuf[len-1] == '\n') libbuf[--len] = 0;
1099
1100 for (cur = names; *cur; cur++) {
1101 struct stat st1, st2;
1102 char *bb = getbasename(*cur);
1103 off_t len = strlen(bb);
1104
1105
1106
1107
1108 if (len<=14 && bb==*cur && !strcmp(comm, bb)) goto match;
1109
1110
1111 if (bb!=*cur && !stat(*cur, &st1)) {
1112 char buf[32];
1113
1114 sprintf(buf, "/proc/%u/exe", u);
1115 if (stat(buf, &st2)) continue;
1116 if (st1.st_dev != st2.st_dev || st1.st_ino != st2.st_ino) continue;
1117 goto match;
1118 }
1119
1120
1121 if (!cmd) {
1122 sprintf(cmd = libbuf+16, "/proc/%u/cmdline", u);
1123 len = sizeof(libbuf)-17;
1124 if (!(cmd = readfileat(AT_FDCWD, cmd, cmd, &len))) continue;
1125
1126
1127 cmd[len] = 0;
1128 }
1129 if (!strcmp(bb, getbasename(cmd))) goto match;
1130 if (bb!=*cur && !strcmp(bb, getbasename(cmd+strlen(cmd)+1))) goto match;
1131 continue;
1132match:
1133 if (callback(u, *cur)) break;
1134 }
1135 }
1136 closedir(dp);
1137}
1138
1139
1140int human_readable_long(char *buf, unsigned long long num, int dgt, int style)
1141{
1142 unsigned long long snap = 0;
1143 int len, unit, divisor = (style&HR_1000) ? 1000 : 1024;
1144
1145
1146
1147
1148 for (unit = 0; snprintf(0, 0, "%llu", num)>dgt; unit++)
1149 num = ((snap = num)+(divisor/2))/divisor;
1150 len = sprintf(buf, "%llu", num);
1151 if (unit && len == 1) {
1152
1153 num = snap/divisor;
1154 snap -= num*divisor;
1155 snap = ((snap*100)+50)/divisor;
1156 snap /= 10;
1157 len = sprintf(buf, "%llu.%llu", num, snap);
1158 }
1159 if (style & HR_SPACE) buf[len++] = ' ';
1160 if (unit) {
1161 unit = " kMGTPE"[unit];
1162
1163 if (!(style&HR_1000)) unit = toupper(unit);
1164 buf[len++] = unit;
1165 } else if (style & HR_B) buf[len++] = 'B';
1166 buf[len] = 0;
1167
1168 return len;
1169}
1170
1171
1172int human_readable(char *buf, unsigned long long num, int style)
1173{
1174 return human_readable_long(buf, num, 3, style);
1175}
1176
1177
1178
1179
1180int qstrcmp(const void *a, const void *b)
1181{
1182 return strcmp(*(char **)a, *(char **)b);
1183}
1184
1185
1186
1187
1188void create_uuid(char *uuid)
1189{
1190
1191 xgetrandom(uuid, 16, 0);
1192
1193
1194
1195 uuid[6] = (uuid[6] & 0x0F) | 0x40;
1196
1197
1198 uuid[8] = (uuid[8] & 0x3F) | 0x80;
1199}
1200
1201char *show_uuid(char *uuid)
1202{
1203 char *out = libbuf;
1204 int i;
1205
1206 for (i=0; i<16; i++) out+=sprintf(out, "-%02x"+!(0x550&(1<<i)), uuid[i]);
1207 *out = 0;
1208
1209 return libbuf;
1210}
1211
1212
1213char *next_printf(char *s, char **start)
1214{
1215 for (; *s; s++) {
1216 if (*s != '%') continue;
1217 if (*++s == '%') continue;
1218 if (start) *start = s-1;
1219 while (0 <= stridx("0'#-+ ", *s)) s++;
1220 while (isdigit(*s)) s++;
1221 if (*s == '.') s++;
1222 while (isdigit(*s)) s++;
1223
1224 return s;
1225 }
1226
1227 return 0;
1228}
1229
1230int dev_minor(int dev)
1231{
1232 return ((dev&0xfff00000)>>12)|(dev&0xff);
1233}
1234
1235int dev_major(int dev)
1236{
1237 return (dev&0xfff00)>>8;
1238}
1239
1240int dev_makedev(int major, int minor)
1241{
1242 return (minor&0xff)|((major&0xfff)<<8)|((minor&0xfff00)<<12);
1243}
1244
1245
1246struct passwd *bufgetpwuid(uid_t uid)
1247{
1248 struct pwuidbuf_list {
1249 struct pwuidbuf_list *next;
1250 struct passwd pw;
1251 } *list = 0;
1252 struct passwd *temp;
1253 static struct pwuidbuf_list *pwuidbuf;
1254 unsigned size = 256;
1255
1256
1257 for (list = pwuidbuf; list; list = list->next)
1258 if (list->pw.pw_uid == uid) return &(list->pw);
1259
1260 for (;;) {
1261 list = xrealloc(list, size *= 2);
1262 errno = getpwuid_r(uid, &list->pw, sizeof(*list)+(char *)list,
1263 size-sizeof(*list), &temp);
1264 if (errno != ERANGE) break;
1265 }
1266
1267 if (!temp) {
1268 free(list);
1269
1270 return 0;
1271 }
1272 list->next = pwuidbuf;
1273 pwuidbuf = list;
1274
1275 return &list->pw;
1276}
1277
1278
1279struct group *bufgetgrgid(gid_t gid)
1280{
1281 struct grgidbuf_list {
1282 struct grgidbuf_list *next;
1283 struct group gr;
1284 } *list = 0;
1285 struct group *temp;
1286 static struct grgidbuf_list *grgidbuf;
1287 unsigned size = 256;
1288
1289 for (list = grgidbuf; list; list = list->next)
1290 if (list->gr.gr_gid == gid) return &(list->gr);
1291
1292 for (;;) {
1293 list = xrealloc(list, size *= 2);
1294 errno = getgrgid_r(gid, &list->gr, sizeof(*list)+(char *)list,
1295 size-sizeof(*list), &temp);
1296 if (errno != ERANGE) break;
1297 }
1298 if (!temp) {
1299 free(list);
1300
1301 return 0;
1302 }
1303 list->next = grgidbuf;
1304 grgidbuf = list;
1305
1306 return &list->gr;
1307}
1308
1309
1310int readlinkat0(int dirfd, char *path, char *buf, int len)
1311{
1312 if (!len) return 0;
1313
1314 len = readlinkat(dirfd, path, buf, len-1);
1315 if (len<0) len = 0;
1316 buf[len] = 0;
1317
1318 return len;
1319}
1320
1321int readlink0(char *path, char *buf, int len)
1322{
1323 return readlinkat0(AT_FDCWD, path, buf, len);
1324}
1325
1326
1327int regexec0(regex_t *preg, char *string, long len, int nmatch,
1328 regmatch_t *pmatch, int eflags)
1329{
1330 regmatch_t backup;
1331
1332 if (!nmatch) pmatch = &backup;
1333 pmatch->rm_so = 0;
1334 pmatch->rm_eo = len;
1335 return regexec(preg, string, nmatch, pmatch, eflags|REG_STARTEND);
1336}
1337
1338
1339
1340char *getusername(uid_t uid)
1341{
1342 struct passwd *pw = bufgetpwuid(uid);
1343 static char unum[12];
1344
1345 sprintf(unum, "%u", (unsigned)uid);
1346 return pw ? pw->pw_name : unum;
1347}
1348
1349
1350
1351char *getgroupname(gid_t gid)
1352{
1353 struct group *gr = bufgetgrgid(gid);
1354 static char gnum[12];
1355
1356 sprintf(gnum, "%u", (unsigned)gid);
1357 return gr ? gr->gr_name : gnum;
1358}
1359
1360
1361
1362
1363
1364void do_lines(int fd, char delim, void (*call)(char **pline, long len))
1365{
1366 FILE *fp = fd ? xfdopen(fd, "r") : stdin;
1367
1368 for (;;) {
1369 char *line = 0;
1370 ssize_t len;
1371
1372 len = getdelim(&line, (void *)&len, delim, fp);
1373 if (len > 0) {
1374 call(&line, len);
1375 if (line == (void *)1) break;
1376 free(line);
1377 } else break;
1378 }
1379 call(0, 0);
1380
1381 if (fd) fclose(fp);
1382}
1383
1384
1385long long millitime(void)
1386{
1387 struct timespec ts;
1388
1389 clock_gettime(CLOCK_MONOTONIC, &ts);
1390 return ts.tv_sec*1000+ts.tv_nsec/1000000;
1391}
1392
1393
1394char *format_iso_time(char *buf, size_t len, struct timespec *ts)
1395{
1396 char *s = buf;
1397
1398 s += strftime(s, len, "%F %T", localtime(&(ts->tv_sec)));
1399 s += sprintf(s, ".%09ld ", ts->tv_nsec);
1400 s += strftime(s, len-strlen(buf), "%z", localtime(&(ts->tv_sec)));
1401
1402 return buf;
1403}
1404
1405
1406
1407void loggit(int priority, char *format, ...)
1408{
1409 int i, facility = LOG_DAEMON;
1410 va_list va;
1411
1412 for (i = 0; i<3; i++) if (isatty(i)) facility = LOG_AUTH;
1413 openlog(toys.which->name, LOG_PID, facility);
1414 va_start(va, format);
1415 vsyslog(priority, format, va);
1416 va_end(va);
1417 closelog();
1418}
1419