-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathmsh.cpp
161 lines (147 loc) · 5.41 KB
/
msh.cpp
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
#include <iostream>
#include <string>
#include <cstdlib>
#include <unistd.h>
#include <sstream>
#include <vector>
#include <wait.h>
#include <signal.h>
using namespace std;
static time_t startTime;
bool cd(char* &currPwd, char* newPwd);
// handler for CTR-C
void handler_sigint(int signal)
{
time_t endTime = time(NULL);
time_t elapsedTime = endTime - startTime;
time_t hours = elapsedTime / 3600;
time_t minutes = (elapsedTime % 3600) / 60;
time_t seconds = (elapsedTime % 3600) % 60;
cout << "\nTime elapsed: " << hours << "h " << minutes << "m " << seconds << "s\n";
exit(EXIT_SUCCESS);
}
// handler for Zombies
void handler_sigchld(int signal)
{
while(waitpid(-1, NULL, WNOHANG) > 0);
}
int main(int argc, char* argv[], char* envp[])
{
startTime = time(NULL);
signal(SIGINT, handler_sigint);
signal(SIGCHLD, handler_sigchld);
char* pwd;
if(!(pwd = get_current_dir_name()))
{
cout << "Envp PWD not found." << endl;
return EXIT_FAILURE;
}
cout << "exit with CTR-C" << endl;
string input;
while (true)
{
cout << pwd << "> ";
// getline to get all user input including whitespace
getline(cin, input);
// string vector to hold the tokens of the whitespace splitted string
vector<string> inputTokens;
// string to hold the current token of the whitespace splitted string
string inputToken;
// stringstream to read the whitespace splitted tokens from, initialized with user input string
stringstream inputStream(input);
// gets the next token of the stringstream and writes it into inputToken until the stringstream is empty
while(getline(inputStream, inputToken, ' '))
{
// pushes the current token (inputToken) into the inputTokens vector
inputTokens.push_back(inputToken);
}
if(inputTokens.size() > 0)
{
bool background = false;
// checks whether the last token in inputTokens is "&"
if(inputTokens.back() == "&")
{
// if "&" was found toggles the background bool and removes the token from inputTokens
background = true;
inputTokens.pop_back();
}
// char* vector to hold all tokens in inputTokens as a C-string for use with chdir() and execvp()
vector<char*> inputTokensC;
// reserving the same amount of memory for the char* vector inputTokensC as there are elements in string vector inputTokens
inputTokensC.reserve(inputTokens.size());
for(int i = 0; i < inputTokens.size(); i++)
{
// pushing the C-string stored in the string of string vector inputTokens into char* vector inputTokensC
inputTokensC.push_back(const_cast<char*>(inputTokens[i].c_str()));
}
// pushing a NULL into the last position of char* vector inputTokensC because execvp() excepts its arguments array to be NULL terminated
inputTokensC.push_back(NULL);
// handling for cd command
if(inputTokens[0] == "cd")
{
// check if user entered a new path
if(inputTokens.size() == 2)
{
// call cd() with the new path, output error if cd() returns false
if(!(cd(pwd, inputTokensC[1])))
{
cout << "Path \"" << inputTokens[1] << "\" not found." << endl;
}
}
}
// handling for other commands
else
{
int childPid;
if((childPid = fork()) == -1)
{
cout << "Can't fork" << endl;
return EXIT_FAILURE;
}
else if(childPid == 0)
{
// CHILD
// call execvp() with out char* vector inputTokensC, output error and exit if execvp() fails
if(execvp(inputTokensC[0], inputTokensC.data()) == -1)
{
cout << "Command \"" << inputTokensC[0] << "\" not found." << endl;
exit(EXIT_FAILURE);
}
// exit after execvp() ran successfully
exit(EXIT_SUCCESS);
}
else
{
// PARENT
if(background == true)
{
// BACKGROUND
// output child PID and restart loop
cout << "[" << childPid << "]" << endl;
}
else
{
// FOREGROUND (blocking)
// wait until child calls exit(), then restart loop
waitpid(childPid, NULL, WUNTRACED | WCONTINUED);
}
}
}
}
}
// Free allocated memory from get_current_dir_name() call
delete pwd;
return EXIT_SUCCESS;
}
// Returns true if directory change was successful, false otherwise
bool cd(char* &currPwd, char* newPwd)
{
if(chdir(newPwd) == 0)
{
// Free allocated memory from get_current_dir_name() call
delete currPwd;
currPwd = get_current_dir_name();
return true;
}
return false;
}