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.
Related
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.
I have to simulate this command using pipes in c: echo "<exp>" | bc -lq.
Process A must read a string and send it to process B;
Process B executes the "bc -lq" command and returns the result to A.
The code is this, but I can't understand why it doesn't work; in particular, the "bc" command appears to be unable to read the expression from stdin.
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>
#include<sys/wait.h>
#define N 1024
#define LEGGI(stringa) if(scanf("%s", stringa) == 0) \
{ \
perror("Impossibile leggere la stringa"); \
exit(EXIT_FAILURE); \
} \
void closePipe(int pipeFd);
void Dup2(int pipeTempFd, int fd);
void Write(int pipeTempFd, char stringa[], int n);
void Read(int pipeTempFd, char stringa[], int n);
int main()
{
char stringa[N];
LEGGI(stringa);
int pipeFd[2];
int pRicezioneFd[2];
if(pipe(pipeFd) == -1 || pipe(pRicezioneFd) == -1)
{
perror("impossibile eseguire la pipe");
exit(EXIT_FAILURE);
}
if(strncmp(stringa, "exit", N) != 0)
{
pid_t processPid;
if((processPid = fork()) == 1)
{
perror("impossibile eseguire la fork");
exit(EXIT_FAILURE);
}
if(processPid != 0)
{
closePipe(pipeFd[0]);
closePipe(pRicezioneFd[1]);
printf("operazione: %s\n", stringa);
Write(pipeFd[1], stringa, N);
closePipe(pipeFd[1]);
read(pRicezioneFd[0], stringa, N);
closePipe(pRicezioneFd[0]);
if(wait(NULL) == -1)
{
perror("Impossibile eseguire la wait");
exit(EXIT_FAILURE);
}
printf("%s\n", stringa);
}
else
{
closePipe(pipeFd[1]);
closePipe(pRicezioneFd[0]);
Dup2(pipeFd[0], 0);
Dup2(pRicezioneFd[1], 1);
Dup2(pRicezioneFd[1], 2);
// closePipe(pipeFd[0]);
// closePipe(pRicezioneFd[1]);
if(execl("/usr/bin/bc", "bc", "-lq", NULL) == -1)
{
perror("programma non reperibile");
exit(EXIT_FAILURE);
}
}
}
return 0;
}
void closePipe(int pipeFd)
{
if(close(pipeFd) == -1)
{
perror("impossibile chiudere il fd della pipe");
exit(EXIT_FAILURE);
}
}
void Dup2(int pipeTempFd, int fd)
{
if(dup2(pipeTempFd, fd) == -1)
{
perror("Impossibile eseguire la dup2");
exit(EXIT_FAILURE);
}
}
void Write(int pipeTempFd, char stringa[], int n)
{
if(write(pipeTempFd, stringa, n) == -1)
{
perror("impossibile scrivere sulla pipa");
exit(EXIT_FAILURE);
}
}
void Read(int pipeTempFd, char stringa[], int n)
{
if(read(pipeTempFd, stringa, n) == -1)
{
perror("impossibile leggere dalla pipe pipa");
exit(EXIT_FAILURE);
}
}
You are writing all 1024 bytes of the mostly uninitialized stringa to bc, which is then choking on illegal characters. bc expects newline terminated, "plain text" expressions.
#define N 1024
char stringa[N]; // stringa := "\236\0\0\241\177>\0\0\3704\241..."
scanf("%s", stringa); // stringa := "1+2\0\177>\0\0\3704\241..."
// ^^^^^^^^^^^^^^^^^^^^
....
Write(pipeFd[1], stringa, N); // ohimè!
You'll want something like this, instead:
Write(pipeFd[1], stringa, strlen(stringa));
Write(pipeFd[1], "\n", 1);
I think my code is similar to yours, one main change was the arguments to the exec call. Another change was that I only have 2 dup2 calls in the child process, one for changing stdin and the other for stdout. You only need to change these.
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>
#include<sys/wait.h>
#define N 1024
#define READ_END 0
#define WRITE_END 1
int main()
{
char *input = NULL;
size_t len = 0;
ssize_t amt_read = 0;
puts("Please enter a string: ");
amt_read = getline(&input, &len, stdin);
if(amt_read < 0)
exit(EXIT_FAILURE);
pid_t pid;
int fd[2];
int fd_return[2];
// Create the pipes
pipe(fd);
pipe(fd_return);
pid = fork();
if(pid==0)
{ // If child process
dup2(fd[READ_END], STDIN_FILENO);
dup2(fd_return[WRITE_END], STDOUT_FILENO);
close(fd[WRITE_END]);
close(fd[READ_END]);
close(fd_return[WRITE_END]);
close(fd_return[READ_END]);
execl("/usr/bin/bc", "/usr/bin/bc", "-lq", (char *)NULL);
fprintf(stderr, "Failed to execute\n");
exit(EXIT_FAILURE);
}
else
{ // If parent process
int status;
close(fd[READ_END]);
close(fd_return[WRITE_END]);
// Write to the pipe
write(fd[WRITE_END], input, strlen(input));
close(fd[WRITE_END]);
// Wait for the child to finish
waitpid(pid, &status, 0);
char buff[N];
buff[N-1] = 0;
read(fd_return[READ_END], buff, N-1);
*(index(buff, '\n')) = '\0'; // Add null terminator on your own
close(fd_return[READ_END]);
printf("The Result is: %s\n", buff);
}
free(input);
return 0;
}
EDIT:
I edited the code and debugged it. I also changed the user input schematic so now you no longer allocated static storage for the user input, rather it is allocated dynamically and then this storage is freed at the end with free();
Note, I did leave the static storage for reading the input back in, you can change this in the future if you want.
illegal character: ^# comes from the fact that write() was writing too much, notice that now we only write strlen(buff) amount.
Note: The input to bc will not work unless the string ends like "...\n\0" luckily getline() does this by default.
Also, I left all the pipe closing the same, that was not causing the issue.
I am trying to implement shell redirection, using this I redirect stdout to fd1
int redirectOut(int fd1)
{
fflush(stdout);
int fd2 = dup(STDOUT_FILENO);
dup2(fd1, STDOUT_FILENO);
close(fd1);
return fd2;
}
I then fork and call an executable, it works except in the case where the executable uses putchar.
On the putchar man page it is written that it uses stdout.
putchar(c); is equivalent to putc(c,stdout).
Why doesn't putchar write anywhere neither in the standard output nor the file I redirected the stream to ?
I tried changing putchar to putc but it didn't help, it might have something to do with the fact that stdout if a *FILE and STDOUT_FILENO an int
How can I make my code work and why does it work with printf which uses (code for printf)
done = vfprintf (stdout, format, arg);
EDIT MORE CODE
int executeBlocs(execBloc *bloc,int fileIn,int fileOut){
if(bloc->first != NULL){
if (strcmp(bloc->ope, ">") == 0){
int out = open(bloc->command[0], O_WRONLY | O_CREAT | O_TRUNC , 0644);
int returnCode = executeBlocs(bloc->first, STDIN_FILENO, out);
redirectOut(fileOut);
redirectIn(fileIn);
return returnCode;
}
}
else{
redirectIn(fileIn);
redirectOut(fileOut);
return call(bloc->nbWords, bloc->command);
}
}
execBloc is a struct that contains a command to execute (or a file name) an operator (>> , | , > ...) and a reference to the another bloc that contains the rest of the command.
If the user enter cat /tmp/testCat > /tmp/testCatRedirection
then a first structure will be created containing the operator > and the command /tmp/testCatRedirection and first which is a reference to the second structure containing the command cat /tmp/testCat
int call(int argc, char const *argv[]) {
if (argc > 0){
if (executeProgram(argv) == 1) return 1;
if (executeStandardLibrary(argc, argv) == 1) return 1;
if (executeDynamicLibrary(argc, argv) == 1) return 1;
}
return -1;
}
int executeProgram(char const *argv[]){
//Creation de la chaine de caractère /home/kerdam/cbin/nonExecutable
char *path = strdup(binFolder);
strcat(path, argv[0]);
//Test si le fichier existe et est executable
if (access(path, F_OK|X_OK) != -1){
//Le fichier existe et on peut l'éxecuter
int pid = fork();
// Error
if (pid == -1){
return -1;
}
//Fils
else if (pid == 0) {
// Executer la commande
execv(path, argv);
return 1;
}
// Parent process
else {
// Wait for child process to finish
int childStatus;
waitpid(pid, &childStatus, 0);
return 1;
}
}
else return -1;
}
Finally the code of the program I am trying to execute
#include<stdio.h>
#include<string.h>
#define MAX_FILE_NAME_CHARS 255
int main(int argc, char *argv[])
{
FILE *fp;
char file_name[MAX_FILE_NAME_CHARS], ch;
int i;
/*
* after creating a.out, rename it as mycat for our own cat command
* and it usage is same as standard cat command
*/
if(argc<=1){
printf("Utiliser cat avec aumoin un argument (un fichier) <nomfichier> \n");
return 0;
}
/*
* This is for multiple file in argument
*/
for(i=1; i<=argc;i++){
strncpy(file_name, argv[i], MAX_FILE_NAME_CHARS);
fp=fopen(file_name, "r");
if(fp == NULL) {
printf("%s: No such file or directory\n", file_name);
return 0;
}
/*
* read file and feed contents to STDIO
*/
while((ch=fgetc(fp)) != EOF || ch == '}'){
putchar(ch);
}
fclose(fp);
}
return 0;
}
Remark
I should not change the code of the executable I am trying to execute as the users of my shell should be able to execute their programs without restriction on what function they can use.
I've been face with the same problem and found the solution.
Look at the code which reads a file argv[1] and writes its content to file argv[2] without spaces and line feeds.
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
int main(int argc, const char* argv[]) {
if (argc != 3) {
printf ("Expected exactly two arguments\n");
return 1;
}
int rd = open(argv[1], O_RDONLY);
if (rd == -1) {
printf ("Failed to open file %s\n", argv[1]);
return 1;
}
int wd = open(argv[2], O_WRONLY | O_TRUNC | O_CREAT, 0666);
if (wd == -1) {
printf ("Failed to open file %s\n", argv[2]);
return 1;
}
int temp_in = dup(0);
int temp_out = dup(1);
dup2(rd, 0);
dup2(wd, 1);
close(rd);
close(wd);
int written_bytes = 0;
int c;
while ((c = getchar()) != EOF) {
if (c == ' ' || c == '\n') {
continue;
}
putchar(c);
written_bytes++;
}
// The instruction below is critically important, because
// putchar by default writes char to an internal buffer,
// so we have to send it to the file descriptor manually
fflush(stdout);
dup2(temp_in, 0);
dup2(temp_out, 1);
printf ("%d bytes have been written\n", written_bytes);
return 0;
}
I'm writing a program that has an interface like:
myprog file1 file2 c
This program creates two children and P2 with an execlp opens file2, makes a grep -c on this file for founding c and gives the results to his brother P1 (I have to do it closing the STDOUT's FD and dupping the pipe p2p1 between them). P1 receives this from p2p1 and sends this value to P0. Moreover this also makes the same thing with file1 and gives the result to P0, which will print them.
The problem is: the father P0 reads something, but it is wrong.
What I'm supposed to do? Here's the code and thanks for your attention.
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
#include <signal.h>
#include <stdlib.h>
#include <string.h>
#include <sys/wait.h>
#define MAX_STRING_LENGTH 128
/**************************/
/* DICHIARAZIONE FUNZIONI */
/**************************/
void wait_child();
void processo_p2(char *inputfile, char *c);
void processo_p1(char *inputfile, char *c);
/*********************/
/* VARIABILI GLOBALI */
/*********************/
int p1p0[2], p2p1[2];
int main(int argc, char* argv[])
{
int pid[2], i, value, count=0;
char *c, buf[10];
if (argc !=4)
{
fprintf(stderr, "Numero di argomenti errato\n");
fprintf(stderr, "Usage: %s file1 file2 C\n", argv[0]);
exit(EXIT_FAILURE);
}
c=argv[3];
/* Init */
pipe(p1p0);
pipe(p2p1);
for (i=0; i<2; i++)
{
pid[i] = fork();
if (pid[i] < 0)
{
fprintf(stderr, "P0: Errore nella fork");
exit(EXIT_FAILURE);
}
else if (pid[i] == 0)
{
if (i==0) /*P1*/
{
close(p1p0[0]);
close(p2p1[1]);
sleep(1);
processo_p1(argv[1], c);
close(p2p1[0]);
close(p1p0[1]);
exit(EXIT_SUCCESS);
}
else if (i==1)
{
close(p2p1[0]);
close(p1p0[0]);
close(p1p0[1]);
processo_p2(argv[2],c);
close(p2p1[1]);
exit(EXIT_SUCCESS);
}
}
else
{
printf("P0: created child P%d with PID %d\n", i+1, pid[i]);
close(p2p1[0]);
close(p2p1[1]);
close(p1p0[1]);
}
}
i=0;
int nread;
while ( (nread = read(p2p1[0], &buf[i], sizeof(char)) ) > 0 ) {
i++;
buf[i] = '\0';
printf("%s\n",buf);
for(i=0;i<2;i++)
{
wait_child();
}
return 0;
}
void processo_p2(char *inputfile, char *c)
{
int fd, nread, i=0, found=0;
char temp, row[100];
close(1);
dup(p2p1[1]);
execlp("grep", "grep", "-c", c, inputfile, (char *)0);
perror("P2: errorr in exec");
close(1);
}
void processo_p1(char *inputfile, char *c)
{
int fd, nrw, sk, nread, p2=0, i=0;
int value=1;
char temp, row[100], buf[10];
//RECEIVING DATA FROM P2 AND SENDING TO P0
while ( (nread = read(p2p1[0], &buf[i], sizeof(char)) ) > 0 ) {
i++;
}
buf[i] = '\0';
printf("from p2: %s\n",buf); //NOTHING STAMPED
write(p1p0[1],&buf,strlen(buf)+1);
close(1);
dup(p1p0[1]);
execlp("grep", "grep", "-c", c, inputfile, (char *)0);
perror("P1: errore in exec");
close(p1p0[1]);
}
void wait_child() {
int pid_terminated,status;
pid_terminated=wait(&status);
if (pid_terminated < 0)
{
fprintf(stderr, "%d\n", getpid());
perror("P0: errore in wait");
exit(EXIT_FAILURE);
}
if(WIFEXITED(status))
{
printf("P0: terminazione volontaria del figlio %d con stato %d\n",
pid_terminated, WEXITSTATUS(status));
if (WEXITSTATUS(status) == EXIT_FAILURE)
{
fprintf(stderr, "P0: errore nella terminazione del figlio pid_terminated\n");
exit(EXIT_FAILURE);
}
}
else if(WIFSIGNALED(status))
{
fprintf(stderr, "P0: terminazione involontaria del figlio %d a causa del segnale %d\n",
pid_terminated,WTERMSIG(status));
exit(EXIT_FAILURE);
}
}
Trivia (but it stops the code compiling): The code shown originally has a close brace in the wrong place — the functions are all apparently embedded inside main(). The last brace should be moved up the file considerably.
In the loop that launches the child processs, you have the parent process execute:
printf("P0: created child P%d with PID %d\n", i+1, pid[i]);
close(p2p1[0]);
close(p2p1[1]);
close(p1p0[1]);
In the parent process, immediately after the loop, you have:
int nread;
while ( (nread = read(p2p1[0], &buf[i], sizeof(char)) ) > 0 ) {
i++;
buf[i] = '\0';
printf("%s\n",buf);
for(i=0;i<2;i++)
{
wait_child();
}
return 0;
}
'Tis a pity that you closed the file descriptor you're trying to read from. The parent should be reading from p1p0[0], which you did leave open.
Fixes:
Move the set of three closes out of the loop.
Read from the correct file descriptor.
Insert a missing close brace for the while loop shown, or remove its open brace.
The question in the comments has, as usual for comments, inscrutable code. The problem though is that you have too big a loop.
This is what the tail of my fixed version of your main() function looks like:
…rest of loop to launch children…
else
{
printf("P0: created child P%d with PID %d\n", i + 1, pid[i]);
}
}
close(p2p1[0]);
close(p2p1[1]);
close(p1p0[1]);
i = 0;
int nread;
while ((nread = read(p1p0[0], &buf[i], sizeof(char)) ) > 0)
i++;
buf[i] = '\0';
printf("%s\n", buf);
for (i = 0; i < 2; i++)
{
wait_child();
}
return 0;
}
Given that I saved the source code in a file pip.c and created the program pip from it, a sample run produced:
$ ./pip pip.c pip.c c
P0: created child P1 with PID 75458
P0: created child P2 with PID 75459
from p2: 49
49
P0: terminazione volontaria del figlio 75459 con stato 0
P0: terminazione volontaria del figlio 75458 con stato 0
$
I'm not entirely happy with all the newlines, but at least the same answer is given twice, as it obviously should be.
I read the following file (file.txt) line by line:
1
-5
6
-8
-33
21
The father sends negative numbers to a process, and sends positive numbers to a second process:
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/wait.h>
void Fils1(int *tube1)
{
int n;
int cpt = 0;
close (tube1[1]);
while (read (tube1[0], &n, 1) >0)
{
cpt+=n;
}
printf("Son 1, count : %i \n", cpt);
exit (1) ;
}
void Fils2(int *tube2)
{
int n;
int cpt = 0;
close (tube2[1]);
while (read (tube2[0], &n, 1) >0)
{
cpt+=n;
}
printf("Son 2, count : %i \n", cpt);
exit (1) ;
}
int main(int argc, char *argv[])
{
FILE* file;
int n;
file = fopen (argv[1], "r");
if (file == NULL){
printf("Error open file %s\n", argv[1]);
exit(1);
}
int tube1[2];
int tube2[2];
if (pipe(tube1) != 0)
{
fprintf(stderr, "Error tube 1\n");
return EXIT_FAILURE;
}
if (pipe(tube2) != 0)
{
fprintf(stderr, "Error tube 2\n");
return EXIT_FAILURE;
}
int pid1 = fork();
if(pid1 == 0)
{
printf("Creation of the first son ! \n");
Fils1 (tube1);
}
else
{
int pid2 = fork();
if(pid2 == 0)
{
printf("Creation of the second son ! \n");
Fils2 (tube2);
}
else
{
printf("I'm the father! \n");
close (tube1[0]);
close (tube2[0]);
while (!feof(file))
{
fscanf (file,"%d",&n);
if (n>0)
{
write (tube1[1], &n, 1);
}
else
{
write (tube2[1], &n, 1);
}
}
fclose (file);
if(wait(NULL) == -1)
{
printf("Error wait()\n");
exit(1);
}
}
}
return EXIT_SUCCESS;
}
Each son is counting, and displays it on screen.
When I execute, I have only that :
I'm the father!
Creation of the first son!
Creation of the second son!
When I expect also
Son1, count : 28
Son2, count : 46
The problem is you're not closing the pipes as you should.
Child1 should close tube2 (both ends)
Child2 should close tube1 (both ends);
The parent should close write end (after the while)