Filehandles, αρχεία, κατάλογοι

ioctl#

Εκτέλεση κλήσης συστήματος ελέγχου συσκευής ioctl(2) σε filehandle.

Η ioctl είναι η άμεση σύνδεση Perl για την κλήση συστήματος POSIX ioctl(2) - τη γενική διεπαφή πυρήνα για ειδικές λειτουργίες συσκευής που δεν ταιριάζουν στο τυπικό μοντέλο read/write: μέγεθος παραθύρου τερματικού, παράμετροι σειριακής γραμμής, ερωτήματα σε συσκευή υποδοχής, τοποθέτηση ταινίας, και ό,τι άλλο επιλέγει να εκθέσει ένας οδηγός μέσω κωδικού αιτήματος. Αποστέλλει την FUNCTION έναντι του FILEHANDLE, περνώντας το SCALAR ως τρίτο όρισμα - είτε έναν μικρό ακέραιο είτε δείκτη σε buffer bytes, ανάλογα με το τι αναμένει η συγκεκριμένη FUNCTION.

Σε αντίθεση με την fcntl, της οποίας οι κωδικοί αιτημάτων βρίσκονται στο άρθρωμα Fcntl, οι κωδικοί αιτημάτων ioctl σχεδόν ποτέ δεν εξάγονται ως έτοιμες σταθερές. Η συνήθης διαδρομή είναι:

require "sys/ioctl.ph";

που εισάγει το μεταφρασμένο header <sys/ioctl.h>. Αν αυτό το αρχείο δεν υπάρχει, ή δεν ορίζει τον κωδικό που χρειάζεστε, κατασκευάστε το από τα headers C με το εργαλείο h2ph που συνοδεύει την Perl, ή ορίστε τη σταθερά μόνοι σας από το header του πυρήνα.

Σύνοψη#

require "sys/ioctl.ph";
ioctl FILEHANDLE, FUNCTION, SCALAR
ioctl($fh, $request, $buf)
my $rv = ioctl($fh, $request, $arg) || -1;

Τι επιστρέφεται#

Σε επιτυχία, ο ακέραιος που επέστρεψε ο πυρήνας. Όταν αυτός ο ακέραιος είναι 0, η Perl υποκαθιστά τη διπλής τιμής συμβολοσειρά "0 but true" - αληθής σε λογικό περιβάλλον, αριθμητικό 0 σε αριθμητικό περιβάλλον, και εξαιρούμενη από την προειδοποίηση Argument "..." isn't numeric. Αυτό σημαίνει ότι ένας απλός λογικός έλεγχος διακρίνει αξιόπιστα την επιτυχία από την αποτυχία ακόμη και για αιτήματα των οποίων η τιμή επιτυχίας είναι κυριολεκτικά μηδέν:

ioctl($fh, $request, $buf) or die "ioctl: $!";

Σε αποτυχία, η ioctl επιστρέφει undef και θέτει την $! στο σχετικό errno. Η πλήρης αντιστοίχιση:

Επιστροφή OS

Επιστροφή Perl

-1

undef

0

συμβολοσειρά "0 but true"

οποιαδήποτε άλλη τιμή

αυτός ο ακέραιος

Όταν χρειάζεστε την αδρή επιστροφή του πυρήνα - για κωδικούς αιτημάτων που κωδικοποιούν πληροφορία στην ίδια την τιμή επιστροφής - χρησιμοποιήστε το ιδίωμα από το perlfunc:

my $retval = ioctl($fh, $request, $arg) || -1;
printf "System returned %d\n", $retval;

Πώς χρησιμοποιείται το SCALAR#

