EngelsFransSpaans

Ad


OnWorks-favicon

expand_lca2010 - Online in de cloud

Voer uitleg_lca2010 uit in de gratis hostingprovider van OnWorks via Ubuntu Online, Fedora Online, Windows online emulator of MAC OS online emulator

Dit is de opdracht expand_lca2010 die kan worden uitgevoerd in de gratis hostingprovider van OnWorks met behulp van een van onze meerdere gratis online werkstations zoals Ubuntu Online, Fedora Online, Windows online emulator of MAC OS online emulator

PROGRAMMA:

NAAM


Explore_lca2010 - Geen medium gevonden: wanneer het tijd is om te stoppen met lezen spanning(3) die van
geest.

MOTIVATIE


Het idee voor libexplain kwam begin jaren tachtig bij me op. Wanneer er een systeemoproep plaatsvindt
retourneert een fout, de kernel weet precies wat er mis is gegaan... en comprimeert dit in
minder dan 8 bits fout. Gebruikersruimte heeft toegang tot dezelfde gegevens als de kernel
Het zou voor de gebruikersruimte mogelijk moeten zijn om erachter te komen wat er precies is gebeurd waardoor de fout is veroorzaakt
return, en gebruik dit om goede foutmeldingen te schrijven.

Zou het zo simpel kunnen zijn?

Fout berichten as finesse
Goede foutmeldingen zijn vaak die ‘één procent’-taken die tijdens de planning worden geschrapt
druk drukt uw project. Een goede foutmelding kan echter een enorme,
onevenredige verbetering van de gebruikerservaring, wanneer de gebruiker in scarey terechtkomt
onbekend terrein dat je normaal gesproken niet tegenkomt. Dit is geen gemakkelijke taak.

Als larvale programmeur zag de auteur het probleem van (volledig nauwkeurige) fouten niet
berichten zoals deze:
zwevende uitzondering (core gedumpt)
totdat de alternatieve niet-programmeursinterpretatie werd opgemerkt. Maar dat is niet de
het enige wat er mis is met Unix-foutmeldingen. Hoe vaak zie je foutmeldingen zoals:
$ ./dom
kan bestand niet openen
$
Er zijn op dit moment twee opties voor een ontwikkelaar:

1.
U kunt een debugger uitvoeren, zoals gdb(1), of

2.
je kunt gebruiken spoor(1) of bundel(1) om naar binnen te kijken.

