mrrl-logincaps

MRRL version of logincaps
git clone https://ccx.te2000.cz/git/mrrl-logincaps
Log | Files | Refs

xwrap.c (20042B)


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