Home | History | Annotate | Download | only in lib
      1 /* xwrap.c - wrappers around existing library functions.
      2  *
      3  * Functions with the x prefix are wrappers that either succeed or kill the
      4  * program with an error message, but never return failure. They usually have
      5  * the same arguments and return value as the function they wrap.
      6  *
      7  * Copyright 2006 Rob Landley <rob (at) landley.net>
      8  */
      9 
     10 #include "toys.h"
     11 
     12 // strcpy and strncat with size checking. Size is the total space in "dest",
     13 // including null terminator. Exit if there's not enough space for the string
     14 // (including space for the null terminator), because silently truncating is
     15 // still broken behavior. (And leaving the string unterminated is INSANE.)
     16 void xstrncpy(char *dest, char *src, size_t size)
     17 {
     18   if (strlen(src)+1 > size) error_exit("'%s' > %ld bytes", src, (long)size);
     19   strcpy(dest, src);
     20 }
     21 
     22 void xstrncat(char *dest, char *src, size_t size)
     23 {
     24   long len = strlen(dest);
     25 
     26   if (len+strlen(src)+1 > size)
     27     error_exit("'%s%s' > %ld bytes", dest, src, (long)size);
     28   strcpy(dest+len, src);
     29 }
     30 
     31 // We replaced exit(), _exit(), and atexit() with xexit(), _xexit(), and
     32 // sigatexit(). This gives _xexit() the option to siglongjmp(toys.rebound, 1)
     33 // instead of exiting, lets xexit() report stdout flush failures to stderr
     34 // and change the exit code to indicate error, lets our toys.exit function
     35 // change happen for signal exit paths and lets us remove the functions
     36 // after we've called them.
     37 
     38 void _xexit(void)
     39 {
     40   if (toys.rebound) siglongjmp(*toys.rebound, 1);
     41 
     42   _exit(toys.exitval);
     43 }
     44 
     45 void xexit(void)
     46 {
     47   // Call toys.xexit functions in reverse order added.
     48   while (toys.xexit) {
     49     // This is typecasting xexit->arg to a function pointer,then calling it.
     50     // Using the invalid signal number 0 lets the signal handlers distinguish
     51     // an actual signal from a regular exit.
     52     ((void (*)(int))(toys.xexit->arg))(0);
     53 
     54     free(llist_pop(&toys.xexit));
     55   }
     56   if (fflush(NULL) || ferror(stdout))
     57     if (!toys.exitval) perror_msg("write");
     58   _xexit();
     59 }
     60 
     61 // Die unless we can allocate memory.
     62 void *xmalloc(size_t size)
     63 {
     64   void *ret = malloc(size);
     65   if (!ret) error_exit("xmalloc(%ld)", (long)size);
     66 
     67   return ret;
     68 }
     69 
     70 // Die unless we can allocate prezeroed memory.
     71 void *xzalloc(size_t size)
     72 {
     73   void *ret = xmalloc(size);
     74   memset(ret, 0, size);
     75   return ret;
     76 }
     77 
     78 // Die unless we can change the size of an existing allocation, possibly
     79 // moving it.  (Notice different arguments from libc function.)
     80 void *xrealloc(void *ptr, size_t size)
     81 {
     82   ptr = realloc(ptr, size);
     83   if (!ptr) error_exit("xrealloc");
     84 
     85   return ptr;
     86 }
     87 
     88 // Die unless we can allocate a copy of this many bytes of string.
     89 char *xstrndup(char *s, size_t n)
     90 {
     91   char *ret = strndup(s, ++n);
     92 
     93   if (!ret) error_exit("xstrndup");
     94   ret[--n] = 0;
     95 
     96   return ret;
     97 }
     98 
     99 // Die unless we can allocate a copy of this string.
    100 char *xstrdup(char *s)
    101 {
    102   return xstrndup(s, strlen(s));
    103 }
    104 
    105 void *xmemdup(void *s, long len)
    106 {
    107   void *ret = xmalloc(len);
    108   memcpy(ret, s, len);
    109 
    110   return ret;
    111 }
    112 
    113 // Die unless we can allocate enough space to sprintf() into.
    114 char *xmprintf(char *format, ...)
    115 {
    116   va_list va, va2;
    117   int len;
    118   char *ret;
    119 
    120   va_start(va, format);
    121   va_copy(va2, va);
    122 
    123   // How long is it?
    124   len = vsnprintf(0, 0, format, va);
    125   len++;
    126   va_end(va);
    127 
    128   // Allocate and do the sprintf()
    129   ret = xmalloc(len);
    130   vsnprintf(ret, len, format, va2);
    131   va_end(va2);
    132 
    133   return ret;
    134 }
    135 
    136 void xprintf(char *format, ...)
    137 {
    138   va_list va;
    139   va_start(va, format);
    140 
    141   vprintf(format, va);
    142   va_end(va);
    143   if (fflush(stdout) || ferror(stdout)) perror_exit("write");
    144 }
    145 
    146 void xputs(char *s)
    147 {
    148   if (EOF == puts(s) || fflush(stdout) || ferror(stdout)) perror_exit("write");
    149 }
    150 
    151 void xputc(char c)
    152 {
    153   if (EOF == fputc(c, stdout) || fflush(stdout) || ferror(stdout))
    154     perror_exit("write");
    155 }
    156 
    157 void xflush(void)
    158 {
    159   if (fflush(stdout) || ferror(stdout)) perror_exit("write");;
    160 }
    161 
    162 // This is called through the XVFORK macro because parent/child of vfork
    163 // share a stack, so child returning from a function would stomp the return
    164 // address parent would need. Solution: make vfork() an argument so processes
    165 // diverge before function gets called.
    166 pid_t __attribute__((returns_twice)) xvforkwrap(pid_t pid)
    167 {
    168   if (pid == -1) perror_exit("vfork");
    169 
    170   // Signal to xexec() and friends that we vforked so can't recurse
    171   toys.stacktop = 0;
    172 
    173   return pid;
    174 }
    175 
    176 // Die unless we can exec argv[] (or run builtin command).  Note that anything
    177 // with a path isn't a builtin, so /bin/sh won't match the builtin sh.
    178 void xexec(char **argv)
    179 {
    180   // Only recurse to builtin when we have multiplexer and !vfork context.
    181   if (CFG_TOYBOX && !CFG_TOYBOX_NORECURSE && toys.stacktop) toy_exec(argv);
    182   execvp(argv[0], argv);
    183 
    184   perror_msg("exec %s", argv[0]);
    185   toys.exitval = 127;
    186   if (!CFG_TOYBOX_FORK) _exit(toys.exitval);
    187   xexit();
    188 }
    189 
    190 // Spawn child process, capturing stdin/stdout.
    191 // argv[]: command to exec. If null, child re-runs original program with
    192 //         toys.stacktop zeroed.
    193 // pipes[2]: stdin, stdout of new process, only allocated if zero on way in,
    194 //           pass NULL to skip pipe allocation entirely.
    195 // return: pid of child process
    196 pid_t xpopen_both(char **argv, int *pipes)
    197 {
    198   int cestnepasun[4], pid;
    199 
    200   // Make the pipes? Note this won't set either pipe to 0 because if fds are
    201   // allocated in order and if fd0 was free it would go to cestnepasun[0]
    202   if (pipes) {
    203     for (pid = 0; pid < 2; pid++) {
    204       if (pipes[pid] != 0) continue;
    205       if (pipe(cestnepasun+(2*pid))) perror_exit("pipe");
    206       pipes[pid] = cestnepasun[pid+1];
    207     }
    208   }
    209 
    210   // Child process.
    211   if (!(pid = CFG_TOYBOX_FORK ? xfork() : XVFORK())) {
    212     // Dance of the stdin/stdout redirection.
    213     if (pipes) {
    214       // if we had no stdin/out, pipe handles could overlap, so test for it
    215       // and free up potentially overlapping pipe handles before reuse
    216       if (pipes[1] != -1) close(cestnepasun[2]);
    217       if (pipes[0] != -1) {
    218         close(cestnepasun[1]);
    219         if (cestnepasun[0]) {
    220           dup2(cestnepasun[0], 0);
    221           close(cestnepasun[0]);
    222         }
    223       }
    224       if (pipes[1] != -1) {
    225         dup2(cestnepasun[3], 1);
    226         dup2(cestnepasun[3], 2);
    227         if (cestnepasun[3] > 2 || !cestnepasun[3]) close(cestnepasun[3]);
    228       }
    229     }
    230     if (argv) xexec(argv);
    231 
    232     // In fork() case, force recursion because we know it's us.
    233     if (CFG_TOYBOX_FORK) {
    234       toy_init(toys.which, toys.argv);
    235       toys.stacktop = 0;
    236       toys.which->toy_main();
    237       xexit();
    238     // In vfork() case, exec /proc/self/exe with high bit of first letter set
    239     // to tell main() we reentered.
    240     } else {
    241       char *s = "/proc/self/exe";
    242 
    243       // We did a nommu-friendly vfork but must exec to continue.
    244       // setting high bit of argv[0][0] to let new process know
    245       **toys.argv |= 0x80;
    246       execv(s, toys.argv);
    247       perror_msg_raw(s);
    248 
    249       _exit(127);
    250     }
    251   }
    252 
    253   // Parent process
    254   if (!CFG_TOYBOX_FORK) **toys.argv &= 0x7f;
    255   if (pipes) {
    256     if (pipes[0] != -1) close(cestnepasun[0]);
    257     if (pipes[1] != -1) close(cestnepasun[3]);
    258   }
    259 
    260   return pid;
    261 }
    262 
    263 // Wait for child process to exit, then return adjusted exit code.
    264 int xwaitpid(pid_t pid)
    265 {
    266   int status;
    267 
    268   while (-1 == waitpid(pid, &status, 0) && errno == EINTR);
    269 
    270   return WIFEXITED(status) ? WEXITSTATUS(status) : WTERMSIG(status)+127;
    271 }
    272 
    273 int xpclose_both(pid_t pid, int *pipes)
    274 {
    275   if (pipes) {
    276     close(pipes[0]);
    277     close(pipes[1]);
    278   }
    279 
    280   return xwaitpid(pid);
    281 }
    282 
    283 // Wrapper to xpopen with a pipe for just one of stdin/stdout
    284 pid_t xpopen(char **argv, int *pipe, int isstdout)
    285 {
    286   int pipes[2], pid;
    287 
    288   pipes[!isstdout] = -1;
    289   pipes[!!isstdout] = 0;
    290   pid = xpopen_both(argv, pipes);
    291   *pipe = pid ? pipes[!!isstdout] : -1;
    292 
    293   return pid;
    294 }
    295 
    296 int xpclose(pid_t pid, int pipe)
    297 {
    298   close(pipe);
    299 
    300   return xpclose_both(pid, 0);
    301 }
    302 
    303 // Call xpopen and wait for it to finish, keeping existing stdin/stdout.
    304 int xrun(char **argv)
    305 {
    306   return xpclose_both(xpopen_both(argv, 0), 0);
    307 }
    308 
    309 void xaccess(char *path, int flags)
    310 {
    311   if (access(path, flags)) perror_exit("Can't access '%s'", path);
    312 }
    313 
    314 // Die unless we can delete a file.  (File must exist to be deleted.)
    315 void xunlink(char *path)
    316 {
    317   if (unlink(path)) perror_exit("unlink '%s'", path);
    318 }
    319 
    320 // Die unless we can open/create a file, returning file descriptor.
    321 // The meaning of O_CLOEXEC is reversed (it defaults on, pass it to disable)
    322 // and WARN_ONLY tells us not to exit.
    323 int xcreate_stdio(char *path, int flags, int mode)
    324 {
    325   int fd = open(path, (flags^O_CLOEXEC)&~WARN_ONLY, mode);
    326 
    327   if (fd == -1) ((mode&WARN_ONLY) ? perror_msg_raw : perror_exit_raw)(path);
    328   return fd;
    329 }
    330 
    331 // Die unless we can open a file, returning file descriptor.
    332 int xopen_stdio(char *path, int flags)
    333 {
    334   return xcreate_stdio(path, flags, 0);
    335 }
    336 
    337 void xpipe(int *pp)
    338 {
    339   if (pipe(pp)) perror_exit("xpipe");
    340 }
    341 
    342 void xclose(int fd)
    343 {
    344   if (close(fd)) perror_exit("xclose");
    345 }
    346 
    347 int xdup(int fd)
    348 {
    349   if (fd != -1) {
    350     fd = dup(fd);
    351     if (fd == -1) perror_exit("xdup");
    352   }
    353   return fd;
    354 }
    355 
    356 // Move file descriptor above stdin/stdout/stderr, using /dev/null to consume
    357 // old one. (We should never be called with stdin/stdout/stderr closed, but...)
    358 int notstdio(int fd)
    359 {
    360   if (fd<0) return fd;
    361 
    362   while (fd<3) {
    363     int fd2 = xdup(fd);
    364 
    365     close(fd);
    366     xopen_stdio("/dev/null", O_RDWR);
    367     fd = fd2;
    368   }
    369 
    370   return fd;
    371 }
    372 
    373 // Create a file but don't return stdin/stdout/stderr
    374 int xcreate(char *path, int flags, int mode)
    375 {
    376   return notstdio(xcreate_stdio(path, flags, mode));
    377 }
    378 
    379 // Open a file descriptor NOT in stdin/stdout/stderr
    380 int xopen(char *path, int flags)
    381 {
    382   return notstdio(xopen_stdio(path, flags));
    383 }
    384 
    385 // Open read only, treating "-" as a synonym for stdin, defaulting to warn only
    386 int openro(char *path, int flags)
    387 {
    388   if (!strcmp(path, "-")) return 0;
    389 
    390   return xopen(path, flags^WARN_ONLY);
    391 }
    392 
    393 // Open read only, treating "-" as a synonym for stdin.
    394 int xopenro(char *path)
    395 {
    396   return openro(path, O_RDONLY|WARN_ONLY);
    397 }
    398 
    399 FILE *xfdopen(int fd, char *mode)
    400 {
    401   FILE *f = fdopen(fd, mode);
    402 
    403   if (!f) perror_exit("xfdopen");
    404 
    405   return f;
    406 }
    407 
    408 // Die unless we can open/create a file, returning FILE *.
    409 FILE *xfopen(char *path, char *mode)
    410 {
    411   FILE *f = fopen(path, mode);
    412   if (!f) perror_exit("No file %s", path);
    413   return f;
    414 }
    415 
    416 // Die if there's an error other than EOF.
    417 size_t xread(int fd, void *buf, size_t len)
    418 {
    419   ssize_t ret = read(fd, buf, len);
    420   if (ret < 0) perror_exit("xread");
    421 
    422   return ret;
    423 }
    424 
    425 void xreadall(int fd, void *buf, size_t len)
    426 {
    427   if (len != readall(fd, buf, len)) perror_exit("xreadall");
    428 }
    429 
    430 // There's no xwriteall(), just xwrite().  When we read, there may or may not
    431 // be more data waiting.  When we write, there is data and it had better go
    432 // somewhere.
    433 
    434 void xwrite(int fd, void *buf, size_t len)
    435 {
    436   if (len != writeall(fd, buf, len)) perror_exit("xwrite");
    437 }
    438 
    439 // Die if lseek fails, probably due to being called on a pipe.
    440 
    441 off_t xlseek(int fd, off_t offset, int whence)
    442 {
    443   offset = lseek(fd, offset, whence);
    444   if (offset<0) perror_exit("lseek");
    445 
    446   return offset;
    447 }
    448 
    449 char *xgetcwd(void)
    450 {
    451   char *buf = getcwd(NULL, 0);
    452   if (!buf) perror_exit("xgetcwd");
    453 
    454   return buf;
    455 }
    456 
    457 void xstat(char *path, struct stat *st)
    458 {
    459   if(stat(path, st)) perror_exit("Can't stat %s", path);
    460 }
    461 
    462 // Cannonicalize path, even to file with one or more missing components at end.
    463 // if exact, require last path component to exist
    464 char *xabspath(char *path, int exact)
    465 {
    466   struct string_list *todo, *done = 0;
    467   int try = 9999, dirfd = open("/", 0);;
    468   char *ret;
    469 
    470   // If this isn't an absolute path, start with cwd.
    471   if (*path != '/') {
    472     char *temp = xgetcwd();
    473 
    474     splitpath(path, splitpath(temp, &todo));
    475     free(temp);
    476   } else splitpath(path, &todo);
    477 
    478   // Iterate through path components
    479   while (todo) {
    480     struct string_list *new = llist_pop(&todo), **tail;
    481     ssize_t len;
    482 
    483     if (!try--) {
    484       errno = ELOOP;
    485       goto error;
    486     }
    487 
    488     // Removable path componenents.
    489     if (!strcmp(new->str, ".") || !strcmp(new->str, "..")) {
    490       int x = new->str[1];
    491 
    492       free(new);
    493       if (x) {
    494         if (done) free(llist_pop(&done));
    495         len = 0;
    496       } else continue;
    497 
    498     // Is this a symlink?
    499     } else len = readlinkat(dirfd, new->str, libbuf, sizeof(libbuf));
    500 
    501     if (len>4095) goto error;
    502     if (len<1) {
    503       int fd;
    504       char *s = "..";
    505 
    506       // For .. just move dirfd
    507       if (len) {
    508         // Not a symlink: add to linked list, move dirfd, fail if error
    509         if ((exact || todo) && errno != EINVAL) goto error;
    510         new->next = done;
    511         done = new;
    512         if (errno == EINVAL && !todo) break;
    513         s = new->str;
    514       }
    515       fd = openat(dirfd, s, 0);
    516       if (fd == -1 && (exact || todo || errno != ENOENT)) goto error;
    517       close(dirfd);
    518       dirfd = fd;
    519       continue;
    520     }
    521 
    522     // If this symlink is to an absolute path, discard existing resolved path
    523     libbuf[len] = 0;
    524     if (*libbuf == '/') {
    525       llist_traverse(done, free);
    526       done=0;
    527       close(dirfd);
    528       dirfd = open("/", 0);
    529     }
    530     free(new);
    531 
    532     // prepend components of new path. Note symlink to "/" will leave new NULL
    533     tail = splitpath(libbuf, &new);
    534 
    535     // symlink to "/" will return null and leave tail alone
    536     if (new) {
    537       *tail = todo;
    538       todo = new;
    539     }
    540   }
    541   close(dirfd);
    542 
    543   // At this point done has the path, in reverse order. Reverse list while
    544   // calculating buffer length.
    545 
    546   try = 2;
    547   while (done) {
    548     struct string_list *temp = llist_pop(&done);;
    549 
    550     if (todo) try++;
    551     try += strlen(temp->str);
    552     temp->next = todo;
    553     todo = temp;
    554   }
    555 
    556   // Assemble return buffer
    557 
    558   ret = xmalloc(try);
    559   *ret = '/';
    560   ret [try = 1] = 0;
    561   while (todo) {
    562     if (try>1) ret[try++] = '/';
    563     try = stpcpy(ret+try, todo->str) - ret;
    564     free(llist_pop(&todo));
    565   }
    566 
    567   return ret;
    568 
    569 error:
    570   close(dirfd);
    571   llist_traverse(todo, free);
    572   llist_traverse(done, free);
    573 
    574   return NULL;
    575 }
    576 
    577 void xchdir(char *path)
    578 {
    579   if (chdir(path)) error_exit("chdir '%s'", path);
    580 }
    581 
    582 void xchroot(char *path)
    583 {
    584   if (chroot(path)) error_exit("chroot '%s'", path);
    585   xchdir("/");
    586 }
    587 
    588 struct passwd *xgetpwuid(uid_t uid)
    589 {
    590   struct passwd *pwd = getpwuid(uid);
    591   if (!pwd) error_exit("bad uid %ld", (long)uid);
    592   return pwd;
    593 }
    594 
    595 struct group *xgetgrgid(gid_t gid)
    596 {
    597   struct group *group = getgrgid(gid);
    598 
    599   if (!group) perror_exit("gid %ld", (long)gid);
    600   return group;
    601 }
    602 
    603 unsigned xgetuid(char *name)
    604 {
    605   struct passwd *up = getpwnam(name);
    606   char *s = 0;
    607   long uid;
    608 
    609   if (up) return up->pw_uid;
    610 
    611   uid = estrtol(name, &s, 10);
    612   if (!errno && s && !*s && uid>=0 && uid<=UINT_MAX) return uid;
    613 
    614   error_exit("bad user '%s'", name);
    615 }
    616 
    617 unsigned xgetgid(char *name)
    618 {
    619   struct group *gr = getgrnam(name);
    620   char *s = 0;
    621   long gid;
    622 
    623   if (gr) return gr->gr_gid;
    624 
    625   gid = estrtol(name, &s, 10);
    626   if (!errno && s && !*s && gid>=0 && gid<=UINT_MAX) return gid;
    627 
    628   error_exit("bad group '%s'", name);
    629 }
    630 
    631 struct passwd *xgetpwnam(char *name)
    632 {
    633   struct passwd *up = getpwnam(name);
    634 
    635   if (!up) perror_exit("user '%s'", name);
    636   return up;
    637 }
    638 
    639 struct group *xgetgrnam(char *name)
    640 {
    641   struct group *gr = getgrnam(name);
    642 
    643   if (!gr) perror_exit("group '%s'", name);
    644   return gr;
    645 }
    646 
    647 // setuid() can fail (for example, too many processes belonging to that user),
    648 // which opens a security hole if the process continues as the original user.
    649 
    650 void xsetuser(struct passwd *pwd)
    651 {
    652   if (initgroups(pwd->pw_name, pwd->pw_gid) || setgid(pwd->pw_uid)
    653       || setuid(pwd->pw_uid)) perror_exit("xsetuser '%s'", pwd->pw_name);
    654 }
    655 
    656 // This can return null (meaning file not found).  It just won't return null
    657 // for memory allocation reasons.
    658 char *xreadlink(char *name)
    659 {
    660   int len, size = 0;
    661   char *buf = 0;
    662 
    663   // Grow by 64 byte chunks until it's big enough.
    664   for(;;) {
    665     size +=64;
    666     buf = xrealloc(buf, size);
    667     len = readlink(name, buf, size);
    668 
    669     if (len<0) {
    670       free(buf);
    671       return 0;
    672     }
    673     if (len<size) {
    674       buf[len]=0;
    675       return buf;
    676     }
    677   }
    678 }
    679 
    680 char *xreadfile(char *name, char *buf, off_t len)
    681 {
    682   if (!(buf = readfile(name, buf, len))) perror_exit("Bad '%s'", name);
    683 
    684   return buf;
    685 }
    686 
    687 // The data argument to ioctl() is actually long, but it's usually used as
    688 // a pointer. If you need to feed in a number, do (void *)(long) typecast.
    689 int xioctl(int fd, int request, void *data)
    690 {
    691   int rc;
    692 
    693   errno = 0;
    694   rc = ioctl(fd, request, data);
    695   if (rc == -1 && errno) perror_exit("ioctl %x", request);
    696 
    697   return rc;
    698 }
    699 
    700 // Open a /var/run/NAME.pid file, dying if we can't write it or if it currently
    701 // exists and is this executable.
    702 void xpidfile(char *name)
    703 {
    704   char pidfile[256], spid[32];
    705   int i, fd;
    706   pid_t pid;
    707 
    708   sprintf(pidfile, "/var/run/%s.pid", name);
    709   // Try three times to open the sucker.
    710   for (i=0; i<3; i++) {
    711     fd = open(pidfile, O_CREAT|O_EXCL|O_WRONLY, 0644);
    712     if (fd != -1) break;
    713 
    714     // If it already existed, read it.  Loop for race condition.
    715     fd = open(pidfile, O_RDONLY);
    716     if (fd == -1) continue;
    717 
    718     // Is the old program still there?
    719     spid[xread(fd, spid, sizeof(spid)-1)] = 0;
    720     close(fd);
    721     pid = atoi(spid);
    722     if (pid < 1 || (kill(pid, 0) && errno == ESRCH)) unlink(pidfile);
    723 
    724     // An else with more sanity checking might be nice here.
    725   }
    726 
    727   if (i == 3) error_exit("xpidfile %s", name);
    728 
    729   xwrite(fd, spid, sprintf(spid, "%ld\n", (long)getpid()));
    730   close(fd);
    731 }
    732 
    733 // Copy the rest of in to out and close both files.
    734 
    735 long long xsendfile(int in, int out)
    736 {
    737   long long total = 0;
    738   long len;
    739 
    740   if (in<0) return 0;
    741   for (;;) {
    742     len = xread(in, libbuf, sizeof(libbuf));
    743     if (len<1) break;
    744     xwrite(out, libbuf, len);
    745     total += len;
    746   }
    747 
    748   return total;
    749 }
    750 
    751 // parse fractional seconds with optional s/m/h/d suffix
    752 long xparsetime(char *arg, long units, long *fraction)
    753 {
    754   double d;
    755   long l;
    756 
    757   if (CFG_TOYBOX_FLOAT) d = strtod(arg, &arg);
    758   else l = strtoul(arg, &arg, 10);
    759 
    760   // Parse suffix
    761   if (*arg) {
    762     int ismhd[]={1,60,3600,86400}, i = stridx("smhd", *arg);
    763 
    764     if (i == -1) error_exit("Unknown suffix '%c'", *arg);
    765     if (CFG_TOYBOX_FLOAT) d *= ismhd[i];
    766     else l *= ismhd[i];
    767   }
    768 
    769   if (CFG_TOYBOX_FLOAT) {
    770     l = (long)d;
    771     if (fraction) *fraction = units*(d-l);
    772   } else if (fraction) *fraction = 0;
    773 
    774   return l;
    775 }
    776 
    777 // Compile a regular expression into a regex_t
    778 void xregcomp(regex_t *preg, char *regex, int cflags)
    779 {
    780   int rc = regcomp(preg, regex, cflags);
    781 
    782   if (rc) {
    783     regerror(rc, preg, libbuf, sizeof(libbuf));
    784     error_exit("xregcomp: %s", libbuf);
    785   }
    786 }
    787 
    788 char *xtzset(char *new)
    789 {
    790   char *old = getenv("TZ");
    791 
    792   if (old) old = xstrdup(old);
    793   if (new ? setenv("TZ", new, 1) : unsetenv("TZ")) perror_exit("setenv");
    794   tzset();
    795 
    796   return old;
    797 }
    798 
    799 // Set a signal handler
    800 void xsignal(int signal, void *handler)
    801 {
    802   struct sigaction *sa = (void *)libbuf;
    803 
    804   memset(sa, 0, sizeof(struct sigaction));
    805   sa->sa_handler = handler;
    806 
    807   if (sigaction(signal, sa, 0)) perror_exit("xsignal %d", signal);
    808 }
    809