mac - ¿Qué puede hacer que un ejecutivo falle? ¿Qué pasa después?
exec() javascript (5)
Desde la página del manual de exec(3)
:
Las
execle()
execl()
,execle()
,execlp()
,execvp()
yexecvP()
pueden fallar y establecer errno para cualquiera de los errores especificados para las funciones de bibliotecaexecve(2)
ymalloc(3)
.La función
execv()
puede fallar y establecer errno para cualquiera de los errores especificados para la función de bibliotecaexecve(2)
.
Y luego desde la página de manual de execve(2)
:
ERRORES
Execve()
fallará y volverá al proceso de llamada si:
[E2BIG]
- El número de bytes en la lista de argumentos del nuevo proceso es mayor que el límite impuesto por el sistema. Este límite se especifica mediante la variable de MIB desysctl(3)
KERN_ARGMAX
.[EACCES]
- Se deniega el permiso de búsqueda para un componente del prefijo de ruta.[EACCES]
- El nuevo archivo de proceso no es un archivo ordinario.[EACCES]
- El nuevo modo de archivo de proceso niega el permiso de ejecución.[EACCES]
: el nuevo archivo de proceso se encuentra en un sistema de archivos montado con la ejecución deshabilitada (MNT_NOEXEC
en<sys/mount.h>
).[EFAULT]
: el nuevo archivo de proceso no es tan largo como lo indican los valores de tamaño en su encabezado.[EFAULT]
: la ruta, argv o envp apuntan a una dirección ilegal.[EIO]
: se produjo un error de E / S al leer del sistema de archivos.[ELOOP]
- Se encontraron demasiados enlaces simbólicos al traducir la ruta de acceso. Esto se considera indicativo de un enlace simbólico en bucle.[ENAMETOOLONG]
: un componente de una ruta excedió los caracteres{NAME_MAX}
, o un nombre de ruta completo excedió los caracteres{PATH_MAX}
.[ENOENT]
- El nuevo archivo de proceso no existe.[ENOEXEC]
- El nuevo archivo de proceso tiene el permiso de acceso apropiado, pero tiene un formato no reconocido (por ejemplo, un número mágico no válido en su encabezado).[ENOMEM]
- El nuevo proceso requiere más memoria virtual de la que permite el máximo impuesto (getrlimit(2)
).[ENOTDIR]
- Un componente del prefijo de ruta no es un directorio.[ETXTBSY]
: el nuevo archivo de proceso es un archivo de procedimiento puro (texto compartido) que actualmente está abierto para escritura o lectura mediante algún proceso.
malloc()
es mucho menos complicado y solo utiliza ENOMEM
. Desde la malloc(3) man page
:
Si tiene éxito, las
calloc()
,malloc()
,realloc()
,reallocf()
yvalloc()
devuelven un puntero a la memoria asignada. Si hay un error, devuelven un punteroNULL
y establecenerrno
enENOMEM
.
¿Cuáles son las razones por las que un exec (execl, execlp, etc.) puede fallar? Si realiza una llamada a exec y vuelve, ¿existen otras prácticas que no sean solo el pánico y la salida?
El problema con el manejo de la falla de exec
es que usualmente exec
se realiza en un proceso secundario, y usted quiere hacer el manejo de errores en el proceso padre Pero no puede simplemente exit(errno)
porque (1) no sabe si los códigos de error caben en un código de salida, y (2), no puede distinguir entre los códigos de salida exec
y los códigos de salida de falla del nuevo programa usted exec
La mejor solución que conozco es usar tuberías para comunicar el éxito o el fracaso de un exec
:
- Antes de bifurcar, abra una tubería en el proceso padre.
- Después de bifurcar, el padre cierra el extremo de escritura de la tubería y lee desde el extremo de lectura.
- El niño cierra el final de lectura y establece el indicador de cierre de ejecución para el final de escritura.
- El niño llama exec.
- Si exec falla, el hijo vuelve a escribir el código de error en el padre utilizando la canalización, luego sale.
- El padre lee eof (una lectura de longitud cero) si el hijo ejecutó con éxito
exec
, ya que close-on-exec hizo queexec
cierre el extremo de escritura de la tubería. O, si elexec
falló, el padre lee el código de error y puede proceder en consecuencia. De cualquier manera, el padre bloquea hasta que el hijo llama aexec
. - El padre cierra el extremo de lectura de la tubería.
Exec siempre debe tener éxito. (excepto los shells, es decir, si el usuario ingresó un comando falso)
Si el exec falla, indica:
- una "falla" con el programa (componente faltante o incorrecto, ruta de acceso incorrecta, memoria incorrecta, ...), o
- un error grave del sistema (memoria insuficiente, demasiados procesos, fallo de disco, ...)
Para cualquier error grave, el enfoque normal es escribir el mensaje de error en stderr y luego salir con un código de falla. Casi todas las herramientas estándar hacen esto. Para el exec:
execl("bork", "bork", NULL);
perror("failed: exec");
exit(127);
La cáscara también hace eso (más o menos).
Normalmente, si un proceso hijo falla, el padre también ha fallado y debería salir. No importa si el hijo falló en exec o durante la ejecución del programa. Si exec falló, no importa por qué exec falló. Si el proceso hijo falló por algún motivo, el proceso de llamada está en problemas y debe detenerse.
No pierda mucho tiempo intentando anticipar todas las posibles condiciones de error. No escriba el código que intenta manejar cada código de error de la mejor manera posible. Simplemente inflarás el código e introducirás muchos errores nuevos. Si su programa está roto, o está siendo abusado, simplemente debería fallar. Si lo obligas a continuar, de eso surgirán problemas peores.
Por ejemplo, si el sistema no tiene memoria y no está cambiando, no queremos realizar un ciclo una y otra vez al intentar ejecutar un proceso; Solo empeoraría la situación. Si obtenemos un error del sistema de archivos, no queremos continuar ejecutándose en ese sistema de archivos; Podría empeorar la corrupción. Si el programa se instaló incorrectamente, tiene un error o está dañado la memoria, queremos detenernos lo antes posible, antes de que el programa dañado cause algún daño real (como enviar un informe dañado a un cliente, eliminar una base de datos, etc.). ..).
Una posible alternativa: un proceso fallido puede requerir ayuda, hacer una pausa (SIGSTOP) y luego volver a intentar la operación si se le indica que continúe. Esto podría ayudar cuando el sistema se queda sin memoria, o los discos están llenos, o quizás incluso si hay un fallo en el programa. Pocas operaciones son tan caras e importantes que valdría la pena.
Si está creando un programa GUI interactivo, intente hacerlo como una envoltura delgada sobre herramientas de línea de comando reutilizables (que salen si algo sale mal). Cada función en su programa debe ser accesible a través de la GUI, a través de la línea de comandos y como una llamada a la función. Escribe tus funciones. Escriba algunas herramientas para hacer envolturas de línea de comando y GUI para cualquier función. Usa subprocesos también.
Si está creando un sistema verdaderamente crítico, como un controlador para una estación de energía nuclear o un programa para predecir tsunamis, ¿qué está haciendo leyendo mi tonto consejo? Los sistemas críticos no deben depender completamente de las computadoras o el software. Es necesario que exista una "anulación manual", con alguien que lo conduzca. Especialmente, no intentes construir un sistema crítico en MS Windows, es como construir castillos de arena bajo el agua.
Lo que haga después de la devolución de la llamada exec()
depende del contexto: qué se supone que debe hacer el programa, cuál es el error y qué podría hacer para solucionar el problema.
Una fuente de problemas podría ser que haya especificado un nombre de programa simple en lugar de un nombre de ruta; tal vez podría volver a intentar con execvp()
, o convertir el comando en una invocación de sh -c ''what you originally specified''
. Si alguno de estos es razonable depende de la aplicación. Si hay problemas de seguridad importantes, probablemente no lo intentes de nuevo.
Si especificó un nombre de ruta y hay un problema con eso (ENOTDIR, ENOENT, EPERM), es posible que no tenga ningún respaldo sensible, pero puede informar el error de manera significativa.
En los viejos tiempos (hace más de 10 años), algunos sistemas no soportaban el ''#!'' notación shebang, y si no estaba seguro de si estaba ejecutando un ejecutable o un script de shell, lo probó como un ejecutable y luego lo volvió a intentar como un script de shell. Eso podría o no funcionar si estuviera ejecutando un script de Perl, pero en esos días, escribió sus scripts de Perl para detectar que estaban siendo ejecutados por un shell y para re-ejecutarse con Perl. Afortunadamente, esos días han terminado en su mayoría.
En la medida de lo posible, es importante asegurarse de que el proceso informe el problema para poder rastrearlo, escribir su mensaje en un archivo de registro o simplemente en stderr (o incluso en syslog()
), para que aquellos que tienen que trabajar Lo que salió mal tiene más información para ayudarlos, además del informe del usuario final, que no tiene suerte. "Probé X y no funcionó". Es crucial que si nada funciona, entonces el estado de salida no sea 0, ya que eso indica éxito. Incluso eso podría ser ignorado, pero hiciste lo que pudiste.
Ya sea que simplemente se aterrorice, puede tomar una decisión basada en el valor de errno.