I am trying to create a interactive shell - c

I am trying to create a interactive shell program that prompts the user for a command, parses the command, and then executes it with a child process. Here is the code that I have but im not sure where to go after this PLEAE HELP !!!!
Int shell(char *cmd_str ){
int commandLength=0;
cmd_t command;
commandLength=make_cmd(cmd_str, command);
cout<< commandLength<<endl;
cout << command.argv[0]<< endl;
if( execvp( command.argv[0], command.argv)==-1)
//if the command it executed nothing runs after this line
{
commandLength=-1;
}else
{
cout<<"work"<<endl;
}
cout<< commandLength<<endl;
return commandLength;
}

Assuming shell() is being run within a child process called with fork(), you'll need to ensure that the parent process properly waits for the child process to terminate. See the wait(2) family of functions.
Additionally, you'll want to retrieve the exit status of said child process (again, see wait(2)).
You can also try to implement stream redirection. Assuming this is an exercise, I'll leave the additional research on how to implement these things up to the user :) -- look into dup(2).

Related

Why is sleep in a child process blocking my program?

So I have this simple program that sleeps for 4 second if the value returned by fork is '0' meaning that the child process is executing, I've tried using sleep in child process but the program is blocked, and flushing standard output isn't working...
code:
#include <stdio.h>
#include <unistd.h>
int main(int argc, char const *argv[]) {
pid_t value = fork();
if (value == 0) {
sleep(4);
}
printf("Value returned by fork: %d\n", value);
printf("I'm the process N°%d\n", getpid());
return 0;
}
I'm running on Ubuntu 20.04.3 LTS.
Output:
Value returned by fork: 12618
I'm the process N°12617\
farouk#farouk-HP-Pavilion-Desktop-TP01-1xxx:~/sysexp$ Value returned by fork: 0
I'm the process N°12618
To allow this question to have an accepted answer.
The child process is not blocking the shell. The shell gave its prompt and the child wrote some output after the prompt, leaving the cursor at the start of a line without a shell prompt visible — because the shell prompt already appeared earlier.
There are a variety of ways around this.
The simplest is just to type a command such as ps and hit return, noting that the shell executes it, and that the ps output does not list the child process. If you type the ps command quick enough, you might see the child listed in the output before its output appears.
Another is to modify the program so that it waits for all child processes to exit before it exits — using wait() or waitpid(). The same code can be used in the child and the parent since the child will have no children of its own. The call to the wait function will return immediately with a 'no more children' status (error).
You can find extensive discussion of all this in the comments — I've chosen to make this a Community Wiki answer since there was a lot of activity in the comments that identified the gist of this answer.

Pipe chaining in my own shell implementation

