I know there are many threads that talk about this problem but I don't really understand the way it can be done.
I'm trying to make a shell that can execute a linux command sucha as ps | grep | less
I've donne the parsing by puting every command and its args in a simply linked list.
Here's my implementation that doesn't work. Hope that's clear enough.
if ((son = fork()) < 0)
return printerr_sys("Unable to fork", 0);
if (son == 0)
{
if (first > 1 && data->format[first - 1] &&
is_directing_elt(data->format[first - 1]) == DIRECT_TPIPE)
dup2(tube_p[0], STDIN_FILENO);
first = make_argv(data, first, &argv);
if (next)
{
dup2(tube_v[1], STDOUT_FILENO);
close(tube_v[0]);
}
if (execvp(argv[0], argv) < 0)
return printerr_cmd(argv[0], 1);
}
else
{
if (next)
{
close(tube_v[1]);
cmdline_executer(data, next, tube_v);
}
waitpid(son, &(data->lastcmd), WUNTRACED);
data->lastcmd = WEXITSTATUS(data->lastcmd);
}
return TRUE;
My questions are:
What would be the correct implementation?
Is it possible to do it with recursion?
Do I need to fork from right to left or left to right (logically it give the same result)?
Here's a part of a UNIX Shell I had to implement in C for Operating System subject in my Computer Science career.
/* Executes the command 'buffer' assuming that doesn't contain redirections */
void execute_only_pipes(char* buffer)
{
char *temp = NULL, *pipeCommands[MAX_PIPES], *cmdArgs[MAX_ARGUMENTS];
int newPipe[2], oldPipe[2], pipesCount, aCount, i, status;
pid_t pid;
pipesCount = -1; /* This variable will contain how many pipes the command contains */
/* Counting the number of pipes and splitting them into pipeCommands */
do
{
temp = strsep(&buffer, "|");
if(temp != NULL)
{
if(strlen(temp) > 0)
{
pipeCommands[++pipesCount] = temp;
}
}
} while(temp);
cmdArgs[++pipesCount] = NULL;
for(i = 0; i < pipesCount; i++) /* For each command */
{
aCount = -1;
/* Parsing command & arguments */
do
{
temp = strsep(&pipeCommands[i], " ");
if(temp != NULL)
{
if(strlen(temp) > 0)
{
/* If a parameter is ~, then replace it by /home/user */
if (!strcmp(temp, "~"))
strcpy(temp, home);
cmdArgs[++aCount] = temp;
}
}
} while(temp);
cmdArgs[++aCount] = NULL;
/* If there still are commands to be executed */
if(i < pipesCount-1)
{
pipe(newPipe); /* just create a pipe */
}
pid = fork();
if(pid == 0) /* Child */
{
/* If there is a previous command */
if(i > 0)
{
close(oldPipe[1]);
dup2(oldPipe[0], 0);
close(oldPipe[0]);
}
/* If there still are commands to be executed */
if(i < pipesCount-1)
{
close(newPipe[0]);
dup2(newPipe[1], 1);
close(newPipe[1]);
}
/* Execute it */
int res = execvp(cmdArgs[0], cmdArgs);
if (res == -1)
{
printf("Error. Command not found: %s\n", cmdArgs[0]);
}
exit(1);
}
else /* Father */
{
/* If there is a previous command */
if(i > 0)
{
close(oldPipe[0]);
close(oldPipe[1]);
}
/* do we have a next command? */
if(i < pipesCount-1)
{
oldPipe[0] = newPipe[0];
oldPipe[1] = newPipe[1];
}
/* wait for last command process? */
if(i == pipesCount-1)
{
waitpid(pid, &status, 0);
}
}
}
}
It might be a little buggy (I'm not checking if fork() < 0, etc) but the main idea is correct.
> Is it possible to do it with recursion?
Most of the time I try to avoid recursion, if I can write a similar understandable code without using it.
Processes run independently, so you need to set up the pipe for at least the first pair of commands before you fork, but you're doing that in the child (son == 0). You could code a recursive solution that, as long as there are at least two commands left, creates a pipe, then forks, then runs the first command.
Related
1) I can't use some commands in this code, such as : cat somefile.txt > somefile2.txt
also I can't use : cat somefile.txt | less
2) When I use commands like : ( cd ../) (cd ./Desktop) and then I want to exit the program, I need to execute exit commands more than one time: ie "if I use 3 cd command, I will need 3 exit commands to end the program"
#define MAX_ARGS 5
// Global Declarations
// Mini Functions
void remove_new_line_char(char line[])
{
int i=0;
while(line[i]!= '\n')
i++;
line[i] = '\0';
}
// Grand Functions
int read_line(char line[])
{
fgets(line, 10000, stdin); // File Get String
remove_new_line_char(line); // Remove New Line Charactere
if (strlen(line) > 512)
{
fprintf(stderr,"The Command exceeded available line length\n");
return 0;
}
if (strcmp(line, "exit") == 0)
exit(0);
return 1;
}
int parse_line(char* args[], char line[])
{
int i=0;
args[i] = strtok(line, " ");
if(args[i] == NULL)
{
printf("Command Line is Empty!\n");
return -1;
}
while (args[i] != NULL)
{
int flag = 0;
if(strcmp(args[i],"&") == 0)
flag = 1;
i++;
args[i] = strtok(NULL, " "); // NULL maintains a static pointer to the previously passed string.
if (args[i] == NULL && flag == 1)
{
args[i-1] = NULL; // Remove & From Argument List and Set Background Flag.
return 1;
}
}
return 0;
}
// Main
int main()
{
char* args[MAX_ARGS]; // Array of Strings
char line[10000]; // String
while(1)
{
printf("Shell> ");
if(read_line(line) == 1) // No Errors
{
int background = parse_line(args, line);
if(background != -1) // Command Line isn't Empty
{
// Fork and Execute
pid_t child_pid = fork();
if(child_pid == 0) // Child
{
if (strcmp(args[0], "cd") == 0 && args[1]!= NULL && args[2] == NULL) // Special Handling For CD
{
//printf("%s\n",args[2]);
int check = chdir(args[1]);
if(check == -1)
fprintf(stderr, "Invalid Directory\n");
}
// Handle if args[1]== NULL, Don't even execvp()
else // Other Functions
{
execvp(args[0], args); // args[0] is actually the command.
fprintf(stderr,"an error occured in execution\n%s\n",strerror(errno));
//fprintf(stderr,"Invalid Instruction\n");
}
}
else // Parent
{
if(background == 0)
waitpid(child_pid, 0);
wait(1000);
}
}
}
}
return 0;
}
I suspect that I can't use any command that has characters like: > < |
Thanks in advance
1) i can't use some commands in this code as : cat somefile.txt > somefile2.txt also i can't use : cat somefile.txt | less
In the standard shell, the > and | are operators interpreted by the shell, not arguments to the command. Since in this case the shell is your program itself, if you must support those operators then you'll need to implement the appropriate redirections yourself. Refer to open(), pipe(), and dup2(), and for the pipe case you'll also need judicious application of close().
2)when i use commands like : ( cd ../) (cd ./Desktop) and then i want to exit the program, i need to execute exit command more than one time "if i use 3 cd command i will need 3 exit command to end the program"
In the special case of the cd command, you fork and then change directory in the child process, but the child does not terminate or exec another process. That leaves you with two copies of your shell running. You need to exit both before control returns to whatever process launched your program. Possibly in that case you want to instead execute chdir without forking (or waiting for a child).
My C shell can successfully handle redirection (e.g. ls -al > output.txt, ./pre < input1.txt, etc.) and multiple pipes (i.e. cmd1 | cmd 2 | cmd 3). However, my code is not working when I try to do input and output redirection together with a pipe, such as ./pre < input.txt | ./sort > output.txt. No output file is ever made, although the ./pre does successfully execute.
pre is an executable that prints names with GPAs over 3.0
sort is an executable that alphabetizes a list of names
input.txt is a file with names and GPAs (Name 3.1...).
CODE:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/stat.h>
#include <fcntl.h>
#ifndef READ
#define READ 0
#endif
#ifndef WRITE
#define WRITE 1
#endif
void clearArgumentContainer (int argumentContainer[]);
int main() {
/* professor-supplied variables for commands and command parsing */
char *iPath, *oPath, *argv[20], buf[80], n, *p;
int m, status, inword, continu;
int start[20];
/* flags for redirection (note: C does not have type bool; using integer value 0 or 1) */
int inputRedirectFlag, outputRedirectFlag;
/* variables for piping */
int count, pipes;
pid_t pid;
/* pipes */
int l_pipe[2], r_pipe[2];
/* required container for handling arguments */
int argumentContainer[20] = { 0 };
while (1) {
inword = m = continu = count = pipes = pid = 0;
p = buf;
/* redirection flags reset */
inputRedirectFlag = outputRedirectFlag = 0;
/* shell prompt */
printf("\nshhh> ");
/* command parsing */
while ((n = getchar()) != '\n' || continu)
{
if (n == ' ') {
if (inword)
{
inword = 0;
*p++ = 0;
}
}
else if (n == '\n')
continu = 0;
else if (n == '\\' && !inword)
continu = 1;
else {
if (!inword)
{
inword = 1;
argv[m++] = p;
*p++ = n;
}
else
*p++ = n;
}
} /* end of command parsing */
*p++ = 0;
argv[m] = 0;
/* user wishes to terminate program */
if (strcmp(argv[0], "exit") == 0)
exit(0);
/* manage redirection */
while (argv[count] != 0) {
if (strcmp(argv[count], "|") == 0) {
argv[count] = 0;
argumentContainer[pipes + 1] = count + 1;
++pipes;
}
else if (strcmp(argv[count], "<") == 0) {
iPath = strdup(argv[count + 1]); /* copy string argument (file string) */
argv[count] = 0;
argv[count + 1] = 0;
inputRedirectFlag = 1;
}
else if (strcmp(argv[count], ">") == 0) {
oPath = strdup(argv[count + 1]); /* copy string argument (file string) */
argv[count] = 0;
argv[count + 1] = 0;
outputRedirectFlag = 1;
}
else {
argumentContainer[count] = count;
}
++count;
} /* end of redirection management */
/* execute commands [<= in for-loop; n pipes require n+1 processes] */
for (int index = 0; index <= pipes; ++index) {
if (pipes > 0 && index != pipes) { /* if user has entered multiple commands with '|' */
pipe(r_pipe); /* no pipe(l_pipe); r_pipe becomes next child's l_pipe */
}
/* switch-statement for command execution */
switch (pid = fork()) {
/* fork() error */
case -1: perror("fork failed");
break;
case 0: /* child process manages redirection and executes */
if ((index == 0) && (inputRedirectFlag == 1)) {
int inputFileDescriptor = open(iPath, O_RDONLY , 0400);
if (inputFileDescriptor == -1) {
perror("input file failed to open\n");
return(EXIT_FAILURE);
}
close(READ);
dup(inputFileDescriptor);
close(inputFileDescriptor);
} /* end of input redirection management */
if ((index == pipes) && (outputRedirectFlag == 1)) {
int outputFileDescriptor = open(oPath, O_WRONLY | O_CREAT, 0755);
if (outputFileDescriptor < 0) {
perror("output file failed to open\n");
return(EXIT_FAILURE);
}
close(WRITE);
dup(outputFileDescriptor);
close(outputFileDescriptor);
} /* end of output redirection management */
/* manage pipes if (a) first child process, (b) middle child process, or (c) third/final child process */
if (pipes > 0) {
if (index == 0){ /* first child process */
close(WRITE);
dup(r_pipe[WRITE]);
close(r_pipe[WRITE]);
close(r_pipe[READ]);
}
else if (index < pipes) { /* middle child process */
close(READ);
dup(l_pipe[READ]);
close(l_pipe[READ]);
close(l_pipe[WRITE]);
close(WRITE);
dup(r_pipe[WRITE]);
close(r_pipe[READ]);
close(r_pipe[WRITE]);
}
else { /* third/final child process */
close(READ);
dup(l_pipe[READ]);
close(l_pipe[READ]);
close(l_pipe[WRITE]);
}
}
/* execute command */
execvp(argv[argumentContainer[index]], &argv[argumentContainer[index]]);
/* if execvp() fails */
perror("execution of command failed\n");
break;
default: /* parent process manages the pipes for child process(es) */
if (index > 0) {
close(l_pipe[READ]);
close(l_pipe[WRITE]);
}
l_pipe[READ] = r_pipe[READ];
l_pipe[WRITE] = r_pipe[WRITE];
/* parent waits for child process to complete */
wait(&status);
break;
} /* end of switch-statement for command execution */
} /* end of loop for all pipes */
// clear all executed commands
for (int i = 0; i < 20; ++i) {
argv[i] = 0;
}
}
}
void clearArgumentContainer (int argumentContainer[]){
// clear argument container
for (int i = 0; i < 20; ++i) {
argumentContainer[i] = 0;
}
}
Here is the input file I'm using:
Tim 3.5
Todd 2.1
Beth 3.9
Jason 3.5
Zander 3.3
Alex 3.5
Tyler 3.5
Lauren 3.6
Jack 2.3
Amir 3.4
Beth 3.2
pre executable will list only those names with GPAs higher than 3.0
sort executable will sort list of names in alphabetical order
Here is my final working code. It does not implement built-ins like cd, but I plan to implement those built-ins soon! Program does meet the requirements for the assignment.
My major change occurred in the redirection handling. I had to remove a line of code in two places:
argv[count + 1] = 0;
From the redirection for "<" and ">."
I also added code to handle the connections of the pipes, whether my process was the first child, the last, or one in between.
Code:
/***********************************************************************************************
***********************************************************************************************
Student: Douglas Adolph
Course: Operating Systems
Project #: 2
Program emulates shell, and can do the following:
1. Can execute a command with the accompanying arguments.
2. Recognize multiple pipe requests and handle them.
3. Recognize redirection requests and handle them.
4. Type "exit" to quit the shhh shell.
Notes:
Shell built-ins (cd, echo, etc.) not yet implemented
REFERENCED:
1. http://www.thinkplexx.com/learn/article/unix/command
2. http://man7.org/linux/man-pages/man2/open.2.html
3. https://stackoverflow.com/questions/19846272/redirecting-i-o-implementation-of-a-shell-in-c
**********************************************************************************************
*********************************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/stat.h>
#include <fcntl.h>
#ifndef READ
#define READ 0
#endif
#ifndef WRITE
#define WRITE 1
#endif
void clearArgIndexContainer (int argLocation[]);
int main() {
/* variables for command parsing and storage*/
char n, *parser, buf[80], *argv[20];
int m, status, inword, continu;
/* variables and flags for redirection (note: C does not have type bool; using integer value 0 or 1) */
char *in_path, *out_path;
int inputRedirectFlag, outputRedirectFlag;
/* variables for piping */
int count, pipes;
pid_t pid;
/* left and right pipes */
int l_pipe[2], r_pipe[2];
/* container for recording argument locations in argv[] */
int argLocation[20] = { 0 };
while (1) {
/* reset parsing and piping variable values */
m = inword = continu = count = pipes = pid = 0;
/* begin parsing at beginning of buffer */
parser = buf;
/* reset redirection flags */
inputRedirectFlag = outputRedirectFlag = 0;
/* print shell prompt */
printf("\nshhh> ");
/* parse commands */
while ((n = getchar()) != '\n' || continu)
{
if (n == ' ') {
if (inword)
{
inword = 0;
*parser++ = 0;
}
}
else if (n == '\n')
continu = 0;
else if (n == '\\' && !inword)
continu = 1;
else {
if (!inword)
{
inword = 1;
argv[m++] = parser;
*parser++ = n;
}
else
*parser++ = n;
}
} /* end of command parsing */
/* append terminating character to end of parser buffer and argv buffer */
*parser++ = 0;
argv[m] = 0;
/* user wishes to terminate program */
if (strcmp(argv[0], "exit") == 0)
exit(0);
/* manage redirection */
while (argv[count] != 0) {
if (strcmp(argv[count], "|") == 0) {
argv[count] = 0;
argLocation[pipes + 1] = count + 1;
++pipes;
}
else if (strcmp(argv[count], "<") == 0) {
in_path = strdup(argv[count + 1]);
argv[count] = 0;
inputRedirectFlag = 1;
}
else if (strcmp(argv[count], ">") == 0) {
out_path = strdup(argv[count + 1]);
argv[count] = 0;
outputRedirectFlag = 1;
}
else {
argLocation[count] = count;
}
++count;
} /* end of redirection management */
/* execute commands [<= in for-loop; n pipes require n+1 processes] */
for (int index = 0; index <= pipes; ++index) {
if (pipes > 0 && index != pipes) { /* if user has entered multiple commands with '|' */
pipe(r_pipe); /* no pipe(l_pipe); r_pipe becomes next child's l_pipe */
}
/* switch-statement for command execution */
switch (pid = fork()) {
case -1: perror("fork failed"); /* fork() error */
break;
case 0: /* child process manages redirection and executes */
if ((index == 0) && (inputRedirectFlag == 1)) {
int inputFileDescriptor = open(in_path, O_RDONLY , 0400);
if (inputFileDescriptor == -1) {
perror("input file failed to open\n");
return(EXIT_FAILURE);
}
close(READ);
dup(inputFileDescriptor);
close(inputFileDescriptor);
} /* end of input redirection management */
if ((index == pipes) && (outputRedirectFlag == 1)) {
//printf("DEBUG: here we should be about to create our output file\n");
int outputFileDescriptor = creat(out_path, 0700);
if (outputFileDescriptor < 0) {
perror("output file failed to open\n");
return(EXIT_FAILURE);
}
close(WRITE);
dup(outputFileDescriptor);
close(outputFileDescriptor);
} /* end of output redirection management */
/* manage pipes if (a) first child process, (b) in-between child process, or (c) final child process */
if (pipes > 0) {
if (index == 0){ /* first child process */
close(WRITE);
dup(r_pipe[WRITE]);
close(r_pipe[WRITE]);
close(r_pipe[READ]);
}
else if (index < pipes) { /* in-between child process */
close(READ);
dup(l_pipe[READ]);
close(l_pipe[READ]);
close(l_pipe[WRITE]);
close(WRITE);
dup(r_pipe[WRITE]);
close(r_pipe[READ]);
close(r_pipe[WRITE]);
}
else { /* final child process */
close(READ);
dup(l_pipe[READ]);
close(l_pipe[READ]);
close(l_pipe[WRITE]);
}
}
/* execute command */
execvp(argv[argLocation[index]], &argv[argLocation[index]]);
/* if execvp() fails */
perror("execution of command failed\n");
break;
default: /* parent process manages the pipes for child process(es) */
if (index > 0) {
close(l_pipe[READ]);
close(l_pipe[WRITE]);
}
l_pipe[READ] = r_pipe[READ];
l_pipe[WRITE] = r_pipe[WRITE];
/* parent waits for child process to complete */
wait(&status);
break;
} /* end of switch-statement for command execution */
} /* end of loop for all pipes */
// clear all executed commands
for (int i = 0; i < 20; ++i) {
argv[i] = 0;
}
}
}
void clearArgIndexContainer (int argLocation[]){
// clear argument container
for (int i = 0; i < 20; ++i) {
argLocation[i] = 0;
}
}
This is where I removed the lines making argv[count + 1] = 0; :
/* manage redirection */
while (argv[count] != 0) {
if (strcmp(argv[count], "|") == 0) {
argv[count] = 0;
argLocation[pipes + 1] = count + 1;
++pipes;
}
else if (strcmp(argv[count], "<") == 0) {
in_path = strdup(argv[count + 1]);
argv[count] = 0;
inputRedirectFlag = 1;
}
else if (strcmp(argv[count], ">") == 0) {
out_path = strdup(argv[count + 1]);
argv[count] = 0;
outputRedirectFlag = 1;
}
else {
argLocation[count] = count;
}
This was my major addition to handle to pipes:
/* manage pipes if (a) first child process, (b) in-between child process, or (c) final child process */
if (pipes > 0) {
if (index == 0){ /* first child process */
close(WRITE);
dup(r_pipe[WRITE]);
close(r_pipe[WRITE]);
close(r_pipe[READ]);
}
else if (index < pipes) { /* in-between child process */
close(READ);
dup(l_pipe[READ]);
close(l_pipe[READ]);
close(l_pipe[WRITE]);
close(WRITE);
dup(r_pipe[WRITE]);
close(r_pipe[READ]);
close(r_pipe[WRITE]);
}
else { /* final child process */
close(READ);
dup(l_pipe[READ]);
close(l_pipe[READ]);
close(l_pipe[WRITE]);
}
}
I still have more work to do, namely implementing the built-ins, but also putting more of this into separate functions to clean up the code and make it more readable. I was also given some good advice on some expressions that might be better written, and I'll soon tackle that.
I want to implement my own shell. I'm stucked on implementing background process . Actually ,I write some piece of code but I'm not sure if it is work or not .
my code :
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#define MAX_LINE 80 /* 80 chars per line, per command, should be enough. */
#define HISTORY_SIZE 5 /*keep track of 5 most recent commands*/
int cmd_count; /*global to keep track of most recent commands entered*/
char history[HISTORY_SIZE][MAX_LINE]; /* global so it can be accessed in interrupt handler. */
void viewHistory()
{
int i;
if (cmd_count < 1)
printf("No command history to show. \n");
else {
printf("\n\n");
for (i = (cmd_count >= HISTORY_SIZE) ? cmd_count - HISTORY_SIZE:0;
i < cmd_count; i++)
printf("%d: %s\n",i+1,history[i%HISTORY_SIZE]);
}
//printf("SystemsIIShell->");
}
int setup(char inputBuffer[], char *args[],int *background)
{
int length, /* # of characters in the command line */
i, /* loop index for accessing inputBuffer array */
start, /* index where beginning of next command parameter is */
ct; /* index of where to place the next parameter into args[] */
int temp;
ct = 0;
/* read what the user enters on the command line */
length = read(STDIN_FILENO, inputBuffer, MAX_LINE);
start = -1;
if (length == 0)
exit(0); /* ^d was entered, end of user command stream */
if (length < 0){
perror("error reading the command");
exit(-1); /* terminate with error code of -1 */
}else{
inputBuffer[length]='\0';
if(inputBuffer[0]=='r'){
if(inputBuffer[1]=='r'){
if(cmd_count==0){
printf("No recent command can be found in the history. \n");
return 0;
}
strcpy(inputBuffer,history[(cmd_count)% HISTORY_SIZE]);
}else{
temp = atoi(&inputBuffer[1]);
if(temp < 1 || temp > cmd_count || temp <= cmd_count -HISTORY_SIZE){
printf("Command number cannot be found. \n");
return 0;
}
strcpy(inputBuffer,history[(temp-1)%HISTORY_SIZE]);
}
length = strlen(inputBuffer);
}
cmd_count++;
strcpy(history[(cmd_count-1)%HISTORY_SIZE], inputBuffer);
for (i = 0; i < length; i++) {
if (inputBuffer[i] == '&') {
inputBuffer[i] = '\0';
*background = 1;
--length;
break;
}
}
}
/* examine every character in the inputBuffer */
for (i = 0; i < length; i++) {
switch (inputBuffer[i]){
case ' ':
case '\t' : /* argument separators */
if(start != -1){
args[ct] = &inputBuffer[start]; /* set up pointer */
ct++;
}
inputBuffer[i] = '\0'; /* add a null char; make a C string */
start = -1;
break;
case '\n': /* should be the final char examined */
if (start != -1){
args[ct] = &inputBuffer[start];
ct++;
}
inputBuffer[i] = '\0';
args[ct] = NULL; /* no more arguments to this command */
break;
case '&':
*background = 1;
inputBuffer[i] = '\0';
break;
default : /* some other character */
if (start == -1)
start = i;
}
}
args[ct] = NULL; /* just in case the input line was > 80 */
}
int main(void)
{
char inputBuffer[MAX_LINE]; /* buffer to hold the command entered */
int background; /* equals 1 if a command is followed by '&' */
char *args[MAX_LINE/2+1];/* command line (of 80) has max of 40 arguments */
while (1){ /* Program terminates normally inside setup */
background = 0;
printf("SystemsIIShell->");
fflush(0);
setup(inputBuffer, args, &background); /* get next command */
pid_t child; /* process id for child */
int status; /* status for execvp */
child = fork(); /* create a child process*/
if(child < 0){ /* if the child process didn't return 0, the fork is failed */
printf("Fork failed! \n");
}else if(child==0){ /* child process */
if(inputBuffer[0]=='history' || inputBuffer[0] =='h'){
viewHistory();
return 0;
}
status = execvp(args[0],args);
if(status !=0){
printf("%s: command not found. \n", args[0]);
}
}else{ /* parent process */
if(background == 0)
waitpid(child,&background,0);
}
/* the steps are:
(1) fork a child process using fork()
(2) the child process will invoke execvp()
(3) if background == 0, the parent will wait,
otherwise returns to the setup() function. */
}return 0;
}
I don't add whole code but the other things are true. I call execv and it works. When I write on the console :
output terminal :
$ gedit ------->it works correctly because it is a foreground
$ gedit & -----> it opens a gedit file which name is "&"
$ firefox ---> it works correctly
$ firefox & ---> it opens a firefox window which url is www.&.com
How can fix it ?any suggestions ?
editing part : https://github.com/iqbalhasnan/CSE2431-System-II/blob/master/lab2/lab2.c --> I use this code as a reference
you're not implementing background processes, you're trying to start a background process using the syntax of the already-implemented-shell on your computer (but honestly, it's pretty hard to tell what's going on with that indentation. That's really bad. Can you make it readable, please?). That '&' character is recognised by your shell, not by execvp. Have a look at this similar looking question which was the first hit in a google search for your problem.
I am doing a university project, we have to use the Unix system call.
Right now, I'm really struggling to understand if, in my project, there really is a mistake. This is because, while in terminal it compiles and it starts and finishes without error, on xcode I get several errors.
In particular, I get errors when using semaphores.
I'll try to explain what errors, I receive, but since I'm not native English speakers forgive me in advance if I make some mistakes.
First, the program creates a number of child processes with a fork (). It does depending on how many clientei.txt located (i = iterator).
Immediately I block parent with a semaphore, I run the child up to a certain point, then I block it with a semaphore and I restart the parent.
At this point, the parent should read a message sent by his son, call a function to print the content inside a log.txt and restart the son.
Then the child does other things (including erase the message) and it block.
The parent restart, and everything is repeated for subsequent children.
While in terminal synchronization is perfect (everything happens at the right time without error) this both Linux and Mac, about XCode I had several errors:
semop: Resource temporarily unavailable (if I created more than 5 txt)
semop: File too large (if I created more than 2)
with 2 instead gave me two errors:
semop 1: Interrupted system call (this stops after running both processes)
semop 3: Identifier removed (with this in restarting the second process)
is not so much time that I do C then I do not know what to do. I would like first of all to know if I have to worry (so there is an error), or I have to be quiet because it is a bug in xcode.
If there was a mistake I kindly ask you not to ask me to change the code a lot.
This is mainly because they are close to expiring and I can not afford to do it all again.
I also ask you, if you can, to be as clear as possible. I understand enough English, but not as a mother-tongue, I can not always follow the responses here on StackOverflow.
The code is here:
https://www.dropbox.com/s/2utsb6r5d7kzzqj/xcode%2Bterminal.zip?dl=0
this zip contain a small part of the project that has this problem.
the terminal version works. there is a makefile in this version to simplify the compilation.
xcode version does not work. It contains the Debug folder. Indeed xcode, txt files, it does not read from the root folder where the codes are contained in the folder where it creates the compiled. There is a readme in each case with the procedure in detail.
I tried to minimize, I commented all in English.
I removed the code that was not needed, but I added the file with all the include and functions that use.
here the code:
main.c
key_t key, key_2;
int semid, semid_2;
union semun arg;
union semun arg_2;
struct sembuf sb_2 = {0, -1, 0};
char* nome_file;
nome_file = (char*) malloc(sizeof(char*));
int numero_clienti;
//semaphore for all the child
struct sembuf sb[numero_clienti];
int i_c;
for (i_c = 0; i_c < numero_clienti; i_c++) {
sb[i_c].sem_num = i_c;
sb[i_c].sem_op = -1;
sb[i_c].sem_flg = 0;
}
//cretion of first SEMAPHORE
{
//key creation
if ((key = ftok("cliente0.txt", 'J')) == -1)
{
perror("ftok");
exit(EXIT_FAILURE);
}
//creation of the semaphore
if ((semid = semget(key, numero_clienti, 0666 | IPC_CREAT | IPC_EXCL)) == -1)
{
perror("semget");
exit(EXIT_FAILURE);
}
//set value of all child semaphore
for (i_c = 0; i_c < numero_clienti; i_c++) {
arg.val = 0;
if (semctl(semid, i_c, SETVAL, arg) == -1)
{
perror("semctl");
exit(EXIT_FAILURE);
}
}
}
//cretion of second SEMAPHORE
{
//key creation
if ((key_2 = ftok("cliente1.txt", 'J')) == -1)
{
perror("ftok");
exit(EXIT_FAILURE);
}
//creation of the semaphore
if ((semid_2 = semget(key_2, 1, 0666 | IPC_CREAT | IPC_EXCL)) == -1)
{
perror("semget");
exit(EXIT_FAILURE);
}
//set value of parent semaphore
arg_2.val = 0;
if (semctl(semid_2, 0, SETVAL, arg_2) == -1)
{
perror("semctl");
exit(EXIT_FAILURE);
}
}
while(fd > 0 && pid > 0){
j++;
close(fd);
pid = fork();
if(pid != 0)
{
i++;
sprintf(nome_file, "./cliente%d.txt", i);
fd = open(nome_file, O_RDONLY);
}
switch(pid)
{
//error case
case -1:
{
perror("Error during fork.");
exit(EXIT_FAILURE);
break;
}
//child case
case 0:
{
puts("Child: I'm a child");
messaggio(numero_clienti, j);
puts("Child: I have to do something");
//Start parent
sb_2.sem_op = 1;
if (semop(semid_2, &sb_2, 1) == -1)
{
perror("semop");
exit(1);
}
//, stop itself
sb[j].sem_op = -1;
if (semop(semid, &sb[j], 1) == -1)
{
perror("semop");
exit(1);
}
printf("Child: I have to do something else %d\n", getpid());
_exit(EXIT_SUCCESS);
break;
}
//parent case
default:
{
puts("Parent: I'm a parent");
//Stop itself
sb_2.sem_op = -1;
if (semop(semid_2, &sb_2, 1) == -1)
{
perror("semop padre");
exit(1);
}
puts("Parent: now I can send the message, my child is blocked");
//restart child
sb[j].sem_op = 1;
if (semop(semid, &sb[j], 1) == -1)
{
perror("semop");
exit(1);
}
//stop itself
sb_2.sem_op = -1;
if (semop(semid_2, &sb_2, 1) == -1)
{
perror("semop");
exit(1);
}
puts("Parent: end of while");
break;
}
}
}
puts("Parent: I can restart all my child");
for (i_c = 0; i_c < numero_clienti; i_c++) {
sb[i_c].sem_op = 1;
if (semop(semid, &sb[i_c], 1) == -1)
{
perror("semop");
exit(1);
}
}
puts("I wait the end of my child...");
while (wait(NULL) != -1);
puts("All child end");
//remove semaphore I create
if (semctl(semid, 0, IPC_RMID, arg) == -1)
{
perror("semctl");
exit(1);
}
if (semctl(semid_2, 0, IPC_RMID, arg_2) == -1)
{
perror("semctl");
exit(1);
}
puts("FINE");
return 0;
}
cliente.c
#include "cliente.h"
/**
inside this function child do some thing.
1. at this point it give control to parent after it create a message
2. at this point it remove the message
*/
void messaggio(int numero_clienti, int num_j){
key_t key, key_2;
int semid, semid_2;
struct sembuf sb[numero_clienti];
int i_c;
for (i_c = 0; i_c < numero_clienti; i_c++) {
sb[i_c].sem_num = i_c;
sb[i_c].sem_op = -1;
sb[i_c].sem_flg = 0;
}
struct sembuf sb_2 = {0, -1, 0};
if ((key = ftok("cliente0.txt", 'J')) == -1) {
perror("ftok");
exit(1);
}
if ((semid = semget(key, 1, 0)) == -1) {
perror("semget");
exit(1);
}
if ((key_2 = ftok("cliente1.txt", 'J')) == -1) {
perror("ftok");
exit(1);
}
if ((semid_2 = semget(key_2, 1, 0)) == -1) {
perror("semget");
exit(1);
}
//creation of a message
//1. Restart parent
sb_2.sem_op = 1;
if (semop(semid_2, &sb_2, 1) == -1)
{
perror("semop");
exit(1);
}
puts("cambio sem");
//stop itself
sb[num_j].sem_op = -1;
if (semop(semid, &sb[num_j], 1) == -1)
{
perror("semop");
exit(1);
}
//here it can move again
puts("remove message");
puts("Figlio: sono tornato attivo, mio padre aspetta");
}
1st you do
nome_file = (char*) malloc(sizeof(char*));
which allocates 4 or 8 bytes (depending on the platform you compile on: 32 or 64bit).
Then you do
sprintf(nome_file, "./cliente%d.txt", i);
The latter writes to invalid memory, as "./cliente%d.txt" is 14+1 characters long plus the potenial number of digits from i if i>9 or and addtional sign if i<0.
To fix this allocate what is needed:
nome_file = malloc(13 + 10 + 1 + 1); /* 13 for the filename,
10 for the digits,
1 for a potential sign,
1 the C-"strings" 0-terminator. */
This is a really ugly bug, which is expected to be the main issue in your code.
Also in the sources (you linked) in function read_line() you allocate memory, which you do not properly initialise, but later depend on its content.
main.c:20
char* myb2 = (char*) malloc(sizeof(char*));
malloc() does not initialise the memory it allocates, so either do:
char * myb2 = calloc(1, sizeof(char*));
of add and addtional call to
memset(mb2, 0, sizeof(char*));
after the call to malloc().
This bug is nasty either.
Also^2 you should build using gcc's options -std=c99 -D_XOPEN_SOURCE.
That is because:
You are using C constructs available from C99 on only. Typically VLAs, so tell the compiler to treat the code as being C99 code by explcitly stating -std=c99
To #define _XOPEN_SOURCE is issued by gcc, for some header you include in your project.
Also^3 you seem to be not necessarily count the correct number of client(file)s, at least not if your files a distributed as per the archive you linked:
main.c:82
system("ls cliente* | wc -l");
Change this to be:
system("ls cliente*.txt | wc -l");
If the bug described above should return more files then there actually are the following code fails as well from a certain value of i on:
main.c:176
fd = open(nome_file, O_RDONLY);
The result of the above operation is NOT tested. The possible invalid fd is used and the infamous undefined behaviour is taking over. Everything can happen.
As a final note: It's mostly never a bug in the tools we are using.
I am working on a shell(yes, it's an assignment, so I am not looking for a solution, more of a guide and clues to what I am doing wrong), and I'm stuck with pipes. I have read numerous tutorials, mans and what not, even copy-pasted some codes that "work", nothing seems to do the trick.
This is what I have so far:
void ft_run_pipe(char **cmd, int num)
{
int i;
int j;
int piped[num][2];
pid_t pid;
i = 0;
j = 0;
while (i < num)
{
ft_putstr("Creating pipe");
ft_putnbr(i);
ft_putchar('\n');
if (pipe(piped[i]) < 0)
ft_putstrn("piped failed");
i++;
}
while (cmd[j] != '\0')
{
pid = fork();
if (pid == 0)
{
ft_putchar('a');
if (j != 0)
{
ft_putstrn("If not first");
ft_putnbr(j - 1);
if (dup2(piped[j - 1][0], 0) < 0)
{
ft_putstrn("dup1 failed");
ft_putstrn(strerror(errno));
}
close(piped[j - 1][1]);
close(piped[j - 1][0]);
}
if (j != num)
{
ft_putstrn("If not last");
ft_putnbr(j);
if (dup2(piped[j][1], 1) < 0)
{
ft_putstrn("dup2i failed");
ft_putstrn(strerror(errno));
}
close (piped[j][0]);
close (piped[j][0]);
}
i = 0;
while (i < num)
{
close(piped[i][0]);
close(piped[i][1]);
i++;
}
// ft_run_special(cmd[j], environ);
}
else
{
i = 0;
while (i < num)
{
close(piped[i][0]);
close(piped[i][1]);
i++;
}
}
j++;
}
wait (NULL);
}
The various ft_something functions are coded by me alternatives to some libc functions(ft_putstr writes a string, with n in the end it adds a \n, etc.). ft_exec_special is a function that executes an executable with execve, searching in the PATH variable.
When ran with two commands and a single pipe, it returns
Creating pipe0
aIf not last
0aIf not first
0dup1 failed
Bad file descriptor
While, normally, it seems to me, it should work - piped[0][0] exists, is properly piped, and something was written to piped[0][1] - why would it say piped[0][0] is a bad file descriptor?