InglésFrancésEspañol

Ad


icono de página de OnWorks

explica_lca2010 - En línea en la nube

Ejecuteexplica_lca2010 en el proveedor de alojamiento gratuito de OnWorks sobre Ubuntu Online, Fedora Online, emulador en línea de Windows o emulador en línea de MAC OS

Este es el comando explica_lca2010 que se puede ejecutar en el proveedor de alojamiento gratuito de OnWorks utilizando una de nuestras múltiples estaciones de trabajo en línea gratuitas, como Ubuntu Online, Fedora Online, emulador en línea de Windows o emulador en línea de MAC OS.

PROGRAMA:

NOMBRE


Explique_lca2010 - No se encontró medio: cuando es el momento de dejar de intentar leer estruendo(3)
mente.

MOTIVACIÓN


La idea de libexplain se me ocurrió a principios de la década de 1980. Siempre que una llamada al sistema
devuelve un error, el kernel sabe exactamente qué salió mal ... y lo comprime en
menos de 8 bits de error. El espacio de usuario tiene acceso a los mismos datos que el kernel,
Debería ser posible que el espacio de usuario descubra exactamente qué sucedió para provocar el error.
return, y utilícelo para escribir buenos mensajes de error.

¿Podría ser tan simple?

Error la vida as finura
Los buenos mensajes de error son a menudo esas tareas del "uno por ciento" que se descartan cuando se programan
la presión aprieta su proyecto. Sin embargo, un buen mensaje de error puede generar un gran
mejora desproporcionada de la experiencia del usuario, cuando el usuario se adentra en el miedo
territorio desconocido que no se suele encontrar. Esta no es una tarea fácil.

Como programador de larvas, el autor no vio el problema con el error (completamente exacto)
mensajes como este:
excepción flotante (núcleo volcado)
hasta que se señaló la interpretación alternativa de no programador. Pero ese no es el
Lo único malo con los mensajes de error de Unix. ¿Con qué frecuencia ve mensajes de error como:
$ ./estúpido
no se puede abrir el archivo
$
Hay dos opciones para un desarrollador en este momento:

1.
puede ejecutar un depurador, como gdb(1) o

2.
puedes usar rastro(1) o braguero(1) para mirar dentro.