I am currently writing my own shell implementation in C. I understood the principle behind piping and redirecting the fds. However, some specific behavior with pipes has attracted my attention:
cat | ls (or any command that does not read from stdin as final element of the pipe).
In that case, what happens in the shell is that ls executes and cat asks for a single line before exiting (resulting from a SIGPIPE I guess). I have tried to follow this tutorial to better understand the principle behind multiple pipes: http://web.cse.ohio-state.edu/~mamrak.1/CIS762/pipes_lab_notes.html
Below is some code I have written to try to replicate the behavior I am looking for:
char *cmd1[] = {"/bin/cat", NULL};
char *cmd2[] = {"/bin/ls", NULL};
int pdes[2];
pid_t child;
if (!(child = fork()))
{
pipe(pdes);
if (!fork())
{
close(pdes[0]);
dup2(pdes[1], STDOUT_FILENO);
/* cat command gets executed here */
execvp(cmd1[0], cmd1);
}
else
{
close(pdes[1]);
dup2(pdes[0], STDIN_FILENO);
/* ls command gets executed here */
execvp(cmd2[0], cmd2);
}
}
wait(NULL);
I am aware of the security flaws of that implementation but this is just for testing. The problem with that code as I understand it is that whenever ls gets executed, it just exits and then cat runs in the background somehow (and in my case fail because it tries to read during the prompt of zsh as my program exits). I cannot find a solution to make it work like it should be. Because if I wait for the commands one by one, such commands as cat /dev/random | head -c 10 would run forever...
If anyone has a solution for this issue or at least some guidance it would be greatly appreciated.
After consideration of comments from #thatotherguy here is the solution I found as implemented in my code. Please bear in mind that pipe and fork calls should be checked for errors but this version is meant to be as simple as possible. Extra exit calls are also necessary for some of my built-in commands.
void exec_pipe(t_ast *tree, t_sh *sh)
{
int pdes[2];
int status;
pid_t child_right;
pid_t child_left;
pipe(pdes);
if (!(child_left = fork()))
{
close(pdes[READ_END]);
dup2(pdes[WRITE_END], STDOUT_FILENO);
/* Execute command to the left of the tree */
exit(execute_cmd(tree->left, sh));
}
if (!(child_right = fork()))
{
close(pdes[WRITE_END]);
dup2(pdes[READ_END], STDIN_FILENO);
/* Recursive call or execution of last command */
if (tree->right->type == PIPE_NODE)
exec_pipe(tree->right, sh);
else
exit(execute_cmd(tree->right, sh));
}
/* Should not forget to close both ends of the pipe */
close(pdes[WRITE_END]);
close(pdes[READ_END]);
wait(NULL);
waitpid(child_right, &status, 0);
exit(get_status(status));
}
I was confused with the original link I posted and the different ways to handle chained pipes. From the link to the POSIX documented posted below my original question (http://pubs.opengroup.org/onlinepubs/009695399/utilities/xcu_chap02.html#tag_02_09_02) it appears that:
If the pipeline is not in the background (see Asynchronous Lists), the shell shall wait for the last command specified in the pipeline to complete, and may also wait for all commands to complete.
Both behavior are therefore accepted: waiting for last command, or waiting for all of them. I chose to implement the second behavior to stick to what bash/zsh would do.

C program is interrupted during the execution of “system” function

I have a problem with my C code, basically I need to send email via mutt program. It must be send when an interrupt comes up from GPIO pin. My sendMail function is listed below. I realized this by using system function. Main contains loop with logAlarm func which contains sendMail. The thing is when system(cmd) function finishes, the whole C program stops. For instance when i put sendMail function at the begining of the main it works and is sending email to my mailbox without stopping whole program, in the loop it manages to send it but it terminates program. I tried to using & sign to run it in background but it didnt help.
P.S i dont know if it matters but im also using system call from setitimer with 2 sec intervals to check few things but i guess it has no impact for this case.
Any ideas?
Thanks in advance :)
sendMail function:
void sendMail(char * msg, char * recipientMail){
char cmd[100];
char subject[30];
char body[60];
sprintf(body, "Intruder detected!!!\n%s", msg);
strcpy(subject, "\"ALARM - SECURITY BREACH\"");
sprintf(cmd,"echo \"%s\" | mutt -s %s %s &", body, subject, recipientMail);
printf("%s\n\n", cmd);
system(cmd);
}
Here is a piece of my main function:
while(1){
sleep(1);
if(prev_state == triggered && !emailDetach){
if(!logAlarm()){
printf("Error writing to log file!!!\n");
}
emailDetach = true;
}
//printf("Czas od poprzedniego alarmu: %d", millis() - alarmTriggeredTime);
if((prev_state == triggered) && (millis() - alarmTriggeredTime >= ALARM_TIME)){
digitalWrite(ALARM_ON_DIODE, LOW);
digitalWrite(ALARM_OFF_DIODE, HIGH);
//warunek czasowy osobno na syrene TODO
if(!silentMode && (millis() - alarmTriggeredTime >= siren_alarm_time)){
digitalWrite(SIREN, LOW);
}
prev_state = nottriggered;
}
}
Good question. As per description, I consider that sendMail function works properly. I've not worked with mutt. But i've worked with system().
What system does is, it forks a child process of your current process and executes the command using execve(). So the problem should be in the returning of the system.
So, first you should check the return status of system function. If you are able to make printf() below the system(), then you're not having problem with system(). If you are not able get printf below the system(), then system() is killing your process. (by sending sigkill or similer signals, but not sigint or sigquit, since it is ignored by system()). You are creating a child process in the cmd itself (echo output piping to mutt). May be this should be root cause.
If you find problem here, then the problem is critical, and you will find directions from the "NOTES" section of "man system", since you have implemented the same logic mentioned there. First just try to wait for conditions mentioned there. If you're still unable to do this, try to fork two new child process, run execl or any other exec family function ("man 3 exec") from that child process to run echo and mutt.
If system() is ok, then check logAlarm(). is it giving the right arguments to the sendMail? if you are getting "Error writing to log file!!!", then entire sequence is ok.

