Ayuda C - Llamadas al sistema UNIX

P

Hola criaturitas,

Necesito un poco de ayuda con una práctica que tengo que entregar.

Creo que es bastante fácil, pero se me ha atascado.

Consiste en ejecutar dos comandos dado el directorio o fichero que va a ejecutar.

La ejecución tiene que ser la siguiente: ./program cmd1 cmd2 < entrada.txt > salida.txt

#include <sys/wait.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>

#define N 1024

int main(int argc, char * argv[]){

int nr,pid;
int p1[2];      //pipe1
char buffer[N];


pipe(p1); //Creamos el pipe1
 	

//HIJO 1
pid=fork();
if (pid<0){												//Control de errores
	perror("Error al crear el pid\n");
	exit(EXIT_FAILURE);
}
if (pid==0){
	close(p1[0]);
	dup2(1,p1[1]);
	execlp(argv[1],argv[1],NULL);
		perror("Error al ejecutar el comando\n");
		exit(EXIT_FAILURE);
}
//HIJO 2
pid=fork();
if (pid<0){												//Control de errores
	perror("Error al crear el pid\n");
	exit(EXIT_FAILURE);
}
if (pid==0){
	close(p1[0]);
	dup2(1,p1[1]);
	execlp(argv[2],argv[2],NULL);
		perror("Error al ejecutar el comando\n");			//Control de errores
		exit(EXIT_FAILURE);
}
close(p1[0]);
close(p1[1]);
close(0);
close(1);

wait(NULL);
wait(NULL);
return 0;
}

No sé exactamente lo q me falla. Sé que hay variables que sobran, pero es algo que he ido reutilizando.

Muchas gracias

elkaoD

¿Y cómo sabes que falla?

Quiero decir, ¿qué ocurre y qué debería ocurrir? ¿O simplemente no funciona?

¿Has pasado encima con un debugger?

Así a bote pronto y dando palos de ciego (quizá me equivoco), a execlp le estás pasando como argumentos un string, cuando los argumentos son un array de strings. Nunca he usado execlp así que es por dar ideas.

P

Se que falla porque al ejecutarlo no muestra lo que deberia de mostrar, es decir, estas dos ejecuciones deberian de dar lo mismo y dan algo distinto

cat entrada.txt | wc > salida.txt
./program cat wc < entrada.txt > salida.txt

#4 Lunes

BLZKZ

si me acordara de esto... es un poco tarde para preguntar no? xD cuando es el examen?

1 respuesta
Czhincksx

Edit: Nada, lo entendí mal...

Igneus

Si lo entendí bien creo que usas mal la pipe. Un proceso hijo tiene que escribir en la pipe (usa el descriptor 1) y el otro hijo lee de la pipe (usa el descriptor 0). Aparte de que creo que deberias redireccionar la pipe a los descriptores de entrada/salida estandar para que al usar el exec funcione. Y repasa la sintaxis del execlp porque no estoy seguro de que los argumentos sean los correctos.

Un saludo

1 1 respuesta
P

#6

Era eso, conseguí arreglarlo, en el primer fork no asignaba correctamente el pipe a los descriptores y por eso fallaba, gracias.

El tema es que ahora tengo otro fallo...

Al ejecutar por ejemplo ./program ls sort <$HOME, no me devuelve lo de $HOME, me devuelve lo que tengo el directorio actual donde estoy. ¿Sabéis a que puede ser debido? Os dejo aquí el código corregido.

#include <sys/wait.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>


int main(int argc, char * argv[]){

int pid;
int p1[2];      //pipe1

if (argc !=3){
	perror("Número de argumentos incorrecto\n");
	exit(EXIT_FAILURE);
}
pipe(p1); //Creamos el pipe1
 	

//HIJO 1
pid=fork();
if (pid<0){												//Control de errores
	perror("Error al crear el pid\n");
	exit(EXIT_FAILURE);
}
if (pid==0){
	close(p1[0]);
	dup2(p1[1],1);
	execlp(argv[1],argv[1],NULL);
		perror("Error al ejecutar el comando\n");
		exit(EXIT_FAILURE);
}
//HIJO 2
pid=fork();
if (pid<0){												//Control de errores
	perror("Error al crear el pid\n");
	exit(EXIT_FAILURE);
}
if (pid==0){
	close(p1[1]);
	dup2(p1[0],0);
	execlp(argv[2],argv[2],NULL);
		perror("Error al ejecutar el comando\n");			//Control de errores
		exit(EXIT_FAILURE);
}
close(p1[0]);
close(p1[1]);
close(0);
close(1);

wait(NULL);
wait(NULL);
return 0;
}

Gracias

1 respuesta
elkaoD

#7 "no me devuelve lo de $HOME"

Normal. ls no lee de stdin sino de argv directamente.

1 respuesta
P

#8

Estoy casi seguro que lo que dices no es asi, te explico porque tampoco sé si estoy en lo correcto al 100%