Το SCALAR παραδίδεται στον πυρήνα ως τρίτο όρισμα της κλήσης C ioctl, και ο ρόλος του εξαρτάται από τον κωδικό αιτήματος:

  • Δείκτης σε buffer. Η συνήθης περίπτωση. Τα περισσότερα αιτήματα ioctl διαβάζουν από ή γράφουν σε ένα C struct του οποίου η διάταξη ορίζεται από τον οδηγό. Κατασκευάστε τον buffer με pack πριν την κλήση και, για αιτήματα που γράφουν πίσω, αποκωδικοποιήστε με unpack έπειτα. Προδιαστασιολογήστε το βαθμωτό στο μήκος του struct τουλάχιστον - η Perl θα επεκτείνει αυτόματα ένα μικρότερο βαθμωτό, αλλά η προδιαστασιολόγηση καθιστά την πρόθεση προφανή και αποφεύγει εκπλήξεις αν ο οδηγός γράψει περισσότερα από ό,τι αναμένατε.

  • Μικρός ακέραιος. Μια μειονότητα αιτημάτων παίρνει σκέτο ακέραιο αντί για δείκτη. Αν το SCALAR δεν έχει συμβολοσειριακή τιμή αλλά έχει αριθμητική, η Perl περνά τον αριθμό αντί για δείκτη. Για να εγγυηθείτε αυτή την αποστολή - ακόμα και για ένα βαθμωτό που μπορεί να έχει μετατραπεί σε συμβολοσειρά παλιότερα - προσθέστε του 0 πρώτα:

    my $n = 0 + $n;      # force numeric representation
    ioctl($fh, $request, $n);
    
  • Αγνοείται. Για κωδικούς αιτημάτων που δεν παίρνουν τρίτο όρισμα, περάστε 0 ως placeholder. Ο πυρήνας το αγνοεί· η σύμβαση κρατά την κλήση αναγνώσιμη.

Καθολική κατάσταση που επηρεάζει#

  • $! - τίθεται σε αποτυχία στο errno που επιστρέφει η ioctl(2).

  • Κατάσταση συσκευής ή περιγραφέα στο FILEHANDLE - η ioctl τυπικά μεταβάλλει κατάσταση πυρήνα σχετιζόμενη με τον υποκείμενο περιγραφέα αρχείου ή τη συσκευή του (χαρακτηριστικά τερματικού, επιλογές υποδοχής, θέση ταινίας). Αυτή η κατάσταση δεν είναι ορατή στην Perl μέσω άλλης μεταβλητής· διαβάστε την ξανά με άλλη κλήση ioctl χρησιμοποιώντας το αντίστοιχο αίτημα TIOCG... / SIOCG....

Παραδείγματα#

Ερώτημα μεγέθους παραθύρου τερματικού σε Linux. Το TIOCGWINSZ γράφει μια struct winsize (δύο unsigned short γραμμές/στήλες συν δύο πεδία που αγνοούνται) στον buffer:

require "sys/ioctl.ph";

my $winsize = "\0" x 8;
ioctl(STDOUT, TIOCGWINSZ(), $winsize)
    or die "TIOCGWINSZ: $!";
my ($rows, $cols) = unpack('S S', $winsize);
print "terminal is $rows rows by $cols cols\n";

Μέτρηση των διαθέσιμων bytes για ανάγνωση σε υποδοχή χωρίς να καταναλωθούν (το FIONREAD υποστηρίζεται ευρέως σε όλα τα Unix):

require "sys/ioctl.ph";

my $pending = pack('L', 0);
ioctl($sock, FIONREAD(), $pending)
    or die "FIONREAD: $!";
my $n = unpack('L', $pending);
print "$n bytes pending\n";

Θέση μιας υποδοχής σε μη μπλοκαριστική λειτουργία μέσω του αιτήματος FIONBIO - εναλλακτική στην προσέγγιση fcntl / F_SETFL, και η μορφή που ιστορικά ήταν φορητή σε ορισμένα παλαιότερα συστήματα:

require "sys/ioctl.ph";

my $on = pack('L', 1);
ioctl($sock, FIONBIO(), $on)
    or die "FIONBIO: $!";

Διάκριση μεταξύ «η κλήση συστήματος επέστρεψε 0» και «η κλήση συστήματος απέτυχε» χρησιμοποιώντας τη σύμβαση "0 but true":

my $rv = ioctl($fh, $request, $buf);
if (!defined $rv) {
    die "ioctl failed: $!";
} elsif ($rv eq "0 but true") {
    # kernel returned 0 - success with a zero value
} else {
    # kernel returned $rv
}

Κατασκευή του δικού σας κωδικού αιτήματος όταν το sys/ioctl.ph λείπει ή είναι ελλιπές. Η κωδικοποίηση (_IOR / _IOW / _IOWR) είναι ειδική του πυρήνα· σε Linux η μακροεντολή αναπτύσσεται σε τιμή 32 bit που μπορείτε να προ-υπολογίσετε και να κωδικοποιήσετε σταθερά:

use constant TIOCGWINSZ => 0x5413;   # Linux <asm-generic/ioctls.h>

my $winsize = "\0" x 8;
ioctl(STDOUT, TIOCGWINSZ, $winsize) or die $!;

