magaz/content/articles/27/04_proc.md
2022-03-23 20:14:33 +02:00

14 KiB

+++ title = 'Περιγραφή του proc filesystem' date = '2000-10-01T00:00:00Z' description = '' author = 'Πρατικάκης Πολύβιος(mailto:polyvios@softlab.ntua.gr)' issue = ['Magaz 27'] issue_weight = 4 +++



1. Εισαγωγή

2. Οι δομές του proc

3. Std disclaimer

[1. Εισαγωγή]

Στο linux υπάρχει ένα σύστημα αρχείων, το proc, το οποίο προσαρτάται συνήθως στο /proc στο δένδρο καταλόγων, και το οποίο είναι εικονικό. Αυτό που δηλαδή φαίνεται ως αρχεία, στην πραγματικότητα δεν υπάρχει πουθενά στο δίσκο ή στην μνήμη του υπολογιστή. Στην πραγματικότητα, τα φαινομενικά αρχεία είναι απλές "εγγραφές" στο δένδρο καταλόγων που αντιστοιχούν το διάβασμα, γράψιμο κ.λ.π των "αρχείων" αυτών σε κλήσεις διαφόρων συναρτήσεων. Έτσι, όταν διαβάζει κάποιος το αρχείο π.χ. /proc/interrupts δεν διαβάζει τα περιεχόμενα ενός υπαρκτού αρχείου, αλλά απλώς την έξοδο μιας συνάρτησης που καλείται κάθε φορά που το αρχείο αυτό διαβάζεται.

Το εικονικό σύστημα αρχείων proc, χρησιμοποιείται κυρίως για την αναφορά πληροφοριών (δυναμικά) του συστήματος. Μπορεί δε να αλλάξει δυναμικά, δηλαδή να προστεθούν και να αφαιρεθούν αρχεία και κατάλογοι, ανάλογα με την τρέχουσα κατάσταση του συστήματος.
Ο προγραμματισμός του συστήματος αρχείων proc στον πυρήνα, προσφέρει ένα υπάρχον σύνολο συναρτήσεων (ελληνιστί API), που καθιστούν την επέμβαση στο proc και την προσθαφαίρεση αρχείων σχετικά εύκολη. Για να προσθέσουμε ένα αρχείο στο proc, χρησιμοποιούμε τη συνάρτηση proc_register(), η οποία παίρνει ως όρισμα μια δομή που περιγράφει το αρχείο (όνομα, μέγεθος, ιδιότητες, κ.λ.π.), καθώς και τις συνδεδεμένες με το αρχείο συναρτήσεις. Επιπλέον, δίνεται η - πολύ χρήσιμη - δυνατότητα να περάσουμε ένα δείκτη, ο οποίος θα περαστεί ως παράμετρος στην συνάρτηση που κάθε φορά καλείται. Με αυτό τον τρόπο, μπορούμε να γράψουμε μια φορά τις συναρτήσεις που καλύπτουν πολλά "ίδια" αρχεία του proc.

Για παράδειγμα, προφανώς δεν χρειάζεται να γραφούν ξεχωριστές συναρτήσεις για το αρχείο /proc/parport/0/irq και /proc/parport/1/irq, αλλά οι ίδιες συναρτήσεις καλούνται με διαφορετικό όρισμα. Ο τρόπος για να γίνει αυτό, είναι ένας δείκτης void *, ο οποίος "συνδέεται" με κάθε αρχείο, και "κουβαλάει" ό,τι αυτό χρειάζεται.

[2. Οι δομές του proc]