· Recuerde que es posible que sus usuarios ni siquiera tengan acceso a estas herramientas, y mucho menos la capacidad
para usarlos. (Hace mucho tiempo que Unix principiante significa "sólo ha escrito una
controlador de dispositivo".)

En este ejemplo, sin embargo, usando rastro(1) revela
$ rastro -e trace = open ./estúpido
open ("some / file", O_RDONLY) = -1 ENOENT (No existe tal archivo o directorio)
no se puede abrir el archivo
$
Ésta es considerablemente más información de la que proporciona el mensaje de error. Normalmente, el
el código fuente estúpido se ve así
int fd = open ("alguna cosa", O_RDONLY);
si (fd <0)
{
fprintf (stderr, "no se puede abrir el archivo \ n");
salida(1);
}
No se le dice al usuario que archivo, y tampoco le dice al usuario que error. Era el archivo
¿aún allí? ¿Hubo un problema de permisos? Te dice que estaba intentando abrir un
archivo, pero probablemente fue por accidente.

Coge tu palo de pista y ve a golpear al programador de larvas con él. Cuéntale sobre perror(3).
La próxima vez que utilice el programa, verá un mensaje de error diferente:
$ ./estúpido
open: No existe tal archivo o directorio
$
Progreso, pero no lo que esperábamos. ¿Cómo puede el usuario solucionar el problema si el mensaje de error
no le dice cuál era el problema? Mirando la fuente, vemos
int fd = open ("alguna cosa", O_RDONLY);
si (fd <0)
{
perror ("abierto");
salida(1);
}
Es hora de otra carrera con el palo de pistas. Esta vez, el mensaje de error da un paso
adelante y un paso atrás:
$ ./estúpido
alguna cosa: El fichero o directorio no existe
$
Ahora sabemos el archivo que estaba intentando abrir, pero ya no se nos informa que estaba habiertos(2)
eso falló. En este caso, probablemente no sea significativo, pero puede serlo para
otras llamadas al sistema. Podría haber sido creat(2) en cambio, una operación que implica que
son necesarios diferentes permisos.
const char * nombre de archivo = "alguna cosa";
int fd = open (nombre de archivo, O_RDONLY);
si (fd <0)
{
perror (nombre de archivo);
salida(1);
}
Desafortunadamente, el código de ejemplo anterior también es típico de los programadores no larvarios. Tiempo
para contarle a nuestro aprendiz padawan sobre el estruendo(3) llamada al sistema.
$ ./estúpido
habiertos alguna cosa: El fichero o directorio no existe
$
Esto maximiza la información que se puede presentar al usuario. El código se parece a
modo:
const char * nombre de archivo = "alguna cosa";
int fd = open (nombre de archivo, O_RDONLY);
si (fd <0)
{
fprintf (stderr, "abrir% s:% s \ n", nombre de archivo, strerror (errno));
salida(1);
}
Ahora tenemos la llamada al sistema, el nombre del archivo y la cadena de error. Esto contiene todos los
información que rastro(1) impreso. Eso es tan bueno como parece.

¿O es eso?

Limitaciones of perror y estruendo
El problema que vio el autor, allá por la década de 1980, fue que el mensaje de error está incompleto.
¿"No existe tal archivo o directorio" se refiere a la "algo"Directorio, o al"cosa" presentar en
la "algo”Directorio?

Un vistazo rápido a la página de manual de estruendo(3) está diciendo:
strerror - cadena de retorno que describe el número de error
Tenga en cuenta bien: está describiendo el error número, no el error.

Por otro lado, el kernel sabe cuál fue el error. Hubo un punto específico en el
código del núcleo, causado por una condición específica, donde el código del núcleo se ramificó y dijo "no".
¿Podría un programa de espacio de usuario descubrir la condición específica y escribir un error mejor?
¿mensaje?

Sin embargo, el problema es más profundo. ¿Qué pasa si el problema ocurre durante el leer(2) sistema
llamar, en lugar del habiertos(2) llamar? Es simple para el mensaje de error asociado con
habiertos(2) para incluir el nombre del archivo, está ahí. Pero para poder incluir un nombre de archivo
en el error asociado con el leer(2) llamada al sistema, debe pasar el nombre del archivo a todos
el camino hacia abajo en la pila de llamadas, así como el descriptor de archivo.

Y aquí está el bit que rechina: el kernel ya sabe qué nombre de archivo es el archivo
descriptor está asociado con. ¿Por qué debería un programador tener que pasar datos redundantes
el camino hacia abajo en la pila de llamadas solo para mejorar un mensaje de error que puede que nunca se emita? En
realidad, muchos programadores no se molestan y los mensajes de error resultantes son peores para
él.

Pero eso fue en la década de 1980, en un PDP11, con recursos limitados y sin bibliotecas compartidas. atrás
entonces, sin sabor de Unix incluido / proc incluso en forma rudimentaria, y el lsof(1) programa
estaba a más de una década de distancia. Así que la idea se archivó por no ser práctica.

Nivel Infinity Soporte
Imagina que eres un soporte de nivel infinito. La descripción de su trabajo dice que nunca
vez tienes que hablar con los usuarios. ¿Por qué, entonces, todavía hay un flujo constante de personas que quieren
usted, el gurú local de Unix, para descifrar otro mensaje de error?

Curiosamente, 25 años después, a pesar de un sistema de permisos simple, implementado con
consistencia, la mayoría de los usuarios de Unix todavía no tienen idea de cómo decodificar "No existe tal archivo o directorio",
o cualquiera de los otros mensajes de error crípticos que ven todos los días. O, al menos, críptico para
de ellas.

¿No sería bueno si el soporte técnico de primer nivel no necesitara descifrar los mensajes de error?
¿No sería bueno tener mensajes de error que los usuarios pudieran entender sin llamar
¿apoyo técnico?

Estos días / proc en Linux es más que capaz de proporcionar la información necesaria para decodificar
la gran mayoría de los mensajes de error, y señalan al usuario la causa inmediata de su
problema. En sistemas con un limitado / proc implementación, la lsof(1) el comando puede completar
muchas de las lagunas.

En 2008, el flujo de solicitudes de traducción le sucedió al autor con demasiada frecuencia. Era
Es hora de volver a examinar esa idea de hace 25 años, y libexplain es el resultado.

USO EL REINO UNIDO LIBRERÍA


La interfaz de la biblioteca intenta ser coherente, siempre que sea posible. Empecemos con un
ejemplo usando estruendo(3):
if (renombrar (ruta_antigua, ruta_ nueva) <0)
{
fprintf (stderr, "renombrar% s% s:% s \ n", ruta_antigua, ruta_nueva,
strerror (errno));
salida(1);
}
La idea detrás de libexplain es proporcionar una estruendo(3) equivalente para cada una llamada al sistema,
adaptado específicamente a esa llamada al sistema, de modo que pueda proporcionar un error más detallado
mensaje, que contiene gran parte de la información que ve en el encabezado "ERRORES" de la sección
2 y 3 hombre páginas, complementadas con información sobre condiciones reales, argumento real
valores y límites del sistema.

El sencillos Funda
El estruendo(3) reemplazo:
if (renombrar (ruta_antigua, ruta_ nueva) <0)
{
fprintf (stderr, "% s \ n", nombre_explicativo (ruta_antigua, ruta_ nueva));
salida(1);
}

El error Funda
También es posible pasar un explícito error(3) valor, si primero debe hacer algo
procesamiento que perturbaría error, como la recuperación de errores:
if (renombrar (ruta_antigua, ruta_ nueva <0))
{
int old_errno = error;
...código esa perturba error...
fprintf (stderr, "% s \ n", explicar_errno_rename (antiguo_errno,
ruta_antigua, ruta_ nueva));
salida(1);
}

El Multihilo Casos
Algunas aplicaciones tienen varios subprocesos y, por lo tanto, no pueden compartir archivos internos de libexplain.
buffer. Puede suministrar su propio búfer usando
if (desvincular (nombre de ruta))
{
char mensaje [3000];
explicar_mensaje_unlink (mensaje, tamaño de(mensaje), nombre de ruta);
error_diálogo(mensaje);
devuelve -1;
}
Y para completar, ambos error(3) y seguro para subprocesos:
ssize_t nbytes = read (fd, data, sizeof (datos));
si (nbytes <0)
{
char mensaje [3000];
int old_errno = error;
...error recuperación...
explicar_mensaje_errno_leer (mensaje, tamaño de(mensaje),
old_errno, fd, data, sizeof (datos));
error_diálogo(mensaje);
devuelve -1;
}

Estos son reemplazos para estrerror_r(3), en sistemas que lo tengan.

Interfaz Azúcar
Un conjunto de funciones agregadas como funciones de conveniencia, para atraer a los programadores a usar el
biblioteca libexplain, resultan ser las funciones libexplain más utilizadas por el autor en
programas de línea de comando:
int fd = explicar_creat_or_die (nombre de archivo, 0666);
Esta función intenta crear un nuevo archivo. Si no puede, imprime un mensaje de error y
sale con EXIT_FAILURE. Si no hay ningún error, devuelve el nuevo descriptor de archivo.

Una función relacionada:
int fd = explicar_creación_en_error (nombre de archivo, 0666);
imprimirá el mensaje de error en caso de falla, pero también devolverá el resultado del error original, y
error(3) tampoco es molestado.

Todos las otros te llamadas
En general, cada llamada al sistema tiene su propio archivo de inclusión.
#incluirnombre .h>
que define prototipos de funciones para seis funciones:

· explicar_nombre ,

· Explicar_errno_nombre ,

· Explicar_mensaje_nombre ,

· Explicar_mensaje_errno_nombre ,

· explicar_nombre _o_die y

· explicar_nombre _en_error.

Cada prototipo de función tiene documentación de Doxygen, y esta documentación is no despojado
cuando se instalan los archivos de inclusión.

El esperar(2) la llamada al sistema (y amigos) tiene algunas variantes adicionales que también interpretan fallas
para ser un estado de salida que no es EXIT_SUCCESS. Esto aplica a te(3) y cerrar(3) como
bien.

La cobertura incluye 221 llamadas al sistema y 547 solicitudes ioctl. Hay muchos más sistemas
llamadas aún por implementar. Llamadas al sistema que nunca regresan, como salida(2), no están presentes
en la biblioteca, y nunca lo estará. los ejecutivo familia de llamadas al sistema en apoyado, porque
regresan cuando hay un error.

Gato
Así es como se vería un programa hipotético "gato", con informes completos de errores,
usando libexplain.
#incluir
#incluir
#incluir
Hay una inclusión para libexplain, además de los sospechosos habituales. (Si desea reducir el
carga del preprocesador, puede utilizar elnombre .h> incluye.)
hoyo estatico
proceso (ARCHIVO * fp)
{
para (;;)
{
tampón de carbón [4096];
size_t n = explicar_fread_or_die (búfer, 1, tamaño de (búfer), fp);
si (! n)
break;
explicar_fwrite_or_die (búfer, 1, n, salida estándar);
}
}
El La función copia un flujo de archivo a la salida estándar. Si ocurriera un error
para leer o escribir, se informa (y el nombre de la ruta se incluirá en el
error) y el comando sale con EXIT_FAILURE. Ni siquiera nos preocupamos por rastrear el
nombres de ruta, o pasándolos por la pila de llamadas.
int
principal (int argc, char ** argv)
{
para (;;)
{
int c = getopt (argc, argv, "o:");
si (c == EOF)
break;
interruptor (c)
{
caso 'o':
explicar_freopen_or_die (optarg, "w", stdout);
break;
La parte divertida de este código es que libexplain puede informar errores de alta calidad que incluyen las ruta incluso
si tu Rechazar Vuelva a abrir explícitamente stdout como se hace aquí. Ni siquiera nos preocupamos por
seguimiento del nombre del archivo.
por defecto:
fprintf (stderr, "Uso:% ss [-o ] ...\norte",
argv [0]);
devuelve EXIT_FAILURE;
}
}
si (optind == argc)
proceso (stdin);
más
{
while (optind <argc)
{
ARCHIVO * fp = explicar_fopen_o_die (argv [optind] ++, "r");
proceso (fp);
explicar_fclose_o_die (fp);
}
}
La salida estándar se cerrará implícitamente, pero demasiado tarde para que se genere un informe de error.
emitido, así que lo hacemos aquí, en caso de que la E / S almacenada en búfer no haya escrito nada todavía, y
hay un error ENOSPC o algo así.
explicar_fflush_or_die (stdout);
devolver EXIT_SUCCESS;
}
Eso es todo. Informe de errores completo, código claro.

Rusty Escala of Interfaz Bondad
Para aquellos de ustedes que no están familiarizados con él, Rusty Russel "¿Cómo hago para que esto sea difícil de usar incorrectamente?"
La página es una lectura obligada para los diseñadores de API.
http://ozlabs.org/~rusty/index.cgi/tech/2008‐03‐30.html

10. Es imposible a obtener equivocada.

Las metas deben establecerse altas, ambiciosamente altas, para que no las cumpla y piense que lo está haciendo.
terminado cuando tú no lo estás.

La biblioteca libexplain detecta punteros falsos y muchos otros parámetros de llamada al sistema falsos,
y, en general, trata de evitar las segmentaciones incluso en las circunstancias más difíciles.

La biblioteca libexplain está diseñada para ser segura para subprocesos. Es probable que el uso en el mundo real
revelar lugares que se pueden mejorar.

El mayor problema es con los propios nombres de las funciones. Porque C no tiene
espacios de nombres, la biblioteca libexplain siempre usa un prefijo de nombre de explicación. Este es el
forma tradicional de crear un pseudo-espacio-nombre para evitar conflictos de símbolos.
Sin embargo, da como resultado algunos nombres que suenan poco naturales.

9. El compilador or izquierda no se dejar Usted obtener it equivocada.

Un error común es utilizar explica_open donde se pretendía explicar_open_or_die.
Afortunadamente, el compilador a menudo emitirá un error de tipo en este punto (p.ej no puedo asignar
const char * rvalue a un int lvalue).

8. El compilador seguirá advertir if Usted obtener it equivocada.

Si se usa el nombre_explicativo cuando estaba previsto el nombre_explicativo_or_die, esto puede causar otros
problemas. GCC tiene un útil atributo de función warn_unused_result, y libexplain
la biblioteca lo adjunta a todos los explicaciones_nombre llamadas a funciones para producir una advertencia cuando
comete este error. Combine esto con gcc -Error para promover esto al nivel 9 de bondad.

7. El obvio utilizan el is (probablemente) las correcta uno.

Los nombres de las funciones se han elegido para transmitir su significado, pero esto no siempre es
exitoso. Mientras explica_nombre _o_muere y explica_nombre _on_error son bastante descriptivos,
las variantes seguras para subprocesos menos utilizadas son más difíciles de decodificar. Los prototipos de funciones ayudan al
compilador hacia la comprensión, y los comentarios de Doxygen en los archivos de encabezado ayudan al usuario
hacia la comprensión.

6. El nombre decirles Usted cómo a utilizan el él.

Es particularmente importante leer explique_nombre _o_die como "explicar (nombre o morir)".
El uso de un prefijo de espacio de nombres explícito consistente tiene algunos efectos secundarios desafortunados en el
departamento de obviedad, también.

El orden de las palabras en los nombres también indica el orden de los argumentos. El argumento
listas siempre final con los mismos argumentos que se pasaron a la llamada al sistema; todos of ellos. Si
_errno_ aparece en el nombre, su argumento siempre precede a los argumentos de la llamada al sistema. Si
_mensaje_ aparece en el nombre, sus dos argumentos siempre van primero.

5. Do it Derecho or it seguirá romper at tiempo de ejecución.

La biblioteca libexplain detecta punteros falsos y muchos otros parámetros de llamada al sistema falsos,
y generalmente trata de evitar segfaults incluso en las circunstancias más difíciles. Debería
nunca se rompa en tiempo de ejecución, pero un uso más real sin duda mejorará esto.

Algunos mensajes de error están dirigidos a desarrolladores y mantenedores en lugar de a usuarios finales, ya que esto
puede ayudar con la resolución de errores. No es tanto "descanso en tiempo de ejecución" como "ser informativo en
runtime ”(después de la llamada al sistema barfs).

4. Seguir común convención y y obtener it tenía razón.

Debido a que C no tiene espacios de nombres, la biblioteca libexplain siempre usa un nombre de explicación
prefijo. Esta es la forma tradicional de crear un pseudo-espacio-nombre para evitar
conflictos de símbolos.

Los argumentos finales de todas las llamadas libexplain son idénticos a la llamada al sistema que
están describiendo. Esto tiene la intención de proporcionar una convención coherente en común con el
el sistema se llama a sí mismo.

3. Leer las documentación y y obtener it tenía razón.

La biblioteca libexplain tiene como objetivo tener documentación completa de Doxygen para todos y cada uno
llamada API pública (e internamente también).

MENSAJE RINCÓN DE


Trabajar en libexplain es un poco como mirar la parte inferior de su automóvil cuando está encendido
el polipasto en el mecánico. Hay algunas cosas feas debajo, además de barro y mugre, y
los usuarios rara vez lo ven. Un buen mensaje de error debe ser informativo, incluso para un usuario que
ha tenido la suerte de no tener que mirar la parte inferior muy a menudo, y también
informativo para el mecánico que escucha la descripción del usuario por teléfono. Este es
no es una tarea fácil.

Revisando nuestro primer ejemplo, al código le gustaría esto si usa libexplain:
int fd = explicar_open_o_die ("algo / cosa", O_RDONLY, 0);
fallará con un mensaje de error como este
open (pathname = "some / file", flags = O_RDONLY) falló, no existe tal archivo o directorio
(2, ENOENT) porque no hay "algún" directorio en el directorio actual
Esto se divide en tres partes
llamada al sistema ha fallado, error del sistema porque
explicación

Antes Gracias
Es posible ver la parte del mensaje antes de "porque" como demasiado técnica para no
usuarios técnicos, principalmente como resultado de imprimir con precisión el sistema se llama a sí mismo en el
comienzo del mensaje de error. Y parece que rastro(1) salida, para geek extra
puntos.
open (pathname = "some / file", flags = O_RDONLY) falló, no existe tal archivo o directorio
(2, ENENTO)
Esta parte del mensaje de error es esencial para el desarrollador cuando escribe el código.
e igualmente importante para el mantenedor que tiene que leer informes de errores y corregir errores en el
código. Dice exactamente lo que falló.

Si este texto no se presenta al usuario, el usuario no puede copiarlo y pegarlo en un
informe de error, y si no está en el informe de error, el mantenedor no puede saber qué fue realmente
equivocada.

Con frecuencia, el personal técnico utilizará rastro(1) o braguero(1) para obtener esta información exacta, pero
esta vía no está abierta al leer informes de errores. El sistema del reportero de errores está lejos
lejos y, a estas alturas, en un estado muy diferente. Por lo tanto, esta información debe estar en el
informe de error, lo que significa que debe estar en el mensaje de error.

La representación de la llamada al sistema también da contexto al resto del mensaje. Si necesita
surge, el argumento de llamada al sistema infractor puede ser mencionado por su nombre en la explicación
después de "porque". Además, todas las cadenas están completamente entre comillas y son cadenas de C de escape, por lo que
Las nuevas líneas incrustadas y los caracteres que no se imprimen no harán que el terminal del usuario se apague.
loco.

El error del sistema es lo que sale de estruendo(2), más el símbolo de error. Impaciente y
Los administradores de sistemas expertos podrían dejar de leer en este punto, pero la experiencia del autor hasta la fecha es
que leer más es gratificante. (Si no es gratificante, probablemente sea un área de
libexplique que se puede mejorar. Las contribuciones al código son bienvenidas, por supuesto).

Después Gracias
Esta es la parte del mensaje de error dirigida a usuarios no técnicos. Mira más allá
el sistema simple llama a argumentos y busca algo más específico.
no hay "algún" directorio en el directorio actual
Esta parte intenta explicar la causa próxima del error en un lenguaje sencillo, y
Es aquí donde la internacionalización es fundamental.

En general, la política es incluir la mayor cantidad de información posible, para que el usuario
no necesita buscarlo (y no lo deja fuera del informe de error).

Internacionalización
La mayoría de los mensajes de error de la biblioteca libexplain se han internacionalizado. Allí
todavía no hay localizaciones, por lo que si desea las explicaciones en su idioma nativo,
por favor contribuya.

El calificativo de "la mayoría de", anterior, se relaciona con el hecho de que la prueba de concepto
la implementación no incluyó el apoyo a la internacionalización. El código base está siendo
revisado progresivamente, generalmente como resultado de la refactorización de mensajes para que cada error
La cadena de mensajes aparece en el código exactamente una vez.

Se han previsto idiomas que necesiten ensamblar las porciones de
llamada al sistema ha fallado, error del sistema porque explicación
en diferentes órdenes para corregir la gramática en los mensajes de error localizados.

Autopsia
Hay ocasiones en las que un programa aún tiene que usar libexplain y no puedes usar rastro(1)
cualquiera. Hay un explicar(1) comando incluido con libexplain que se puede utilizar para
descifrar los mensajes de error, si el estado del sistema subyacente no ha cambiado demasiado.
$ explicar rebautizar foo / tmp / bar / baz -e ENOENTE
cambio de nombre (oldpath = "foo", newpath = "/ tmp / bar / baz") falló, no existe tal archivo o directorio
(2, ENOENT) porque no hay un directorio "bar" en la nueva ruta "/ Tmp"directorio
$
Observe cómo se resuelve la ambigüedad de la ruta utilizando el nombre del argumento de la llamada al sistema. De
Por supuesto, debe conocer el error y la llamada al sistema para explicar(1) para ser útil. Como un
Aparte, esta es una de las formas utilizadas por el conjunto de pruebas automático libexplain para verificar que
libexplain está funcionando.

Filosofía
"Cuéntame todo, incluidas las cosas que no sabía que debía buscar".

La biblioteca se implementa de tal manera que cuando está vinculada estáticamente, solo el código que
el uso real estará vinculado. Esto se logra al tener una función por archivo fuente,
siempre que sea posible.

Cuando sea posible proporcionar más información, libexplain lo hará. Cuanto menos el usuario
tiene que rastrear por sí mismos, mejor. Esto significa que los UID van acompañados del
nombre de usuario, los GID van acompañados del nombre del grupo, los PID van acompañados del proceso
el nombre, los descriptores de archivo y las transmisiones van acompañados del nombre de la ruta, etc..

Al resolver rutas, si no existe un componente de ruta, libexplain buscará similares
nombres, con el fin de sugerir alternativas a los errores tipográficos.

La biblioteca libexplain intenta utilizar la menor cantidad de montón posible y, por lo general, ninguno. Este es
para evitar perturbar el estado del proceso, en la medida de lo posible, aunque a veces es
inevitable.

La biblioteca libexplain intenta ser segura para subprocesos, evitando variables globales, manteniendo
Estado en la pila tanto como sea posible. Hay un único búfer de mensajes común y el
las funciones que lo utilizan están documentadas como no seguras para subprocesos.

La biblioteca libexplain no perturba los manejadores de señales de un proceso. Esto hace
determinar si un puntero haría un error de segmentación en un desafío, pero no imposible.

Cuando la información está disponible a través de una llamada al sistema, así como disponible a través de un / proc
entrada, se prefiere la llamada al sistema. Esto es para evitar perturbar el estado del proceso.
También hay ocasiones en las que no hay descriptores de archivo disponibles.

La biblioteca libexplain está compilada con soporte para archivos grandes. No hay grandes / pequeños
esquizofrenia. Cuando esto afecte a los tipos de argumentos en la API, se emitirá un error
si las definiciones de archivo grande necesarias están ausentes.

FIXME: Es necesario trabajar para asegurarse de que las cuotas del sistema de archivos se manejen en el código. Esta
se aplica a algunos obtener límite(2) límites también.

Hay casos en los que los caminos de los parientes no son informativos. Por ejemplo: demonios del sistema,
servidores y procesos en segundo plano. En estos casos, se utilizan rutas absolutas en el error.
Explicaciones.

TRAYECTORIA RESOLUCIÓN


Versión corta: ver resolución_ruta(7).

Versión larga: la mayoría de los usuarios nunca han oído hablar de resolución_ruta(7) y muchos usuarios avanzados
nunca lo he leído. Aquí hay una versión anotada:

paso 1: Inicio of las resolución
Si el nombre de la ruta comienza con el carácter de barra inclinada (“/”), el directorio de búsqueda inicial es
el directorio raíz del proceso de llamada.

Si el nombre de la ruta no comienza con el carácter de barra ("/"), la búsqueda inicial
directorio del proceso de resolución es el directorio de trabajo actual del proceso.

paso 2: Caminar a lo largo de las camino
Establezca el directorio de búsqueda actual en el directorio de búsqueda inicial. Ahora, para cada no
componente final del nombre de la ruta, donde un componente es una subcadena delimitada por una barra ("/")
caracteres, este componente se busca en el directorio de búsqueda actual.

Si el proceso no tiene permiso de búsqueda en el directorio de búsqueda actual, un EACCES
se devuelve el error ("Permiso denegado").
open (pathname = "/home/archives/.ssh/private_key", flags = O_RDONLY) falló,
Permiso denegado (13, EACCES) porque el proceso no tiene permiso de búsqueda
al directorio de nombre de ruta "/home/archives/.ssh", el proceso efectivo GID 1000
"pmiller" no coincide con el propietario del directorio 1001 "archivos", por lo que el propietario
el modo de permiso "rwx" se ignora, el modo de permiso de los demás es "---", y el
el proceso no tiene privilegios (no tiene la capacidad DAC_READ_SEARCH)

Si no se encuentra el componente, se devuelve un error ENOENT ("No existe tal archivo o directorio").
unlink (pathname = "/ home / microsoft / rubbish") falló, no existe tal archivo o directorio (2,
ENOENT) porque no hay un directorio "microsoft" en el nombre de la ruta "/ home"directorio

También hay algo de soporte para los usuarios cuando escriben mal los nombres de ruta, haciendo sugerencias cuando
ENOENT se devuelve:
open (pathname = "/user/include/fcntl.h", flags = O_RDONLY) falló, no existe tal archivo o
directorio (2, ENOENT) porque no hay un directorio de "usuario" en el nombre de ruta "/"
directorio, ¿te refieres al directorio "usr" en su lugar?

Si se encuentra el componente, pero no es un directorio ni un enlace simbólico, un ENOTDIR
se devuelve el error ("No es un directorio").
open (pathname = "/home/pmiller/.netrc/lca", flags = O_RDONLY) falló, no es un
directorio (20, ENOTDIR) porque el archivo normal ".netrc" en el nombre de ruta
El directorio "/ home / pmiller" se está utilizando como directorio cuando no

Si el componente se encuentra y es un directorio, configuramos el directorio de búsqueda actual en ese
directorio y vaya al siguiente componente.

Si se encuentra el componente y es un enlace simbólico (enlace simbólico), primero resolvemos este
enlace (con el directorio de búsqueda actual como directorio de búsqueda inicial). En caso de error, eso
se devuelve el error. Si el resultado no es un directorio, se devuelve un error ENOTDIR.
unlink (pathname = "/ tmp / colgando / basura") falló, no existe tal archivo o directorio (2,
ENOENT) porque el enlace simbólico "colgante" en el nombre de la ruta "/ Tmp"directorio
se refiere a "ninguna parte" que no existe
Si la resolución del enlace simbólico es exitosa y devuelve un directorio, establecemos el actual
busque el directorio a ese directorio y vaya al siguiente componente. Tenga en cuenta que el
El proceso de resolución aquí implica recursividad. Para proteger el kernel contra la pila
desbordamiento, y también para proteger contra la denegación de servicio, hay límites en el máximo
profundidad de recursividad, y sobre el número máximo de enlaces simbólicos seguidos. Un error ELOOP es
devuelto cuando se supera el máximo ("Demasiados niveles de enlaces simbólicos").
open (pathname = "/ tmp / dangling", flags = O_RDONLY) falló, demasiados niveles de
enlaces simbólicos (40, ELOOP) porque se encontró un bucle de enlace simbólico en
nombre de ruta, comenzando en "/ tmp / colgando"
También es posible obtener un error ELOOP o EMLINK si hay demasiados enlaces simbólicos, pero no
Se detectó bucle.
open (pathname = "/ tmp / rabbit-hole", flags = O_RDONLY) falló, demasiados niveles de
enlaces simbólicos (40, ELOOP) porque se encontraron demasiados enlaces simbólicos en
nombre de ruta (8)
Observe cómo también se imprime el límite real.

paso 3: Encuentre las final entrada
La búsqueda del componente final del nombre de ruta es igual que la de todos los demás
componentes, como se describe en el paso anterior, con dos diferencias:

(i) El componente final no necesita ser un directorio (al menos en cuanto a la resolución de la ruta
el proceso se refiere. Puede que tenga que ser un directorio, o un no directorio, debido a
los requisitos de la llamada al sistema específica).

(Ii)
No es necesariamente un error si no se encuentra el componente final; tal vez solo somos
creándolo. Los detalles sobre el tratamiento de la entrada final se describen en el
páginas de manual de las llamadas al sistema específicas.

(iii)
También es posible tener un problema con el último componente si es un enlace simbólico
y no debe seguirse. Por ejemplo, usando el habiertos(2) Bandera O_NOFOLLOW:
open (pathname = "a ‐ symlink", flags = O_RDONLY | O_NOFOLLOW) falló, demasiados niveles de
enlaces simbólicos (ELOOP) porque se especificó O_NOFOLLOW pero el nombre de ruta se refiere a un
enlace simbólico

(iv)
Es común que los usuarios cometan errores al escribir nombres de rutas. La biblioteca libexplain
intenta hacer sugerencias cuando se devuelve ENOENT, por ejemplo:
open (pathname = "/usr/include/filecontrl.h", flags = O_RDONLY) falló, No existe tal archivo o
directorio (2, ENOENT) porque no hay un archivo regular "filecontrl.h" en el nombre de la ruta
"/ usr / include"directorio, ¿te refieres al archivo normal" fcntl.h "en su lugar?

(v) También es posible que se requiera que el componente final sea algo diferente a un
archivo regular:
readlink (pathname = "just-a-file", data = 0x7F930A50, data_size = 4097) falló,
Argumento no válido (22, EINVAL) porque el nombre de ruta es un archivo normal, no un enlace simbólico

(vi)
FIXME: manejo del bit "t".

Límites
Hay una serie de límites con respecto a los nombres de rutas y archivos.

Límite de longitud del nombre de ruta
Hay una longitud máxima para los nombres de ruta. Si el nombre de la ruta (o algún intermedio
ruta obtenida al resolver enlaces simbólicos) es demasiado larga, un ENAMETOOLONG
se devuelve el error ("Nombre de archivo demasiado largo"). Observe cómo se incluye el límite del sistema
en el mensaje de error.
abierto (nombre de ruta = "muy largo", flags = O_RDONLY) falló, nombre de archivo demasiado largo (36,
ENAMETOOLONG) porque el nombre de la ruta excede la longitud máxima de la ruta del sistema (4096)

Límite de longitud del nombre de archivo
Algunas variantes de Unix tienen un límite en el número de bytes en cada componente de ruta.
Algunos de ellos se ocupan de esto en silencio, y otros dan ENAMETOOLONG; la biblioteca explica
usos de la biblioteca rutaconf(3) _PC_NO_TRUNC para saber cuál. Si ocurre este error, el
La biblioteca libexplain indicará el límite en el mensaje de error, el límite es
obtenido de rutaconf(3) _PC_NAME_MAX. Observe cómo se incluye el límite del sistema
en el mensaje de error.
abierto (nombre de ruta = "system7 / solo-tenía-14-caracteres", flags = O_RDONLY) falló, Archivo
nombre demasiado largo (36, ENAMETOOLONG) porque el componente "only-had-14-characters" es
más largo que el límite del sistema (14)

Nombre de ruta vacío
En el Unix original, la ruta vacía se refería al directorio actual.
Hoy en día, POSIX decreta que un nombre de ruta vacío no debe resolverse con éxito.
open (pathname = "", flags = O_RDONLY) falló, no existe tal archivo o directorio (2,
ENOENT) porque POSIX decreta que un nombre de ruta vacío no debe resolverse
lograr

Permisos
Los bits de permiso de un archivo constan de tres grupos de tres bits. El primer grupo de
tres se utiliza cuando el ID de usuario efectivo del proceso de llamada es igual al ID de propietario del
expediente. El segundo grupo de tres se utiliza cuando el ID de grupo del archivo es igual al
ID de grupo efectivo del proceso de llamada, o es uno de los ID de grupo suplementarios del
proceso de llamada. Cuando ninguno de los dos se mantiene, se utiliza el tercer grupo.
abierto (nombre de ruta = "/ Etc / passwd", flags = O_WRONLY) falló, Permiso denegado (13,
EACCES) porque el proceso no tiene permiso de escritura para el "passwd" regular
archivo en el nombre de ruta "/ Etc"directorio, el proceso efectivo UID 1000" pmiller "
no coincide con el propietario del archivo normal 0 "raíz", por lo que el modo de permiso de propietario "rw-"
se ignora, el modo de permiso de los demás es "r--" y el proceso no tiene privilegios
(no tiene la capacidad DAC_OVERRIDE)
Se da un espacio considerable a esta explicación, ya que la mayoría de los usuarios no saben que
así es como funciona el sistema de permisos. En particular: el propietario, el grupo y otros
los permisos son exclusivos, no se “O” ed juntos.

EXTRAÑO Y INTERESANTE SISTEMA LLAMADAS


El proceso de escribir un controlador de errores específico para cada llamada al sistema a menudo revela
peculiaridades interesantes y condiciones de contorno, u oscuras error(3) valores.

ENOMEDIO, No mediano encontrado
El acto de copiar un CD fue la fuente del título de este artículo.
$ dd si = / dev / cdrom de = fubar.iso
dd: opening "/ dev / cdrom": no se encontró ningún medio
$
El autor se preguntó por qué su computadora le decía que no existe tal cosa como un psíquico.
medio. Aparte del hecho de que un gran número de hablantes nativos de inglés no son
incluso consciente de que "media" es un plural, y mucho menos que "medium" es su singular, la cadena
devuelto por estruendo(3) porque ENOMEDIUM es tan conciso que está casi completamente libre de
contenido.

Cuándo habiertos(2) devuelve ENOMEDIUM sería bueno si la biblioteca libexplain pudiera expandir un
poco sobre esto, según el tipo de unidad que sea. Por ejemplo:
... porque no hay ningún disco en la disquetera
... porque no hay ningún disco en la unidad de CD ‐ ROM
... porque no hay cinta en la unidad de cinta
... porque no hay tarjeta de memoria en el lector de tarjetas

Y así sucedió...
open (pathname = "/ dev / cdrom", flags = O_RDONLY) falló, No se encontró medio (123,
ENOMEDIO) porque no parece haber un disco en la unidad de CD-ROM
El truco, que el autor no conocía anteriormente, consistía en abrir el dispositivo con el
Indicador O_NONBLOCK, que le permitirá abrir una unidad sin medio. Entonces tú
problema específico del dispositivo ioctl(2) solicitudes hasta que descubras qué diablos es. (No
seguro si esto es POSIX, pero también parece funcionar de esa manera en BSD y Solaris, según
las madera(1) fuentes.)

Tenga en cuenta también los diferentes usos de "disco" y "disco" en contexto. El estándar CD se originó
en Francia, pero todo lo demás tiene una "k".

EFECTO, Malo dirección
Cualquier llamada al sistema que tome un argumento de puntero puede devolver EFAULT. La biblioteca libexplain
puede averiguar qué argumento tiene la culpa y lo hace sin perturbar el proceso
(o hilo) manejo de señales.

Cuando esté disponible, el mínimo(2) se utiliza la llamada al sistema para preguntar si la región de memoria es válida.
Puede devolver tres resultados: mapeado pero no en la memoria física, mapeado y en física
memoria, y no mapeado. Al probar la validez de un puntero, los dos primeros son "sí"
y el último es "no".

Verificar cadenas de C es más difícil, porque en lugar de un puntero y un tamaño, solo
tener un puntero. Para determinar el tamaño tendríamos que encontrar el NUL, y eso podría
segfault, catch-22.

Para solucionar este problema, la biblioteca libexplain utiliza la lstat(2) llamada sysem (con un conocido
buen segundo argumento) para probar la validez de las cadenas C. Un retorno de falla && errno == EFAULT
es un "no", y cualquier otra cosa es un "sí". Esto, por supuesto, limita las cadenas a PATH_MAX
caracteres, pero eso generalmente no es un problema para la biblioteca libexplain, porque eso es
casi siempre las cadenas más largas que le interesan.

EMFILE, de más muchos habiertos archivos
Este error ocurre cuando un proceso ya tiene abierto el número máximo de descriptores de archivo.
Si se va a imprimir el límite real y la biblioteca libexplain intenta hacerlo, no puede abrir
un archivo en / proc para leer lo que es.
open_max = sysconf (_SC_OPEN_MAX);
Este no es tan difícil, hay un configuración del sistema(3) forma de obtener el límite.

ENFILAR, de más muchos habiertos archivos in te
Este error se produce cuando se ha superado el límite del sistema sobre el número total de archivos abiertos.
alcanzó. En este caso no es útil configuración del sistema(3) forma de obtener el límite.

Profundizando, uno puede descubrir que en Linux hay un / proc entrada que podríamos leer
obtener este valor. Catch-22: no tenemos descriptores de archivo, por lo que no podemos abrir un archivo para
leer el límite.

En Linux hay una llamada al sistema para obtenerlo, pero no tiene la función de envoltura [e] glibc, por lo que
tienes que hacerlo todo con mucho cuidado:
Corto
explicar_archivo_máx (vacío)
{
#ifdef __linux__
estructura __sysctl_args argumentos;
int32_t maxfile;
tamaño_t maxfile_size = tamaño de(archivo máximo);
int nombre [] = {CTL_FS, FS_MAXFILE};
memset (& args, 0, tamaño de (estructura __sysctl_args));
args.name = nombre;
argumentos.nlen = 2;
args.oldval = & maxfile;
args.oldlenp = & maxfile_size;
if (syscall (SYS__sysctl, & args)> = 0)
devuelve maxfile;
#terminara si
devuelve -1;
}
Esto permite incluir el límite en el mensaje de error, cuando esté disponible.

EINVAL "Inválido argumento" vs ENÓSYS "Función no implementado"
Acciones no admitidas (como enlace simbólico(2) en un sistema de archivos FAT) no se informa
consistentemente de una llamada al sistema a la siguiente. Es posible tener EINVAL o
ENOSYS regresó.

Como resultado, se debe prestar atención a estos casos de error para corregirlos, particularmente
ya que EINVAL también podría referirse a problemas con uno o más argumentos de llamada al sistema.

Note esa error(3) is no hacerlo set
Hay ocasiones en las que es necesario leer las fuentes de [e] glibc para determinar cómo y
cuando se devuelven errores para algunas llamadas al sistema.

miedo(3) archivono(3)
A menudo se supone que estas funciones no pueden devolver un error. Esto solo es cierto si
las stream argumento es vlido, sin embargo son capaces de detectar un invlido
puntero.

fpathconf(3) rutaconf(3)
El valor de retorno de fpathconf(2) y rutaconf(2) legítimamente podría ser -1, por lo que es
necesario para ver si error(3) se ha establecido explícitamente.

ioctl(2)
El valor de retorno de ioctl(2) legítimamente podría ser -1, por lo que es necesario ver si
error(3) se ha establecido explícitamente.

leerdir(3)
El valor de retorno de leerdir(3) es NULO tanto para los errores como para el final del archivo. Está
necesario para ver si error(3) se ha establecido explícitamente.

setbuf(3) establecer búfer(3) setlinebuf(3) setvbuf(3)
Todas estas funciones, excepto la última, devuelven vacías. Y setvbuf(3) solo se documenta como
devolviendo "distinto de cero" en caso de error. Es necesario ver si error(3) ha sido explícitamente
conjunto.

strtod(3) strtol(3) dicho(3) paseo(3) strtoul(3) strtoul(3)
Estas funciones devuelven 0 en caso de error, pero ese también es un valor de retorno legítimo. Está
necesario para ver si error(3) se ha establecido explícitamente.

ungetc(3)
Si bien el estándar ANSI C solo exige un único carácter de copia de seguridad,
que [e] glibc permite más ... pero eso significa que puede fallar con ENOMEM. Puede
también falla con EBADF si fp es falso. Lo más difícil de todo, si pasa EOF un error
se produce el retorno, pero no se establece errno.

La biblioteca libexplain detecta todos estos errores correctamente, incluso en los casos en que
los valores de error están mal documentados, en todo caso.

ENOSPC, No espacio izquierda on dispositivo
Cuando este error se refiere a un archivo en un sistema de archivos, la biblioteca libexplain imprime el montaje
punto del sistema de archivos con el problema. Esto puede hacer que la fuente del error sea mucho
más claro.
escribir (fildes = 1 "ejemplo", datos = 0xbfff2340, tamaño_datos = 5) falló, no queda espacio
en el dispositivo (28, ENOSPC) porque el sistema de archivos que contiene los archivos ("/ home") no tiene
más espacio para los datos
A medida que se agrega compatibilidad con dispositivos más especiales, se espera que los mensajes de error incluyan el dispositivo
nombre y tamaño real del dispositivo.

EROF, Solo lectura presentar te
Cuando este error se refiere a un archivo en un sistema de archivos, la biblioteca libexplain imprime el montaje
punto del sistema de archivos con el problema. Esto puede hacer que la fuente del error sea mucho
más claro.

A medida que se agrega compatibilidad con dispositivos más especiales, se espera que los mensajes de error incluyan el dispositivo
nombre y tipo.
open (pathname = "/ dev / fd0", O_RDWR, 0666) falló, sistema de archivos de solo lectura (30, EROFS)
porque el disquete tiene la pestaña de protección contra escritura configurada

... porque no se puede escribir en un CD-ROM
... porque la tarjeta de memoria tiene la pestaña de protección contra escritura configurada
... porque la cinta magnética de ½ pulgada no tiene anillo de escritura

rebautizar
El rebautizar(2) la llamada al sistema se usa para cambiar la ubicación o el nombre de un archivo, moviéndolo
entre directorios si es necesario. Si el nombre de la ruta de destino ya existe, será
atómicamente reemplazado, de modo que no hay ningún punto en el que otro proceso que intente
acceder a él lo encontrará perdido.

Sin embargo, existen limitaciones: solo puede cambiar el nombre de un directorio encima de otro
directorio si el directorio de destino no está vacío.
el cambio de nombre (oldpath = "foo", newpath = "bar") falló, el directorio no está vacío (39,
ENOTEMPTY) porque newpath no es un directorio vacío; es decir, contiene entradas
que no sea "." y ".."
Tampoco puede cambiar el nombre de un directorio en la parte superior de un directorio que no sea.
cambio de nombre (oldpath = "foo", newpath = "bar") falló, No es un directorio (20, ENOTDIR)
porque oldpath es un directorio, pero newpath es un archivo normal, no un directorio
Tampoco se permite lo contrario
renombrar (oldpath = "foo", newpath = "bar") falló, es un directorio (21, EISDIR)
porque newpath es un directorio, pero oldpath es un archivo normal, no un directorio

Esto, por supuesto, hace que el trabajo de la biblioteca libexplain sea más complicado, porque el
desconectar(2) o rmdir(2) la llamada al sistema es llamada implícitamente por rebautizar(2), por lo que todos los
desconectar(2) o rmdir(2) los errores también deben detectarse y manejarse.

dup2
El dup2(2) la llamada al sistema se utiliza para crear un segundo descriptor de archivo que hace referencia al
mismo objeto que el primer descriptor de archivo. Por lo general, esto se usa para implementar la entrada de shell
y redirección de salida.

Lo divertido es que, al igual que rebautizar(2) puede cambiar el nombre de un archivo de forma atómica en la parte superior de un
archivo existente y elimine el archivo antiguo, dup2(2) puede hacer esto en un archivo ya abierto
descriptor

Una vez más, esto hace que el trabajo de la biblioteca libexplain sea más complicado, porque el Cerrar(2)
la llamada al sistema es llamada implícitamente por dup2(2), y así todos CerrarLos errores de (2) deben ser
detectado y manejado, también.

AVENTURAS IN IOCTL SOPORTE


El ioctl(2) la llamada al sistema proporciona a los autores de controladores de dispositivos una forma de comunicarse con
espacio de usuario que no se ajusta a la API del kernel existente. Ver lista_ioctl(2).

Descodificación SOLICITUD Números
De una mirada superficial al ioctl(2) interfaz, parecería haber una gran pero finita
número de posibles ioctl(2) solicitudes. Cada uno diferente ioctl(2) la solicitud es efectivamente
otra llamada al sistema, pero sin ningún tipo de seguridad en absoluto: el compilador no puede
programador hacerlo bien. Esta fue probablemente la motivación detrás tcflush(3) y
amigos.

La impresión inicial es que podrías decodificar ioctl(2) solicitudes usando un interruptor enorme
declaración. Esto resulta inviable porque uno descubre muy rápidamente que es
imposible incluir todos los encabezados del sistema necesarios que definen los distintos ioctl(2)
solicitudes, porque tienen dificultades para jugar bien entre ellos.

Una mirada más profunda revela que existe una variedad de números de solicitud "privados" y
Se anima a los autores de controladores a utilizarlos. Esto significa que hay una posibilidad mucho mayor
conjunto de solicitudes, con números de solicitud ambiguos, que son inmediatamente evidentes. También,
también hay algunas ambigüedades históricas.

Ya sabíamos que el cambio no era práctico, pero ahora sabemos que para seleccionar el
el nombre de la solicitud y la explicación apropiados, debemos considerar no solo el número de solicitud, sino
también el descriptor de archivo.

La implementación de ioctl(2) el soporte dentro de la biblioteca libexplain es tener una tabla de
punteros a ioctl(2) descriptores de solicitud. Cada uno de estos descriptores incluye un
puntero a una función de desambiguación.

Cada solicitud se implementa realmente en un archivo fuente separado, de modo que los
Los archivos de inclusión están exentos de la obligación de jugar bien con los demás.

Representación
La filosofía detrás de la biblioteca libexplain es proporcionar tanta información como
posible, incluida una representación precisa de la llamada al sistema. En el caso de
ioctl(2) esto significa imprimir el número de solicitud correcto (por nombre) y también un número correcto (o
al menos útil) representación del tercer argumento.

El ioctl(2) el prototipo se ve así:
int ioctl (int fildes, int request, ...);
que debería hacer sonar sus alarmas de seguridad de tipo. Interna de [e] glibc, esto se convierte
en una variedad de formas:
int __ioctl (int fildes, int request, long arg);
int __ioctl (int fildes, int request, void * arg);
y la interfaz syscall del kernel de Linux espera
asmlinkage long sys_ioctl (archivos int sin firmar, solicitud int sin firmar, sin firmar long
argumento);
La extrema variabilidad del tercer argumento es un desafío, cuando la biblioteca libexplain
intenta imprimir una representación de ese tercer argumento. Sin embargo, una vez que el número de solicitud
se ha eliminado la ambigüedad, cada entrada en la tabla ioctl de la biblioteca libexplain tiene un
función print_data personalizada (OO hecho manualmente).

Explicación
Hay menos problemas para determinar la explicación que se utilizará. Una vez que el número de solicitud
se ha eliminado la ambigüedad, cada entrada en la tabla ioctl de la biblioteca libexplain tiene un
Función print_explanation (nuevamente, OO hecho manualmente).

A diferencia de las llamadas al sistema de la sección 2 y la sección 3, la mayoría ioctl(2) las solicitudes no tienen errores
documentado. Esto significa que, para dar buenas descripciones de errores, es necesario leer el kernel
fuentes para descubrir

· qué error(3) se pueden devolver valores, y

· La causa de cada error.

Debido a la naturaleza OO del envío de llamadas a funciones dentro del kernel, debe leer
todos fuentes que implementan eso ioctl(2) solicitud, no solo la implementación genérica. Eso
Es de esperar que diferentes núcleos tengan diferentes números de error y sutilmente
diferentes causas de error.

EINVAL vs ENOTTY
La situación es aún peor para ioctl(2) solicitudes que para llamadas al sistema, con EINVAL y
ENOTTY ambos se utilizan para indicar que un ioctl(2) la solicitud es inapropiada porque
contexto, y ocasionalmente ENOSYS, ENOTSUP y EOPNOTSUPP (destinado a ser utilizado para sockets) como
bien. Hay comentarios en las fuentes del kernel de Linux que parecen indicar un progresivo
la limpieza está en curso. Para un caos adicional, BSD agrega ENOIOCTL a la confusión.

Como resultado, se debe prestar atención a estos casos de error para corregirlos, particularmente
ya que EINVAL también podría referirse a problemas con uno o más argumentos de llamada al sistema.

intptr_t
El estándar C99 define un tipo de entero que está garantizado para poder contener cualquier puntero
sin pérdida de representación.

El prototipo de syscall de la función anterior estaría mejor escrito
long sys_ioctl (archivos int sin firmar, solicitud int sin firmar, intptr_t arg);
El problema es la disonancia cognitiva inducida por dispositivos específicos o específicos del sistema de archivos.
ioctl(2) implementaciones, tales como:
long vfs_ioctl (archivo de estructura * filp, cmd int sin firmar, arg largo sin firmar);
La mayoría de los ioctl(2) las solicitudes en realidad tienen un tercer argumento int * arg. Pero tenerlo
declarado long conduce a que el código trate esto como long * arg. Esto es inofensivo en 32 bits
(tamaño de (largo) == tamaño de (int)) pero desagradable en 64 bits (tamaño de (largo)! = tamaño de (int)).
Dependiendo de la endianidad, obtienes o no el valor que esperas, pero hacerlo obtener
un garabato de memoria o un garabato de pila también.

Escribiendo todos estos como
int ioctl (int fildes, int request, ...);
int __ioctl (int fildes, int request, intptr_t arg);
long sys_ioctl (archivos int sin firmar, solicitud int sin firmar, intptr_t arg);
long vfs_ioctl (archivo de estructura * filp, unsigned int cmd, intptr_t arg);
enfatiza que el número entero es solo un número entero para representar una cantidad que es casi
siempre un tipo de puntero no relacionado.

CONCLUSIÓN


Utilice libexplain, a sus usuarios les gustará.

DERECHOS DE AUTOR


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

Utiliceexplique_lca2010 en línea utilizando los servicios de onworks.net


Servidores y estaciones de trabajo gratuitos

Descargar aplicaciones de Windows y Linux

  • 1
    TRAGO
    TRAGO
    SWIG es una herramienta de desarrollo de software
    que conecta programas escritos en C y
    C ++ con una variedad de alto nivel
    lenguajes de programación. SWIG se utiliza con
    diferente...
    Descargar SWIG
  • 2
    WooCommerce Nextjs reaccionar tema
    WooCommerce Nextjs reaccionar tema
    Tema React WooCommerce, creado con
    Siguiente JS, Webpack, Babel, Node y
    Express, usando GraphQL y Apollo
    Cliente. Tienda WooCommerce en React(
    contiene: Productos...
    Descargar el tema WooCommerce Nextjs React
  • 3
    archlabs_repo
    archlabs_repo
    Paquete de repositorio para ArchLabs Este es un
    aplicación que también se puede buscar
    en
    https://sourceforge.net/projects/archlabs-repo/.
    Ha sido alojado en OnWorks en...
    Descargar archlabs_repo
  • 4
    Proyecto Zephyr
    Proyecto Zephyr
    El Proyecto Zephyr es una nueva generación
    sistema operativo en tiempo real (RTOS) que
    soporta múltiples hardware
    arquitecturas. Se basa en un
    kernel de tamaño reducido ...
    Descargar Proyecto Zephyr
  • 5
    Desventajas
    Desventajas
    SCons es una herramienta de construcción de software
    que es una alternativa superior a la
    herramienta de compilación clásica "Make" que
    todos conocemos y amamos. SCons es
    implementó un ...
    Descargar SCons
  • 6
    PSeInt
    PSeInt
    PSeInt es un intérprete de pseudocódigo para
    estudiantes de programación de habla hispana.
    Su propósito principal es ser una herramienta para
    aprendiendo y entendiendo lo básico
    concepto ...
    Descargar PSeInt
  • Más "

Comandos de Linux

  • 1
    7z
    7z
    7z - Un archivador de archivos con la más alta
    índice de compresión ...
    Ejecutar 7z
  • 2
    7za
    7za
    7za - Un archivador de archivos con la más alta
    índice de compresión ...
    Ejecutar 7za
  • 3
    espeluznante
    espeluznante
    CREEPY - Una información de geolocalización
    agregador DESCRIPCIÓN: espeluznante es un
    aplicación que te permite recopilar
    información relacionada con la geolocalización de
    usuarios de...
    correr espeluznante
  • 4
    compilación de cricket
    compilación de cricket
    grillo - Un programa para gestionar el
    recopilación y visualización de series temporales
    datos ...
    Ejecutar compilación de cricket
  • 5
    g-wrap-config
    g-wrap-config
    g-wrap-config - secuencia de comandos para obtener
    información sobre la versión instalada
    de G-Wrap...
    Ejecute g-wrap-config
  • 6
    g.accessgrass
    g.accessgrass
    g.access - Controla el acceso a la
    conjunto de mapas actual para otros usuarios en el
    sistema. Si no se da ninguna opción, imprime
    estado actual. PALABRAS CLAVE: general, mapa
    gestión, p ...
    Ejecutar g.accessgrass
  • Más "

Ad