toybox/lib/xwrap.c
<<
>>
Prefs
   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.)
  16void 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
  22void 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
  38void _xexit(void)
  39{
  40  if (toys.rebound) siglongjmp(*toys.rebound, 1);
  41
  42  _exit(toys.exitval);
  43}
  44
  45void 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  xflush(1);
  58  _xexit();
  59}
  60
  61void *xmmap(void *addr, size_t length, int prot, int flags, int fd, off_t off)
  62{
  63  void *ret = mmap(addr, length, prot, flags, fd, off);
  64  if (ret == MAP_FAILED) perror_exit("mmap");
  65  return ret;
  66}
  67
  68// Die unless we can allocate memory.
  69void *xmalloc(size_t size)
  70{
  71  void *ret = malloc(size);
  72  if (!ret) error_exit("xmalloc(%ld)", (long)size);
  73
  74  return ret;
  75}
  76
  77// Die unless we can allocate prezeroed memory.
  78void *xzalloc(size_t size)
  79{
  80  void *ret = xmalloc(size);
  81  memset(ret, 0, size);
  82  return ret;
  83}
  84
  85// Die unless we can change the size of an existing allocation, possibly
  86// moving it.  (Notice different arguments from libc function.)
  87void *xrealloc(void *ptr, size_t size)
  88{
  89  ptr = realloc(ptr, size);
  90  if (!ptr) error_exit("xrealloc");
  91
  92  return ptr;
  93}
  94
  95// Die unless we can allocate a copy of this many bytes of string.
  96char *xstrndup(char *s, size_t n)
  97{
  98  char *ret = strndup(s, n);
  99
 100  if (!ret) error_exit("xstrndup");
 101
 102  return ret;
 103}
 104
 105// Die unless we can allocate a copy of this string.
 106char *xstrdup(char *s)
 107{
 108  return xstrndup(s, strlen(s));
 109}
 110
 111void *xmemdup(void *s, long len)
 112{
 113  void *ret = xmalloc(len);
 114  memcpy(ret, s, len);
 115
 116  return ret;
 117}
 118
 119// Die unless we can allocate enough space to sprintf() into.
 120char *xmprintf(char *format, ...)
 121{
 122  va_list va, va2;
 123  int len;
 124  char *ret;
 125
 126  va_start(va, format);
 127  va_copy(va2, va);
 128
 129  // How long is it?
 130  len = vsnprintf(0, 0, format, va);
 131  len++;
 132  va_end(va);
 133
 134  // Allocate and do the sprintf()
 135  ret = xmalloc(len);
 136  vsnprintf(ret, len, format, va2);
 137  va_end(va2);
 138
 139  return ret;
 140}
 141
 142// if !flush just check for error on stdout without flushing 
 143void xflush(int flush)
 144{
 145  if ((flush && fflush(0)) || ferror(stdout))
 146    if (!toys.exitval) perror_msg("write");
 147}
 148
 149void xprintf(char *format, ...)
 150{
 151  va_list va;
 152  va_start(va, format);
 153
 154  vprintf(format, va);
 155  va_end(va);
 156  xflush(0);
 157}
 158
 159// Put string with length (does not append newline)
 160void xputsl(char *s, int len)
 161{
 162  xflush(1);
 163  xwrite(1, s, len);
 164}
 165
 166// xputs with no newline
 167void xputsn(char *s)
 168{
 169  xputsl(s, strlen(s));
 170}
 171
 172// Write string to stdout with newline, flushing and checking for errors
 173void xputs(char *s)
 174{
 175  puts(s);
 176  xflush(0);
 177}
 178
 179void xputc(char c)
 180{
 181  if (EOF == fputc(c, stdout)) perror_exit("write");
 182  xflush(0);
 183}
 184
 185// daemonize via vfork(). Does not chdir("/"), caller should do that first
 186// note: restarts process from command_main()
 187void xvdaemon(void)
 188{
 189  int fd;
 190
 191  // vfork and exec /proc/self/exe
 192  if (toys.stacktop) {
 193    xpopen_both(0, 0);
 194    _exit(0);
 195  }
 196
 197  // new session id, point fd 0-2 at /dev/null, detach from tty
 198  setsid();
 199  close(0);
 200  xopen_stdio("/dev/null", O_RDWR);
 201  dup2(0, 1);
 202  if (-1 != (fd = open("/dev/tty", O_RDONLY))) {
 203    ioctl(fd, TIOCNOTTY);
 204    close(fd);
 205  }
 206  dup2(0, 2);
 207}
 208
 209// This is called through the XVFORK macro because parent/child of vfork
 210// share a stack, so child returning from a function would stomp the return
 211// address parent would need. Solution: make vfork() an argument so processes
 212// diverge before function gets called.
 213pid_t __attribute__((returns_twice)) xvforkwrap(pid_t pid)
 214{
 215  if (pid == -1) perror_exit("vfork");
 216
 217  // Signal to xexec() and friends that we vforked so can't recurse
 218  if (!pid) toys.stacktop = 0;
 219
 220  return pid;
 221}
 222
 223// Die unless we can exec argv[] (or run builtin command).  Note that anything
 224// with a path isn't a builtin, so /bin/sh won't match the builtin sh.
 225void xexec(char **argv)
 226{
 227  // Only recurse to builtin when we have multiplexer and !vfork context.
 228  if (CFG_TOYBOX && !CFG_TOYBOX_NORECURSE && toys.stacktop && **argv != '/')
 229    toy_exec(argv);
 230  execvp(argv[0], argv);
 231
 232  toys.exitval = 126+(errno == ENOENT);
 233  perror_msg("exec %s", argv[0]);
 234  if (!toys.stacktop) _exit(toys.exitval);
 235  xexit();
 236}
 237
 238// Spawn child process, capturing stdin/stdout.
 239// argv[]: command to exec. If null, child re-runs original program with
 240//         toys.stacktop zeroed.
 241// pipes[2]: Filehandle to move to stdin/stdout of new process.
 242//           If -1, replace with pipe handle connected to stdin/stdout.
 243//           NULL treated as {0, 1}, I.E. leave stdin/stdout as is
 244// return: pid of child process
 245pid_t xpopen_setup(char **argv, int *pipes, void (*callback)(char **argv))
 246{
 247  int cestnepasun[4], pid;
 248
 249  // Make the pipes?
 250  memset(cestnepasun, 0, sizeof(cestnepasun));
 251  if (pipes) for (pid = 0; pid < 2; pid++) {
 252    if (pipes[pid] != -1) continue;
 253    if (pipe(cestnepasun+(2*pid))) perror_exit("pipe");
 254  }
 255
 256  if (!(pid = CFG_TOYBOX_FORK ? xfork() : XVFORK())) {
 257    // Child process: Dance of the stdin/stdout redirection.
 258    // cestnepasun[1]->cestnepasun[0] and cestnepasun[3]->cestnepasun[2]
 259    if (pipes) {
 260      // if we had no stdin/out, pipe handles could overlap, so test for it
 261      // and free up potentially overlapping pipe handles before reuse
 262
 263      // in child, close read end of output pipe, use write end as new stdout
 264      if (cestnepasun[2]) {
 265        close(cestnepasun[2]);
 266        pipes[1] = cestnepasun[3];
 267      }
 268
 269      // in child, close write end of input pipe, use read end as new stdin
 270      if (cestnepasun[1]) {
 271        close(cestnepasun[1]);
 272        pipes[0] = cestnepasun[0];
 273      }
 274
 275      // If swapping stdin/stdout, dup a filehandle that gets closed before use
 276      if (!pipes[1]) pipes[1] = dup(0);
 277
 278      // Are we redirecting stdin?
 279      if (pipes[0]) {
 280        dup2(pipes[0], 0);
 281        close(pipes[0]);
 282      }
 283
 284      // Are we redirecting stdout?
 285      if (pipes[1] != 1) {
 286        dup2(pipes[1], 1);
 287        close(pipes[1]);
 288      }
 289    }
 290    if (callback) callback(argv);
 291    if (argv) xexec(argv);
 292
 293    // In fork() case, force recursion because we know it's us.
 294    if (CFG_TOYBOX_FORK) {
 295      toy_init(toys.which, toys.argv);
 296      toys.stacktop = 0;
 297      toys.which->toy_main();
 298      xexit();
 299    // In vfork() case, exec /proc/self/exe with high bit of first letter set
 300    // to tell main() we reentered.
 301    } else {
 302      char *s = "/proc/self/exe";
 303
 304      // We did a nommu-friendly vfork but must exec to continue.
 305      // setting high bit of argv[0][0] to let new process know
 306      **toys.argv |= 0x80;
 307      execv(s, toys.argv);
 308      if ((s = getenv("_"))) execv(s, toys.argv);
 309      perror_msg_raw(s);
 310
 311      _exit(127);
 312    }
 313  }
 314
 315  // Parent process: vfork had a shared environment, clean up.
 316  if (!CFG_TOYBOX_FORK) **toys.argv &= 0x7f;
 317
 318  if (pipes) {
 319    if (cestnepasun[1]) {
 320      pipes[0] = cestnepasun[1];
 321      close(cestnepasun[0]);
 322    }
 323    if (cestnepasun[2]) {
 324      pipes[1] = cestnepasun[2];
 325      close(cestnepasun[3]);
 326    }
 327  }
 328
 329  return pid;
 330}
 331
 332pid_t xpopen_both(char **argv, int *pipes)
 333{
 334  return xpopen_setup(argv, pipes, 0);
 335}
 336
 337
 338// Wait for child process to exit, then return adjusted exit code.
 339int xwaitpid(pid_t pid)
 340{
 341  int status;
 342
 343  while (-1 == waitpid(pid, &status, 0) && errno == EINTR);
 344
 345  return WIFEXITED(status) ? WEXITSTATUS(status) : WTERMSIG(status)+128;
 346}
 347
 348int xpclose_both(pid_t pid, int *pipes)
 349{
 350  if (pipes) {
 351    close(pipes[0]);
 352    close(pipes[1]);
 353  }
 354
 355  return xwaitpid(pid);
 356}
 357
 358// Wrapper to xpopen with a pipe for just one of stdin/stdout
 359pid_t xpopen(char **argv, int *pipe, int isstdout)
 360{
 361  int pipes[2], pid;
 362
 363  pipes[0] = isstdout ? 0 : -1;
 364  pipes[1] = isstdout ? -1 : 1;
 365  pid = xpopen_both(argv, pipes);
 366  *pipe = pid ? pipes[!!isstdout] : -1;
 367
 368  return pid;
 369}
 370
 371int xpclose(pid_t pid, int pipe)
 372{
 373  close(pipe);
 374
 375  return xpclose_both(pid, 0);
 376}
 377
 378// Call xpopen and wait for it to finish, keeping existing stdin/stdout.
 379int xrun(char **argv)
 380{
 381  return xpclose_both(xpopen_both(argv, 0), 0);
 382}
 383
 384void xaccess(char *path, int flags)
 385{
 386  if (access(path, flags)) perror_exit("Can't access '%s'", path);
 387}
 388
 389// Die unless we can delete a file.  (File must exist to be deleted.)
 390void xunlink(char *path)
 391{
 392  if (unlink(path)) perror_exit("unlink '%s'", path);
 393}
 394
 395// Die unless we can open/create a file, returning file descriptor.
 396// The meaning of O_CLOEXEC is reversed (it defaults on, pass it to disable)
 397// and WARN_ONLY tells us not to exit.
 398int xcreate_stdio(char *path, int flags, int mode)
 399{
 400  int fd = open(path, (flags^O_CLOEXEC)&~WARN_ONLY, mode);
 401
 402  if (fd == -1) ((flags&WARN_ONLY) ? perror_msg_raw : perror_exit_raw)(path);
 403  return fd;
 404}
 405
 406// Die unless we can open a file, returning file descriptor.
 407int xopen_stdio(char *path, int flags)
 408{
 409  return xcreate_stdio(path, flags, 0);
 410}
 411
 412void xpipe(int *pp)
 413{
 414  if (pipe(pp)) perror_exit("xpipe");
 415}
 416
 417void xclose(int fd)
 418{
 419  if (close(fd)) perror_exit("xclose");
 420}
 421
 422int xdup(int fd)
 423{
 424  if (fd != -1) {
 425    fd = dup(fd);
 426    if (fd == -1) perror_exit("xdup");
 427  }
 428  return fd;
 429}
 430
 431// Move file descriptor above stdin/stdout/stderr, using /dev/null to consume
 432// old one. (We should never be called with stdin/stdout/stderr closed, but...)
 433int notstdio(int fd)
 434{
 435  if (fd<0) return fd;
 436
 437  while (fd<3) {
 438    int fd2 = xdup(fd);
 439
 440    close(fd);
 441    xopen_stdio("/dev/null", O_RDWR);
 442    fd = fd2;
 443  }
 444
 445  return fd;
 446}
 447
 448void xrename(char *from, char *to)
 449{
 450  if (rename(from, to)) perror_exit("rename %s -> %s", from, to);
 451}
 452
 453int xtempfile(char *name, char **tempname)
 454{
 455  int fd;
 456
 457   *tempname = xmprintf("%s%s", name, "XXXXXX");
 458  if(-1 == (fd = mkstemp(*tempname))) error_exit("no temp file");
 459
 460  return fd;
 461}
 462
 463// Create a file but don't return stdin/stdout/stderr
 464int xcreate(char *path, int flags, int mode)
 465{
 466  return notstdio(xcreate_stdio(path, flags, mode));
 467}
 468
 469// Open a file descriptor NOT in stdin/stdout/stderr
 470int xopen(char *path, int flags)
 471{
 472  return notstdio(xopen_stdio(path, flags));
 473}
 474
 475// Open read only, treating "-" as a synonym for stdin, defaulting to warn only
 476int openro(char *path, int flags)
 477{
 478  if (!strcmp(path, "-")) return 0;
 479
 480  return xopen(path, flags^WARN_ONLY);
 481}
 482
 483// Open read only, treating "-" as a synonym for stdin.
 484int xopenro(char *path)
 485{
 486  return openro(path, O_RDONLY|WARN_ONLY);
 487}
 488
 489FILE *xfdopen(int fd, char *mode)
 490{
 491  FILE *f = fdopen(fd, mode);
 492
 493  if (!f) perror_exit("xfdopen");
 494
 495  return f;
 496}
 497
 498// Die unless we can open/create a file, returning FILE *.
 499FILE *xfopen(char *path, char *mode)
 500{
 501  FILE *f = fopen(path, mode);
 502  if (!f) perror_exit("No file %s", path);
 503  return f;
 504}
 505
 506// Die if there's an error other than EOF.
 507size_t xread(int fd, void *buf, size_t len)
 508{
 509  ssize_t ret = read(fd, buf, len);
 510  if (ret < 0) perror_exit("xread");
 511
 512  return ret;
 513}
 514
 515void xreadall(int fd, void *buf, size_t len)
 516{
 517  if (len != readall(fd, buf, len)) perror_exit("xreadall");
 518}
 519
 520// There's no xwriteall(), just xwrite().  When we read, there may or may not
 521// be more data waiting.  When we write, there is data and it had better go
 522// somewhere.
 523
 524void xwrite(int fd, void *buf, size_t len)
 525{
 526  if (len != writeall(fd, buf, len)) perror_exit("xwrite");
 527}
 528
 529// Die if lseek fails, probably due to being called on a pipe.
 530
 531off_t xlseek(int fd, off_t offset, int whence)
 532{
 533  offset = lseek(fd, offset, whence);
 534  if (offset<0) perror_exit("lseek");
 535
 536  return offset;
 537}
 538
 539char *xgetcwd(void)
 540{
 541  char *buf = getcwd(NULL, 0);
 542  if (!buf) perror_exit("xgetcwd");
 543
 544  return buf;
 545}
 546
 547void xstat(char *path, struct stat *st)
 548{
 549  if(stat(path, st)) perror_exit("Can't stat %s", path);
 550}
 551
 552// Canonicalize path, even to file with one or more missing components at end.
 553// Returns allocated string for pathname or NULL if doesn't exist
 554// exact = 1 file must exist, 0 dir must exist, -1 show theoretical location,
 555// -2 don't resolve last file
 556char *xabspath(char *path, int exact)
 557{
 558  struct string_list *todo, *done = 0;
 559  int try = 9999, dirfd = open("/", O_PATH), missing = 0;
 560  char *ret;
 561
 562  // If this isn't an absolute path, start with cwd.
 563  if (*path != '/') {
 564    char *temp = xgetcwd();
 565
 566    splitpath(path, splitpath(temp, &todo));
 567    free(temp);
 568  } else splitpath(path, &todo);
 569
 570  // Iterate through path components in todo, prepend processed ones to done.
 571  while (todo) {
 572    struct string_list *new = llist_pop(&todo), **tail;
 573    ssize_t len;
 574
 575    // Eventually break out of endless loops
 576    if (!try--) {
 577      errno = ELOOP;
 578      goto error;
 579    }
 580
 581    // Removable path componenents.
 582    if (!strcmp(new->str, ".") || !strcmp(new->str, "..")) {
 583      int x = new->str[1];
 584
 585      free(new);
 586      if (!x) continue;
 587      if (done) free(llist_pop(&done));
 588      len = 0;
 589
 590      if (missing) missing--;
 591      else {
 592        if (-1 == (x = openat(dirfd, "..", O_PATH))) goto error;
 593        close(dirfd);
 594        dirfd = x;
 595      }
 596      continue;
 597    }
 598
 599    // Is this a symlink?
 600    if (exact == -2 && !todo) len = 0;
 601    else len = readlinkat(dirfd, new->str, libbuf, sizeof(libbuf));
 602    if (len>4095) goto error;
 603
 604    // Not a symlink: add to linked list, move dirfd, fail if error
 605    if (len<1) {
 606      int fd;
 607
 608      new->next = done;
 609      done = new;
 610      if (errno == EINVAL && !todo) break;
 611      if (errno == ENOENT && exact<0) {
 612        missing++;
 613        continue;
 614      }
 615      if (errno != EINVAL && (exact || todo)) goto error;
 616
 617      fd = openat(dirfd, new->str, O_PATH);
 618      if (fd == -1 && (exact || todo || errno != ENOENT)) goto error;
 619      close(dirfd);
 620      dirfd = fd;
 621      continue;
 622    }
 623
 624    // If this symlink is to an absolute path, discard existing resolved path
 625    libbuf[len] = 0;
 626    if (*libbuf == '/') {
 627      llist_traverse(done, free);
 628      done=0;
 629      close(dirfd);
 630      dirfd = open("/", O_PATH);
 631    }
 632    free(new);
 633
 634    // prepend components of new path. Note symlink to "/" will leave new NULL
 635    tail = splitpath(libbuf, &new);
 636
 637    // symlink to "/" will return null and leave tail alone
 638    if (new) {
 639      *tail = todo;
 640      todo = new;
 641    }
 642  }
 643  close(dirfd);
 644
 645  // At this point done has the path, in reverse order. Reverse list while
 646  // calculating buffer length.
 647
 648  try = 2;
 649  while (done) {
 650    struct string_list *temp = llist_pop(&done);
 651
 652    if (todo) try++;
 653    try += strlen(temp->str);
 654    temp->next = todo;
 655    todo = temp;
 656  }
 657
 658  // Assemble return buffer
 659
 660  ret = xmalloc(try);
 661  *ret = '/';
 662  ret [try = 1] = 0;
 663  while (todo) {
 664    if (try>1) ret[try++] = '/';
 665    try = stpcpy(ret+try, todo->str) - ret;
 666    free(llist_pop(&todo));
 667  }
 668
 669  return ret;
 670
 671error:
 672  close(dirfd);
 673  llist_traverse(todo, free);
 674  llist_traverse(done, free);
 675
 676  return 0;
 677}
 678
 679void xchdir(char *path)
 680{
 681  if (chdir(path)) perror_exit("chdir '%s'", path);
 682}
 683
 684void xchroot(char *path)
 685{
 686  if (chroot(path)) error_exit("chroot '%s'", path);
 687  xchdir("/");
 688}
 689
 690struct passwd *xgetpwuid(uid_t uid)
 691{
 692  struct passwd *pwd = getpwuid(uid);
 693  if (!pwd) error_exit("bad uid %ld", (long)uid);
 694  return pwd;
 695}
 696
 697struct group *xgetgrgid(gid_t gid)
 698{
 699  struct group *group = getgrgid(gid);
 700
 701  if (!group) perror_exit("gid %ld", (long)gid);
 702  return group;
 703}
 704
 705unsigned xgetuid(char *name)
 706{
 707  struct passwd *up = getpwnam(name);
 708  char *s = 0;
 709  long uid;
 710
 711  if (up) return up->pw_uid;
 712
 713  uid = estrtol(name, &s, 10);
 714  if (!errno && s && !*s && uid>=0 && uid<=UINT_MAX) return uid;
 715
 716  error_exit("bad user '%s'", name);
 717}
 718
 719unsigned xgetgid(char *name)
 720{
 721  struct group *gr = getgrnam(name);
 722  char *s = 0;
 723  long gid;
 724
 725  if (gr) return gr->gr_gid;
 726
 727  gid = estrtol(name, &s, 10);
 728  if (!errno && s && !*s && gid>=0 && gid<=UINT_MAX) return gid;
 729
 730  error_exit("bad group '%s'", name);
 731}
 732
 733struct passwd *xgetpwnam(char *name)
 734{
 735  struct passwd *up = getpwnam(name);
 736
 737  if (!up) perror_exit("user '%s'", name);
 738  return up;
 739}
 740
 741struct group *xgetgrnam(char *name)
 742{
 743  struct group *gr = getgrnam(name);
 744
 745  if (!gr) perror_exit("group '%s'", name);
 746  return gr;
 747}
 748
 749// setuid() can fail (for example, too many processes belonging to that user),
 750// which opens a security hole if the process continues as the original user.
 751
 752void xsetuser(struct passwd *pwd)
 753{
 754  if (initgroups(pwd->pw_name, pwd->pw_gid) || setgid(pwd->pw_uid)
 755      || setuid(pwd->pw_uid)) perror_exit("xsetuser '%s'", pwd->pw_name);
 756}
 757
 758// This can return null (meaning file not found).  It just won't return null
 759// for memory allocation reasons.
 760char *xreadlink(char *name)
 761{
 762  int len, size = 0;
 763  char *buf = 0;
 764
 765  // Grow by 64 byte chunks until it's big enough.
 766  for(;;) {
 767    size +=64;
 768    buf = xrealloc(buf, size);
 769    len = readlink(name, buf, size);
 770
 771    if (len<0) {
 772      free(buf);
 773      return 0;
 774    }
 775    if (len<size) {
 776      buf[len]=0;
 777      return buf;
 778    }
 779  }
 780}
 781
 782char *xreadfile(char *name, char *buf, off_t len)
 783{
 784  if (!(buf = readfile(name, buf, len))) perror_exit("Bad '%s'", name);
 785
 786  return buf;
 787}
 788
 789// The data argument to ioctl() is actually long, but it's usually used as
 790// a pointer. If you need to feed in a number, do (void *)(long) typecast.
 791int xioctl(int fd, int request, void *data)
 792{
 793  int rc;
 794
 795  errno = 0;
 796  rc = ioctl(fd, request, data);
 797  if (rc == -1 && errno) perror_exit("ioctl %x", request);
 798
 799  return rc;
 800}
 801
 802// Open a /var/run/NAME.pid file, dying if we can't write it or if it currently
 803// exists and is this executable.
 804void xpidfile(char *name)
 805{
 806  char pidfile[256], spid[32];
 807  int i, fd;
 808  pid_t pid;
 809
 810  sprintf(pidfile, "/var/run/%s.pid", name);
 811  // Try three times to open the sucker.
 812  for (i=0; i<3; i++) {
 813    fd = open(pidfile, O_CREAT|O_EXCL|O_WRONLY, 0644);
 814    if (fd != -1) break;
 815
 816    // If it already existed, read it.  Loop for race condition.
 817    fd = open(pidfile, O_RDONLY);
 818    if (fd == -1) continue;
 819
 820    // Is the old program still there?
 821    spid[xread(fd, spid, sizeof(spid)-1)] = 0;
 822    close(fd);
 823    pid = atoi(spid);
 824    if (pid < 1 || (kill(pid, 0) && errno == ESRCH)) unlink(pidfile);
 825
 826    // An else with more sanity checking might be nice here.
 827  }
 828
 829  if (i == 3) error_exit("xpidfile %s", name);
 830
 831  xwrite(fd, spid, sprintf(spid, "%ld\n", (long)getpid()));
 832  close(fd);
 833}
 834
 835// error_exit if we couldn't copy all bytes
 836long long xsendfile_len(int in, int out, long long bytes)
 837{
 838  long long len = sendfile_len(in, out, bytes, 0);
 839
 840  if (bytes != -1 && bytes != len) {
 841    if (out == 1 && len<0) xexit();
 842    error_exit("short %s", (len<0) ? "write" : "read");
 843  }
 844
 845  return len;
 846}
 847
 848// warn and pad with zeroes if we couldn't copy all bytes
 849void xsendfile_pad(int in, int out, long long len)
 850{
 851  len -= xsendfile_len(in, out, len);
 852  if (len) {
 853    perror_msg("short read");
 854    memset(libbuf, 0, sizeof(libbuf));
 855    while (len) {
 856      int i = len>sizeof(libbuf) ? sizeof(libbuf) : len;
 857
 858      xwrite(out, libbuf, i);
 859      len -= i;
 860    }
 861  }
 862}
 863
 864// copy all of in to out
 865long long xsendfile(int in, int out)
 866{
 867  return xsendfile_len(in, out, -1);
 868}
 869
 870double xstrtod(char *s)
 871{
 872  char *end;
 873  double d;
 874
 875  errno = 0;
 876  d = strtod(s, &end);
 877  if (!errno && *end) errno = E2BIG;
 878  if (errno) perror_exit("strtod %s", s);
 879
 880  return d;
 881}
 882
 883// parse fractional seconds with optional s/m/h/d suffix
 884long xparsetime(char *arg, long zeroes, long *fraction)
 885{
 886  long l, fr = 0, mask = 1;
 887  char *end;
 888
 889  if (*arg != '.' && !isdigit(*arg)) error_exit("Not a number '%s'", arg);
 890  l = strtoul(arg, &end, 10);
 891  if (*end == '.') {
 892    end++;
 893    while (zeroes--) {
 894      fr *= 10;
 895      mask *= 10;
 896      if (isdigit(*end)) fr += *end++-'0';
 897    }
 898    while (isdigit(*end)) end++;
 899  }
 900
 901  // Parse suffix
 902  if (*end) {
 903    int ismhd[]={1,60,3600,86400}, i = stridx("smhd", *end);
 904
 905    if (i == -1 || *(end+1)) error_exit("Unknown suffix '%s'", end);
 906    l *= ismhd[i];
 907    fr *= ismhd[i];
 908    l += fr/mask;
 909    fr %= mask;
 910  }
 911  if (fraction) *fraction = fr;
 912
 913  return l;
 914}
 915
 916long long xparsemillitime(char *arg)
 917{
 918  long l, ll;
 919
 920  l = xparsetime(arg, 3, &ll);
 921
 922  return (l*1000LL)+ll;
 923}
 924
 925
 926
 927// Compile a regular expression into a regex_t
 928void xregcomp(regex_t *preg, char *regex, int cflags)
 929{
 930  int rc;
 931
 932  // BSD regex implementations don't support the empty regex (which isn't
 933  // allowed in the POSIX grammar), but glibc does. Fake it for BSD.
 934  if (!*regex) {
 935    regex = "()";
 936    cflags |= REG_EXTENDED;
 937  }
 938
 939  if ((rc = regcomp(preg, regex, cflags))) {
 940    regerror(rc, preg, libbuf, sizeof(libbuf));
 941    error_exit("bad regex: %s", libbuf);
 942  }
 943}
 944
 945char *xtzset(char *new)
 946{
 947  char *old = getenv("TZ");
 948
 949  if (old) old = xstrdup(old);
 950  if (new ? setenv("TZ", new, 1) : unsetenv("TZ")) perror_exit("setenv");
 951  tzset();
 952
 953  return old;
 954}
 955
 956// Set a signal handler
 957void xsignal_flags(int signal, void *handler, int flags)
 958{
 959  struct sigaction *sa = (void *)libbuf;
 960
 961  memset(sa, 0, sizeof(struct sigaction));
 962  sa->sa_handler = handler;
 963  sa->sa_flags = flags;
 964
 965  if (sigaction(signal, sa, 0)) perror_exit("xsignal %d", signal);
 966}
 967
 968void xsignal(int signal, void *handler)
 969{
 970  xsignal_flags(signal, handler, 0);
 971}
 972
 973
 974time_t xvali_date(struct tm *tm, char *str)
 975{
 976  time_t t;
 977
 978  if (tm && (unsigned)tm->tm_sec<=60 && (unsigned)tm->tm_min<=59
 979     && (unsigned)tm->tm_hour<=23 && tm->tm_mday && (unsigned)tm->tm_mday<=31
 980     && (unsigned)tm->tm_mon<=11 && (t = mktime(tm)) != -1) return t;
 981
 982  error_exit("bad date %s", str);
 983}
 984
 985// Parse date string (relative to current *t). Sets time_t and nanoseconds.
 986void xparsedate(char *str, time_t *t, unsigned *nano, int endian)
 987{
 988  struct tm tm;
 989  time_t now = *t;
 990  int len = 0, i = 0;
 991  // Formats with seconds come first. Posix can't agree on whether 12 digits
 992  // has year before (touch -t) or year after (date), so support both.
 993  char *s = str, *p, *oldtz = 0, *formats[] = {"%Y-%m-%d %T", "%Y-%m-%dT%T",
 994    "%a %b %e %H:%M:%S %Z %Y", // date(1) output format in POSIX/C locale.
 995    "%H:%M:%S", "%Y-%m-%d %H:%M", "%Y-%m-%d", "%H:%M", "%m%d%H%M",
 996    endian ? "%m%d%H%M%y" : "%y%m%d%H%M",
 997    endian ? "%m%d%H%M%C%y" : "%C%y%m%d%H%M"};
 998
 999  *nano = 0;
1000
1001  // Parse @UNIXTIME[.FRACTION]
1002  if (*str == '@') {
1003    long long ll;
1004
1005    // Collect seconds and nanoseconds.
1006    // &ll is not just t because we can't guarantee time_t is 64 bit (yet).
1007    sscanf(s, "@%lld%n", &ll, &len);
1008    if (s[len]=='.') {
1009      s += len+1;
1010      for (len = 0; len<9; len++) {
1011        *nano *= 10;
1012        if (isdigit(*s)) *nano += *s++-'0';
1013      }
1014    }
1015    *t = ll;
1016    if (!s[len]) return;
1017    xvali_date(0, str);
1018  }
1019
1020  // Try each format
1021  for (i = 0; i<ARRAY_LEN(formats); i++) {
1022    localtime_r(&now, &tm);
1023    tm.tm_hour = tm.tm_min = tm.tm_sec = 0;
1024    tm.tm_isdst = -endian;
1025
1026    if ((p = strptime(s, formats[i], &tm))) {
1027      // Handle optional fractional seconds.
1028      if (*p == '.') {
1029        p++;
1030        // If format didn't already specify seconds, grab seconds
1031        if (i>2) {
1032          len = 0;
1033          sscanf(p, "%2u%n", &tm.tm_sec, &len);
1034          p += len;
1035        }
1036        // nanoseconds
1037        for (len = 0; len<9; len++) {
1038          *nano *= 10;
1039          if (isdigit(*p)) *nano += *p++-'0';
1040        }
1041      }
1042
1043      // Handle optional Z or +HH[[:]MM] timezone
1044      if (*p && strchr("Z+-", *p)) {
1045        unsigned hh, mm = 0, len;
1046        char *tz, sign = *p++;
1047
1048        if (sign == 'Z') tz = "UTC0";
1049        else if (sscanf(p, "%2u%2u%n",  &hh, &mm, &len) == 2
1050              || sscanf(p, "%2u%n:%2u%n", &hh, &len, &mm, &len) > 0)
1051        {
1052          // flip sign because POSIX UTC offsets are backwards
1053          sprintf(tz = libbuf, "UTC%c%02d:%02d", "+-"[sign=='+'], hh, mm);
1054          p += len;
1055        } else continue;
1056
1057        if (!oldtz) {
1058          oldtz = getenv("TZ");
1059          if (oldtz) oldtz = xstrdup(oldtz);
1060        }
1061        setenv("TZ", tz, 1);
1062      }
1063
1064      if (!*p) break;
1065    }
1066  }
1067
1068  // Sanity check field ranges
1069  *t = xvali_date((i!=ARRAY_LEN(formats)) ? &tm : 0, str);
1070
1071  if (oldtz) setenv("TZ", oldtz, 1);
1072  free(oldtz);
1073}
1074
1075char *xgetline(FILE *fp, int *len)
1076{
1077  char *new = 0;
1078  size_t linelen = 0;
1079  long ll;
1080
1081  errno = 0;
1082  if (1>(ll = getline(&new, &linelen, fp))) {
1083    if (errno && errno != EINTR) perror_msg("getline");
1084    new = 0;
1085  } else if (new[ll-1] == '\n') new[--ll] = 0;
1086  if (len) *len = ll;
1087
1088  return new;
1089}
1090
1091time_t xmktime(struct tm *tm, int utc)
1092{
1093  char *old_tz = utc ? xtzset("UTC0") : 0;
1094  time_t result;
1095
1096  if ((result = mktime(tm)) < 0) error_exit("mktime");
1097  if (utc) {
1098    free(xtzset(old_tz));
1099    free(old_tz);
1100  }
1101  return result;
1102}
1103