IngleseFranceseSpagnolo

Ad


Favicon di OnWorks

spiegazione_lca2010 - Online nel cloud

Esegui spiegazione_lca2010 nel provider di hosting gratuito OnWorks su Ubuntu Online, Fedora Online, emulatore online Windows o emulatore online MAC OS

Questo è il comando spiegazione_lca2010 che può essere eseguito nel provider di hosting gratuito OnWorks utilizzando una delle nostre molteplici postazioni di lavoro online gratuite come Ubuntu Online, Fedora Online, emulatore online Windows o emulatore online MAC OS

PROGRAMMA:

NOME


spiegazione_lca2010 - Nessun supporto trovato: quando è il momento di smettere di provare a leggere stress(3)'s
mente.

MOTIVAZIONE


L'idea di libexplain mi è venuta nei primi anni '1980. Ogni volta che una chiamata di sistema
restituisce un errore, il kernel sa esattamente cosa è andato storto... e lo comprime in
meno di 8 bit di err. Lo spazio utente ha accesso agli stessi dati del kernel,
dovrebbe essere possibile per lo spazio utente capire esattamente cosa è successo per provocare l'errore
return e usalo per scrivere buoni messaggi di errore.

Potrebbe essere così semplice?

Errore messaggi as finezza
I buoni messaggi di errore sono spesso quelle attività "all'uno per cento" che vengono eliminate quando pianificate
la pressione schiaccia il tuo progetto. Tuttavia, un buon messaggio di errore può creare un enorme,
miglioramento sproporzionato per l'esperienza dell'utente, quando l'utente vaga nello spavento
territorio sconosciuto che di solito non si incontra. Non è un compito facile.

Come programmatore larvale, l'autore non ha visto il problema con un errore (completamente accurato)
messaggi come questo:
eccezione mobile (core dump)
fino a quando non è stata indicata l'interpretazione alternativa del non programmatore. Ma non è questo
l'unica cosa sbagliata con i messaggi di errore di Unix. Con quale frequenza vedi messaggi di errore come:
$ ./stupido
non riesco ad aprire il file
$
Ci sono due opzioni per uno sviluppatore a questo punto:

1.
puoi eseguire un debugger, come gdb(1), o

2.
Puoi usare straccio(1) o travatura(1) guardare dentro.

