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.