Οριακές περιπτώσεις#

  • Παράλειψη του .ph require: σταθερές όπως TIOCGWINSZ αναλύονται ως barewords χωρίς ορισμένη τιμή, πυροδοτώντας EINVAL από τον πυρήνα. Είτε require "sys/ioctl.ph" είτε ορίστε τη σταθερά μόνοι σας με use constant.

  • Επιστροφή "0 but true": μη συγκρίνετε την επιστροφή με == 0 ως έλεγχο αποτυχίας. Χρησιμοποιήστε απλή λογική τιμή (or die) ή defined. Η σύγκριση ισότητας με την κυριολεκτική συμβολοσειρά λειτουργεί επίσης ($rv eq "0 but true") αλλά σπάνια χρειάζεται.

  • Έκπληξη αποστολής βαθμωτό/ακέραιος: ένα βαθμωτό που ήταν αριθμητικό αλλά μετατράπηκε σε συμβολοσειρά - για παράδειγμα μέσω παρεμβολής σε μήνυμα - αντιστρέφεται από σημασιολογία ορίσματος-ακεραίου σε σημασιολογία δείκτη-buffer στην επόμενη κλήση. Εξαναγκάστε αριθμητική αναπαράσταση με 0 + $x όταν ο κωδικός αιτήματος αναμένει ακέραιο.

  • Η διάταξη struct είναι ειδική της πλατφόρμας. Οι struct winsize, struct termios, struct ifreq και άλλες διαφέρουν μεταξύ πυρήνων και ακόμη μεταξύ αρχιτεκτονικών στον ίδιο πυρήνα. Μην κωδικοποιείτε σταθερά πρότυπα pack από μνήμη· επαληθεύστε έναντι του header του συστήματος-στόχου.

  • Υπομεγέθης buffer εξόδου. Αν ο οδηγός γράψει περισσότερα bytes από όσα κρατά αυτή τη στιγμή το SCALAR, το βαθμωτό επεκτείνεται, αλλά δεν έχετε καμία ένδειξη στην Perl ότι αυτό συνέβη. Προδιαστασιολογήστε στο μήκος του struct τουλάχιστον με "\0" x N ώστε αναγνώσεις πέρα από το τέλος του buffer να είναι σφάλματα οδηγού, όχι Perl.

  • Δεν υλοποιεί κάθε σύστημα κάθε αίτημα. Η ίδια η ioctl είναι POSIX, αλλά οι συγκεκριμένοι κωδικοί αιτημάτων είναι ορισμένοι από τον οδηγό. Ένα μη υποστηριζόμενο αίτημα αποτυγχάνει με ENOTTY ή EINVAL· μια κλήση ioctl σε σύστημα χωρίς καθόλου ioctl(2) εγείρει εξαίρεση.

  • ioctl έναντι fcntl: πανομοιότυπη επεξεργασία ορισμάτων και σύμβαση τιμής επιστροφής, διαφορετική διεπαφή πυρήνα. Χρησιμοποιήστε την fcntl για σημαίες περιγραφέων και POSIX locks· χρησιμοποιήστε την ioctl για κωδικούς ελέγχου συσκευής.

Διαφορές από το upstream#

Πλήρως συμβατό με το upstream Perl 5.42.

Δείτε επίσης#

  • fcntl - ίδια σύμβαση κλήσης και τιμής επιστροφής· χρησιμοποιείται για σημαίες σε επίπεδο περιγραφέα και advisory locks παρά για ειδικούς κωδικούς ελέγχου συσκευής

  • pack / unpack - απαιτούνται για κατασκευή και αποκωδικοποίηση των struct buffers που τα περισσότερα αιτήματα ioctl ανταλλάσσουν με τον πυρήνα

  • open / sysopen - άνοιγμα της συσκευής ή του ειδικού αρχείου με τον οδηγό του οποίου θα μιλήσει το αίτημα ioctl

  • binmode - ορισμένα αιτήματα ioctl (π.χ. αλλαγές λειτουργίας τερματικού) αλληλεπιδρούν με την ενταμίευση PerlIO· αλλάξτε σε raw mode όταν ο οδηγός και το PerlIO διαφωνούν για το line discipline

  • select / sysread - η κανονική διαδρομή I/O· καταφεύγετε στην ioctl μόνο όταν η λειτουργία που χρειάζεστε δεν εκφράζεται ως read ή write