In: Computer Science
This program is a simple version of the linux shell using execvp by forking using C
Currently this program of the shell assumes user enters no spaces before and no extra spaces between strings.
Using exec, an executable binary file (eg: a.out) can be converted into a process. An example of using exec is implementing a shell program or a command interpreter. A shell program takes user commands and executes them.
int execvp(const char *file, char *const argv[]);
Same as execv except that we don’t have to give the full path name of the command. Uses the $PATH environment variable to find the path.
static char* args[] = {"cp", "cat.txt", "test1.txt",
NULL}; |
Only code void cmdToArray().
Program should be able to execute ls -l.
<cmd> ls -l <cmd> cp file1.txt file2.txt
#include <stdio.h>
#include <string,h>// strcmp
#include <stdlib.h>// exit
#include <unistd.h>// fork, exec
#include <sys/wait.h>// wait
#define MAXARGS 20
#define ARGLEN 256
void execute(char *cmd, char *arglist[]);
void cmdToArray(char *cmd, char *arglist);
int main(void)
{
int pid;
char *arglist[MAXARGS+1]; // array of pointers
char cmd[ARGLEN]; // read stuff here
while (1)
{
printf("cmd> ");
fgets(cmd, ARGLEN, stdin);
// remove newline from cmd
cmd[strlen(cmd) - 1] = '\0';
// exit if user types exit
if (strcmp(cmd, "exit") == 0)
{
exit(0);
}
else if (*cmd != '\0')
{
// TODO: break cmd into individual strings as elements of
arglist
cmdToArray(cmd, arglist);
execute(arglist);
}
}
return 0;
}
void cmdToArray(char *cmd, char *arglist[]) //code
here
{
// cmd = "*cp file1.txt file2.txt"
// char cmd[25] = ('c', 'p', ' ', 'f', ')
// arglist[0] = cmd;
// arglist[1] = &cmd[3];
// arglist[2] = &cmd[9];
// arglist[3] = "NULL";
// arglist = (**char)malloc(sizeof(char*) * cmd);
// arglist[0] = (char *)malloc(sizeof(char) *MAXARGS *
string);
// int length = strlen(cmd);
/* for (int i = 0; i < length; ++i)
{
if (cmd[i] != ' ')
{
arglist[argc] = &cmd[i];
++argc;
}
else if(cmd[i] == ' ')
{
cmd[i] = '\0';
}
} */
}
void execute(char *arglist[])
{
int pid, exitstatus;
pid = fork(); // make new process
if (pid == -1)
{
perror("fork failed");
exit(1);
}
else if (pid == 0)
{
execvp(arglist[0], arglist);
// exec cannot return
fprintf(stderr, "Cannot execute %s\n", arglist[0]);
exit(1); // exec failed
}
else
{
int got_pid = wait(&exitstatus);
if (got_pid == pid)
{
printf("The child we were waiting for died\n");
if (WIFEXITED(exitstatus))
{
printf("child process %d exited with value %d\n", pid,
WEXITSTATUS(exitstatus));
}
}
else if (got_pid == -1)
{
perror("wait failed");
}
}
}
Please look at my code and in case of indentation issues check the screenshots.
-----------------main.c----------------
#include <stdio.h>
#include <string.h>// strcmp
#include <stdlib.h>// exit
#include <unistd.h>// fork, exec
#include <sys/wait.h>// wait
#define MAXARGS 20
#define ARGLEN 256
void execute(char *arglist[]);
void cmdToArray(char *line, char *arglist[]);
int main(void)
{
int pid;
char *arglist[MAXARGS + 1]; // array of
pointers
char cmd[ARGLEN]; // read stuff here
while (1)
{
printf("cmd > ");
fgets(cmd, ARGLEN, stdin);
// remove newline from cmd
cmd[strlen(cmd) - 1] = '\0';
// exit if user types exit
if (strcmp(cmd, "exit") == 0)
{
exit(0);
}
else if (*cmd != '\0')
{
// TODO: break
cmd into individual strings as elements of arglist
cmdToArray(cmd,
arglist);
execute(arglist);
}
}
return 0;
}
void cmdToArray(char *line,
char *arglist[]) //splits the line into words and
stores in arglist array
{
while (*line
!= '\0')
// if not the end of line .......
{
while (*line == ' ' || *line == '\t' || *line ==
'\n') //checks if we are near whitespaces
*line++ = '\0';
// replace white spaces with
\0 NULL character
*arglist++ = line;
// save
the argument position (start position of word)
while (*line != '\0' && *line != ' '
&& *line != '\t' && *line != '\n')
//skips characters within a word
line++;
//skip till end of next argument (end position
of the word)
}
*arglist =
'\0';
//mark the end of argument list
}
void execute(char *arglist[])
{
int pid, exitstatus;
pid = fork(); // make new process
if (pid == -1)
{
perror("fork failed");
exit(1);
}
else if (pid == 0)
{
execvp(arglist[0], arglist);
// exec cannot return
fprintf(stderr, "Cannot execute
%s\n", arglist[0]);
exit(1); // exec
failed
}
else
{
int got_pid =
wait(&exitstatus);
if (got_pid == pid)
{
printf("The
child we were waiting for died\n");
if
(WIFEXITED(exitstatus))
{
printf("child process %d exited with value
%d\n", pid, WEXITSTATUS(exitstatus));
}
}
else if (got_pid == -1)
{
perror("wait
failed");
}
}
}
--------------Screenshots-------------------
------------------Output-----------------
---------------------------------------------------------------------------------------
Please give a thumbs up if you find this answer helpful.
If it doesn't help, please comment before giving a thumbs
down.
Please Do comment if you need any clarification.
I will surely help you.
Thankyou