10f66f451Sopenharmony_ci/* lib.c - various reusable stuff.
20f66f451Sopenharmony_ci *
30f66f451Sopenharmony_ci * Copyright 2006 Rob Landley <rob@landley.net>
40f66f451Sopenharmony_ci */
50f66f451Sopenharmony_ci
60f66f451Sopenharmony_ci#define SYSLOG_NAMES
70f66f451Sopenharmony_ci#include "toys.h"
80f66f451Sopenharmony_ci
90f66f451Sopenharmony_civoid verror_msg(char *msg, int err, va_list va)
100f66f451Sopenharmony_ci{
110f66f451Sopenharmony_ci  char *s = ": %s";
120f66f451Sopenharmony_ci
130f66f451Sopenharmony_ci  fprintf(stderr, "%s: ", toys.which->name);
140f66f451Sopenharmony_ci  if (msg) vfprintf(stderr, msg, va);
150f66f451Sopenharmony_ci  else s+=2;
160f66f451Sopenharmony_ci  if (err>0) fprintf(stderr, s, strerror(err));
170f66f451Sopenharmony_ci  if (err<0 && CFG_TOYBOX_HELP)
180f66f451Sopenharmony_ci    fprintf(stderr, " (see \"%s --help\")", toys.which->name);
190f66f451Sopenharmony_ci  if (msg || err) putc('\n', stderr);
200f66f451Sopenharmony_ci  if (!toys.exitval) toys.exitval++;
210f66f451Sopenharmony_ci}
220f66f451Sopenharmony_ci
230f66f451Sopenharmony_ci// These functions don't collapse together because of the va_stuff.
240f66f451Sopenharmony_ci
250f66f451Sopenharmony_civoid error_msg(char *msg, ...)
260f66f451Sopenharmony_ci{
270f66f451Sopenharmony_ci  va_list va;
280f66f451Sopenharmony_ci
290f66f451Sopenharmony_ci  va_start(va, msg);
300f66f451Sopenharmony_ci  verror_msg(msg, 0, va);
310f66f451Sopenharmony_ci  va_end(va);
320f66f451Sopenharmony_ci}
330f66f451Sopenharmony_ci
340f66f451Sopenharmony_civoid perror_msg(char *msg, ...)
350f66f451Sopenharmony_ci{
360f66f451Sopenharmony_ci  va_list va;
370f66f451Sopenharmony_ci
380f66f451Sopenharmony_ci  va_start(va, msg);
390f66f451Sopenharmony_ci  verror_msg(msg, errno, va);
400f66f451Sopenharmony_ci  va_end(va);
410f66f451Sopenharmony_ci}
420f66f451Sopenharmony_ci
430f66f451Sopenharmony_ci// Die with an error message.
440f66f451Sopenharmony_civoid error_exit(char *msg, ...)
450f66f451Sopenharmony_ci{
460f66f451Sopenharmony_ci  va_list va;
470f66f451Sopenharmony_ci
480f66f451Sopenharmony_ci  va_start(va, msg);
490f66f451Sopenharmony_ci  verror_msg(msg, 0, va);
500f66f451Sopenharmony_ci  va_end(va);
510f66f451Sopenharmony_ci
520f66f451Sopenharmony_ci  xexit();
530f66f451Sopenharmony_ci}
540f66f451Sopenharmony_ci
550f66f451Sopenharmony_ci// Die with an error message and strerror(errno)
560f66f451Sopenharmony_civoid perror_exit(char *msg, ...)
570f66f451Sopenharmony_ci{
580f66f451Sopenharmony_ci  // Die silently if our pipeline exited.
590f66f451Sopenharmony_ci  if (errno != EPIPE) {
600f66f451Sopenharmony_ci    va_list va;
610f66f451Sopenharmony_ci
620f66f451Sopenharmony_ci    va_start(va, msg);
630f66f451Sopenharmony_ci    verror_msg(msg, errno, va);
640f66f451Sopenharmony_ci    va_end(va);
650f66f451Sopenharmony_ci  }
660f66f451Sopenharmony_ci
670f66f451Sopenharmony_ci  xexit();
680f66f451Sopenharmony_ci}
690f66f451Sopenharmony_ci
700f66f451Sopenharmony_ci// Exit with an error message after showing help text.
710f66f451Sopenharmony_civoid help_exit(char *msg, ...)
720f66f451Sopenharmony_ci{
730f66f451Sopenharmony_ci  va_list va;
740f66f451Sopenharmony_ci
750f66f451Sopenharmony_ci  if (!msg) show_help(stdout);
760f66f451Sopenharmony_ci  else {
770f66f451Sopenharmony_ci    va_start(va, msg);
780f66f451Sopenharmony_ci    verror_msg(msg, -1, va);
790f66f451Sopenharmony_ci    va_end(va);
800f66f451Sopenharmony_ci  }
810f66f451Sopenharmony_ci
820f66f451Sopenharmony_ci  xexit();
830f66f451Sopenharmony_ci}
840f66f451Sopenharmony_ci
850f66f451Sopenharmony_ci// If you want to explicitly disable the printf() behavior (because you're
860f66f451Sopenharmony_ci// printing user-supplied data, or because android's static checker produces
870f66f451Sopenharmony_ci// false positives for 'char *s = x ? "blah1" : "blah2"; printf(s);' and it's
880f66f451Sopenharmony_ci// -Werror there for policy reasons).
890f66f451Sopenharmony_civoid error_msg_raw(char *msg)
900f66f451Sopenharmony_ci{
910f66f451Sopenharmony_ci  error_msg("%s", msg);
920f66f451Sopenharmony_ci}
930f66f451Sopenharmony_ci
940f66f451Sopenharmony_civoid perror_msg_raw(char *msg)
950f66f451Sopenharmony_ci{
960f66f451Sopenharmony_ci  perror_msg("%s", msg);
970f66f451Sopenharmony_ci}
980f66f451Sopenharmony_ci
990f66f451Sopenharmony_civoid error_exit_raw(char *msg)
1000f66f451Sopenharmony_ci{
1010f66f451Sopenharmony_ci  error_exit("%s", msg);
1020f66f451Sopenharmony_ci}
1030f66f451Sopenharmony_ci
1040f66f451Sopenharmony_civoid perror_exit_raw(char *msg)
1050f66f451Sopenharmony_ci{
1060f66f451Sopenharmony_ci  perror_exit("%s", msg);
1070f66f451Sopenharmony_ci}
1080f66f451Sopenharmony_ci
1090f66f451Sopenharmony_ci// Keep reading until full or EOF
1100f66f451Sopenharmony_cissize_t readall(int fd, void *buf, size_t len)
1110f66f451Sopenharmony_ci{
1120f66f451Sopenharmony_ci  size_t count = 0;
1130f66f451Sopenharmony_ci
1140f66f451Sopenharmony_ci  while (count<len) {
1150f66f451Sopenharmony_ci    int i = read(fd, (char *)buf+count, len-count);
1160f66f451Sopenharmony_ci    if (!i) break;
1170f66f451Sopenharmony_ci    if (i<0) return i;
1180f66f451Sopenharmony_ci    count += i;
1190f66f451Sopenharmony_ci  }
1200f66f451Sopenharmony_ci
1210f66f451Sopenharmony_ci  return count;
1220f66f451Sopenharmony_ci}
1230f66f451Sopenharmony_ci
1240f66f451Sopenharmony_ci// Keep writing until done or EOF
1250f66f451Sopenharmony_cissize_t writeall(int fd, void *buf, size_t len)
1260f66f451Sopenharmony_ci{
1270f66f451Sopenharmony_ci  size_t count = 0;
1280f66f451Sopenharmony_ci
1290f66f451Sopenharmony_ci  while (count<len) {
1300f66f451Sopenharmony_ci    int i = write(fd, count+(char *)buf, len-count);
1310f66f451Sopenharmony_ci    if (i<1) return i;
1320f66f451Sopenharmony_ci    count += i;
1330f66f451Sopenharmony_ci  }
1340f66f451Sopenharmony_ci
1350f66f451Sopenharmony_ci  return count;
1360f66f451Sopenharmony_ci}
1370f66f451Sopenharmony_ci
1380f66f451Sopenharmony_ci// skip this many bytes of input. Return 0 for success, >0 means this much
1390f66f451Sopenharmony_ci// left after input skipped.
1400f66f451Sopenharmony_cioff_t lskip(int fd, off_t offset)
1410f66f451Sopenharmony_ci{
1420f66f451Sopenharmony_ci  off_t cur = lseek(fd, 0, SEEK_CUR);
1430f66f451Sopenharmony_ci
1440f66f451Sopenharmony_ci  if (cur != -1) {
1450f66f451Sopenharmony_ci    off_t end = lseek(fd, 0, SEEK_END) - cur;
1460f66f451Sopenharmony_ci
1470f66f451Sopenharmony_ci    if (end > 0 && end < offset) return offset - end;
1480f66f451Sopenharmony_ci    end = offset+cur;
1490f66f451Sopenharmony_ci    if (end == lseek(fd, end, SEEK_SET)) return 0;
1500f66f451Sopenharmony_ci    perror_exit("lseek");
1510f66f451Sopenharmony_ci  }
1520f66f451Sopenharmony_ci
1530f66f451Sopenharmony_ci  while (offset>0) {
1540f66f451Sopenharmony_ci    int try = offset>sizeof(libbuf) ? sizeof(libbuf) : offset, or;
1550f66f451Sopenharmony_ci
1560f66f451Sopenharmony_ci    or = readall(fd, libbuf, try);
1570f66f451Sopenharmony_ci    if (or < 0) perror_exit("lskip to %lld", (long long)offset);
1580f66f451Sopenharmony_ci    else offset -= or;
1590f66f451Sopenharmony_ci    if (or < try) break;
1600f66f451Sopenharmony_ci  }
1610f66f451Sopenharmony_ci
1620f66f451Sopenharmony_ci  return offset;
1630f66f451Sopenharmony_ci}
1640f66f451Sopenharmony_ci
1650f66f451Sopenharmony_ci// flags: 1=make last dir (with mode lastmode, otherwise skips last component)
1660f66f451Sopenharmony_ci//        2=make path (already exists is ok)
1670f66f451Sopenharmony_ci//        4=verbose
1680f66f451Sopenharmony_ci// returns 0 = path ok, 1 = error
1690f66f451Sopenharmony_ciint mkpathat(int atfd, char *dir, mode_t lastmode, int flags)
1700f66f451Sopenharmony_ci{
1710f66f451Sopenharmony_ci  struct stat buf;
1720f66f451Sopenharmony_ci  char *s;
1730f66f451Sopenharmony_ci
1740f66f451Sopenharmony_ci  // mkdir -p one/two/three is not an error if the path already exists,
1750f66f451Sopenharmony_ci  // but is if "three" is a file. The others we dereference and catch
1760f66f451Sopenharmony_ci  // not-a-directory along the way, but the last one we must explicitly
1770f66f451Sopenharmony_ci  // test for. Might as well do it up front.
1780f66f451Sopenharmony_ci
1790f66f451Sopenharmony_ci  if (!fstatat(atfd, dir, &buf, 0) && !S_ISDIR(buf.st_mode)) {
1800f66f451Sopenharmony_ci    errno = EEXIST;
1810f66f451Sopenharmony_ci    return 1;
1820f66f451Sopenharmony_ci  }
1830f66f451Sopenharmony_ci
1840f66f451Sopenharmony_ci  for (s = dir; ;s++) {
1850f66f451Sopenharmony_ci    char save = 0;
1860f66f451Sopenharmony_ci    mode_t mode = (0777&~toys.old_umask)|0300;
1870f66f451Sopenharmony_ci
1880f66f451Sopenharmony_ci    // find next '/', but don't try to mkdir "" at start of absolute path
1890f66f451Sopenharmony_ci    if (*s == '/' && (flags&2) && s != dir) {
1900f66f451Sopenharmony_ci      save = *s;
1910f66f451Sopenharmony_ci      *s = 0;
1920f66f451Sopenharmony_ci    } else if (*s) continue;
1930f66f451Sopenharmony_ci
1940f66f451Sopenharmony_ci    // Use the mode from the -m option only for the last directory.
1950f66f451Sopenharmony_ci    if (!save) {
1960f66f451Sopenharmony_ci      if (flags&1) mode = lastmode;
1970f66f451Sopenharmony_ci      else break;
1980f66f451Sopenharmony_ci    }
1990f66f451Sopenharmony_ci
2000f66f451Sopenharmony_ci    if (mkdirat(atfd, dir, mode)) {
2010f66f451Sopenharmony_ci      if (!(flags&2) || errno != EEXIST) return 1;
2020f66f451Sopenharmony_ci    } else if (flags&4)
2030f66f451Sopenharmony_ci      fprintf(stderr, "%s: created directory '%s'\n", toys.which->name, dir);
2040f66f451Sopenharmony_ci
2050f66f451Sopenharmony_ci    if (!(*s = save)) break;
2060f66f451Sopenharmony_ci  }
2070f66f451Sopenharmony_ci
2080f66f451Sopenharmony_ci  return 0;
2090f66f451Sopenharmony_ci}
2100f66f451Sopenharmony_ci
2110f66f451Sopenharmony_ci// The common case
2120f66f451Sopenharmony_ciint mkpath(char *dir)
2130f66f451Sopenharmony_ci{
2140f66f451Sopenharmony_ci  return mkpathat(AT_FDCWD, dir, 0, MKPATHAT_MAKE);
2150f66f451Sopenharmony_ci}
2160f66f451Sopenharmony_ci
2170f66f451Sopenharmony_ci// Split a path into linked list of components, tracking head and tail of list.
2180f66f451Sopenharmony_ci// Filters out // entries with no contents.
2190f66f451Sopenharmony_cistruct string_list **splitpath(char *path, struct string_list **list)
2200f66f451Sopenharmony_ci{
2210f66f451Sopenharmony_ci  char *new = path;
2220f66f451Sopenharmony_ci
2230f66f451Sopenharmony_ci  *list = 0;
2240f66f451Sopenharmony_ci  do {
2250f66f451Sopenharmony_ci    int len;
2260f66f451Sopenharmony_ci
2270f66f451Sopenharmony_ci    if (*path && *path != '/') continue;
2280f66f451Sopenharmony_ci    len = path-new;
2290f66f451Sopenharmony_ci    if (len > 0) {
2300f66f451Sopenharmony_ci      *list = xmalloc(sizeof(struct string_list) + len + 1);
2310f66f451Sopenharmony_ci      (*list)->next = 0;
2320f66f451Sopenharmony_ci      memcpy((*list)->str, new, len);
2330f66f451Sopenharmony_ci      (*list)->str[len] = 0;
2340f66f451Sopenharmony_ci      list = &(*list)->next;
2350f66f451Sopenharmony_ci    }
2360f66f451Sopenharmony_ci    new = path+1;
2370f66f451Sopenharmony_ci  } while (*path++);
2380f66f451Sopenharmony_ci
2390f66f451Sopenharmony_ci  return list;
2400f66f451Sopenharmony_ci}
2410f66f451Sopenharmony_ci
2420f66f451Sopenharmony_ci// Find all file in a colon-separated path with access type "type" (generally
2430f66f451Sopenharmony_ci// X_OK or R_OK).  Returns a list of absolute paths to each file found, in
2440f66f451Sopenharmony_ci// order.
2450f66f451Sopenharmony_ci
2460f66f451Sopenharmony_cistruct string_list *find_in_path(char *path, char *filename)
2470f66f451Sopenharmony_ci{
2480f66f451Sopenharmony_ci  struct string_list *rlist = NULL, **prlist=&rlist;
2490f66f451Sopenharmony_ci  char *cwd;
2500f66f451Sopenharmony_ci
2510f66f451Sopenharmony_ci  if (!path) return 0;
2520f66f451Sopenharmony_ci
2530f66f451Sopenharmony_ci  cwd = xgetcwd();
2540f66f451Sopenharmony_ci  for (;;) {
2550f66f451Sopenharmony_ci    char *res, *next = strchr(path, ':');
2560f66f451Sopenharmony_ci    int len = next ? next-path : strlen(path);
2570f66f451Sopenharmony_ci    struct string_list *rnext;
2580f66f451Sopenharmony_ci    struct stat st;
2590f66f451Sopenharmony_ci
2600f66f451Sopenharmony_ci    rnext = xmalloc(sizeof(void *) + strlen(filename)
2610f66f451Sopenharmony_ci      + (len ? len : strlen(cwd)) + 2);
2620f66f451Sopenharmony_ci    if (!len) sprintf(rnext->str, "%s/%s", cwd, filename);
2630f66f451Sopenharmony_ci    else {
2640f66f451Sopenharmony_ci      memcpy(res = rnext->str, path, len);
2650f66f451Sopenharmony_ci      res += len;
2660f66f451Sopenharmony_ci      *(res++) = '/';
2670f66f451Sopenharmony_ci      strcpy(res, filename);
2680f66f451Sopenharmony_ci    }
2690f66f451Sopenharmony_ci
2700f66f451Sopenharmony_ci    // Confirm it's not a directory.
2710f66f451Sopenharmony_ci    if (!stat(rnext->str, &st) && S_ISREG(st.st_mode)) {
2720f66f451Sopenharmony_ci      *prlist = rnext;
2730f66f451Sopenharmony_ci      rnext->next = NULL;
2740f66f451Sopenharmony_ci      prlist = &(rnext->next);
2750f66f451Sopenharmony_ci    } else free(rnext);
2760f66f451Sopenharmony_ci
2770f66f451Sopenharmony_ci    if (!next) break;
2780f66f451Sopenharmony_ci    path += len;
2790f66f451Sopenharmony_ci    path++;
2800f66f451Sopenharmony_ci  }
2810f66f451Sopenharmony_ci  free(cwd);
2820f66f451Sopenharmony_ci
2830f66f451Sopenharmony_ci  return rlist;
2840f66f451Sopenharmony_ci}
2850f66f451Sopenharmony_ci
2860f66f451Sopenharmony_cilong long estrtol(char *str, char **end, int base)
2870f66f451Sopenharmony_ci{
2880f66f451Sopenharmony_ci  errno = 0;
2890f66f451Sopenharmony_ci
2900f66f451Sopenharmony_ci  return strtoll(str, end, base);
2910f66f451Sopenharmony_ci}
2920f66f451Sopenharmony_ci
2930f66f451Sopenharmony_cilong long xstrtol(char *str, char **end, int base)
2940f66f451Sopenharmony_ci{
2950f66f451Sopenharmony_ci  long long l = estrtol(str, end, base);
2960f66f451Sopenharmony_ci
2970f66f451Sopenharmony_ci  if (errno) perror_exit_raw(str);
2980f66f451Sopenharmony_ci
2990f66f451Sopenharmony_ci  return l;
3000f66f451Sopenharmony_ci}
3010f66f451Sopenharmony_ci
3020f66f451Sopenharmony_ci// atol() with the kilo/mega/giga/tera/peta/exa extensions, plus word and block.
3030f66f451Sopenharmony_ci// (zetta and yotta don't fit in 64 bits.)
3040f66f451Sopenharmony_cilong long atolx(char *numstr)
3050f66f451Sopenharmony_ci{
3060f66f451Sopenharmony_ci  char *c = numstr, *suffixes="cwbkmgtpe", *end;
3070f66f451Sopenharmony_ci  long long val;
3080f66f451Sopenharmony_ci
3090f66f451Sopenharmony_ci  val = xstrtol(numstr, &c, 0);
3100f66f451Sopenharmony_ci  if (c != numstr && *c && (end = strchr(suffixes, tolower(*c)))) {
3110f66f451Sopenharmony_ci    int shift = end-suffixes-2;
3120f66f451Sopenharmony_ci    ++c;
3130f66f451Sopenharmony_ci    if (shift==-1) val *= 2;
3140f66f451Sopenharmony_ci    else if (!shift) val *= 512;
3150f66f451Sopenharmony_ci    else if (shift>0) {
3160f66f451Sopenharmony_ci      if (*c && tolower(*c++)=='d') while (shift--) val *= 1000;
3170f66f451Sopenharmony_ci      else val *= 1LL<<(shift*10);
3180f66f451Sopenharmony_ci    }
3190f66f451Sopenharmony_ci  }
3200f66f451Sopenharmony_ci  while (isspace(*c)) c++;
3210f66f451Sopenharmony_ci  if (c==numstr || *c) error_exit("not integer: %s", numstr);
3220f66f451Sopenharmony_ci
3230f66f451Sopenharmony_ci  return val;
3240f66f451Sopenharmony_ci}
3250f66f451Sopenharmony_ci
3260f66f451Sopenharmony_cilong long atolx_range(char *numstr, long long low, long long high)
3270f66f451Sopenharmony_ci{
3280f66f451Sopenharmony_ci  long long val = atolx(numstr);
3290f66f451Sopenharmony_ci
3300f66f451Sopenharmony_ci  if (val < low) error_exit("%lld < %lld", val, low);
3310f66f451Sopenharmony_ci  if (val > high) error_exit("%lld > %lld", val, high);
3320f66f451Sopenharmony_ci
3330f66f451Sopenharmony_ci  return val;
3340f66f451Sopenharmony_ci}
3350f66f451Sopenharmony_ci
3360f66f451Sopenharmony_ciint stridx(char *haystack, char needle)
3370f66f451Sopenharmony_ci{
3380f66f451Sopenharmony_ci  char *off;
3390f66f451Sopenharmony_ci
3400f66f451Sopenharmony_ci  if (!needle) return -1;
3410f66f451Sopenharmony_ci  off = strchr(haystack, needle);
3420f66f451Sopenharmony_ci  if (!off) return -1;
3430f66f451Sopenharmony_ci
3440f66f451Sopenharmony_ci  return off-haystack;
3450f66f451Sopenharmony_ci}
3460f66f451Sopenharmony_ci
3470f66f451Sopenharmony_ci// Convert wc to utf8, returning bytes written. Does not null terminate.
3480f66f451Sopenharmony_ciint wctoutf8(char *s, unsigned wc)
3490f66f451Sopenharmony_ci{
3500f66f451Sopenharmony_ci  int len = (wc>0x7ff)+(wc>0xffff), i;
3510f66f451Sopenharmony_ci
3520f66f451Sopenharmony_ci  if (wc<128) {
3530f66f451Sopenharmony_ci    *s = wc;
3540f66f451Sopenharmony_ci    return 1;
3550f66f451Sopenharmony_ci  } else {
3560f66f451Sopenharmony_ci    i = len;
3570f66f451Sopenharmony_ci    do {
3580f66f451Sopenharmony_ci      s[1+i] = 0x80+(wc&0x3f);
3590f66f451Sopenharmony_ci      wc >>= 6;
3600f66f451Sopenharmony_ci    } while (i--);
3610f66f451Sopenharmony_ci    *s = (((signed char) 0x80) >> (len+1)) | wc;
3620f66f451Sopenharmony_ci  }
3630f66f451Sopenharmony_ci
3640f66f451Sopenharmony_ci  return 2+len;
3650f66f451Sopenharmony_ci}
3660f66f451Sopenharmony_ci
3670f66f451Sopenharmony_ci// Convert utf8 sequence to a unicode wide character
3680f66f451Sopenharmony_ciint utf8towc(unsigned *wc, char *str, unsigned len)
3690f66f451Sopenharmony_ci{
3700f66f451Sopenharmony_ci  unsigned result, mask, first;
3710f66f451Sopenharmony_ci  char *s, c;
3720f66f451Sopenharmony_ci
3730f66f451Sopenharmony_ci  // fast path ASCII
3740f66f451Sopenharmony_ci  if (len && *str<128) return !!(*wc = *str);
3750f66f451Sopenharmony_ci
3760f66f451Sopenharmony_ci  result = first = *(s = str++);
3770f66f451Sopenharmony_ci  if (result<0xc2 || result>0xf4) return -1;
3780f66f451Sopenharmony_ci  for (mask = 6; (first&0xc0)==0xc0; mask += 5, first <<= 1) {
3790f66f451Sopenharmony_ci    if (!--len) return -2;
3800f66f451Sopenharmony_ci    if (((c = *(str++))&0xc0) != 0x80) return -1;
3810f66f451Sopenharmony_ci    result = (result<<6)|(c&0x3f);
3820f66f451Sopenharmony_ci  }
3830f66f451Sopenharmony_ci  result &= (1<<mask)-1;
3840f66f451Sopenharmony_ci  c = str-s;
3850f66f451Sopenharmony_ci
3860f66f451Sopenharmony_ci  // Avoid overlong encodings
3870f66f451Sopenharmony_ci  if (result<(unsigned []){0x80,0x800,0x10000}[c-2]) return -1;
3880f66f451Sopenharmony_ci
3890f66f451Sopenharmony_ci  // Limit unicode so it can't encode anything UTF-16 can't.
3900f66f451Sopenharmony_ci  if (result>0x10ffff || (result>=0xd800 && result<=0xdfff)) return -1;
3910f66f451Sopenharmony_ci  *wc = result;
3920f66f451Sopenharmony_ci
3930f66f451Sopenharmony_ci  return str-s;
3940f66f451Sopenharmony_ci}
3950f66f451Sopenharmony_ci
3960f66f451Sopenharmony_cichar *strlower(char *s)
3970f66f451Sopenharmony_ci{
3980f66f451Sopenharmony_ci  char *try, *new;
3990f66f451Sopenharmony_ci
4000f66f451Sopenharmony_ci  if (!CFG_TOYBOX_I18N) {
4010f66f451Sopenharmony_ci    try = new = xstrdup(s);
4020f66f451Sopenharmony_ci    for (; *s; s++) *(new++) = tolower(*s);
4030f66f451Sopenharmony_ci  } else {
4040f66f451Sopenharmony_ci    // I can't guarantee the string _won't_ expand during reencoding, so...?
4050f66f451Sopenharmony_ci    try = new = xmalloc(strlen(s)*2+1);
4060f66f451Sopenharmony_ci
4070f66f451Sopenharmony_ci    while (*s) {
4080f66f451Sopenharmony_ci      unsigned c;
4090f66f451Sopenharmony_ci      int len = utf8towc(&c, s, MB_CUR_MAX);
4100f66f451Sopenharmony_ci
4110f66f451Sopenharmony_ci      if (len < 1) *(new++) = *(s++);
4120f66f451Sopenharmony_ci      else {
4130f66f451Sopenharmony_ci        s += len;
4140f66f451Sopenharmony_ci        // squash title case too
4150f66f451Sopenharmony_ci        c = towlower(c);
4160f66f451Sopenharmony_ci
4170f66f451Sopenharmony_ci        // if we had a valid utf8 sequence, convert it to lower case, and can't
4180f66f451Sopenharmony_ci        // encode back to utf8, something is wrong with your libc. But just
4190f66f451Sopenharmony_ci        // in case somebody finds an exploit...
4200f66f451Sopenharmony_ci        len = wcrtomb(new, c, 0);
4210f66f451Sopenharmony_ci        if (len < 1) error_exit("bad utf8 %x", (int)c);
4220f66f451Sopenharmony_ci        new += len;
4230f66f451Sopenharmony_ci      }
4240f66f451Sopenharmony_ci    }
4250f66f451Sopenharmony_ci    *new = 0;
4260f66f451Sopenharmony_ci  }
4270f66f451Sopenharmony_ci
4280f66f451Sopenharmony_ci  return try;
4290f66f451Sopenharmony_ci}
4300f66f451Sopenharmony_ci
4310f66f451Sopenharmony_ci// strstr but returns pointer after match
4320f66f451Sopenharmony_cichar *strafter(char *haystack, char *needle)
4330f66f451Sopenharmony_ci{
4340f66f451Sopenharmony_ci  char *s = strstr(haystack, needle);
4350f66f451Sopenharmony_ci
4360f66f451Sopenharmony_ci  return s ? s+strlen(needle) : s;
4370f66f451Sopenharmony_ci}
4380f66f451Sopenharmony_ci
4390f66f451Sopenharmony_ci// Remove trailing \n
4400f66f451Sopenharmony_cichar *chomp(char *s)
4410f66f451Sopenharmony_ci{
4420f66f451Sopenharmony_ci  char *p = strrchr(s, '\n');
4430f66f451Sopenharmony_ci
4440f66f451Sopenharmony_ci  if (p && !p[1]) *p = 0;
4450f66f451Sopenharmony_ci  return s;
4460f66f451Sopenharmony_ci}
4470f66f451Sopenharmony_ci
4480f66f451Sopenharmony_ciint unescape(char c)
4490f66f451Sopenharmony_ci{
4500f66f451Sopenharmony_ci  char *from = "\\abefnrtv", *to = "\\\a\b\033\f\n\r\t\v";
4510f66f451Sopenharmony_ci  int idx = stridx(from, c);
4520f66f451Sopenharmony_ci
4530f66f451Sopenharmony_ci  return (idx == -1) ? 0 : to[idx];
4540f66f451Sopenharmony_ci}
4550f66f451Sopenharmony_ci
4560f66f451Sopenharmony_ci// parse next character advancing pointer. echo requires leading 0 in octal esc
4570f66f451Sopenharmony_ciint unescape2(char **c, int echo)
4580f66f451Sopenharmony_ci{
4590f66f451Sopenharmony_ci  int idx = *((*c)++), i, off;
4600f66f451Sopenharmony_ci
4610f66f451Sopenharmony_ci  if (idx != '\\' || !**c) return idx;
4620f66f451Sopenharmony_ci  if (**c == 'c') return 31&*(++*c);
4630f66f451Sopenharmony_ci  for (i = 0; i<4; i++) {
4640f66f451Sopenharmony_ci    if (sscanf(*c, (char *[]){"0%3o%n"+!echo, "x%2x%n", "u%4x%n", "U%6x%n"}[i],
4650f66f451Sopenharmony_ci        &idx, &off) > 0)
4660f66f451Sopenharmony_ci    {
4670f66f451Sopenharmony_ci      *c += off;
4680f66f451Sopenharmony_ci
4690f66f451Sopenharmony_ci      return idx;
4700f66f451Sopenharmony_ci    }
4710f66f451Sopenharmony_ci  }
4720f66f451Sopenharmony_ci
4730f66f451Sopenharmony_ci  if (-1 == (idx = stridx("\\abeEfnrtv'\"?0", **c))) return '\\';
4740f66f451Sopenharmony_ci  ++*c;
4750f66f451Sopenharmony_ci
4760f66f451Sopenharmony_ci  return "\\\a\b\033\033\f\n\r\t\v'\"?"[idx];
4770f66f451Sopenharmony_ci}
4780f66f451Sopenharmony_ci
4790f66f451Sopenharmony_ci// If string ends with suffix return pointer to start of suffix in string,
4800f66f451Sopenharmony_ci// else NULL
4810f66f451Sopenharmony_cichar *strend(char *str, char *suffix)
4820f66f451Sopenharmony_ci{
4830f66f451Sopenharmony_ci  long a = strlen(str), b = strlen(suffix);
4840f66f451Sopenharmony_ci
4850f66f451Sopenharmony_ci  if (a>b && !strcmp(str += a-b, suffix)) return str;
4860f66f451Sopenharmony_ci
4870f66f451Sopenharmony_ci  return 0;
4880f66f451Sopenharmony_ci}
4890f66f451Sopenharmony_ci
4900f66f451Sopenharmony_ci// If *a starts with b, advance *a past it and return 1, else return 0;
4910f66f451Sopenharmony_ciint strstart(char **a, char *b)
4920f66f451Sopenharmony_ci{
4930f66f451Sopenharmony_ci  char *c = *a;
4940f66f451Sopenharmony_ci
4950f66f451Sopenharmony_ci  while (*b && *c == *b) b++, c++;
4960f66f451Sopenharmony_ci  if (!*b) *a = c;
4970f66f451Sopenharmony_ci
4980f66f451Sopenharmony_ci  return !*b;
4990f66f451Sopenharmony_ci}
5000f66f451Sopenharmony_ci
5010f66f451Sopenharmony_ci// If *a starts with b, advance *a past it and return 1, else return 0;
5020f66f451Sopenharmony_ciint strcasestart(char **a, char *b)
5030f66f451Sopenharmony_ci{
5040f66f451Sopenharmony_ci  int len = strlen(b), i = !strncasecmp(*a, b, len);
5050f66f451Sopenharmony_ci
5060f66f451Sopenharmony_ci  if (i) *a += len;
5070f66f451Sopenharmony_ci
5080f66f451Sopenharmony_ci  return i;
5090f66f451Sopenharmony_ci}
5100f66f451Sopenharmony_ci
5110f66f451Sopenharmony_ci// Return how long the file at fd is, if there's any way to determine it.
5120f66f451Sopenharmony_cioff_t fdlength(int fd)
5130f66f451Sopenharmony_ci{
5140f66f451Sopenharmony_ci  struct stat st;
5150f66f451Sopenharmony_ci  off_t base = 0, range = 1, expand = 1, old;
5160f66f451Sopenharmony_ci
5170f66f451Sopenharmony_ci  if (!fstat(fd, &st) && S_ISREG(st.st_mode)) return st.st_size;
5180f66f451Sopenharmony_ci
5190f66f451Sopenharmony_ci  // If the ioctl works for this, return it.
5200f66f451Sopenharmony_ci  // TODO: is blocksize still always 512, or do we stat for it?
5210f66f451Sopenharmony_ci  // unsigned int size;
5220f66f451Sopenharmony_ci  // if (ioctl(fd, BLKGETSIZE, &size) >= 0) return size*512L;
5230f66f451Sopenharmony_ci
5240f66f451Sopenharmony_ci  // If not, do a binary search for the last location we can read.  (Some
5250f66f451Sopenharmony_ci  // block devices don't do BLKGETSIZE right.)  This should probably have
5260f66f451Sopenharmony_ci  // a CONFIG option...
5270f66f451Sopenharmony_ci
5280f66f451Sopenharmony_ci  // If not, do a binary search for the last location we can read.
5290f66f451Sopenharmony_ci
5300f66f451Sopenharmony_ci  old = lseek(fd, 0, SEEK_CUR);
5310f66f451Sopenharmony_ci  do {
5320f66f451Sopenharmony_ci    char temp;
5330f66f451Sopenharmony_ci    off_t pos = base + range / 2;
5340f66f451Sopenharmony_ci
5350f66f451Sopenharmony_ci    if (lseek(fd, pos, 0)>=0 && read(fd, &temp, 1)==1) {
5360f66f451Sopenharmony_ci      off_t delta = (pos + 1) - base;
5370f66f451Sopenharmony_ci
5380f66f451Sopenharmony_ci      base += delta;
5390f66f451Sopenharmony_ci      if (expand) range = (expand <<= 1) - base;
5400f66f451Sopenharmony_ci      else range -= delta;
5410f66f451Sopenharmony_ci    } else {
5420f66f451Sopenharmony_ci      expand = 0;
5430f66f451Sopenharmony_ci      range = pos - base;
5440f66f451Sopenharmony_ci    }
5450f66f451Sopenharmony_ci  } while (range > 0);
5460f66f451Sopenharmony_ci
5470f66f451Sopenharmony_ci  lseek(fd, old, SEEK_SET);
5480f66f451Sopenharmony_ci
5490f66f451Sopenharmony_ci  return base;
5500f66f451Sopenharmony_ci}
5510f66f451Sopenharmony_ci
5520f66f451Sopenharmony_ci// Read contents of file as a single nul-terminated string.
5530f66f451Sopenharmony_ci// measure file size if !len, allocate buffer if !buf
5540f66f451Sopenharmony_ci// Existing buffers need len in *plen
5550f66f451Sopenharmony_ci// Returns amount of data read in *plen
5560f66f451Sopenharmony_cichar *readfileat(int dirfd, char *name, char *ibuf, off_t *plen)
5570f66f451Sopenharmony_ci{
5580f66f451Sopenharmony_ci  off_t len, rlen;
5590f66f451Sopenharmony_ci  int fd;
5600f66f451Sopenharmony_ci  char *buf, *rbuf;
5610f66f451Sopenharmony_ci
5620f66f451Sopenharmony_ci  // Unsafe to probe for size with a supplied buffer, don't ever do that.
5630f66f451Sopenharmony_ci  if (CFG_TOYBOX_DEBUG && (ibuf ? !*plen : *plen)) error_exit("bad readfileat");
5640f66f451Sopenharmony_ci
5650f66f451Sopenharmony_ci  if (-1 == (fd = openat(dirfd, name, O_RDONLY))) return 0;
5660f66f451Sopenharmony_ci
5670f66f451Sopenharmony_ci  // If we dunno the length, probe it. If we can't probe, start with 1 page.
5680f66f451Sopenharmony_ci  if (!*plen) {
5690f66f451Sopenharmony_ci    if ((len = fdlength(fd))>0) *plen = len;
5700f66f451Sopenharmony_ci    else len = 4096;
5710f66f451Sopenharmony_ci  } else len = *plen-1;
5720f66f451Sopenharmony_ci
5730f66f451Sopenharmony_ci  if (!ibuf) buf = xmalloc(len+1);
5740f66f451Sopenharmony_ci  else buf = ibuf;
5750f66f451Sopenharmony_ci
5760f66f451Sopenharmony_ci  for (rbuf = buf;;) {
5770f66f451Sopenharmony_ci    rlen = readall(fd, rbuf, len);
5780f66f451Sopenharmony_ci    if (*plen || rlen<len) break;
5790f66f451Sopenharmony_ci
5800f66f451Sopenharmony_ci    // If reading unknown size, expand buffer by 1.5 each time we fill it up.
5810f66f451Sopenharmony_ci    rlen += rbuf-buf;
5820f66f451Sopenharmony_ci    buf = xrealloc(buf, len = (rlen*3)/2);
5830f66f451Sopenharmony_ci    rbuf = buf+rlen;
5840f66f451Sopenharmony_ci    len -= rlen;
5850f66f451Sopenharmony_ci  }
5860f66f451Sopenharmony_ci  *plen = len = rlen+(rbuf-buf);
5870f66f451Sopenharmony_ci  close(fd);
5880f66f451Sopenharmony_ci
5890f66f451Sopenharmony_ci  if (rlen<0) {
5900f66f451Sopenharmony_ci    if (ibuf != buf) free(buf);
5910f66f451Sopenharmony_ci    buf = 0;
5920f66f451Sopenharmony_ci  } else buf[len] = 0;
5930f66f451Sopenharmony_ci
5940f66f451Sopenharmony_ci  return buf;
5950f66f451Sopenharmony_ci}
5960f66f451Sopenharmony_ci
5970f66f451Sopenharmony_cichar *readfile(char *name, char *ibuf, off_t len)
5980f66f451Sopenharmony_ci{
5990f66f451Sopenharmony_ci  return readfileat(AT_FDCWD, name, ibuf, &len);
6000f66f451Sopenharmony_ci}
6010f66f451Sopenharmony_ci
6020f66f451Sopenharmony_ci// Sleep for this many thousandths of a second
6030f66f451Sopenharmony_civoid msleep(long milliseconds)
6040f66f451Sopenharmony_ci{
6050f66f451Sopenharmony_ci  struct timespec ts;
6060f66f451Sopenharmony_ci
6070f66f451Sopenharmony_ci  ts.tv_sec = milliseconds/1000;
6080f66f451Sopenharmony_ci  ts.tv_nsec = (milliseconds%1000)*1000000;
6090f66f451Sopenharmony_ci  nanosleep(&ts, &ts);
6100f66f451Sopenharmony_ci}
6110f66f451Sopenharmony_ci
6120f66f451Sopenharmony_ci// Adjust timespec by nanosecond offset
6130f66f451Sopenharmony_civoid nanomove(struct timespec *ts, long long offset)
6140f66f451Sopenharmony_ci{
6150f66f451Sopenharmony_ci  long long nano = ts->tv_nsec + offset, secs = nano/1000000000;
6160f66f451Sopenharmony_ci
6170f66f451Sopenharmony_ci  ts->tv_sec += secs;
6180f66f451Sopenharmony_ci  nano %= 1000000000;
6190f66f451Sopenharmony_ci  if (nano<0) {
6200f66f451Sopenharmony_ci    ts->tv_sec--;
6210f66f451Sopenharmony_ci    nano += 1000000000;
6220f66f451Sopenharmony_ci  }
6230f66f451Sopenharmony_ci  ts->tv_nsec = nano;
6240f66f451Sopenharmony_ci}
6250f66f451Sopenharmony_ci
6260f66f451Sopenharmony_ci// return difference between two timespecs in nanosecs
6270f66f451Sopenharmony_cilong long nanodiff(struct timespec *old, struct timespec *new)
6280f66f451Sopenharmony_ci{
6290f66f451Sopenharmony_ci  return (new->tv_sec - old->tv_sec)*1000000000LL+(new->tv_nsec - old->tv_nsec);
6300f66f451Sopenharmony_ci}
6310f66f451Sopenharmony_ci
6320f66f451Sopenharmony_ci// return 1<<x of highest bit set
6330f66f451Sopenharmony_ciint highest_bit(unsigned long l)
6340f66f451Sopenharmony_ci{
6350f66f451Sopenharmony_ci  int i;
6360f66f451Sopenharmony_ci
6370f66f451Sopenharmony_ci  for (i = 0; l; i++) l >>= 1;
6380f66f451Sopenharmony_ci
6390f66f451Sopenharmony_ci  return i-1;
6400f66f451Sopenharmony_ci}
6410f66f451Sopenharmony_ci
6420f66f451Sopenharmony_ci// Inefficient, but deals with unaligned access
6430f66f451Sopenharmony_ciint64_t peek_le(void *ptr, unsigned size)
6440f66f451Sopenharmony_ci{
6450f66f451Sopenharmony_ci  int64_t ret = 0;
6460f66f451Sopenharmony_ci  char *c = ptr;
6470f66f451Sopenharmony_ci  int i;
6480f66f451Sopenharmony_ci
6490f66f451Sopenharmony_ci  for (i=0; i<size; i++) ret |= ((int64_t)c[i])<<(i*8);
6500f66f451Sopenharmony_ci  return ret;
6510f66f451Sopenharmony_ci}
6520f66f451Sopenharmony_ci
6530f66f451Sopenharmony_ciint64_t peek_be(void *ptr, unsigned size)
6540f66f451Sopenharmony_ci{
6550f66f451Sopenharmony_ci  int64_t ret = 0;
6560f66f451Sopenharmony_ci  char *c = ptr;
6570f66f451Sopenharmony_ci  int i;
6580f66f451Sopenharmony_ci
6590f66f451Sopenharmony_ci  for (i=0; i<size; i++) ret = (ret<<8)|(c[i]&0xff);
6600f66f451Sopenharmony_ci  return ret;
6610f66f451Sopenharmony_ci}
6620f66f451Sopenharmony_ci
6630f66f451Sopenharmony_ciint64_t peek(void *ptr, unsigned size)
6640f66f451Sopenharmony_ci{
6650f66f451Sopenharmony_ci  return (IS_BIG_ENDIAN ? peek_be : peek_le)(ptr, size);
6660f66f451Sopenharmony_ci}
6670f66f451Sopenharmony_ci
6680f66f451Sopenharmony_civoid poke_le(void *ptr, long long val, unsigned size)
6690f66f451Sopenharmony_ci{
6700f66f451Sopenharmony_ci  char *c = ptr;
6710f66f451Sopenharmony_ci
6720f66f451Sopenharmony_ci  while (size--) {
6730f66f451Sopenharmony_ci    *c++ = val&255;
6740f66f451Sopenharmony_ci    val >>= 8;
6750f66f451Sopenharmony_ci  }
6760f66f451Sopenharmony_ci}
6770f66f451Sopenharmony_ci
6780f66f451Sopenharmony_civoid poke_be(void *ptr, long long val, unsigned size)
6790f66f451Sopenharmony_ci{
6800f66f451Sopenharmony_ci  char *c = ptr + size;
6810f66f451Sopenharmony_ci
6820f66f451Sopenharmony_ci  while (size--) {
6830f66f451Sopenharmony_ci    *--c = val&255;
6840f66f451Sopenharmony_ci    val >>=8;
6850f66f451Sopenharmony_ci  }
6860f66f451Sopenharmony_ci}
6870f66f451Sopenharmony_ci
6880f66f451Sopenharmony_civoid poke(void *ptr, long long val, unsigned size)
6890f66f451Sopenharmony_ci{
6900f66f451Sopenharmony_ci  (IS_BIG_ENDIAN ? poke_be : poke_le)(ptr, val, size);
6910f66f451Sopenharmony_ci}
6920f66f451Sopenharmony_ci
6930f66f451Sopenharmony_ci// Iterate through an array of files, opening each one and calling a function
6940f66f451Sopenharmony_ci// on that filehandle and name. The special filename "-" means stdin if
6950f66f451Sopenharmony_ci// flags is O_RDONLY, stdout otherwise. An empty argument list calls
6960f66f451Sopenharmony_ci// function() on just stdin/stdout.
6970f66f451Sopenharmony_ci//
6980f66f451Sopenharmony_ci// Note: pass O_CLOEXEC to automatically close filehandles when function()
6990f66f451Sopenharmony_ci// returns, otherwise filehandles must be closed by function().
7000f66f451Sopenharmony_ci// pass WARN_ONLY to produce warning messages about files it couldn't
7010f66f451Sopenharmony_ci// open/create, and skip them. Otherwise function is called with fd -1.
7020f66f451Sopenharmony_civoid loopfiles_rw(char **argv, int flags, int permissions,
7030f66f451Sopenharmony_ci  void (*function)(int fd, char *name))
7040f66f451Sopenharmony_ci{
7050f66f451Sopenharmony_ci  int fd, failok = !(flags&WARN_ONLY);
7060f66f451Sopenharmony_ci
7070f66f451Sopenharmony_ci  flags &= ~WARN_ONLY;
7080f66f451Sopenharmony_ci
7090f66f451Sopenharmony_ci  // If no arguments, read from stdin.
7100f66f451Sopenharmony_ci  if (!*argv) function((flags & O_ACCMODE) != O_RDONLY ? 1 : 0, "-");
7110f66f451Sopenharmony_ci  else do {
7120f66f451Sopenharmony_ci    // Filename "-" means read from stdin.
7130f66f451Sopenharmony_ci    // Inability to open a file prints a warning, but doesn't exit.
7140f66f451Sopenharmony_ci
7150f66f451Sopenharmony_ci    if (!strcmp(*argv, "-")) fd = 0;
7160f66f451Sopenharmony_ci    else if (0>(fd = notstdio(open(*argv, flags, permissions))) && !failok) {
7170f66f451Sopenharmony_ci      perror_msg_raw(*argv);
7180f66f451Sopenharmony_ci      continue;
7190f66f451Sopenharmony_ci    }
7200f66f451Sopenharmony_ci    function(fd, *argv);
7210f66f451Sopenharmony_ci    if ((flags & O_CLOEXEC) && fd) close(fd);
7220f66f451Sopenharmony_ci  } while (*++argv);
7230f66f451Sopenharmony_ci}
7240f66f451Sopenharmony_ci
7250f66f451Sopenharmony_ci// Call loopfiles_rw with O_RDONLY|O_CLOEXEC|WARN_ONLY (common case)
7260f66f451Sopenharmony_civoid loopfiles(char **argv, void (*function)(int fd, char *name))
7270f66f451Sopenharmony_ci{
7280f66f451Sopenharmony_ci  loopfiles_rw(argv, O_RDONLY|O_CLOEXEC|WARN_ONLY, 0, function);
7290f66f451Sopenharmony_ci}
7300f66f451Sopenharmony_ci
7310f66f451Sopenharmony_ci// glue to call do_lines() from loopfiles
7320f66f451Sopenharmony_cistatic void (*do_lines_bridge)(char **pline, long len);
7330f66f451Sopenharmony_cistatic void loopfile_lines_bridge(int fd, char *name)
7340f66f451Sopenharmony_ci{
7350f66f451Sopenharmony_ci  do_lines(fd, '\n', do_lines_bridge);
7360f66f451Sopenharmony_ci}
7370f66f451Sopenharmony_ci
7380f66f451Sopenharmony_civoid loopfiles_lines(char **argv, void (*function)(char **pline, long len))
7390f66f451Sopenharmony_ci{
7400f66f451Sopenharmony_ci  do_lines_bridge = function;
7410f66f451Sopenharmony_ci  // No O_CLOEXEC because we need to call fclose.
7420f66f451Sopenharmony_ci  loopfiles_rw(argv, O_RDONLY|WARN_ONLY, 0, loopfile_lines_bridge);
7430f66f451Sopenharmony_ci}
7440f66f451Sopenharmony_ci
7450f66f451Sopenharmony_ci// Slow, but small.
7460f66f451Sopenharmony_cichar *get_line(int fd)
7470f66f451Sopenharmony_ci{
7480f66f451Sopenharmony_ci  char c, *buf = NULL;
7490f66f451Sopenharmony_ci  long len = 0;
7500f66f451Sopenharmony_ci
7510f66f451Sopenharmony_ci  for (;;) {
7520f66f451Sopenharmony_ci    if (1>read(fd, &c, 1)) break;
7530f66f451Sopenharmony_ci    if (!(len & 63)) buf=xrealloc(buf, len+65);
7540f66f451Sopenharmony_ci    if ((buf[len++]=c) == '\n') break;
7550f66f451Sopenharmony_ci  }
7560f66f451Sopenharmony_ci  if (buf) {
7570f66f451Sopenharmony_ci    buf[len]=0;
7580f66f451Sopenharmony_ci    if (buf[--len]=='\n') buf[len]=0;
7590f66f451Sopenharmony_ci  }
7600f66f451Sopenharmony_ci
7610f66f451Sopenharmony_ci  return buf;
7620f66f451Sopenharmony_ci}
7630f66f451Sopenharmony_ci
7640f66f451Sopenharmony_ciint wfchmodat(int fd, char *name, mode_t mode)
7650f66f451Sopenharmony_ci{
7660f66f451Sopenharmony_ci  int rc = fchmodat(fd, name, mode, 0);
7670f66f451Sopenharmony_ci
7680f66f451Sopenharmony_ci  if (rc) {
7690f66f451Sopenharmony_ci    perror_msg("chmod '%s' to %04o", name, mode);
7700f66f451Sopenharmony_ci    toys.exitval=1;
7710f66f451Sopenharmony_ci  }
7720f66f451Sopenharmony_ci  return rc;
7730f66f451Sopenharmony_ci}
7740f66f451Sopenharmony_ci
7750f66f451Sopenharmony_cistatic char *tempfile2zap;
7760f66f451Sopenharmony_cistatic void tempfile_handler(void)
7770f66f451Sopenharmony_ci{
7780f66f451Sopenharmony_ci  if (1 < (long)tempfile2zap) unlink(tempfile2zap);
7790f66f451Sopenharmony_ci}
7800f66f451Sopenharmony_ci
7810f66f451Sopenharmony_ci// Open a temporary file to copy an existing file into.
7820f66f451Sopenharmony_ciint copy_tempfile(int fdin, char *name, char **tempname)
7830f66f451Sopenharmony_ci{
7840f66f451Sopenharmony_ci  struct stat statbuf;
7850f66f451Sopenharmony_ci  int fd = xtempfile(name, tempname), ignored __attribute__((__unused__));
7860f66f451Sopenharmony_ci
7870f66f451Sopenharmony_ci  // Record tempfile for exit cleanup if interrupted
7880f66f451Sopenharmony_ci  if (!tempfile2zap) sigatexit(tempfile_handler);
7890f66f451Sopenharmony_ci  tempfile2zap = *tempname;
7900f66f451Sopenharmony_ci
7910f66f451Sopenharmony_ci  // Set permissions of output file.
7920f66f451Sopenharmony_ci  if (!fstat(fdin, &statbuf)) fchmod(fd, statbuf.st_mode);
7930f66f451Sopenharmony_ci
7940f66f451Sopenharmony_ci  // We chmod before chown, which strips the suid bit. Caller has to explicitly
7950f66f451Sopenharmony_ci  // switch it back on if they want to keep suid.
7960f66f451Sopenharmony_ci
7970f66f451Sopenharmony_ci  // Suppress warn-unused-result. Both gcc and clang clutch their pearls about
7980f66f451Sopenharmony_ci  // this but it's _supposed_ to fail when we're not root.
7990f66f451Sopenharmony_ci  ignored = fchown(fd, statbuf.st_uid, statbuf.st_gid);
8000f66f451Sopenharmony_ci
8010f66f451Sopenharmony_ci  return fd;
8020f66f451Sopenharmony_ci}
8030f66f451Sopenharmony_ci
8040f66f451Sopenharmony_ci// Abort the copy and delete the temporary file.
8050f66f451Sopenharmony_civoid delete_tempfile(int fdin, int fdout, char **tempname)
8060f66f451Sopenharmony_ci{
8070f66f451Sopenharmony_ci  close(fdin);
8080f66f451Sopenharmony_ci  close(fdout);
8090f66f451Sopenharmony_ci  if (*tempname) unlink(*tempname);
8100f66f451Sopenharmony_ci  tempfile2zap = (char *)1;
8110f66f451Sopenharmony_ci  free(*tempname);
8120f66f451Sopenharmony_ci  *tempname = NULL;
8130f66f451Sopenharmony_ci}
8140f66f451Sopenharmony_ci
8150f66f451Sopenharmony_ci// Copy the rest of the data and replace the original with the copy.
8160f66f451Sopenharmony_civoid replace_tempfile(int fdin, int fdout, char **tempname)
8170f66f451Sopenharmony_ci{
8180f66f451Sopenharmony_ci  char *temp = xstrdup(*tempname);
8190f66f451Sopenharmony_ci
8200f66f451Sopenharmony_ci  temp[strlen(temp)-6]=0;
8210f66f451Sopenharmony_ci  if (fdin != -1) {
8220f66f451Sopenharmony_ci    xsendfile(fdin, fdout);
8230f66f451Sopenharmony_ci    xclose(fdin);
8240f66f451Sopenharmony_ci  }
8250f66f451Sopenharmony_ci  xclose(fdout);
8260f66f451Sopenharmony_ci  xrename(*tempname, temp);
8270f66f451Sopenharmony_ci  tempfile2zap = (char *)1;
8280f66f451Sopenharmony_ci  free(*tempname);
8290f66f451Sopenharmony_ci  free(temp);
8300f66f451Sopenharmony_ci  *tempname = NULL;
8310f66f451Sopenharmony_ci}
8320f66f451Sopenharmony_ci
8330f66f451Sopenharmony_ci// Create a 256 entry CRC32 lookup table.
8340f66f451Sopenharmony_ci
8350f66f451Sopenharmony_civoid crc_init(unsigned int *crc_table, int little_endian)
8360f66f451Sopenharmony_ci{
8370f66f451Sopenharmony_ci  unsigned int i;
8380f66f451Sopenharmony_ci
8390f66f451Sopenharmony_ci  // Init the CRC32 table (big endian)
8400f66f451Sopenharmony_ci  for (i=0; i<256; i++) {
8410f66f451Sopenharmony_ci    unsigned int j, c = little_endian ? i : i<<24;
8420f66f451Sopenharmony_ci    for (j=8; j; j--)
8430f66f451Sopenharmony_ci      if (little_endian) c = (c&1) ? (c>>1)^0xEDB88320 : c>>1;
8440f66f451Sopenharmony_ci      else c=c&0x80000000 ? (c<<1)^0x04c11db7 : (c<<1);
8450f66f451Sopenharmony_ci    crc_table[i] = c;
8460f66f451Sopenharmony_ci  }
8470f66f451Sopenharmony_ci}
8480f66f451Sopenharmony_ci
8490f66f451Sopenharmony_ci// Init base64 table
8500f66f451Sopenharmony_ci
8510f66f451Sopenharmony_civoid base64_init(char *p)
8520f66f451Sopenharmony_ci{
8530f66f451Sopenharmony_ci  int i;
8540f66f451Sopenharmony_ci
8550f66f451Sopenharmony_ci  for (i = 'A'; i != ':'; i++) {
8560f66f451Sopenharmony_ci    if (i == 'Z'+1) i = 'a';
8570f66f451Sopenharmony_ci    if (i == 'z'+1) i = '0';
8580f66f451Sopenharmony_ci    *(p++) = i;
8590f66f451Sopenharmony_ci  }
8600f66f451Sopenharmony_ci  *(p++) = '+';
8610f66f451Sopenharmony_ci  *(p++) = '/';
8620f66f451Sopenharmony_ci}
8630f66f451Sopenharmony_ci
8640f66f451Sopenharmony_ciint yesno(int def)
8650f66f451Sopenharmony_ci{
8660f66f451Sopenharmony_ci  return fyesno(stdin, def);
8670f66f451Sopenharmony_ci}
8680f66f451Sopenharmony_ci
8690f66f451Sopenharmony_ciint fyesno(FILE *in, int def)
8700f66f451Sopenharmony_ci{
8710f66f451Sopenharmony_ci  char buf;
8720f66f451Sopenharmony_ci
8730f66f451Sopenharmony_ci  fprintf(stderr, " (%c/%c):", def ? 'Y' : 'y', def ? 'n' : 'N');
8740f66f451Sopenharmony_ci  fflush(stderr);
8750f66f451Sopenharmony_ci  while (fread(&buf, 1, 1, in)) {
8760f66f451Sopenharmony_ci    int new;
8770f66f451Sopenharmony_ci
8780f66f451Sopenharmony_ci    // The letter changes the value, the newline (or space) returns it.
8790f66f451Sopenharmony_ci    if (isspace(buf)) break;
8800f66f451Sopenharmony_ci    if (-1 != (new = stridx("ny", tolower(buf)))) def = new;
8810f66f451Sopenharmony_ci  }
8820f66f451Sopenharmony_ci
8830f66f451Sopenharmony_ci  return def;
8840f66f451Sopenharmony_ci}
8850f66f451Sopenharmony_ci
8860f66f451Sopenharmony_ci// Handler that sets toys.signal, and writes to toys.signalfd if set
8870f66f451Sopenharmony_civoid generic_signal(int sig)
8880f66f451Sopenharmony_ci{
8890f66f451Sopenharmony_ci  if (toys.signalfd) {
8900f66f451Sopenharmony_ci    char c = sig;
8910f66f451Sopenharmony_ci
8920f66f451Sopenharmony_ci    writeall(toys.signalfd, &c, 1);
8930f66f451Sopenharmony_ci  }
8940f66f451Sopenharmony_ci  toys.signal = sig;
8950f66f451Sopenharmony_ci}
8960f66f451Sopenharmony_ci
8970f66f451Sopenharmony_civoid exit_signal(int sig)
8980f66f451Sopenharmony_ci{
8990f66f451Sopenharmony_ci  if (sig) toys.exitval = sig|128;
9000f66f451Sopenharmony_ci  xexit();
9010f66f451Sopenharmony_ci}
9020f66f451Sopenharmony_ci
9030f66f451Sopenharmony_ci// Install the same handler on every signal that defaults to killing the
9040f66f451Sopenharmony_ci// process, calling the handler on the way out. Calling multiple times
9050f66f451Sopenharmony_ci// adds the handlers to a list, to be called in order.
9060f66f451Sopenharmony_civoid sigatexit(void *handler)
9070f66f451Sopenharmony_ci{
9080f66f451Sopenharmony_ci  xsignal_all_killers(handler ? exit_signal : SIG_DFL);
9090f66f451Sopenharmony_ci
9100f66f451Sopenharmony_ci  if (handler) {
9110f66f451Sopenharmony_ci    struct arg_list *al = xmalloc(sizeof(struct arg_list));
9120f66f451Sopenharmony_ci
9130f66f451Sopenharmony_ci    al->next = toys.xexit;
9140f66f451Sopenharmony_ci    al->arg = handler;
9150f66f451Sopenharmony_ci    toys.xexit = al;
9160f66f451Sopenharmony_ci  } else {
9170f66f451Sopenharmony_ci    llist_traverse(toys.xexit, free);
9180f66f451Sopenharmony_ci    toys.xexit = 0;
9190f66f451Sopenharmony_ci  }
9200f66f451Sopenharmony_ci}
9210f66f451Sopenharmony_ci
9220f66f451Sopenharmony_ci// Output a nicely formatted 80-column table of all the signals.
9230f66f451Sopenharmony_civoid list_signals()
9240f66f451Sopenharmony_ci{
9250f66f451Sopenharmony_ci  int i = 0, count = 0;
9260f66f451Sopenharmony_ci  char *name;
9270f66f451Sopenharmony_ci
9280f66f451Sopenharmony_ci  for (; i<=NSIG; i++) {
9290f66f451Sopenharmony_ci    if ((name = num_to_sig(i))) {
9300f66f451Sopenharmony_ci      printf("%2d) SIG%-9s", i, name);
9310f66f451Sopenharmony_ci      if (++count % 5 == 0) putchar('\n');
9320f66f451Sopenharmony_ci    }
9330f66f451Sopenharmony_ci  }
9340f66f451Sopenharmony_ci  putchar('\n');
9350f66f451Sopenharmony_ci}
9360f66f451Sopenharmony_ci
9370f66f451Sopenharmony_ci// premute mode bits based on posix mode strings.
9380f66f451Sopenharmony_cimode_t string_to_mode(char *modestr, mode_t mode)
9390f66f451Sopenharmony_ci{
9400f66f451Sopenharmony_ci  char *whos = "ogua", *hows = "=+-", *whats = "xwrstX", *whys = "ogu",
9410f66f451Sopenharmony_ci       *s, *str = modestr;
9420f66f451Sopenharmony_ci  mode_t extrabits = mode & ~(07777);
9430f66f451Sopenharmony_ci
9440f66f451Sopenharmony_ci  // Handle octal mode
9450f66f451Sopenharmony_ci  if (isdigit(*str)) {
9460f66f451Sopenharmony_ci    mode = estrtol(str, &s, 8);
9470f66f451Sopenharmony_ci    if (errno || *s || (mode & ~(07777))) goto barf;
9480f66f451Sopenharmony_ci
9490f66f451Sopenharmony_ci    return mode | extrabits;
9500f66f451Sopenharmony_ci  }
9510f66f451Sopenharmony_ci
9520f66f451Sopenharmony_ci  // Gaze into the bin of permission...
9530f66f451Sopenharmony_ci  for (;;) {
9540f66f451Sopenharmony_ci    int i, j, dowho, dohow, dowhat, amask;
9550f66f451Sopenharmony_ci
9560f66f451Sopenharmony_ci    dowho = dohow = dowhat = amask = 0;
9570f66f451Sopenharmony_ci
9580f66f451Sopenharmony_ci    // Find the who, how, and what stanzas, in that order
9590f66f451Sopenharmony_ci    while (*str && (s = strchr(whos, *str))) {
9600f66f451Sopenharmony_ci      dowho |= 1<<(s-whos);
9610f66f451Sopenharmony_ci      str++;
9620f66f451Sopenharmony_ci    }
9630f66f451Sopenharmony_ci    // If who isn't specified, like "a" but honoring umask.
9640f66f451Sopenharmony_ci    if (!dowho) {
9650f66f451Sopenharmony_ci      dowho = 8;
9660f66f451Sopenharmony_ci      umask(amask=umask(0));
9670f66f451Sopenharmony_ci    }
9680f66f451Sopenharmony_ci    if (!*str || !(s = strchr(hows, *str))) goto barf;
9690f66f451Sopenharmony_ci    dohow = *(str++);
9700f66f451Sopenharmony_ci
9710f66f451Sopenharmony_ci    if (!dohow) goto barf;
9720f66f451Sopenharmony_ci    while (*str && (s = strchr(whats, *str))) {
9730f66f451Sopenharmony_ci      dowhat |= 1<<(s-whats);
9740f66f451Sopenharmony_ci      str++;
9750f66f451Sopenharmony_ci    }
9760f66f451Sopenharmony_ci
9770f66f451Sopenharmony_ci    // Convert X to x for directory or if already executable somewhere
9780f66f451Sopenharmony_ci    if ((dowhat&32) &&  (S_ISDIR(mode) || (mode&0111))) dowhat |= 1;
9790f66f451Sopenharmony_ci
9800f66f451Sopenharmony_ci    // Copy mode from another category?
9810f66f451Sopenharmony_ci    if (!dowhat && *str && (s = strchr(whys, *str))) {
9820f66f451Sopenharmony_ci      dowhat = (mode>>(3*(s-whys)))&7;
9830f66f451Sopenharmony_ci      str++;
9840f66f451Sopenharmony_ci    }
9850f66f451Sopenharmony_ci
9860f66f451Sopenharmony_ci    // Are we ready to do a thing yet?
9870f66f451Sopenharmony_ci    if (*str && *(str++) != ',') goto barf;
9880f66f451Sopenharmony_ci
9890f66f451Sopenharmony_ci    // Ok, apply the bits to the mode.
9900f66f451Sopenharmony_ci    for (i=0; i<4; i++) {
9910f66f451Sopenharmony_ci      for (j=0; j<3; j++) {
9920f66f451Sopenharmony_ci        mode_t bit = 0;
9930f66f451Sopenharmony_ci        int where = 1<<((3*i)+j);
9940f66f451Sopenharmony_ci
9950f66f451Sopenharmony_ci        if (amask & where) continue;
9960f66f451Sopenharmony_ci
9970f66f451Sopenharmony_ci        // Figure out new value at this location
9980f66f451Sopenharmony_ci        if (i == 3) {
9990f66f451Sopenharmony_ci          // suid/sticky bit.
10000f66f451Sopenharmony_ci          if (j) {
10010f66f451Sopenharmony_ci            if ((dowhat & 8) && (dowho&(8|(1<<i)))) bit++;
10020f66f451Sopenharmony_ci          } else if (dowhat & 16) bit++;
10030f66f451Sopenharmony_ci        } else {
10040f66f451Sopenharmony_ci          if (!(dowho&(8|(1<<i)))) continue;
10050f66f451Sopenharmony_ci          if (dowhat&(1<<j)) bit++;
10060f66f451Sopenharmony_ci        }
10070f66f451Sopenharmony_ci
10080f66f451Sopenharmony_ci        // When selection active, modify bit
10090f66f451Sopenharmony_ci
10100f66f451Sopenharmony_ci        if (dohow == '=' || (bit && dohow == '-')) mode &= ~where;
10110f66f451Sopenharmony_ci        if (bit && dohow != '-') mode |= where;
10120f66f451Sopenharmony_ci      }
10130f66f451Sopenharmony_ci    }
10140f66f451Sopenharmony_ci
10150f66f451Sopenharmony_ci    if (!*str) break;
10160f66f451Sopenharmony_ci  }
10170f66f451Sopenharmony_ci
10180f66f451Sopenharmony_ci  return mode|extrabits;
10190f66f451Sopenharmony_cibarf:
10200f66f451Sopenharmony_ci  error_exit("bad mode '%s'", modestr);
10210f66f451Sopenharmony_ci}
10220f66f451Sopenharmony_ci
10230f66f451Sopenharmony_ci// Format access mode into a drwxrwxrwx string
10240f66f451Sopenharmony_civoid mode_to_string(mode_t mode, char *buf)
10250f66f451Sopenharmony_ci{
10260f66f451Sopenharmony_ci  char c, d;
10270f66f451Sopenharmony_ci  int i, bit;
10280f66f451Sopenharmony_ci
10290f66f451Sopenharmony_ci  buf[10]=0;
10300f66f451Sopenharmony_ci  for (i=0; i<9; i++) {
10310f66f451Sopenharmony_ci    bit = mode & (1<<i);
10320f66f451Sopenharmony_ci    c = i%3;
10330f66f451Sopenharmony_ci    if (!c && (mode & (1<<((d=i/3)+9)))) {
10340f66f451Sopenharmony_ci      c = "tss"[d];
10350f66f451Sopenharmony_ci      if (!bit) c &= ~0x20;
10360f66f451Sopenharmony_ci    } else c = bit ? "xwr"[c] : '-';
10370f66f451Sopenharmony_ci    buf[9-i] = c;
10380f66f451Sopenharmony_ci  }
10390f66f451Sopenharmony_ci
10400f66f451Sopenharmony_ci  if (S_ISDIR(mode)) c = 'd';
10410f66f451Sopenharmony_ci  else if (S_ISBLK(mode)) c = 'b';
10420f66f451Sopenharmony_ci  else if (S_ISCHR(mode)) c = 'c';
10430f66f451Sopenharmony_ci  else if (S_ISLNK(mode)) c = 'l';
10440f66f451Sopenharmony_ci  else if (S_ISFIFO(mode)) c = 'p';
10450f66f451Sopenharmony_ci  else if (S_ISSOCK(mode)) c = 's';
10460f66f451Sopenharmony_ci  else c = '-';
10470f66f451Sopenharmony_ci  *buf = c;
10480f66f451Sopenharmony_ci}
10490f66f451Sopenharmony_ci
10500f66f451Sopenharmony_ci// dirname() can modify its argument or return a pointer to a constant string
10510f66f451Sopenharmony_ci// This always returns a malloc() copy of everyting before last (run of ) '/'.
10520f66f451Sopenharmony_cichar *getdirname(char *name)
10530f66f451Sopenharmony_ci{
10540f66f451Sopenharmony_ci  char *s = xstrdup(name), *ss = strrchr(s, '/');
10550f66f451Sopenharmony_ci
10560f66f451Sopenharmony_ci  while (ss && *ss && *ss == '/' && s != ss) *ss-- = 0;
10570f66f451Sopenharmony_ci
10580f66f451Sopenharmony_ci  return s;
10590f66f451Sopenharmony_ci}
10600f66f451Sopenharmony_ci
10610f66f451Sopenharmony_ci// basename() can modify its argument or return a pointer to a constant string
10620f66f451Sopenharmony_ci// This just gives after the last '/' or the whole stirng if no /
10630f66f451Sopenharmony_cichar *getbasename(char *name)
10640f66f451Sopenharmony_ci{
10650f66f451Sopenharmony_ci  char *s = strrchr(name, '/');
10660f66f451Sopenharmony_ci
10670f66f451Sopenharmony_ci  if (s) return s+1;
10680f66f451Sopenharmony_ci
10690f66f451Sopenharmony_ci  return name;
10700f66f451Sopenharmony_ci}
10710f66f451Sopenharmony_ci
10720f66f451Sopenharmony_ci// Return pointer to xabspath(file) if file is under dir, else 0
10730f66f451Sopenharmony_cichar *fileunderdir(char *file, char *dir)
10740f66f451Sopenharmony_ci{
10750f66f451Sopenharmony_ci  char *s1 = xabspath(dir, 1), *s2 = xabspath(file, -1), *ss = s2;
10760f66f451Sopenharmony_ci  int rc = s1 && s2 && strstart(&ss, s1) && (!s1[1] || s2[strlen(s1)] == '/');
10770f66f451Sopenharmony_ci
10780f66f451Sopenharmony_ci  free(s1);
10790f66f451Sopenharmony_ci  if (!rc) free(s2);
10800f66f451Sopenharmony_ci
10810f66f451Sopenharmony_ci  return rc ? s2 : 0;
10820f66f451Sopenharmony_ci}
10830f66f451Sopenharmony_ci
10840f66f451Sopenharmony_ci// Execute a callback for each PID that matches a process name from a list.
10850f66f451Sopenharmony_civoid names_to_pid(char **names, int (*callback)(pid_t pid, char *name),
10860f66f451Sopenharmony_ci    int scripts)
10870f66f451Sopenharmony_ci{
10880f66f451Sopenharmony_ci  DIR *dp;
10890f66f451Sopenharmony_ci  struct dirent *entry;
10900f66f451Sopenharmony_ci
10910f66f451Sopenharmony_ci  if (!(dp = opendir("/proc"))) perror_exit("no /proc");
10920f66f451Sopenharmony_ci
10930f66f451Sopenharmony_ci  while ((entry = readdir(dp))) {
10940f66f451Sopenharmony_ci    unsigned u = atoi(entry->d_name);
10950f66f451Sopenharmony_ci    char *cmd = 0, *comm = 0, **cur;
10960f66f451Sopenharmony_ci    off_t len;
10970f66f451Sopenharmony_ci
10980f66f451Sopenharmony_ci    if (!u) continue;
10990f66f451Sopenharmony_ci
11000f66f451Sopenharmony_ci    // Comm is original name of executable (argv[0] could be #! interpreter)
11010f66f451Sopenharmony_ci    // but it's limited to 15 characters
11020f66f451Sopenharmony_ci    if (scripts) {
11030f66f451Sopenharmony_ci      sprintf(libbuf, "/proc/%u/comm", u);
11040f66f451Sopenharmony_ci      len = sizeof(libbuf);
11050f66f451Sopenharmony_ci      if (!(comm = readfileat(AT_FDCWD, libbuf, libbuf, &len)) || !len)
11060f66f451Sopenharmony_ci        continue;
11070f66f451Sopenharmony_ci      if (libbuf[len-1] == '\n') libbuf[--len] = 0;
11080f66f451Sopenharmony_ci    }
11090f66f451Sopenharmony_ci
11100f66f451Sopenharmony_ci    for (cur = names; *cur; cur++) {
11110f66f451Sopenharmony_ci      struct stat st1, st2;
11120f66f451Sopenharmony_ci      char *bb = getbasename(*cur);
11130f66f451Sopenharmony_ci      off_t len = strlen(bb);
11140f66f451Sopenharmony_ci
11150f66f451Sopenharmony_ci      // Fast path: only matching a filename (no path) that fits in comm.
11160f66f451Sopenharmony_ci      // `len` must be 14 or less because with a full 15 bytes we don't
11170f66f451Sopenharmony_ci      // know whether the name fit or was truncated.
11180f66f451Sopenharmony_ci      if (scripts && len<=14 && bb==*cur && !strcmp(comm, bb)) goto match;
11190f66f451Sopenharmony_ci
11200f66f451Sopenharmony_ci      // If we have a path to existing file only match if same inode
11210f66f451Sopenharmony_ci      if (bb!=*cur && !stat(*cur, &st1)) {
11220f66f451Sopenharmony_ci        char buf[32];
11230f66f451Sopenharmony_ci
11240f66f451Sopenharmony_ci        sprintf(buf, "/proc/%u/exe", u);
11250f66f451Sopenharmony_ci        if (stat(buf, &st2)) continue;
11260f66f451Sopenharmony_ci        if (st1.st_dev != st2.st_dev || st1.st_ino != st2.st_ino) continue;
11270f66f451Sopenharmony_ci        goto match;
11280f66f451Sopenharmony_ci      }
11290f66f451Sopenharmony_ci
11300f66f451Sopenharmony_ci      // Nope, gotta read command line to confirm
11310f66f451Sopenharmony_ci      if (!cmd) {
11320f66f451Sopenharmony_ci        sprintf(cmd = libbuf+16, "/proc/%u/cmdline", u);
11330f66f451Sopenharmony_ci        len = sizeof(libbuf)-17;
11340f66f451Sopenharmony_ci        if (!(cmd = readfileat(AT_FDCWD, cmd, cmd, &len))) continue;
11350f66f451Sopenharmony_ci        // readfile only guarantees one null terminator and we need two
11360f66f451Sopenharmony_ci        // (yes the kernel should do this for us, don't care)
11370f66f451Sopenharmony_ci        cmd[len] = 0;
11380f66f451Sopenharmony_ci      }
11390f66f451Sopenharmony_ci      if (!strcmp(bb, getbasename(cmd))) goto match;
11400f66f451Sopenharmony_ci      if (scripts && !strcmp(bb, getbasename(cmd+strlen(cmd)+1))) goto match;
11410f66f451Sopenharmony_ci      continue;
11420f66f451Sopenharmony_cimatch:
11430f66f451Sopenharmony_ci      if (callback(u, *cur)) break;
11440f66f451Sopenharmony_ci    }
11450f66f451Sopenharmony_ci  }
11460f66f451Sopenharmony_ci  closedir(dp);
11470f66f451Sopenharmony_ci}
11480f66f451Sopenharmony_ci
11490f66f451Sopenharmony_ci// display first "dgt" many digits of number plus unit (kilo-exabytes)
11500f66f451Sopenharmony_ciint human_readable_long(char *buf, unsigned long long num, int dgt, int style)
11510f66f451Sopenharmony_ci{
11520f66f451Sopenharmony_ci  unsigned long long snap = 0;
11530f66f451Sopenharmony_ci  int len, unit, divisor = (style&HR_1000) ? 1000 : 1024;
11540f66f451Sopenharmony_ci
11550f66f451Sopenharmony_ci  // Divide rounding up until we have 3 or fewer digits. Since the part we
11560f66f451Sopenharmony_ci  // print is decimal, the test is 999 even when we divide by 1024.
11570f66f451Sopenharmony_ci  // We can't run out of units because 1<<64 is 18 exabytes.
11580f66f451Sopenharmony_ci  for (unit = 0; snprintf(0, 0, "%llu", num)>dgt; unit++)
11590f66f451Sopenharmony_ci    num = ((snap = num)+(divisor/2))/divisor;
11600f66f451Sopenharmony_ci  len = sprintf(buf, "%llu", num);
11610f66f451Sopenharmony_ci  if (unit && len == 1) {
11620f66f451Sopenharmony_ci    // Redo rounding for 1.2M case, this works with and without HR_1000.
11630f66f451Sopenharmony_ci    num = snap/divisor;
11640f66f451Sopenharmony_ci    snap -= num*divisor;
11650f66f451Sopenharmony_ci    snap = ((snap*100)+50)/divisor;
11660f66f451Sopenharmony_ci    snap /= 10;
11670f66f451Sopenharmony_ci    len = sprintf(buf, "%llu.%llu", num, snap);
11680f66f451Sopenharmony_ci  }
11690f66f451Sopenharmony_ci  if (style & HR_SPACE) buf[len++] = ' ';
11700f66f451Sopenharmony_ci  if (unit) {
11710f66f451Sopenharmony_ci    unit = " kMGTPE"[unit];
11720f66f451Sopenharmony_ci
11730f66f451Sopenharmony_ci    if (!(style&HR_1000)) unit = toupper(unit);
11740f66f451Sopenharmony_ci    buf[len++] = unit;
11750f66f451Sopenharmony_ci  } else if (style & HR_B) buf[len++] = 'B';
11760f66f451Sopenharmony_ci  buf[len] = 0;
11770f66f451Sopenharmony_ci
11780f66f451Sopenharmony_ci  return len;
11790f66f451Sopenharmony_ci}
11800f66f451Sopenharmony_ci
11810f66f451Sopenharmony_ci// Give 3 digit estimate + units ala 999M or 1.7T
11820f66f451Sopenharmony_ciint human_readable(char *buf, unsigned long long num, int style)
11830f66f451Sopenharmony_ci{
11840f66f451Sopenharmony_ci  return human_readable_long(buf, num, 3, style);
11850f66f451Sopenharmony_ci}
11860f66f451Sopenharmony_ci
11870f66f451Sopenharmony_ci// The qsort man page says you can use alphasort, the posix committee
11880f66f451Sopenharmony_ci// disagreed, and doubled down: http://austingroupbugs.net/view.php?id=142
11890f66f451Sopenharmony_ci// So just do our own. (The const is entirely to humor the stupid compiler.)
11900f66f451Sopenharmony_ciint qstrcmp(const void *a, const void *b)
11910f66f451Sopenharmony_ci{
11920f66f451Sopenharmony_ci  return strcmp(*(char **)a, *(char **)b);
11930f66f451Sopenharmony_ci}
11940f66f451Sopenharmony_ci
11950f66f451Sopenharmony_ci// See https://tools.ietf.org/html/rfc4122, specifically section 4.4
11960f66f451Sopenharmony_ci// "Algorithms for Creating a UUID from Truly Random or Pseudo-Random
11970f66f451Sopenharmony_ci// Numbers".
11980f66f451Sopenharmony_civoid create_uuid(char *uuid)
11990f66f451Sopenharmony_ci{
12000f66f451Sopenharmony_ci  // "Set all the ... bits to randomly (or pseudo-randomly) chosen values".
12010f66f451Sopenharmony_ci  xgetrandom(uuid, 16, 0);
12020f66f451Sopenharmony_ci
12030f66f451Sopenharmony_ci  // "Set the four most significant bits ... of the time_hi_and_version
12040f66f451Sopenharmony_ci  // field to the 4-bit version number [4]".
12050f66f451Sopenharmony_ci  uuid[6] = (uuid[6] & 0x0F) | 0x40;
12060f66f451Sopenharmony_ci  // "Set the two most significant bits (bits 6 and 7) of
12070f66f451Sopenharmony_ci  // clock_seq_hi_and_reserved to zero and one, respectively".
12080f66f451Sopenharmony_ci  uuid[8] = (uuid[8] & 0x3F) | 0x80;
12090f66f451Sopenharmony_ci}
12100f66f451Sopenharmony_ci
12110f66f451Sopenharmony_cichar *show_uuid(char *uuid)
12120f66f451Sopenharmony_ci{
12130f66f451Sopenharmony_ci  char *out = libbuf;
12140f66f451Sopenharmony_ci  int i;
12150f66f451Sopenharmony_ci
12160f66f451Sopenharmony_ci  for (i=0; i<16; i++) out+=sprintf(out, "-%02x"+!(0x550&(1<<i)), uuid[i]);
12170f66f451Sopenharmony_ci  *out = 0;
12180f66f451Sopenharmony_ci
12190f66f451Sopenharmony_ci  return libbuf;
12200f66f451Sopenharmony_ci}
12210f66f451Sopenharmony_ci
12220f66f451Sopenharmony_ci// Returns pointer to letter at end, 0 if none. *start = initial %
12230f66f451Sopenharmony_cichar *next_printf(char *s, char **start)
12240f66f451Sopenharmony_ci{
12250f66f451Sopenharmony_ci  for (; *s; s++) {
12260f66f451Sopenharmony_ci    if (*s != '%') continue;
12270f66f451Sopenharmony_ci    if (*++s == '%') continue;
12280f66f451Sopenharmony_ci    if (start) *start = s-1;
12290f66f451Sopenharmony_ci    while (0 <= stridx("0'#-+ ", *s)) s++;
12300f66f451Sopenharmony_ci    while (isdigit(*s)) s++;
12310f66f451Sopenharmony_ci    if (*s == '.') s++;
12320f66f451Sopenharmony_ci    while (isdigit(*s)) s++;
12330f66f451Sopenharmony_ci
12340f66f451Sopenharmony_ci    return s;
12350f66f451Sopenharmony_ci  }
12360f66f451Sopenharmony_ci
12370f66f451Sopenharmony_ci  return 0;
12380f66f451Sopenharmony_ci}
12390f66f451Sopenharmony_ci
12400f66f451Sopenharmony_ciint dev_minor(int dev)
12410f66f451Sopenharmony_ci{
12420f66f451Sopenharmony_ci  return ((dev&0xfff00000)>>12)|(dev&0xff);
12430f66f451Sopenharmony_ci}
12440f66f451Sopenharmony_ci
12450f66f451Sopenharmony_ciint dev_major(int dev)
12460f66f451Sopenharmony_ci{
12470f66f451Sopenharmony_ci  return (dev&0xfff00)>>8;
12480f66f451Sopenharmony_ci}
12490f66f451Sopenharmony_ci
12500f66f451Sopenharmony_ciint dev_makedev(int major, int minor)
12510f66f451Sopenharmony_ci{
12520f66f451Sopenharmony_ci  return (minor&0xff)|((major&0xfff)<<8)|((minor&0xfff00)<<12);
12530f66f451Sopenharmony_ci}
12540f66f451Sopenharmony_ci
12550f66f451Sopenharmony_ci// Return cached passwd entries.
12560f66f451Sopenharmony_cistruct passwd *bufgetpwuid(uid_t uid)
12570f66f451Sopenharmony_ci{
12580f66f451Sopenharmony_ci  struct pwuidbuf_list {
12590f66f451Sopenharmony_ci    struct pwuidbuf_list *next;
12600f66f451Sopenharmony_ci    struct passwd pw;
12610f66f451Sopenharmony_ci  } *list = 0;
12620f66f451Sopenharmony_ci  struct passwd *temp;
12630f66f451Sopenharmony_ci  static struct pwuidbuf_list *pwuidbuf;
12640f66f451Sopenharmony_ci  unsigned size = 256;
12650f66f451Sopenharmony_ci
12660f66f451Sopenharmony_ci  // If we already have this one, return it.
12670f66f451Sopenharmony_ci  for (list = pwuidbuf; list; list = list->next)
12680f66f451Sopenharmony_ci    if (list->pw.pw_uid == uid) return &(list->pw);
12690f66f451Sopenharmony_ci
12700f66f451Sopenharmony_ci  for (;;) {
12710f66f451Sopenharmony_ci    list = xrealloc(list, size *= 2);
12720f66f451Sopenharmony_ci    errno = getpwuid_r(uid, &list->pw, sizeof(*list)+(char *)list,
12730f66f451Sopenharmony_ci      size-sizeof(*list), &temp);
12740f66f451Sopenharmony_ci    if (errno != ERANGE) break;
12750f66f451Sopenharmony_ci  }
12760f66f451Sopenharmony_ci
12770f66f451Sopenharmony_ci  if (!temp) {
12780f66f451Sopenharmony_ci    free(list);
12790f66f451Sopenharmony_ci
12800f66f451Sopenharmony_ci    return 0;
12810f66f451Sopenharmony_ci  }
12820f66f451Sopenharmony_ci  list->next = pwuidbuf;
12830f66f451Sopenharmony_ci  pwuidbuf = list;
12840f66f451Sopenharmony_ci
12850f66f451Sopenharmony_ci  return &list->pw;
12860f66f451Sopenharmony_ci}
12870f66f451Sopenharmony_ci
12880f66f451Sopenharmony_ci// Return cached group entries.
12890f66f451Sopenharmony_cistruct group *bufgetgrgid(gid_t gid)
12900f66f451Sopenharmony_ci{
12910f66f451Sopenharmony_ci  struct grgidbuf_list {
12920f66f451Sopenharmony_ci    struct grgidbuf_list *next;
12930f66f451Sopenharmony_ci    struct group gr;
12940f66f451Sopenharmony_ci  } *list = 0;
12950f66f451Sopenharmony_ci  struct group *temp;
12960f66f451Sopenharmony_ci  static struct grgidbuf_list *grgidbuf;
12970f66f451Sopenharmony_ci  unsigned size = 256;
12980f66f451Sopenharmony_ci
12990f66f451Sopenharmony_ci  for (list = grgidbuf; list; list = list->next)
13000f66f451Sopenharmony_ci    if (list->gr.gr_gid == gid) return &(list->gr);
13010f66f451Sopenharmony_ci
13020f66f451Sopenharmony_ci  for (;;) {
13030f66f451Sopenharmony_ci    list = xrealloc(list, size *= 2);
13040f66f451Sopenharmony_ci    errno = getgrgid_r(gid, &list->gr, sizeof(*list)+(char *)list,
13050f66f451Sopenharmony_ci      size-sizeof(*list), &temp);
13060f66f451Sopenharmony_ci    if (errno != ERANGE) break;
13070f66f451Sopenharmony_ci  }
13080f66f451Sopenharmony_ci  if (!temp) {
13090f66f451Sopenharmony_ci    free(list);
13100f66f451Sopenharmony_ci
13110f66f451Sopenharmony_ci    return 0;
13120f66f451Sopenharmony_ci  }
13130f66f451Sopenharmony_ci  list->next = grgidbuf;
13140f66f451Sopenharmony_ci  grgidbuf = list;
13150f66f451Sopenharmony_ci
13160f66f451Sopenharmony_ci  return &list->gr;
13170f66f451Sopenharmony_ci}
13180f66f451Sopenharmony_ci
13190f66f451Sopenharmony_ci// Always null terminates, returns 0 for failure, len for success
13200f66f451Sopenharmony_ciint readlinkat0(int dirfd, char *path, char *buf, int len)
13210f66f451Sopenharmony_ci{
13220f66f451Sopenharmony_ci  if (!len) return 0;
13230f66f451Sopenharmony_ci
13240f66f451Sopenharmony_ci  len = readlinkat(dirfd, path, buf, len-1);
13250f66f451Sopenharmony_ci  if (len<0) len = 0;
13260f66f451Sopenharmony_ci  buf[len] = 0;
13270f66f451Sopenharmony_ci
13280f66f451Sopenharmony_ci  return len;
13290f66f451Sopenharmony_ci}
13300f66f451Sopenharmony_ci
13310f66f451Sopenharmony_ciint readlink0(char *path, char *buf, int len)
13320f66f451Sopenharmony_ci{
13330f66f451Sopenharmony_ci  return readlinkat0(AT_FDCWD, path, buf, len);
13340f66f451Sopenharmony_ci}
13350f66f451Sopenharmony_ci
13360f66f451Sopenharmony_ci// Do regex matching with len argument to handle embedded NUL bytes in string
13370f66f451Sopenharmony_ciint regexec0(regex_t *preg, char *string, long len, int nmatch,
13380f66f451Sopenharmony_ci  regmatch_t *pmatch, int eflags)
13390f66f451Sopenharmony_ci{
13400f66f451Sopenharmony_ci  regmatch_t backup;
13410f66f451Sopenharmony_ci
13420f66f451Sopenharmony_ci  if (!nmatch) pmatch = &backup;
13430f66f451Sopenharmony_ci  pmatch->rm_so = 0;
13440f66f451Sopenharmony_ci  pmatch->rm_eo = len;
13450f66f451Sopenharmony_ci  return regexec(preg, string, nmatch, pmatch, eflags|REG_STARTEND);
13460f66f451Sopenharmony_ci}
13470f66f451Sopenharmony_ci
13480f66f451Sopenharmony_ci// Return user name or string representation of number, returned buffer
13490f66f451Sopenharmony_ci// lasts until next call.
13500f66f451Sopenharmony_cichar *getusername(uid_t uid)
13510f66f451Sopenharmony_ci{
13520f66f451Sopenharmony_ci  struct passwd *pw = bufgetpwuid(uid);
13530f66f451Sopenharmony_ci  static char unum[12];
13540f66f451Sopenharmony_ci
13550f66f451Sopenharmony_ci  sprintf(unum, "%u", (unsigned)uid);
13560f66f451Sopenharmony_ci  return pw ? pw->pw_name : unum;
13570f66f451Sopenharmony_ci}
13580f66f451Sopenharmony_ci
13590f66f451Sopenharmony_ci// Return group name or string representation of number, returned buffer
13600f66f451Sopenharmony_ci// lasts until next call.
13610f66f451Sopenharmony_cichar *getgroupname(gid_t gid)
13620f66f451Sopenharmony_ci{
13630f66f451Sopenharmony_ci  struct group *gr = bufgetgrgid(gid);
13640f66f451Sopenharmony_ci  static char gnum[12];
13650f66f451Sopenharmony_ci
13660f66f451Sopenharmony_ci  sprintf(gnum, "%u", (unsigned)gid);
13670f66f451Sopenharmony_ci  return gr ? gr->gr_name : gnum;
13680f66f451Sopenharmony_ci}
13690f66f451Sopenharmony_ci
13700f66f451Sopenharmony_ci// Iterate over lines in file, calling function. Function can write 0 to
13710f66f451Sopenharmony_ci// the line pointer if they want to keep it, or 1 to terminate processing,
13720f66f451Sopenharmony_ci// otherwise line is freed. Passed file descriptor is closed at the end.
13730f66f451Sopenharmony_ci// At EOF calls function(0, 0)
13740f66f451Sopenharmony_civoid do_lines(int fd, char delim, void (*call)(char **pline, long len))
13750f66f451Sopenharmony_ci{
13760f66f451Sopenharmony_ci  FILE *fp = fd ? xfdopen(fd, "r") : stdin;
13770f66f451Sopenharmony_ci
13780f66f451Sopenharmony_ci  for (;;) {
13790f66f451Sopenharmony_ci    char *line = 0;
13800f66f451Sopenharmony_ci    ssize_t len;
13810f66f451Sopenharmony_ci
13820f66f451Sopenharmony_ci    len = getdelim(&line, (void *)&len, delim, fp);
13830f66f451Sopenharmony_ci    if (len > 0) {
13840f66f451Sopenharmony_ci      call(&line, len);
13850f66f451Sopenharmony_ci      if (line == (void *)1) break;
13860f66f451Sopenharmony_ci      free(line);
13870f66f451Sopenharmony_ci    } else break;
13880f66f451Sopenharmony_ci  }
13890f66f451Sopenharmony_ci  call(0, 0);
13900f66f451Sopenharmony_ci
13910f66f451Sopenharmony_ci  if (fd) fclose(fp);
13920f66f451Sopenharmony_ci}
13930f66f451Sopenharmony_ci
13940f66f451Sopenharmony_ci// Return unix time in milliseconds
13950f66f451Sopenharmony_cilong long millitime(void)
13960f66f451Sopenharmony_ci{
13970f66f451Sopenharmony_ci  struct timespec ts;
13980f66f451Sopenharmony_ci
13990f66f451Sopenharmony_ci  clock_gettime(CLOCK_MONOTONIC, &ts);
14000f66f451Sopenharmony_ci  return ts.tv_sec*1000+ts.tv_nsec/1000000;
14010f66f451Sopenharmony_ci}
14020f66f451Sopenharmony_ci
14030f66f451Sopenharmony_ci// Formats `ts` in ISO format ("2018-06-28 15:08:58.846386216 -0700").
14040f66f451Sopenharmony_cichar *format_iso_time(char *buf, size_t len, struct timespec *ts)
14050f66f451Sopenharmony_ci{
14060f66f451Sopenharmony_ci  char *s = buf;
14070f66f451Sopenharmony_ci
14080f66f451Sopenharmony_ci  s += strftime(s, len, "%F %T", localtime(&(ts->tv_sec)));
14090f66f451Sopenharmony_ci  s += sprintf(s, ".%09ld ", ts->tv_nsec);
14100f66f451Sopenharmony_ci  s += strftime(s, len-strlen(buf), "%z", localtime(&(ts->tv_sec)));
14110f66f451Sopenharmony_ci
14120f66f451Sopenharmony_ci  return buf;
14130f66f451Sopenharmony_ci}
14140f66f451Sopenharmony_ci
14150f66f451Sopenharmony_ci// Syslog with the openlog/closelog, autodetecting daemon status via no tty
14160f66f451Sopenharmony_ci
14170f66f451Sopenharmony_civoid loggit(int priority, char *format, ...)
14180f66f451Sopenharmony_ci{
14190f66f451Sopenharmony_ci  int i, facility = LOG_DAEMON;
14200f66f451Sopenharmony_ci  va_list va;
14210f66f451Sopenharmony_ci
14220f66f451Sopenharmony_ci  for (i = 0; i<3; i++) if (isatty(i)) facility = LOG_AUTH;
14230f66f451Sopenharmony_ci  openlog(toys.which->name, LOG_PID, facility);
14240f66f451Sopenharmony_ci  va_start(va, format);
14250f66f451Sopenharmony_ci  vsyslog(priority, format, va);
14260f66f451Sopenharmony_ci  va_end(va);
14270f66f451Sopenharmony_ci  closelog();
14280f66f451Sopenharmony_ci}
14290f66f451Sopenharmony_ci
14300f66f451Sopenharmony_ci// Calculate tar packet checksum, with cksum field treated as 8 spaces
14310f66f451Sopenharmony_ciunsigned tar_cksum(void *data)
14320f66f451Sopenharmony_ci{
14330f66f451Sopenharmony_ci  unsigned i, cksum = 8*' ';
14340f66f451Sopenharmony_ci
14350f66f451Sopenharmony_ci  for (i = 0; i<500; i += (i==147) ? 9 : 1) cksum += ((char *)data)[i];
14360f66f451Sopenharmony_ci
14370f66f451Sopenharmony_ci  return cksum;
14380f66f451Sopenharmony_ci}
14390f66f451Sopenharmony_ci
14400f66f451Sopenharmony_ci// is this a valid tar header?
14410f66f451Sopenharmony_ciint is_tar_header(void *pkt)
14420f66f451Sopenharmony_ci{
14430f66f451Sopenharmony_ci  char *p = pkt;
14440f66f451Sopenharmony_ci  int i = 0;
14450f66f451Sopenharmony_ci
14460f66f451Sopenharmony_ci  if (p[257] && memcmp("ustar", p+257, 5)) return 0;
14470f66f451Sopenharmony_ci  if (p[148] != '0' && p[148] != ' ') return 0;
14480f66f451Sopenharmony_ci  sscanf(p+148, "%8o", &i);
14490f66f451Sopenharmony_ci
14500f66f451Sopenharmony_ci  return i && tar_cksum(pkt) == i;
14510f66f451Sopenharmony_ci}
1452