· Ricorda che i tuoi utenti potrebbero non avere nemmeno accesso a questi strumenti, figuriamoci alla possibilità
per usarli. (è passato molto tempo da quando Unix principiante significava "ha solo scritto prima
driver del dispositivo".)

In questo esempio, tuttavia, usando straccio(1) rivela
$ straccio -e traccia=apri ./stupido
open("alcuni/file", O_RDONLY) = -1 ENOENT (Nessun file o directory)
non riesco ad aprire il file
$
Si tratta di molte più informazioni rispetto a quelle fornite dal messaggio di errore. In genere, il
il codice sorgente stupido assomiglia a questo
int fd = aperto("qualcosa", O_RDONLY);
se (fd < 0)
{
fprintf(stderr, "impossibile aprire il file\n");
exit(1);
}
L'utente non viene informato quale file, e non riesce nemmeno a dirlo all'utente quale errore. era il file
anche lì? C'è stato un problema di permessi? Ti dice che stava cercando di aprire un
file, ma probabilmente è stato per caso.

Prendi la tua chiavetta e vai a battere il programmatore larvale con essa. Raccontagli di errore(3).
La prossima volta che utilizzerai il programma vedrai un messaggio di errore diverso:
$ ./stupido
aperto: nessun file o directory del genere
$
Progresso, ma non quello che ci aspettavamo. Come può l'utente risolvere il problema se il messaggio di errore?
non gli dice qual era il problema? Guardando la fonte, vediamo
int fd = aperto("qualcosa", O_RDONLY);
se (fd < 0)
{
perror("apri");
exit(1);
}
È ora di un'altra corsa con il bastoncino d'indizio. Questa volta, il messaggio di errore richiede un passaggio
avanti e un passo indietro:
$ ./stupido
qualcosa: Nessun file o directory con questo nome
$
Ora sappiamo il file che stava tentando di aprire, ma non siamo più informati che lo fosse aprire(2)
che ha fallito. In questo caso probabilmente non è significativo, ma può essere significativo per
altre chiamate di sistema. Avrebbe potuto essere creat(2) invece, un'operazione che implica che
sono necessarie autorizzazioni diverse.
const char *nomefile = "qualcosa";
int fd = open(nomefile, O_RDONLY);
se (fd < 0)
{
perror(nomefile);
exit(1);
}
Il codice di esempio sopra è purtroppo tipico anche dei programmatori non larvali. Volta
per dire al nostro studente padawan del stress(3) chiamata di sistema.
$ ./stupido
aprire qualcosa: Nessun file o directory con questo nome
$
Ciò massimizza le informazioni che possono essere presentate all'utente. Il codice sembra
Questo:
const char *nomefile = "qualcosa";
int fd = open(nomefile, O_RDONLY);
se (fd < 0)
{
fprintf(stderr, "apri %s: %s\n", nome file, strerror(errno));
exit(1);
}
Ora abbiamo la chiamata di sistema, il nome del file e la stringa di errore. Questo contiene tutti i
informazioni che straccio(1) stampato. È quanto di meglio si possa.

O è?

Limiti of errore ed stress
Il problema riscontrato dall'autore, negli anni '1980, era che il messaggio di errore era incompleto.
"Nessun file o directory di questo tipo" si riferisce al "alcuni” o alla cartella “cosa"file in"
il "alcuni” rubrica?

Una rapida occhiata alla pagina man per stress(3) sta dicendo:
strerror - restituisce la stringa che descrive il numero di errore
Nota bene: sta descrivendo l'errore numero, non l'errore.

D'altra parte, il kernel conosce qual'era l'errore. C'era un punto specifico nel
codice del kernel, causato da una condizione specifica, in cui il codice del kernel si è ramificato e ha detto "no".
Un programma nello spazio utente potrebbe capire la condizione specifica e scrivere un errore migliore?
Messaggio?

Tuttavia, il problema è più profondo. Cosa succede se il problema si verifica durante il read(2) sistema
chiamare, piuttosto che il aprire(2) chiamare? È semplice per il messaggio di errore associato a
aprire(2) per includere il nome del file, è proprio lì. Ma per poter includere un nome di file
nell'errore associato al read(2) chiamata di sistema, devi passare il nome del file a tutti
giù nello stack di chiamate, così come il descrittore di file.

Ed ecco il bit che gratta: il kernel sa già che nome file il file
a cui è associato il descrittore. Perché un programmatore dovrebbe passare tutti i dati ridondanti?
giù nello stack di chiamate solo per migliorare un messaggio di errore che potrebbe non essere mai emesso? In
realtà, molti programmatori non si preoccupano e i messaggi di errore risultanti sono peggiori per
esso.

Ma erano gli anni '1980, su un PDP11, con risorse limitate e nessuna libreria condivisa. Indietro
quindi, nessun sapore di Unix incluso / proc anche in forma rudimentale, e il lsof(1) programma
era più di un decennio di distanza. Quindi l'idea è stata accantonata come impraticabile.

Livello infinito Assistenza
Immagina di essere a livello di supporto infinito. La descrizione del tuo lavoro dice che non lo fai mai
mai devi parlare con gli utenti Perché, allora, c'è ancora un flusso costante di persone che vogliono?
tu, il guru Unix locale, per decifrare l'ennesimo messaggio di errore?

Stranamente, 25 anni dopo, nonostante un semplice sistema di permessi, implementato con complete
coerenza, la maggior parte degli utenti Unix non ha ancora idea di come decodificare "Nessun file o directory di questo tipo",
o uno qualsiasi degli altri messaggi di errore criptici che vedono ogni giorno. O, almeno, criptico per
Loro.

Non sarebbe bello se il supporto tecnico di primo livello non avesse bisogno di decifrare i messaggi di errore?
Non sarebbe bello avere messaggi di errore che gli utenti potrebbero capire senza chiamare?
supporto tecnico?

Questi giorni / proc su Linux è più che in grado di fornire le informazioni necessarie per la decodifica
la stragrande maggioranza dei messaggi di errore e indirizzano l'utente alla causa prossima del loro
problema. Sui sistemi con un limitato / proc attuazione, il lsof(1) il comando può essere compilato
molte delle lacune.

Nel 2008, il flusso di richieste di traduzione è capitato troppo spesso all'autore. Era
tempo per riesaminare quell'idea vecchia di 25 anni e libexplain è il risultato.

UTILIZZO LA BIBLIOTECA


L'interfaccia alla libreria cerca di essere coerente, ove possibile. Cominciamo con un
esempio usando stress(3)
if (rename(vecchio_percorso, nuovo_percorso) < 0)
{
fprintf(stderr, "rinomina %s %s: %s\n", vecchio_percorso, nuovo_percorso,
strerror(errno));
exit(1);
}
L'idea alla base di libexplain è quella di fornire a stress(3) equivalente per ogni chiamata di sistema,
su misura per quella chiamata di sistema, in modo che possa fornire un errore più dettagliato
messaggio, contenente molte delle informazioni che vedete sotto l'intestazione "ERRORI" della sezione
2 e 3 uomo pagine, integrate con informazioni su condizioni reali, argomento reale
valori e limiti di sistema.

I Un'espansione Caso
I stress(3) sostituzione:
if (rename(vecchio_percorso, nuovo_percorso) < 0)
{
fprintf(stderr, "%s\n", spiegare_rinominare (vecchio_percorso, nuovo_percorso));
exit(1);
}

I Errno Caso
È anche possibile passare un'esplicita err(3) valore, se devi prima fare qualcosa
elaborazione che disturberebbe err, come il ripristino degli errori:
if (rename(vecchio_percorso, nuovo_percorso < 0))
{
int vecchio_errno = errno;
...codice che disturba err...
fprintf(stderr, "%s\n", spiega_errno_rename(old_errno,
vecchio_percorso, nuovo_percorso));
exit(1);
}

I Multi thread Astuccio
Alcune applicazioni sono multi-thread e quindi non sono in grado di condividere l'interno di libexplain
respingente. Puoi fornire il tuo buffer usando
if (unlink(percorso))
{
char messaggio[3000];
spiegazione_messaggio_unlink(messaggio, sizeof(messaggio), percorso);
dialogo_errore(Messaggio);
return -1;
}
E per completezza, entrambi err(3) e thread-safe:
ssize_t nbytes = read(fd, data, sizeof(data));
if (nbyte < 0)
{
char messaggio[3000];
int vecchio_errno = errno;
...errore recupero...
spiegazione_messaggio_errno_read(messaggio, sizeof(Messaggio),
old_errno, fd, data, sizeof(data));
dialogo_errore(Messaggio);
return -1;
}

Questi sono sostituti per strerror_r(3), sui sistemi che lo hanno.

Interfaccia Zucchero
Una serie di funzioni aggiunte come funzioni di convenienza, per convincere i programmatori a utilizzare il
libreria libexplain, risultano essere le funzioni libexplain più comunemente usate dall'autore in
programmi da riga di comando:
int fd = spiega_creat_or_die(nomefile, 0666);
Questa funzione tenta di creare un nuovo file. In caso contrario, stampa un messaggio di errore e
esce con EXIT_FAILURE. Se non ci sono errori, restituisce il nuovo descrittore di file.

Una funzione correlata:
int fd = spiega_creat_on_error(nomefile, 0666);
stamperà il messaggio di errore in caso di errore, ma restituirà anche il risultato dell'errore originale e
errAnche la (3) non è molestata.

Tutti , il Altro sistema chiamate
In generale, ogni chiamata di sistema ha il proprio file di inclusione
#includereNome.h>
che definisce i prototipi di funzione per sei funzioni:

· spiegare_Nome,

· spiegare_errno_Nome,

· spiegazione_messaggio_Nome,

· spiegazione_messaggio_errno_Nome,

· spiegare_Nome_o_morire e

· spiegare_Nome_su_errore.

Ogni prototipo di funzione ha la documentazione Doxygen e questa documentazione is non nudo
quando i file di inclusione sono installati.

I aspettare(2) la chiamata di sistema (e gli amici) hanno alcune varianti extra che interpretano anche il fallimento
essere uno stato di uscita diverso da EXIT_SUCCESS. Questo vale per sistema(3) e pchiudi(3) come
bene.

La copertura include 221 chiamate di sistema e 547 richieste ioctl. Ci sono molti altri sistemi
chiamate ancora da implementare. Chiamate di sistema che non tornano mai, come exit(2), non sono presenti
in biblioteca, e non lo sarà mai. Il exec famiglia di chiamate di sistema sono supportato, perché
ritornano quando c'è un errore.

Gatto
Ecco come potrebbe apparire un ipotetico programma "gatto", con segnalazione completa degli errori,
usando libexplain.
#includere
#includere
#includere
C'è un'inclusione per libexplain, oltre ai soliti sospetti. (Se si desidera ridurre il
carico del preprocessore, è possibile utilizzare lo specificoNome.h> include.)
vuoto statico
processo(FILE *fp)
{
per (;;)
{
buffer di caratteri [4096];
size_t n = spiega_fread_or_die(buffer, 1, sizeof(buffer), fp);
se (!n)
break;
spiegazione_fwrite_or_die(buffer, 1, n, stdout);
}
}
I processi La funzione copia un flusso di file nell'output standard. Se si verifica un errore
sia in lettura che in scrittura, viene riportato (e il percorso sarà incluso nel
errore) e il comando termina con EXIT_FAILURE. Non ci preoccupiamo nemmeno di tracciare il
nomi di percorso o passarli nello stack di chiamate.
int
main(int argc, char **argv)
{
per (;;)
{
int c = getopt(argc, argv, "o:");
se (c == EOF)
break;
interruttore (c)
{
caso 'o':
spiegazione_freopen_or_die(optarg, "w", stdout);
break;
La parte divertente di questo codice è che libexplain può segnalare errori Compreso , il pathname anche
se tu non riaprire esplicitamente lo stdout come fatto qui. Non ci preoccupiamo nemmeno di
tracciare il nome del file.
di default:
fprintf(stderr, "Utilizzo: %ss [ -o ] ...\n",
arg[0]);
ritorna EXIT_FAILURE;
}
}
se (optind == argc)
processo(stdin);
altro
{
while (optind < argc)
{
FILE *fp = spiegazione_fopen_or_die(argv[optind]++, "r");
processo (fp);
spiegazione_fclose_or_die(fp);
}
}
Lo standard output verrà chiuso implicitamente, ma troppo tardi per un rapporto di errore
emesso, quindi lo facciamo qui, nel caso in cui l'I/O bufferizzato non abbia ancora scritto nulla, e
c'è un errore ENOSPC o qualcosa del genere.
spiegazione_fflush_or_die(stdout);
restituire EXIT_SUCCESS;
}
È tutto. Segnalazione errori completa, codice chiaro.

Rusty's Scala of Interfaccia Bontà
Per quelli di voi che non lo conoscono, "How Do I Make This Hard to Mesuse?" di Rusty Russel.
page è una lettura obbligata per i progettisti di API.
http://ozlabs.org/~rusty/index.cgi/tech/2008‐03-30.html

10 Suo impossibile a ottenere sbagliato.

Gli obiettivi devono essere fissati in alto, ambiziosamente alti, per non raggiungerli e pensare di esserlo
finito quando non lo sei.

La libreria libexplain rileva puntatori fasulli e molti altri parametri di chiamate di sistema fasulli,
e generalmente cerca di evitare i segfault anche nelle circostanze più difficili.

La libreria libexplain è progettata per essere thread-safe. Probabilmente sarà più utilizzato nel mondo reale
rivelare luoghi che possono essere migliorati.

Il problema più grande è con i nomi delle funzioni effettive. Perché C non ha
spazi dei nomi, la libreria libexplain usa sempre un prefisso nome_spiega. Questo è il
modo tradizionale di creare uno pseudo-spazio dei nomi al fine di evitare conflitti di simboli.
Tuttavia, risulta in alcuni nomi dal suono innaturale.

9. I compilatore or Links Non sarà lasciare Tu ottenere it sbagliato.

Un errore comune è quello di usare spiegare_apri dove era inteso spiegare_apri_o_die.
Fortunatamente, a questo punto il compilatore genererà spesso un errore di tipo (per esempio non posso assegnare
const char * rvalue in un int lvalue).

8. I compilatore volere avvertire if Tu ottenere it sbagliato.

Se si usa spiegare_rinominare quando si intende spiegare_rinominare_o_die, questo può causare altro
i problemi. GCC ha un utile attributo della funzione warn_unused_result e il libexplain
la libreria lo allega a tutte le spiegazioni_Nome chiamate di funzione per produrre un avviso quando si
fare questo errore. Combina questo con gcc -Errore per promuovere questo al livello 9 di bontà.

7. I ovvio uso is (probabilmente) , il correggere uno.

I nomi delle funzioni sono stati scelti per trasmettere il loro significato, ma non è sempre così
riuscito. mentre spiega_Nome_o_muori e spiega_Nome_on_error sono abbastanza descrittivi,
le varianti thread-safe meno utilizzate sono più difficili da decodificare. I prototipi di funzione aiutano il
compilatore verso la comprensione e i commenti Doxygen nei file di intestazione aiutano l'utente
verso la comprensione.

6. I Nome dice Tu come a uso esso.

È particolarmente importante leggere spiegare_Nome_or_die come “spiega (Nome o morire)".
L'uso di un prefisso dello spazio dei nomi spiegato coerente ha alcuni sfortunati effetti collaterali nel
anche il dipartimento di ovvietà.

L'ordine delle parole nei nomi indica anche l'ordine degli argomenti. L'argomento
elenchi sempre fine con gli stessi argomenti passati alla chiamata di sistema; contro tutti i of loro. Se
_errno_ appare nel nome, il suo argomento precede sempre gli argomenti della chiamata di sistema. Se
_message_ appare nel nome, i suoi due argomenti vengono sempre per primi.

5. Do it destra or it volere rompere at tempo di esecuzione.

La libreria libexplain rileva puntatori fasulli e molti altri parametri di chiamate di sistema fasulli,
e generalmente cerca di evitare i segfault anche nelle circostanze più difficili. Dovrebbe
non si interrompono mai in fase di esecuzione, ma senza dubbio un uso maggiore nel mondo reale migliorerà questo.

Alcuni messaggi di errore sono rivolti a sviluppatori e manutentori piuttosto che agli utenti finali, in quanto questo
può aiutare con la risoluzione dei bug. Non tanto "pausa in fase di esecuzione" quanto "sii informativo su
runtime” (dopo la chiamata di sistema barfs).

4. Segui comune convenzione ed potrai ottenere it destra.

Poiché il C non ha spazi dei nomi, la libreria libexplain usa sempre un nome_spiegare
prefisso. Questo è il modo tradizionale di creare uno pseudo-spazio dei nomi per evitare
conflitti di simboli.

Gli argomenti finali di tutte le chiamate libexplain sono identici alla chiamata di sistema che loro
stanno descrivendo. Questo ha lo scopo di fornire una convenzione coerente in comune con il
il sistema chiama se stessi.

3. Leggi , il documentazione ed potrai ottenere it destra.

La libreria libexplain mira ad avere una documentazione Doxygen completa per ogni singolo utente
chiamata API pubblica (e anche interna).

MESSAGGIO CONTENUTO


Lavorare su libexplain è un po' come guardare la parte inferiore della tua auto quando è accesa
il paranco dal meccanico. Ci sono delle cose brutte là sotto, più fango e sporcizia, e
gli utenti lo vedono raramente. Un buon messaggio di errore deve essere informativo, anche per un utente che
ha avuto la fortuna di non dover guardare molto spesso la parte inferiore, e anche
informativo per il meccanico che ascolta la descrizione dell'utente al telefono. Questo è
nessun compito facile.

Rivisitando il nostro primo esempio, il codice vorrebbe questo se utilizza libexplain:
int fd = spiegare_apri_o_die("qualcosa/cosa", O_RDONLY, 0);
fallirà con un messaggio di errore come questo
open(pathname = "some/file", flags = O_RDONLY) non è riuscito, nessun file o directory di questo tipo
(2, ENOENT) perché non esiste una directory "alcune" nella directory corrente
Questo si scompone in tre pezzi
chiamata di sistema fallito, errore di sistema perché
spiegazione

Prima Perché
È possibile vedere la parte del messaggio prima di "perché" come eccessivamente tecnica per non
utenti tecnici, per lo più a causa della stampa accurata del sistema si chiama al
inizio del messaggio di errore. E sembra che straccio(1) uscita, per i fanatici del bonus
punti.
open(pathname = "some/file", flags = O_RDONLY) non è riuscito, nessun file o directory di questo tipo
(2, ENOENTE)
Questa parte del messaggio di errore è essenziale per lo sviluppatore quando scrive il codice,
e altrettanto importante per il manutentore che deve leggere le segnalazioni di bug e correggere i bug nel
codice. Dice esattamente cosa non è riuscito.

Se questo testo non viene presentato all'utente, l'utente non può copiarlo e incollarlo in a
segnalazione di bug, e se non è nella segnalazione di bug il manutentore non può sapere cosa sia effettivamente successo
sbagliato.

Spesso il personale tecnico utilizzerà straccio(1) o travatura(1) per ottenere queste informazioni esatte, ma
questa strada non è aperta durante la lettura delle segnalazioni di bug. Il sistema del segnalatore di bug è molto lontano
lontano, e, ormai, in uno stato molto diverso. Pertanto, questa informazione deve essere nel
segnalazione di bug, il che significa che deve essere nel messaggio di errore.

La rappresentazione della chiamata di sistema fornisce anche il contesto al resto del messaggio. Se necessario
si verifica, l'argomento della chiamata di sistema offensivo può essere indicato per nome nella spiegazione
dopo “perché”. Inoltre, tutte le stringhe sono stringhe C con virgolette complete, quindi
le nuove righe incorporate e i caratteri non stampabili non faranno andare il terminale dell'utente
in tilt.

I errore di sistema è quello che esce stress(2), più il simbolo di errore. impaziente e
gli amministratori di sistema esperti potrebbero smettere di leggere a questo punto, ma l'esperienza dell'autore fino ad oggi è
che leggere oltre è gratificante. (Se non è gratificante, probabilmente è un'area di
libexplain che può essere migliorato. I contributi al codice sono ben accetti, ovviamente.)

Dopo shavasana, sedersi in silenzio; saluti; Perché
Questa è la parte del messaggio di errore rivolta agli utenti non tecnici. Sembra oltre
i semplici argomenti della chiamata di sistema e cerca qualcosa di più specifico.
non c'è una directory "alcune" nella directory corrente
Questa parte tenta di spiegare la causa prossimale dell'errore in un linguaggio semplice e
è qui che l'internazionalizzazione è essenziale.

In generale, la politica è di includere quante più informazioni possibili, in modo che l'utente
non ha bisogno di cercarlo (e non lo lascia fuori dalla segnalazione di bug).

Internazionalizzazione
La maggior parte dei messaggi di errore nella libreria libexplain è stata internazionalizzata. Là
non ci sono ancora localizzazioni, quindi se vuoi le spiegazioni nella tua lingua madre,
si prega di contribuire.

Il qualificatore "most of", sopra, si riferisce al fatto che il proof-of-concept
l'implementazione non includeva il supporto all'internazionalizzazione. La base del codice è in corso
rivisto progressivamente, di solito a seguito di messaggi di refactoring in modo che ogni errore
la stringa del messaggio viene visualizzata nel codice esattamente una volta.

Sono state previste lingue che devono assemblare le porzioni di
chiamata di sistema fallito, errore di sistema perché spiegazione
in ordini diversi per la grammatica corretta nei messaggi di errore localizzati.

autopsia
Ci sono momenti in cui un programma deve ancora usare libexplain e non puoi usarlo straccio(1)
o. C'è un spiegare(1) comando incluso con libexplain che può essere usato per
decifrare i messaggi di errore, se lo stato del sistema sottostante non è cambiato troppo.
$ spiegare rinominare foo /tmp/bar/baz -e ENOENTE
rename(oldpath = "foo", newpath = "/tmp/bar/baz") non riuscito, nessun file o directory di questo tipo
(2, ENOENT) perché non esiste una directory "bar" nel nuovo percorso "/ Tmp" directory
$
Nota come l'ambiguità del percorso viene risolta utilizzando il nome dell'argomento della chiamata di sistema. Di
certo, devi conoscere l'errore e la richiesta di sistema spiegare(1) essere utile. come un
a parte, questo è uno dei modi utilizzati dalla suite di test automatici libexplain per verificarlo
libexplain funziona.

Filosofia
"Dimmi tutto, comprese le cose che non sapevo cercare."

La libreria è implementata in modo tale che quando è collegata staticamente, solo il codice
effettivamente l'uso sarà collegato. Ciò si ottiene avendo una funzione per file sorgente,
ogni volta che è fattibile.

Quando sarà possibile fornire maggiori informazioni, libexplain lo farà. Meno l'utente
deve rintracciare da soli, meglio è. Ciò significa che gli UID sono accompagnati dal
nome utente, i GID sono accompagnati dal nome del gruppo, i PID sono accompagnati dal processo
nome, descrittori di file e flussi sono accompagnati dal nome del percorso, eccetera.

Quando si risolvono i percorsi, se un componente del percorso non esiste, libexplain cercherà simili
nomi, al fine di suggerire alternative per errori tipografici.

La libreria libexplain cerca di utilizzare il minor numero di heap possibile e di solito nessuno. Questo è
per evitare di perturbare lo stato del processo, per quanto possibile, anche se a volte lo è
inevitabile.

La libreria libexplain tenta di essere thread-safe, evitando le variabili globali, mantenendo
stato in pila il più possibile. C'è un unico buffer di messaggi comune, e il
le funzioni che lo utilizzano sono documentate come non thread-safe.

La libreria libexplain non disturba i gestori del segnale di un processo. Questo fa
determinare se un puntatore segfault una sfida, ma non impossibile.

Quando le informazioni sono disponibili tramite una chiamata di sistema e disponibili tramite a / proc
voce, la chiamata di sistema è preferita. Questo per evitare di disturbare lo stato del processo.
Ci sono anche momenti in cui non sono disponibili descrittori di file.

La libreria libexplain è compilata con il supporto di file di grandi dimensioni. Non c'è grande/piccolo
schizofrenia. Laddove ciò influisca sui tipi di argomento nell'API e verrà emesso un errore
se le necessarie definizioni di file di grandi dimensioni sono assenti.

FIXME: È necessario lavorare per assicurarsi che le quote del file system siano gestite nel codice. Questo
si applica ad alcuni getrlimit(2) anche i confini.

Ci sono casi in cui i percorsi dei parenti non sono informativi. Ad esempio: demoni di sistema,
server e processi in background. In questi casi, nell'errore vengono utilizzati percorsi assoluti
spiegazioni.

PERCORSO RISOLUZIONE


Versione breve: vedi risoluzione_percorso(7).

Versione lunga: la maggior parte degli utenti non ne ha mai sentito parlare risoluzione_percorso(7) e molti utenti avanzati
non l'ho mai letto. Ecco una versione annotata:

step 1: Inizio of , il risoluzione processi
Se il nome del percorso inizia con il carattere barra ("/"), la directory di ricerca iniziale è
la directory principale del processo chiamante.

Se il nome del percorso non inizia con il carattere slash ("/"), la ricerca iniziale
directory del processo di risoluzione è la directory di lavoro corrente del processo.

step 2: Camminare lungo , il sentiero
Imposta la directory di ricerca corrente sulla directory di ricerca iniziale. Ora, per ogni non
componente finale del percorso, dove un componente è una sottostringa delimitata da una barra ("/")
caratteri, questo componente viene cercato nella directory di ricerca corrente.

Se il processo non dispone dell'autorizzazione di ricerca nella directory di ricerca corrente, un EACCES
viene restituito l'errore ("Autorizzazione negata").
open(pathname = "/home/archives/.ssh/private_key", flags = O_RDONLY) non riuscito,
Autorizzazione negata (13, EACCES) perché il processo non dispone dell'autorizzazione di ricerca
alla directory del percorso "/home/archives/.ssh", il processo ha effetto GID 1000
"pmiller" non corrisponde al proprietario della directory 1001 "archivi", quindi il proprietario
la modalità di autorizzazione "rwx" viene ignorata, la modalità di autorizzazione degli altri è "---" e il
il processo non è privilegiato (non ha la capacità DAC_READ_SEARCH)

Se il componente non viene trovato, viene restituito un errore ENOENT ("Nessun file o directory").
unlink(pathname = "/home/microsoft/rubbish") non riuscito, nessun file o directory di questo tipo (2,
ENOENT) perché non esiste una directory "microsoft" nel percorso "/ Home" directory

C'è anche un po' di supporto per gli utenti quando digitano male i nomi dei percorsi, dando suggerimenti quando
ENOENT viene restituito:
open(pathname = "/user/include/fcntl.h", flags = O_RDONLY) non riuscito, nessun file o
directory (2, ENOENT) perché non esiste una directory "utente" nel percorso "/"
directory, intendevi invece la directory "usr"?

Se il componente viene trovato, ma non è né una directory né un collegamento simbolico, un ENOTDIR
viene restituito l'errore ("Non una directory").
open(pathname = "/home/pmiller/.netrc/lca", flags = O_RDONLY) non riuscito, non un
directory (20, ENOTDIR) perché il file normale ".netrc" nel percorso
La directory "/home/pmiller" viene utilizzata come directory quando non lo è

Se il componente viene trovato ed è una directory, impostiamo la directory di ricerca corrente su quella
directory e passare al componente successivo.

Se il componente viene trovato ed è un collegamento simbolico (link simbolico), risolviamo prima questo simbolico
collegamento (con la directory di ricerca corrente come directory di ricerca iniziale). In caso di errore, che
errore viene restituito. Se il risultato non è una directory, viene restituito un errore ENOTDIR.
unlink(pathname = "/tmp/dangling/rubbish") fallito, nessun file o directory di questo tipo (2,
ENOENT) perché il collegamento simbolico "pendente" nel percorso "/ Tmp" directory
si riferisce a "da nessuna parte" che non esiste
Se la risoluzione del collegamento simbolico ha successo e restituisce una directory, impostiamo la corrente
cerca la directory in quella directory e vai al componente successivo. Nota che il
il processo di risoluzione qui implica la ricorsione. Per proteggere il kernel dallo stack
overflow, e anche per proteggersi dalla negazione del servizio, ci sono limiti al massimo
profondità di ricorsione e sul numero massimo di collegamenti simbolici seguiti. Un errore ELOOP è
restituito quando viene superato il massimo ("Troppi livelli di collegamenti simbolici").
open(pathname = "/tmp/dangling", flags = O_RDONLY) non riuscito, troppi livelli di
collegamenti simbolici (40, ELOOP) perché è stato rilevato un ciclo di collegamento simbolico in
nome del percorso, che inizia da "/tmp/dangling"
È anche possibile ottenere un errore ELOOP o EMLINK se ci sono troppi collegamenti simbolici, ma no
è stato rilevato un ciclo.
open(pathname = "/tmp/rabbit-hole", flags = O_RDONLY) non riuscito, troppi livelli di
collegamenti simbolici (40, ELOOP) perché sono stati incontrati troppi collegamenti simbolici in
nome del percorso (8)
Notare come viene stampato anche il limite effettivo.

step 3: Trovare , il finale iscrizione
La ricerca del componente finale del percorso va esattamente come quella di tutti gli altri
componenti, come descritto nel passaggio precedente, con due differenze:

(i) Il componente finale non deve essere una directory (almeno per quanto riguarda la risoluzione del percorso
processo è interessato. Potrebbe essere una directory o una non directory, a causa di
i requisiti della specifica chiamata di sistema).

(Ii)
Non è necessariamente un errore se il componente finale non viene trovato; forse siamo solo
creandolo. I dettagli sul trattamento della voce finale sono descritti nel
pagine di manuale delle chiamate di sistema specifiche.

(III)
È anche possibile avere un problema con l'ultimo componente se è un collegamento simbolico
e non dovrebbe essere seguito. Ad esempio, utilizzando il aprire(2) bandiera O_NOFOLLOW:
open(pathname = "a-symlink", flags = O_RDONLY | O_NOFOLLOW) non riuscito, troppi livelli di
collegamenti simbolici (ELOOP) perché è stato specificato O_NOFOLLOW ma il nome del percorso si riferisce a a
collegamento simbolico

(Iv)
È comune che gli utenti commettano errori durante la digitazione dei nomi di percorso. La libreria libexplain
tenta di fornire suggerimenti quando viene restituito ENOENT, ad esempio:
open(pathname = "/usr/include/filecontrl.h", flags = O_RDONLY) non riuscito, nessun file o
directory (2, ENOENT) perché non c'è un file normale "filecontrl.h" nel percorso
"/ usr / include", intendevi invece il file normale "fcntl.h"?

(v) È anche possibile che il componente finale debba essere qualcosa di diverso da a
file normale:
readlink(percorso = "solo un file", dati = 0x7F930A50, dimensione_dati = 4097) non riuscito,
Argomento non valido (22, EINVAL) perché il percorso è un file normale, non un collegamento simbolico

(Vi)
FIXME: gestione del bit "t".

Limiti
Ci sono una serie di limiti per quanto riguarda i nomi dei percorsi e dei file.

Limite di lunghezza del percorso
C'è una lunghezza massima per i nomi di percorso. Se il percorso (o qualche intermedio
percorso ottenuto durante la risoluzione dei collegamenti simbolici) è troppo lungo, un ENAMETOOLONG
viene restituito l'errore ("Nome file troppo lungo"). Notare come è incluso il limite di sistema
nel messaggio di errore.
open(percorso = "molto lungo", flags = O_RDONLY) non riuscito, nome file troppo lungo (36,
ENAMETOOLONG) perché il nome del percorso supera la lunghezza massima del percorso del sistema (4096)

