Il file system Proc riflette lo stato corrente del kernel Linux.
Lo stato attuale del kernel potrebbe rappresentare varie informazioni come i processi in esecuzione su di esso, le informazioni sull'hardware, le informazioni di rete ecc. Quindi questo sistema è progettato in modo tale che tutte queste informazioni possano essere facilmente accessibili dai processi a livello di utente.
Diciamo anche che un file system proc è uno pseudo file system. Questo perché i file in questo file system vengono caricati con informazioni quando si accede a questi file e questo è il motivo per cui i file in questo file system di solito mostrano una dimensione zero.
Esegui un ls /proc sul tuo sistema e noterai qualcosa di simile al seguente:
$ ls /proc 1 15 1681 1719 35 60 713 878 cgroups filesystems kpageflags pagetypeinfo sysrq-trigger ....
Quindi vediamo che questo file system contiene file e directory. I nomi dei file o delle directory sono alfabetici o numerici. I nomi di file o directory numerici corrispondono principalmente ai processi in esecuzione sul sistema e il numero rappresenta l'ID processo del processo. Quindi è molto facile conoscere le informazioni a livello di kernel su qualsiasi processo usando il suo ID processo e aprendo il file corrispondente.
In questo articolo approfondiremo la nostra conoscenza dei moduli del kernel caricabili (LKM) e discuteremo come vengono creati, letti e scritti questi file proc.
Fare riferimento al nostro precedente articolo sul file system proc Linux per comprendere i vari file che si trovano in /proc.
Creazione di file Proc
Nell'articolo sui moduli del kernel Linux, abbiamo discusso su come creare, caricare e scaricare LKM. Questo era il concetto di base per aggiungere più funzionalità al kernel Linux in fase di esecuzione. I file Proc funzionano secondo lo stesso principio. Ogni file proc viene creato, caricato e scaricato sotto forma di LKM.
Nel codice seguente, proviamo a creare un file proc e a definirne le capacità di lettura e scrittura.
#include <linux/module.h> #include <linux/kernel.h> #include <linux/proc_fs.h> #include <linux/string.h> #include <linux/vmalloc.h> #include <asm/uaccess.h> #define MAX_LEN 4096 int read_info( char *page, char **start, off_t off,int count, int *eof, void *data ); ssize_t write_info( struct file *filp, const char __user *buff,unsigned long len, void *data ); static struct proc_dir_entry *proc_entry; static char *info; static int write_index; static int read_index; int init_module( void ) { int ret = 0; info = (char *)vmalloc( MAX_LEN ); memset( info, 0, MAX_LEN ); proc_entry = create_proc_entry( "procEntry123", 0644, NULL ); if (proc_entry == NULL) { ret = -1; vfree(info); printk(KERN_INFO "procEntry123 could not be created\n"); } else { write_index = 0; read_index = 0; proc_entry->read_proc = read_info; proc_entry->write_proc = write_info; printk(KERN_INFO "procEntry123 created.\n"); } return ret; } void cleanup_module( void ) { remove_proc_entry("procEntry123", proc_entry); printk(KERN_INFO "procEntry123 unloaded.\n"); vfree(info); } ssize_t write_info( struct file *filp, const char __user *buff, unsigned long len, void *data ) { int capacity = (MAX_LEN-write_index)+1; if (len > capacity) { printk(KERN_INFO "No space to write in procEntry123!\n"); return -1; } if (copy_from_user( &info[write_index], buff, len )) { return -2; } write_index += len; info[write_index-1] = 0; return len; } int read_info( char *page, char **start, off_t off, int count, int *eof, void *data ) { int len; if (off > 0) { *eof = 1; return 0; } if (read_index >= write_index) read_index = 0; len = sprintf(page, "%s\n", &info[read_index]); read_index += len; return len; }
Nel codice sopra :
- Nella funzione init_module abbiamo usato la funzione 'create_proc_entry' per creare un file proc chiamato 'procEntry123'
- Il file viene creato con privilegi adeguati come descritto dal secondo argomento della funzione create_proc_entry.
- Due funzioni read_info e write_info vengono utilizzate durante la lettura e la scrittura del file proc.
- L'indirizzo di queste due funzioni è assegnato ai membri della struttura proc_dir_entry.
- Il passaggio precedente è stato eseguito affinché il codice sapesse quale funzione chiamare quando il file proc viene letto e scritto.
- Nella funzione write_info, se c'è capacità di scrivere nel buffer, la funzione copy_from_user viene utilizzata per copiare la stringa dallo spazio utente al buffer di memoria allocato del modulo del kernel.
- Nella funzione read_info, le informazioni presenti nel buffer vengono rispedite allo spazio utente.
Il Makefile per il codice sopra è simile a:
$ cat Makefile obj-m += proc.o all: sudo make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules clean: sudo make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean
Ora, quando il codice sopra è compilato, vediamo :
$ make sudo make -C /lib/modules/2.6.32-21-generic/build M=/home/himanshu modules make: Entering directory `/usr/src/linux-headers-2.6.32-21-generic' CC [M] /home/himanshu/proc.o /home/himanshu/proc.c: In function ‘init_module’: /home/himanshu/proc.c:33: warning: assignment from incompatible pointer type Building modules, stage 2. MODPOST 1 modules LD [M] /home/himanshu/proc.ko make: Leaving directory `/usr/src/linux-headers-2.6.32-21-generic'
Una volta che il codice è stato compilato correttamente, il modulo viene inserito e caricato dal seguente comando:
$ sudo insmod proc.ko
E dopo aver inserito se vediamo la directory proc, troviamo una voce 'procEntry123'
$ ls /proc/procEntry123 /proc/procEntry123
Ora, se proviamo a scrivere e leggere da esso:
$ echo "TGS" > /proc/procEntry123 $ cat /proc/procEntry123 TGS
Quindi vediamo che siamo in grado di leggere e scrivere il file proc. Allo stesso modo vengono implementati tutti i file di proc standard.