Add history
[minishell-2.git] / Sources / opsys.cpp
blobb2319b608d4ba4a39c1e92be84e0c2abef0a040f
1 #include "Headers/opsys.h"
3 #include <sys/param.h> // MAXPATHLEN
4 #include <sys/wait.h> // waitpid
5 #include <unistd.h> // getcwd, fork, chdir, geuid, gethostname, execvp
6 #include <pwd.h> // struct passwd, getpwuid_r
8 using std::cin;
9 using std::cout;
10 using std::cerr;
12 OpSys OS; // Global OpSys variable. Should be accessible to all modules.
13 bool exit_program = false;
15 void signal_handler(int s)
17 if (s==SIGINT)
19 cout << "\nSIGINT (Ctrl+C) received. Code " << s << ". Exiting.\n";
20 exit_program = true; // We'll do this instead of an exit(0) in order to allow for cleanup.
23 if (s==SIGHUP)
25 cout << "\nSIGHUP received. Code " << s << ". Exiting.\n";
26 exit_program = true; // We'll do this instead of an exit(0) in order to allow for cleanup.
30 SignalHandler::SignalHandler()
32 signal_action.sa_handler = signal_handler;
33 sigemptyset(&signal_action.sa_mask);
34 signal_action.sa_flags = 0;
35 sigaction(SIGINT, &signal_action, NULL);
38 string OpSys::get_cwd()
40 char temp[MAXPATHLEN];
41 return getcwd(temp, sizeof(temp)) ? std::string( temp ) : std::string("");
44 void OpSys::change_dir(vector<string> command)
46 if (command.size() == 1 || !command[1].compare("~") || !command[1].compare("$HOME"))
47 { // User wants to cd into $HOME/~.
48 chdir(getenv("HOME"));
49 this->cwd = get_cwd();
50 cwd_changed = true;
51 return;
54 string cmd;
56 for(unsigned short int i = 1; i < command.size(); i++) // TODO: unneeded?
57 cmd += command[i];
59 if (chdir(cmd.c_str()))
61 // Couldn't get to change dirs
62 cerr << "minish2: cd: " << cmd << ": Arquivo ou diretório não encontrado.\n";
64 else
66 // chdir worked. and tell Prompt to act accordingly.
67 this->cwd = get_cwd(); // Update the OpSys OS's current cwd
68 cwd_changed = true; // Signals a cwd change to Prompt.
72 vector<const char*> make_argv(vector<string>const& in)
74 vector<const char*> out;
75 out.reserve(in.size() + 1);
76 for (const auto& s : in)
77 out.push_back(s.data());
78 out.push_back(nullptr);
79 out.shrink_to_fit();
80 return out;
83 short OpSys::piped_command(vector<string> tokens, int pipe_count)
85 if(is_verbose)
87 cerr << "Running piped_command with ";
88 cerr << "tokens: [";
89 for(unsigned short int k = 0; k < tokens.size()-1; k++)
90 cerr << "\"" << tokens[k] << "\", ";
91 cerr << "\"" << tokens.back() << "\"]\n";
94 int n_commands = pipe_count + 1;
95 int file_descriptor_array[10][2];
96 unsigned short i, j=0;
97 string pipe_str = "|";
99 for(i=0; i < n_commands; i++)
101 if (n_commands > 10)
102 { // This is an arbitrary decision. Allowing for more pipes is easily possible.
103 cerr << "More pipes than supported.\n";
104 return -1;
106 vector<string> aux_cmd;
107 for(;j<tokens.size();)
109 if (!tokens[j].compare(pipe_str))
110 { // We've hit a pipe character.
111 j++; // Skip a position for the next iteration.
112 break;
114 else
115 { /* Current token is not a pipe character
116 * so let's add it to our auxiliary command vector */
117 aux_cmd.push_back(tokens[j++]);
121 // Creating pipe
122 if(i!=n_commands-1)
124 if(pipe(file_descriptor_array[i])<0)
126 cerr << "Error on pipe initialization.\n";
127 return -1;
130 // Forking
131 pid_t pid = fork();
132 if(pid==0) // Primeiro processo filho
134 if(i!=n_commands-1)
136 dup2(file_descriptor_array[i][WRITE_END],STDOUT_FILENO);
137 close(file_descriptor_array[i][READ_END]);
138 close(file_descriptor_array[i][WRITE_END]);
140 if(i!=0)
142 dup2(file_descriptor_array[i-1][READ_END],STDIN_FILENO);
143 close(file_descriptor_array[i-1][WRITE_END]);
144 close(file_descriptor_array[i-1][READ_END]);
146 if(is_verbose)
148 cerr << "piped_command is going to execvp aux_cmd: [";
149 for(unsigned short int k = 0; k < aux_cmd.size()-1; k++)
150 cerr << "\"" << aux_cmd[k] << "\", ";
151 cerr << "\"" << aux_cmd.back() << "\"]\n";
153 execvp(aux_cmd[0].c_str(), const_cast<char* const *>(make_argv(aux_cmd).data()));
154 cerr << aux_cmd[0] << ": Comando não encontrado.\n";
155 return -1;
157 else {
158 if(i!=0)
160 close(file_descriptor_array[i - 1][READ_END]);
161 close(file_descriptor_array[i - 1][WRITE_END]);
165 for(i=0; i<n_commands; i++)
166 wait(NULL);
167 return 1;
170 void OpSys::show_history() // TODO: save (and read) history on a file? use Bourne Again's history??
172 unsigned short i = 0, j;
173 for(vector<string> command : history)
175 string command_str = "";
176 for(j=0; j<command.size()-1; j++)
178 command_str += command[j] + ' ';
180 command_str += command.back();
181 printf("%-20hu\t%s\n", i++, command_str.c_str()); // You may think this is unoptimized... which would actually be quite true.
183 fflush(stdout);
186 short OpSys::simple_command(vector<string> tokens)
188 int status;
189 if(is_verbose)
191 cerr << "execvp(\"" << tokens[0] << "\",\"";
192 for(unsigned int i = 0; i < tokens.size()-1; i++)
193 cerr << tokens[i] << ' ';
194 cerr << tokens.back();
195 cerr << "\");\n";
198 pid_t pid = fork();
199 if (pid == 0)
201 execvp(tokens[0].c_str(), const_cast<char* const *>(make_argv(tokens).data()));
202 cerr << tokens[0] << ": command not found.\n";
203 return -1; // TODO: exit with cleanup
205 else if (pid < 0)
207 printf("Couldn't fork a process.");
208 return 0;
210 waitpid(-1, &status, WUNTRACED);
211 return 1;
214 OpSys::OpSys()
216 cwd = get_cwd();
217 if(cwd.empty())
218 cerr << RED_ANSI << "Could not get the current working directory.\n" << RESET_ANSI;
220 uid_t uid = geteuid(); // Gets the effective ID of the user that started miniSHELL
221 struct passwd pwent;
222 struct passwd *pwent_ptr;
223 char buffer[1024];
225 // Looks for the UDI on the password databank and saves the result on pwent
226 getpwuid_r(uid, &pwent, buffer, sizeof buffer, &pwent_ptr);
227 username = pwent.pw_name; // Saves username
229 char hostname[64];
230 gethostname(hostname, 64);
231 this->hostname = hostname;