ash: add bash-compatible EPOCH variables
authorRon Yorston <rmy@pobox.com>
Mon, 15 Apr 2019 09:52:05 +0000 (10:52 +0100)
committerDenys Vlasenko <vda.linux@googlemail.com>
Tue, 16 Apr 2019 16:29:52 +0000 (18:29 +0200)
Bash 5.0 added the dynamic variable EPOCHSECONDS and EPOCHREALTIME
which return the number of seconds since the Unix Epoch as an
integer or float.  These are useful for logging or tracing.

function                                             old     new   delta
change_epoch                                           -      78     +78
.rodata                                           175167  175235     +68
varinit_data                                         264     312     +48
change_seconds                                         -      24     +24
change_realtime                                        -      24     +24
------------------------------------------------------------------------------
(add/remove: 3/0 grow/shrink: 2/0 up/down: 242/0)             Total: 242 bytes
   text    data     bss     dec     hex filename
 938508    4203    1888  944599   e69d7 busybox_old
 938702    4203    1888  944793   e6a99 busybox_unstripped

v2: Cast tv_sec and tv_usec to unsigned quantities.
    Add brackets to macros.

Signed-off-by: Ron Yorston <rmy@pobox.com>
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
shell/ash.c

index 255d57e6249c6afbb99c4a3e579e576de18f502e..b707d00d055a416d28e18abaf44306826c856734 100644 (file)
 #define    BASH_SOURCE          ENABLE_ASH_BASH_COMPAT
 #define    BASH_PIPEFAIL        ENABLE_ASH_BASH_COMPAT
 #define    BASH_HOSTNAME_VAR    ENABLE_ASH_BASH_COMPAT
+#define    BASH_EPOCH_VARS      ENABLE_ASH_BASH_COMPAT
 #define    BASH_SHLVL_VAR       ENABLE_ASH_BASH_COMPAT
 #define    BASH_XTRACEFD        ENABLE_ASH_BASH_COMPAT
 #define    BASH_READ_D          ENABLE_ASH_BASH_COMPAT
@@ -2053,6 +2054,10 @@ static void changepath(const char *) FAST_FUNC;
 #if ENABLE_ASH_RANDOM_SUPPORT
 static void change_random(const char *) FAST_FUNC;
 #endif
+#if BASH_EPOCH_VARS
+static void change_seconds(const char *) FAST_FUNC;
+static void change_realtime(const char *) FAST_FUNC;
+#endif
 
 static const struct {
        int flags;
@@ -2079,6 +2084,10 @@ static const struct {
 #if ENABLE_ASH_RANDOM_SUPPORT
        { VSTRFIXED|VTEXTFIXED|VUNSET|VDYNAMIC, "RANDOM", change_random },
 #endif
+#if BASH_EPOCH_VARS
+       { VSTRFIXED|VTEXTFIXED|VUNSET|VDYNAMIC, "EPOCHSECONDS", change_seconds },
+       { VSTRFIXED|VTEXTFIXED|VUNSET|VDYNAMIC, "EPOCHREALTIME", change_realtime },
+#endif
 #if ENABLE_LOCALE_SUPPORT
        { VSTRFIXED|VTEXTFIXED|VUNSET, "LC_ALL"    , change_lc_all   },
        { VSTRFIXED|VTEXTFIXED|VUNSET, "LC_CTYPE"  , change_lc_ctype },
@@ -2110,26 +2119,26 @@ extern struct globals_var *BB_GLOBAL_CONST ash_ptr_to_globals_var;
 #define linenovar     (G_var.linenovar    )
 #define vifs      varinit[0]
 #if ENABLE_ASH_MAIL
-# define vmail    (&vifs)[1]
-# define vmpath   (&vmail)[1]
-# define vpath    (&vmpath)[1]
-#else
-# define vpath    (&vifs)[1]
-#endif
-#define vps1      (&vpath)[1]
-#define vps2      (&vps1)[1]
-#define vps4      (&vps2)[1]
+# define vmail    varinit[1]
+# define vmpath   varinit[2]
+#endif
+#define VAR_OFFSET1 (ENABLE_ASH_MAIL*2)
+#define vpath     varinit[VAR_OFFSET1 + 1]
+#define vps1      varinit[VAR_OFFSET1 + 2]
+#define vps2      varinit[VAR_OFFSET1 + 3]
+#define vps4      varinit[VAR_OFFSET1 + 4]
 #if ENABLE_ASH_GETOPTS
-# define voptind  (&vps4)[1]
-# define vlineno  (&voptind)[1]
-# if ENABLE_ASH_RANDOM_SUPPORT
-#  define vrandom (&vlineno)[1]
-# endif
-#else
-# define vlineno  (&vps4)[1]
-# if ENABLE_ASH_RANDOM_SUPPORT
-#  define vrandom (&vlineno)[1]
-# endif
+# define voptind  varinit[VAR_OFFSET1 + 5]
+#endif
+#define VAR_OFFSET2 (VAR_OFFSET1 + ENABLE_ASH_GETOPTS)
+#define vlineno   varinit[VAR_OFFSET2 + 5]
+#if ENABLE_ASH_RANDOM_SUPPORT
+# define vrandom  varinit[VAR_OFFSET2 + 6]
+#endif
+#define VAR_OFFSET3 (VAR_OFFSET2 + ENABLE_ASH_RANDOM_SUPPORT)
+#if BASH_EPOCH_VARS
+# define vepochs  varinit[VAR_OFFSET3 + 6]
+# define vepochr  varinit[VAR_OFFSET3 + 7]
 #endif
 #define INIT_G_var() do { \
        unsigned i; \
@@ -2268,7 +2277,7 @@ lookupvar(const char *name)
 
        v = *findvar(hashvar(name), name);
        if (v) {
-#if ENABLE_ASH_RANDOM_SUPPORT
+#if ENABLE_ASH_RANDOM_SUPPORT || BASH_EPOCH_VARS
        /*
         * Dynamic variables are implemented roughly the same way they are
         * in bash. Namely, they're "special" so long as they aren't unset.
@@ -2364,7 +2373,7 @@ setvareq(char *s, int flags)
                }
 
                flags |= vp->flags & ~(VTEXTFIXED|VSTACK|VNOSAVE|VUNSET);
-#if ENABLE_ASH_RANDOM_SUPPORT
+#if ENABLE_ASH_RANDOM_SUPPORT || BASH_EPOCH_VARS
                if (flags & VUNSET)
                        flags &= ~VDYNAMIC;
 #endif
@@ -11249,6 +11258,32 @@ change_random(const char *value)
 }
 #endif
 
+#if BASH_EPOCH_VARS
+static void FAST_FUNC
+change_epoch(struct var *vepoch, const char *fmt)
+{
+       struct timeval tv;
+       char buffer[sizeof("%lu.nnnnnn") + sizeof(long)*3];
+
+       gettimeofday(&tv, NULL);
+       sprintf(buffer, fmt, (unsigned long)tv.tv_sec, (unsigned)tv.tv_usec);
+       setvar(vepoch->var_text, buffer, VNOFUNC);
+       vepoch->flags &= ~VNOFUNC;
+}
+
+static void FAST_FUNC
+change_seconds(const char *value UNUSED_PARAM)
+{
+       change_epoch(&vepochs, "%lu");
+}
+
+static void FAST_FUNC
+change_realtime(const char *value UNUSED_PARAM)
+{
+       change_epoch(&vepochr, "%lu.%06u");
+}
+#endif
+
 #if ENABLE_ASH_GETOPTS
 static int
 getopts(char *optstr, char *optvar, char **optfirst)