simple shell for multiple commands in a line - c

my program should print out a prompt: myshell> when it is ready to accept input. It must read a line of input, accepting several possible commands. This is a very simple shell, so it only accepts two command: run and exit.
#include<stdio.h>
#include<string.h>
#include <sys/types.h>
#include <errno.h>
#include <stdio.h>
#include <sys/wait.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
int h=0;
void keep(int sig){
h=1;
}
int main()
{
signal(SIGINT,keep);//gets into the interrupt
while(1)
{
printf("myshell>");
char line[255];
fgets(line, 255, stdin);
if(!strcmp(line,"\n")){//checks if the given line is not empty
continue;
}
if(h)
{
h=0;
continue;
}
int g = 0;
char *words[5];
words[g] = strtok(line," \n");//Tokenize the given line
while (words[g]!=NULL)//splitting the tokens
{
g++;
words[g] = strtok(NULL," \n");
}
if(strcmp(words[0],"run")==0)
{
int status;
printf("myshell:Started child pid %d \n",getpid());
pid_t result = fork();
printf("myshell:Started child pid %d \n",getpid());
if(result>0)
{
wait(&status);//gets into the wait state
}
else if (result == 0)//new child process created
{
char *args[3];
int k=0;
while(k<4)//take the whole string into array and execute
{
args[k] = words[k+1];
k++;
}
int output;
output = execvp(*args,args);
if(output==-1)
{
printf("myshell: could not find the program %s\n",words[1]);
}
}
}
else if(strcmp(words[0],"exit")==0)//comparing with the exit
{
exit(1);
}
else
{
printf("myshell: %s is not a valid command\n",words[0]);
}
}
return 0;
}
it works good with
./myshell
myshell> run ls
myshell: started child pid 7973
myshell myshell.c
MY shell should support using ; to execute multiple programs with a single command. To make it simple, let's assume there is a space before and after the ;. For example:
./myshell
myshell> run ls -l ; date ; who
But this is not working with this code.

Related

Creating a simple shell

I'm trying to program a simple shell in C that can execute an executable by just entering the filename. I've tried writing my code which you will see below, but i keep getting the "NO such file or directory error. I'm new to C and I would really love someone to help.
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>
/**
* main - a super simple shell
*
* Return: always 0
*/
int main(void)
{
char *command[] = {"", NULL};
size_t len = 0;
int flag = 1;
pid_t child_process;
int status;
while (flag == 1)
{
printf("#fountain-shell$ ");
getline(&command[0], &len, stdin);
child_process = fork();
if (child_process == -1)
{
perror("Error:");
return (1);
}
if (child_process == 0)
{
if (execve(command[0], command, NULL) == -1)
{
perror("Error:");
}
}
else
{
wait(&status);
continue;
}
}
}
This is an example of what I'm trying to achieve.
#cisfun$ /bin/ls
env-environ.c exec fork mypid ppid printenv promptc shell wait
env-main.c exec.c fork.c pid.c ppid.c prompt prompt.c shell.c wait.c
#cisfun$ ./ppid
5451
#cisfun$ ./ppid
5451
#cisfun$ ^C

Why this code with fork() generates Runtime Error in ejudge?

Why this code may generate Runtime Error in ejudge? This program counts the number of words from stdin input. Words can be separated by any amount of ' ' and '\n'.
It seems like fork() can cause a problem but I am not sure why I don't get the same error on my computer.
ejudge uses gcc - Plain C, 64 bit, using -std=c11 or -std=gnu11
The task:
On the standard input stream a text string is given which consists of
words (a sequence of non-space characters), between which there can be
any number of whitespace characters, including line feeds.
You need to calculate the number of words if you know there are not
more than 255, and output this value to the standard output stream.
Use creating new processes so that each process reads not more than
one word, e.g. using scanf("%s", ...).
You can only output the result from the process which was started
first (i.e. from the original program).
The resulting program must return with return code 0.
The size of each word does not exceed 4096 bytes.
My code:
#include <stdio.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <unistd.h>
#define DBG(args...) fprintf(stderr, args)
//#define DBG(args...)
int main(int argc, char* argv[])
{
int status;
pid_t pid;
pid_t first_child;
for (int i = 0; i < 256; ++i) {
pid = fork();
if (pid == 0) { // child continue reading
char str[4097];
if (scanf("%s", str) != EOF)
continue;
exit(1);
} else {
if (i == 1) {
first_child = pid;
}
if (wait(&status) == first_child) {
break;
} else {
exit(WEXITSTATUS(status) + 1);
}
}
}
fprintf(stdout, "%i\n", WEXITSTATUS(status));
fflush(stdout);
fclose(stdout);
return 0;
}
Rewrote the algorithm and it worked!
In the first version, many unnecessary forks were made. For example, if 6 were intended it created 12.
#include <stdio.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <unistd.h>
// #define DBG(args...) fprintf(stderr, args)
#define DBG(args...)
int main(int argc, char* argv[])
{
int status;
pid_t first_pid;
pid_t pid = fork();
if (pid != 0) {
wait(&status);
printf("%i\n", WEXITSTATUS(status));
return 0;
}
for (int i = 0; i < 256; ++i) {
char str[4097];
if (scanf("%s", str) == EOF) {
DBG("PID %i\n", pid);
exit(0);
}
pid = fork();
if (pid != 0)
break;
}
DBG("PID %i waiting\n", pid);
wait(&status);
exit(WEXITSTATUS(status) + 1);
}