Limite di lunghezza del nome del file
Alcune varianti di Unix hanno un limite al numero di byte in ogni componente del percorso.
Alcuni di loro si occupano di questo in silenzio, e alcuni danno ENAMETOOLONG; il libexplain
usi della biblioteca percorso conf(3) _PC_NO_TRUNC per dire quale. Se si verifica questo errore, il
La libreria libexplain indicherà il limite nel messaggio di errore, il limite è
ottenuto da percorso conf(3) _PC_NAME_MAX. Notare come è incluso il limite di sistema
nel messaggio di errore.
open(percorso = "sistema7/solo-aveva-14-caratteri", flags = O_RDONLY) non riuscito, File
nome troppo lungo (36, ENAMETOOLONG) perché il componente "only-had-14-characters" è
più lungo del limite di sistema (14)

Percorso vuoto
In Unix originale, il percorso vuoto si riferiva alla directory corrente.
Al giorno d'oggi POSIX decreta che un percorso vuoto non deve essere risolto con successo.
open(pathname = "", flags = O_RDONLY) non riuscito, nessun file o directory di questo tipo (2,
ENOENT) perché POSIX decreta che un percorso vuoto non deve essere risolto
avere ottimi risultati di

Permessi
I bit di autorizzazione di un file sono costituiti da tre gruppi di tre bit. Il primo gruppo di
tre viene utilizzato quando l'ID utente effettivo del processo chiamante è uguale all'ID proprietario del
file. Il secondo gruppo di tre viene utilizzato quando l'ID del gruppo del file è uguale a
ID di gruppo effettivo del processo di chiamata, o è uno degli ID di gruppo supplementari del
processo di chiamata. Quando nessuno dei due è valido, viene utilizzato il terzo gruppo.
open(percorso = "/etc/passwd", flag = O_WRONLY) non riuscito, Permesso negato (13,
EACCES) perché il processo non ha il permesso di scrittura per la "passwd" regolare
file nel percorso "/ Etc" directory, il processo effettivo UID 1000 "pmiller"
non corrisponde al normale proprietario del file 0 "root", quindi la modalità di autorizzazione del proprietario "rw-"
viene ignorato, la modalità di autorizzazione degli altri è "r--" e il processo non è privilegiato
(non ha la capacità DAC_OVERRIDE)
Viene dato uno spazio considerevole a questa spiegazione, poiché la maggior parte degli utenti non lo sa
ecco come funziona il sistema dei permessi. In particolare: il proprietario, il gruppo e altri
le autorizzazioni sono esclusive, non sono "OR"ed insieme.

