Function timeval_to_secs() takes as the last argument the unit-scale in which
you want the fractional part returned to be in. When you call this function to
get your fractional part in centiseconds or in milliseconds, all is good. But
if you ask it to be in nanoseconds, then the number returned is just wrong.
Attached is the patch that fixes that.
Patch (apply with `patch -p0'):
Fixes a bug in timeval.c
Patch (apply with `patch -p0'):
--- lib/sh/timeval.c Thu Jun 15 16:02:53 2023
+++ ../bash-5.3-patched/lib/sh/timeval.c Mon Sep 29 01:06:02 2025
@@ -123,35 +123,33 @@
return ((t2.tv_sec == 0) ? 0 : t1.tv_sec / t2.tv_sec);
}
-/* Convert a pointer to a struct timeval to seconds and fractions of a
- second, returning the values in *SP and *SFP, respectively. The precision
- of the fractional part is determined by MAXVAL. For instance, if MAXVAL
- is 10000000, this just returns the tv_usec field. This does rounding on
- the fractional part, not just truncation to three places. */
-void
-timeval_to_secs (struct timeval *tvp, time_t *sp, long *sfp, int maxval)
-{
- int rest;
+/* Convert a pointer to a struct timeval to seconds and fractions
+ of a second, returning the values in *SP and *SFP, respectively.
+ The precision of the fractional part is determined by frac_scale.
+ Properly rounds the fractional part.
+
+ NOTE: This function was assumed to work only with microseconds, as noted in
+ execute_cmd.c. Yes, timeval values have their fractional part in
microseconds,
+ but this function returns their fractional part in whatever unit-scale is
+ requested by frac_scale -- be it centiseconds, nanoseconds, what have you.
*/
+void
+timeval_to_secs (struct timeval *tvp, time_t *sp, long *sfp, long frac_scale)
+{
+ long mul, div, base_scale = 1000000;
+ *sp = tvp->tv_sec;
+ *sfp = tvp->tv_usec;
+
+ if (frac_scale < base_scale) {
+ div = base_scale / frac_scale;
+ *sfp = (*sfp * 10 / div + 5) / 10;
+ }
+
+ if (frac_scale > base_scale) {
+ mul = frac_scale / base_scale;
+ *sfp = *sfp * mul;
+ }
+}
- *sp = tvp->tv_sec;
-
- *sfp = tvp->tv_usec % 1000000; /* pretty much a no-op */
- if (maxval < 1000000) /* don't bother otherwise */
- {
- rest = *sfp % maxval;
- *sfp = (*sfp * maxval) / 1000000;
- if (rest >= maxval/2)
- *sfp += 1;
- }
-
- /* Sanity check */
- if (*sfp >= maxval)
- {
- *sp += 1;
- *sfp -= maxval;
- }
-}
-
/* Print the contents of a struct timeval * in a standard way to stdio
stream FP. */
void