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