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