Επειδή το καλό με το Open Source είναι το... open source, παρατηρώντας το αρχείο linux/include/linux/proc_fs.h, βλέπουμε τα εξής:

  • 3-4 enum τα οποία καθορίζουν σταθερές. Οι σταθερές αυτές χρησιμοποιούνται από κάποια "αρχεία" του proc, το ποιά είναι φανερό από την ονομασία τους. Π.χ., οι σταθερές PROC_* (το πρώτο enum), είναι τα "είδη" των αρχείων ή καταλόγων που βλέπει κανείς ακριβώς "κάτω" από το σημείο που προσαρτάται το proc, συνήθως δηλαδή στο /proc/*. Οι σταθερές PROC_NET_* βρίσκονται στο /proc/net κ.ο.κ.

  • Στη συνέχεια, βλέπουμε το σημαντικό μέρος του αρχείου, την δομή proc_dir_entry. Κάθε αρχείο του proc είναι ουσιαστικά μια τέτοια δομή. Αναλυτικά, τα πεδία της δομής είναι:

    low_ino

    Στη μεταβλητή αυτή τίθεται το είδος του αρχείου, που συνήθως είναι μια από τις σταθερές που ορίζονται παραπάνω.

    namelen

    Όπως ίσως φαίνεται, στη μεταβλητή αυτή αποθηκεύεται το μήκος του ονόματος του αρχείου.

    name

    Πρόκειται για δείκτη σε null terminated αλφαριθμητικό, με το όνομα του αρχείου.

    mode

    Στη μεταβλητή αυτή, καθορίζεται ο τύπος και τα permissions του αρχείου, δηλαδή το αν πρόκειται για αρχείο ή κατάλογο, αν και για ποιόν επιτρέπεται η εγγραφή, η ανάγνωση κ.λ.π.

    nlink

    Στη μεταβλητή αυτή αποθηκεύεται ο αριθμός των συνδεδεμένων αρχείων με αυτό το αρχείο, δηλαδή 1 αν πρόκειται για απλό αρχείο που συνδέεται μόνο με τον κατάλογο που το περιέχει, ή 2 αν πρόκειται για κατάλογο. Στην περίπτωση αυτή, το nlink καταλόγου αυξάνει όταν προσθέτουμε αρχεία σε κατάλογο.

    uid

    Το owner ID του αρχείου.

    gid

    Το group ID του αρχείου.

    size

    Το φαινομενικό μέγεθος του αρχείου, όπως αυτό φαίνεται π.χ. με την εντολή ls -l.

    ops

    Μια δομή inode_operations στην οποία περιέχονται δείκτες στις συναρτήσεις που χειρίζονται το inode (βλέπε κείμενα για συστήματα αρχείων) που δημιουργείται. Στο άρθρο αυτό, δεν θα υπάρξει εκτενής περιγραφή για τη δομή αυτή και τις πιθανές χρήσεις της. Για όποιον ενδιαφέρεται, ας κοιτάξει το linux kernel module programming guide, στο http://www.linuxdoc.org όπου γίνεται μια περιγραφή του proc, και χρησιμοποιείται η συγκεκριμένη δομή για είσοδο.

    get_info

    Συνάρτηση που καλείται κατά την ανάγνωση από το αρχείο και επιστρέφει το μήκος.

    fill_inode

    Η συνάρτηση αυτή καλείται για να συμπληρώσει τη δομή inode που αντιστοιχεί στο αρχείο, και χρησιμοποιείται μόνο όταν αυτά τα δεδομένα δεν μπορούν να καθοριστούν στατικά κατά την δημιουργία του αρχείου.

    next,parent,subdir

    Πρόκειται για δείκτες σε δομές proc_dir_entry. Με το δείκτη next, δημιουργείται μια συνδεδεμένη λίστα από όλες τις εγγραφές (entries) στο proc, ενώ χρησιμοποιώντας τους δείκτες parent και subdir, διατηρείται στη μνήμη ένα "δένδρο" καταλόγων για το proc.

    data

    Όπως αναφέρθηκε και στην εισαγωγή, κατά τη δημιουργία του αρχείου θέτουμε το δείκτη αυτό ώστε να δείχνει στα δεδομένα που αντικατοπτρίζει το αρχείο, και στη συνέχεια όταν καλλούνται οι διάφορες συναρτήσεις του αρχείου περνιέται ως παράμετρος. Έτσι, οι συναρτήσεις του αρχείου "ξέρουν" σε ποιά δεδομένα αναφέρεται το αρχείο αυτό.

    read_proc

    Συνάρτηση που καλείται όταν το αρχείο διαβάζεται. Η συνάρτηση αυτή χρησιμοποιείται για έξοδο από τον πυρήνα, και επιστρέφει (γράφει σε ένα buffer) δεδομένα κάθε φορά που καλείται. Μια από τις παραμέτρους της συνάρτησης αυτής είναι ο δείκτης data που προαναφέρθηκε.

    write_proc

    Συνάρτηση που καλείται κατά το γράψιμο στο αρχείο. Με τη συνάρτηση αυτή επιτυγχάνεται η είσοδος παραμέτρων προς τον πυρήνα μέσα από το σύστημα αρχείων proc. Αυτό βέβαια γίνεται και μέσω των συναρτήσεων του inode του αρχείου, αλλά ο τρόπος αυτός είναι προτιμότερος, γιατί υπάρχει και εδώ ο μηχανισμός με το δείκτη data, που επιτρέπει να υπάρχουν "παρόμοια" αρχεία.

    readlink_proc

    Η συνάρτηση αυτή (από ότι έχω καταλάβει πάντα) καλείται όταν το αρχείο "συνδέεται" (link), όπως π.χ. με την εντολή ln.

    count

    Μετρητής για την απαρίθμηση της χρήσης του αρχείου. Αυξάνει κάθε φορά που το αρχείο ανοίγεται, και μειώνεται όταν κλείνεται.

    deleted

    Σημαία για το αν το αρχείο έχει σβηστεί.

  • Μετά τον ορισμό της δομής proc_dir_entry, ακολουθούν ορισμοί τύπων για τους δείκτες συναρτήσεων που χρησιμοποιούνται, και δηλώνονται ορισμένες μεταβλητές που αντιστοιχούν στα "σίγουρα" αρχεία του proc, όπως π.χ. η ρίζα του, οι υποκατάλογοι net, scsi, sys, pid, κ.λ.π.

  • Οι επόμενες ενδιαφέρουσες δηλώσεις στο αρχείο, είναι αυτές των συναρτήσεων proc_register και proc_unregister. Χρησιμοποιώντας τις συναρτήσεις αυτές, "βάζουμε" και "βγάζουμε" proc_dir_entries, δηλαδή αρχεία, στο και από το proc filesystem.

Η συνέχεια του αρχείου είναι λίγο εως πολύ συγκεκριμένες δηλώσεις που χρησιμοποιούνται για τα υπάρχοντα αρχεία του proc, ή απλώς δεν τα έχω ψάξει αρκετα ;-).

Η μέχρι τώρα επεξήγηση πρέπει να είναι αρκετή για να "φτιάξετε" ένα αρχείο στο proc που θα μπορεί από το να "περιέχει" ένα απλό "hello world!", μέχρι να κάνει dump τα στατιστικά μιας tbf queueing discipline (Αυτό είναι σίγουρα ένα άλλο θέμα!). Για το πού θα πρέπει να προσθέσετε την proc_register() γραμμή σας, ένα πιθανό μέρος είναι η do_basic_setup() συνάρτηση στο αρχείο linux/init/main.c, ή η init_module() συνάρτηση του αρχείου που θα κάνετε insmod (Αλλά κι αυτό είναι ένα άλλο θέμα...)

Αν αυτή η περιγραφή σας άνοιξε την όρεξη, μπορείτε να διαβάσετε περισσότερα στον linux kernel module programmers guide, αν και οι αναφορές δεν είναι με τίποτα εκτενείς. Στο συγκεκριμένο guide υπάρχει γενικότερη αναφορά στα modules, σε IO - device drivers κ.λ.π. Μην ξεχνάτε όμως πως ο καλύτερος οδηγός είναι ο κώδικας. Άλλωστε γιατί ειναι τόσο σημαντικό το Open Source;

[3. Std disclaimer]

Στο παρόν άρθρο, καταβλήθηκε προσπάθεια να περιγραφεί το σύστημα αρχείων proc, όπως το έχω καταλάβει προσωπικά από τα sources του πυρήνα, και διάφορα guides. Δεν είμαι σίγουρος ότι οι πληροφορίες που δίνονται ανταποκρίνονται στην πραγματικότητα, και μη βασιστείτε σε αυτο :-).