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 = xmalloc(sizeof(struct arg_list));
854 int i;
855
856 for (i=0; signames[i].num != SIGCHLD; i++)
857 signal(signames[i].num, exit_signal);
858 al->next = toys.xexit;
859 al->arg = handler;
860 toys.xexit = al;
861}
862
863
864int sig_to_num(char *pidstr)
865{
866 int i;
867
868 if (pidstr) {
869 char *s;
870
871 i = estrtol(pidstr, &s, 10);
872 if (!errno && !*s) return i;
873
874 if (!strncasecmp(pidstr, "sig", 3)) pidstr+=3;
875 }
876 for (i = 0; i < sizeof(signames)/sizeof(struct signame); i++)
877 if (!pidstr) xputs(signames[i].name);
878 else if (!strcasecmp(pidstr, signames[i].name)) return signames[i].num;
879
880 return -1;
881}
882
883char *num_to_sig(int sig)
884{
885 int i;
886
887 for (i=0; i<sizeof(signames)/sizeof(struct signame); i++)
888 if (signames[i].num == sig) return signames[i].name;
889 return NULL;
890}
891
892
893mode_t string_to_mode(char *modestr, mode_t mode)
894{
895 char *whos = "ogua", *hows = "=+-", *whats = "xwrstX", *whys = "ogu",
896 *s, *str = modestr;
897 mode_t extrabits = mode & ~(07777);
898
899
900 if (isdigit(*str)) {
901 mode = estrtol(str, &s, 8);
902 if (errno || *s || (mode & ~(07777))) goto barf;
903
904 return mode | extrabits;
905 }
906
907
908 for (;;) {
909 int i, j, dowho, dohow, dowhat, amask;
910
911 dowho = dohow = dowhat = amask = 0;
912
913
914 while (*str && (s = strchr(whos, *str))) {
915 dowho |= 1<<(s-whos);
916 str++;
917 }
918
919 if (!dowho) {
920 dowho = 8;
921 umask(amask=umask(0));
922 }
923 if (!*str || !(s = strchr(hows, *str))) goto barf;
924 dohow = *(str++);
925
926 if (!dohow) goto barf;
927 while (*str && (s = strchr(whats, *str))) {
928 dowhat |= 1<<(s-whats);
929 str++;
930 }
931
932
933 if ((dowhat&32) && (S_ISDIR(mode) || (mode&0111))) dowhat |= 1;
934
935
936 if (!dowhat && *str && (s = strchr(whys, *str))) {
937 dowhat = (mode>>(3*(s-whys)))&7;
938 str++;
939 }
940
941
942 if (*str && *(str++) != ',') goto barf;
943
944
945 for (i=0; i<4; i++) {
946 for (j=0; j<3; j++) {
947 mode_t bit = 0;
948 int where = 1<<((3*i)+j);
949
950 if (amask & where) continue;
951
952
953 if (i == 3) {
954
955 if (j) {
956 if ((dowhat & 8) && (dowho&(8|(1<<i)))) bit++;
957 } else if (dowhat & 16) bit++;
958 } else {
959 if (!(dowho&(8|(1<<i)))) continue;
960 if (dowhat&(1<<j)) bit++;
961 }
962
963
964
965 if (dohow == '=' || (bit && dohow == '-')) mode &= ~where;
966 if (bit && dohow != '-') mode |= where;
967 }
968 }
969
970 if (!*str) break;
971 }
972
973 return mode|extrabits;
974barf:
975 error_exit("bad mode '%s'", modestr);
976}
977
978
979void mode_to_string(mode_t mode, char *buf)
980{
981 char c, d;
982 int i, bit;
983
984 buf[10]=0;
985 for (i=0; i<9; i++) {
986 bit = mode & (1<<i);
987 c = i%3;
988 if (!c && (mode & (1<<((d=i/3)+9)))) {
989 c = "tss"[d];
990 if (!bit) c &= ~0x20;
991 } else c = bit ? "xwr"[c] : '-';
992 buf[9-i] = c;
993 }
994
995 if (S_ISDIR(mode)) c = 'd';
996 else if (S_ISBLK(mode)) c = 'b';
997 else if (S_ISCHR(mode)) c = 'c';
998 else if (S_ISLNK(mode)) c = 'l';
999 else if (S_ISFIFO(mode)) c = 'p';
1000 else if (S_ISSOCK(mode)) c = 's';
1001 else c = '-';
1002 *buf = c;
1003}
1004
1005
1006
1007char *getdirname(char *name)
1008{
1009 char *s = xstrdup(name), *ss = strrchr(s, '/');
1010
1011 while (*ss && *ss == '/' && s != ss) *ss-- = 0;
1012
1013 return s;
1014}
1015
1016
1017
1018char *getbasename(char *name)
1019{
1020 char *s = strrchr(name, '/');
1021
1022 if (s) return s+1;
1023
1024 return name;
1025}
1026
1027
1028int fileunderdir(char *file, char *dir)
1029{
1030 char *s1 = xabspath(dir, 1), *s2 = xabspath(file, -1), *ss = s2;
1031 int rc = s1 && s2 && strstart(&ss, s1) && (!s1[1] || s2[strlen(s1)] == '/');
1032
1033 free(s1);
1034 free(s2);
1035
1036 return rc;
1037}
1038
1039
1040void names_to_pid(char **names, int (*callback)(pid_t pid, char *name))
1041{
1042 DIR *dp;
1043 struct dirent *entry;
1044
1045 if (!(dp = opendir("/proc"))) perror_exit("no /proc");
1046
1047 while ((entry = readdir(dp))) {
1048 unsigned u = atoi(entry->d_name);
1049 char *cmd = 0, *comm, **cur;
1050 off_t len;
1051
1052 if (!u) continue;
1053
1054
1055
1056 sprintf(libbuf, "/proc/%u/comm", u);
1057 len = sizeof(libbuf);
1058 if (!(comm = readfileat(AT_FDCWD, libbuf, libbuf, &len)) || !len)
1059 continue;
1060 if (libbuf[len-1] == '\n') libbuf[--len] = 0;
1061
1062 for (cur = names; *cur; cur++) {
1063 struct stat st1, st2;
1064 char *bb = getbasename(*cur);
1065 off_t len = strlen(bb);
1066
1067
1068
1069
1070 if (len<=14 && bb==*cur && !strcmp(comm, bb)) goto match;
1071
1072
1073 if (bb!=*cur && !stat(*cur, &st1)) {
1074 char buf[32];
1075
1076 sprintf(buf, "/proc/%u/exe", u);
1077 if (stat(buf, &st2)) continue;
1078 if (st1.st_dev != st2.st_dev || st1.st_ino != st2.st_ino) continue;
1079 goto match;
1080 }
1081
1082
1083 if (!cmd) {
1084 sprintf(cmd = libbuf+16, "/proc/%u/cmdline", u);
1085 len = sizeof(libbuf)-17;
1086 if (!(cmd = readfileat(AT_FDCWD, cmd, cmd, &len))) continue;
1087
1088
1089 cmd[len] = 0;
1090 }
1091 if (!strcmp(bb, getbasename(cmd))) goto match;
1092 if (bb!=*cur && !strcmp(bb, getbasename(cmd+strlen(cmd)+1))) goto match;
1093 continue;
1094match:
1095 if (callback(u, *cur)) break;
1096 }
1097 }
1098 closedir(dp);
1099}
1100
1101
1102int human_readable(char *buf, unsigned long long num, int style)
1103{
1104 unsigned long long snap = 0;
1105 int len, unit, divisor = (style&HR_1000) ? 1000 : 1024;
1106
1107
1108
1109
1110
1111 for (unit = 0; num > 999; unit++) num = ((snap = num)+(divisor/2))/divisor;
1112 len = sprintf(buf, "%llu", num);
1113 if (unit && len == 1) {
1114
1115 num = snap/divisor;
1116 snap -= num*divisor;
1117 snap = ((snap*100)+50)/divisor;
1118 snap /= 10;
1119 len = sprintf(buf, "%llu.%llu", num, snap);
1120 }
1121 if (style & HR_SPACE) buf[len++] = ' ';
1122 if (unit) {
1123 unit = " kMGTPE"[unit];
1124
1125 if (!(style&HR_1000)) unit = toupper(unit);
1126 buf[len++] = unit;
1127 } else if (style & HR_B) buf[len++] = 'B';
1128 buf[len] = 0;
1129
1130 return len;
1131}
1132
1133
1134
1135
1136int qstrcmp(const void *a, const void *b)
1137{
1138 return strcmp(*(char **)a, *(char **)b);
1139}
1140
1141
1142
1143
1144void create_uuid(char *uuid)
1145{
1146
1147 int fd = xopenro("/dev/urandom");
1148 xreadall(fd, uuid, 16);
1149 close(fd);
1150
1151
1152
1153 uuid[6] = (uuid[6] & 0x0F) | 0x40;
1154
1155
1156 uuid[8] = (uuid[8] & 0x3F) | 0x80;
1157}
1158
1159char *show_uuid(char *uuid)
1160{
1161 char *out = libbuf;
1162 int i;
1163
1164 for (i=0; i<16; i++) out+=sprintf(out, "-%02x"+!(0x550&(1<<i)), uuid[i]);
1165 *out = 0;
1166
1167 return libbuf;
1168}
1169
1170
1171char *next_printf(char *s, char **start)
1172{
1173 for (; *s; s++) {
1174 if (*s != '%') continue;
1175 if (*++s == '%') continue;
1176 if (start) *start = s-1;
1177 while (0 <= stridx("0'#-+ ", *s)) s++;
1178 while (isdigit(*s)) s++;
1179 if (*s == '.') s++;
1180 while (isdigit(*s)) s++;
1181
1182 return s;
1183 }
1184
1185 return 0;
1186}
1187
1188
1189char *strnstr(char *line, char *str)
1190{
1191 long len = strlen(str);
1192 char *s;
1193
1194 for (s = line; *s; s++) if (!strncasecmp(s, str, len)) break;
1195
1196 return *s ? s : 0;
1197}
1198
1199int dev_minor(int dev)
1200{
1201 return ((dev&0xfff00000)>>12)|(dev&0xff);
1202}
1203
1204int dev_major(int dev)
1205{
1206 return (dev&0xfff00)>>8;
1207}
1208
1209int dev_makedev(int major, int minor)
1210{
1211 return (minor&0xff)|((major&0xfff)<<8)|((minor&0xfff00)<<12);
1212}
1213
1214
1215struct passwd *bufgetpwuid(uid_t uid)
1216{
1217 struct pwuidbuf_list {
1218 struct pwuidbuf_list *next;
1219 struct passwd pw;
1220 } *list;
1221 struct passwd *temp;
1222 static struct pwuidbuf_list *pwuidbuf;
1223
1224 for (list = pwuidbuf; list; list = list->next)
1225 if (list->pw.pw_uid == uid) return &(list->pw);
1226
1227 list = xmalloc(512);
1228 list->next = pwuidbuf;
1229
1230 errno = getpwuid_r(uid, &list->pw, sizeof(*list)+(char *)list,
1231 512-sizeof(*list), &temp);
1232 if (!temp) {
1233 free(list);
1234
1235 return 0;
1236 }
1237 pwuidbuf = list;
1238
1239 return &list->pw;
1240}
1241
1242
1243struct group *bufgetgrgid(gid_t gid)
1244{
1245 struct grgidbuf_list {
1246 struct grgidbuf_list *next;
1247 struct group gr;
1248 } *list;
1249 struct group *temp;
1250 static struct grgidbuf_list *grgidbuf;
1251
1252 for (list = grgidbuf; list; list = list->next)
1253 if (list->gr.gr_gid == gid) return &(list->gr);
1254
1255 list = xmalloc(512);
1256 list->next = grgidbuf;
1257
1258 errno = getgrgid_r(gid, &list->gr, sizeof(*list)+(char *)list,
1259 512-sizeof(*list), &temp);
1260 if (!temp) {
1261 free(list);
1262
1263 return 0;
1264 }
1265 grgidbuf = list;
1266
1267 return &list->gr;
1268}
1269
1270
1271int readlinkat0(int dirfd, char *path, char *buf, int len)
1272{
1273 if (!len) return 0;
1274
1275 len = readlinkat(dirfd, path, buf, len-1);
1276 if (len<1) return 0;
1277 buf[len] = 0;
1278
1279 return len;
1280}
1281
1282int readlink0(char *path, char *buf, int len)
1283{
1284 return readlinkat0(AT_FDCWD, path, buf, len);
1285}
1286
1287
1288
1289
1290
1291int regexec0(regex_t *preg, char *string, long len, int nmatch,
1292 regmatch_t pmatch[], int eflags)
1293{
1294 char *s = string;
1295
1296 for (;;) {
1297 long ll = 0;
1298 int rc;
1299
1300 while (len && !*s) {
1301 s++;
1302 len--;
1303 }
1304 while (s[ll] && ll<len) ll++;
1305
1306 rc = regexec(preg, s, nmatch, pmatch, eflags);
1307 if (!rc) {
1308 for (rc = 0; rc<nmatch && pmatch[rc].rm_so!=-1; rc++) {
1309 pmatch[rc].rm_so += s-string;
1310 pmatch[rc].rm_eo += s-string;
1311 }
1312
1313 return 0;
1314 }
1315 if (ll==len) return rc;
1316
1317 s += ll;
1318 len -= ll;
1319 }
1320}
1321
1322
1323
1324char *getusername(uid_t uid)
1325{
1326 struct passwd *pw = bufgetpwuid(uid);
1327 static char unum[12];
1328
1329 sprintf(unum, "%u", (unsigned)uid);
1330 return pw ? pw->pw_name : unum;
1331}
1332
1333
1334
1335char *getgroupname(gid_t gid)
1336{
1337 struct group *gr = bufgetgrgid(gid);
1338 static char gnum[12];
1339
1340 sprintf(gnum, "%u", (unsigned)gid);
1341 return gr ? gr->gr_name : gnum;
1342}
1343
1344
1345
1346
1347
1348void do_lines(int fd, void (*call)(char **pline, long len))
1349{
1350 FILE *fp = fd ? xfdopen(fd, "r") : stdin;
1351
1352 for (;;) {
1353 char *line = 0;
1354 ssize_t len;
1355
1356 len = getline(&line, (void *)&len, fp);
1357 if (len > 0) {
1358 call(&line, len);
1359 if (line == (void *)1) break;
1360 free(line);
1361 } else break;
1362 }
1363 call(0, 0);
1364
1365 if (fd) fclose(fp);
1366}
1367
1368
1369
1370
1371long environ_bytes()
1372{
1373 long bytes = sizeof(char *);
1374 char **ev;
1375
1376 for (ev = environ; *ev; ev++) bytes += sizeof(char *) + strlen(*ev) + 1;
1377
1378 return bytes;
1379}
1380
1381
1382long long millitime(void)
1383{
1384 struct timespec ts;
1385
1386 clock_gettime(CLOCK_MONOTONIC, &ts);
1387 return ts.tv_sec*1000+ts.tv_nsec/1000000;
1388}
1389