EnglezăFrancezăSpaniolă

Ad


Favicon OnWorks

explic_lca2010 - Online în cloud

Rulați explic_lca2010 în furnizorul de găzduire gratuit OnWorks prin Ubuntu Online, Fedora Online, emulator online Windows sau emulator online MAC OS

Aceasta este comanda explica_lca2010 care poate fi rulată în furnizorul de găzduire gratuit OnWorks folosind una dintre multiplele noastre stații de lucru online gratuite, cum ar fi Ubuntu Online, Fedora Online, emulator online Windows sau emulator online MAC OS

PROGRAM:

NUME


explic_lca2010 - Nu s-a găsit niciun mediu: când este timpul să nu mai încerci să citești strerror(3).
minte.

MOTIVAȚIE


Ideea pentru libexplain mi-a venit la începutul anilor 1980. Ori de câte ori un apel de sistem
returnează o eroare, nucleul știe exact ce a mers prost... și comprimă aceasta în
mai puțin de 8 biți de greseala. Spațiul utilizatorului are acces la aceleași date ca și nucleul, acesta
ar trebui să fie posibil ca spațiul utilizatorului să descopere exact ce s-a întâmplat pentru a provoca eroarea
returnați și utilizați-o pentru a scrie mesaje de eroare bune.

Ar putea fi atât de simplu?

Eroare mesaje as finețe
Mesajele de eroare bune sunt adesea acele sarcini „un procent” care sunt renunțate la program
presiunea îți stoarce proiectul. Cu toate acestea, un mesaj de eroare bun poate face un uriaș,
Îmbunătățirea disproporționată a experienței utilizatorului, atunci când utilizatorul rătăcește în înfricoșător
teritoriu necunoscut neîntâlnit de obicei. Aceasta nu este o sarcină ușoară.

În calitate de programator de larve, autorul nu a văzut problema cu eroarea (complet exactă)
mesaje ca acesta:
excepție flotantă (core dumping)
până când a fost indicată interpretarea alternativă non-programator. Dar asta nu este
singurul lucru în neregulă cu mesajele de eroare Unix. Cât de des vezi mesaje de eroare precum:
$ ./prost
nu se poate deschide fișierul
$
Există două opțiuni pentru un dezvoltator în acest moment:

1.
puteți rula un depanator, cum ar fi gDB(1) sau

2.
poți să folosești strace(1) sau grindă cu zăbrele(1) a privi înăuntru.

· Amintiți-vă că este posibil ca utilizatorii dvs. să nu aibă acces la aceste instrumente, cu atât mai puțin la capacitatea
pentru a le folosi. (A trecut foarte mult timp de atunci Unix începător însemna „a scris doar unu
driver de dispozitiv”.)

În acest exemplu, totuși, folosind strace(1) dezvăluie
$ strace -e urmă=deschis ./prost
open("unele/fișier", O_RDONLY) = -1 ENOENT (Nu există un astfel de fișier sau director)
nu se poate deschide fișierul
$
Acestea sunt considerabil mai multe informații decât oferă mesajul de eroare. De obicei,
codul sursă stupid arată așa
int fd = deschis("ceva", O_RDONLY);
dacă (fd < 0)
{
fprintf(stderr, „nu se poate deschide fișierul\n”);
ieşire(1);
}
Utilizatorului nu i se spune care fișier și, de asemenea, nu reușește să spună utilizatorului care eroare. A fost dosarul
chiar acolo? A existat o problemă cu permisiunile? Îți spune că a încercat să deschidă un
dosar, dar probabil că a fost întâmplător.

Ia-ți stick-ul cu indicii și învinge-l pe programatorul de larve. Spune-i despre groază(3).
Data viitoare când utilizați programul, veți vedea un mesaj de eroare diferit:
$ ./prost
deschide: Nu există un astfel de fișier sau director
$
Progres, dar nu ceea ce ne așteptam. Cum poate utilizatorul să remedieze problema dacă apare mesajul de eroare
nu-i spune care a fost problema? Privind la sursă, vedem
int fd = deschis("ceva", O_RDONLY);
dacă (fd < 0)
{
eroare ("deschis");
ieşire(1);
}
E timpul pentru o altă alergare cu stick-ul cu indicii. De data aceasta, mesajul de eroare face un pas
înainte și un pas înapoi:
$ ./prost
ceva: Nu există un astfel de fișier sau director
$
Acum știm fișierul pe care încerca să-l deschidă, dar nu mai suntem informați că a fost deschide(2)
care a eșuat. În acest caz, probabil că nu este semnificativ, dar poate fi semnificativ pentru
alte apeluri de sistem. Ar fi putut fi creat(2) în schimb, o operațiune care implică faptul că
sunt necesare permisiuni diferite.
const char *filename = "ceva";
int fd = open(nume fișier, O_RDONLY);
dacă (fd < 0)
{
eroare (nume fișier);
ieşire(1);
}
Exemplul de cod de mai sus este, din păcate, tipic și pentru programatorii non-larvare. Timp
pentru a spune cursantului nostru padawan despre strerror(3) apel de sistem.
$ ./prost
deschide ceva: Nu există un astfel de fișier sau director
$
Acest lucru maximizează informațiile care pot fi prezentate utilizatorului. Codul arată ca
acest:
const char *filename = "ceva";
int fd = open(nume fișier, O_RDONLY);
dacă (fd < 0)
{
fprintf(stderr, „deschide %s: %s\n”, nume de fișier, strerror(errno));
ieşire(1);
}
Acum avem apelul de sistem, numele fișierului și șirul de eroare. Acesta conține toate
informaţii care strace(1) tipărit. E la fel de bine.

Sau este?

Limitări of groază și strerror
Problema pe care autorul a văzut-o, în anii 1980, a fost că mesajul de eroare este incomplet.
„Niciun astfel de fișier sau director” se referă la „unele„directorul” sau la „lucru” dosar în
unele” director?

O privire rapidă la pagina de manual pentru strerror(3) spune:
strerror - returnează șirul care descrie numărul erorii
Rețineți bine: descrie eroarea număr, nu eroarea.

Pe de altă parte, nucleul știe care a fost eroarea. A existat un punct specific în
codul nucleului, cauzat de o anumită condiție, în care codul nucleului s-a ramificat și a spus „nu”.
Ar putea un program de spațiu utilizator să descopere condiția specifică și să scrie o eroare mai bună
mesaj?

Cu toate acestea, problema merge mai profund. Ce se întâmplă dacă problema apare în timpul citit(2) sistem
apel, mai degrabă decât deschide(2) sunați? Este simplu pentru mesajul de eroare asociat
deschide(2) pentru a include numele fișierului, este chiar acolo. Dar pentru a putea include un nume de fișier
în eroarea asociată cu citit(2) apel de sistem, trebuie să treceți numele fișierului toate
drumul în jos în stiva de apeluri, precum și descriptorul fișierului.

Și aici este bitul care zboară: nucleul știe deja ce nume de fișier este fișierul
descriptorul este asociat cu. De ce ar trebui un programator să treacă toate datele redundante
calea în jos a stivei de apeluri doar pentru a îmbunătăți un mesaj de eroare care s-ar putea să nu fie emis niciodată? În
realitate, mulți programatori nu se deranjează, iar mesajele de eroare rezultate sunt mai rău pentru
aceasta.

Dar asta era anii 1980, pe un PDP11, cu resurse limitate și fără biblioteci partajate. Înapoi
apoi, nicio aromă de Unix inclusă / proc chiar și în formă rudimentară, iar cel lsof(1) program
era la peste un deceniu distanță. Așa că ideea a fost abandonată ca nepractică.