Al ejecutar el programa mediante ./program ls sort <$HOME, le estás diciendo que la stdin es $HOME mediante el '<', con lo cual argv[0] es la llamada al programa, argv[1] el ls y argv[2] el sort, creo que no lee de argv por ningún lugar, ya que heredan lo del padre, y el padre deberia de tener $HOME como stdin

Estoy casi seguro de ello, ¿alguien lo podría confirmar?

En caso que sea como tu dices, como lo arreglarías?

Edit: Quizás sea un tema de sintaxis, y hay que poner el $HOME entrecomillado o algo así

2 respuestas
dagavi

#9 LS lee el argumento de argv no de stdin. Fin.

En el ejemplo que pusiste antes de cat no es:
cat entrada.txt
(que lee argv[1])

Lo que estás haciendo es:

cat < entrada.txt
(que lee stdin)

Igneus

#9 heredan los descriptores del padre, pero le has cambiado el descriptor de entrada estandar por el de la pipe!!!

Revisa la sintaxis del exec

P

¿Podríais decirme que tendría que tocar para que funcionase tanto un, no sé exactamente lo que debería de ser

./program cat wc <fichero
./program ls sort <directorio

Gracias

2 respuestas
dagavi

#12 Tiene sentido pasar por la entrada estándar un directorio? Sería la primera vez que lo veo.

Piensa que "< ARCHIVO" abre el archivo y lo pasa por la entrada estándar como si tu estuvieras escribiendo. ¿Que sentido tiene < DIRECTORIO bajo esta descripción? ¿Abre la estructura del SO que representa un directorio y pasa sus datos binarios al programa por la stdin?

elkaoD

#12 no puedes, no tiene sentido.

Prueba a hacer: ls ~ y ls < . El segundo te dará el resultado que tienes.

STDIN != argv

P

Ok, ya lo he entendido, era un problema de conceptos básicos.

Muchas gracias ;). Podeis cerrar el post si quereis

P

Hola de nuevo, agradezco que no se haya cerrado el post, porque tengo otra dudilla con otro código.

Os explico, necesito hacer un rev a un fichero de entrada que se le pasa con <, el resultado de esto tengo que sacarlo por stdout, y a ese resultado, tengo que hacerle un wc -w.
No sé que hago exactamente mal, pero al escribir ambas cosas, el wc -w no sale correctamente.

La llamada al programa es ./program fsalida <fentrada

Os dejo aquí el código para ver si me podeis ayudar a ver que es lo que falla. Gracias

#include <sys/wait.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>

#define N 1024

int main(int argc, char * argv[]){

int fdin,fdout; //ficheros de entrada y salida
int nr,nr1,pid;
int p1[2];      //pipe1
int p2[2];		 //pipe2
char buffer[N];
char buffer1[N];

if (argc!=2){														// Control de argumentos
	perror("Número de argumentos incorrecto\n");
	exit(EXIT_FAILURE);
}

pipe(p1); //Creamos el pipe1
pipe(p2); //Creamos el pipe2


//HIJO 1
pid=fork();
if (pid<0){												//Control de errores
	perror("Error al crear el pid\n");
	exit(EXIT_FAILURE);
}
if (pid==0){
	close(p1[0]);
	dup2(p1[1],1);
	close(p1[1]);
	close(p2[0]);
	close(p2[1]);
	execlp("rev","rev",NULL);
		perror("Error al ejecutar el comando rev\n");
		exit(EXIT_FAILURE);
}
//HIJO 2

pid=fork();
if (pid<0){												//Control de errores
	perror("Error al crear el pid\n");
	exit(EXIT_FAILURE);
}
if (pid==0){
	close(p1[1]);
	dup2(p1[0],0);
	close(p1[0]);
	close(p2[0]);
	dup2(p2[1],1);
	close(p2[1]);
	execlp("wc","wc","-w",NULL);
		perror("Error al ejecutar el comando wc\n");			//Control de errores
		exit(EXIT_FAILURE);
}
close(p1[1]);
close(p2[1]);



fdout=creat(argv[1],S_IRWXU);		//Creamos el fichero de salida y vamos leyendo de la segunda tubería para escribirlo en el fichero
for(;;){
	nr=read(p1[0],buffer,N);
		if (nr<=0){
			break;
		}
	write(1,buffer,nr);
}
for(;;){
	nr=read(p2[0],buffer,N);
		if(nr<=0){
			break;
		}
	write(fdout,buffer,nr);
}
close(p1[0]);
close(p2[0]);
close(fdout);
wait(NULL);
wait(NULL);
return 0;
}
1 respuesta
elkaoD

#16 no solemos cerrar los hilos por lo general aunque esté la duda resuelta.

Según mi experiencia es mejor que para las dudas nuevas abras un hilo (ábrelo sin miedo, para eso está), porque llama más la atención a la gente que ya sabe que este estaba resuelto y obtienes más respuestas.

Mañana si puedo le echo un vistazo, que ahora estoy en móvil.

Usuarios habituales