Souborový systém Proc odráží aktuální stav linuxového jádra.
Aktuální stav jádra může představovat různé informace, jako jsou procesy na něm běžící, informace o hardwaru, informace o síti atd. Tento systém je tedy navržen tak, aby všechny tyto informace byly snadno přístupné procesům na uživatelské úrovni.
Také říkáme, že souborový systém proc je pseudo souborový systém. Je to proto, že soubory v tomto souborovém systému jsou načteny informacemi při přístupu k těmto souborům a to je důvod, proč soubory v tomto souborovém systému obvykle vykazují velikost nula.
Proveďte ve svém systému příkaz ls /proc a všimnete si něčeho podobného následujícímu:
$ ls /proc 1 15 1681 1719 35 60 713 878 cgroups filesystems kpageflags pagetypeinfo sysrq-trigger ....
Vidíme tedy, že tento souborový systém obsahuje soubory i adresáře. Názvy souborů nebo adresářů jsou buď abecední nebo číselné. Číselné názvy souborů nebo adresářů většinou odpovídají procesům běžícím v systému a číslo představuje ID procesu procesu. Je tedy velmi snadné zjistit informace na úrovni jádra o jakémkoli procesu pomocí jeho ID procesu a otevření odpovídajícího souboru.
V tomto článku budeme stavět na našich znalostech Loadable Kernel Modules (LKM) a probereme, jak jsou tyto proc soubory vytvářeny, čteny a zapisovány.
Informace o různých souborech, které se nacházejí pod /proc.
, naleznete v našem dřívějším článku o souborovém systému Linux procVytváření souborů Proc
V článku o modulech linuxového jádra jsme diskutovali o tom, jak vytvořit, načíst a uvolnit LKM. To byl základní koncept pro přidání dalších funkcí do linuxového jádra za běhu. Proc soubory fungují na stejném principu. Každý soubor proc je vytvořen, načten a uvolněn ve formě LKM.
V následujícím kódu se pokusíme vytvořit soubor proc a definovat jeho schopnosti čtení a zápisu.
#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; }
Ve výše uvedeném kódu:
- Ve funkci init_module jsme použili funkci ‚create_proc_entry‘ k vytvoření souboru proc s názvem ‚procEntry123‘
- Soubor je vytvořen s vhodnými oprávněními, jak je popsáno ve druhém argumentu funkce create_proc_entry.
- Při čtení a zápisu souboru proc se používají dvě funkce read_info a write_info.
- Adresa těchto dvou funkcí je přiřazena členům struktury proc_dir_entry.
- Výše uvedený krok byl proveden, aby kód věděl, kterou funkci má volat, když se čte a zapisuje soubor proc.
- Pokud je ve funkci write_info kapacita pro zápis do vyrovnávací paměti, použije se funkce copy_from_user ke zkopírování řetězce z uživatelského prostoru do vyrovnávací paměti přidělené modulu jádra.
- Ve funkci read_info jsou informace přítomné ve vyrovnávací paměti odesílány zpět do uživatelského prostoru.
Makefile pro výše uvedený kód vypadá takto:
$ 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
Nyní, když je výše uvedený kód zkompilován, vidíme :
$ 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'
Jakmile je kód úspěšně zkompilován, modul je vložen a načten následujícím příkazem:
$ sudo insmod proc.ko
A po vložení, pokud vidíme adresář proc, najdeme záznam ‚procEntry123‘
$ ls /proc/procEntry123 /proc/procEntry123
Teď, když se z toho pokusíme psát a číst:
$ echo "TGS" > /proc/procEntry123 $ cat /proc/procEntry123 TGS
Vidíme tedy, že jsme schopni číst a zapisovat soubor proc. Stejným způsobem jsou implementovány všechny standardní soubory proc.