Nivel Infinit Suport
Imaginați-vă că sunteți suport de nivel infinit. Fișa postului tău spune că niciodată
vreodată trebuie să vorbească cu utilizatorii. De ce, atunci, există încă un flux constant de oameni care doresc
tu, guru local Unix, să descifrezi încă un mesaj de eroare?

În mod ciudat, 25 de ani mai târziu, în ciuda unui sistem de permisiuni simplu, implementat cu complet
consecvență, majoritatea utilizatorilor Unix încă nu au idee cum să decodifice „Nu există un astfel de fișier sau director”,
sau oricare dintre celelalte mesaje de eroare criptice pe care le văd în fiecare zi. Sau, cel puțin, criptic
Le.

Nu ar fi frumos dacă suportul tehnic de prim nivel nu ar avea nevoie de descifrarea mesajelor de eroare?
Nu ar fi frumos să aveți mesaje de eroare pe care utilizatorii le-ar putea înțelege fără să sune
suport tehnic?

Aceste zile / proc pe Linux este mai mult decât capabil să ofere informațiile necesare pentru decodare
marea majoritate a mesajelor de eroare și indică utilizatorul cauza imediată a acestora
problemă. Pe sistemele cu un limitat / proc implementare, cel lsof(1) comanda poate fi completată
multe dintre goluri.

În 2008, fluxul de cereri de traducere i s-a întâmplat mult prea des autorului. A fost
este timpul să reexaminăm acea idee veche de 25 de ani, iar rezultatul este libexplain.

UTILIZAREA THE BIBLIOTECĂ


Interfața cu bibliotecă încearcă să fie consecventă, acolo unde este posibil. Să începem cu un
exemplu folosind strerror(3):
dacă (redenumiți (calea_veche, calea_nouă) < 0)
{
fprintf(stderr, „redenumiți %s %s: %s\n”, cale_veche, cale_nouă,
strerror(errno));
ieşire(1);
}
Ideea din spatele libexplain este de a oferi un strerror(3) echivalent pentru fiecare apel de sistem,
adaptat în mod special pentru acel apel de sistem, astfel încât să poată furniza o eroare mai detaliată
mesaj, care conține multe dintre informațiile pe care le vedeți sub titlul „ERORI” al secțiunii
2 și 3 om pagini, completate cu informații despre condițiile reale, argumente reale
valorile și limitele sistemului.

simplu Caz
strerror(3) înlocuire:
dacă (redenumiți (calea_veche, calea_nouă) < 0)
{
fprintf(stderr, "%s\n", explică_rename(veche_cale, noua_cale));
ieşire(1);
}

Errno Caz
De asemenea, este posibil să treceți un explicit greseala(3) valoare, dacă mai întâi trebuie să faceți ceva
procesare care ar deranja greseala, cum ar fi recuperarea erorilor:
dacă (redenumiți(calea_veche, calea_nouă < 0))
{
int old_errno = errno;
...cod acea deranjează greseala...
fprintf(stderr, „%s\n”, explică_errno_rename(old_errno,
cale_veche, cale_noua));
ieşire(1);
}

Multi-thread Cazuri
Unele aplicații sunt cu mai multe fire și, prin urmare, nu pot partaja interiorul libexplain
tampon. Puteți furniza propriul buffer folosind
dacă (deconectare (nume cale))
{
mesaj char[3000];
explic_message_unlink(mesaj, mărimea(mesaj), cale);
dialog_error(mesaj);
retur -1;
}
Și pentru completitudine, ambele greseala(3) și sigur pentru fire:
ssiize_t nbytes = read(fd, data, sizeof(data));
dacă (nbytes < 0)
{
mesaj char[3000];
int old_errno = errno;
...eroare recuperare...
explic_message_errno_read(mesaj, mărimea(mesaj),
old_errno, fd, data, sizeof(data));
dialog_error(mesaj);
retur -1;
}

Acestea sunt înlocuitori pentru strerror_r(3), pe sistemele care o au.

interfaţă zahăr
Un set de funcții adăugate ca funcții de confort, pentru a convinge programatorii să folosească
libexplain, se dovedesc a fi cele mai frecvent utilizate funcții libexplain ale autorului
programe de linie de comandă:
int fd = explică_creat_sau_die(nume fișier, 0666);
Această funcție încearcă să creeze un fișier nou. Dacă nu poate, tipărește un mesaj de eroare și
iese cu EXIT_FAILURE. Dacă nu există nicio eroare, returnează noul descriptor de fișier.

O funcție înrudită:
int fd = explic_creat_on_error(nume fișier, 0666);
va imprima mesajul de eroare la eșec, dar va returna și rezultatul inițial al erorii și
greseala(3) este de asemenea nederanjat.

TOATE il alte sistem Apeluri
În general, fiecare apel de sistem are propriul fișier include
#includenume.h>
care definește prototipuri de funcție pentru șase funcții:

· explica_nume,

· explica_errno_nume,

· explica_mesajul_nume,

· explica_mesajul_errno_nume,

· explica_nume_sau_mor și

· explica_nume_on_error.

Fiecare prototip de funcție are documentația Doxygen și această documentație is nu dezbrăcat
când fișierele includ sunt instalate.

aștepta(2) apelul de sistem (și prietenii) au câteva variante suplimentare care interpretează și eșecul
să fie o stare de ieșire care nu este EXIT_SUCCESS. Acest lucru se aplică sistem(3) și pclose(3) as
bine.

Acoperirea include 221 de apeluri de sistem și 547 de solicitări ioctl. Există mult mai multe sisteme
solicită încă de implementat. Apeluri de sistem care nu revin niciodată, cum ar fi ieşire(2), nu sunt prezente
în bibliotecă și nu va fi niciodată. The Exec familie de apeluri de sistem sunt sprijinit, deoarece
se întorc când apare o eroare.

Pisica
Așa ar putea arăta un program ipotetic „pisica”, cu raportarea completă a erorilor,
folosind libexplain.
#include
#include
#include
Există o includere pentru libexplain, plus suspecții obișnuiți. (Dacă doriți să reduceți
încărcarea preprocesorului, puteți utiliza specificulnume.h> include.)
gol static
proces (FIȘIER *fp)
{
pentru (;;)
{
tampon de caractere[4096];
size_t n = explică_fread_or_die(buffer, 1, sizeof(buffer), fp);
dacă (!n)
rupe;
explică_fwrite_or_die(buffer, 1, n, stdout);
}
}
proces funcția copiează un flux de fișiere în ieșirea standard. În cazul în care apare o eroare
fie pentru citire, fie pentru scriere, este raportat (și calea va fi inclusă în fișierul
eroare) și comanda iese cu EXIT_FAILURE. Nici măcar nu ne facem griji cu privire la urmărirea
căi sau transmiterea lor în stiva de apeluri.
int
main(int argc, char **argv)
{
pentru (;;)
{
int c = getopt(argc, argv, "o:");
dacă (c == EOF)
rupe;
comutator (c)
{
cazul „o”:
explică_freopen_or_die(optarg, "w", stdout);
rupe;
Partea distractivă a acestui cod este că libexplain poate raporta erori inclusiv il caii de acces chiar
dacă nu face redeschide în mod explicit stdout așa cum se face aici. Nici măcar nu ne facem griji
urmărirea numelui fișierului.
implicit:
fprintf(stderr, „Utilizare: %ss [ -o ] ...\n",
argv[0]);
returnează EXIT_FAILURE;
}
}
if (optind == argc)
proces (stdin);
altfel
{
în timp ce (optind < argc)
{
FIȘIER *fp = explica_fopen_or_die(argv[optind]++, "r");
proces (fp);
explică_fclose_or_die(fp);
}
}
Ieșirea standard va fi închisă implicit, dar prea târziu pentru ca un raport de eroare să fie
emis, așa că facem asta aici, doar în cazul în care I/O-ul tamponat nu a scris încă nimic și
există o eroare ENOSPC sau așa ceva.
explică_flush_or_die(stdout);
returnează EXIT_SUCCESS;
}
Asta e tot. Raportare completă a erorilor, cod clar.