· Houd er rekening mee dat uw gebruikers mogelijk niet eens toegang hebben tot deze tools, laat staan ​​de mogelijkheid
om ze te gebruiken. (Het is heel lang geleden Unix beginner bedoelde “heeft alleen maar geschreven een
stuurprogramma".)

In dit voorbeeld wordt echter gebruik gemaakt van spoor(1) onthult
$ spoor -e spoor=open ./dom
open("some/file", O_RDONLY) = -1 ENOENT (Bestand of map bestaat niet)
kan bestand niet openen
$
Dit is aanzienlijk meer informatie dan de foutmelding biedt. Meestal is de
stomme broncode ziet er zo uit
int fd = open("iets", O_RDONLY);
als (fd <0)
{
fprintf(stderr, "kan bestand niet openen\n");
afrit(1);
}
De gebruiker wordt niet geïnformeerd welke bestand, en laat het de gebruiker ook niet weten welke fout. Was het bestand
zelfs daar? Was er een toestemmingsprobleem? Er staat wel dat het probeerde een
bestand, maar dat was waarschijnlijk per ongeluk.

Pak je aanwijzingsstok en versla ermee de larvale programmeur. Vertel hem erover fout(3).
De volgende keer dat u het programma gebruikt, ziet u een ander foutbericht:
$ ./dom
open: een dergelijk bestand of map bestaat niet
$
Vooruitgang, maar niet wat we verwacht hadden. Hoe kan de gebruiker het probleem oplossen als de foutmelding wordt weergegeven
vertelt hem niet wat het probleem was? Als we naar de bron kijken, zien we het
int fd = open("iets", O_RDONLY);
als (fd <0)
{
fout("open");
afrit(1);
}
Tijd voor nog een run met de aanwijzingsstok. Deze keer duurt het foutbericht één stap
vooruit en één stap terug:
$ ./dom
iets: Onbekend bestand of map
$
Nu weten we welk bestand het probeerde te openen, maar we worden er niet langer van op de hoogte gesteld dat dit het geval was open(2)
dat mislukte. In dit geval is het waarschijnlijk niet significant, maar het kan wel significant zijn voor
andere systeemoproepen. Het had kunnen zijn creat(2) in plaats daarvan een operatie die dat impliceert
Er zijn verschillende machtigingen nodig.
const char *bestandsnaam = "iets";
int fd = open(bestandsnaam, O_RDONLY);
als (fd <0)
{
fout(bestandsnaam);
afrit(1);
}
De bovenstaande voorbeeldcode is helaas ook typerend voor niet-larvale programmeurs. Tijd
om onze Padawan-leerling te vertellen over de spanning(3) systeemoproep.
$ ./dom
open iets: Onbekend bestand of map
$
Dit maximaliseert de informatie die aan de gebruiker kan worden gepresenteerd. De code ziet eruit als
deze:
const char *bestandsnaam = "iets";
int fd = open(bestandsnaam, O_RDONLY);
als (fd <0)
{
fprintf(stderr, "open %s: %s\n", bestandsnaam, strerror(errno));
afrit(1);
}
Nu hebben we de systeemaanroep, de bestandsnaam en de foutreeks. Hierin staan ​​alle
informatie die spoor(1) afgedrukt. Dat is zo goed als maar kan.

Of is het?

Beperkingen of fout en spanning
Het probleem dat de auteur in de jaren tachtig zag, was dat de foutmelding onvolledig was.
Verwijst “geen dergelijk bestand of map” naar de “sommige” map, of naar de “ding"bestand in
de "sommigemap?

Een snelle blik op de manpagina voor spanning(3) vertelt:
strerror - retourreeks die het foutnummer beschrijft
Let goed op: het beschrijft de fout aantal, niet de fout.

Aan de andere kant de kern weet wat de fout was. Er was een specifiek punt in de
kernelcode, veroorzaakt door een specifieke aandoening, waarbij de kernelcode vertakte en “nee” zei.
Zou een gebruikersruimteprogramma de specifieke toestand kunnen achterhalen en een betere fout kunnen schrijven?
bericht?

Het probleem gaat echter dieper. Wat als het probleem zich voordoet tijdens de dit artikel lezen(2) systeem
bellen, in plaats van de open(2) bellen? Het is eenvoudig voor de bijbehorende foutmelding
open(2) om de bestandsnaam op te nemen, deze staat daar. Maar om een ​​bestandsnaam te kunnen opnemen
in de fout die verband houdt met de dit artikel lezen(2) systeemoproep, u moet de bestandsnaam allemaal doorgeven
de weg naar beneden in de call-stack, evenals de bestandsdescriptor.

En hier is het vervelende: de kernel weet al welke bestandsnaam het bestand heeft
descriptor is geassocieerd met. Waarom zou een programmeur alle redundante gegevens moeten doorgeven?
de weg naar beneden in de call-stack alleen maar om een ​​foutmelding te verbeteren die mogelijk nooit wordt afgegeven? In
In werkelijkheid maken veel programmeurs zich daar niet druk over, en de daaruit voortvloeiende foutmeldingen zijn des te erger
het.

Maar dat waren de jaren tachtig, op een PDP1980, met beperkte middelen en geen gedeelde bibliotheken. Rug
dan was er geen Unix-smaak inbegrepen / proc zelfs in rudimentaire vorm, en de lsof(1) programma
was meer dan een decennium verwijderd. Het idee werd dus op de plank gelegd omdat het onpraktisch was.

Niveau Infinity Support
Stel je voor dat je oneindige ondersteuning hebt. In uw functieomschrijving staat dat u dat nooit doet
ooit moet met gebruikers praten. Waarom is er dan nog steeds een constante stroom van mensen die iets willen?
jij, de lokale Unix-goeroe, om nog een foutmelding te ontcijferen?

Vreemd genoeg werd 25 jaar later, ondanks een eenvoudig machtigingssysteem, compleet geïmplementeerd
consistentie hebben de meeste Unix-gebruikers nog steeds geen idee hoe ze “No such file or directory” moeten decoderen,
of een van de andere cryptische foutmeldingen die ze elke dag zien. Of, op zijn minst, cryptisch
Hen.

Zou het niet mooi zijn als de eerstelijns technische ondersteuning de foutmeldingen niet hoefde te ontcijferen?
Zou het niet fijn zijn om foutmeldingen te hebben die gebruikers kunnen begrijpen zonder te bellen?
technische ondersteuning?

Deze dagen / proc op Linux is meer dan in staat om de informatie te leveren die nodig is om te decoderen
de overgrote meerderheid van de foutmeldingen, en wijzen de gebruiker op de directe oorzaak ervan
probleem. Op systemen met een beperkt / proc uitvoering, de lsof(1) opdracht kan worden ingevuld
veel van de gaten.

In 2008 overkwam de stroom aan vertaalaanvragen de auteur veel te vaak. Het was
tijd om dat 25 jaar oude idee opnieuw te onderzoeken, en libexplain is het resultaat.

GEBRUIK MAKEND VAN HET BIBLIOTHEEK


De interface met de bibliotheek probeert waar mogelijk consistent te zijn. Laten we beginnen met een
voorbeeld met behulp van spanning(3):
if (hernoemen (oud_pad, nieuw_pad) < 0)
{
fprintf(stderr, "hernoem %s %s: %s\n", oud_pad, nieuw_pad,
strerror(errno));
afrit(1);
}
Het idee achter libexplain is om een spanning(3) gelijkwaardig voor elk systeemoproep,
specifiek afgestemd op die systeemoproep, zodat deze een meer gedetailleerde fout kan opleveren
bericht, dat veel van de informatie bevat die u ziet onder de kop 'FOUTEN' van de sectie
2 en 3 man pagina's, aangevuld met informatie over feitelijke omstandigheden, feitelijke argumentatie
waarden en systeemlimieten.

De Eenvoudig SITUATIE
De spanning(3) vervanging:
if (hernoemen (oud_pad, nieuw_pad) < 0)
{
fprintf(stderr, "%s\n", uitleg_hernoemen(oud_pad, nieuw_pad));
afrit(1);
}

De errno SITUATIE
Het is ook mogelijk om een ​​expliciete door te geven fout(3) waarde, als u eerst wat moet doen
verwerking die zou verstoren fout, zoals foutherstel:
if (hernoemen (oud_pad, nieuw_pad < 0))
{
int old_errno = errno;
...code dat verstoort fout...
fprintf(stderr, "%s\n", uitleg_errno_rename(oude_errno,
oud_pad, nieuw_pad));
afrit(1);
}

De Multi-thread Behuizingen
Sommige applicaties zijn multi-threaded en kunnen dus de interne libexplain-bestanden niet delen
buffer. U kunt uw eigen buffer aanleveren met behulp van
if (ontkoppelen(padnaam))
{
char-bericht [3000];
uitleg_bericht_unlink(bericht, De grootte van(bericht), padnaam);
foutdialoog(bericht);
retour -1;
}
En voor de volledigheid: beide fout(3) en draadveilig:
ssize_t nbytes = lezen(fd, data, sizeof(data));
als (nbytes <0)
{
char-bericht [3000];
int old_errno = errno;
...fout na een training...
uitleg_bericht_errno_read(bericht, De grootte van(bericht),
old_errno, fd, data, sizeof(data));
foutdialoog(bericht);
retour -1;
}

Dit zijn vervangingen voor strerror_r(3), op systemen die dit hebben.

Interface Suiker
Een reeks functies toegevoegd als gemaksfuncties, om programmeurs te overtuigen de
libexplain-bibliotheek, blijken de meest gebruikte libexplain-functies van de auteur te zijn
opdrachtregelprogramma's:
int fd = uitleg_creat_or_die(bestandsnaam, 0666);
Deze functie probeert een nieuw bestand te maken. Als dit niet lukt, wordt er een foutmelding afgedrukt en
wordt afgesloten met EXIT_FAILURE. Als er geen fout is, wordt de nieuwe bestandsdescriptor geretourneerd.

Een gerelateerde functie:
int fd = uitleg_creat_on_error(bestandsnaam, 0666);
drukt het foutbericht af bij een fout, maar retourneert ook het oorspronkelijke foutresultaat, en
fout(3) is ook ongemoeid.

Alles de anders system gesprekken
Over het algemeen heeft elke systeemaanroep zijn eigen include-bestand
#erbij betrekkennaam.h>
dat functieprototypes definieert voor zes functies:

· uitleggen_naam,

· leg_errno_ uitnaam,

· leg_bericht_ uitnaam,

· leg_bericht_errno_ uitnaam,

· uitleggen_naam_of_sterf en

· uitleggen_naam_op_fout.

Elk functieprototype heeft Doxygen-documentatie, en deze documentatie is niet gestript
wanneer de include-bestanden zijn geïnstalleerd.

De wachten(2) systeemoproepen (en vrienden) hebben een aantal extra varianten die ook fouten interpreteren
een afsluitstatus hebben die niet EXIT_SUCCESS is. Dit heeft betrekking op system(3) en sluit(3) als
goed.

De dekking omvat 221 systeemoproepen en 547 ioctl-verzoeken. Er zijn nog veel meer systemen
oproepen die nog moeten worden uitgevoerd. Systeemoproepen die nooit terugkeren, zoals afrit(2), zijn niet aanwezig
in de bibliotheek, en dat zal nooit zo zijn. De exec familie van systeemoproepen zijn ondersteund, omdat
ze komen terug als er een fout is.

Kat
Dit is hoe een hypothetisch ‘cat’-programma eruit zou kunnen zien, met volledige foutrapportage.
met behulp van libexplain.
#erbij betrekken
#inclusief
#erbij betrekken
Er is één toevoeging voor libexplain, plus de gebruikelijke verdachten. (Als u de
preprocessor belasting, kunt u de specificnaam.h> omvat.)
statische leegte
proces(BESTAND *fp)
{
voor (;;)
{
char-buffer[4096];
size_t n = uitleg_fread_or_die(buffer, 1, sizeof(buffer), fp);
als (!n)
te breken;
uitleg_fwrite_or_die(buffer, 1, n, stdout);
}
}
De functie kopieert een bestandsstroom naar de standaarduitvoer. Mocht er een fout optreden
voor zowel lezen als schrijven wordt het gerapporteerd (en de padnaam wordt opgenomen in de
error) en de opdracht wordt afgesloten met EXIT_FAILURE. We maken ons niet eens zorgen over het volgen van de
padnamen, of ze doorgeven aan de call-stack.
int
main(int argc, char **argv)
{
voor (;;)
{
int c = getopt(argc, argv, "o:");
als (c == EOF)
te breken;
schakelaar (c)
{
geval 'o':
uitleg_freopen_or_die(optarg, "w", stdout);
te breken;
Het leuke van deze code is dat libexplain fouten kan melden waaronder de padnaam zal u zelfs
als je niet open stdout expliciet opnieuw zoals hier wordt gedaan. Wij maken ons er niet eens zorgen over
het bijhouden van de bestandsnaam.
default:
fprintf(stderr, "Gebruik: %ss [ -o ] ...\N",
argv[0]);
retourneer EXIT_FAILURE;
}
}
als (optind == argc)
proces(stdin);
anders
{
terwijl (optind <argc)
{
BESTAND *fp = uitleg_fopen_or_die(argv[optind]++, "r");
proces(fp);
uitleg_fclose_or_die(fp);
}
}
De standaarduitvoer wordt impliciet gesloten, maar te laat voor een foutmelding
uitgegeven, dus dat doen we hier, voor het geval de gebufferde I/O nog niets heeft geschreven, en
er is een ENOSPC-fout of zoiets.
uitleg_flush_or_die(stdout);
retourneer EXIT_SUCCESS;
}
Dat is alles. Volledige foutrapportage, duidelijke code.

Rusty's Scale of Interface Goedheid
Voor degenen onder u die er niet bekend mee zijn: Rusty Russell's "Hoe maak ik dit moeilijk te misbruiken?"
pagina is een must-read voor API-ontwerpers.
http://ozlabs.org/~rusty/index.cgi/tech/2008‐03‐30.html

10. Het is onmogelijk naar krijgen fout.

Doelen moeten hoog worden gesteld, ambitieus hoog, zodat je ze niet bereikt en denkt dat je dat wel bent
klaar als jij dat niet bent.

De libexplain-bibliotheek detecteert valse pointers en vele andere valse systeemaanroepparameters,
en probeert over het algemeen segmentfouten te vermijden, zelfs onder de meest moeilijke omstandigheden.

De libexplain-bibliotheek is ontworpen om thread-safe te zijn. Meer gebruik in de echte wereld zal waarschijnlijk plaatsvinden
Ontdek waar dit verbeterd kan worden.

Het grootste probleem ligt bij de feitelijke functienamen zelf. Omdat C dat niet heeft
naamruimten gebruikt de libexplain-bibliotheek altijd het voorvoegsel 'explain_name'. Dit is de
traditionele manier om een ​​pseudonaamruimte te creëren om symboolconflicten te vermijden.
Het resulteert echter in een aantal onnatuurlijk klinkende namen.

9. De compiler or Links zal niet laten u krijgen it fout.

Een veel voorkomende fout is het gebruik van 'explain_open' waar 'explain_open_or_die' bedoeld was.
Gelukkig zal de compiler op dit punt vaak een typefout geven (bv kan niet toewijzen
const char * rvalue naar een int lvalue).

8. De compiler wil waarschuwen if u krijgen it fout.

Als 'explain_rename' wordt gebruikt terwijl 'explain_rename_or_die' bedoeld was, kan dit andere oorzaken hebben
problemen. GCC heeft een handig functiekenmerk warn_unused_result en de libexplain
bibliotheek koppelt het aan alle uitleg_naam functieaanroepen om een ​​waarschuwing te geven wanneer u
deze fout maken. Combineer dit met gcc -fout om dit te bevorderen naar niveau 9 goedheid.

7. De Voor de hand liggend . is (waarschijnlijk) de te corrigeren een.

De functienamen zijn gekozen om hun betekenis over te brengen, maar dit is niet altijd het geval
succesvol. Terwijl uitleg_naam_of_sterf en leg het uit_naam_on_error zijn redelijk beschrijvend,
de minder gebruikte draadveilige varianten zijn moeilijker te decoderen. De functieprototypes helpen de
compiler op weg naar begrip, en de Doxygen-opmerkingen in de headerbestanden helpen de gebruiker
naar begrip.

6. De naam vertelt u hoe naar . het.

Het is vooral belangrijk om uitleg_ te lezennaam_or_die als “uitleg (naam of sterf)".
Het gebruik van een consistente expand_name-space-voorvoegsel heeft enkele ongelukkige bijwerkingen in de
duidelijkheidsafdeling, ook.

De volgorde van de woorden in de namen geeft ook de volgorde van de argumenten aan. Het argument
lijstjes altijd einde met dezelfde argumenten als doorgegeven aan de systeemaanroep; allen of aan hen. Indien
_errno_ verschijnt in de naam, het argument gaat altijd vooraf aan de systeemaanroepargumenten. Als
_message_ verschijnt in de naam, de twee argumenten komen altijd op de eerste plaats.

5. Do it rechts or it wil breken at looptijd.

De libexplain-bibliotheek detecteert valse pointers en vele andere valse systeemaanroepparameters,
en probeert over het algemeen segmentfouten te vermijden, zelfs onder de meest moeilijke omstandigheden. Het zou moeten
zal nooit kapot gaan tijdens runtime, maar meer gebruik in de echte wereld zal dit ongetwijfeld verbeteren.

Sommige foutmeldingen zijn gericht op ontwikkelaars en beheerders in plaats van op eindgebruikers
kan helpen bij het oplossen van bugs. Niet zozeer ‘pauze tijdens runtime’ als wel ‘informatief zijn
runtime” (na de systeemaanroep barfs).

4. Volg gemeenschappelijk conventie en je zult krijgen it rechts.

Omdat C geen naamruimten heeft, gebruikt de libexplain-bibliotheek altijd een expand_name
voorvoegsel. Dit is de traditionele manier om een ​​pseudonaamruimte te creëren om deze te vermijden
symboolconflicten.

De volgargumenten van alle libexplain-aanroepen zijn identiek aan de systeemaanroepen
zijn aan het beschrijven. Dit is bedoeld om een ​​consistente conventie te bieden, gemeenschappelijk met de
systeem roept zichzelf aan.

3. Lees de documentatie en je zult krijgen it rechts.

De libexplain-bibliotheek streeft ernaar om voor iedereen volledige Doxygen-documentatie te hebben
openbare API-aanroep (en ook intern).

BERICHT INHOUD


Werken aan libexplain lijkt een beetje op het kijken naar de onderkant van je auto als deze erop staat
de takel bij de monteur. Er zit wat lelijk spul onder, plus modder en vuil, en...
gebruikers zien het zelden. Een goede foutmelding moet informatief zijn, zelfs voor een gebruiker die
heeft het geluk gehad niet vaak naar de onderkant te hoeven kijken, en ook
informatief voor de monteur die telefonisch de beschrijving van de gebruiker beluistert. Dit is
geen gemakkelijke opgave.

Als we ons eerste voorbeeld opnieuw bekijken, zou de code dit leuk vinden als hij libexplain gebruikt:
int fd = uitleg_open_or_die("iets/ding", O_RDONLY, 0);
zal mislukken met een foutmelding als deze
open(padnaam = "een/bestand", flags = O_RDONLY) mislukt, bestand of map bestaat niet
(2, ENOENT) omdat er geen "sommige" directory in de huidige directory aanwezig is
Dit valt uiteen in drie stukken
systeemoproep mislukt, systeemfout omdat
uitleg

Voor Omdat
Het is mogelijk om het deel van de boodschap vóór ‘omdat’ te zien als te technisch of niet-‐
technische gebruikers, vooral als gevolg van het nauwkeurig afdrukken van het systeem, noemen zichzelf op de
begin van de foutmelding. En het lijkt erop spoor(1) uitvoer, voor bonusnerd
punten.
open(padnaam = "een/bestand", flags = O_RDONLY) mislukt, bestand of map bestaat niet
(2, GENOENT)
Dit deel van de foutmelding is essentieel voor de ontwikkelaar wanneer hij de code schrijft.
en net zo belangrijk voor de beheerder die bugrapporten moet lezen en bugs in het
code. Er staat precies in wat er niet is gelukt.

Als deze tekst niet aan de gebruiker wordt gepresenteerd, kan de gebruiker deze niet kopiëren en plakken in een
bugrapport, en als het niet in het bugrapport staat, kan de onderhouder niet weten wat er feitelijk is gebeurd
fout.

Vaak zal technisch personeel gebruik maken van spoor(1) of bundel(1) om deze exacte informatie te krijgen, maar
deze weg is niet open bij het lezen van bugrapporten. Het systeem van de bugreporter is ver weg
weg, en inmiddels in een heel andere staat. Deze informatie moet dus in de
bugrapport, wat betekent dat het in de foutmelding moet staan.

De systeemoproeprepresentatie geeft ook context aan de rest van het bericht. Indien nodig
zich voordoet, kan in de uitleg naar het betreffende systeemaanroepargument worden verwezen
na ‘omdat’. Bovendien zijn alle strings volledig geciteerde en geëscapede C-strings, dus
ingebedde nieuwe regels en niet-afdrukbare tekens zorgen er niet voor dat de terminal van de gebruiker uitvalt
in de war.

De systeemfout is wat eruit komt spanning(2), plus het foutsymbool. Ongeduldig en
deskundige systeembeheerders zouden op dit punt kunnen stoppen met lezen, maar de ervaring van de auteur tot nu toe is dat wel
dat verder lezen de moeite waard is. (Als het niet lonend is, is het waarschijnlijk een gebied van
libexplain wat verbeterd kan worden. Codebijdragen zijn natuurlijk welkom.)

Na Omdat
Dit is het gedeelte van de foutmelding dat gericht is op niet-technische gebruikers. Het kijkt verder
het eenvoudige systeem roept argumenten aan en zoekt naar iets specifiekers.
er is geen "sommige" map in de huidige map
In dit gedeelte wordt geprobeerd de proximale oorzaak van de fout in gewone taal uit te leggen, en dat ook
is hier dat internationalisering essentieel is.

Over het algemeen is het beleid om zoveel mogelijk informatie op te nemen, zodat de gebruiker
hoeft er niet naar te zoeken (en laat het niet buiten het bugrapport).

internationalisering
De meeste foutmeldingen in de libexplain-bibliotheek zijn geïnternationaliseerd. Daar
zijn nog geen lokalisaties, dus als u de uitleg in uw moedertaal wilt,
draag alstublieft bij.

De kwalificatie ‘meest van’ hierboven heeft betrekking op het feit dat het proof-of-concept
De implementatie omvatte geen steun voor internationalisering. De codebasis wordt
geleidelijk herzien, meestal als gevolg van het herstructureren van berichten, zodat elke fout
berichtreeks verschijnt precies één keer in de code.

Er zijn voorzieningen getroffen voor talen waarin de gedeelten moeten worden samengesteld
systeemoproep mislukt, systeemfout omdat uitleg
in verschillende volgordes voor correcte grammatica in gelokaliseerde foutmeldingen.

postmortem
Er zijn momenten waarop een programma libexplain nog moet gebruiken en u het niet kunt gebruiken spoor(1)
of. Er is een verklaren(1) opdracht opgenomen in libexplain die kan worden gebruikt
foutmeldingen ontcijferen, als de toestand van het onderliggende systeem niet te veel is veranderd.
$ verklaren andere naam geven foo /tmp/bar/baz -e GENOENT
rename(oldpath = "foo", newpath = "/tmp/bar/baz") mislukt, bestand of map bestaat niet
(2, ENOENT) omdat er geen map "bar" in het nieuwepad staat "/ tmp" map
$
Merk op hoe de dubbelzinnigheid van het pad wordt opgelost door de naam van het systeemaanroepargument te gebruiken. Van
Natuurlijk moet je de fout kennen en weten waar het systeem om vraagt verklaren(1) nuttig zijn. Als een
Afgezien daarvan is dit een van de manieren die door de automatische testsuite libexplain worden gebruikt om dat te verifiëren
libexplain werkt.

Filosofie
"Vertel me alles, inclusief dingen waarvan ik niet wist dat ik ze moest zoeken."

De bibliotheek is zo geïmplementeerd dat wanneer deze statisch gekoppeld is, alleen de code beschikbaar is
daadwerkelijk gebruik zal worden gekoppeld. Dit wordt bereikt door één functie per bronbestand te hebben,
wanneer mogelijk.

Wanneer het mogelijk is om meer informatie te verstrekken, zal libexplain dat doen. Hoe minder de gebruiker
zelf moet opsporen, des te beter. Dit betekent dat UID's vergezeld gaan van de
gebruikersnaam, GID's gaan vergezeld van de groepsnaam, PID's gaan vergezeld van het proces
naam, bestandsbeschrijvingen en streams worden vergezeld door de padnaam, etc.

Als bij het oplossen van paden een padcomponent niet bestaat, zal libexplain naar soortgelijke zoeken
namen, om alternatieven voor typografische fouten voor te stellen.

De libexplain-bibliotheek probeert zo weinig mogelijk heap te gebruiken, en meestal geen. Dit is
om zoveel mogelijk te voorkomen dat de processtatus wordt verstoord, ook al is dat soms wel het geval
onvermijdelijk.

De libexplain-bibliotheek probeert thread-safe te zijn, door globale variabelen te vermijden en behouden
zoveel mogelijk op de stapel staat. Er is één gemeenschappelijke berichtenbuffer, en de
functies die er gebruik van maken, zijn gedocumenteerd als niet thread-safe.

De libexplain-bibliotheek verstoort de signaalbehandelaars van een proces niet. Dit maakt
bepalen of een aanwijzer een uitdaging zou doorbreken, maar niet onmogelijk.

Wanneer informatie zowel via een systeemoproep als via een / proc
invoer, heeft de systeemoproep de voorkeur. Dit is om te voorkomen dat de status van het proces wordt verstoord.
Er zijn ook momenten waarop er geen bestandsdescriptors beschikbaar zijn.

De libexplain-bibliotheek is gecompileerd met ondersteuning voor grote bestanden. Er is geen groot/klein
schizofrenie. Wanneer dit van invloed is op de argumenttypen in de API, wordt er een fout gegenereerd
als de benodigde grote bestandsdefinities ontbreken.

FIXME: Er is werk nodig om ervoor te zorgen dat bestandssysteemquota in de code worden verwerkt. Dit
geldt voor sommigen getrlimiet(2) ook grenzen.

Er zijn gevallen waarin familieledenpaden niet-informatief zijn. Bijvoorbeeld: systeemdaemons,
servers en achtergrondprocessen. In deze gevallen worden absolute paden gebruikt in de fout
uitleg.

PATH RESOLUTIE


Korte versie: zie pad_resolutie(7).

Lange versie: De meeste gebruikers hebben er nog nooit van gehoord pad_resolutie(7), en veel geavanceerde gebruikers
heb het nog nooit gelezen. Hier is een geannoteerde versie:

Stap voor 1: Start of de resolutie
Als de padnaam begint met een schuine streep (“/”), is dat de startzoekmap
de hoofdmap van het aanroepende proces.

Als de padnaam niet begint met het slash(“/”) teken, wordt de startzoekopdracht uitgevoerd
map van het oplossingsproces is de huidige werkmap van het proces.

Stap voor 2: Lopen langs de pad
Stel de huidige opzoekmap in op de startopzoekmap. Nu, voor elke niet-
laatste component van de padnaam, waarbij een component een subtekenreeks is, begrensd door een schuine streep (“/”)
tekens, wordt dit onderdeel opgezocht in de huidige opzoekdirectory.

Als het proces geen zoekmachtiging heeft voor de huidige opzoekmap, wordt een EACCES
fout wordt geretourneerd ("Toestemming geweigerd").
open(padnaam = "/home/archives/.ssh/private_key", flags = O_RDONLY) mislukt,
Toestemming geweigerd (13, EACCES) omdat het proces geen zoekmachtiging heeft
naar de padnaam "/home/archives/.ssh" directory, het proces effectief GID 1000
"pmiller" komt niet overeen met de mapeigenaar 1001 "archieven", dus de eigenaar
toestemmingsmodus "rwx" wordt genegeerd, de andere toestemmingsmodus is "---", en de
proces heeft geen privileges (heeft niet de mogelijkheid DAC_READ_SEARCH)

Als de component niet wordt gevonden, wordt een ENOENT-fout geretourneerd ("Geen bestand of map").
unlink(pathname = "/home/microsoft/rubbish") mislukt, bestand of map bestaat niet (2,
ENOENT) omdat er geen map "microsoft" in de padnaam staat "/ Home" map

Er is ook enige ondersteuning voor gebruikers wanneer ze padnamen verkeerd typen, en daarbij suggesties doen
ENOENT wordt geretourneerd:
open(padnaam = "/user/include/fcntl.h", flags = O_RDONLY) mislukt, geen dergelijk bestand of
directory (2, ENOENT) omdat er geen "user" directory in de padnaam "/" staat
map, bedoelde je in plaats daarvan de map "usr"?

Als de component wordt gevonden, maar geen directory of symbolische link is, wordt een ENOTDIR
fout wordt geretourneerd ("Geen map").
open(padnaam = "/home/pmiller/.netrc/lca", flags = O_RDONLY) mislukt, geen
directory (20, ENOTDIR) omdat het reguliere bestand ".netrc" in de padnaam staat
De map "/home/pmiller" wordt gebruikt als map, terwijl dat niet het geval is

Als de component wordt gevonden en een map is, stellen we de huidige opzoekmap daarop in
directory en ga naar het volgende onderdeel.

Als de component wordt gevonden en een symbolische link (symlink) is, lossen we deze symbolische link eerst op
link (met de huidige opzoekmap als startopzoekmap). Bij een fout, dat
fout wordt geretourneerd. Als het resultaat geen map is, wordt een ENOTDIR-fout geretourneerd.
unlink(pathname = "/tmp/dangling/rubbish") mislukt, bestand of map bestaat niet (2,
ENOENT) omdat de "bungelende" symbolische link in de padnaam "/ tmp" map
verwijst naar "nergens" dat niet bestaat
Als de resolutie van de symlink succesvol is en een directory retourneert, stellen we de current
zoek de map naar die map en ga naar het volgende onderdeel. Merk op dat de
Het oplossingsproces omvat hier recursie. Om de kernel te beschermen tegen stack
overflow, en ook om te beschermen tegen denial of service, zijn er limieten aan het maximum
recursiediepte en het maximale aantal gevolgde symbolische links. Er is sprake van een ELOOP-fout
geretourneerd wanneer het maximum wordt overschreden ("Te veel niveaus van symbolische links").
open(pathname = "/tmp/dangling", flags = O_RDONLY) mislukt, te veel niveaus van
symbolische links (40, ELOOP) omdat er een symbolische linklus is aangetroffen in
padnaam, beginnend bij "/tmp/dangling"
Het is ook mogelijk om een ​​ELOOP- of EMLINK-fout te krijgen als er te veel symlinks zijn, maar nee
lus werd gedetecteerd.
open(pathname = "/tmp/rabbit‐hole", flags = O_RDONLY) mislukt, te veel niveaus van
symbolische links (40, ELOOP) omdat er te veel symbolische links zijn aangetroffen in
padnaam (8)
Merk op hoe de werkelijke limiet ook wordt afgedrukt.

Stap voor 3: VIND DE PLEK DIE PERFECT VOOR JOU IS de finale toegang
Het opzoeken van het laatste onderdeel van de padnaam gaat net als dat van alle andere
componenten, zoals beschreven in de vorige stap, met twee verschillen:

(i) Het laatste onderdeel hoeft geen map te zijn (althans wat de padresolutie betreft
proces betreft. Mogelijk moet het een directory zijn, of een niet-directory, vanwege
de vereisten van de specifieke systeemoproep).

(Ii)
Het is niet noodzakelijkerwijs een fout als het laatste onderdeel niet wordt gevonden; misschien zijn we dat gewoon
het creëren ervan. De details over de behandeling van de definitieve inschrijving worden beschreven in de
handleidingpagina's van de specifieke systeemoproepen.

(Iii)
Het is ook mogelijk dat er een probleem is met het laatste onderdeel als het een symbolische link is
en het mag niet worden gevolgd. Gebruik bijvoorbeeld de open(2) O_NOFOLLOW-vlag:
open(padnaam = "a-symlink", flags = O_RDONLY | O_NOFOLLOW) mislukt, te veel niveaus van
symbolische links (ELOOP) omdat O_NOFOLLOW is opgegeven, maar padnaam verwijst naar a
symbolische link

(Iv)
Het komt vaak voor dat gebruikers fouten maken bij het typen van padnamen. De libexplain-bibliotheek
probeert suggesties te doen wanneer ENOENT wordt geretourneerd, bijvoorbeeld:
open(padnaam = "/usr/include/filecontrl.h", flags = O_RDONLY) mislukt, geen dergelijk bestand of
directory (2, ENOENT) omdat er geen regulier bestand "filecontrl.h" in de padnaam staat
"/ Usr / include" map, bedoelde je in plaats daarvan het gewone bestand "fcntl.h"?

(v) Het is ook mogelijk dat het laatste onderdeel iets anders moet zijn dan a
normaal bestand:
readlink(padnaam = "slechts een bestand", data = 0x7F930A50, data_size = 4097) mislukt,
Ongeldig argument (22, EINVAL) omdat padnaam een ​​normaal bestand is en geen symbolische link

(Vi)
FIXME: afhandeling van het "t"-bit.

Grenzen
Er zijn een aantal limieten met betrekking tot padnamen en bestandsnamen.

Lengtelimiet voor padnaam
Er is een maximale lengte voor padnamen. Als de padnaam (of een tussenliggende
padnaam verkregen tijdens het oplossen van symbolische links) is te lang, een ENAMETOOLONG
Er wordt een fout geretourneerd ("Bestandsnaam te lang"). Merk op hoe de systeemlimiet is opgenomen
in de foutmelding.
open(padnaam = "erg lang", flags = O_RDONLY) mislukt, bestandsnaam te lang (36,
ENAMETOOLONG) omdat padnaam de maximale padlengte van het systeem overschrijdt (4096)

Limiet voor lengte van bestandsnaam
Sommige Unix-varianten hebben een limiet op het aantal bytes in elke padcomponent.
Sommigen van hen gaan hier in stilte mee om, en sommigen geven ENAMETOOLONG; de libexplain
bibliotheek gebruikt padconfiguratie(3) _PC_NO_TRUNC om te vertellen welke. Als deze fout optreedt, wordt de
De libexplain-bibliotheek zal de limiet in het foutbericht vermelden, de limiet is
verkregen van padconfiguratie(3) _PC_NAME_MAX. Merk op hoe de systeemlimiet is opgenomen
in de foutmelding.
open(padnaam = "system7/had-slechts-14-tekens", flags = O_RDONLY) mislukt, Bestand
naam te lang (36, ENAMETOOLONG) omdat de component "slechts-14 tekens" is
langer dan de systeemlimiet (14)

Lege padnaam
In de originele Unix verwees de lege padnaam naar de huidige map.
Tegenwoordig bepaalt POSIX dat een lege padnaam niet succesvol mag worden opgelost.
open(padnaam = "", flags = O_RDONLY) mislukt, geen bestand of map (2,
ENOENT) omdat POSIX bepaalt dat een lege padnaam niet mag worden opgelost
met goed gevolg

machtigingen
De permissiebits van een bestand bestaan ​​uit drie groepen van drie bits. De eerste groep van
drie wordt gebruikt wanneer de effectieve gebruikers-ID van het aanroepproces gelijk is aan de eigenaar-ID van de
bestand. De tweede groep van drie wordt gebruikt wanneer de groeps-ID van het bestand gelijk is aan de
effectieve groeps-ID van het oproepproces, of is een van de aanvullende groeps-ID's van de
oproepproces. Als geen van beide geldt, wordt de derde groep gebruikt.
open(padnaam = "/ Etc / passwd", vlaggen = O_WRONLY) mislukt, toestemming geweigerd (13,
EACCES) omdat het proces geen schrijfrechten heeft voor de reguliere "passwd".
bestand in de padnaam "/ Etc" directory, het proces effectief UID 1000 "pmiller"
komt niet overeen met de reguliere bestandseigenaar 0 "root", dus de eigenaarstoestemmingsmodus "rw-"
wordt genegeerd, de andere toestemmingsmodus is "r--", en het proces heeft geen privileges
(beschikt niet over de DAC_OVERRIDE-mogelijkheid)
Er wordt behoorlijk wat ruimte gegeven aan deze uitleg, omdat de meeste gebruikers dit niet weten
is hoe het machtigingssysteem werkt. In het bijzonder: de eigenaar, groep en anderen
machtigingen zijn exclusief, ze zijn niet samen 'OF'.

VREEMD EN INTERESSANT SYSTEM GESPREKKEN


Het proces van het schrijven van een specifieke foutafhandelaar voor elke systeemaanroep komt vaak aan het licht
interessante eigenaardigheden en randvoorwaarden, of onduidelijk fout(3) waarden.

ENOMEDIUM, Nee Medium gevonden
Het kopiëren van een cd was de bron van de titel van dit artikel.
$ dd if=/dev/cdrom van=fubar.iso
dd: opening “/dev/cdrom”: Geen medium gevonden
$
De auteur vroeg zich af waarom zijn computer hem vertelde dat er niet zoiets bestaat als een helderziende
medium. Nog afgezien van het feit dat grote aantallen moedertaalsprekers van het Engels dat niet zijn
zich er zelfs van bewust dat ‘media’ een meervoud is, laat staan ​​dat ‘medium’ het enkelvoud ervan is, de string
geretourneerd door spanning(3) want ENOMEDIUM is zo beknopt dat het bijna volledig vrij is van
inhoud.

. open(2) retourneert ENOMEDIUM. Het zou mooi zijn als de libexplain-bibliotheek a zou kunnen uitbreiden
weinig hierover, gebaseerd op het type schijf dat het is. Bijvoorbeeld:
... omdat er geen schijf in het diskettestation zit
... omdat er geen schijf in het cd-romstation zit
... omdat er geen tape in de tapedrive zit
... omdat er geen geheugenstick in de kaartlezer zit

En zo gebeurde het...
open(padnaam = "/dev/cdrom", flags = O_RDONLY) mislukt, geen medium gevonden (123,
ENOMEDIUM) omdat er geen schijf in het cd-romstation lijkt te zitten
De truc, waarvan de auteur zich voorheen niet bewust was, was om het apparaat te openen met behulp van de
O_NONBLOCK-vlag, waarmee u een schijf zonder medium kunt openen. Jij dan
probleem apparaatspecifiek ioctls(2) verzoeken totdat je erachter komt wat het in vredesnaam is. (Niet
zeker of dit POSIX is, maar het lijkt ook zo te werken in BSD en Solaris, volgens
de wodim(1) bronnen.)

Let ook op het verschillende gebruik van “schijf” en “schijf” in de context. De cd-standaard is ontstaan
in Frankrijk, maar al het andere heeft een “k”.

EFAULT, slecht adres
Elke systeemaanroep waaraan een pointer-argument moet voldoen, kan EFAULT retourneren. De libexplain-bibliotheek
kan uitzoeken welk argument de schuldige is, en doet dit zonder het proces te verstoren
(of draad) signaalverwerking.

Indien beschikbaar, de mincore(2) Er wordt een systeemaanroep gebruikt om te vragen of de geheugenregio geldig is.
Het kan drie resultaten retourneren: in kaart gebracht maar niet in fysiek geheugen, in kaart gebracht en in fysiek geheugen
geheugen, en niet in kaart gebracht. Bij het testen van de geldigheid van een aanwijzer zijn de eerste twee ‘ja’
en de laatste is “nee”.

Het controleren van C-snaren is moeilijker, omdat we in plaats van een aanwijzer en een maat alleen maar
heb een wijzer. Om de grootte te bepalen zouden we de NUL moeten vinden, en dat zou kunnen
Segfault, catch-22.

Om dit te omzeilen, gebruikt de libexplain-bibliotheek de staat(2) systeemoproep (met een bekend
goed tweede argument) om C-strings te testen op geldigheid. Een mislukte terugkeer && errno == EFAULT
is een “nee”, en al het andere is een “ja”. Dit beperkt uiteraard de tekenreeksen tot PATH_MAX
karakters, maar dat is meestal geen probleem voor de libexplain-bibliotheek, want dat is het wel
bijna altijd de langste snaren waar het om gaat.

EMFILE, Te veel open bestanden
Deze fout treedt op wanneer een proces al het maximale aantal bestandsdescriptors geopend heeft.
Als de werkelijke limiet moet worden afgedrukt en de libexplain-bibliotheek probeert dit, kunt u niet openen
een bestand in / proc om te lezen wat het is.
open_max = sysconf(_SC_OPEN_MAX);
Deze is niet zo moeilijk, er is een sysconf(3) manier om de limiet te verkrijgen.

ENFILE, Te veel open bestanden in system
Deze fout treedt op wanneer de systeemlimiet voor het totale aantal geopende bestanden is bereikt
bereikt. In dit geval is er geen handig sysconf(3) manier om de limiet te verkrijgen.

Als je dieper graaft, kun je ontdekken dat er op Linux een / proc inzending waar we voor konden lezen
deze waarde verkrijgen. Catch-22: we hebben geen bestandsbeschrijvingen meer, dus we kunnen geen bestand openen
lees de limiet.

Op Linux is er een systeemaanroep om het te verkrijgen, maar het heeft dus geen [e]glibc-wrapperfunctie
je moet het allemaal heel voorzichtig doen:
lang
uitleg_maxbestand(ongeldig)
{
#ifdef __linux__
struct __sysctl_args argumenten;
int32_t maxbestand;
size_t maxbestand_grootte = De grootte van(maxbestand);
int naam[] = { CTL_FS, FS_MAXFILE };
memset(&args, 0, sizeof(struct __sysctl_args));
args.naam = naam;
args.nlen = 2;
args.oldval = &maxbestand;
args.oldlenp = &maxbestand_grootte;
if (syscall(SYS__sysctl, &args) >= 0)
maxbestand retourneren;
#stop als
retour -1;
}
Hierdoor kan de limiet worden opgenomen in het foutbericht, indien beschikbaar.

EINVAL "Ongeldig argument" vs ENOSYS "Functie niet geïmplementeerd"
Niet-ondersteunde acties (zoals symbolische link(2) op een FAT-bestandssysteem) worden niet gerapporteerd
consistent van de ene systeemoproep naar de volgende. Het is mogelijk om EINVAL of
ENOSYS is teruggekeerd.

Als gevolg hiervan moet er vooral aandacht worden besteed aan deze foutgevallen om ze goed te krijgen
omdat de EINVAL ook zou kunnen verwijzen naar problemen met een of meer systeemaanroepargumenten.

Note dat fout(3) is niet altijd reeks
Er zijn momenten waarop het nodig is om de [e]glibc-bronnen te lezen om te bepalen hoe en
wanneer er fouten worden geretourneerd voor sommige systeemaanroepen.

feof(3) bestandsnr(3)
Vaak wordt aangenomen dat deze functies geen fout kunnen retourneren. Dit is alleen waar als
de stream argument geldig is, maar ze kunnen een ongeldig argument detecteren
wijzer.

fpathconf(3) padconfiguratie(3)
De retourwaarde van fpathconf(2) en padconfiguratie(2) zou legitiem -1 kunnen zijn, en dat is ook zo
nodig om te kijken of fout(3) is expliciet vastgelegd.

ioctls(2)
De retourwaarde van ioctls(2) zou legitiem -1 kunnen zijn, dus het is noodzakelijk om te zien of
fout(3) is expliciet vastgelegd.

leesmap(3)
De retourwaarde van leesmap(3) is NULL voor zowel fouten als het einde van het bestand. Het is
nodig om te kijken of fout(3) is expliciet vastgelegd.

setbuf(3) setbuffer(3) setlinebuf(3) setvbuf(3)
Op de laatste na zijn alle functies ongeldig. En setvbuf(3) is alleen gedocumenteerd als
retourneert “niet-nul” bij een fout. Het is noodzakelijk om te zien of fout(3) is expliciet geweest
in te stellen.

strtod(3) strtol(3) gestrold(3) wandelen(3) strijd(3) stoer(3)
Deze functies retourneren bij een fout 0, maar dat is ook een legitieme retourwaarde. Het is
nodig om te kijken of fout(3) is expliciet vastgelegd.

niet getc(3)
Hoewel slechts één teken voor back-up verplicht is gesteld door de ANSI C-standaard, verandert dit wel
dat [e]glibc meer toestaat... maar dat betekent dat het kan mislukken met ENOMEM. Het kan
mislukken ook met EBADF als fp is nep. Het moeilijkste van allemaal is dat als je EOF doorgeeft, er een fout optreedt
return vindt plaats, maar errno is niet ingesteld.

De libexplain-bibliotheek detecteert al deze fouten correct, zelfs in gevallen waarin de
foutwaarden zijn slecht of helemaal niet gedocumenteerd.

ENOSPC, Nee ruimte links on apparaat
Wanneer deze fout verwijst naar een bestand op een bestandssysteem, drukt de libexplain-bibliotheek de mount af
punt van het bestandssysteem met het probleem. Dit kan de oorzaak van de fout veel zijn
duidelijker.
write(fildes = 1 "voorbeeld", data = 0xbfff2340, data_size = 5) mislukt, geen spatie over
op apparaat (28, ENOSPC) omdat het bestandssysteem fildes ("/ Home") heeft geen
meer ruimte voor gegevens
Naarmate er meer speciale apparaatondersteuning wordt toegevoegd, wordt verwacht dat foutmeldingen ook betrekking hebben op het apparaat
naam en werkelijke grootte van het apparaat.

erofs, Alleen lezen filet system
Wanneer deze fout verwijst naar een bestand op een bestandssysteem, drukt de libexplain-bibliotheek de mount af
punt van het bestandssysteem met het probleem. Dit kan de oorzaak van de fout veel zijn
duidelijker.

Naarmate er meer speciale apparaatondersteuning wordt toegevoegd, wordt verwacht dat foutmeldingen ook betrekking hebben op het apparaat
naam en soort.
open(padnaam = "/dev/fd0", O_RDWR, 0666) mislukt, alleen-lezen bestandssysteem (30, EROFS)
omdat op de diskette het schuifje voor schrijfbeveiliging is ingesteld

...omdat een cd-rom niet beschrijfbaar is
...omdat op de geheugenkaart het schrijfbeveiligingsnokje is ingesteld
...omdat de ½ inch magneetband geen schrijfring heeft

andere naam geven
De andere naam geven(2) systeemaanroep wordt gebruikt om de locatie of naam van een bestand te wijzigen en te verplaatsen
tussen mappen indien nodig. Als de doelpadnaam al bestaat, zal dat zo zijn
atomair vervangen, zodat er geen moment is waarop een ander proces dit probeert
er toegang toe krijgt, zal het ontbreken.

Er zijn echter beperkingen: u kunt alleen een map over een andere map hernoemen
map als de doelmap niet leeg is.
rename(oldpath = "foo", newpath = "bar") mislukt, map niet leeg (39,
ENOTEMPTY) omdat nieuwpad geen lege map is; dat wil zeggen, het bevat vermeldingen
anders dan "." En ".."
U kunt ook geen map hernoemen bovenop een niet-map.
rename(oldpath = "foo", newpath = "bar") mislukt, geen map (20, ENOTDIR)
omdat oudpad een map is, maar nieuwpad een gewoon bestand is, geen map
Het omgekeerde is ook niet toegestaan
rename(oldpath = "foo", newpath = "bar") mislukt, is een map (21, EISDIR)
omdat newpath een directory is, maar oldpath een gewoon bestand is, geen directory

Dit maakt de taak van de libexplain-bibliotheek natuurlijk ingewikkelder, omdat de
ontkoppelen(2) of rmdir(2) systeemaanroep wordt impliciet aangeroepen door andere naam geven(2), en dus alle
ontkoppelen(2) of rmdir(2) Ook fouten moeten worden opgespoord en afgehandeld.

dup2
De dup2(2) systeemaanroep wordt gebruikt om een ​​tweede bestandsdescriptor te maken die verwijst naar het
hetzelfde object als de eerste bestandsdescriptor. Meestal wordt dit gebruikt om shell-invoer te implementeren
en uitvoeromleiding.

Het leuke is dat, net als andere naam geven(2) kan een bestand atomair hernoemen bovenop een
bestaande bestand en verwijder het oude bestand, dup2(2) kan dit doen op een reeds geopend bestand
descriptor.

Nogmaals, dit maakt de taak van de libexplain-bibliotheek ingewikkelder, omdat de dichtbij(2)
systeemaanroep wordt impliciet aangeroepen door dup2(2), en dus allemaal dichtbij(2)'s fouten moeten zijn
ook gedetecteerd en afgehandeld.

AVONTUREN IN IOCTL ONDERSTEUNING


De ioctls(2) een systeemoproep biedt auteurs van apparaatstuurprogramma's een manier om mee te communiceren
gebruikersruimte die niet past binnen de bestaande kernel-API. Zien ioctl_lijst(2).

decodering Aanvraag Aantallen
Van een vluchtige blik op de ioctls(2) interface, er lijkt een grote maar eindige interface te bestaan
aantal mogelijk ioctls(2) verzoeken. Elk verschillend ioctls(2) verzoek is effectief
nog een systeemaanroep, maar zonder enige typeveiligheid - de compiler kan niet helpen
programmeur krijgt deze goed. Dit was waarschijnlijk de motivatie erachter tcflush(3) en
vrienden.

De eerste indruk is dat je kunt decoderen ioctls(2) verzoeken met behulp van een enorme schakelaar
stelling. Dit blijkt onhaalbaar omdat je er al snel achter komt dat dit wel zo is
Het is onmogelijk om alle noodzakelijke systeemheaders op te nemen die de verschillende definiëren ioctls(2)
verzoeken, omdat ze het lastig vinden om leuk met elkaar te spelen.

Als we dieper kijken, zien we dat er een reeks ‘privé’-verzoeknummers en apparaten bestaat
Auteurs van stuurprogramma's worden aangemoedigd deze te gebruiken. Dit betekent dat er een veel groter mogelijk is
reeks verzoeken, met dubbelzinnige verzoeknummers, dan onmiddellijk duidelijk zijn. Ook,
er zijn ook enkele historische onduidelijkheden.

We wisten al dat de schakelaar onpraktisch was, maar nu weten we dat om de schakelaar te selecteren
juiste verzoeknaam en uitleg, we moeten niet alleen rekening houden met het verzoeknummer, maar ook met het verzoeknummer
ook de bestandsbeschrijving.

De implementatie van ioctls(2) ondersteuning binnen de libexplain-bibliotheek is het hebben van een tabel met
verwijzingen naar ioctls(2) verzoekbeschrijvingen. Elk van deze descriptoren bevat een optionele
verwijzing naar een ondubbelzinnigheidsfunctie.

Iedere aanvraag wordt feitelijk in een apart bronbestand geïmplementeerd, zodat het benodigde
bestanden opnemen zijn ontheven van de verplichting om lekker met anderen te spelen.

Vertegenwoordiging
De filosofie achter de libexplain-bibliotheek is om zoveel mogelijk informatie te bieden
mogelijk, inclusief een nauwkeurige weergave van de systeemoproep. In het geval van
ioctls(2) dit betekent het afdrukken van het juiste aanvraagnummer (op naam) en ook een correct (of
op zijn minst nuttige) weergave van het derde argument.

De ioctls(2) prototype ziet er als volgt uit:
int ioctl(int fildes, int verzoek, ...);
waardoor uw typeveiligheidsalarmen zouden moeten afgaan. Intern bij [e]glibc is dit omgedraaid
in allerlei vormen:
int __ioctl(int fildes, int verzoek, lange arg);
int __ioctl(int fildes, int request, void *arg);
en de Linux kernel syscall-interface verwacht
asmlinkage long sys_ioctl(unsigned int fildes, unsigned int request, unsigned long
arg);
De extreme variabiliteit van het derde argument is een uitdaging als de bibliotheek libexplain
probeert een representatie van dat derde argument af te drukken. Echter, zodra het verzoeknummer
is ondubbelzinnig gemaakt, elk item in de ioctl-tabel van de libexplain-bibliotheek heeft een
aangepaste print_data-functie (OO handmatig gedaan).

Verklaringen
Er zijn minder problemen bij het bepalen van de te gebruiken verklaring. Eenmaal het aanvraagnummer
is ondubbelzinnig gemaakt, elk item in de ioctl-tabel van de libexplain-bibliotheek heeft een custom
print_explanation-functie (opnieuw, OO handmatig gedaan).

In tegenstelling tot sectie 2 en sectie 3 systeemaanroepen, de meeste ioctls(2) verzoeken bevatten geen fouten
gedocumenteerd. Dit betekent dat het, om goede foutbeschrijvingen te geven, noodzakelijk is om kernel te lezen
bronnen te ontdekken

· Wat fout(3) waarden kunnen worden geretourneerd, en

· de oorzaak van elke fout.

Vanwege de OO-aard van het verzenden van functieaanroepen binnen de kernel, moet je dit lezen
allen bronnen die dat implementeren ioctls(2) verzoek, niet alleen de generieke implementatie. Het
Het is te verwachten dat verschillende kernels op subtiele wijze verschillende foutnummers zullen hebben
verschillende foutoorzaken.

EINVAL vs GENOEG
De situatie is zelfs nog erger voor ioctls(2) verzoeken dan voor systeemoproepen, met EINVAL en
ENOTTY worden beide gebruikt om aan te geven dat een ioctls(2) verzoek is daarin ongepast
context, en af ​​en toe ENOSYS, ENOTSUP en EOPNOTSUPP (bedoeld voor gebruik voor sockets) als
Goed. Er zijn commentaren in de Linux-kernelbronnen die lijken te wijzen op een progressieve ontwikkeling
het opruimen is bezig. Voor extra chaos voegt BSD ENOIOCTL toe aan de verwarring.

Als gevolg hiervan moet er vooral aandacht worden besteed aan deze foutgevallen om ze goed te krijgen
omdat de EINVAL ook zou kunnen verwijzen naar problemen met een of meer systeemaanroepargumenten.

intptr_t
De C99-standaard definieert een integer-type dat gegarandeerd elke pointer kan bevatten
zonder representatieverlies.

Het bovenstaande functie-syscall-prototype zou beter geschreven zijn
long sys_ioctl(niet-ondertekende int-fildes, niet-ondertekende int-aanvraag, intptr_t arg);
Het probleem is de cognitieve dissonantie die wordt veroorzaakt door apparaatspecifiek of bestandssysteemspecifiek
ioctls(2) implementaties, zoals:
lange vfs_ioctl(struct-bestand *filp, niet-ondertekende int cmd, niet-ondertekende lange arg);
De meerderheid van ioctls(2) verzoeken hebben feitelijk een int *arg derde argument. Maar het hebben
verklaarde lange leads naar code die dit als lang behandelt *arg. Op 32-bits is dit onschadelijk
(sizeof(long) == sizeof(int)) maar vervelend op 64-bits (sizeof(long) != sizeof(int)).
Afhankelijk van de endian-heid krijg jij wel of niet de waarde die je verwacht, maar jij altijd krijgen
ook een geheugenkrabbel of stapelkrabbel.

Schrijf dit allemaal als
int ioctl(int fildes, int verzoek, ...);
int __ioctl(int fildes, int verzoek, intptr_t arg);
long sys_ioctl(niet-ondertekende int-fildes, niet-ondertekende int-aanvraag, intptr_t arg);
long vfs_ioctl(struct-bestand *filp, unsigned int cmd, intptr_t arg);
benadrukt dat het gehele getal slechts een geheel getal is om een ​​hoeveelheid weer te geven die bijna gelijk is
altijd een niet-gerelateerd pointertype.

CONCLUSIE


Gebruik libexplain, uw gebruikers zullen het leuk vinden.

COPYRIGHT


libexplain versie 1.4
Auteursrecht (C) 2008, 2009, 2010, 2011, 2012, 2013, 2014 Peter Miller

Gebruik expand_lca2010 online met behulp van de onworks.net-services


Gratis servers en werkstations

Windows- en Linux-apps downloaden

  • 1
    SLOK
    SLOK
    SWIG is een tool voor softwareontwikkeling
    dat programma's verbindt die zijn geschreven in C en
    C ++ met een verscheidenheid aan high-level
    programmeertalen. SWIG wordt gebruikt met
    verschillend...
    SWIG downloaden
  • 2
    WooCommerce Nextjs React-thema
    WooCommerce Nextjs React-thema
    Reageer WooCommerce-thema, gebouwd met
    Volgende JS, Webpack, Babel, Node en
    Express, met behulp van GraphQL en Apollo
    Cliënt. WooCommerce Store in React(
    bevat: Producten...
    Download het WooCommerce Nextjs React-thema
  • 3
    archlabs_repo
    archlabs_repo
    Pakketrepo voor ArchLabs Dit is een
    toepassing die ook kan worden opgehaald
    oppompen van
    https://sourceforge.net/projects/archlabs-repo/.
    Het is gehost in OnWorks in...
    Archlabs_repo downloaden
  • 4
    Zephyr-project
    Zephyr-project
    Het Zephyr Project is een nieuwe generatie
    real-time besturingssysteem (RTOS) dat
    ondersteunt meerdere hardware
    architecturen. Het is gebaseerd op een
    kernel met kleine voetafdruk ...
    Zephyr-project downloaden
  • 5
    SConen
    SConen
    SCons is een softwareconstructietool
    dat is een superieur alternatief voor de
    klassieke "Make" build-tool die
    we kennen en houden allemaal van. SCons is
    implementeerde een...
    SCons downloaden
  • 6
    PSeInt
    PSeInt
    PSeInt is een pseudo-code-interpreter voor
    Spaanstalige programmeerstudenten.
    Het belangrijkste doel is om een ​​hulpmiddel te zijn voor:
    de basis leren en begrijpen
    concept...
    PSeInt downloaden
  • Meer "

Linux-commando's

  • 1
    7z
    7z
    7z - Een bestandsarchiveringstool met de hoogste
    compressieverhouding ...
    Loop 7z
  • 2
    7za
    7za
    7za - Een bestandsarchiveringstool met de hoogste
    compressieverhouding ...
    Loop 7za
  • 3
    griezelig
    griezelig
    CREEPY - Een geolocatie-informatie
    aggregator BESCHRIJVING: griezelig is een
    applicatie waarmee u kunt verzamelen
    geolocatie gerelateerde informatie over
    gebruikers van ...
    Loop griezelig
  • 4
    cricket-compileren
    cricket-compileren
    cricket - Een programma om de
    verzameling en weergave van tijdreeksen
    gegevens ...
    Voer cricket-compilatie uit
  • 5
    g-wrap-config
    g-wrap-config
    g-wrap-config - script om te krijgen
    informatie over de geïnstalleerde versie
    van G-wrap ...
    Voer g-wrap-config uit
  • 6
    g.toegangsgras
    g.toegangsgras
    g.access - Beheert de toegang tot de
    huidige kaartenset voor andere gebruikers op de
    systeem. Als er geen optie wordt gegeven, drukt u af
    huidige status. KEYWORDS: algemeen, kaart
    management, pr...
    Voer g.accessgrass uit
  • Meer "

Ad