Cuando un programa en C llama a system() para ejecutar un comando Unix, sé que es posible pasar argumentos al comando, y de acuerdo con un Respuesta de StackOverflow (de un usuario de muy alta representación), la llamada system() usa el shell para ejecutar el comando.

Me sorprendió ver a system("ls -lh >/dev/null 2>&1"); como un ejemplo system() llamada para un programa en C, ya que parece que esto es utilizando las mismas "palabras" delimitadas por espacios en blanco que utiliza el shell interactivamente.

Desde mi punto de vista como administrador de sistemas, me gustaría entender qué las condiciones y las trampas son cuando se va a ejecutar una llamada system() desde un programa en C en algunos archivos o comandos de mi sistema. Pasar nombres de archivos que contienen espacios en blanco a un script de shell es muy propenso a problemas; ¿Hay problemas similares cuando un programa en C llama a un comando?

O para hacer el punto aún más contundente (aunque menos exacto): ¿Es un programa en C escrito por un novato tan probable que se rompa en nombres de archivo que contienen espacios en blanco como un script de shell?

1
Wildcard 27 ene. 2016 a las 11:29

2 respuestas

La mejor respuesta

No hay nada que hacer aquí en la fuente C, la cadena que le pasa a system () se ejecutó en el contexto de la shell. El shell analizará esa cadena, su programa C no lo hace.


Si observa el prototipo de la función system ():

#include <stdlib.h>

int system(const char *command);

El argumento pasado a system() es una cadena. No tiene nada que ver con los caracteres de espacios en blanco en una cadena, obtiene una cadena y pasa esa cadena a otra llamada del sistema. Lo mismo que hiciste tú:

sh -c 'ls -l'

Aquí system () use execve ():

$ cat <<\CODE | gcc -xc -
#include <stdlib.h>
int main(void) {
  system("ls -l");
  return 0;
}
CODE

$ strace -fe execve ./a.out
execve("./a.out", ["./a.out"], [/* 64 vars */]) = 0
Process 16281 attached
[pid 16281] execve("/bin/sh", ["sh", "-c", "ls -l"], [/* 64 vars */]) = 0
Process 16282 attached
[pid 16282] execve("/bin/ls", ["ls", "-l"], [/* 64 vars */]) = 0
...
6
cuonglm 27 ene. 2016 a las 08:49

Si un programa en C usa system() para invocar otro programa, debe crear un comando para ser analizado por el shell (específicamente, /bin/sh).

La implementación de system(const char *command) normalmente terminará llamando a algo como execl('/bin/sh', 'sh', '-c', command, (char*)NULL) en el proceso hijo (y la función de biblioteca execl terminará llamando a la llamada al sistema execve).

1
Toby Speight 28 ene. 2016 a las 13:35