Al lui Rusty Scară of interfaţă Bunătate
Pentru cei dintre voi care nu sunt familiarizați cu el, „Cum fac asta greu de folosit greșit?” de Rusty Russel.
pagina este o citire obligatorie pentru designerii API.
http://ozlabs.org/~rusty/index.cgi/tech/2008‐03‐30.html

10. E imposibil la obține gresit.

Obiectivele trebuie stabilite înalte, ambițios de înalte, ca să nu le îndeplinești și să crezi că ești
terminat când nu ești.

Biblioteca libexplain detectează indicatori falși și mulți alți parametri de apel de sistem falși,
și, în general, încearcă să evite erorile de securitate chiar și în cele mai dificile circumstanțe.

Biblioteca libexplain este concepută pentru a fi sigură pentru fire. Va fi probabil mai multă utilizare în lumea reală
dezvăluie locuri care pot fi îmbunătățite.

Cea mai mare problemă este cu numele funcțiilor în sine. Pentru că C nu are
spații de nume, biblioteca libexplain folosește întotdeauna un prefix de nume explică_. Acesta este
mod tradițional de a crea un pseudo‐nume‐spațiu pentru a evita conflictele de simboluri.
Cu toate acestea, rezultă unele nume care sună nefiresc.

9. compilator or Link-uri nu va lăsa tu obține it gresit.

O greșeală obișnuită este să folosiți explic_open acolo unde a fost intenționat explic_open_or_die.
Din fericire, compilatorul va emite adesea o eroare de tip în acest moment (de exemplu nu pot atribui
const char * rvalue la o int lvalue).

8. compilator voi avertiza if tu obține it gresit.

Dacă explica_rename este folosit când a fost intenționat explic_rename_or_die, acest lucru poate cauza altele
Probleme. GCC are un atribut util de funcție warn_unused_result și libexplain
biblioteca îl atașează la toate explicațiile_nume apeluri de funcții pentru a produce un avertisment atunci când dvs
face aceasta greseala. Combină asta cu gcc -Eroare pentru a promova acest lucru la nivelul 9 bunătate.

7. evident utilizare is (probabil) il corecta unul.

Numele funcțiilor au fost alese pentru a-și transmite semnificația, dar acest lucru nu este întotdeauna
de succes. in timp ce explica_nume_sau_mor și explică_nume_on_error sunt destul de descriptive,
variantele mai puțin utilizate thread safe sunt mai greu de decodat. Prototipurile funcției ajută la
compilatorul spre înțelegere, iar comentariile Doxygen din fișierele de antet ajută utilizatorul
spre înţelegere.

6. nume spune tu cum la utilizare aceasta.

Este deosebit de important să citiți explica_nume_sau_mor ca „explica (nume sau mori)".
Folosirea unui prefix coerent explică_ spațiu de nume are unele efecte secundare nefericite în
departamentul de evidență, de asemenea.

Ordinea cuvintelor în nume indică și ordinea argumentelor. Argumentul
liste întotdeauna capăt cu aceleași argumente ca cele transmise apelului de sistem; toate of lor. Dacă
_errno_ apare în nume, argumentul său precede întotdeauna argumentele apelului de sistem. Dacă
_mesaj_ apare în nume, cele două argumente ale sale sunt întotdeauna primele.

5. Do it dreapta or it voi rupe at timpul de rulare.

Biblioteca libexplain detectează indicatori falși și mulți alți parametri de apel de sistem falși,
și, în general, încearcă să evite erorile de securitate chiar și în cele mai dificile circumstanțe. Ar trebui
nu se întrerupe niciodată în timpul execuției, dar o utilizare mai mare în lumea reală va îmbunătăți fără îndoială acest lucru.

Unele mesaje de eroare sunt destinate dezvoltatorilor și întrețintorilor mai degrabă decât utilizatorilor finali, așa cum este
poate ajuta la rezolvarea erorilor. Nu atât „pauză la timpul de execuție”, cât „fii informativ la
runtime” (după apelul de sistem barfs).

4. Urma comun convenţie și veți obține it dreapta.

Deoarece C nu are spații de nume, biblioteca libexplain folosește întotdeauna un nume explicit
prefix. Acesta este modul tradițional de a crea un pseudo-nume-spațiu pentru a evita
conflicte de simboluri.

Argumentele de sfârșit ale tuturor apelurilor libexplain sunt identice cu apelurile de sistem
descriu. Aceasta este menită să ofere o convenție consecventă în comun cu
numerele de sistem.

3. Citeste il documentaţie și veți obține it dreapta.

Biblioteca libexplain își propune să aibă documentație completă Doxygen pentru fiecare
apel public API (și intern).

MESAJ CONȚINUTUL


Lucrul la libexplain este un pic ca să te uiți la partea inferioară a mașinii când este pornită
palanul la mecanic. Sunt niște chestii urâte dedesubt, plus noroi și crud și
utilizatorii îl văd rar. Un mesaj de eroare bun trebuie să fie informativ, chiar și pentru un utilizator care
a fost destul de norocos să nu trebuiască să se uite foarte des la partea inferioară și, de asemenea
informativ pentru mecanicul care asculta descrierea utilizatorului la telefon. Aceasta este
nici o sarcină ușoară.

Revizuind primul nostru exemplu, codul ar dori asta dacă folosește libexplain:
int fd = explica_deschis_sau_die("ceva/ceva", O_RDONLY, 0);
va eșua cu un mesaj de eroare ca acesta
deschide (nume cale = „unele/fișier”, steaguri = O_RDONLY) a eșuat, Nu există un astfel de fișier sau director
(2, ENOENT) deoarece nu există un director „unele” în directorul curent
Aceasta se descompune în trei bucăți
apel de sistem a eșuat, eroare de sistem deoarece
explicație

Inainte de pentru că
Este posibil să vedeți partea din mesaj înainte de „pentru că” ca fiind prea tehnică pentru non‐
utilizatorii tehnici, mai ales ca urmare a tipăririi cu precizie a apelului de sistem în sine la
începutul mesajului de eroare. Și se pare că strace(1) ieșire, pentru bonus geek
puncte.
deschide (nume cale = „unele/fișier”, steaguri = O_RDONLY) a eșuat, Nu există un astfel de fișier sau director
(2, ENOENT)
Această parte a mesajului de eroare este esențială pentru dezvoltator atunci când scrie codul,
și la fel de important pentru întreținătorul care trebuie să citească rapoartele de erori și să repare erorile în
cod. Spune exact ce a eșuat.

Dacă acest text nu este prezentat utilizatorului, atunci utilizatorul nu îl poate copia și lipi într-un
raport de eroare, iar dacă nu este în raportul de eroare, întreținătorul nu poate ști ce sa întâmplat de fapt
gresit.

