[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