STRANO E INTERESSANTE SISTEMA CHIAMATE


Il processo di scrittura di un gestore di errori specifico per ogni chiamata di sistema spesso rivela
stranezze e condizioni al contorno interessanti, o oscure err(3) valori.

ENOMEDIO, Non medie essere trovato
L'atto di copiare un CD è stata la fonte del titolo di questo articolo.
$ dd if=/dev/cdrom di=fubar.iso
dd: apertura “/dev/cdrom”: nessun supporto trovato
$
L'autore si chiedeva perché il suo computer gli dicesse che non esiste una cosa come un sensitivo
medio. A parte il fatto che un gran numero di madrelingua inglesi non lo è
pur consapevole che “media” è un plurale, figuriamoci che “medium” è il suo singolare, la stringa
restituito da stress(3) per ENOMEDIUM è così conciso da essere quasi completamente privo di
contenuto.

Quando aprire(2) restituisce ENOMEDIUM sarebbe bello se la libreria libexplain potesse espandersi a
poco su questo, in base al tipo di azionamento che è. Per esempio:
... perché non c'è un disco nell'unità floppy
... perché non c'è nessun disco nell'unità CD‐ROM
... perché non c'è nastro nell'unità nastro
... perché non c'è una memory stick nel lettore di schede

E così avvenne...
open(pathname = "/dev/cdrom", flags = O_RDONLY) non riuscito, nessun supporto trovato (123,
ENOMEDIUM) perché non sembra esserci un disco nell'unità CD‐ROM
Il trucco, che l'autore non era a conoscenza in precedenza, era quello di aprire il dispositivo utilizzando il
O_NONBLOCK flag, che ti consentirà di aprire un'unità senza supporto. tu allora
problema specifico del dispositivo ioctls(2) richieste fino a quando non capisci di cosa si tratta. (Non
certo se questo è POSIX, ma sembra funzionare in questo modo anche in BSD e Solaris, secondo
, il wodim(1) fonti.)

