Piped commands work now
[minishell-2.git] / Sources / opsys.cpp
blob37f9ed2c08e2c6ded1d499e04356a0f86e26b88c
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)
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))
111 j++;
112 break;
114 else
116 aux_cmd.push_back(tokens[j++]);
120 // Creating pipe
121 if(i!=n_commands-1)
123 if(pipe(file_descriptor_array[i])<0)
125 cerr << "Error on pipe initialization.\n";
126 return -1;
129 // Forking
130 pid_t pid = fork();
131 if(pid==0) // Primeiro processo filho
133 if(i!=n_commands-1)
135 dup2(file_descriptor_array[i][WRITE_END],STDOUT_FILENO);
136 close(file_descriptor_array[i][READ_END]);
137 close(file_descriptor_array[i][WRITE_END]);
139 if(i!=0)
141 dup2(file_descriptor_array[i-1][READ_END],STDIN_FILENO);
142 close(file_descriptor_array[i-1][WRITE_END]);
143 close(file_descriptor_array[i-1][READ_END]);
145 if(is_verbose)
147 cerr << "piped_command is going to execvp aux_cmd: [";
148 for(unsigned short int k = 0; k < aux_cmd.size()-1; k++)
149 cerr << "\"" << aux_cmd[k] << "\", ";
150 cerr << "\"" << aux_cmd.back() << "\"]\n";
152 execvp(aux_cmd[0].c_str(), const_cast<char* const *>(make_argv(aux_cmd).data()));
153 cerr << aux_cmd[0] << ": Comando não encontrado.\n";
154 return -1;
156 else {
157 if(i!=0)
159 close(file_descriptor_array[i - 1][READ_END]);
160 close(file_descriptor_array[i - 1][WRITE_END]);
164 for(i=0; i<n_commands; i++)
165 wait(NULL);
166 return 1;
169 short OpSys::simple_command(vector<string> tokens)
171 int status;
172 if(is_verbose)
174 cerr << "execvp(\"" << tokens[0] << "\",\"";
175 for(unsigned int i = 0; i < tokens.size()-1; i++)
176 cerr << tokens[i] << ' ';
177 cerr << tokens.back();
178 cerr << "\");\n";
181 pid_t pid = fork();
182 if (pid == 0)
184 execvp(tokens[0].c_str(), const_cast<char* const *>(make_argv(tokens).data()));
185 cerr << tokens[0] << ": command not found.\n";
186 return -1; // TODO: exit with cleanup
188 else if (pid < 0)
190 printf("Couldn't fork a process.");
191 return 0;
193 waitpid(-1, &status, WUNTRACED);
194 return 1;
197 OpSys::OpSys()
199 cwd = get_cwd();
200 if(cwd.empty())
201 cerr << RED_ANSI << "Could not get the current working directory.\n" << RESET_ANSI;
203 uid_t uid = geteuid(); // Gets the effective ID of the user that started miniSHELL
204 struct passwd pwent;
205 struct passwd *pwent_ptr;
206 char buffer[1024];
208 // Looks for the UDI on the password databank and saves the result on pwent
209 getpwuid_r(uid, &pwent, buffer, sizeof buffer, &pwent_ptr);
210 username = pwent.pw_name; // Saves username
212 char hostname[64];
213 gethostname(hostname, 64);
214 this->hostname = hostname;