¿Cómo convertir una cadena char a int en el kernel de Linux?

Cómo convertir char [] a int en el núcleo de Linux

con la validación de que el texto introducido es en realidad un 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; } 

Vea las diversas encarnaciones de kstrtol() en #include en su árbol fuente de Linux amigable.

El que necesita depende de si el *buffer es un usuario o una dirección del kernel, y de qué tan estrictas sean sus necesidades en el manejo / control de errores del contenido del búfer (por ejemplo, ¿es 123qx no válido o debería devolver 123 ?).

Debido a la falta de disponibilidad de una gran cantidad de funciones / macros comunes en el kernel de Linux, no puede usar ninguna función directa para obtener un valor entero de un búfer de cadena.

Este es el código que he estado usando durante mucho tiempo para hacer esto y se puede usar en todos los sabores * NIX (probablemente sin ninguna modificación).

Esta es la forma modificada de código, que usé hace mucho tiempo desde un proyecto de código abierto (no recuerdo el nombre ahora).

 #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 mínima de kstrtoull_from_user debugfs

La familia kstrto*_from_user es muy conveniente cuando se trata de datos de usuario.

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"); 

Uso:

 insmod kstrto.ko cd /sys/kernel/debug echo 1234 > lkmc_kstrto echo foobar > lkmc_kstrto 

Dmesg salidas:

 ok = 1234 ko = -22 

Probado en el kernel de Linux 4.16 con esta configuración QEMU + Buildroot .

Para este ejemplo en particular, es posible que haya querido usar debugfs_create_u32 en debugfs_create_u32 lugar.

Use atoi e isdigit (nota isdigit solo toma un char). http://www.cplusplus.com/reference/clibrary/cctype/isdigit/

Utilizo sscanf () (la versión del kernel) para escanear desde una secuencia de cadenas, y funciona en 2.6.39-gentoo-r3. Francamente, nunca pude hacer que simple_strtol () trabaje en el kernel; actualmente estoy descubriendo por qué esto no funciona en mi caja.

  ... 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" ...