Reputation: 19
I need my code to be able to read n lines from stdin (each line will be a command from the Linux terminal), give it to a child process and execute it. Then when that child process ends, the program must read text again and execute another child process so that there are always n child processes running. I have tried in various ways but it always only reads one line even if I write several through stdin it executes only one child process and waits for more standard input. N must be between the values 1 and 8.
Standard input must be read in blocks of 16 bytes, and each command cannot be larger than 128 bytes.
This is the code I have:
#define _POSIX_C_SOURCE 200809L
#include <stdlib.h>
#include <stdio.h>
#include <assert.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <errno.h>
#include <string.h>
#define BUF_SIZE 16
struct ordenes{
int num;
char *args[60];
};
typedef struct ordenes * ordenes;
void error(char * argv, int num_exit){
fprintf(stderr,"Uso: %s [-p NUMPROC]\n",argv);
fprintf(stderr,"Lee de la entrada estándar una sencuencia de líneas conteniendo órdenes para ser ejecutadas y lanza cada una de dichas órdenes en un proceso diferente.\n");
fprintf(stderr,"-p NUMPROC Número de procesos en ejecución de forma simultánea (1 <= NUMPROC <= 8)\n");
exit(num_exit);
}
ordenes leer(){
char * buf;
if ((buf = (char *) malloc(BUF_SIZE * sizeof(char))) == NULL){
perror("malloc()");
exit(EXIT_FAILURE);
}
const char espacio[1] = " ";
const char salto_linea[2] = "\n";
char *token;
ordenes orden = malloc(sizeof(orden));
char *line = (char *) malloc(sizeof(char)*128);
while((read(STDIN_FILENO,buf,BUF_SIZE))>0){
strcpy(line,buf);
}
if(sizeof(line)>128){
fprintf(stderr,"Error: Tamaño de línea mayor que 128.");
exit(EXIT_FAILURE);
}
orden->num=0;
token = strtok(line, espacio);
orden->args[orden->num] = token;
while(token != NULL){
token = strtok(NULL, espacio);
if(token!=NULL) {
orden->num+=1;
orden->args[orden->num] = token;
}
}
orden->num+=1;
orden->args[orden->num] = NULL;
return orden;
}
int ejecutar_proceso(ordenes orden){
pid_t pid;
int status;
switch(pid = fork()){
case -1:
perror("fork()");
exit(EXIT_FAILURE);
break;
case 0:
execvp(orden->args[0],orden->args);
fprintf(stderr,"execvp() failed\n");
exit(EXIT_FAILURE);
break;
default:
if(waitpid(pid,&status,0) == -1){
perror("wait()");
free(orden);
exit(EXIT_FAILURE);
}
free(orden);
break;
}
return 1;
}
int main(int argc, char *argv[]){
char *arg1;
char *arg2;
int opt;
int num_procesos=1;
int num=num_procesos;
if(argc > 3){
error(argv[0],EXIT_FAILURE);
}
while((opt = getopt(argc,argv,"p")) != -1){
switch(opt){
case 'p':
if(argv[2]==NULL){
error(argv[0],EXIT_FAILURE);
}
num_procesos = atoi(argv[2]);
if(num_procesos < 1 || num_procesos > 8){
fprintf(stderr,"Error: el número de procesos en ejecución tiene que estar entre 1 y 8.");
error(argv[0],EXIT_FAILURE);
}
break;
default:
num_procesos = 1;
break;
}
}
int i=0;
while(i==0){
if(num_procesos>0){
ordenes orden = leer();
num_procesos-=1;
num_procesos += ejecutar_proceso(orden);
}
}
return EXIT_SUCCESS;
}
The Makefile that should be able to compile it is the following:
CFLAGS=-Wall -ggdb3 -Werror -Wno-unused -std=c11 CC=gcc TARGETS=$(patsubst %.c,%,$(wildcard *.c))
all: $(TARGETS)
clean:
-rm -rf $(TARGETS)
.PHONY: clean all
And for example it should be able to pass tests like: echo -e "ls -l\nls -l" | ./mycode -p 1
Upvotes: 0
Views: 75
Reputation: 57997
In ejecutar_proceso
the parent always calls waitpid
immediately after fork
, so it will not proceed until the child it just created has terminated.
If you want to immediately go on and create more processes, then don't call waitpid
yet. Create all n
processes first. Then enter a loop where you call waitpid
, and each time it returns, call fork()
to create a new process to replace the one that just exited.
Upvotes: 1