Personalul tehnic va folosi frecvent strace(1) sau grindă cu zăbrele(1) pentru a obține aceste informații exacte, dar
această cale nu este deschisă când citiți rapoartele de erori. Sistemul reporterului de erori este departe
departe și, până acum, într-o stare mult diferită. Astfel, aceste informații trebuie să fie în
raport de eroare, ceea ce înseamnă că trebuie să fie în mesajul de eroare.

Reprezentarea apelului de sistem oferă, de asemenea, context restului mesajului. Dacă este nevoie
apare, argumentul de apel de sistem ofensator poate fi menționat prin nume în explicație
după „pentru că”. În plus, toate șirurile sunt complet între ghilimele și șirurile C scapă, deci
Liniile noi încorporate și caracterele care nu se imprimă nu vor cauza oprirea terminalului utilizatorului
fire de fân.

eroare de sistem este ceea ce iese din strerror(2), plus simbolul de eroare. Nerăbdător și
Administratorii de sistem experți ar putea opri citirea în acest moment, dar experiența autorului până în prezent este
că lectura în continuare este plină de satisfacții. (Dacă nu este plină de satisfacții, probabil că este o zonă de
libexplain care poate fi îmbunătățit. Contribuțiile la cod sunt binevenite, desigur.)

După pentru că
Aceasta este partea din mesajul de eroare destinată utilizatorilor non-tehnici. Se uită dincolo
argumentele de apel de sistem simplu și caută ceva mai specific.
nu există nici un director „unele” în directorul curent
Această porțiune încearcă să explice cauza proximală a erorii într-un limbaj simplu și aceasta
este aici că internaționalizarea este esențială.

În general, politica este de a include cât mai multe informații posibil, astfel încât utilizatorul
nu trebuie să-l caute (și nu o lasă în afara raportului de eroare).

Internaționalizare
Majoritatea mesajelor de eroare din biblioteca libexplain au fost internaționalizate. Acolo
încă nu există localizări, așa că dacă doriți explicații în limba dvs. maternă,
vă rog să contribuiți.

Calificativul „cele mai multe”, de mai sus, se referă la faptul că dovada-de-concept
implementarea nu a inclus sprijin pentru internaționalizare. Baza codului este
revizuit progresiv, de obicei ca urmare a refactorizării mesajelor astfel încât fiecare eroare
șirul de mesaj apare în cod exact o dată.

S-au făcut prevederi pentru limbile care trebuie să asambleze porțiunile de
apel de sistem a eșuat, eroare de sistem deoarece explicație
în ordine diferite pentru gramatica corectă în mesajele de eroare localizate.

Post-mortem
Există momente în care un program încă nu folosește libexplain și nu poți folosi strace(1)
fie. Este o explica(1) comandă inclusă în libexplain care poate fi folosită pentru
descifrați mesajele de eroare, dacă starea sistemului de bază nu s-a schimbat prea mult.
$ explica redenumi foo /tmp/bar/baz -e ENOENT
rename(oldpath = "foo", newpath = "/tmp/bar/baz") a eșuat, nu există un astfel de fișier sau director
(2, ENOENT) deoarece nu există un director „bar” în noua cale „/ tmp"directorul
$
Observați cum este rezolvată ambiguitatea căii utilizând numele argumentului apelului de sistem. De
desigur, trebuie să cunoașteți eroarea și apelul de sistem explica(1) a fi util. Ca un
deoparte, aceasta este una dintre modalitățile folosite de suita de testare automată libexplain pentru a verifica asta
libexplain funcționează.

Filozofie
„Spune-mi totul, inclusiv lucruri pe care nu știam să le caut.”

Biblioteca este implementată în așa fel încât atunci când este legată static, doar codul dvs
utilizarea efectivă va fi legată. Acest lucru se realizează având o funcție pentru fiecare fișier sursă,
ori de câte ori este fezabil.

Când este posibil să furnizați mai multe informații, libexplain va face acest lucru. Cu cât utilizatorul este mai puțin
trebuie să urmărească singuri, cu atât mai bine. Aceasta înseamnă că UID-urile sunt însoțite de
numele de utilizator, GID-urile sunt însoțite de numele grupului, PID-urile sunt însoțite de proces
numele, descriptorii de fișiere și fluxurile sunt însoțite de calea, etc.

La rezolvarea căilor, dacă o componentă a căii nu există, libexplain va căuta similare
nume, pentru a sugera alternative pentru greșelile de tipar.

Biblioteca libexplain încearcă să folosească cât mai puțin heap posibil și, de obicei, niciunul. Aceasta este
pentru a evita perturbarea stării procesului, pe cât posibil, deși uneori este
inevitabil.

Biblioteca libexplain încearcă să fie sigură pentru fire, evitând variabilele globale, păstrând
state pe stivă cât mai mult posibil. Există un singur buffer de mesaje comun și
funcțiile care îl folosesc sunt documentate ca nefiind sigure pentru fire.

Biblioteca libexplain nu deranjează gestionatorii de semnal ai unui proces. Asta face
determinând dacă un pointer ar defecta o provocare, dar nu imposibil.

Când informațiile sunt disponibile printr-un apel de sistem, precum și prin intermediul unui / proc
intrare, apelul de sistem este preferat. Acest lucru este pentru a evita perturbarea stării procesului.
Există, de asemenea, momente când nu sunt disponibili descriptori de fișiere.

Biblioteca libexplain este compilată cu suport pentru fișiere mari. Nu există mare/mic
schizofrenie. Acolo unde acest lucru afectează tipurile de argument din API, va fi emisă o eroare
dacă definițiile de fișiere mari necesare sunt absente.

FIXME: Este nevoie de muncă pentru a vă asigura că cotele sistemului de fișiere sunt gestionate în cod. Acest
se aplică unora getrlimit(2) limite, de asemenea.

Există cazuri când căile rudelor nu sunt informative. De exemplu: demoni de sistem,
servere și procese de fundal. În aceste cazuri, căile absolute sunt utilizate în eroare
explicații.

PATH REZOLUȚIE


Versiune scurtă: vezi rezoluție_cale(7).

Versiune lungă: majoritatea utilizatorilor nu au auzit niciodată de rezoluție_cale(7) și mulți utilizatori avansați
nu l-am citit niciodată. Iată o versiune adnotată:

Pas 1: acasă of il rezoluţie proces
Dacă calea începe cu caracterul slash ("/"), directorul de căutare de pornire este
directorul rădăcină al procesului de apelare.

Dacă calea nu începe cu caracterul slash ("/"), căutarea de pornire
directorul procesului de rezoluție este directorul de lucru curent al procesului.

Pas 2: Mers pe jos de-a lungul il cale
Setați directorul de căutare curent în directorul de căutare de pornire. Acum, pentru fiecare non-
componenta finală a căii, unde o componentă este un subșir delimitat de bară oblică (“/”)
caractere, această componentă este căutată în directorul de căutare curent.

Dacă procesul nu are permisiunea de căutare în directorul de căutare curent, un EACCES
este returnată eroarea ("Permisiunea refuzată").
open(pathname = "/home/archives/.ssh/private_key", flags = O_RDONLY) a eșuat,
Permisiune refuzată (13, EACCES) deoarece procesul nu are permisiunea de căutare
către directorul calea „/home/archives/.ssh”, procesul efectiv GID 1000
„pmiller” nu se potrivește cu proprietarul directorului 1001 „arhive”, deci proprietarul
modul de permisiune „rwx” este ignorat, celălalt mod de permisiune este „---”, iar modul
procesul nu este privilegiat (nu are capacitatea DAC_READ_SEARCH)

