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
12 OpSys OS
; // Global OpSys variable. Should be accessible to all modules.
13 bool exit_program
= false;
15 void signal_handler(int s
)
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.
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();
56 for(unsigned short int i
= 1; i
< command
.size(); i
++) // TODO: unneeded?
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";
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);
83 short OpSys::piped_command(vector
<string
> tokens
, int pipe_count
)
87 cerr
<< "Running piped_command with ";
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
++)
102 { // This is an arbitrary decision. Allowing for more pipes is easily possible.
103 cerr
<< "More pipes than supported.\n";
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.
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
++]);
124 if(pipe(file_descriptor_array
[i
])<0)
126 cerr
<< "Error on pipe initialization.\n";
132 if(pid
==0) // Primeiro processo filho
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
]);
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
]);
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";
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
++)
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.
186 short OpSys::simple_command(vector
<string
> tokens
)
191 cerr
<< "execvp(\"" << tokens
[0] << "\",\"";
192 for(unsigned int i
= 0; i
< tokens
.size()-1; i
++)
193 cerr
<< tokens
[i
] << ' ';
194 cerr
<< tokens
.back();
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
207 printf("Couldn't fork a process.");
210 waitpid(-1, &status
, WUNTRACED
);
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
222 struct passwd
*pwent_ptr
;
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
230 gethostname(hostname
, 64);
231 this->hostname
= hostname
;