System plików proc (dalej będę zwykle pisać krótko procfs) jest
wirtualnym systemem plików i interfejsem do pewnych struktur danych
działającego systemu (jądra). Celem powstania procfs'a było
ułatwienie życia programistom i użytkownikom systemu, dlatego
też idea ta przyjęła kształt właśnie wirtualnego systemu plików -
dane z pliku czyta się łatwo, nietrudno także się je w plikach
zapisuje.
Zauważmy jak łatwo, mając procfs'a, napisać taki program jak
top albo ps (te programy rzeczywiście korzystają z
katalogu /proc - można sprawdzić zabierając prawa dostępu, wyrzucą
wtedy jakiś błąd).
Interfejs ten pozwala przeważnie na odczyt pewnych informacji, ale w niektórych przypadkach można także do plików w strukturze procfs'a zapisywać dane i w ten sposób zmieniać zachowanie niektórych części jądra systemu.
Warto zwrócić uwagę na wspomnianą ideę łatwego, ogólnie znanego interfejsu, nie jest to jedyne miejsce gdzie się stosuje podejście plikowe do rzeczy o wiele bardziej abstrakcyjnych (pytanie do słuchaczy: gdzie na przykład jeszcze?).
Nie ma nic magicznego w montowaniu systemu plików proc, choć w większości dystrybucji montuje się go nieco wcześniej niż pozostałe systemy plików, a robi się tak dlatego, że wiele programów uruchamianych podczas startu korzysta właśnie z informacji zawartych w katalogu /proc. Gdyby ktoś chciał ręcznie zamontować sobie procfs, to należy zrobić coś takiego:
mount -t proc none /procmożna na przykład zamienić parametr /proc na jakiś inny katalog i stworzyć sobie "drugiego" procfs'a. Linijka w /etc/fstab wygląda tak:
none /proc proc defaults 0 0różni się ona od innych linijek głównie tym, że na pierwszym miejscu, gdzie powinno być urządzenie jakie należy zamontować jest none.
Inicjalizacją procfs'a zajmuje się funkcja proc_root_init wywoływana z funkcji start_kernel. Inicjalizacja, to głównie:
int err = register_filesystem(&proc_fs_type);gdzie proc_fs_type jest strukturą typu file_system_type zawierającą podstawowe informacje o systemach plików.
//typ funkcji generującej zawartość pliku
typedef int (read_proc_t)(char *page, char **start, off_t off,
int count, int *eof, void *data);
//typ funkcji obsługującej zapis do pliku z procfs'a
typedef int (write_proc_t)(struct file *file, const char *buffer,
unsigned long count, void *data);
//typ funkcji generującej zawartość funkcji (dawniejsze implementacje)
typedef int (get_info_t)(char *, char **, off_t, int);
//struktura zawierająca pojedynczy wpis w procfs
struct proc_dir_entry {
//numer i-węzła
unsigned short low_ino;
//długość nazwy
unsigned short namelen;
//nazwa
const char *name;
//atrybuty pliku
mode_t mode;
//liczba zawieranych plików (dla katalogów)
nlink_t nlink;
//właściciel pliku
uid_t uid;
//grupa do jakiej należy plik
gid_t gid;
//rozmiar pliku
unsigned long size;
//operacje i-węzłowe
struct inode_operations *proc_iops;
//operacje na pliku
struct file_operations *proc_fops;
//funkcja do generowania zaw. pliku
//(zaszłość trzymana ze względu na niektóre, starsze kawałki kodu,
//zamiast tego powinno używać się read_proc)
get_info_t *get_info;
//jeżeli dany wpis jest z jakiegoś modułu, to powinno się to pole ustawić
//na THIS_MODULE (używane do zwiększania/zmniejszania liczników użycia modułu)
struct module *owner;
//następny w katalogu, katalog-ojciec oraz lista podkatalogów
struct proc_dir_entry *next, *parent, *subdir;
//dane specyficzne dla pliku (głównie zawartość linków)
void *data;
//funkcja wywoływana przy czytaniu z pliku
read_proc_t *read_proc;
//funkcja wywoływana przy zapisie do pliku
write_proc_t *write_proc;
//licznik użyć
atomic_t count;
//flaga skasowania (ustawia się jak ma być skasowany, a jest w użyciu)
int deleted;
//dla tworzonych urządzeń w procfs'ie
kdev_t rdev;
};

Schemat postępowania zawsze jest taki sam:
static struct proc_dir_entry *proc_create( struct proc_dir_entry **parent, const char *name, mode_t mode, nlink_t nlink);
static int proc_register(struct proc_dir_entry * dir, struct proc_dir_entry * dp);
struct proc_dir_entry *proc_mkdir(const char *name, struct proc_dir_entry *parent);
struct proc_dir_entry *proc_mknod(const char *name, mode_t mode, struct proc_dir_entry *parent, kdev_t rdev);
struct proc_dir_entry *proc_symlink(const char *name, struct proc_dir_entry *parent, const char *dest);
struct proc_dir_entry *create_proc_entry(const char *name, mode_t mode, struct proc_dir_entry *parent);Przy czym w tym przypadku należy jeszcze samodzielnie ustawić pole proc_fops gdyż i tak dla każdego pliku będzie to co innego.
Aby stworzyć plik, dla którego przewidujemy możliwość czytania, potrzebna nam będzie funkcja obsługująca to czytanie, musi ona wyglądać jakoś tak:
int read_function(char* page, char** start, off_t off, int count, int* eof, void* data);Generowane informacje powinny zostać zapisane pod adres page + off i nie powinno być zapisane więcej niż count bajtów. Pod adres eof powinna zostać wpisana jedynka jeżeli nastąpił koniec informacji, a 0 wpp. Taka funkcja musi zwrócić ilość zapisanych do page znaków.
Podobnie jak w przypadku wypisywania zawartości, tak i teraz należy zdefiniować własną funkcję:
int write_function(struct file* file, const char* buffer, unsigned long count, void* data);Funkcja ta ma czytać z adresu buffer maksymalnie count bajtów (należy użyć funkcji copy_from_user bo jest to pamięć z user space). Zwracać należy ilość wczytanych bajtów.
Katalogi odpowiadające procesom oraz link self w /proc są dość specyficzne dlatego implementowane są nieco inaczej. Nie ma dla nich oddzielnych struktur proc_dir_entry, wszystkie funkcje obsługujące katalog /proc różnią się przez to nieco od funkcji obsługujących pozostałe katalogi procfs'a (zwykle tym, że oprócz zrobienia tego co tamte wykonują na koniec dodatkowe rzeczy związane z katalogami procesów).