Dacă componenta nu este găsită, este returnată o eroare ENOENT ("Nu există un astfel de fișier sau director").
unlink(pathname = "/home/microsoft/rubsh") a eșuat, Nu există un astfel de fișier sau director (2,
ENOENT) deoarece nu există un director „microsoft” în calea „/ Home"directorul

Există, de asemenea, un anumit suport pentru utilizatori atunci când introduc greșit numele de căi, făcând sugestii când
ENOENT este returnat:
open(pathname = "/user/include/fcntl.h", flags = O_RDONLY) a eșuat, Nu există un astfel de fișier sau
directorul (2, ENOENT) deoarece nu există niciun director „utilizator” în calea „/”
director, ai vrut să spui în schimb directorul „usr”?

Dacă componenta este găsită, dar nu este nici un director, nici o legătură simbolică, un ENOTDIR
este returnată eroarea ("Nu este un director").
open(pathname = "/home/pmiller/.netrc/lca", flags = O_RDONLY) a eșuat, nu
directorul (20, ENOTDIR) deoarece fișierul obișnuit „.netrc” din calea
Directorul „/home/pmiller” este folosit ca director atunci când nu este

Dacă componenta este găsită și este un director, setăm directorul de căutare curent la acesta
director și mergeți la următoarea componentă.

Dacă componenta este găsită și este o legătură simbolică (symlink), mai întâi rezolvăm acest simbol
link (cu directorul de căutare curent ca director de căutare de pornire). La eroare, asta
eroare este returnată. Dacă rezultatul nu este un director, este returnată o eroare ENOTDIR.
unlink(pathname = "/tmp/dangling/rubsh") a eșuat, Nu există un astfel de fișier sau director (2,
ENOENT) deoarece legătura simbolică „atârnând” din calea „/ tmp"directorul
se referă la „nicăieri” care nu există
Dacă rezoluția legăturii simbolice are succes și returnează un director, setăm curentul
Căutați directorul în acel director și mergeți la următoarea componentă. Rețineți că
procesul de rezoluție aici implică recursivitate. Pentru a proteja nucleul împotriva stivei
depășire și, de asemenea, pentru a proteja împotriva refuzului serviciului, există limite ale maximului
adâncimea recursiunii și asupra numărului maxim de legături simbolice urmate. O eroare ELOOP este
returnat atunci când maximul este depășit ("Prea multe niveluri de legături simbolice").
open(pathname = "/tmp/dangling", flags = O_RDONLY) a eșuat, Prea multe niveluri de
legături simbolice (40, ELOOP) deoarece a fost întâlnită o buclă de legătură simbolică în
cale, începând cu „/tmp/dangling”
De asemenea, este posibil să obțineți o eroare ELOOP sau EMLINK dacă există prea multe legături simbolice, dar nu
bucla a fost detectată.
open(pathname = "/tmp/rabbit-hole", flags = O_RDONLY) a eșuat, Prea multe niveluri de
legături simbolice (40, ELOOP) deoarece au fost întâlnite prea multe legături simbolice în
nume cale (8)
Observați cum este imprimată și limita reală.

Pas 3: Găsi il final intrare
Căutarea componentei finale a numelui căii merge exact ca cea a tuturor celorlalte
componente, așa cum este descris în pasul anterior, cu două diferențe:

(i) Componenta finală nu trebuie să fie un director (cel puțin în ceea ce privește rezoluția căii
proces este în cauză. Poate că trebuie să fie un director sau un non-director, din cauza
cerinţele apelului de sistem specific).

(Ii)
Nu este neapărat o eroare dacă componenta finală nu este găsită; poate suntem doar
creând-o. Detaliile privind tratarea intrării finale sunt descrise în
paginile manuale ale apelurilor de sistem specifice.

(Iii)
De asemenea, este posibil să aveți o problemă cu ultima componentă dacă este o legătură simbolică
si nu trebuie urmat. De exemplu, folosind deschide(2) steag O_NOFOLLOW:
open(pathname = "a‐symlink", flags = O_RDONLY | O_NOFOLLOW) a eșuat, Prea multe niveluri de
legături simbolice (ELOOP) deoarece a fost specificat O_NOFOLLOW, dar numele căii se referă la a
simbolic

(Iv)
Este obișnuit ca utilizatorii să facă greșeli atunci când tastează căi. Biblioteca libexplain
încearcă să facă sugestii când ENOENT este returnat, de exemplu:
open(pathname = "/usr/include/filecontrl.h", flags = O_RDONLY) a eșuat, Nu există un astfel de fișier sau
directorul (2, ENOENT) deoarece nu există niciun fișier obișnuit „filecontrl.h” în calea
"/ usr / include", ai vrut să spui în schimb fișierul obișnuit "fcntl.h"?

(v) Este, de asemenea, posibil ca componenta finală să fie necesară să fie altceva decât a
fișier obișnuit:
readlink(nume cale = „doar un fișier”, date = 0x7F930A50, dimensiunea_date = 4097) a eșuat,
Argument nevalid (22, EINVAL) deoarece calea este un fișier obișnuit, nu o legătură simbolică

(Vi)
FIXME: manipularea bitului „t”.

limite
Există o serie de limite în ceea ce privește căile și numele fișierelor.

Limită de lungime a căii
Există o lungime maximă pentru numele căilor. Dacă numele căii (sau unele intermediare
calea obținută în timpul rezolvării legăturilor simbolice) este prea lung, un ENAMETOOLONG
este returnată eroarea („Numele fișierului este prea lung”). Observați cum este inclusă limita de sistem
în mesajul de eroare.
deschide(nume cale = "foarte lung", flags = O_RDONLY) a eșuat, Numele fișierului este prea lung (36,
ENAMETOOLONG) deoarece numele căii depășește lungimea maximă a căii de sistem (4096)

Limită de lungime a numelui fișierului
Unele variante Unix au o limită a numărului de octeți din fiecare componentă a căii.
Unii dintre ei se ocupă de asta în tăcere, iar alții dau ENAMETOOLONG; libexplain
utilizări ale bibliotecii pathconf(3) _PC_NO_TRUNC pentru a spune care. Dacă se întâmplă această eroare,
biblioteca libexplain va indica limita în mesajul de eroare, limita este
obtinut de la pathconf(3) _PC_NAME_MAX. Observați cum este inclusă limita de sistem
în mesajul de eroare.
deschide(nume cale = "system7/numai-avea-14-caractere", flags = O_RDONLY) a eșuat, fișier
nume prea lung (36, ENAMETOOLONG) deoarece componenta „numai-avea-14-caractere” este
mai mare decât limita sistemului (14)

Numele de cale gol
În Unix original, calea goală se referea la directorul curent.
În prezent, POSIX decretează că un nume de cale gol nu trebuie rezolvat cu succes.
open(pathname = "", flags = O_RDONLY) a eșuat, Nu există un astfel de fișier sau director (2,
ENOENT) deoarece POSIX decretează că o cale goală nu trebuie rezolvată
cu succes

