busybox/libbb/xfuncs_printf.c
<<
>>
Prefs
   1/* vi: set sw=4 ts=4: */
   2/*
   3 * Utility routines.
   4 *
   5 * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
   6 * Copyright (C) 2006 Rob Landley
   7 * Copyright (C) 2006 Denys Vlasenko
   8 *
   9 * Licensed under GPLv2, see file LICENSE in this source tree.
  10 */
  11/* We need to have separate xfuncs.c and xfuncs_printf.c because
  12 * with current linkers, even with section garbage collection,
  13 * if *.o module references any of XXXprintf functions, you pull in
  14 * entire printf machinery. Even if you do not use the function
  15 * which uses XXXprintf.
  16 *
  17 * xfuncs.c contains functions (not necessarily xfuncs)
  18 * which do not pull in printf, directly or indirectly.
  19 * xfunc_printf.c contains those which do.
  20 */
  21#include "libbb.h"
  22
  23
  24/* All the functions starting with "x" call bb_error_msg_and_die() if they
  25 * fail, so callers never need to check for errors.  If it returned, it
  26 * succeeded. */
  27
  28void FAST_FUNC bb_die_memory_exhausted(void)
  29{
  30        bb_simple_error_msg_and_die(bb_msg_memory_exhausted);
  31}
  32
  33#ifndef DMALLOC
  34/* dmalloc provides variants of these that do abort() on failure.
  35 * Since dmalloc's prototypes overwrite the impls here as they are
  36 * included after these prototypes in libbb.h, all is well.
  37 */
  38// Warn if we can't allocate size bytes of memory.
  39void* FAST_FUNC malloc_or_warn(size_t size)
  40{
  41        void *ptr = malloc(size);
  42        if (ptr == NULL && size != 0)
  43                bb_simple_error_msg(bb_msg_memory_exhausted);
  44        return ptr;
  45}
  46
  47// Die if we can't allocate size bytes of memory.
  48void* FAST_FUNC xmalloc(size_t size)
  49{
  50        void *ptr = malloc(size);
  51        if (ptr == NULL && size != 0)
  52                bb_die_memory_exhausted();
  53        return ptr;
  54}
  55
  56// Die if we can't resize previously allocated memory.  (This returns a pointer
  57// to the new memory, which may or may not be the same as the old memory.
  58// It'll copy the contents to a new chunk and free the old one if necessary.)
  59void* FAST_FUNC xrealloc(void *ptr, size_t size)
  60{
  61        ptr = realloc(ptr, size);
  62        if (ptr == NULL && size != 0)
  63                bb_die_memory_exhausted();
  64        return ptr;
  65}
  66#endif /* DMALLOC */
  67
  68// Die if we can't allocate and zero size bytes of memory.
  69void* FAST_FUNC xzalloc(size_t size)
  70{
  71        void *ptr = xmalloc(size);
  72        memset(ptr, 0, size);
  73        return ptr;
  74}
  75
  76// Die if we can't copy a string to freshly allocated memory.
  77char* FAST_FUNC xstrdup(const char *s)
  78{
  79        char *t;
  80
  81        if (s == NULL)
  82                return NULL;
  83
  84        t = strdup(s);
  85
  86        if (t == NULL)
  87                bb_die_memory_exhausted();
  88
  89        return t;
  90}
  91
  92// Die if we can't allocate n+1 bytes (space for the null terminator) and copy
  93// the (possibly truncated to length n) string into it.
  94char* FAST_FUNC xstrndup(const char *s, int n)
  95{
  96        char *t;
  97
  98        if (ENABLE_DEBUG && s == NULL)
  99                bb_simple_error_msg_and_die("xstrndup bug");
 100
 101        t = strndup(s, n);
 102
 103        if (t == NULL)
 104                bb_die_memory_exhausted();
 105
 106        return t;
 107}
 108
 109void* FAST_FUNC xmemdup(const void *s, int n)
 110{
 111        return memcpy(xmalloc(n), s, n);
 112}
 113
 114void* FAST_FUNC mmap_read(int fd, size_t size)
 115{
 116        return mmap(NULL, size, PROT_READ, MAP_PRIVATE, fd, 0);
 117}
 118
 119void* FAST_FUNC mmap_anon(size_t size)
 120{
 121        return mmap(NULL, size,
 122                        PROT_READ | PROT_WRITE,
 123                        MAP_PRIVATE | MAP_ANONYMOUS,
 124                        /* ignored: */ -1, 0);
 125}
 126
 127void* FAST_FUNC xmmap_anon(size_t size)
 128{
 129        void *p = mmap_anon(size);
 130        if (p == MAP_FAILED)
 131                bb_die_memory_exhausted();
 132        return p;
 133}
 134
 135// Die if we can't open a file and return a FILE* to it.
 136// Notice we haven't got xfread(), This is for use with fscanf() and friends.
 137FILE* FAST_FUNC xfopen(const char *path, const char *mode)
 138{
 139        FILE *fp = fopen(path, mode);
 140        if (fp == NULL)
 141                bb_perror_msg_and_die("can't open '%s'", path);
 142        return fp;
 143}
 144
 145// Die if we can't open a file and return a fd.
 146int FAST_FUNC xopen3(const char *pathname, int flags, int mode)
 147{
 148        int ret;
 149
 150        ret = open(pathname, flags, mode);
 151        if (ret < 0) {
 152                bb_perror_msg_and_die("can't open '%s'", pathname);
 153        }
 154        return ret;
 155}
 156
 157// Die if we can't open a file and return a fd.
 158int FAST_FUNC xopen(const char *pathname, int flags)
 159{
 160        return xopen3(pathname, flags, 0666);
 161}
 162
 163// Warn if we can't open a file and return a fd.
 164int FAST_FUNC open3_or_warn(const char *pathname, int flags, int mode)
 165{
 166        int ret;
 167
 168        ret = open(pathname, flags, mode);
 169        if (ret < 0) {
 170                bb_perror_msg("can't open '%s'", pathname);
 171        }
 172        return ret;
 173}
 174
 175// Warn if we can't open a file and return a fd.
 176int FAST_FUNC open_or_warn(const char *pathname, int flags)
 177{
 178        return open3_or_warn(pathname, flags, 0666);
 179}
 180
 181/* Die if we can't open an existing file readonly with O_NONBLOCK
 182 * and return the fd.
 183 * Note that for ioctl O_RDONLY is sufficient.
 184 */
 185int FAST_FUNC xopen_nonblocking(const char *pathname)
 186{
 187        return xopen(pathname, O_RDONLY | O_NONBLOCK);
 188}
 189
 190int FAST_FUNC xopen_as_uid_gid(const char *pathname, int flags, uid_t u, gid_t g)
 191{
 192        int fd;
 193        uid_t old_euid = geteuid();
 194        gid_t old_egid = getegid();
 195
 196        xsetegid(g);
 197        xseteuid(u);
 198
 199        fd = xopen(pathname, flags);
 200
 201        xseteuid(old_euid);
 202        xsetegid(old_egid);
 203
 204        return fd;
 205}
 206
 207void FAST_FUNC xunlink(const char *pathname)
 208{
 209        if (unlink(pathname))
 210                bb_perror_msg_and_die("can't remove file '%s'", pathname);
 211}
 212
 213void FAST_FUNC xrename(const char *oldpath, const char *newpath)
 214{
 215        if (rename(oldpath, newpath))
 216                bb_perror_msg_and_die("can't move '%s' to '%s'", oldpath, newpath);
 217}
 218
 219int FAST_FUNC rename_or_warn(const char *oldpath, const char *newpath)
 220{
 221        int n = rename(oldpath, newpath);
 222        if (n)
 223                bb_perror_msg("can't move '%s' to '%s'", oldpath, newpath);
 224        return n;
 225}
 226
 227void FAST_FUNC xpipe(int *filedes)
 228{
 229        if (pipe(filedes))
 230                bb_simple_perror_msg_and_die("can't create pipe");
 231}
 232
 233void FAST_FUNC xdup2(int from, int to)
 234{
 235        if (dup2(from, to) != to)
 236                bb_simple_perror_msg_and_die("can't duplicate file descriptor");
 237                //              " %d to %d", from, to);
 238}
 239
 240// "Renumber" opened fd
 241void FAST_FUNC xmove_fd(int from, int to)
 242{
 243        if (from == to)
 244                return;
 245        xdup2(from, to);
 246        close(from);
 247}
 248
 249// Die with an error message if we can't write the entire buffer.
 250void FAST_FUNC xwrite(int fd, const void *buf, size_t count)
 251{
 252        if (count) {
 253                ssize_t size = full_write(fd, buf, count);
 254                if ((size_t)size != count) {
 255                        /*
 256                         * Two cases: write error immediately;
 257                         * or some writes succeeded, then we hit an error.
 258                         * In either case, errno is set.
 259                         */
 260                        bb_simple_perror_msg_and_die(
 261                                size >= 0 ? "short write" : "write error"
 262                        );
 263                }
 264        }
 265}
 266void FAST_FUNC xwrite_str(int fd, const char *str)
 267{
 268        xwrite(fd, str, strlen(str));
 269}
 270
 271void FAST_FUNC xclose(int fd)
 272{
 273        if (close(fd))
 274                bb_simple_perror_msg_and_die("close failed");
 275}
 276
 277// Die with an error message if we can't lseek to the right spot.
 278off_t FAST_FUNC xlseek(int fd, off_t offset, int whence)
 279{
 280        off_t off = lseek(fd, offset, whence);
 281        if (off == (off_t)-1) {
 282                bb_perror_msg_and_die("lseek(%"OFF_FMT"u, %d)", offset, whence);
 283        }
 284        return off;
 285}
 286
 287int FAST_FUNC xmkstemp(char *template)
 288{
 289        int fd = mkstemp(template);
 290        if (fd < 0)
 291                bb_perror_msg_and_die("can't create temp file '%s'", template);
 292        return fd;
 293}
 294
 295// Die with supplied filename if this FILE* has ferror set.
 296void FAST_FUNC die_if_ferror(FILE *fp, const char *fn)
 297{
 298        if (ferror(fp)) {
 299                /* ferror doesn't set useful errno */
 300                bb_error_msg_and_die("%s: I/O error", fn);
 301        }
 302}
 303
 304// Die with an error message if stdout has ferror set.
 305void FAST_FUNC die_if_ferror_stdout(void)
 306{
 307        die_if_ferror(stdout, bb_msg_standard_output);
 308}
 309
 310int FAST_FUNC fflush_all(void)
 311{
 312        return fflush(NULL);
 313}
 314
 315
 316int FAST_FUNC bb_putchar(int ch)
 317{
 318        return putchar(ch);
 319}
 320
 321int FAST_FUNC fputs_stdout(const char *s)
 322{
 323        return fputs(s, stdout);
 324}
 325
 326/* Die with an error message if we can't copy an entire FILE* to stdout,
 327 * then close that file. */
 328void FAST_FUNC xprint_and_close_file(FILE *file)
 329{
 330        fflush_all();
 331        // copyfd outputs error messages for us.
 332        if (bb_copyfd_eof(fileno(file), STDOUT_FILENO) == -1)
 333                xfunc_die();
 334
 335        fclose(file);
 336}
 337
 338// Die with an error message if we can't malloc() enough space and do an
 339// sprintf() into that space.
 340char* FAST_FUNC xasprintf(const char *format, ...)
 341{
 342        va_list p;
 343        int r;
 344        char *string_ptr;
 345
 346        va_start(p, format);
 347        r = vasprintf(&string_ptr, format, p);
 348        va_end(p);
 349
 350        if (r < 0)
 351                bb_die_memory_exhausted();
 352        return string_ptr;
 353}
 354
 355void FAST_FUNC xsetenv(const char *key, const char *value)
 356{
 357        if (setenv(key, value, 1))
 358                bb_die_memory_exhausted();
 359}
 360
 361/* Handles "VAR=VAL" strings, even those which are part of environ
 362 * _right now_
 363 */
 364void FAST_FUNC bb_unsetenv(const char *var)
 365{
 366        char onstack[128 - 16]; /* smaller stack setup code on x86 */
 367        char *tp;
 368
 369        tp = strchr(var, '=');
 370        if (tp) {
 371                /* In case var was putenv'ed, we can't replace '='
 372                 * with NUL and unsetenv(var) - it won't work,
 373                 * env is modified by the replacement, unsetenv
 374                 * sees "VAR" instead of "VAR=VAL" and does not remove it!
 375                 * Horror :(
 376                 */
 377                unsigned sz = tp - var;
 378                if (sz < sizeof(onstack)) {
 379                        ((char*)mempcpy(onstack, var, sz))[0] = '\0';
 380                        tp = NULL;
 381                        var = onstack;
 382                } else {
 383                        /* unlikely: very long var name */
 384                        var = tp = xstrndup(var, sz);
 385                }
 386        }
 387        unsetenv(var);
 388        free(tp);
 389}
 390
 391void FAST_FUNC bb_unsetenv_and_free(char *var)
 392{
 393        bb_unsetenv(var);
 394        free(var);
 395}
 396
 397// Die with an error message if we can't set gid.  (Because resource limits may
 398// limit this user to a given number of processes, and if that fills up the
 399// setgid() will fail and we'll _still_be_root_, which is bad.)
 400void FAST_FUNC xsetgid(gid_t gid)
 401{
 402        if (setgid(gid)) bb_simple_perror_msg_and_die("setgid");
 403}
 404
 405// Die with an error message if we can't set uid.  (See xsetgid() for why.)
 406void FAST_FUNC xsetuid(uid_t uid)
 407{
 408        if (setuid(uid)) bb_simple_perror_msg_and_die("setuid");
 409}
 410
 411void FAST_FUNC xsetegid(gid_t egid)
 412{
 413        if (setegid(egid)) bb_simple_perror_msg_and_die("setegid");
 414}
 415
 416void FAST_FUNC xseteuid(uid_t euid)
 417{
 418        if (seteuid(euid)) bb_simple_perror_msg_and_die("seteuid");
 419}
 420
 421// Die if we can't chdir to a new path.
 422void FAST_FUNC xchdir(const char *path)
 423{
 424        if (chdir(path))
 425                bb_perror_msg_and_die("can't change directory to '%s'", path);
 426}
 427
 428void FAST_FUNC xfchdir(int fd)
 429{
 430        if (fchdir(fd))
 431                bb_simple_perror_msg_and_die("fchdir");
 432}
 433
 434void FAST_FUNC xchroot(const char *path)
 435{
 436        if (chroot(path))
 437                bb_perror_msg_and_die("can't change root directory to '%s'", path);
 438        xchdir("/");
 439}
 440
 441// Print a warning message if opendir() fails, but don't die.
 442DIR* FAST_FUNC warn_opendir(const char *path)
 443{
 444        DIR *dp;
 445
 446        dp = opendir(path);
 447        if (!dp)
 448                bb_perror_msg("can't open '%s'", path);
 449        return dp;
 450}
 451
 452// Die with an error message if opendir() fails.
 453DIR* FAST_FUNC xopendir(const char *path)
 454{
 455        DIR *dp;
 456
 457        dp = opendir(path);
 458        if (!dp)
 459                bb_perror_msg_and_die("can't open '%s'", path);
 460        return dp;
 461}
 462
 463// Die with an error message if we can't open a new socket.
 464int FAST_FUNC xsocket(int domain, int type, int protocol)
 465{
 466        int r = socket(domain, type, protocol);
 467
 468        if (r < 0) {
 469                /* Hijack vaguely related config option */
 470#if ENABLE_VERBOSE_RESOLUTION_ERRORS
 471                const char *s = "INET";
 472# ifdef AF_PACKET
 473                if (domain == AF_PACKET) s = "PACKET";
 474# endif
 475# ifdef AF_NETLINK
 476                if (domain == AF_NETLINK) s = "NETLINK";
 477# endif
 478IF_FEATURE_IPV6(if (domain == AF_INET6) s = "INET6";)
 479                bb_perror_msg_and_die("socket(AF_%s,%d,%d)", s, type, protocol);
 480#else
 481                bb_simple_perror_msg_and_die("socket");
 482#endif
 483        }
 484
 485        return r;
 486}
 487
 488// Die with an error message if we can't bind a socket to an address.
 489void FAST_FUNC xbind(int sockfd, struct sockaddr *my_addr, socklen_t addrlen)
 490{
 491        if (bind(sockfd, my_addr, addrlen)) bb_simple_perror_msg_and_die("bind");
 492}
 493
 494// Die with an error message if we can't listen for connections on a socket.
 495void FAST_FUNC xlisten(int s, int backlog)
 496{
 497        if (listen(s, backlog)) bb_simple_perror_msg_and_die("listen");
 498}
 499
 500/* Die with an error message if sendto failed.
 501 * Return bytes sent otherwise  */
 502ssize_t FAST_FUNC xsendto(int s, const void *buf, size_t len, const struct sockaddr *to,
 503                                socklen_t tolen)
 504{
 505        ssize_t ret = sendto(s, buf, len, 0, to, tolen);
 506        if (ret < 0) {
 507                if (ENABLE_FEATURE_CLEAN_UP)
 508                        close(s);
 509                bb_simple_perror_msg_and_die("sendto");
 510        }
 511        return ret;
 512}
 513
 514// xstat() - a stat() which dies on failure with meaningful error message
 515void FAST_FUNC xstat(const char *name, struct stat *stat_buf)
 516{
 517        if (stat(name, stat_buf))
 518                bb_perror_msg_and_die("can't stat '%s'", name);
 519}
 520
 521void FAST_FUNC xfstat(int fd, struct stat *stat_buf, const char *errmsg)
 522{
 523        /* errmsg is usually a file name, but not always:
 524         * xfstat may be called in a spot where file name is no longer
 525         * available, and caller may give e.g. "can't stat input file" string.
 526         */
 527        if (fstat(fd, stat_buf))
 528                bb_simple_perror_msg_and_die(errmsg);
 529}
 530
 531#if ENABLE_SELINUX
 532// selinux_or_die() - die if SELinux is disabled.
 533void FAST_FUNC selinux_or_die(void)
 534{
 535        int rc = is_selinux_enabled();
 536        if (rc == 0) {
 537                bb_simple_error_msg_and_die("SELinux is disabled");
 538        } else if (rc < 0) {
 539                bb_simple_error_msg_and_die("is_selinux_enabled() failed");
 540        }
 541}
 542#else
 543/* not defined, other code must have no calls to it */
 544#endif
 545
 546int FAST_FUNC ioctl_or_perror_and_die(int fd, unsigned request, void *argp, const char *fmt,...)
 547{
 548        int ret;
 549        va_list p;
 550
 551        ret = ioctl(fd, request, argp);
 552        if (ret < 0) {
 553                va_start(p, fmt);
 554                bb_verror_msg(fmt, p, strerror(errno));
 555                /* xfunc_die can actually longjmp, so be nice */
 556                va_end(p);
 557                xfunc_die();
 558        }
 559        return ret;
 560}
 561
 562int FAST_FUNC ioctl_or_perror(int fd, unsigned request, void *argp, const char *fmt,...)
 563{
 564        va_list p;
 565        int ret = ioctl(fd, request, argp);
 566
 567        if (ret < 0) {
 568                va_start(p, fmt);
 569                bb_verror_msg(fmt, p, strerror(errno));
 570                va_end(p);
 571        }
 572        return ret;
 573}
 574
 575#if ENABLE_IOCTL_HEX2STR_ERROR
 576int FAST_FUNC bb_ioctl_or_warn(int fd, unsigned request, void *argp, const char *ioctl_name)
 577{
 578        int ret;
 579
 580        ret = ioctl(fd, request, argp);
 581        if (ret < 0)
 582                bb_simple_perror_msg(ioctl_name);
 583        return ret;
 584}
 585int FAST_FUNC bb_xioctl(int fd, unsigned request, void *argp, const char *ioctl_name)
 586{
 587        int ret;
 588
 589        ret = ioctl(fd, request, argp);
 590        if (ret < 0)
 591                bb_simple_perror_msg_and_die(ioctl_name);
 592        return ret;
 593}
 594#else
 595int FAST_FUNC bb_ioctl_or_warn(int fd, unsigned request, void *argp)
 596{
 597        int ret;
 598
 599        ret = ioctl(fd, request, argp);
 600        if (ret < 0)
 601                bb_perror_msg("ioctl %#x failed", request);
 602        return ret;
 603}
 604int FAST_FUNC bb_xioctl(int fd, unsigned request, void *argp)
 605{
 606        int ret;
 607
 608        ret = ioctl(fd, request, argp);
 609        if (ret < 0)
 610                bb_perror_msg_and_die("ioctl %#x failed", request);
 611        return ret;
 612}
 613#endif
 614
 615char* FAST_FUNC xmalloc_ttyname(int fd)
 616{
 617        char buf[128];
 618        int r = ttyname_r(fd, buf, sizeof(buf) - 1);
 619        if (r)
 620                return NULL;
 621        return xstrdup(buf);
 622}
 623
 624void FAST_FUNC generate_uuid(uint8_t *buf)
 625{
 626        /* http://www.ietf.org/rfc/rfc4122.txt
 627         *  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
 628         * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 629         * |                          time_low                             |
 630         * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 631         * |       time_mid                |         time_hi_and_version   |
 632         * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 633         * |clk_seq_and_variant            |         node (0-1)            |
 634         * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 635         * |                         node (2-5)                            |
 636         * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 637         * IOW, uuid has this layout:
 638         * uint32_t time_low (big endian)
 639         * uint16_t time_mid (big endian)
 640         * uint16_t time_hi_and_version (big endian)
 641         *  version is a 4-bit field:
 642         *   1 Time-based
 643         *   2 DCE Security, with embedded POSIX UIDs
 644         *   3 Name-based (MD5)
 645         *   4 Randomly generated
 646         *   5 Name-based (SHA-1)
 647         * uint16_t clk_seq_and_variant (big endian)
 648         *  variant is a 3-bit field:
 649         *   0xx Reserved, NCS backward compatibility
 650         *   10x The variant specified in rfc4122
 651         *   110 Reserved, Microsoft backward compatibility
 652         *   111 Reserved for future definition
 653         * uint8_t node[6]
 654         *
 655         * For version 4, these bits are set/cleared:
 656         * time_hi_and_version & 0x0fff | 0x4000
 657         * clk_seq_and_variant & 0x3fff | 0x8000
 658         */
 659        pid_t pid;
 660        int i;
 661
 662        open_read_close("/dev/urandom", buf, 16);
 663        /* Paranoia. /dev/urandom may be missing.
 664         * rand() is guaranteed to generate at least [0, 2^15) range,
 665         * but lowest bits in some libc are not so "random".
 666         */
 667        srand(monotonic_us()); /* pulls in printf */
 668        pid = getpid();
 669        while (1) {
 670                for (i = 0; i < 16; i++)
 671                        buf[i] ^= rand() >> 5;
 672                if (pid == 0)
 673                        break;
 674                srand(pid);
 675                pid = 0;
 676        }
 677
 678        /* version = 4 */
 679        buf[4 + 2    ] = (buf[4 + 2    ] & 0x0f) | 0x40;
 680        /* variant = 10x */
 681        buf[4 + 2 + 2] = (buf[4 + 2 + 2] & 0x3f) | 0x80;
 682}
 683
 684#if BB_MMU
 685pid_t FAST_FUNC xfork(void)
 686{
 687        pid_t pid;
 688        pid = fork();
 689        if (pid < 0) /* wtf? */
 690                bb_simple_perror_msg_and_die("vfork"+1);
 691        return pid;
 692}
 693#endif
 694
 695void FAST_FUNC xvfork_parent_waits_and_exits(void)
 696{
 697        pid_t pid;
 698
 699        fflush_all();
 700        pid = xvfork();
 701        if (pid > 0) {
 702                /* Parent */
 703                int exit_status = wait_for_exitstatus(pid);
 704                if (WIFSIGNALED(exit_status))
 705                        kill_myself_with_sig(WTERMSIG(exit_status));
 706                _exit(WEXITSTATUS(exit_status));
 707        }
 708        /* Child continues */
 709}
 710
 711// Useful when we do know that pid is valid, and we just want to wait
 712// for it to exit. Not existing pid is fatal. waitpid() status is not returned.
 713int FAST_FUNC wait_for_exitstatus(pid_t pid)
 714{
 715        int exit_status, n;
 716
 717        n = safe_waitpid(pid, &exit_status, 0);
 718        if (n < 0)
 719                bb_simple_perror_msg_and_die("waitpid");
 720        return exit_status;
 721}
 722
 723void FAST_FUNC xsettimeofday(const struct timeval *tv)
 724{
 725        if (settimeofday(tv, NULL))
 726                bb_simple_perror_msg_and_die("settimeofday");
 727}
 728
 729void FAST_FUNC xgettimeofday(struct timeval *tv)
 730{
 731#if 0
 732        if (gettimeofday(tv, NULL))
 733                bb_simple_perror_msg_and_die("gettimeofday");
 734#else
 735        /* Never fails on Linux */
 736        gettimeofday(tv, NULL);
 737#endif
 738}
 739