busybox/coreutils/sleep.c
<<
>>
Prefs
   1/* vi: set sw=4 ts=4: */
   2/*
   3 * sleep implementation for busybox
   4 *
   5 * Copyright (C) 2003  Manuel Novoa III  <mjn3@codepoet.org>
   6 *
   7 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
   8 */
   9/* Mar 16, 2003      Manuel Novoa III   (mjn3@codepoet.org)
  10 *
  11 * Rewritten to do proper arg and error checking.
  12 * Also, added a 'fancy' configuration to accept multiple args with
  13 * time suffixes for seconds, minutes, hours, and days.
  14 */
  15//config:config SLEEP
  16//config:       bool "sleep (1.7 kb)"
  17//config:       default y
  18//config:       help
  19//config:       sleep is used to pause for a specified number of seconds.
  20//config:       It comes in 3 versions:
  21//config:       - small: takes one integer parameter
  22//config:       - fancy: takes multiple integer arguments with suffixes:
  23//config:               sleep 1d 2h 3m 15s
  24//config:       - fancy with fractional numbers:
  25//config:               sleep 2.3s 4.5h sleeps for 16202.3 seconds
  26//config:       Last one is "the most compatible" with coreutils sleep,
  27//config:       but it adds around 1k of code.
  28//config:
  29//config:config FEATURE_FANCY_SLEEP
  30//config:       bool "Enable multiple arguments and s/m/h/d suffixes"
  31//config:       default y
  32//config:       depends on SLEEP
  33//config:       help
  34//config:       Allow sleep to pause for specified minutes, hours, and days.
  35//config:
  36//config:config FEATURE_FLOAT_SLEEP
  37//config:       bool "Enable fractional arguments"
  38//config:       default y
  39//config:       depends on FEATURE_FANCY_SLEEP
  40//config:       help
  41//config:       Allow for fractional numeric parameters.
  42
  43/* Do not make this applet NOFORK. It breaks ^C-ing of pauses in shells */
  44//applet:IF_SLEEP(APPLET(sleep, BB_DIR_BIN, BB_SUID_DROP))
  45
  46//kbuild:lib-$(CONFIG_SLEEP) += sleep.o
  47
  48/* BB_AUDIT SUSv3 compliant */
  49/* BB_AUDIT GNU issues -- fancy version matches except args must be ints. */
  50/* http://www.opengroup.org/onlinepubs/007904975/utilities/sleep.html */
  51
  52//usage:#define sleep_trivial_usage
  53//usage:        IF_FEATURE_FANCY_SLEEP("[") "N" IF_FEATURE_FANCY_SLEEP("]...")
  54//usage:#define sleep_full_usage "\n\n"
  55//usage:        IF_NOT_FEATURE_FANCY_SLEEP("Pause for N seconds")
  56//usage:        IF_FEATURE_FANCY_SLEEP(
  57//usage:       "Pause for a time equal to the total of the args given, where each arg can\n"
  58//usage:       "have an optional suffix of (s)econds, (m)inutes, (h)ours, or (d)ays")
  59//usage:
  60//usage:#define sleep_example_usage
  61//usage:       "$ sleep 2\n"
  62//usage:       "[2 second delay results]\n"
  63//usage:        IF_FEATURE_FANCY_SLEEP(
  64//usage:       "$ sleep 1d 3h 22m 8s\n"
  65//usage:       "[98528 second delay results]\n")
  66
  67#include "libbb.h"
  68
  69#if ENABLE_FEATURE_FANCY_SLEEP || ENABLE_FEATURE_FLOAT_SLEEP
  70static const struct suffix_mult sfx[] = {
  71        { "s", 1 },
  72        { "m", 60 },
  73        { "h", 60*60 },
  74        { "d", 24*60*60 },
  75        { "", 0 }
  76};
  77#endif
  78
  79int sleep_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
  80int sleep_main(int argc UNUSED_PARAM, char **argv)
  81{
  82#if ENABLE_FEATURE_FLOAT_SLEEP
  83        double duration;
  84        struct timespec ts;
  85#else
  86        unsigned duration;
  87#endif
  88
  89        ++argv;
  90        if (!*argv)
  91                bb_show_usage();
  92
  93#if ENABLE_FEATURE_FLOAT_SLEEP
  94
  95# if ENABLE_LOCALE_SUPPORT
  96        /* undo busybox.c setlocale */
  97        setlocale(LC_NUMERIC, "C");
  98# endif
  99        duration = 0;
 100        do {
 101                char *arg = *argv;
 102                if (strchr(arg, '.')) {
 103                        double d;
 104                        char *pp;
 105                        int len = strspn(arg, "0123456789.");
 106                        char sv = arg[len];
 107                        arg[len] = '\0';
 108                        errno = 0;
 109                        d = strtod(arg, &pp);
 110                        if (errno || *pp)
 111                                bb_show_usage();
 112                        arg += len;
 113                        *arg-- = sv;
 114                        sv = *arg;
 115                        *arg = '1';
 116                        duration += d * xatoul_sfx(arg, sfx);
 117                        *arg = sv;
 118                } else {
 119                        duration += xatoul_sfx(arg, sfx);
 120                }
 121        } while (*++argv);
 122
 123        ts.tv_sec = MAXINT(typeof(ts.tv_sec));
 124        ts.tv_nsec = 0;
 125        if (duration >= 0 && duration < ts.tv_sec) {
 126                ts.tv_sec = duration;
 127                ts.tv_nsec = (duration - ts.tv_sec) * 1000000000;
 128        }
 129        do {
 130                errno = 0;
 131                nanosleep(&ts, &ts);
 132        } while (errno == EINTR);
 133
 134#elif ENABLE_FEATURE_FANCY_SLEEP
 135
 136        duration = 0;
 137        do {
 138                duration += xatou_range_sfx(*argv, 0, UINT_MAX - duration, sfx);
 139        } while (*++argv);
 140        sleep(duration);
 141
 142#else /* simple */
 143
 144        duration = xatou(*argv);
 145        sleep(duration);
 146        // Off. If it's really needed, provide example why
 147        //if (sleep(duration)) {
 148        //      bb_perror_nomsg_and_die();
 149        //}
 150
 151#endif
 152
 153        return EXIT_SUCCESS;
 154}
 155