C Program for shell: Execvp prints output and then segmentation fault occurs when executing a background process

I am writing a simple C program to create my own shell. It takes in input as commands and executes them. But when I try to execute a process in background( i.e. I fork a process from parent. The parent won't wait for the child process to finish, it just goes on to take more input commands while the child process runs in the background.) The execvp does execute the command but then gives a segmentation fault immediately.
Can you help me? I'll post my part of the code which I think is relevant. Let me know if you need to know anything more, i'll edit my question accordingly.
while(1){
pid = fork();
if(pid == 0)
executeCommand(info);
else
{
if(info->boolBackground ==1)
{
waitpid(pid , status , WNOHANG);
}
else
wait(NULL);
}
} //Info contains the command to be executed and it's arguments.
Here is me executeCommand function:
void executeCommand(parseInfo * info)
{
FILE *infile, *outfile;
struct commandType * com;
char * cmd;
int i , status;
cmd = (char*)malloc(1024);
strcpy(cmd , info->CommArray[0].command);
if(info->boolOutfile == 1)
{
outfile = fopen(info->outFile, "w");
dup2(fileno(outfile), 1);
}
if(info->boolInfile == 1)
{
infile = fopen(info->inFile, "r");
dup2(fileno(infile), 0);
}
status = execvp(cmd , info->CommArray[0].VarList); //VarList contains the arguments
if(status == -1){
printf("%s\n",strerror(errno));}
exit(0);
}
When I give an input command: ls &
(& means that ls should be executed in background.)
It forks a child process which executes ls and prints the list of files/directories in the directory and then gives segmentation fault. Can you spot the error? I tried running execvp in background with simply ls command. It also lead to a segmentation fault.
Yes, as Mark Plotnick pointed out in a comment, you'll need probably need &status. I'd use &info->status. Also, if you do detached jobs, you need to maintain a list of their info objects and do a waitpid loop on them:
forall (info in detached_detach_job_list) {
pid = waitpid(info->pid,&info->status,WNOHANG);
if (pid > 0) {
report_status(info);
remove_job_from_list(info);
}
}
Hopefully, the code frag you gave for your outer loop does something like this.
Also, I might not do "wait(NULL)" for a foreground. I'd treat it similarly to a detached job. Consider a case where a user does:det1 &
det2 &
...
det9000 &
run_long_30_minute_job
Because your shell is doing a hard wait on the foreground, it can't reap the detached jobs as they finish and you'll end up with zombie processes. Do the list/loop approach, just don't give user a prompt until the foreground completes (e.g. it's in the list, it's just the one with the background flag cleared). In other words, call the list something like child_list to denote all child processes, not just background. Put a sleep in the outer loop. Or, attach to SIGCHLD and do a single long sleep

Can the order of execution of fork() be determined?

I'm working on an exercise on the textbook "Operating System Concepts 7th Edition", and I'm a bit confused about how does fork() work. From my understanding, fork() creates a child process which runs concurrently with its parent. But then, how do we know exactly which process runs first? I meant the order of execution.
Problem
Write a C program using fork() system call that generates the Fibonacci sequence in the child process. The number of sequence will be provided in the command line.
This is my solution:
#include <sys/types.h>
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
void display_fibonacci_sequence( int n ) {
int i = 0;
int a = 1;
int b = 1;
int value;
printf( "%d, %d, ", a, b );
for( ;i < n - 2; ++i ) {
value = a + b;
printf( "%d, ", value );
a = b;
b = value;
}
printf( "\n" );
}
int main( int argc, char** argv ) {
int n;
pid_t pid;
pid = fork();
if( argc != 2 ) {
fprintf( stderr, "Invalid arguments" );
exit( -1 );
}
n = atoi( argv[1] );
if( pid < 0 ) {
fprintf( stderr, "Fork failed" );
exit( -1 );
}
else if( pid == 0 ) {
display_fibonacci_sequence( n );
}
else { // parent process
// what do we need to do here?
}
}
To be honest, I don't see any difference between using fork and not using fork. Besides, if I want the parent process to handle the input from user, and let the child process handle the display, how could I do that?
You are asking many questions, I'll try to answer them in a convenient order.
First question
To be honest, I don't see any difference between using fork and not
using fork.
That's because the example is not a very good one. In your example the parent doesn't do anything so the fork is useless.
Second
else {
// what do we need to do here?
}
You need to wait(2) for the child to terminate. Make sure you read that page carefully.
Third
I want the parent process to handle the input from user, and let the
child process handle the display
Read the input before the fork and "handle" the display inside if (pid == 0)
Fourth
But then, how do we know exactly which process runs first?
Very few programs should concern themselves with this. You can't know the order of execution, it's entirely dependent on the environment. TLPI says this:
After a fork(), it is indeterminate which process—the parent or the
child—next has access to the CPU. On a multiprocessor system, they may both simultaneously get access to a CPU.
Applications that implicitly or explicitly rely on a particular
sequence of execution in order to achieve correct results are open to
failure due to race conditions
That said, an operating system can allow you to control this order. For instance, Linux has /proc/sys/kernel/sched_child_runs_first.
We don't know which runs first, the parent or the child. This is why the parent generally has to wait for the child process to complete if there is some dependency on order of execution between them.
In your specific problem, there isn't any particular reason to use fork(). Your professor probably gave you this just for a trivial example.
If you want the parent to handle input and the child to calculate, all you have to do is move the call to fork() below the point at which you handle the command-line args. Using the same basic logic as above, have the child call display_fibonacci_sequence, and have the parent simply wait
The process which is selected by your system scheduler is chosen to run, not unlike any other application running on your operating system. The process spawned is treated like any other process where the scheduler assigns a priority or spot in queue or whatever the implementation is.
But then, how do we know exactly which process runs first? I meant the
order of execution.
There is no guarantee to which one ran first. fork returns 0 if it is the child and the pid of the child if it is the parent. Theoretically they could run at exactly the same time on a multiprocessor system. If you actually wanted to determine which ran first you could have a shared lock between the two processes. The one that acquires the lock first could be said to have run first.
In terms of what to do in your else statement. You'll want to wait for the child process to exit using wait or waitpid.
To be honest, I don't see any difference between using fork and not using fork.
The difference is that you create a child process. Another process on the system doing computation. For this simple problem the end user experience is the same. But fork is very different when you are writing systems like servers that need to deal with things concurrently.
Besides, if I want the parent process to handle the input from user, and let the child process handle the display, how could I do that?
You appear to have that setup already. The parent process just needs to wait for the child process to finish. The child process will printf the results to the terminal. And the parent process currently gets user input from the command line.
While you cannot control which process (parent or child) gets scheduled first after the fork (in fact on SMP/multicore it might be both!) there are many ways to synchronize the two processes, having one wait until the other reaches a certain point before it performs any nontrivial operations. One classic, extremely portable method is the following:
Prior to fork, call pipe to create a pipe.
Immediately after fork, the process that wants to wait should close the writing end of the pipe and call read on the reading end of the pipe.
The other process should immediately close the reading end of the pipe, and wait to close the writing end of the pipe until it's ready to let the other process run. (read will then return 0 in the other process)

Resources