-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathcommands.c
More file actions
171 lines (157 loc) · 5.62 KB
/
commands.c
File metadata and controls
171 lines (157 loc) · 5.62 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
/* COMMANDS.C
*
* Author: James
* Date: 03/11/2020
* Last Modified: 06/11/2020
*
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/wait.h>
#include "commands.h"
#define EXIT_LOOP 1
#define LOOP_AGAIN 0
/*
* Function: runCommand
* ------------------------
* Checks for certain special commands otherwise it executes the command in the Command struct via a child process.
* Decides whether to exit or maintain the main program loop
* Performs error checking to ensure the shell operates even when incorrect values are input
*
* @param command - pointer to a command struct
*
* @return an int to decide whether the current process should break the main loop and exit, or keep looping.
*/
int runCommand(Command* command) {
if (strcmp(command->commandName, "exit") == 0) { // IF commandName == exit --> EXIT_LOOP
return EXIT_LOOP;
} else if (strcmp(command->commandName, "cd") == 0){ // IF commandName == exit --> EXIT_LOOP
if(chdir(getArg(command, 1))==-1){
printf("The file or directory '%s' doesn't exist\n", getArg(command, 1), stderr);
perror("chdir error ");
}; // System Call to change directory
return LOOP_AGAIN;
} else {
pid_t pid = fork(); // Creates child process with pid=0
if (pid < 0) {
perror("fork error ");
return EXIT_LOOP;
} else if (pid == 0) {
if (execv(getCommandPath(command), command->arguments)) { // Executes the command
printf("The command '%s' doesn't exist\n", command->commandName, stderr);
perror("execv error ");
return EXIT_LOOP;
}
} else {
int status;
waitpid(pid, &status, 0); // Parent process waits here until child process has finished
return LOOP_AGAIN;
}
}
}
/*
* Function: initCommand
* ------------------------
* Initialises the Command struct variables; allocating memory on the heap and setting default values.
*
* @param command - pointer to a command struct
* @param commandString - char array containing a command name followed by arguments. e.g. "ls -l -a"
*
* @return void
*/
void initCommand(Command* command, char* commandString){
// Initialises all command's variables.
command->length = 0;
command->commandName = strtok(commandString, " "); // extract first word in commandString
command->arguments = (char**) malloc(0);
// Creates the file path to the commands executable.
const char unixCommandPath[] = "/bin/";
int length = strlen(unixCommandPath) + strlen(command->commandName);
char* commandPath = (char*) malloc(length*sizeof(char));
strcpy(commandPath,unixCommandPath);
strcat(commandPath,command->commandName);
addArg(command, commandPath); // Sets first argument in array to be the commandPath
// Extracts and appends all the arguments from commandString
char *arg;
while(arg != NULL){
arg = strtok(NULL, " ");
addArg(command, arg);
}while(arg != NULL);
free(arg); // Free the memory on the heap allocated for holding temporary argument strings.
}
/*
* Function: getCommandPath
* ------------------------
* An accessor function to retrieve a pointer to a char array containing the file path for
* the Command struct's command executable.
*
* @param command - pointer to a command struct
*
* @return pointer to a char array containing the file path to command executable. e.g. "/bin/ls"
*/
char* getCommandPath(Command* command){
return getArg(command,0);
}
/*
* Function: getArg
* ------------------------
* An accessor method for accessing the arguments stored in a Command struct
* Implemented via pointer arithmetic.
*
* @param command - pointer to a command struct
* @param index - integer to decide which argument in the arguments array to return.
*
* @return a pointer to a char array containing the argument stored in the arguments array at the index provided.
*/
char* getArg(Command* command, int index){
return *(command->arguments + index);
}
/*
* Function: addArg
* ------------------------
* Stores a copy of the provided argument in the provided Command structs' array of arguments
* The realloc function is used followed by pointer arithmetic to add the new argument to the end of the array
*
* @param command - pointer to a command struct
* @param arg - a pointer to a char array containing a command line input from the user. e.g. "-la"
*
* @return void
*/
void addArg(Command* command, char* arg){
// Re-allocates the arguments array so that its length is incremented by one.
command->arguments = (char**) realloc(command->arguments, sizeof(char*) * ++command->length);
// sets the value of the last element in the arguments array equal to arg.
*(command->arguments + (command->length - 1)) = arg;
}
/*
* Function: freeCommand
* ------------------------
* De-allocates the dynamic memory stored for the Command struct provided.
*
* @param command - pointer to a command struct
*
* @return void
*/
void freeCommand(Command* command){
free(command->commandName);
free(command->arguments);
}
/*
* Function: outputCommand
* ------------------------
* Prints the provided Command structs' command name and all its arguments to stdout.
*
* @param command - pointer to a command struct
*
* @return void
*/
void outputCommand(Command* command){
printf("Command: %s\n", command->commandName);
printf("Arguments (%d):\n", command->length);
for(int i = 0; i < command->length; i++){
printf("%d %s\n", i, getArg(command,i));
}
printf("----------------\n");
}