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
|
#include <sys/wait.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <limits.h>
#include <stdbool.h>
#include "shell.h"
#define MAX_CMD 1024
#define MAX_PATH 512
int main(int argc, char* argv[]) {
// setup an array of the values in $PATH
char* pathstr = getenv("PATH");
const char* delim = ":";
const char* cmddelim = " ";
const int binlen = strcnt(pathstr, delim[0]) + 1;
char* bins[binlen];
char* path = strtok(pathstr, delim);
int i = 0;
while (path != NULL) {
bins[i++] = path;
path = strtok(NULL, delim);
}
while (true) {
//prefix command, show user, host, cwd
char hostbfr[256];
gethostname(hostbfr, sizeof(hostbfr));
char cwdbfr[MAX_PATH];
getcwd(cwdbfr, sizeof(cwdbfr));
printf(
"[\033[1;32m%s\033[0m@\033[1;31m%s\033[0m]:\033[1;34m%s\033[1;31m$ \033[0m", getenv("USER"),
hostbfr, cwdbfr
);
// get the input string - keep accepting words until a newline
char cmdstr[MAX_CMD];
scanf("%[^\n]", cmdstr);
int c;
while ((c = getchar()) != '\n' && c != EOF); //clear buffer
// parse the input string into an array, splitting by spaces
uint cmdlen = strcnt(cmdstr, cmddelim[0]) + 1;
char* cmdarr[cmdlen + 1];
char* arg = strtok(cmdstr, cmddelim);
i = 0;
while (arg != NULL) {
cmdarr[i++] = arg;
arg = strtok(NULL, cmddelim);
}
//work out if we need to change the cwd
if (strcmp(cmdarr[0], "cd") == 0) {
// printf("Change directory to '%s'\n", cmdarr[1]);
if (chdir(cmdarr[1]) != 0) {
printf("\033[0;31mERROR - Could not change cwd\n\033[0m");
}
continue;
}
//work out if we need to exit
if (exitPrefix(cmdstr)) {
printf("Exited.\n");
break;
}
// try to find a binary
strcpy(cmdstr, cmdarr[0]);
bool binExists = false;
char cmdpath[512];
for (i = 0; i < binlen + 1; i++) {
if (i >= binlen) {
strcpy(cmdpath, cwdbfr);
} else {
strcpy(cmdpath, bins[i]);
}
strcat(cmdpath, "/");
strcat(cmdpath, cmdstr);
if (access(cmdpath, F_OK) != -1) {
binExists = true;
break;
}
}
if (!(binExists)) {
printf("Couldn't find binary - Looked in the following places:\n - %s\n", cwdbfr);
for (i = 0; i < binlen; i++) {
printf(" - %s\n", bins[i]);
}
continue;
}
// printf("Found binary at '%s'\n", cmdpath);
cmdarr[cmdlen] = NULL;
pid_t pid = fork();
bool success = true;
if (pid == 0) {
// printf("Child Process: PID = %i, PPID = %i\n", getpid(), getppid());
if (execvp(cmdpath, cmdarr) < 0) {
perror("\033[0;31mexec error ");
printf("\033[0m");
success = false;
}
break;
} else {
// printf("Parent Process: PID = %i, PPID = %i\n", getpid(), getppid());
int status;
if (waitpid(pid, &status, 0) < 0) {
perror("\033[0;31mwaitpid error ");
printf("\033[0m");
success = false;
}
if (success) {
printStatus(status);
}
}
}
return EXIT_SUCCESS;
}
// prints out the status code of an exited process.
// prints in green if the status code is zero. anything
// else is red.
void printStatus(int status) {
if (status == 0) {
printf("\033[0;32m");
} else {
printf("\033[0;31m");
}
printf("[Process exited with status code %i]\n\033[0m", status);
}
// returns an integer of how many times a char was found in a char
// array
int strcnt(char* str, const char cnt) {
int count = 0;
for (int i = 0; i < INT_MAX; i++) {
char c = str[i];
if (c == '\0') {
break;
}
if (c == cnt) {
count++;
}
}
return count;
}
// returns a boolean if a char array starts with the string "exit"
bool exitPrefix(const char* cmdstr) {
char fourChars[5];
strncpy(fourChars, cmdstr, 4);
return strcmp(fourChars, "exit") == 0;
}
|