Permisiuni
Biții de permisiune ai unui fișier constau din trei grupuri de trei biți. Primul grup de
trei este utilizat atunci când ID-ul de utilizator efectiv al procesului de apelare este egal cu ID-ul proprietarului
fişier. Al doilea grup de trei este folosit atunci când ID-ul de grup al fișierului fie este egal cu
ID-ul de grup efectiv al procesului apelant sau este unul dintre ID-urile de grup suplimentare ale
proces de apelare. Când niciunul nu este valabil, se folosește al treilea grup.
deschide(nume cale = "/ Etc / passwd", flags = O_WRONLY) a eșuat, Permisiune refuzată (13,
EACCES) deoarece procesul nu are permisiunea de scriere la „passwd” obișnuit
fișier în calea "/ Etc" directorul, procesul efectiv UID 1000 "pmiller"
nu se potrivește cu proprietarul obișnuit al fișierului 0 „rădăcină”, deci modul de permisiune a proprietarului „rw-”
este ignorat, celălalt mod de permisiune este „r--”, iar procesul nu este privilegiat
(nu are capacitatea DAC_OVERRIDE)
Se acordă un spațiu considerabil acestei explicații, deoarece majoritatea utilizatorilor nu știu asta
este modul în care funcționează sistemul de permisiuni. În special: proprietar, grup și altele
permisiunile sunt exclusive, nu sunt „SAU” combinate.

CIUDAT AND INTERESANT SISTEM APELĂRI


Procesul de scriere a unui anumit handler de erori pentru fiecare apel de sistem dezvăluie adesea
ciudatelor interesante și condițiilor limită, sau obscure greseala(3) valori.

ENOMEDIU, Nu mediu găsit
Actul de a copia un CD a fost sursa titlului acestei lucrări.
$ dd if=/dev/cdrom of=fubar.iso
dd: deschiderea „/dev/cdrom”: Nu a fost găsit niciun mediu
$
Autorul s-a întrebat de ce computerul lui îi spunea că nu există un psihic
mediu. În afară de faptul că un număr mare de vorbitori nativi de engleză nu sunt
chiar și conștient de faptul că „media” este un plural, darămite că „mediu” este singularul său, șirul
returnat de strerror(3) pentru ENOMEDIUM este atât de concis încât să fie aproape complet lipsit de
conținut.

Cand deschide(2) returnează ENOMEDIUM ar fi bine dacă biblioteca libexplain ar putea extinde a
puțin despre asta, în funcție de tipul de unitate. De exemplu:
... pentru că nu există disc în unitatea de dischetă
... deoarece nu există niciun disc în unitatea CD-ROM
... pentru că nu există bandă în unitatea de bandă
... pentru că nu există un stick de memorie în cititorul de carduri

Și așa s-a întâmplat...
open(pathname = "/dev/cdrom", flags = O_RDONLY) a eșuat, nu a fost găsit niciun mediu (123,
ENOMEDIUM) deoarece nu pare să existe un disc în unitatea CD-ROM
Trucul, de care autorul nu știa anterior, a fost să deschidă dispozitivul folosind
Steagul O_NONBLOCK, care vă va permite să deschideți o unitate fără mediu în ea. Tu atunci
emite dispozitiv specific ioctls(2) solicitări până îți dai seama ce naiba este. (Nu
sigur dacă acesta este POSIX, dar pare să funcționeze așa și în BSD și Solaris, conform
il wodim(1) surse.)

Rețineți, de asemenea, utilizările diferite ale „disc” și „disc” în context. A apărut standardul CD
în Franța, dar orice altceva are un „k”.

EFAULT, Rău adresa
Orice apel de sistem care preia un argument pointer poate returna EFAULT. Biblioteca libexplain
poate da seama care argument este de vină și o face fără a perturba procesul
(sau fir) manipularea semnalului.

Când este disponibil, mincore(2) este folosit apelul de sistem pentru a întreba dacă regiunea de memorie este validă.
Poate returna trei rezultate: mapat, dar nu în memoria fizică, mapat și în fizic
memorie, și nu mapate. Când se testează validitatea unui indicator, primele două sunt „da”
iar ultimul este „nu”.

Verificarea șirurilor C este mai dificilă, deoarece în loc de un indicator și o dimensiune, doar noi
au un indicator. Pentru a determina dimensiunea, ar trebui să găsim NUL și asta ar putea
segfault, catch-22.

Pentru a rezolva acest lucru, biblioteca libexplain folosește lstat(2) apel de sistem (cu un cunoscut
al doilea argument bun) pentru a testa șirurile C pentru validitate. Un eșec return && errno == EFAULT
este un „nu”, iar orice altceva este un „da”. Acest lucru, desigur, limitează șirurile la PATH_MAX
caractere, dar asta de obicei nu este o problemă pentru biblioteca libexplain, pentru că așa este
aproape întotdeauna cele mai lungi șiruri la care îi pasă.

EMFILE, De asemenea multe deschide fișiere
Această eroare apare atunci când un proces are deja numărul maxim de descriptori de fișier deschis.
Dacă limita reală urmează să fie tipărită și biblioteca libexplain încearcă, nu puteți deschide
un dosar in / proc sa citesc ce este.
open_max = sysconf(_SC_OPEN_MAX);
Acesta nu e atât de dificil, există o sysconf(3) modalitatea de obținere a limitei.

ENFILE, De asemenea multe deschide fișiere in sistem
Această eroare apare atunci când limita de sistem a numărului total de fișiere deschise a fost
atins. În acest caz, nu este la îndemână sysconf(3) modalitatea de obținere a limitei.

Săpând mai adânc, se poate descoperi că pe Linux există un / proc intrare la care am putea citi
obține această valoare. Catch‐22: nu avem descriptori de fișiere, așa că nu putem deschide un fișier pentru
citeste limita.

Pe Linux există un apel de sistem pentru a-l obține, dar nu are funcție [e]glibc wrapper, deci
trebuie să le faci cu mare atenție:
lung
explic_maxfile(void)
{
#ifdef __linux__
struct __sysctl_args args;
int32_t maxfile;
size_t maxfile_size = mărimea(maxfile);
int nume[] = { CTL_FS, FS_MAXFILE };
memset(&args, 0, sizeof(struct __sysctl_args));
args.name = nume;
args.nlen = 2;
args.oldval = &maxfile;
args.oldlenp = &maxfile_size;
dacă (syscall(SYS__sysctl, &args) >= 0)
return maxfile;
#endif
retur -1;
}
Acest lucru permite ca limita să fie inclusă în mesajul de eroare, atunci când este disponibilă.

EINVAL "Invalid argument" vs ENOSYS "Funcţie nu implementat”
Acțiuni neacceptate (cum ar fi link simbolic(2) pe un sistem de fișiere FAT) nu sunt raportate
constant de la un apel de sistem la altul. Este posibil să aveți fie EINVAL, fie
ENOSYS s-a întors.

În consecință, trebuie acordată atenție acestor cazuri de eroare pentru a le corecta, în special
deoarece EINVAL s-ar putea referi și la probleme cu unul sau mai multe argumente de apel de sistem.

notițe acea greseala(3) is nu mereu set
Există momente când este necesar să citiți sursele [e]glibc pentru a determina cum și
când sunt returnate erori pentru unele apeluri de sistem.

feof(3), număr fișier(3)
Se presupune adesea că aceste funcții nu pot returna o eroare. Acest lucru este adevărat numai dacă
il curent argumentul este valid, totuși ei sunt capabili să detecteze un invalid
indicator.

fpathconf(3), pathconf(3)
Valoarea de returnare a fpathconf(2) și pathconf(2) ar putea fi în mod legitim -1, deci este
necesar pentru a vedea dacă greseala(3) a fost stabilit în mod explicit.

ioctls(2)
Valoarea de returnare a ioctls(2) ar putea fi în mod legitim -1, deci este necesar să vedem dacă
greseala(3) a fost stabilit în mod explicit.