Nota anche i diversi usi di "disco" e "disco" nel contesto. Nasce lo standard CD
in Francia, ma tutto il resto ha una “k”.

ERRORE, Vasca indirizzo
Qualsiasi chiamata di sistema che accetta un argomento puntatore può restituire EFAULT. La libreria libexplain
può capire quale argomento è in errore e lo fa senza disturbare il processo
(o thread) gestione del segnale.

Quando disponibile, il mincore(2) viene utilizzata la chiamata di sistema per chiedere se la regione di memoria è valida.
Può restituire tre risultati: mappato ma non in memoria fisica, mappato e in fisico
memoria e non mappata. Quando si verifica la validità di un puntatore, i primi due sono "sì"
e l'ultimo è "no".

Il controllo delle stringhe C è più difficile, perché invece di un puntatore e una dimensione, abbiamo solo
avere un puntatore. Per determinare la dimensione dovremmo trovare il NUL, e questo potrebbe
segfault, cattura-22.

Per ovviare a questo problema, la libreria libexplain utilizza il comando Istat(2) chiamata di sistema (con un noto
buon secondo argomento) per testare la validità delle stringhe C. Un errore restituito && errno == EFAULT
è un "no", e qualsiasi altra cosa è un "sì". Questo, ovviamente, limita le stringhe a PATH_MAX
caratteri, ma di solito non è un problema per la libreria libexplain, perché è
quasi sempre le corde più lunghe le interessa.

