如何在Linux内核中将char[]字符串转换为int?

如何在Linux内核中将char[]字符串转换为int?,c,linux,linux-kernel,kernel,C,Linux,Linux Kernel,Kernel,如何在linux内核中将char[]转换为int 是否验证输入的文本实际上是int int procfile_write(struct file *file, const char *buffer, unsigned long count, void *data) { char procfs_buffer[PROCFS_MAX_SIZE]; /* get buffer size */ unsigned long procfs_buffer_size = co

如何在linux内核中将char[]转换为int

是否验证输入的文本实际上是int

int procfile_write(struct file *file, const char *buffer, unsigned long count,
       void *data)
{

   char procfs_buffer[PROCFS_MAX_SIZE];

    /* get buffer size */
   unsigned long procfs_buffer_size = count;
   if (procfs_buffer_size > PROCFS_MAX_SIZE ) {
       procfs_buffer_size = PROCFS_MAX_SIZE;
   }

   /* write data to the buffer */
   if ( copy_from_user(procfs_buffer, buffer, procfs_buffer_size) ) {
       return -EFAULT;
   }

   int = buffer2int(procfs_buffer, procfs_buffer_size);

   return procfs_buffer_size;
}
使用atoi和isdigit(注意isdigit只接受一个字符)。

您可以使用
strtoul
strtol
。以下是手册页的链接:



在友好的linux源代码树中查看中的
kstrtol()
的各种体现


您需要哪一个取决于
*缓冲区是用户还是内核地址,以及您对缓冲区内容的错误处理/检查的要求有多严格(例如,
123qx
是否无效或是否应返回
123
?).

由于linux内核中许多常用函数/宏不可用,因此不能使用任何直接函数从字符串缓冲区获取整数值

这是我长期以来一直在使用的代码,它可以用于所有*NIX风格(可能无需任何修改)

这是经过修改的代码形式,我很久以前在一个开源项目中使用过它(现在不记得名字了)

#定义ISSPACE(c)((c)='''| |((c)>='\t'&&&(c)='A'&(c)='A'&(c)='0'&(c)=基)
打破
如果(任何<0 | | | acc>截止| | |(acc==截止和&c>cutlim))
任何=-1;
其他的
{
任意=1;
acc*=基准;
acc+=c;
}
}
如果(任何<0)
{
acc=INT_最大值;
}
否则,如果(负)
acc=-acc;
如果(endptr!=0)
*((const char**)endptr)=任意?s-1:nstr;
返回(acc);
#恩迪夫
}
我使用sscanf()(内核版本)从字符串流进行扫描,它在2.6.39-gentoo-r3上工作。坦率地说,我永远无法让simple_strtol()在内核中工作——我目前正在弄清楚为什么这在我的机器上不起作用

  ...
  memcpy(bufActual, calc_buffer, calc_buffer_size);
  /* a = simple_strtol(bufActual, NULL, 10); */ // Could not get this to work
  sscanf(bufActual, "%c%ld", &opr, &a); // places '+' in opr and a=20 for bufActual = "20+\0"
  ...

最小可运行
kstrtoull\u来自用户
debugfs
示例

当处理用户数据时,来自用户的
kstrto*\u
系列非常方便

kstrto.c:

#include <linux/debugfs.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <uapi/linux/stat.h> /* S_IRUSR */

static struct dentry *toplevel_file;

static ssize_t write(struct file *filp, const char __user *buf, size_t len, loff_t *off)
{
    int ret;
    unsigned long long res;
    ret = kstrtoull_from_user(buf, len, 10, &res);
    if (ret) {
        /* Negative error code. */
        pr_info("ko = %d\n", ret);
        return ret;
    } else {
        pr_info("ok = %llu\n", res);
        *off= len;
        return len;
    }
}

static const struct file_operations fops = {
    .owner = THIS_MODULE,
    .write = write,
};

static int myinit(void)
{
    toplevel_file = debugfs_create_file("lkmc_kstrto", S_IWUSR, NULL, NULL, &fops);
    if (!toplevel_file) {
        return -1;
    }
    return 0;
}

static void myexit(void)
{
    debugfs_remove(toplevel_file);
}

module_init(myinit)
module_exit(myexit)
MODULE_LICENSE("GPL");
Dmesg输出:

ok = 1234
ko = -22
在Linux内核4.16中测试


对于这个特定的示例,您可能想改用。

您实际上是在寻找具有更好验证的
atoi
吗?内核既没有
atoi
也没有
strtol
这样的“C/C++标准库”仅对用户空间应用程序可用。对于许多这样的函数,虽然在内核中有函数等价物,但不一定同名。在Linux内核中有
isdigit()
(在
中,虽然不是
),但没有
atoi()
.AFAIK,您不能在内核模式下直接使用它们,即使它在某些内核中以某种形式可用,也不能保证在所有*NIX平台上都能正常工作。@Vikram:我不知道这个限制。可移植性是可以的,但对内核代码来说重新实现并不是最好的;当您谈到“其他Unix”时例如,Solaris内核确实有
strtol()
(即使在Solaris第9节手册中有记录,FreeBSD(它在libkern中)也有记录。Linux虽然有不同的名称。在所有这些方面,一个
#define
就可以了…@FrankH,同意了。但是我确信,如果你的代码将在很多操作系统上发布(比如我正在开发的1个操作系统),您肯定会发现至少有1个不支持/实现了所需的函数。无论如何,我完全同意,在这种情况下,最好使用现有代码,而不是使用自己的代码。这完全是错误的。正如另一个答案所说,Linux确实有非常有用的函数来将字符串转换为整数。@Roland just b因为一个被接受的答案这么说并不意味着这是正确的。请阅读我在这篇文章上的第二条评论,希望这能澄清你的疑问。我真的想不出否决投票的理由。这个问题与linux内核有关。其他内核?谁在乎呢。是的,
strict\u strtol()
simple\u strtol()
可能会在这里完成这项工作。123dew无效,我需要检查用户addersse,同时查看
kstrtol…()
funcs与
simple\u strtol()
和/或
strict\u strtol()
。在任何情况下,如果您不在最前沿,请使用它们。关于“用户地址”也请参见.这是个错误。
kstrotox()
不是
simple\u strtox()
的替代品。
insmod kstrto.ko
cd /sys/kernel/debug
echo 1234 > lkmc_kstrto
echo foobar > lkmc_kstrto
ok = 1234
ko = -22