readdir(3)
Valoarea de returnare a readdir(3) este NULL atât pentru erori, cât și pentru sfârșitul fișierului. Este
necesar pentru a vedea dacă greseala(3) a fost stabilit în mod explicit.

setbuf(3), setbuffer(3), setlinebuf(3), setvbuf(3)
Toate aceste funcții, cu excepția ultimei, revin nule. Și setvbuf(3) este documentat doar ca
returnând „non-zero” la eroare. Este necesar să vedem dacă greseala(3) a fost explicit
set.

strtod(3), strtol(3), strtold(3), strtoll(3), strtoul(3), strtoull(3)
Aceste funcții returnează 0 în caz de eroare, dar aceasta este și o valoare returnată legitimă. Este
necesar pentru a vedea dacă greseala(3) a fost stabilit în mod explicit.

ungetc(3)
Deși doar un singur caracter de backup este impus de standardul ANSI C, acesta se transformă
că [e]glibc permite mai mult... dar asta înseamnă că poate eșua cu ENOMEM. Se poate
eșuează și cu EBDF dacă fp este fals. Cel mai dificil dintre toate, dacă treceți EOF o eroare
apare returnarea, dar errno nu este setat.

Biblioteca libexplain detectează corect toate aceste erori, chiar și în cazurile în care
valorile de eroare sunt prost documentate, dacă nu sunt deloc.

ENOSPC, Nu spaţiu stânga on dispozitiv
Când această eroare se referă la un fișier dintr-un sistem de fișiere, biblioteca libexplain tipărește montarea
punct al sistemului de fișiere cu problema. Acest lucru poate face sursa erorii mult
mai clar.
write(fildes = 1 "example", data = 0xbfff2340, data_size = 5) a eșuat, nu a mai rămas spațiu
pe dispozitiv (28, ENOSPC) deoarece sistemul de fișiere care conține fișiere ("/ Home") nu are nici o
mai mult spațiu pentru date
Pe măsură ce se adaugă mai mult suport special pentru dispozitive, este de așteptat ca mesajele de eroare să includă dispozitivul
numele și dimensiunea reală a dispozitivului.

EROFS, Numai citire fişier sistem
Când această eroare se referă la un fișier dintr-un sistem de fișiere, biblioteca libexplain tipărește montarea
punct al sistemului de fișiere cu problema. Acest lucru poate face sursa erorii mult
mai clar.

Pe măsură ce se adaugă mai mult suport special pentru dispozitive, este de așteptat ca mesajele de eroare să includă dispozitivul
nume și tip.
open(pathname = "/dev/fd0", O_RDWR, 0666) a eșuat, sistem de fișiere numai pentru citire (30, EROFS)
deoarece discheta are setată fila de protecție la scriere

... pentru că un CD-ROM nu poate fi scris
...deoarece cardul de memorie are setată clapeta de protecție la scriere
... pentru că banda magnetică de ½ inch nu are inel de scriere

redenumi
redenumi(2) apelul de sistem este folosit pentru a schimba locația sau numele unui fișier, mutându-l
între directoare, dacă este necesar. Dacă calea destinației există deja, va fi
înlocuit atomic, astfel încât să nu existe niciun moment în care un alt proces să încerce
accesul la el îl va găsi lipsă.

Există însă limitări: puteți redenumi doar un director peste altul
director dacă directorul de destinație nu este gol.
rename(oldpath = "foo", newpath = "bar") a eșuat, directorul nu este gol (39,
ENOTEMPTY) deoarece newpath nu este un director gol; adică conține intrări
în afară de "." și ".."
Nici nu puteți redenumi un director deasupra unui non-director.
rename(oldpath = "foo", newpath = "bar") a eșuat, nu este un director (20, ENOTDIR)
deoarece oldpath este un director, dar newpath este un fișier obișnuit, nu un director
Nici inversul nu este permis
rename(oldpath = "foo", newpath = "bar") a eșuat, Este un director (21, EISDIR)
deoarece newpath este un director, dar oldpath este un fișier obișnuit, nu un director

Acest lucru, desigur, face munca bibliotecii libexplain mai complicată, deoarece
deconectez(2) sau rmdir(2) apelul de sistem este apelat implicit de redenumi(2), și astfel toate
deconectez(2) sau rmdir(2) erorile trebuie de asemenea detectate și tratate.

dup2
dup2(2) apelul de sistem este utilizat pentru a crea un al doilea descriptor de fișier care face referire la
același obiect ca primul descriptor de fișier. De obicei, aceasta este folosită pentru a implementa intrarea în shell
și redirecționarea ieșirii.

Lucrul distractiv este că, la fel ca redenumi(2) poate redenumi atomic un fișier deasupra unui
fișierul existent și eliminați fișierul vechi, dup2(2) poate face acest lucru pe un fișier deja deschis
descriptor.

Încă o dată, acest lucru face munca bibliotecii libexplain mai complicată, deoarece închide(2)
apelul de sistem este apelat implicit de dup2(2), și așa toate închide(2) erorile trebuie să fie
detectat și manipulat, de asemenea.

AVENTURI IN IOCTL SUPORT


ioctls(2) Apelul de sistem oferă autorilor driverelor de dispozitiv o modalitate de a comunica cu
spațiu de utilizator care nu se încadrează în API-ul kernel-ului existent. Vedea ioctl_list(2).

Decodare Cerere Numere
Dintr-o privire superficială asupra ioctls(2) interfață, ar părea să existe o interfață mare, dar finită
număr posibil ioctls(2) cereri. Fiecare diferit ioctls(2) cererea este efectivă
un alt apel de sistem, dar fără nicio siguranță de tip - compilatorul nu poate ajuta a
programatorul le face bine. Aceasta a fost probabil motivația din spate tcflush(3) și
prieteni.

Impresia inițială este că ai putea decoda ioctls(2) solicitări folosind un comutator imens
afirmație. Acest lucru se dovedește a fi imposibil pentru că cineva descoperă foarte repede că este
imposibil de a include toate anteturile de sistem necesare care definesc diferitele ioctls(2)
solicitări, pentru că le este greu să se joace frumos între ei.

O privire mai profundă dezvăluie că există o serie de numere de solicitare „private” și dispozitiv
autorii șoferilor sunt încurajați să le folosească. Aceasta înseamnă că există un posibil mult mai mare
set de solicitări, cu numere de cereri ambigue, decât sunt imediat evidente. De asemenea,
există și unele ambiguități istorice.

Știam deja că comutatorul nu era practic, dar acum știm că pentru a selecta
numele cererii corespunzătoare și explicația trebuie să luăm în considerare nu numai numărul cererii ci
de asemenea, descriptorul de fișier.

Implementarea ioctls(2) suportul din biblioteca libexplain este de a avea un tabel de
indicii către ioctls(2) descriptori de cerere. Fiecare dintre acești descriptori include un opțional
pointer către o funcție de dezambiguizare.

Fiecare cerere este de fapt implementată într-un fișier sursă separat, astfel încât să fie necesar
include fișierele sunt scutite de obligația de a se juca frumos cu ceilalți.

Reprezentare
Filosofia din spatele bibliotecii libexplain este de a oferi cât mai multe informații
posibil, inclusiv o reprezentare exactă a apelului de sistem. În cazul în care
ioctls(2) aceasta înseamnă tipărirea numărului corect al cererii (după nume) și, de asemenea, a unui număr corect (sau
cel puţin utilă) reprezentare a celui de-al treilea argument.

