如何在Linux内核中将char 字符串转换为int?
如何在linux内核中将char []转换为int
validation输入的文本实际上是一个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; }
在友好的linux源代码树中查看#include
中kstrtol()
的各种forms。
您需要哪一个取决于*buffer
是用户还是内核地址,以及您对error handling/检查缓冲区内容的需求有多严格(例如, 123qx
无效还是应该返回123
?)。
由于linux内核中没有很多常用的函数/宏,你不能使用任何直接函数从字符串缓冲区中获取整数值。
这是我长期使用的代码,它可用于所有* NIX风格(可能没有任何修改)。
这是修改后的代码forms,我从开源项目中使用了很长时间(现在不记得名字了)。
#define ISSPACE(c) ((c) == ' ' || ((c) >= '\t' && (c) <= '\r')) #define ISASCII(c) (((c) & ~0x7f) == 0) #define ISUPPER(c) ((c) >= 'A' && (c) <= 'Z') #define ISLOWER(c) ((c) >= 'a' && (c) <= 'z') #define ISALPHA(c) (ISUPPER(c) || ISLOWER(c)) #define ISDIGIT(c) ((c) >= '0' && (c) <= '9') unsigned long mystr_toul ( char* nstr, char** endptr, int base) { #if !(defined(__KERNEL__)) return strtoul (nstr, endptr, base); /* user mode */ #else char* s = nstr; unsigned long acc; unsigned char c; unsigned long cutoff; int neg = 0, any, cutlim; do { c = *s++; } while (ISSPACE(c)); if (c == '-') { neg = 1; c = *s++; } else if (c == '+') c = *s++; if ((base == 0 || base == 16) && c == '0' && (*s == 'x' || *s == 'X')) { c = s[1]; s += 2; base = 16; } if (base == 0) base = c == '0' ? 8 : 10; cutoff = (unsigned long)ULONG_MAX / (unsigned long)base; cutlim = (unsigned long)ULONG_MAX % (unsigned long)base; for (acc = 0, any = 0; ; c = *s++) { if (!ISASCII(c)) break; if (ISDIGIT(c)) c -= '0'; else if (ISALPHA(c)) c -= ISUPPER(c) ? 'A' - 10 : 'a' - 10; else break; if (c >= base) break; if (any < 0 || acc > cutoff || (acc == cutoff && c > cutlim)) any = -1; else { any = 1; acc *= base; acc += c; } } if (any < 0) { acc = INT_MAX; } else if (neg) acc = -acc; if (endptr != 0) *((const char **)endptr) = any ? s - 1 : nstr; return (acc); #endif }
最小的可运行的kstrtoull_from_user
debugfs
示例
处理用户数据时, kstrto*_from_user
系列非常方便。
kstrto.c:
#include #include #include #include /* 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");
用法:
insmod kstrto.ko cd /sys/kernel/debug echo 1234 > lkmc_kstrto echo foobar > lkmc_kstrto
Dmesg输出:
ok = 1234 ko = -22
使用此QEMU + Buildroot设置在Linux内核4.16中进行了测试。
对于此特定示例,您可能希望使用debugfs_create_u32
。
使用atoi和isdigit(注意isdigit只需要一个字符)。 http://www.cplusplus.com/reference/clibrary/cctype/isdigit/
你可以使用strtoul
或strtol
。 这是手册页的链接:
http://www.kernel.org/doc/man-pages/online/pages/man3/strtoul.3.html
http://www.kernel.org/doc/man-pages/online/pages/man3/strtol.3.html
我使用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" ...