I have a program with three child processes all doing the exact same thing with a fourth child process told send signals while the main function waits until the three child processes are complete. I am using an alarm signal as well as two user signals to make the child process send output to a different terminal. I'm using the pause function to wait for a signal but the second I start the program it completes, not waiting at all. Am I using pause correctly?
int alarmR =0;
int SNMPR =0;
int reconR=0;
int child_pid[4];
char strD[100];
FILE *fpt[4];
void Alarmhandler(int sig);
void Reconfigure(int sig);
void SNMPhandler(int sig);
int which(int wait_ret, int child_proc[], int p);
void IT1(void);
void IT2(void);
void IT3(void);
void command(void);
void command(void)
{
signal(SIGALRM,Alarmhandler);
signal(SIGUSR1,Reconfigure );
signal(SIGUSR2,SNMPhandler );
char text;
int n;
printf("please enter a command from the following list\n");
printf("\tsn:Send a SNMP request\n\trn:Send a reconfiguration");
printf("script\n\tkn: shutdown process\n");
scanf("%c%d",&text,&n);
if(text == 'k')
{
printf("Terminated IT service %d\n",n);
n = n-1;
kill(child_pid[n],1);
}
else if(text=='s')
{
n = n-1;
kill(child_pid[n],SIGUSR2);
}
else if(text=='r')
{
n = n-1;
kill(child_pid[n],SIGUSR1);
}
}
void Alarmhandler(int sig)
{
alarmR =1;
}
void Reconfigure(int sig)
{
reconR =1;
}
void SNMPhandler(int sig)
{
SNMPR =1;
}
int which(int wait_ret, int child_proc[], int p)
{
int i;
for (i = 0; i < p; i++)
if (child_proc[i] == wait_ret)
return i;
return -1;
}
int main(int argc, char *argv[])
{
int ttyindex;
// int Terminal[4];
int term_cnt = 0;
int wait_r,x;
int process = 0;
int child_proc[4];
int es[3];
if(argc != 5) {
printf("Usage: ./lab7 1 2 3 4\n");
exit(1);
}
for(term_cnt =0; term_cnt <4;term_cnt ++)
{
ttyindex = -1;
ttyindex = atoi(argv[term_cnt+1]);
if (ttyindex < 1) {
printf("invalid terminal number %s\n", argv[term_cnt+1]);
exit(1);
}
sprintf(strD, "/dev/pts/%d", ttyindex);
child_proc[process] = fork();
if (child_proc[process] != 0)
{
// parent process
process++;
child_proc[process] = fork();
if (child_proc[process] != 0)
{
// parent process
process++;
child_proc[process] = fork();
if (child_proc[process] != 0)
{
// parent process
process++;
child_proc[process] = fork();
if(child_proc[process] !=0)
{
wait_r = wait(NULL);
x =which(wait_r, child_proc, process);
printf("Waited for %d (child %d) to finish.\n", wait_r,x);
if(WIFEXITED(wait_r))
{
es[x] = WEXITSTATUS(wait_r);
}
wait_r = wait(NULL);
x =which(wait_r, child_proc, process);
printf("Waited for %d (child %d) to finish.\n", wait_r,x);
if(WIFEXITED(wait_r))
{
es[x] = WEXITSTATUS(wait_r);
}
wait_r = wait(NULL);
x =which(wait_r, child_proc, process);
printf("Waited for %d (child %d) to finish.\n", wait_r,x);
if(WIFEXITED(wait_r))
{
es[x] = WEXITSTATUS(wait_r);
}
for(x = 0; x <3;x++)
{
if(es[x] == 0)
{
printf("\nJob well done IT specialist %d",(x+1));
printf(" Prepare for new attacks!\n");
}
else if(es[x] == 1)
{
printf("\nIT service %d compromised",(x+1));
printf(" , we are going out of business!\n");
}
else
{
printf("\nCall HR, we need a new");
printf(" cybersecurity expert for service");
printf(" %d\n",(x+1));
}
}
}
else
{
child_pid[3] = getpid();
command();
}
}
else
{
child_pid[2]=getpid();
IT3();
}
}
else
{
child_pid[1] = getpid();
IT2();
}
}
else
{
child_pid[0] = getpid();
IT1();
}
}
void IT1(void)
{
printf("i live");
signal(SIGALRM,Alarmhandler);
signal(SIGUSR1,Reconfigure );
signal(SIGUSR2,SNMPhandler );
clock_t start=0, end=0;
static int check = 0;
static int recona =0;
double t= 0;
int threat= 1;
srand48(time(NULL));
fprintf(fpt[1],"This is IT service 1\n");
while(1)
{
printf("%d %d %d",reconR,alarmR,SNMPR);
pause();
// alarm(1);
if(reconR == 1)
{
reconR =0;
if(recona >0)
{
fprintf(fpt[1],"Cannot reconfigure more than once.you are fired!");
exit(1);
}
if(threat < 16)
{
fprintf(fpt[1],"Threat level is not critical.you are fired");
exit(1);
}
fprintf(fpt[1],"Reconfiguring system to thwart attack-this may take a few seconds\n");
recona++;
}
if(alarmR == 1 )
{
if(check >0)
{
t =((double)(end - start))/CLOCKS_PER_SEC;
}
alarmR = 0;
if(recona >0)
{
threat --;
}
else
{
if (drand48() < 0.5)
{
threat++;
}
else if (threat > 1 && drand48() < 0.6)
{
threat--;
}
}
if(t <5)
{
fprintf(fpt[1],"Next report available in %f seconds\n",(5-t));
}
if(threat >15)
{
fprintf(fpt[1],"Intruder! Data stolen...");
exit(1);
}
else if(threat < 10 && recona >0)
{
fprintf(fpt[1],"Attack averted. Mission Complete");
exit(0);
}
}
if(SNMPR == 1)
{
if(check == 2)
{
end = clock();
t = ((double)(end - start))/CLOCKS_PER_SEC;
}
SNMPR = 0;
check = 1;
if(t <5)
{
fprintf(fpt[1],"Load to high. Threat is increased");
threat++;
t = 0;
}
else{
if(threat >=10)
fprintf(fpt[1],"Threat level is red\n");
else if(threat <10 && threat >=5)
fprintf(fpt[1],"Threat level is orange\n");
else
fprintf(fpt[1],"Threat level is green\n");
}
if(check ==1)
{
start = clock();
check = 2;
}
}
}
}
you can use the sigsuspend() system call to make a process wait for a signal, and kill() for sending signal to a process or process group.I hope by using both of these system calls, you can code your desired task.
you are putting a wait() on a process which has no child here
wait_r = wait(NULL);
This causes that wait() return immediately with error ECHILD and terminates the fourth child process. It's termination raises SIGCHLD causes pause() to return.
Related
I'm creating a shell in C and have implemented piping. This involves dividing the argument on the left side and right side of the pipe into two separate array of strings to be executed separately with execvp. For some reason, the array of strings pcmd2 contains data other than the argument I entered in the shell.
For example, I enter ls | sort into the shell after running the program and it outputs the following: sort: open failed: : No such file or directory
Seeing this, I suspected that the array of strings pcmd2 containing the sort command may have empty strings and other things that are being processed.
I print out pcmd2 with a for-loop (with a new line after each string) and I find the following printed onto the screen:
sort
UJ
There clearly seems to be extra stuff in there. Seems like empty strings but I have no clue where the UJ is coming from (this gets consistenly printed out).
I've tried setting the index in pcmd2 that's right after where sort is stored in the array to NULL. Like so, pcmd2[1] = NULL and that seemed to "fix" it since the weird extra data would no longer be processed by the execvp function. However, that means that I can't pipe commands with multiple arguments like grep myshell as it would only be able to take in the grep part.
I will show the full code below because I'm unsure how much context is needed in this case.
I know there's some very broken piping implementation here (I've tried some weird solution to get it work with two pipes) but I'm working to just get one pipe to work. I'm not asking for help piping in particular.
The most relevant part, I believe, is in the splitPipeCommands function.
#include <stdio.h>
#include <sys/wait.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#define MAX_ARGS 20
#define MAX_PIPE_ARGS 3
#define BUFSIZE 1024
int input, output, append, usePipe;
char *inputFile;
char *outputFile;
FILE *fp1;
FILE *fp2;
int get_args(char* cmdline, char* args[])
{
int i = 0;
/* if no args */
if((args[0] = strtok(cmdline, "\n\t ")) == NULL)
return 0;
while((args[++i] = strtok(NULL, "\n\t ")) != NULL) {
if(i >= MAX_ARGS) {
printf("Too many arguments!\n");
exit(1);
}
}
/* the last one is always NULL */
return i;
}
void checkIORedirect(char* args[])
{
input = 0;
output = 0;
append = 0;
int i;
for(i = 0; args[i] != NULL; i++)
{
if(!strcmp(args[i], ">"))
{
output = 1;
outputFile = args[i+1];
args[i] = NULL;
}
else if(!strcmp(args[i], "<"))
{
input = 1;
inputFile = args[i+1];
args[i] = NULL;
//printf("inputFile: %s\n", inputFile);
}
else if(!strcmp(args[i], ">>"))
{
append = 1;
outputFile = args[i+1];
args[i] = NULL;
}
}
}
int getPipeIndexes(char* args[], int* pIndex1, int* pIndex2)
{
*pIndex1 = -1;
*pIndex2 = -1;
int i = 0;
int pcount = 0;
usePipe = 0;
for(i = 0; args[i] != NULL; i++)
{
if(!strcmp(args[i], "|") && pcount == 0)
{
//printf("First pipe!\n");
*pIndex1 = i;
args[i] = NULL;
pcount++;
usePipe = 1;
}
else if(!strcmp(args[i], "|") && pcount == 1)
{
//printf("Second pipe!\n");
*pIndex2 = i;
args[i] = NULL;
pcount++;
}
else if(!strcmp(args[i], "|") && pcount > 1)
{
printf("Too many pipes, only accepting first two!\n");
args[i] = NULL;
}
}
return pcount;
}
void splitPipeCommands(char* args[], int* pIndex1, int* pIndex2, int pcount, char* pcmd1[], char* pcmd2[], char* pcmd3[])
{
if(pcount == 1)
{
int i;
int cmdIndex = 0;
for(i = 0; i < *pIndex1; i++)
{
pcmd1[cmdIndex] = args[i];
cmdIndex++;
}
cmdIndex = 0;
//printf("2nd half of args: \n");
for(i = *pIndex1 + 1; args[i] != NULL; i++)
{
pcmd2[cmdIndex] = args[i];
//printf("%s\n", args[i]);
cmdIndex++;
}
//pcmd2[1] = NULL;
//*pcmd1 = args[0];
//*pcmd2 = args[*pIndex1 + 1];
/*TODO: del when you finish debugging*/
//printf("pcmd1=%s,%s,%s\n", pcmd1[0], pcmd1[1], pcmd1[2]);
//printf("pcmd2=%s\n", pcmd2[0]);
}
else if(pcount == 2)
{
int i;
int cmdIndex = 0;
for(i = 0; i < *pIndex1; i++)
{
pcmd1[cmdIndex] = args[i];
cmdIndex++;
}
cmdIndex = 0;
for(i = *pIndex1 + 1; i < *pIndex2; i++)
{
pcmd2[cmdIndex] = args[i];
cmdIndex++;
}
//pcmd2[1] = NULL;
cmdIndex = 0;
for(i = *pIndex2 + 1; args[i] != NULL; i++)
{
pcmd3[cmdIndex] = args[i];
cmdIndex++;
}
/*
*pcmd1 = args[0];
*pcmd2 = args[*pIndex1 + 1];
*pcmd3 = args[*pIndex2 + 1];
*/
/*TODO: del when you finish debugging*/
//printf("pcmd1=%s,", *pcmd1);
//printf("pcdm2=%s,", *pcmd2);
//printf("pcmd3=%s\n", *pcmd3);
}
}
void closeFiles()
{
if(fp1 != NULL)
{
fclose(fp1);
}
if(fp2 != NULL)
{
fclose(fp2);
}
}
void execute(char* cmdline)
{
int pid, pid2, async;
char* args[MAX_ARGS];
int nargs = get_args(cmdline, args);
if(nargs <= 0) return;
if(!strcmp(args[0], "quit") || !strcmp(args[0], "exit")) {
exit(0);
}
/* check if async call */
if(!strcmp(args[nargs-1], "&")) { async = 1; args[--nargs] = 0; }
else async = 0;
/*Pipe related*/
int pIndex1, pIndex2;
char* pcmd1[30];
char* pcmd2[30];
char* pcmd3[30];
int pcount = getPipeIndexes(args, &pIndex1, &pIndex2);
if(usePipe)
{
splitPipeCommands(args, &pIndex1, &pIndex2, pcount, pcmd1, pcmd2, pcmd3);
if(pcount == 1)
{
checkIORedirect(pcmd1);
checkIORedirect(pcmd2);
}
else if(pcount == 2)
{
checkIORedirect(pcmd1);
checkIORedirect(pcmd2);
checkIORedirect(pcmd3);
}
}
else
{
checkIORedirect(args);
}
/*TODO: del when finished debugging*/
//printf("pIndex1=%d,pIndex2=%d,pcount=%d\n", pIndex1, pIndex2, pcount);
//checkIORedirect(args);
if(output)
{
if((fp1 = fopen(outputFile, "w")) == NULL)
{
printf("Output to file failed!\n");
}
}
else if(append)
{
if((fp1 = fopen(outputFile, "a")) == NULL)
{
printf("Append to file failed!\n");
}
}
if(input)
{
if((fp2 = fopen(inputFile, "r")) == NULL)
{
printf("Input from file failed!\n");
}
}
int fd[2];
int fd2[2];
if(usePipe)
{
if(pipe(fd) == -1)
{
perror("pipe failed");
exit(1);
}
}
pid = fork();
if(pid == 0) { /* child process */
if(input)
{
//printf("Input\n");
dup2(fileno(fp2), STDIN_FILENO);
fclose(fp2);
input = 0;
}
if(output || append)
{
dup2(fileno(fp1), STDOUT_FILENO);
fclose(fp1);
output = 0;
append = 0;
//printf("Output or append\n");
}
if(usePipe)
{
//TODO: Make case for one pipe and two pipes
if(pcount == 2)
{
if(pipe(fd2) == -1)
{
perror("pipe failed");
exit(1);
}
pid2 = fork();
if(pid2 == -1)
{
perror("fork 2 failed");
exit(1);
}
if(pid2 == 0) //Child 2
{
close(fd[1]);
close(fd[0]);
close(fd2[1]);
dup2(fd2[0], 0);
close(fd2[0]);
execvp(pcmd2[0], pcmd2);
perror("exec second child failed");
exit(-1);
}
else //Child 1
{
close(fd[1]);
dup2(fd[0], 0);
close(fd[0]);
close(fd2[0]);
dup2(fd2[1], 1);
close(fd2[1]);
execvp(pcmd3[0], pcmd3);
perror("exec first child failed");
exit(-1);
}
}
else if(pcount == 1)
{
//TODO: pipe for one pipe
//close(fd[1]);
//dup2(fd[0], 0);
dup2(fd[1], STDOUT_FILENO);
close(fd[0]);
close(fd[1]);
printf("pcmd1=%s\n", pcmd1[0]);
execvp(pcmd1[0], pcmd1);
perror("exec child failed");
exit(-1);
}
}
else
{
execvp(args[0], args);
/* return only when exec fails */
perror("exec failed");
exit(-1);
}
/*
execvp(args[0], args);
// return only when exec fails
perror("exec failed");
exit(-1);
*/
} else if(pid > 0) { /* parent process */
if(usePipe)
{
pid=fork();
if(pid==0)
{
dup2(fd[0], STDIN_FILENO);
close(fd[1]);
close(fd[0]);
printf("pcmd2 contents: \n");
int j;
for(j = 0; pcmd2[j] != NULL; j++)
{
printf("%s\n", pcmd2[j]);
}
//FIXME: Something's wrong with pcmd2
execvp(pcmd2[0], pcmd2);
//execlp("sort", "sort", (char*)NULL);
perror("exec second command failed");
}
else
{
int status;
close(fd[0]);
close(fd[1]);
waitpid(pid, &status, 0);
}
//wait(NULL);
/*
close(fd[0]);
dup2(fd[1], 1);
printf("pcmd1=%s\n", pcmd1[0]);
execvp(pcmd1[0], pcmd1);
perror("exec parent failed");
*/
}
if(!async)
{
waitpid(pid, NULL, 0);
}
else
{
printf("this is an async call\n");
}
} else { /* error occurred */
perror("fork failed");
exit(1);
}
}
int main (int argc, char* argv [])
{
char cmdline[BUFSIZE];
for(;;) {
printf("COP4338$ ");
if(fgets(cmdline, BUFSIZE, stdin) == NULL) {
perror("fgets failed");
exit(1);
}
execute(cmdline);
usePipe = 0;
//closeFiles();
fflush(stdout);
}
return 0;
}
Hi I've recently started learning unix system programming.
I'm trying to create a minishell in c but when I run my code,
I always get:
EXC_BAD_ACCESS (code=EXC_I386_GPFLT
Don't really know what's wrong here. Searched online they say it's something wrong with malloc, but I don't see what's wrong.
Can someone help me with this problem?
#include <stdlib.h>
#include <fcntl.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <string.h>
#include <unistd.h>
#include "minishell.h"
char promptString[] = "mysh>";
struct command_t command;
int enviromentlength;
int commandlength;
char *pathv[MAX_PATHS];
//to display the prompt in the front of every line
void printPrompt()
{
printf("%s", promptString);
}
//get the user's command
void readCommand(char *buffer)
{
gets(buffer);
}
//get the environment variable and store in a pathEnvVar
int parsePath( char* dirs[] )
{
char* pathEnvVar;
char* thePath;
int i;
for(i = 0; i < MAX_ARGS; i++)
{
dirs[i] = NULL;
}
i = 0;
//use system call to get the environment variable
pathEnvVar = (char*) getenv("PATH");
//printf("%s\n", pathEnvVar);
thePath = (char*) malloc(strlen(pathEnvVar) + 1);
strcpy(thePath, pathEnvVar);
//splict the variable and store in the pathv
char *temp = strtok(thePath, ":");
dirs[i] = temp;
while(temp != NULL)
{
i++;
temp = strtok(NULL, ":");
if(temp == NULL)
{
break;
}
else
{
dirs[i] = temp;
}
}
dirs[i+1] = NULL;
return i;
}
//get the user's command and parameters
int parseCommand(char * commandline)
{
int i = 0;
char* temp;
temp = strtok(commandline, " ");
while(temp != NULL)
{
command.argv[i] = temp;
i++;
temp = strtok(NULL, " ");
}
command.argv[i] = NULL;
return i;
}
//input the user's command to
//fix the absolute path of the command
char* lookupPath(char* dir[], char* command[])
{
char* result = NULL;
int i;
//printf("%c\n", *command.argv[0]);
//if the command is already an absolute path
if(*command[0] == '/')
{
result = command[0];
//printf("test\n");
if( access(result, X_OK) == 0)
{
return result;
}
else
{
fprintf(stderr, "%s: command not found\n", result);
return NULL;
}
}
//if the command is not an absolute path
else
{
for(i = 0; i < enviromentlength; i++)
{
char *temp = (char *) malloc (30);
strcpy(temp, dir[i]);
strcat(temp, "/");
strcat(temp, command[0]);
result = temp;
if( access(result, X_OK) == 0)
{
return result;
}
}
fprintf(stderr, "%s: command not found\n", result);
return NULL;
}
}
//to change the directory and
//display the absolute path of the current directory
void do_cd(char* dir[])
{
char currentdirectory[MAX_PATHS];
if(dir[1] == NULL || (strcmp(dir[1], ".") == 0))
{
printf("director does not change\n");
//printf("The current directory is:%s", currentdirectory);
}
else
{
if(chdir(dir[1]) < 0)
{
printf("change director error\n");
}
else
{
printf("change director success\n");
}
}
getcwd(currentdirectory, MAX_PATHS);
printf("The current directory is:%s\n", currentdirectory);
}
//redirection the result to file
void redirection(char* command, char* commandcontent[], int position, pid_t thisChPID)
{
char* content[commandlength - 1];
char* filename = (char *) malloc(MAX_PATH_LEN);
FILE* fid;
int i = 0;
int stat;
strcpy(filename, commandcontent[position + 1]);
//printf("%s\n", commandcontent[position + 1]);
for(i = 0; i < position; i++)
{
content[i] = commandcontent[i];
//printf("content: %s\n", content[i]);
}
content[i + 1] = NULL;
for(i = 0; i< position + 1; i++)
{
printf("%s\n", content[i]);
}
printf("%s\n", command);
if((thisChPID=fork()) < 0)
{
fprintf(stderr, "fork failed\n");
}
else if(thisChPID == 0)
{
fid = open(filename, O_WRONLY || O_CREAT);
close(1);
dup(fid);
close(fid);
execve(command, content, pathv);
}
else
{
wait(&stat);
}
}
//use pipe to run the program
void piperun(char* command, char* commandcontent[], int position, pid_t thisChPID)
{
printf("%s\n%d\n", command, position);
char* firstcommand[position+1];
char* secondcommand[commandlength-position];
char* result = (char *) malloc(MAX_PATH_LEN);
pid_t child;
//the pipe name
int pipeID[2];
int j;
for(j = 0; j< position; j++)
{
firstcommand[j] = commandcontent[j];
printf("%s\n", firstcommand[j]);
}
firstcommand[j] = NULL;
printf("length: %d\n", commandlength-position);
for(j = 0; j < (commandlength-position); j++)
{
secondcommand[j] = commandcontent[position + 1 + j];
printf("second:%s\n",secondcommand[j]);
}
//secondcommand[j+1] = NULL;
result = lookupPath(pathv, secondcommand);
//printf("%s\n", secondcommand[0]);
printf("%s\n", result);
//create pipe "pipeID"
if(pipe(pipeID)==-1)
{
printf("Fail to creat pipe.\n");
}
if((thisChPID=fork())==-1)
{
printf("Fail to creat child process.\n");
}
if(thisChPID==0)
{
printf("in the child\n");
close(1);
dup(pipeID[1]);
close(pipeID[0]);
close(pipeID[1]);
if(execve(command, firstcommand, pathv)==-1)
{
printf("Child process can't exec command %s.\n",firstcommand[0]);
}
}
else
{
child = fork();
if((child=fork())==-1)
{
printf("Fail to creat child process.\n");
}
if(child==0)
{
close(0);
dup(pipeID[0]);
close(pipeID[1]);
close(pipeID[0]);
if(execve(result, secondcommand, pathv)==-1)
{
printf("Child process can't exec command %s.\n",secondcommand[0]);
}
}
else
{
wait(NULL);
}
}
}
int main()
{
char commandLine[LINE_LEN];
int child_pid; //child process id
int stat; //used by parent wait
pid_t thisChPID;
char *arg[MAX_ARGS];
//the flag of redirection, piping and background running
int redirectionsituation = 0;
int pipesituation = 0;
int background = 0;
char * tempchar;
//Command initialization
int i;
for(i = 0; i < MAX_ARGS; i++ )
{
command.argv[i] = (char *) malloc(MAX_ARG_LEN);
}
//get all directories from PATH env var
enviromentlength = parsePath(pathv);
//Main loop
while(TRUE)
{
redirectionsituation = 0;
pipesituation = 0;
background = 0;
//Read the command line
printPrompt();
readCommand(commandLine);
//input nothing
if(commandLine[0] == '\0')
{
continue;
}
//quit the shell?
if((strcmp(commandLine, "exit") == 0) || (strcmp(commandLine, "quit") == 0))
{
break;
}
//if it is background running
if(commandLine[strlen(commandLine) - 1] == '&')
{
printf("backgrond\n");
tempchar = strtok (commandLine, "&");
//strcpy(commandLine, tempchar);
printf("%s\n", tempchar);
background = 1;
}
//Parse the command line
commandlength = parseCommand(commandLine);
//if the command is "cd"
if(strcmp(command.argv[0], "cd") == 0)
{
do_cd(command.argv);
continue;
}
//Get the full path name
command.name = lookupPath(pathv, command.argv);
printf("command name %s\n", command.name);
//report error
if( command.name == NULL)
{
continue; //non-fatal
}
//if redirection is required
for(i = 0; i < commandlength; i++)
{
if(strcmp(command.argv[i], ">") == 0)
{
redirectionsituation = 1;
break;
}
}
if(redirectionsituation == 1)
{
redirection(command.name, command.argv, i, thisChPID);
continue;
}
//if pipe is required
for(i = 0; i < commandlength; i++)
{
if(strcmp(command.argv[i], "|") == 0)
{
pipesituation = 1;
break;
}
}
if(pipesituation == 1)
{ //run pipe
piperun(command.name, command.argv, i, thisChPID);
continue;
}
//normal running
if((thisChPID=fork()) < 0)
{
fprintf(stderr, "fork failed\n");
}
else if(thisChPID == 0)
{
//printf("run again\n");
execve(command.name, command.argv, pathv);
}
else
{
//do not put the process in the background, wait until the child process terminates
if(background == 0)
{
wait(&stat);
}
}
}
return 0;
}
Run it in a debugger and see where you are dereferencing a null.
I have a problem with accessing semaphore in child process. I can't get already created semaphore through semget() when in child process.
Here is make_semaphores() function;
int make_semaphores(key_t key)
{
int semid;
semid = semget(key, 3, IPC_CREAT|/*IPC_EXCL|*/0666);
if(semid == -1)
{
perror("Creating an array of semaphores");
exit(1);
}
if(semctl(semid,0,SETVAL, (int)MAX)==-1)
{
perror("Initializing 'empty' semaphore");
exit(1);
}
if(semctl(semid,1,SETVAL, (int)0)==-1)
{
perror("Initializing 'full' semaphore");
exit(1);
}
if(semctl(semid,2,SETVAL, (int)1)==-1)
{
perror("Initializing mutex");
exit(1);
}
return semid;
}
Here is allocate_memory function:
int* allocate_memory(int *buf, key_t key)
{
int shmid;
shmid=shmget(key,(MAX+1)*sizeof(int),IPC_CREAT|/*IPC_EXCL|*/0666);
if(shmid==-1)
{
perror("Creating shared memory segment");
exit(1);
}
buf=(int*)shmat(shmid,NULL,0);
if(buf==NULL)
{
perror("Including shared memory segment");
exit(1);
}
buf[0]=0;
return buf;
}
I searched and didn't find a satisfying answer, so sorry if I'm needlessly spamming. Thanks in advance for any kind of help.
Here is full main:
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <sys/shm.h>
#include <sys/wait.h>
#define S1KEY 467221
#define S2KEY 379231
#define S3KEY 217411
#define MAX 10
int main(int argc, char* argv[])
{
srand(time(NULL));
int fork_id;
int *buf1, *buf2, *buf3;
int semid1, semid2, semid3, i, j, r, smd1;
int prod_info[3]={0,0,0}, cons_info[3]={0,0,0};
printf("-------------------\n");
buf1=allocate_memory(buf1,S1KEY);
buf2=allocate_memory(buf2,S2KEY);
buf3=allocate_memory(buf3,S3KEY);
printf("-------------------\n");
semid1=make_semaphores(S1KEY);
semid2=make_semaphores(S2KEY);
semid3=make_semaphores(S3KEY);
smd1=semget(S1KEY,3,0666);//here is okay
if(semid1!=smd1)
{
printf("semid1: %d smd1: %d\n",semid1,smd1);
perror("S1KEY does not exist");
}
printf("----------------\n");
for(i=0;i<4;++i)
{
fork_id=fork();
if(fork_id<0)
{
perror("fork()");
exit(1);
}
else if(fork_id==0)// one of four children
{
smd1=semget(S1KEY,3,0666);//here is NOT okay, smd returns -1
if(smd1==-1)
{
printf("[%d]semid1: %d smd1: %d\n",i,semid1,smd1);
perror("S1KEY does not exist");
}
if(i==3) //producer for 3 buffers
{
for(j=0;j<100;j++)
{
r=(rand()%3)+1;
printf("-------------------------\n");
if(r==1)
{
printf("Prod:1||%d||%d\n",prod_info[0],getval_semaphores(semid1,0));
printf(" %d\n", buf1[0]);
produce(buf1,semid1,i);
prod_info[0]++;
}
else if(r==2)
{
printf("Prod:2||%d||%d\n",prod_info[1],getval_semaphores(semid2,0));
printf(" %d\n", buf2[0]);
produce(buf2,semid2,i);
prod_info[1]++;
}
else
{
printf("Prod:3||%d||%d\n",prod_info[2],getval_semaphores(semid3,0));
printf(" %d\n", buf3[0]);
produce(buf3,semid3,i);
prod_info[2]++;
}
}
printf("Produced: 1:%d 2:%d 3:%d\n", prod_info[0],prod_info[1],prod_info[2]);
exit(1);
}
else if(i==2) //3 consumers for 3 buffers (1,2,3)
{
for(j=0;j<100;j++)
{
//usleep(1);
printf("Cons:3\n");
printf("%d\n", buf1[0]);
printf("%d\n", buf2[0]);
printf("%d\n", buf3[0]);
cons_info[0]=consume(buf1,semid1);
cons_info[1]=consume(buf2,semid2);
cons_info[2]=consume(buf3,semid3);
printf("Buf1: %d\n",cons_info[0]);
printf("Buf2: %d\n",cons_info[1]);
printf("Buf3: %d\n",cons_info[2]);
}
exit(1);
}
else if(i==1) //2 consumers for 2 buffers (2,3)
{
for(j=0;j<100;j++)
{
//usleep(1);
printf("Cons:2\n");
printf("%d\n", buf2[0]);
printf("%d\n", buf3[0]);
cons_info[1]=consume(buf2,semid2);
cons_info[2]=consume(buf3,semid3);
printf("Buf2: %d\n",cons_info[1]);
printf("Buf3: %d\n",cons_info[2]);
}
exit(1);
}
else if(i==0) //1 consumer for 1 buffer (3)
{
for(j=0;j<100;j++)
{
//usleep(1);
printf("Cons:1\n");
printf("%d\n", buf3[0]);
cons_info[2]=consume(buf3,semid3);
printf("Buf3: %d\n",cons_info[2]);
}
exit(1);
}
}
else
{
if(i==4) //Parent, waits after making children
{
smd1=semget(S1KEY,3,0666);
if(semid1!=smd1)
{
printf("[%d]semid1: %d smd1: %d\n",i,semid1,smd1);
perror("S1KEY does not exist");
}
printf("Parent\n");
wait(NULL);
}
}
}
break_semaphores(semid1);
break_semaphores(semid2);
break_semaphores(semid3);
return 0;
}
I am afraid you misunderstand how the creation of processes works.
Parent/Child process model
The process creation model is generally as follows
pid_t p1 = fork();
if (p1 < 0) {
perror("problem forking");
}
else if (p1 == 0) {
// parent process
printf("parent process\n");
// do_parent_process_stuff()
}
else {
// child process
printf("child process: %d\n", p1);
// do_child_process_stuff()
}
Correction to your code
As for your code, in your main function you will want to replace
for(i=0;i<4;++i)//parent creates four children
{
fork_id=fork();
smd1=semget(S1KEY,3,0666);//here is NOT okay (when in child process), smd returns -1
if(smd1==-1)
{
printf("[%d]semid1: %d smd1: %d\n",i,semid1,smd1);
perror("S1KEY does not exist");
}
//the rest
with something like this
/* Start children. */
for (i = 0; i < n; ++i) {
if ((pids[i] = fork()) < 0) {
perror("error forking");
}
// parent
else if (pids[i] == 0) {
exit(0);
}
// child process
else {
smd1=semget(S1KEY,3,0666);
if(smd1==-1)
{
printf("[%d]semid1: %d smd1: %d\n",i,semid1,smd1);
perror("S1KEY does not exist");
}
else {
// do stuff with semaphores
}
}
}
I'm writing a small shell as an exercis to learn C. Now I can execute custom commands like ls and date but when I try to run firefox it doesn't start. Why? My session is
$ ./a.out
miniShell>> ls
ls
a.out digenv2.c~ digenv.c.orig miniShell.c README.md test
digenv digenv.c digenv.old.c miniShell.c~ smallshell.c
digenv2.c digenv.c~ LICENSE miniShell.c.orig smallshell.c.orig
miniShell>> date
date
Tue May 12 09:38:27 CEST 2015
miniShell>> firefox
firefox
miniShell>>
My program is
#include <sys/stat.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <dirent.h>
#include <errno.h>
#include <stdarg.h>
#include <stdlib.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/wait.h>
#define BUFFER_LEN 1024
#define BUFFERSIZE 1024
pid_t foreground = -1;
int mystrcmp(char const *, char const *);
struct command
{
char * const *argv;
};
void err_syserr(char *fmt, ...)
{
int errnum = errno;
va_list args;
va_start(args, fmt);
vfprintf(stderr, fmt, args);
va_end(args);
if (errnum != 0)
fprintf(stderr, "(%d: %s)\n", errnum, strerror(errnum));
exit(EXIT_FAILURE);
}
int StartsWith(const char *a, const char *b)
{
if(strncmp(a, b, strlen(b)) == 0) return 1;
return 0;
}
/* Helper function that spawns processes */
/*static int spawn_proc(int in, int out, struct command *cmd)
{
pid_t pid;
if ((pid = fork()) == 0)
{
if (in != 0)
{
if (dup2(in, 0) < 0)
err_syserr("dup2() failed on stdin for %s: ", cmd->argv[0]);
;
close(in);
}
if (out != 1)
{
if (dup2(out, 1) < 0)
err_syserr("dup2() failed on stdout for %s: ", cmd->argv[0]);
close(out);
}
fprintf(stderr, "%d: executing %s\n", (int)getpid(), cmd->argv[0]);
execvp(cmd->argv[0], cmd->argv);
err_syserr("failed to execute %s: ", cmd->argv[0]);
}
else if (pid < 0) {
err_syserr("fork failed: ");
}
return pid;
}*/
/* Helper function that forks pipes */
/*static void fork_pipes(int n, struct command *cmd)
{
int i;
int in = 0;
int fd[2];
for (i = 0; i < n - 1; ++i)
{
pipe(fd);
spawn_proc(in, fd[1], cmd + i);
close(fd[1]);
in = fd[0];
}
if (dup2(in, 0) < 0) {
err_syserr("dup2() failed on stdin for %s: ", cmd[i].argv[0]);
}
fprintf(stderr, "%d: executing %s\n", (int)getpid(), cmd[i].argv[0]);
execvp(cmd[i].argv[0], cmd[i].argv);
err_syserr("failed to execute %s: ", cmd[i].argv[0]);
}*/
/*Remove zoombie processes*/
/*Return if background process terminated*/
/*
http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/signal.h.html
*/
void Janitor(int status) {
if(status==SIGCHLD) { /*Child process terminated, stopped, or continued*/
int a = 1;
while(a) {
pid_t pid_my1 = waitpid(-1, &status, WNOHANG);
/*WNOHANG = return immediately if no child has exited*/
/*Wait*/
/*http://linux.die.net/man/2/waitpid*/
if(0<pid_my1) { /*Still things to clean up*/
if(pid_my1!=foreground) { /*Don't stop me since it's the foregound process*/
/*http://linux.die.net/man/3/wait*/
if(WIFEXITED(status)) { /*Child process terminated*/
printf("%d terminated", pid_my1);
}
}
}
else { /*All work done, for now*/
a = 0;
}
}
}
}
int main() {
char line[BUFFER_LEN];
char* argv[100];
char* path= "/bin/";
char progpath[20];
int argc;
size_t length;
char *token;
int i=0;
int pid;
char *tokenstr;
char *search = " ";
int isSignal = 0;
int isBackground = 0;
#ifdef SIGDET
#if SIGDET == 1
isSignal = 1; /*Termination detected by signals*/
#endif
#endif
while(1) {
i = 0;
int built_in_command = 0;
printf("miniShell>> ");
if(!fgets(line, BUFFER_LEN, stdin)) {
break;
}
length = strlen(line);
if (line[length - 1] == '\n') {
line[length - 1] = '\0';
}
if(strcmp(line, "exit")==0) {
break;
}
if(StartsWith(line, "cd")) {
built_in_command=1;
printf("change directory\n");
tokenstr = strtok(line, search);
tokenstr = strtok(NULL, search);
chdir(tokenstr);
/*TODO maybe have a check whether extra argument exist, if not go to home directory*/
}
token = strtok(line," ");
while(token!=NULL) {
argv[i]=token;
token = strtok(NULL," ");
i++;
}
if(StartsWith(line, "checkEnv")) {
built_in_command=1;
if (0==i) {
char *printenv[] = { "printenv", 0};
char *sort[] = { "sort", 0 };
char *less[] = { "less", 0 };
struct command cmd[] = { {printenv}, {sort}, {less} };
fork();
}
else {
char *tmp;
int len = 1;
for (i = 1; i < argc; i++)
{
len += strlen(argv[i]) + 2;
}
tmp = (char *) malloc(len);
tmp[0] = '\0';
int pos = 0;
for (i = 1; i < argc; i++)
{
pos += sprintf(tmp + pos, "%s%s", (i == 1 ? "" : "|"), argv[i]);
}
char *printenv[] = { "printenv", 0};
char *grep[] = { "grep", "-E", tmp, NULL};
char *sort[] = { "sort", 0 };
char *less[] = { "less", 0 };
struct command cmd[] = { {printenv}, {grep}, {sort}, {less} };
fork();
free(tmp);
}
}
if(0==built_in_command) { /*Not a built in command, so let execute it*/
argv[i]=NULL;
argc=i;
for(i=0; i<argc; i++) {
printf("%s\n", argv[i]);
}
strcpy(progpath, path);
strcat(progpath, argv[0]);
for(i=0; i<strlen(progpath); i++) {
if(progpath[i]=='\n') {
progpath[i]='\0';
}
}
isBackground = 0;
sigset_t my_sig;
pid_t pid_temp;
int lastElem = (sizeof(line)/sizeof(line[0]))-1; /*Last input argument index*/
/*TODO check if background process*/
/*TODO store the time forground process started*/
int fd[2];
if (isBackground == 1) { //If backgroundprocess
pipe(fd); /*(two new file descriptors)*/
/*FIXME pid_temp = fork_pipes(2, .....);*/
pid_temp = fork();
}
else if (isBackground == 0) { //If foreground process
int isSignal = 0; /*FIXME*/
if (1 == isSignal) { /*If using signaldetection*/
sigemptyset(&my_sig); /*empty and initialising a signal set*/
sigaddset(&my_sig, SIGCHLD); /*Adds signal to a signal set (my_sig)*/
/*http://pubs.opengroup.org/onlinepubs/7908799/xsh/sigprocmask.html*/
sigprocmask(SIG_BLOCK, &my_sig, NULL);
}
/*FIXME pid_temp = fork_pipes(2, .....);*/
pid_temp = fork();
foreground = pid_temp; /*Set pid for foreground process*/
}
if (0<pid_temp) {
/*Parent process*/
}
else if (0>pid_temp) {
/*Error*/
}
else {
/*Child process*/
if (1 == isBackground) { //Backgroundprocess
dup2(fd[STDIN_FILENO], STDIN_FILENO);
close(fd[0]);
close(fd[1]);
}
execvp(progpath,argv);
/*TODO execute command here, some is working*/
}
if (0 == isBackground) { //Foregroundprocess
/*Write here, Emil*/
int status = 0;
waitpid(pid_temp, &status, 0);
/*Foregroundprocess terminated*/
/*TODO How long time was the total execution time*/
int isSignal = 0; /*FIXME*/
if (1 == isSignal) { /*If using signaldetection*/
int a = sigprocmask(SIG_UNBLOCK, &my_sig, NULL);
/*http://man7.org/linux/man-pages/man2/sigprocmask.2.html*/
if (0 == a) {
/*Sigprocmask was successfull*/
}
else {
/*Sigprocmask was not successfull, return=-1*/
}
Janitor(SIGCHLD);
}
}
else if (1==isBackground) {
close(fd[0]);
close(fd[1]);
}
}
/* pid= fork();
if(pid==0) {
execvp(progpath,argv);
fprintf(stderr, "Child process could not do execvp\n");
} else {
wait(NULL);
printf("Child exited\n");
}*/
}
return (0);
}
int mystrcmp(char const *p, char const *q)
{
int i = 0;
for(i = 0; q[i]; i++)
{
if(p[i] != q[i])
return -1;
}
return 0;
}
int cd(char *pth) {
char path[BUFFERSIZE];
char cwd[BUFFERSIZE];
char * return_value;
int other_return;
strcpy(path,pth);
if(pth[0] != '/')
{
return_value = getcwd(cwd,sizeof(cwd));
strcat(cwd,"/");
strcat(cwd,path);
other_return = chdir(cwd);
} else {
other_return = chdir(pth);
}
printf("Spawned foreground process: %d\n", getpid());
return 0;
}
The issue is with the path. You always assume the command is in /bin/ whereas firefox is usually in /usr/bin/. So your child is going to exec /bin/firefox and fail. Checking the return code of execvp would have helped finding this. On success, execvp family functions don't return. So if they do, you know why.
I am trying to implement a basic linux shell with support for pipelining. However, my code seems to hang or just not execute programs and I can't figure out why.
if (list_empty(&job_list))
job_index = 1;
bool dopipe = false;
if (list_size(&pipeline->commands) > 1)
dopipe = true;
esh_signal_sethandler(SIGCHLD, signal_handler);
esh_signal_block(SIGCHLD);
setpgid(0, 0);
pipeline->pgrp = getpgid(0);
pipeline->jid = job_index++;
list_push_back(&job_list, &pipeline->elem);
bool background = pipeline->bg_job;
pid_t pid;
if ( (pid = fork()) == 0)
{
//Child
if (pipeline->bg_job)
setpgid(0, 0);
int oldpipe[2];
int newpipe[2];
int count = 0;
int size = list_size(&pipeline->commands);
struct list_elem * current_job;
printf("SIZE: %zu\n", list_size(&pipeline->commands));
for (current_job = list_begin(&pipeline->commands); current_job != list_tail(&pipeline->commands); current_job = list_next(current_job))
{
if (count < size)
pipe(newpipe);
pid_t fpid = fork();
printf("fpid: %d\n", (int)fpid);
if (fpid == 0)
{
//Child
printf("Executing Child\n");
if (count > 0)
{
//prev command exists
dup2(oldpipe[0], 0);
close(oldpipe[0]);
close(oldpipe[1]);
}
if (count < size - 1)
{
//next command exists
close(newpipe[0]);
dup2(newpipe[1], 1);
close(newpipe[1]);
}
esh_command* cmd = list_entry(current_job, struct esh_command, elem);
printf("Running: %s %s\n", cmd->argv[0], cmd->argv[1]);
if (execvp(cmd->argv[0], cmd->argv) < 0)
esh_sys_fatal_error("Program Does Not Exist\n");
}
else
{
//Parent
//*
int status = 0;
if (waitpid(fpid, &status, 0) < 0)
esh_sys_fatal_error("Could not fork pipe\n");
//*/
printf("Parent\n");
if (count > 0)
{
//prev command exists
close(oldpipe[0]);
close(oldpipe[1]);
}
if (count < size - 1)
{
//next command exists
oldpipe[0] = newpipe[0];
oldpipe[1] = newpipe[1];
}
printf("End of Parent\n");
}
count++;
}
if (size > 1)
{
close(oldpipe[0]);
close(oldpipe[1]);
}
printf("Finished Pipeline\n");
exit(3);
}
else
{
//*
int status = 0;
commands->pid = pid;
//Parent
if (!background)
{
pipeline->status = FOREGROUND;
if (waitpid(pid, &status, 0) < 0)
printf("waitpid ERROR\n");
list_remove(&pipeline->elem);
}
else
pipeline->status = BACKGROUND;
//*/
}
esh_signal_unblock(SIGCHLD);
I am fairly certain the error has to do with either the piping, or the forking of child processes in the loop.