Whamcloud - gitweb
LU-9325 libcfs: handle complex strings in cfs_str2num_check 17/32217/3
authorJames Simmons <uja.ornl@yahoo.com>
Tue, 8 May 2018 13:30:15 +0000 (09:30 -0400)
committerOleg Drokin <oleg.drokin@intel.com>
Thu, 17 May 2018 02:31:10 +0000 (02:31 +0000)
Originally the function cfs_str2num_check used simple_strtoul
but has been updated to kstrtoul. The string passed into
cfs_str2num_check can be a very complex, for example we could
have 10.37.202.[59-61]. When simple_strtoul was used the first
number until we hit a non-digit character could be extracted
but testing showed that kstrtoul will not return any value if
it detects any non-digit character. Because of this change in
behavior a different approach is needed to handle these types
of complex strings. The use of sscanf was investigated to see
if it could be used to extract numbers from the passed in
string but unlike its glibc counterpart the kernel version
also just reported a error with no results if a non-digit value
in the string was encountered. Another possible approach would
be to use __parse_int directly but that class of functions is
not exported by the kernel. So the approach in this patch is
to scan the string passed in for the first non-digit character
and replace that character with a '\0' so kstrtoul can be used.
Once completed the original character is restored. We also
restore a original behavior that was removed to return 0 when
we encounter any non digit character before the nob count.

Linux-commit : 3ad6152d766039cb8ffd8633d971fb79402e5464

Change-Id: If73d605499e2f05224a14417b0029036db38c8ba
Signed-off-by: Oleg Drokin <green@linuxhacker.ru>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Signed-off-by: James Simmons <uja.ornl@yahoo.com>
Reviewed-on: https://review.whamcloud.com/32217
Tested-by: Jenkins
Reviewed-by: John L. Hammond <john.hammond@intel.com>
Tested-by: Maloo <hpdd-maloo@intel.com>
Reviewed-by: Andreas Dilger <andreas.dilger@intel.com>
Reviewed-by: Dmitry Eremin <dmitry.eremin@intel.com>
Reviewed-by: Oleg Drokin <oleg.drokin@intel.com>
libcfs/libcfs/libcfs_string.c
libcfs/libcfs/tracefile.c

index cd93921..b460df3 100644 (file)
@@ -254,17 +254,47 @@ int
 cfs_str2num_check(char *str, int nob, unsigned *num,
                  unsigned min, unsigned max)
 {
-       char    *endp;
-
-       *num = simple_strtoul(str, &endp, 0);
-       if (endp == str)
-               return 0;
+       bool all_numbers = true;
+       char *endp, cache;
+       int len;
+       int rc;
+
+       endp = strim(str);
+       /**
+        * kstrouint can only handle strings composed
+        * of only numbers. We need to scan the string
+        * passed in for the first non-digit character
+        * and end the string at that location. If we
+        * don't find any non-digit character we still
+        * need to place a '\0' at position len since
+        * we are not interested in the rest of the
+        * string which is longer than len in size.
+        * After we are done the character at the
+        * position we placed '\0' must be restored.
+        */
+       len = min((int)strlen(endp), nob);
+       for (; endp < str + len; endp++) {
+               if (!isxdigit(*endp) && *endp != '-' &&
+                   *endp != '+') {
+                       all_numbers = false;
+                       break;
+               }
+       }
 
-       for (; endp < str + nob; endp++) {
-               if (!isspace(*endp))
-                       return 0;
+       /* Eat trailing space */
+       if (!all_numbers && isspace(*endp)) {
+               all_numbers = true;
+               endp--;
        }
 
+       cache = *endp;
+       *endp = '\0';
+
+       rc = kstrtouint(str, 0, num);
+       *endp = cache;
+       if (rc || !all_numbers)
+               return 0;
+
        return (*num >= min && *num <= max);
 }
 EXPORT_SYMBOL(cfs_str2num_check);
index 6e6a28f..54e0fab 100644 (file)
@@ -833,13 +833,16 @@ int cfs_trace_daemon_command(char *str)
                 cfs_tracefile_write_lock();
                 memset(cfs_tracefile, 0, sizeof(cfs_tracefile));
 
-        } else if (strncmp(str, "size=", 5) == 0) {
-                cfs_tracefile_size = simple_strtoul(str + 5, NULL, 0);
-                if (cfs_tracefile_size < 10 || cfs_tracefile_size > 20480)
-                        cfs_tracefile_size = CFS_TRACEFILE_SIZE;
-                else
-                        cfs_tracefile_size <<= 20;
-
+       } else if (strncmp(str, "size=", 5) == 0) {
+               unsigned long tmp;
+
+               rc = kstrtoul(str + 5, 10, &tmp);
+               if (!rc) {
+                       if (tmp < 10 || tmp > 20480)
+                               cfs_tracefile_size = CFS_TRACEFILE_SIZE;
+                       else
+                               cfs_tracefile_size = tmp << 20;
+               }
         } else if (strlen(str) >= sizeof(cfs_tracefile)) {
                 rc = -ENAMETOOLONG;
         } else if (str[0] != '/') {