Piped commands (almost) working
[minishell-2.git] / Sources / opsys.cpp
blob5ef2f432436e0062bdaa101394867680945282c5
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 cerr << "I'm in piped_command\n";
86 int n_commands = pipe_count + 1;
87 int file_descriptor_array[10][2];
88 unsigned short i, j=0;
89 string pipe_str = "|";
91 cerr << "tokens: [";
92 for(unsigned short int k = 0; k < tokens.size()-1; k++)
93 cerr << "\"" << tokens[k] << "\", ";
94 cerr << "\"" << tokens.back() << "\"]\n";
96 for(i=0; i < n_commands; i++)
98 if (n_commands > 10)
100 cerr << "More pipes than supported.\n";
101 return -1;
103 vector<string> aux_cmd;
104 for(;j<tokens.size();)
106 if (!tokens[j].compare(pipe_str))
108 j++;
109 cerr << "BREAKING\n";
110 break;
112 else
114 aux_cmd.push_back(tokens[j++]);
115 cerr << "aux_cmd: [";
116 for(unsigned short int k = 0; k < aux_cmd.size()-1; k++)
117 cerr << "\"" << aux_cmd[k] << "\", ";
118 cerr << "\"" << aux_cmd.back() << "\"]\n";
122 // Creating pipe
123 if(i!=n_commands-1)
125 if(pipe(file_descriptor_array[i])<0)
127 cerr << "Error on pipe initialization.\n";
128 return -1;
131 // Forking
132 pid_t pid = fork();
133 if(pid==0) // Primeiro processo filho
135 if(i!=n_commands-1)
137 dup2(file_descriptor_array[i][WRITE_END],STDOUT_FILENO);
138 close(file_descriptor_array[i][READ_END]);
139 close(file_descriptor_array[i][WRITE_END]);
141 if(i!=0)
143 dup2(file_descriptor_array[i-1][READ_END],STDIN_FILENO);
144 close(file_descriptor_array[i-1][WRITE_END]);
145 close(file_descriptor_array[i-1][READ_END]);
147 execvp(aux_cmd[0].c_str(), const_cast<char* const *>(make_argv(aux_cmd).data()));
148 cerr << aux_cmd[0] << ": Comando não encontrado.\n";
149 return -1;
151 else
153 if(i!=0)
155 close(file_descriptor_array[i - 1][READ_END]);
156 close(file_descriptor_array[i - 1][WRITE_END]);
160 for(i=0; i<n_commands; i++)
161 wait(NULL);
162 return 1;
165 short OpSys::simple_command(vector<string> tokens)
167 int status;
168 if(is_verbose)
170 cerr << "execvp(\"" << tokens[0] << "\",\"";
171 for(unsigned int i = 0; i < tokens.size()-1; i++)
172 cerr << tokens[i] << ' ';
173 cerr << tokens.back();
174 cerr << "\");\n";
177 pid_t pid = fork();
178 if (pid == 0)
180 execvp(tokens[0].c_str(), const_cast<char* const *>(make_argv(tokens).data()));
181 cerr << tokens[0] << ": command not found.\n";
182 return -1; // TODO: exit with cleanup
184 else if (pid < 0)
186 printf("Couldn't fork a process.");
187 return 0;
189 waitpid(-1, &status, WUNTRACED);
190 return 1;
193 OpSys::OpSys()
195 cwd = get_cwd();
196 if(cwd.empty())
197 cerr << RED_ANSI << "Could not get the current working directory.\n" << RESET_ANSI;
199 uid_t uid = geteuid(); // Gets the effective ID of the user that started miniSHELL
200 struct passwd pwent;
201 struct passwd *pwent_ptr;
202 char buffer[1024];
204 // Looks for the UDI on the password databank and saves the result on pwent
205 getpwuid_r(uid, &pwent, buffer, sizeof buffer, &pwent_ptr);
206 username = pwent.pw_name; // Saves username
208 char hostname[64];
209 gethostname(hostname, 64);
210 this->hostname = hostname;