[PATCH] lib: Extend kstrtobool() to accept "true"/"false"

From: Peter Zijlstra
Date: Fri Jun 26 2020 - 06:45:35 EST


On Fri, Jun 26, 2020 at 12:22:55PM +0200, Peter Zijlstra wrote:

> > This is too lax - it will be enabled for any !0 value. Please accept
> > only 0 and 1.
>
> kstrtobool() ftw

And looking at that, I find it really strange it does not in fact accept
"true" / "false", so how about this?

---
Subject: lib: Extend kstrtobool() to accept "true"/"false"

Extend the strings recognised by kstrtobool() to cover:

- 1/0
- y/n
- yes/no (new)
- t/f (new)
- true/false (new)
- on/off

Signed-off-by: Peter Zijlstra (Intel) <peterz@xxxxxxxxxxxxx>
---
lib/kstrtox.c | 60 ++++++++++++++++++++++++++++++++++++++++++++---------------
1 file changed, 45 insertions(+), 15 deletions(-)

diff --git a/lib/kstrtox.c b/lib/kstrtox.c
index 1006bf70bf74..b8b950325097 100644
--- a/lib/kstrtox.c
+++ b/lib/kstrtox.c
@@ -325,9 +325,17 @@ EXPORT_SYMBOL(kstrtos8);
* @s: input string
* @res: result
*
- * This routine returns 0 iff the first character is one of 'Yy1Nn0', or
- * [oO][NnFf] for "on" and "off". Otherwise it will return -EINVAL. Value
- * pointed to by res is updated upon finding a match.
+ * This return return 0 on success, otherwise it will return -EINVAL.
+ * It will accept (case invariant):
+ *
+ * - 1/0
+ * - y/n
+ * - yes/no
+ * - t/f
+ * - true/false
+ * - on/off
+ *
+ * and set @*res to either true/false respectively.
*/
int kstrtobool(const char *s, bool *res)
{
@@ -335,30 +343,52 @@ int kstrtobool(const char *s, bool *res)
return -EINVAL;

switch (s[0]) {
+ case 't':
+ case 'T':
+ if (!s[1] || !strcasecmp(s, "true"))
+ goto have_true;
+
+ break;
+
case 'y':
case 'Y':
+ if (!s[1] || !strcasecmp(s, "yes"))
+ goto have_true;
+
+ break;
+
case '1':
+have_true:
*res = true;
return 0;
+
+ case 'f':
+ case 'F':
+ if (!s[1] || !strcasecmp(s, "false"))
+ goto have_false;
+
+ break;
case 'n':
case 'N':
+ if (!s[1] || !strcasecmp(s, "no"))
+ goto have_false;
+
+ break;
case '0':
+have_false:
*res = false;
return 0;
+
case 'o':
case 'O':
- switch (s[1]) {
- case 'n':
- case 'N':
- *res = true;
- return 0;
- case 'f':
- case 'F':
- *res = false;
- return 0;
- default:
- break;
- }
+ if (!strcasecmp(s, "on"))
+ goto have_true;
+
+ if (!strcasecmp(s, "off"))
+ goto have_false;
+
+ break;
+
default:
break;
}