Eu olhei para isso principalmente por diversão e por aprendizado (e esperançosamente para o representante!). Eu gostaria de ter mais tempo para jogar com ioctl
(graças a Sneetsher pela sugestão) e com o que eu fiz até agora para fazer uma solução mais elegante, mas a recompensa está prestes a expirar e não é É provável que eu possa fazer tudo a tempo, então estou postando essa solução "como está" (pelo menos por enquanto).
Aviso:
Eu não sei quais são as conseqüências de mudar algo para /proc/device-tree
, então se você realmente sabe o que está fazendo, continue lendo.
Esta implementação específica desta solução requer um kernel em execução > 3,10. Ele envolve a compilação de um módulo de kernel personalizado e a execução de um script bash
para executar uma espécie de hot-switch entre /proc/device-tree
e um arquivo personalizado device-tree_new
.
Limites :
- Após a remoção do módulo, o
/proc/device-tree
personalizado é removido! Outro motivo para ler o aviso novamente . -
O buffer personalizado de
/proc/device-tree
tem um limite de65535
caracteres. Tudo sobre o caractere65535
está truncado. Para ajustar o tamanho do buffer, altere a seguinte definição de constante e declaração de variável no código-fonte do módulo:-
#define MAX_BUFFER_SIZE 65535
-
static unsigned int proc_buffer_length_v;
(para que possa conter um número >65535
)
-
Como funciona:
O próprio módulo:
-
elimina
/proc/device-tree
-
cria um novo espaço em branco
/proc/device-tree
com permissões0666
O script bash
em si:
- Carrega o módulo
- Grava em
/proc/device-tree
o conteúdo dedevice-tree_new
Este é o " Makefile
" Makefile
para o módulo ( observe que todos os espaços brancos no início de cada linha make
devem ser substituídos por um caractere TAB
):
obj-m += proc_module.o
all:
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules
clean:
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean
Este é o arquivo de origem " proc_module.c
" do módulo:
#include <linux/module.h>
#include <linux/init.h>
#include <linux/proc_fs.h>
#include <linux/slab.h>
#include <linux/uaccess.h>
#define DEBUG 1
#define MAX_BUFFER_SIZE 65535
static struct proc_dir_entry* proc_dir_entry_p;
static struct file_operations file_operations_s;
static char* proc_buffer_p;
static unsigned int proc_buffer_length_v;
static unsigned short int read_flag;
int read_proc(struct file* file, char* buffer, size_t count, loff_t* offset) {
if(DEBUG) printk(KERN_INFO "read_proc() called.\n");
if(read_flag)
read_flag = 0;
else {
read_flag = 1;
return 0;
}
copy_to_user(buffer, proc_buffer_p, proc_buffer_length_v);
if(DEBUG) printk(KERN_INFO "Ok. (count = %zu)\n", count);
return proc_buffer_length_v;
}
int write_proc(struct file* file, char* buffer, size_t count, loff_t* offset) {
size_t n;
if(DEBUG) printk(KERN_INFO "write_proc() called.\n");
if(count >= MAX_BUFFER_SIZE) {
if(DEBUG) printk(KERN_INFO "write_proc(): Buffer exceeded!\n");
n = MAX_BUFFER_SIZE;
}
else
n = count;
kfree(proc_buffer_p);
if(DEBUG) printk(KERN_INFO "kfree() called.\n");
if(!(proc_buffer_p = (char*)kmalloc(MAX_BUFFER_SIZE*sizeof(char), GFP_KERNEL))) {
if(DEBUG) printk(KERN_INFO "kmalloc() ko.\n");
return count;
}
if(DEBUG) printk(KERN_INFO "kmalloc() ok.\n");
copy_from_user(proc_buffer_p, buffer, n);
proc_buffer_length_v = n;
if(DEBUG) printk(KERN_INFO "Ok. (count = %zu)\n", count);
return count;
}
static int __init init_f(void) {
if(DEBUG) printk(KERN_INFO "Module inserted.\n");
remove_proc_entry("device-tree", NULL);
if(!(proc_dir_entry_p = proc_create("device-tree", 0666, NULL, &file_operations_s))) {
if(DEBUG) printk(KERN_INFO "Proc entry not created.\n");
return -1;
}
if(DEBUG) printk(KERN_INFO "Proc entry created.\n");
file_operations_s.read = read_proc;
file_operations_s.write = write_proc;
if(!(proc_buffer_p = (char*)kmalloc(1*sizeof(char), GFP_KERNEL))) {
if(DEBUG) printk(KERN_INFO "kmalloc() ko.\n");
return -1;
}
if(DEBUG) printk(KERN_INFO "kmalloc() ok.\n");
proc_buffer_p[0] = '#!/bin/bash
sudo rmmod proc_module.ko
sudo insmod proc_module.ko && cat device-tree_new > /proc/device-tree
';
proc_buffer_length_v = 0;
read_flag = 1;
if(DEBUG) printk(KERN_INFO "Ok.\n");
return 0;
}
static void __exit exit_f(void) {
kfree(proc_buffer_p);
if(DEBUG) printk(KERN_INFO "kfree() called.\n");
proc_remove(proc_dir_entry_p);
if(DEBUG) printk(KERN_INFO "Proc entry removal requested.\n");
if(DEBUG) printk(KERN_INFO "Module removed.\n");
}
module_init(init_f);
module_exit(exit_f);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("kos");
MODULE_DESCRIPTION("proc_module");
Este é o script " switch.sh
" bash
:
obj-m += proc_module.o
all:
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules
clean:
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean
Instruções:
- Abra um
Terminal
com Ctrl + Alt + t - Crie uma nova pasta:
mkdir <folder_name>
- Altere o diretório de trabalho atual para a nova pasta:
cd <folder_name>
- Crie os três arquivos acima usando os mesmos nomes exatos entre aspas duplas
- Crie o arquivo
device-tree
personalizado e nomeie-o comodevice-tree_new
- Marque "
switch.sh
" como executável:chmod a+x switch.sh
- Compile o módulo:
make
(dois avisos serão lançados porgcc
) - Inicie o script
bash
:./switch.sh
-
cat /proc/device-tree
para ver o resultado