[openssh-commits] [openssh] 01/03: upstream: Add convtime_double() that converts a string interval,
git+noreply at mindrot.org
git+noreply at mindrot.org
Fri Dec 5 19:19:48 AEDT 2025
This is an automated email from the git hooks/post-receive script.
djm pushed a commit to branch master
in repository openssh.
commit f45cd249e45a15c84bf1316ac719039d04a74e84
Author: djm at openbsd.org <djm at openbsd.org>
AuthorDate: Fri Dec 5 07:43:12 2025 +0000
upstream: Add convtime_double() that converts a string interval,
such as "3w2d4h5m10.5s", into a floating point number of seconds.
Reimplement the existing convtime() function using convtime_double()
(it just drops the fractional seconds)
lots of feedback deraadt@ / dtucker@; ok deraadt@
OpenBSD-Commit-ID: 053cdd0c72325a20efc6613caa847473fb89e36f
---
misc.c | 130 +++++++++++++++++++++++++++++++++++++----------------------------
misc.h | 4 +-
2 files changed, 78 insertions(+), 56 deletions(-)
diff --git a/misc.c b/misc.c
index 15d7fc4df..aff5b3fc3 100644
--- a/misc.c
+++ b/misc.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: misc.c,v 1.209 2025/11/06 01:31:11 djm Exp $ */
+/* $OpenBSD: misc.c,v 1.210 2025/12/05 07:43:12 djm Exp $ */
/*
* Copyright (c) 2000 Markus Friedl. All rights reserved.
* Copyright (c) 2005-2020 Damien Miller. All rights reserved.
@@ -622,25 +622,22 @@ a2tun(const char *s, int *remote)
return (tun);
}
-#define SECONDS 1
+#define SECONDS 1.0
#define MINUTES (SECONDS * 60)
#define HOURS (MINUTES * 60)
#define DAYS (HOURS * 24)
#define WEEKS (DAYS * 7)
-static char *
-scandigits(char *s)
-{
- while (isdigit((unsigned char)*s))
- s++;
- return s;
-}
-
/*
- * Convert a time string into seconds; format is
- * a sequence of:
+ * Convert an interval/duration time string into seconds, which may include
+ * fractional seconds.
+ *
+ * The format is a sequence of:
* time[qualifier]
*
+ * This supports fractional values for the seconds value only. All other
+ * values must be integers.
+ *
* Valid time qualifiers are:
* <none> seconds
* s|S seconds
@@ -650,44 +647,46 @@ scandigits(char *s)
* w|W weeks
*
* Examples:
- * 90m 90 minutes
- * 1h30m 90 minutes
- * 2d 2 days
- * 1w 1 week
+ * 90m 90 minutes
+ * 1h30m 90 minutes
+ * 1.5s 1.5 seconds
+ * 2d 2 days
+ * 1w 1 week
*
- * Return -1 if time string is invalid.
+ * Returns <0.0 if the time string is invalid.
*/
-int
-convtime(const char *s)
+double
+convtime_double(const char *s)
{
- int secs, total = 0, multiplier;
- char *p, *os, *np, c = 0;
- const char *errstr;
+ double val, total_sec = 0.0, multiplier;
+ const char *p, *start_p;
+ char *endp;
+ int seen_seconds = 0;
if (s == NULL || *s == '\0')
- return -1;
- p = os = strdup(s); /* deal with const */
- if (os == NULL)
- return -1;
+ return -1.0;
- while (*p) {
- np = scandigits(p);
- if (np) {
- c = *np;
- *np = '\0';
- }
- secs = (int)strtonum(p, 0, INT_MAX, &errstr);
- if (errstr)
- goto fail;
- *np = c;
+ for (p = s; *p != '\0';) {
+ if (!isdigit((unsigned char)*p) && *p != '.')
+ return -1.0;
- multiplier = 1;
- switch (c) {
+ errno = 0;
+ if ((val = strtod(p, &endp)) < 0 || errno != 0 || p == endp)
+ return -1.0;
+ /* Allow only decimal forms */
+ if (p + strspn(p, "0123456789.") != endp)
+ return -1.0;
+ start_p = p;
+ p = endp;
+
+ switch (*p) {
case '\0':
- np--; /* back up */
- break;
+ /* FALLTHROUGH */
case 's':
case 'S':
+ if (seen_seconds++)
+ return -1.0;
+ multiplier = SECONDS;
break;
case 'm':
case 'M':
@@ -706,23 +705,44 @@ convtime(const char *s)
multiplier = WEEKS;
break;
default:
- goto fail;
+ return -1.0;
}
- if (secs > INT_MAX / multiplier)
- goto fail;
- secs *= multiplier;
- if (total > INT_MAX - secs)
- goto fail;
- total += secs;
- if (total < 0)
- goto fail;
- p = ++np;
+
+ /* Special handling if this was a decimal */
+ if (memchr(start_p, '.', endp - start_p) != NULL) {
+ /* Decimal point present */
+ if (multiplier > 1.0)
+ return -1.0; /* No fractionals for non-seconds */
+ /* For seconds, ensure digits follow */
+ if (!isdigit((unsigned char)*(endp - 1)))
+ return -1.0;
+ }
+
+ total_sec += val * multiplier;
+
+ if (*p != '\0')
+ p++;
}
- free(os);
- return total;
-fail:
- free(os);
- return -1;
+ return total_sec;
+}
+
+/*
+ * Same as convtime_double() above but fractional seconds are ignored.
+ * Return -1 if time string is invalid.
+ */
+int
+convtime(const char *s)
+{
+ double sec_val;
+
+ if ((sec_val = convtime_double(s)) < 0.0)
+ return -1;
+
+ /* Check for overflow into int */
+ if (sec_val < 0 || sec_val > INT_MAX)
+ return -1;
+
+ return (int)sec_val;
}
#define TF_BUFS 8
diff --git a/misc.h b/misc.h
index f106be18f..5b401c5c4 100644
--- a/misc.h
+++ b/misc.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: misc.h,v 1.113 2025/11/06 01:31:11 djm Exp $ */
+/* $OpenBSD: misc.h,v 1.114 2025/12/05 07:43:12 djm Exp $ */
/*
* Author: Tatu Ylonen <ylo at cs.hut.fi>
@@ -81,7 +81,9 @@ char *colon(char *);
int parse_user_host_path(const char *, char **, char **, char **);
int parse_user_host_port(const char *, char **, char **, int *);
int parse_uri(const char *, const char *, char **, char **, int *, char **);
+double convtime_double(const char *);
int convtime(const char *);
+double convtime_double(const char *);
const char *fmt_timeframe(time_t t);
int tilde_expand(const char *, uid_t, char **);
char *tilde_expand_filename(const char *, uid_t);
--
To stop receiving notification emails like this one, please contact
djm at mindrot.org.
More information about the openssh-commits
mailing list