EMFILO, Too molti aprire file
Questo errore si verifica quando un processo ha già aperto il numero massimo di descrittori di file.
Se il limite effettivo deve essere stampato e la libreria libexplain tenta di farlo, non puoi aprire
un file in / proc per leggere di cosa si tratta.
open_max = sysconf(_SC_OPEN_MAX);
Questo non era così difficile, c'è un sysconf(3) modo per ottenere il limite.

FILE, Too molti aprire file in sistema
Questo errore si verifica quando il limite di sistema sul numero totale di file aperti è stato
raggiunto. In questo caso non è utile sysconf(3) modo per ottenere il limite.

Scavando più a fondo, si potrebbe scoprire che su Linux c'è un / proc voce che potremmo leggere a
ottenere questo valore. Catch‐22: abbiamo esaurito i descrittori di file, quindi non possiamo aprire un file per
leggi il limite

Su Linux c'è una chiamata di sistema per ottenerlo, ma non ha la funzione wrapper [e]glibc, quindi
devi fare tutto con molta attenzione:
lungo
spiegazione_maxfile(void)
{
#ifdef __linux__
struttura __sysctl_args args;
int32_t file massimo;
dimensione_t dimensione_maxfile = sizeof(file massimo);
int nome[] = { CTL_FS, FS_MAXFILE };
memset(&args, 0, sizeof(struct __sysctl_args));
argomenti.name = nome;
args.nlen = 2;
args.oldval = &maxfile;
args.oldlenp = &maxfile_size;
if (syscall(SYS__sysctl, &args) >= 0)
restituisce maxfile;
#endif
return -1;
}
Ciò consente di includere il limite nel messaggio di errore, quando disponibile.

EINVAL "Non valido discussione" vs ENOSIS "Funzione non implementato”
Azioni non supportate (come link simbolico(2) su un file system FAT) non sono riportati
costantemente da una chiamata di sistema all'altra. È possibile avere EINVAL o
ENOSYS restituito.

Di conseguenza, è necessario prestare attenzione a questi casi di errore per ottenerli corretti, in particolare
poiché EINVAL potrebbe anche riferirsi a problemi con uno o più argomenti di chiamata di sistema.

Note: che err(3) is non sempre set
Ci sono momenti in cui è necessario leggere le fonti [e]glibc per determinare come e
quando vengono restituiti errori per alcune chiamate di sistema.

fef(3) nessun file(3)
Si presume spesso che queste funzioni non possano restituire un errore. Questo è vero solo se
, il ruscello l'argomento è valido, tuttavia sono in grado di rilevare un non valido
puntatore.

fpathconf(3) percorso conf(3)
Il valore restituito di fpathconf(2) e percorso conf(2) potrebbe legittimamente essere -1, quindi è
necessario per vedere se err(3) è stato esplicitamente impostato.

ioctls(2)
Il valore restituito di ioctls(2) potrebbe legittimamente essere -1, quindi è necessario vedere se
err(3) è stato esplicitamente impostato.

leggidir(3)
Il valore restituito di leggidir(3) è NULL sia per gli errori che per la fine del file. è
necessario per vedere se err(3) è stato esplicitamente impostato.