ioctls(2) prototipul arată astfel:
int ioctl(int fildes, int cerere, ...);
care ar trebui să declanșeze alarmele de siguranță de tip. Intern în [e]glibc, acesta este transformat
într-o varietate de forme:
int __ioctl(int fildes, int cerere, long arg);
int __ioctl(int fildes, int cerere, void *arg);
iar interfața syscall a nucleului Linux se așteaptă
asmlinkage long sys_ioctl(unsigned int fildes, unsigned int cerere, unsigned long
arg);
Variabilitatea extremă a celui de-al treilea argument este o provocare, atunci când biblioteca libexplain
încearcă să imprime o reprezentare a celui de-al treilea argument. Cu toate acestea, odată cu numărul cererii
a fost dezambiguat, fiecare intrare din tabelul ioctl al bibliotecii libexplain are un
funcția personalizată print_data (OO făcut manual).

explicaţii
Există mai puține probleme la determinarea explicației care trebuie utilizată. Odată cu numărul cererii
a fost dezambiguat, fiecare intrare din tabelul ioctl al bibliotecii libexplain are un personalizat
funcția print_explanation (din nou, OO făcut manual).

Spre deosebire de apelurile de sistem din secțiunea 2 și secțiunea 3, majoritatea ioctls(2) cererile nu au erori
documentat. Aceasta înseamnă că, pentru a oferi descrieri bune de eroare, este necesar să citiți nucleul
surse de descoperit

· ce greseala(3) valorile pot fi returnate și

· cauza fiecărei erori.

Din cauza naturii OO a trimiterii apelurilor de funcție în nucleu, trebuie să citiți
toate surse care implementează asta ioctls(2) cerere, nu doar implementarea generică. Aceasta
este de așteptat ca nuclee diferite să aibă numere de eroare diferite și subtil
diferite cauze de eroare.

EINVAL vs ENOTTY
Situația este și mai rea pentru ioctls(2) cereri decât pentru apeluri de sistem, cu EINVAL și
ENOTTY ambele fiind folosite pentru a indica faptul că an ioctls(2) cererea este inadecvată prin aceea că
context și, ocazional, ENOSYS, ENOTSUP și EOPNOTSUPP (destinate a fi utilizate pentru prize) ca
bine. Există comentarii în sursele nucleului Linux care par să indice un progres
curățarea este în curs. Pentru un haos suplimentar, BSD adaugă ENOIOCTL la confuzie.

În consecință, trebuie acordată atenție acestor cazuri de eroare pentru a le corecta, în special
deoarece EINVAL s-ar putea referi și la probleme cu unul sau mai multe argumente de apel de sistem.

intptr_t
Standardul C99 definește un tip întreg care este garantat să poată ține orice pointer
fără pierdere de reprezentare.

Prototipul de mai sus a funcției syscall ar fi mai bine scris
long sys_ioctl(unsigned int fildes, unsigned int request, intptr_t arg);
Problema este disonanța cognitivă indusă de dispozitive specifice sau specifice sistemului de fișiere
ioctls(2) implementări, cum ar fi:
long vfs_ioctl(struct file *filp, unsigned int cmd, unsigned long arg);
Majoritatea ioctls(2) cererile au de fapt un int *arg al treilea argument. Dar având-o
declarat lung conduce la codul tratând acest lucru ca lung *arg. Acest lucru este inofensiv pe 32 de biți
(sizeof(long) == sizeof(int)) dar neplăcut pe 64 de biți (sizeof(long) != sizeof(int)).
În funcție de endian, obții sau nu valoarea pe care o aștepți, dar tu mereu obține
o mâzgălire de memorie sau de stivă, de asemenea.

Scriind toate acestea ca
int ioctl(int fildes, int cerere, ...);
int __ioctl(int fildes, int cerere, intptr_t arg);
long sys_ioctl(unsigned int fildes, unsigned int request, intptr_t arg);
long vfs_ioctl(struct file *filp, unsigned int cmd, intptr_t arg);
subliniază că întregul este doar un întreg pentru a reprezenta o cantitate care este aproape
întotdeauna un tip de indicator fără legătură.

CONCLUZIE


Folosește libexplain, utilizatorilor tăi le va plăcea.

DREPTURI DE AUTOR


libexplain versiunea 1.4
Drepturi de autor (C) 2008, 2009, 2010, 2011, 2012, 2013, 2014 Peter Miller

Utilizați online explic_lca2010 folosind serviciile onworks.net


Servere și stații de lucru gratuite

Descărcați aplicații Windows și Linux

  • 1
    ÎNGHIŢITURĂ
    ÎNGHIŢITURĂ
    SWIG este un instrument de dezvoltare software
    care conectează programele scrise în C și
    C++ cu o varietate de nivel înalt
    limbaje de programare. SWIG este folosit cu
    diferit...
    Descărcați SWIG
  • 2
    Tema WooCommerce Nextjs React
    Tema WooCommerce Nextjs React
    Tema React WooCommerce, construită cu
    Urmează JS, Webpack, Babel, Node și
    Express, folosind GraphQL și Apollo
    Client. Magazin WooCommerce în React(
    contine: Produse...
    Descărcați tema WooCommerce Nextjs React
  • 3
    archlabs_repo
    archlabs_repo
    Pachetul depozit pentru ArchLabs Acesta este un
    aplicație care poate fi, de asemenea, preluată
    din
    https://sourceforge.net/projects/archlabs-repo/.
    A fost găzduit în OnWorks în...
    Descărcați archlabs_repo
  • 4
    Proiectul Zephyr
    Proiectul Zephyr
    Proiectul Zephyr este o nouă generație
    sistem de operare în timp real (RTOS) care
    suportă mai multe hardware-uri
    arhitecturi. Se bazează pe a
    nucleu cu amprentă mică...
    Descărcați Zephyr Project
  • 5
    SCcons
    SCcons
    SCons este un instrument de construcție software
    aceasta este o alternativă superioară
    instrument clasic de construcție „Make” care
    cu toții cunoaștem și iubim. SCons este
    implementat un...
    Descărcați SCons
  • 6
    PSeInt
    PSeInt
    PSeInt este un interpret de pseudo-cod pentru
    studenți de programare vorbitori de spaniolă.
    Scopul său principal este de a fi un instrument pentru
    învăţarea şi înţelegerea elementelor de bază
    concept...
    Descărcați PSeInt
  • Mai mult »

Comenzi Linux

  • 1
    7z
    7z
    7z - Un arhivator de fișiere cu cea mai mare
    rata compresiei ...
    Rulați 7z
  • 2
    7za
    7za
    7za - Un arhivator de fișiere cu cea mai mare
    rata compresiei ...
    Run 7za
  • 3
    înfiorător
    înfiorător
    CREEPY - O informație de geolocalizare
    agregator DESCRIERE: înfiorător este un
    aplicație care vă permite să adunați
    informații legate de geolocalizare despre
    utilizatori din...
    Fugi înfiorător
  • 4
    cricket-compilare
    cricket-compilare
    cricket - Un program pentru gestionarea
    colectarea și afișarea seriilor temporale
    date ...
    Rulați cricket-compile
  • 5
    g-wrap-config
    g-wrap-config
    g-wrap-config - script pentru a obține
    informații despre versiunea instalată
    de G-Wrap...
    Rulați g-wrap-config
  • 6
    g.iarbă de acces
    g.iarbă de acces
    g.access - Controlează accesul la
    setul de hărți curent pentru alți utilizatori de pe
    sistem. Dacă nu este oferită nicio opțiune, se imprimă
    Statusul curent. CUVINTE CHEIE: general, hartă
    management, p...
    Rulați g.accessgrass
  • Mai mult »

Ad