with the provided segments of codes that need to be completed in command.h file:
ID: 3777323 • Letter: W
Question
with the provided segments of codes that need to be completed
in command.h file:
#define MAX_CHAR_LINE 1024
#define MAX_NO_ARGS 10
#define MAX_COMMANDS 10
struct command
{
char *comm;
char *args[MAX_NO_ARGS+2]; //the first item is the command itself and the last is NULL
int no_args; //actual number of arguments excluding the first item, command name, and the last item, NULL.
int order; //the order of the command 0, 1, ...
};
in exec_commands.c file:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>
#include "command.h"
/*
* This function should execute all of the commands in mycommands[],
* properly setting up the pipes between them.
* This means, for example, that the output of mycommands[0] will be
* the input of mycommands[1], and the output of mycommands[1] will
* be the input of mycommands[2], etc.
*
* This function should create the required pipes and then use
* execute_command to create the individual processes.
*/
void execute_commands(struct command mycommands[], int no_commands)
{
return;
}
/*
* This function calls fork and executes a single command. It uses dup2 as
* appropriate to redirect stdin and stdout to fd_in and fd_out.
*
* Arguments:
* command: The command to be executed
* args: An array of strings containing the arguments to the command
* argc: The number of arguments stored in args
* fd_in: The filedescriptor that should be used as stdin for
* the command
* fd_out: The filedescriptor that should be used as stdout for
* the command
*/
int execute_command(char *command, int argc, char *args[], int fd_in, int fd_out )
{
return 0;
}
in exec_commands.h file:
void execute_commands(struct command mycommands[], int no_commands);
int execute_command(char *command, int argc, char *args[], int fd_in, int fd_out );
in get_commands.c file:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include "command.h"
/*
* This is a trim function for strings. You pass it a string,
* and it removes any starting and trailing whitespace.
* It returns a pointer to the trimmed string.
*/
char *mytrim(char *s)
{
if (s == NULL)
return s;
while (isspace((unsigned char) *s))
s++;
if (*s) {
char *p = s;
while (*p)
p++;
while (isspace((unsigned char) *(--p)));
p[1] = '';
}
return s;
}
/*
* Parse the commands found in line and store them in the
* array of struct command data structures mycommands
*/
int get_commands(char *line, struct command mycommands[])
{
int i = 0;
int j = 0;
int k = 0;
/*
* Step 1: Parse the line based on the | character and split up each
* separate command into its own entry in the mycommands array.
* Note that this stores the entire command, with its arguments, in
* the comm entry of the struct command. This is wrong, because the
* arguments should be stored in their own array. We'll fix it later.
*/
while (1) {
char *tmp;
if (i == 0) {
tmp = mytrim(strtok(line, "|"));
} else {
tmp = mytrim(strtok(NULL, "|"));
}
if (tmp == NULL)
break;
mycommands[i].comm = tmp;
mycommands[i].order = i;
i++;
}
/*
* Step 2: Go through each of the commands and parse their
* arguments. This splits the commands by space and/or tab
* in order to get the arguments.
*/
for (j = 0; j < i; j++) {
k = 0;
while (1) {
char *tmp;
if (k == 0) {
tmp = mytrim(strtok(mycommands[j].comm, " "));
} else {
tmp = mytrim(strtok(NULL, " "));
}
mycommands[j].args[k] = tmp;
if (tmp == NULL) {
break;
}
k++;
}
mycommands[j].comm = mycommands[j].args[0];
mycommands[j].no_args = k - 1;
}
return i;
}
in get_commands.h file:
int get_commands(char* line, struct command mycommands[]);
char *mytrim(char *s);
in shell.c file:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "command.h"
#include "get_commands.h"
#include "exec_commands.h"
int main()
{
char *prompt = "cmps405> ";
char line[MAX_CHAR_LINE];
struct command mycommands[MAX_COMMANDS];
int no_co = 0;
while (1) {
// Print the prompt and get a line of input from the user
printf("%s", prompt);
fgets(line, MAX_CHAR_LINE, stdin);
// Check if the user typed "exit"
if (strcmp(mytrim(line), "exit") == 0) {
break;
}
// Check if the user entered a blank line
if (strcmp(mytrim(line), "") == 0) {
continue;
}
// Parse the commands
no_co = get_commands(line, mycommands);
// Execute the commands
execute_commands(mycommands, no_co);
}
return 0;
}
Explanation / Answer
If my understanding of your requirement is correct, is this the code below you want? If not let me know i'll modify it accordingly. I have given you exec_commands.c file below which forks and executes the commands given by the user one at a time.
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>
#include "command.h"
/*
* This function should execute all of the commands in mycommands[],
* properly setting up the pipes between them.
* This means, for example, that the output of mycommands[0] will be
* the input of mycommands[1], and the output of mycommands[1] will
* be the input of mycommands[2], etc.
*
* This function should create the required pipes and then use
* execute_command to create the individual processes.
*/
void execute_commands(struct command mycommands[], int no_commands)
{
int i=0;
int cPids[no_commands];
int fd[2];
int status;
for(i=0;i<no_commands;i++)
{
switch(cPids[i]=fork()){
pipe(fd);
case 0: //child process
close(fd[0]);
execute_command(mycommands[i].comm,mycommands[i].no_args,mycommands[i].args,fd[0],fd[1]);
break;
case -1:
printf("Error while executing the command %s ", mycommands[i].comm);
break;
default:
close(fd[1]);
while (wait(&status) != cPids[i])
break;
}
}
return;
}
/*
* This function calls fork and executes a single command. It uses dup2 as
* appropriate to redirect stdin and stdout to fd_in and fd_out.
*
* Arguments:
* command: The command to be executed
* args: An array of strings containing the arguments to the command
* argc: The number of arguments stored in args
* fd_in: The filedescriptor that should be used as stdin for
* the command
* fd_out: The filedescriptor that should be used as stdout for
* the command
*/
int execute_command(char *command, int argc, char *args[], int fd_in, int fd_out )
{
int n;
if(fd_out==2)
dup2(fd_out,n);
execvp(command,args);
return 0;
}
Related Questions
Navigate
Integrity-first tutoring: explanations and feedback only — we do not complete graded work. Learn more.