setbuff(3) setbuffer(3) setlinebuff(3) setvbuff(3)
Tutte tranne l'ultima di queste funzioni restituiscono void. e setvbuff(3) è documentato solo come
restituendo "diverso da zero" in caso di errore. Bisogna vedere se err(3) è stato esplicitamente
impostato.

strtod(3) strtola(3) detto(3) strtoll(3) forza(3) strtull(3)
Queste funzioni restituiscono 0 in caso di errore, ma questo è anche un valore restituito legittimo. è
necessario per vedere se err(3) è stato esplicitamente impostato.

ungetc(3)
Sebbene lo standard ANSI C preveda un solo carattere di backup, diventa
fuori che [e]glibc consente di più ... ma ciò significa che può fallire con ENOMEM. Può
fallisce anche con EBADF se fp è falso. La cosa più difficile di tutte, se passi EOF un errore
return si verifica, ma errno non è impostato.

La libreria libexplain rileva correttamente tutti questi errori, anche nei casi in cui il
i valori di errore sono scarsamente documentati, se non del tutto.

ENOSPC, Non spazio a sinistra on dispositivo
Quando questo errore si riferisce a un file su un file system, la libreria libexplain stampa il montaggio
punto del file system con il problema. Questo può rendere molto la fonte dell'errore
più chiaro.
write(fildes = 1 "example", data = 0xbfff2340, data_size = 5) non riuscito, spazio vuoto
sul dispositivo (28, ENOSPC) perché il file system contenente fildes ("/ Home") non ha
più spazio per i dati
Man mano che viene aggiunto un supporto per dispositivi più speciali, è previsto che i messaggi di errore includano il dispositivo
nome e le dimensioni effettive del dispositivo.

EROFS, Sola lettura filetto sistema
Quando questo errore si riferisce a un file su un file system, la libreria libexplain stampa il montaggio
punto del file system con il problema. Questo può rendere molto la fonte dell'errore
più chiaro.

Man mano che viene aggiunto un supporto per dispositivi più speciali, è previsto che i messaggi di errore includano il dispositivo
nome e tipo.
open(pathname = "/dev/fd0", O_RDWR, 0666) non riuscito, file system di sola lettura (30, EROFS)
perché il disco floppy ha la scheda di protezione dalla scrittura impostata

...perché un CD‐ROM non è scrivibile
...perché la scheda di memoria ha la linguetta di protezione dalla scrittura impostata
...perché il nastro magnetico da ½ pollice non ha un anello di scrittura

rinominare
I rinominare(2) la chiamata di sistema viene utilizzata per modificare la posizione o il nome di un file, spostandolo
tra le directory, se necessario. Se il percorso di destinazione esiste già, sarà
sostituito atomicamente, in modo che non vi sia alcun punto in cui un altro processo tenti di
accedere lo troverà mancante.

Ci sono limitazioni, tuttavia: puoi solo rinominare una directory sopra un'altra
directory se la directory di destinazione non è vuota.
rename(oldpath = "foo", newpath = "bar") non riuscito, Directory non vuota (39,
ENOTEMPTY) perché newpath non è una directory vuota; cioè, contiene voci
diverso da "." e ".."
Non puoi nemmeno rinominare una directory sopra una non-directory.
rename(oldpath = "foo", newpath = "bar") non riuscito, non una directory (20, ENOTDIR)
perché oldpath è una directory, ma newpath è un file normale, non una directory
Né è permesso il contrario
rename(oldpath = "foo", newpath = "bar") non riuscito, è una directory (21, EISDIR)
perché newpath è una directory, ma oldpath è un file normale, non una directory

Questo, ovviamente, rende il lavoro della libreria libexplain più complicato, perché il
scollegare(2) o rmdir(2) la chiamata di sistema è chiamata implicitamente da rinominare(2), e quindi tutti i
scollegare(2) o rmdir(2) anche gli errori devono essere rilevati e gestiti.

dup2
I dup2(2) la chiamata di sistema viene utilizzata per creare un secondo descrittore di file che fa riferimento al
stesso oggetto del primo descrittore di file. Tipicamente questo è usato per implementare l'input della shell
e reindirizzamento dell'output.

La cosa divertente è che, proprio come rinominare(2) può rinominare atomicamente un file sopra an
file esistente e rimuovere il vecchio file, dup2(2) può farlo su un file già aperto
descrittore.

Ancora una volta, questo rende il lavoro della libreria libexplain più complicato, perché il close(2)
chiamata di sistema viene chiamata implicitamente da dup2(2), e così tutto closeGli errori di (2) devono essere
rilevata e anche gestita.

AVVENTURE IN IOCTL SUPPORTO


I ioctls(2) la chiamata di sistema fornisce agli autori del driver del dispositivo un modo per comunicare con
spazio utente che non rientra nell'API del kernel esistente. Vedere ioctl_list(2).

Decodifica RICHIEDI numeri
Da uno sguardo superficiale al ioctls(2) interfaccia, sembrerebbe esserci un'ampia ma finita
numero di possibili ioctls(2) richieste. ognuno diverso ioctls(2) la richiesta è efficace
un'altra chiamata di sistema, ma senza alcuna sicurezza di tipo - il compilatore non può aiutare a
programmatore ottenere questi diritto. Questa era probabilmente la motivazione dietro tcflush(3) e
amici.

L'impressione iniziale è che potresti decodificare ioctls(2) richieste utilizzando un enorme interruttore
dichiarazione. Questo si rivela irrealizzabile perché si scopre molto rapidamente che lo è
impossibile includere tutte le necessarie intestazioni di sistema che definiscono le varie ioctls(2)
richieste, perché hanno difficoltà a giocare bene l'uno con l'altro.

Uno sguardo più approfondito rivela che esiste una gamma di numeri di richiesta "privati" e dispositivi
gli autori dei driver sono incoraggiati a usarli. Ciò significa che c'è un possibile molto più grande
insieme di richieste, con numeri di richiesta ambigui, che sono immediatamente evidenti. Anche,
ci sono anche alcune ambiguità storiche.

Sapevamo già che lo switch era poco pratico, ma ora sappiamo che per selezionare il
nome della richiesta appropriato e spiegazione dobbiamo considerare non solo il numero della richiesta ma
anche il descrittore di file.

L'implementazione di ioctls(2) il supporto all'interno della libreria libexplain è avere una tabella di
puntatori a ioctls(2) descrittori della richiesta. Ciascuno di questi descrittori include un optional
puntatore a una funzione di disambiguazione.

Ogni richiesta è effettivamente implementata in un file sorgente separato, in modo che il necessario
i file include sono sollevati dall'obbligo di giocare bene con gli altri.

sul Mercato
La filosofia alla base della libreria libexplain è quella di fornire quante più informazioni possibili
possibile, inclusa una rappresentazione accurata della chiamata di sistema. In caso di
ioctls(2) questo significa stampare il numero di richiesta corretto (per nome) e anche un corretto (o
almeno utile) rappresentazione del terzo argomento.