How can I pass data to the input stream and receive data from the output stream of the child process?

A program for Linux, in the C programming language. In a program I am developing, a child process is created using the fork function, which is replaced by another program using the execl function, which I cannot change. How can I pass data from my program to the input stream and get data from the output stream of the child process?
Below is a test program that runs another test program. The parent program sends the character string to the child on standard input, the child returns it back on the standard output. I need to get an interface to programs that run interactively through the terminal. Am I doing everything right?
./parent child test_string
// parent.c
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char * argv[]) {
if (argc < 3) {
return 0;
}
char* in_str = argv[2];
char out_str[10] = {};
char* command = argv[1];
int pin[2], pout[2], perr[2];
pipe(pin);
pipe(pout);
pipe(perr);
pid_t pid = fork();
if (pid == 0) {
/*Child*/
close(pin[1]);
dup2(pin[0], 0);
close(pin[0]);
close(pout[0]);
dup2(pout[1], 1);
close(pout[1]);
close(perr[0]);
dup2(perr[1], 2);
close(perr[1]);
execl(command, command, NULL);
perror(command);
exit(1);
}
/*Parent*/
close(pin[0]);
close(pout[1]);
close(perr[1]);
FILE *fin = fdopen(pin[1], "a");
FILE *fout = fdopen(pout[0], "r");
fprintf(fin, "%s\n", in_str);
fflush(fin);
fscanf(fout, "%9s", out_str);
printf("%s\n", out_str);
fclose(fin);
close(pin[1]);
wait(NULL);
return 0;
}
// child.c
#include <ctype.h>
#include <stdio.h>
int main(int argc, char * argv[]) {
char str[10];
scanf("%9s", str);
printf("%s\n", str);
return 0;
}
// child2.c
#include <ctype.h>
#include <stdio.h>
int main(int argc, char * argv[]) {
int c;
while ((c = getchar()) != '\n') {
putchar(c);
}
putchar('\n');
return 0;
}
// build.sh
#!/bin/sh
gcc parent.c -o parent
gcc child.c -o child
gcc child2.c -o child2

i am confused with the child process that I have to implement for each unix command in this program

I just want implementation of child process for each unix command that I have created and need to printout each process id. It should be like for every individual unix command I have to make child process
#include <stdio.h>
#include <math.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char **argv)
{
if(argc == 1){
printf("Pass UNIX commands as command line arguments to execute it.");
exit(0);
}
int commandLen = ceil((argc - 1)/2) ;
printf("Command length : %d", commandLen);
pid_t pids[commandLen];
for(int i=1; i< argc ; i= i +2 ){
if( i< argc && (i+1)< argc){
char * command = (char *) malloc(2 + strlen(argv[i])+ strlen(argv[i+1]) );
strcpy(command, argv[i]);
strcat(command, " ");
strcat(command, argv[i+1]);
system(command);
}else{
system(argv[i]);
}
}
return 0;
}
Unfortunately the system function doesn't provide any mechanism to return process IDs for childs.

Unix command line arguments to kill process after a single print

I need to pass unix arguments to run C file so that it prints a certain line "Hello World" a single time only. The file uses fork to print the sentence multiple times but I need to send a kill signal to kill the processes after the sentence "Hello World" is printed once only.
I tried
./"file name" sleep 4 KILL -9
I do not think I am using the right syntax here.
#include <unistd.h>
#include <stdlib.h>
#include <signal.h>
#include <stdio.h>
int main(int argc, char * argv[])
{
int m, i, c = 0;
pid_t pgid;
m = atoi(argv[1]);
for(i = 0; i < 3; ++i)
{
if(fork() > 0)
{
c = 1;
}
}
if(!c)
{
pgid = getpgid(getpid());
setpgid(getpid(), getpid());
kill(m * pgid, SIGINT);
}
sleep(3);
if(fork() > 0)
{
puts("Hello World");
}
return 0;
}
It is printing few times and then it hangs.

Resources