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 |
|---|---|
| |
| συμβολοσειρά |
οποιαδήποτε άλλη τιμή | αυτός ο ακέραιος |
Όταν χρειάζεστε την αδρή επιστροφή του πυρήνα - για κωδικούς αιτημάτων που κωδικοποιούν πληροφορία στην ίδια την τιμή επιστροφής - χρησιμοποιήστε το ιδίωμα από το 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 $!;
Οριακές περιπτώσεις#
Παράλειψη του
.phrequire: σταθερές όπως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- άνοιγμα της συσκευής ή του ειδικού αρχείου με τον οδηγό του οποίου θα μιλήσει το αίτημαioctlbinmode- ορισμένα αιτήματαioctl(π.χ. αλλαγές λειτουργίας τερματικού) αλληλεπιδρούν με την ενταμίευση PerlIO· αλλάξτε σε raw mode όταν ο οδηγός και το PerlIO διαφωνούν για το line disciplineselect/sysread- η κανονική διαδρομή I/O· καταφεύγετε στηνioctlμόνο όταν η λειτουργία που χρειάζεστε δεν εκφράζεται ως read ή write