I ioctls(2) il prototipo assomiglia a questo:
int ioctl(int file, int richiesta, ...);
che dovrebbe far scattare i tuoi allarmi di sicurezza. Interno a [e]glibc, questo è girato
in una varietà di forme:
int __ioctl(int file, int request, long arg);
int __ioctl(int campo, int richiesta, void *arg);
e l'interfaccia syscall del kernel Linux si aspetta
asmlinkage long sys_ioctl(fildi int unsigned, richiesta int unsigned, unsigned long
argomento);
L'estrema variabilità del terzo argomento è una sfida, quando la libreria libexplain
tenta di stampare una rappresentazione di quel terzo argomento. Tuttavia, una volta che il numero di richiesta
è stato disambiguato, ogni voce nella tabella ioctl della libreria libexplain ha un
funzione print_data personalizzata (OO eseguita manualmente).

Spiegazioni
Ci sono meno problemi nel determinare la spiegazione da utilizzare. Una volta che il numero di richiesta
è stato disambiguato, ogni voce nella tabella ioctl della libreria libexplain ha una personalizzazione
funzione print_explanation (di nuovo, OO fatto manualmente).

A differenza delle chiamate di sistema della sezione 2 e della sezione 3, la maggior parte ioctls(2) le richieste non contengono errori
documentato. Ciò significa che, per fornire una buona descrizione degli errori, è necessario leggere il kernel
fonti da scoprire

· che cosa err(3) i valori possono essere restituiti, e

· la causa di ogni errore.

A causa della natura OO dell'invio delle chiamate di funzione all'interno del kernel, è necessario leggere
contro tutti i fonti che lo implementano ioctls(2) richiesta, non solo l'implementazione generica. Esso
c'è da aspettarsi che kernel diversi abbiano numeri di errore diversi e sottilmente
diverse cause di errore.

EINVAL vs ENOTTA
La situazione è ancora peggiore per ioctls(2) richieste rispetto alle chiamate di sistema, con EINVAL e
ENOTTY entrambi usati per indicare che an ioctls(2) la richiesta è inappropriata in quanto
contesto, e occasionalmente ENOSYS, ENOTSUP e EOPNOTSUPP (destinati ad essere utilizzati per i socket) come
bene. Ci sono commenti nei sorgenti del kernel Linux che sembrano indicare un progressivo
la pulizia è in corso. Per ulteriore caos, BSD aggiunge ENOIOCTL alla confusione.

Di conseguenza, è necessario prestare attenzione a questi casi di errore per ottenerli corretti, in particolare
poiché EINVAL potrebbe anche riferirsi a problemi con uno o più argomenti di chiamata di sistema.

intptr_t
Lo standard C99 definisce un tipo intero che è garantito per essere in grado di contenere qualsiasi puntatore
senza perdita di rappresentanza.

Il prototipo di syscall della funzione sopra sarebbe scritto meglio
long sys_ioctl(fildi int senza segno, richiesta int senza segno, intptr_t arg);
Il problema è la dissonanza cognitiva indotta da dispositivi specifici o specifici del file system
ioctls(2) implementazioni, come:
long vfs_ioctl(file struct *filp, unsigned int cmd, unsigned long arg);
La maggioranza dei ioctls(2) le richieste in realtà hanno un terzo argomento int *arg. ma averlo
dichiarato long porta al codice che lo considera long *arg. Questo è innocuo a 32 bit
(sizeof(long) == sizeof(int)) ma brutto a 64 bit (sizeof(long) != sizeof(int)).
A seconda dell'endian‐ness, ottieni o non ottieni il valore che ti aspetti, ma tu sempre ottenere
anche uno scarabocchio in memoria o uno stack.

Scrivendo tutto questo come
int ioctl(int file, int richiesta, ...);
int __ioctl(int file, int richiesta, intptr_t arg);
long sys_ioctl(fildi int senza segno, richiesta int senza segno, intptr_t arg);
long vfs_ioctl(file struct *filp, unsigned int cmd, intptr_t arg);
sottolinea che l'intero è solo un intero per rappresentare una quantità che è quasi
sempre un tipo di puntatore non correlato.

CONCLUSIONE


Usa libexplain, ai tuoi utenti piacerà.

COPYRIGHT


libexplain versione 1.4
Copyright (C) 2008, 2009, 2010, 2011, 2012, 2013, 2014 Peter Miller

Usa spiegazione_lca2010 online utilizzando i servizi onworks.net


Server e workstation gratuiti

Scarica app per Windows e Linux

  • 1
    SWIG
    SWIG
    SWIG è uno strumento di sviluppo software
    che collega programmi scritti in C e
    C++ con una varietà di alto livello
    linguaggi di programmazione. SWIG è usato con
    diverso...
    Scarica SIG
  • 2
    Tema React di WooCommerce Nextjs
    Tema React di WooCommerce Nextjs
    Tema React WooCommerce, costruito con
    Avanti JS, Webpack, Babel, Node e
    Express, utilizzando GraphQL e Apollo
    Cliente. Negozio WooCommerce a React(
    contiene: Prodotti...
    Scarica il tema WooCommerce Nextjs React
  • 3
    archlabs_repo
    archlabs_repo
    Repository dei pacchetti per ArchLabs Questo è un file
    applicazione che può anche essere recuperata
    da
    https://sourceforge.net/projects/archlabs-repo/.
    È stato ospitato in OnWorks in...
    Scarica archlabs_repo
  • 4
    Progetto Zefiro
    Progetto Zefiro
    Il progetto Zephyr è una nuova generazione
    sistema operativo in tempo reale (RTOS) che
    supporta più hardware
    architetture. Si basa su a
    kernel a ingombro ridotto...
    Scarica il progetto zephyr
  • 5
    SCons
    SCons
    SCons è uno strumento di costruzione di software
    che è un'alternativa superiore al
    il classico strumento di costruzione "Make" che
    tutti conosciamo e amiamo. SCons è
    implementato un...
    Scarica SCons
  • 6
    PSInt
    PSInt
    PSeInt è un interprete di pseudo-codice per
    studenti di programmazione di lingua spagnola.
    Il suo scopo principale è quello di essere uno strumento per
    imparare e comprendere le basi
    concetto...
    Scarica PSInt
  • Di Più "

Comandi Linux

  • 1
    7z
    7z
    7z - Un archiviatore di file con la massima estensione
    rapporto di compressione ...
    Corri 7z
  • 2
    7za
    7za
    7za - Un archiviatore di file con la massima estensione
    rapporto di compressione ...
    Esegui 7za
  • 3
    raccapricciante
    raccapricciante
    CREEPY - Un'informazione di geolocalizzazione
    aggregatore DESCRIZIONE: raccapricciante è un
    applicazione che ti permette di raccogliere
    informazioni relative alla geolocalizzazione su
    utenti di...
    Corri inquietante
  • 4
    cricket-compila
    cricket-compila
    cricket - Un programma per gestire il
    raccolta e visualizzazione di serie temporali
    dati ...
    Esegui la compilazione di cricket
  • 5
    g-wrap-config
    g-wrap-config
    g-wrap-config - script da ottenere
    informazioni sulla versione installata
    di G-Wrap...
    Esegui g-wrap-config
  • 6
    g.accessgrass
    g.accessgrass
    g.access - Controlla l'accesso a
    mapset corrente per altri utenti sul
    sistema. Se non viene fornita alcuna opzione, viene stampato
    stato attuale. PAROLE CHIAVE: generale, mappa
    gestione, p...
    Esegui g.accessgrass
  • Di Più "

Ad