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
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.
Related
Hello I am trying to do a program in c that uses named pipes to communicate with another program but if i run it more than once it fails most of the time with occasionally working perfectly, even though i don't change anything between tests.
Here is the code for arbitro.c the program that i execute first
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <signal.h>
int main(int argc, char *argv[])
{
int fd,id1,cont_pront=0,i=0;
char nomejog[40]="",instrucao[40]="";
// FIFO file path
char * myfifo = "myfifo";
// Creating the named file(FIFO)
mkfifo(myfifo, 0666);
do{
fd = open(myfifo,O_RDONLY);
if(fd == -1){
fprintf(stdout, "Erro a abrir.\n");
}
// First open in read only and read
for(int i=0;i<2;i++){
read(fd, nomejog, 40); //Recebe o nome do jogador
read(fd, &id1,sizeof(id1)); //Recebe o id do primeiro jogador
fprintf(stdout, "Nome: %s -» %d\n", nomejog,id1);
cont_pront++;
}
fprintf(stdout, "Nº: %d\n", cont_pront);
//Now open in write mode and write
fd = open(myfifo,O_WRONLY);
if(fd == -1){
fprintf(stdout, "Erro a abrir.\n");
}
if(cont_pront >= 2){
cont_pront = -1;
}
write(fd, &cont_pront, sizeof(int));
close(fd);
// optind is for the extra arguments
// which are not parsed
for(; optind < argc; optind++){
if(i == 0){
printf("Duração do campeonato: %s\n", argv[optind]);
}else{
if(i == 1){
printf("Tempo de espera: %s\n", argv[optind]);
}
}
i++;
}
}while(strcmp(instrucao,"exit") != 0);
return 0;
}
and here is the code for cliente.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <signal.h>
int main(int argc, char *argv[]){
int fd1,cont_pront=0;
char nomejog[40]="";
// FIFO file path
char * myfifo = "myfifo";
// Creating the named file(FIFO)
mkfifo(myfifo, 0666);
// Open FIFO for write only
fd1 = open(myfifo, O_WRONLY);
//Enviar o nome do jogador ao arbitro
for(int i=0;i<2;i++){
write(fd1, nomejog,strlen(nomejog)+1); //Envia o nome do jogador já pronto
write(fd1,&i, sizeof(int)); //Envia o id
strcpy(nomejog,"pedro");
}
close(fd1);
//Receber quantos jogadores estão prontos
fd1 = open(myfifo, O_RDONLY);
read(fd1, &cont_pront, sizeof(int)); //Recebe o nome do jogador
if(cont_pront == -1){
//Tem jogadores necessários para começar o jogo
fprintf(stdout,"Existem jogadores suficientes, o campeonato vai ser iniciado...\n");
execl("GAMEDIR/game01","GAMEDIR/game01", NULL);
}else{
//Ainda não tem jogadores suficientes para começar o jogo
fprintf(stdout,"Nao tem jogadores suficientes para comecar o campeonato.\n");
}
close(fd1);
return 0;
}
if everything goes well this is supposed to say that there are enough players and the executes the game, but for some reason sometimes it repeats everything sending more players in blank or the client stops midway execution or even doesn't send the correct players in the first place
I want to write a code using pipes. This code is about the rock, scissor, paper game, so I need to ask and receive messages all the time until one of two players score 3. So far, now I have the following code, but I don´t know how to iterate this code, could be with a while iteration?
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#define READ_END 0 /* index pipe extremo escritura */
#define WRITE_END 1 /* index pipe extremo lectura */
int main(int argc, char* argv[])
{
int fd1[2],fd2[2];
int status, pid;
pipe(fd1); /* comunica ls y grep */
pid = fork();
if(pid == 0) /* hijo 1*/
{
close(fd1[READ_END]); /* cerrar extremo no necesario */
dup2(fd1[WRITE_END], STDOUT_FILENO);
close(fd1[WRITE_END]);
}
else /* padre */
{
close(fd1[WRITE_END]); /* extremo no necesario ya */
pipe(fd2); /* comunica grep y wc */
pid = fork();
if(pid == 0) /* hijo 2 */
{
close(fd2[READ_END]); /* cerrar extremo no necesario */
dup2(fd1[READ_END], STDIN_FILENO);
close(fd1[READ_END]);
dup2(fd2[WRITE_END], STDOUT_FILENO);
close(fd2[WRITE_END]);
}
else /* padre */
{
close(fd1[READ_END]); /* cerrar extremo no necesario */
close(fd2[WRITE_END]); /* cerrar extremo no necesario */
}
}
close(fd2[READ_END]); /* cerrar extremo que queda abierto en el padre */
/* wait para cada hijo */
wait(&status);
wait(&status);
return 0;
}
it's been a long time since I touched C. I'm trying to get the name of the last file created in a folder. In a daemon I get the live file number with scandir, however I can not get the timestamp of the files in the dirent.
Do you have an idea ? I do not want to use popen () and a bash command.
(thank you for your answers and sorry for the approximate english)
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <cjson/cJSON.h>
#include <curl/curl.h>
#include <dirent.h>
#include <errno.h>
#include <time.h>
int main(int argc, char *argv[] ){
int pid = fork();
if (pid < 0){
perror("Echec lors du clonage.");
exit(-1);
}
else if (pid > 0){
printf("Service lancé sur le PID : %d \n", pid);
exit(0);
}
time_t debut, fin, difference;
int numOfFiles = 0, oldNumOfFiles = 0, i = 0;
char *path = "/home/ackbar/Documents/watchmen/testfolder";
debut = time (NULL);
while(1 == 1){
i++;
struct dirent **fileListTemp;
int numOfFiles = scandir(path, &fileListTemp, NULL, alphasort);
if((numOfFiles > oldNumOfFiles) && (oldNumOfFiles == 0)){
printf("first -\n");
oldNumOfFiles = numOfFiles;
}
else if(numOfFiles < oldNumOfFiles){
printf("delete -\n");
oldNumOfFiles = numOfFiles;
}
else if(numOfFiles > oldNumOfFiles){
printf("%d -- add %d\n", oldNumOfFiles, numOfFiles);
oldNumOfFiles = numOfFiles;
}
fin = time (NULL);
difference = difftime (fin, debut);
if((int)difference > 120){
printf("fin\n");
break;
}
}
}
it's some implementation of linux shell in c. Since i have added background process support i have some output that i fail to understand. Here is the code:
#include <stdlib.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/time.h>
#include <sys/resource.h>
#include <signal.h>
#include <wait.h>
#define DEFAULT_PROMPT "\nLog710H2014%>"
#define EXIT_CMD "exit"
#define CD_CMD "cd"
#define HOME_ENV_VAR "HOME"
#define NEW_LINE "\n**************************************************\n"
#define BCG_CMD_FLAG "&"
void cd_handler(int argc, char *argv[]);
int lire(char *chaine, int longueur);
char** init_command(int* size,char *str);
int execProg(int *argc, char **argv);
int execProgBg(int *argc, char **argv);
void sigchldHandler(int sig_num);
struct beanProcess {
pid_t pid;
int job_num;
char *command;
};
struct beanProcess *beans;
int jobCount = 1;
int main() {
printf(NEW_LINE);
printf("Bienvenue sur le shell de l'equipe 1");
printf(NEW_LINE);
while(1){
char str[200];
printf(DEFAULT_PROMPT);
lire(str, 200);
int commArgsC = 0, bg = 0;
char** comms = init_command(&commArgsC, str);
if(commArgsC == 0){
printf("Saisie vide, veuillez entrez une commande.");
continue;
}
if(strcmp(comms[commArgsC-1], BCG_CMD_FLAG) == 0){
bg = 1;
comms[commArgsC-1] = 0;
}
if(strcmp(comms[0], CD_CMD) == 0){
cd_handler(commArgsC, comms);
commArgsC = commArgsC -1;
}
else if (strcmp(comms[0], EXIT_CMD) == 0){
exit(0);
}
else {
if(bg){
execProgBg(&commArgsC, comms);
}
else{
execProg(&commArgsC, comms);
}
}
}
exit;
}
void cd_handler(int argc, char *argv[]){
char buff[512];
char * directory;
if(argc < 2){
directory = getenv(HOME_ENV_VAR);
}else if (argc == 2){
directory = argv[1];
}else{
exit(1);
}
if (chdir(directory) == -1) {
printf ("Erreur de changement de repertoire actif", strerror (errno));
}else{
if (getcwd(buff, sizeof(buff)) == NULL)
perror("Impossible d'afficher le repertoire courant");
else
printf("le repertoire courant est: %s\n", buff);
}
}
//Cette fonction est adaptée a partir du code de refp sur http://stackoverflow.com/questions/11198604/c-split-string-into-an-array-of-strings
char** init_command(int* size, char* str){
char ** res = NULL;
char * p = strtok (str, " ");
int n_spaces = 0;
while (p) {
res = realloc (res, sizeof (char*) * ++n_spaces);
if (res == NULL){
exit (-1);
}
res[n_spaces-1] = p;
p = strtok (NULL, " ");
}
res = realloc (res, sizeof (char*) * (n_spaces+1));
res[n_spaces] = 0;
*size = n_spaces;
return res;
}
//cette fonction est tirée d'un exemple de http://fr.openclassrooms.com/informatique/cours/apprenez-a-programmer-en-c/recuperer-une-chaine-de-caracteres
int lire(char *chaine, int longueur)
{
char *positionEntree = NULL;
if (fgets(chaine, longueur, stdin) != NULL)
{
positionEntree = strchr(chaine, '\n');
if (positionEntree != NULL)
{
*positionEntree = '\0';
}
return 1;
}
else
{
return 0;
}
}
int execProg(int *argc, char **argv){
char path[] = "/bin/";
strcat(path,argv[0]);
printf("\nThis is the %d process executing the code in non bg mode\n", getpid());
printf("Voici le resultat de l'execution de votre commande\n");
pid_t pid;
pid = fork();
if (pid < 0) {
perror("Creation de processus avec fork echouee");
exit(-1);
}
else if (pid == 0) {
if(execvp(argv[0], argv) == -1){
printf("\nthis is the child process %d executing the command in non bg mode\n", getpid());
perror("execv");
return EXIT_FAILURE;
}
}
else {
printf("\nthis is the parent process %d showing the stats in non bg mode\n", getpid());
struct rusage rusg;
long temp, tempCpu;
wait (NULL);
getrusage(RUSAGE_CHILDREN, &rusg);
printf("\nStatistique de la commande %s:\n", argv[0]);
temp = (rusg.ru_utime.tv_sec * 1000) + (rusg.ru_utime.tv_usec / 1000);
tempCpu = (rusg.ru_stime.tv_sec * 1000) + (rusg.ru_stime.tv_usec / 1000);
printf("\nLe temps wall-clock (ms): %ld", temp);
printf("\nLe temps CPU (ms) %ld", tempCpu);
printf("\nNB interruptions volontaires: %ld", rusg.ru_nvcsw);
printf("\nNB interruptions involontaires: %ld", rusg.ru_nivcsw);
printf("\nNB defaults de pages: %ld", rusg.ru_majflt);
printf("\nNB defaults de pages satifaits du noyau : %ld", rusg.ru_minflt);
}
return EXIT_SUCCESS;
}
int execProgBg(int *argc, char **argv){
signal(SIGCHLD, sigchldHandler);
printf("\nThis is the %d process executing the code in bg mode\n", getpid());
pid_t pid;
pid = fork();
if (pid < 0) {
perror("Creation de processus avec fork echouee");
return EXIT_FAILURE;
}
else if (pid == 0) {
//printf("This is the pid %d", getpid());
printf("\nthis is the child process %d executing the command in bg mode\n", getpid());
if(execvp(argv[0], argv) == -1){
perror("execvp");
return EXIT_FAILURE;
}
}
else {
printf("\nthis is the parent process %d showing the queue in bg mode\n", getpid());
printf("[%d] %d", jobCount, pid);
jobCount++;
//cleanJobList(childPid);
//ajoutProcess();
}
return EXIT_SUCCESS;
}
void sigchldHandler(int sig_num)
{
int status;
int childPid;
childPid = waitpid(-1, &status, 1);
printf("Hello the process %d has died\n", childPid);
//cleanJobList(childPid);
}
When i execute a bg command like "ls &", here's the output:
**************************************************
Bienvenue sur le shell de l'equipe 1
**************************************************
Log710H2014%>ls &
This is the 23464 process executing the code in bg mode
this is the parent process 23464 showing the queue in bg mode
[1] 23472
Log710H2014%>
this is the child process 23472 executing the command in bg mode
Debug PARTIE3.c
Hello the process 23472 has died
This is the 23464 process executing the code in non bg mode
Voici le resultat de l'execution de votre commande
this is the parent process 23464 showing the stats in non bg mode
Debug PARTIE3.c
Statistique de la commande ls:
Le temps wall-clock (ms): 0
Le temps CPU (ms) 2
NB interruptions volontaires: 2
NB interruptions involontaires: 9
NB defaults de pages: 0
NB defaults de pages satifaits du noyau : 644
Log710H2014%>
Why is that the parent process overlapping the lire() function and going directly to execProg function after the first execution ?
You are in a while loop. When your execProgBg function returns, no matter what it returns, the loop keeps going. If you want to stop you need to break or call exit from execProgBg.
Why is that the parent process overlapping the lire() function and
going directly to execProg function after the first execution
I don't know how you are executing your program but it looks like the second time around fgets fails, which you don't notice since you don't check the return code of the lire function. SO you go on and reuse the buffer from the previous call. It seems likely that you pass EOF to the program - perhaps by hitting ctrl-d.
I decided to run the code and obtained the same result as the OP does by hitting CTRL-D after the first ls &.
It is besides the point but warrants some explanation:
exit;
This evaluates the function exit converting it to a function pointer and throws away the result. It does not call the function. More importantly, calling exit as the last statement of main is pointless, since main is exiting anyway. You should just return some_code to indicate success of failure.
The following server creates a named pipe when it's run like this:
./serverprogram -p nameofthepipe -t 99
the optarg after t indicates a number of threads to be created (not done here).
Anyway, the pipe isn't working here:
/* Open the first named pipe for reading */
int rdfd = open(pipeName, O_RDONLY);
/* Read from the first pipe */
int numread = read(rdfd, command_and_pid, 280);
printf("what's being read is %s \n", command_and_pid); // not printing!!1!
Why?
Server program:
#include <unistd.h>
#include <stdio.h>
#include <errno.h>
#include <ctype.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
int main (int argc, char * argv[])
{
char pipeName[30];
int numThreads;
char command_and_pid[280];
int opcion;
if (argc < 2) {
printf ("ERROR: Missing arguments\n");//
exit(1);
}
opterr = 0;
while ((opcion = getopt (argc, argv, "p:t:w")) != -1)
{
switch (opcion) {
case 'p': // -p indica el nombre del pipe
printf("The name of the pipe is: %s\n",optarg);
strcpy(pipeName, optarg);
break;
case 't'://-t indica los hilos
printf("The number of threads is: %s\n",optarg);
numThreads= atoi(optarg);
break;
case '?':
fprintf(stderr,"no reconozco esa opcion\n");
break;
}
}
int ret_val = mkfifo(pipeName, 0666);
if ((ret_val == -1) && (errno != EEXIST)) {
perror("Error creating the named pipe");
exit (0);
}
/* Open the first named pipe for reading */
int rdfd = open(pipeName, O_RDONLY);
/* Read from the first pipe */
int numread = read(rdfd, command_and_pid, 280);
printf("what's being read is %s \n", command_and_pid); // not printing!!1!
close(rdfd);
return 0;
}
Client program:
#include <unistd.h>
#include<stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
int main (int argc, char * argv[])
{
char pipeName[30];
printf("write the name of the pipe used to write to the server \n");
fgets(pipeName,30, stdin);
/* Open the first named pipe for writing */
int wrfd = open(pipeName, O_WRONLY);
printf("write the name of the command you want to execute \n");
char command_and_pid[280];
char command[250];
fgets(command,250, stdin);
puts(command); //quitar
strcpy(command_and_pid,command);
strcat(command_and_pid," ");
int pipeIntId;
char pidstring [30];
int pid= getpid();
sprintf(pidstring,"%d", pid);
strcat(command_and_pid,pidstring);
int written;
written=write(pipeIntId,command_and_pid,280);
//write to the pipe
// send the command and pid
close(pipeIntId); // close write pipe
return 0;
}
In the client, fgets keeps the newline at the end of the line, so you'll need to strip that before opening the file.
Also, in the code as given, you're opening wrfd but writing to pipeIntId, which is uninitialized (though perhaps you are extracting something from a function here).