This is a cleaned code that I'm using in order to execute shell commands.
Though isExit is always 0 and loop should run as long as it is !isExit, my program terminates after one loop with the command ls as argument to execute.
Does anyone have any idea?
The output is OK (ls) but then program terminates.
The code is written in C, on Eclipse.
Running on Ubuntu 12 which is running on VM over Windows 7.
int main() {
int numberOfCommands, numOfWords, i, isExit = 0, isBackGround = 0, isSucces;
char input[256];
char *cmdAndArgs[256];
char *commands[256];
do{
// gets and parses user command...
ExecuteCmd(cmdAndArgs);
} while (!isExit);
return EXIT_SUCCESS;
}
void ExecuteCmd(char *cmdAndArgs[]){
pid_t pid;
pid = fork();
if (pid != 0) {
execvp(cmdAndArgs[0], cmdAndArgs);
exit(0);
} else {
waitpid(pid, &status, 0);
}
}
You're running the execvp in the parent process, not in the child. the logic:
pid_t pid;
pid = fork();
if (pid != 0) {
execvp(cmdAndArgs[0], cmdAndArgs);
exit(0);
} else {
waitpid(pid, &status, 0);
}
should be reversed to:
pid_t pid;
pid = fork();
if (pid == 0) { /* Child */
execvp(cmdAndArgs[0], cmdAndArgs);
exit(0);
} else if (pid == -1) {
perror("fork");
} else {
waitpid(pid, &status, 0);
}
the return codes from fork() are: -1 == fork failed (use errno to determine the reason). 0 == I am the child. > 0 == I am the parent. See the reference for fork under the RETURN VALUE section.
Is it possible that you have a buffer overflow in // gets and parses user command...? If you write past the allocated space, you can end up overwriting the value of isExit
Related
I try to get the exit code from a child of a child process in the parent process.
If the process goes in the while loop to fork again i don't get the exit code.
I tried some options for waitpid like WNOHANG but then the program hangs.
Maybe what i wan't is not possible because it's some like a zombie child?
This is my code.
void parrent_process(t_token *token, t_info *info)
{
pid_t pid;
int wstatus;
pid = fork();
if (pid == -1)
return (print_error_msg(FORK_FAIL, NULL, NULL));
if (pid == 0)
{
child_process(token);
}
if (info->in)
close(info->in);
waitpid(pid, &wstatus, 0);
if (WIFEXITED(wstatus))
info->exit_code = WEXITSTATUS(wstatus);
}
void child_process(t_token *token)
{
t_token *cmd_token;
pid_t pid;
pid = 0;
cmd_token = token;
while (token->next && ((token->next)->type == GREAT))
{
pid = fork();
if (pid == -1)
return (print_error_msg(FORK_FAIL, NULL, NULL));
if (pid == 0)
{
redirect_output(token);
break;
}
token = token->next->next;
}
if (execve(cmd_token->path, cmd_token->args, cmd_token->envp) == -1)
{
print_error_msg(CMD_NOT_FOUND, "minishell", cmd_token->args[0]);
exit(127);
}
}
In most POSIX-like systems, the answer is "No — a process can only wait on its own children, those it created directly with fork()1".
However, on Linux, there is the prctl(2) system call. The option PR_SET_CHILD_SUBREAPER allows a process to wait for more distant descendants (grandchildren, great-grandchildren, …) too. However, if the direct parent of a process waits for it, the ancestral process will not get the exit status information.
1 Or posix_spawn()
I'm trying to simulate a unix shell in a C program and it's still in the beginning and working for at most two pipes. I have a vector of commands (char *com[3][3]), which were separated considering the character "|", but my question is how to proceed to more pipes in a for loop? In the follow the current implementation, I'm trying to execute 3 commands separeted by pipes:
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <sys/types.h>
int main(int argc, char **argv){
//Vector with positions of pipes found, position 0 reserved for the total amount of commands.
char* com[3][3] = { { "/bin/ls", "-la", 0 },
{ "/bin/grep", ".", 0}, { "/usr/bin/wc", "-l", 0 }};
//EXECUTE COMMANDS
pid_t fork1, fork2, fork3;
int fd1[2], fd2[2];
if(pipe(fd1) < 0){
perror("pipe1");
}
if(pipe(fd2) < 0){
perror("pipe2");
}
//COMMAND 1
fork1 = fork();
if(fork1 == 0){
dup2(fd1[1], STDOUT_FILENO);
close(fd1[0]);
close(fd2[0]);
close(fd2[1]);
execvp(com[0][0], com[0]);
perror("execvp 1");
exit(EXIT_FAILURE);
}
//COMMAND 2
fork2 = fork();
if(fork2 == 0){
dup2(fd1[0], STDIN_FILENO);
dup2(fd2[1], STDOUT_FILENO);
close(fd1[1]);
close(fd2[0]);
execvp(com[1][0], com[1]);
perror("execvp 2");
exit(EXIT_FAILURE);
}
//COMMAND 3
fork3 = fork();
if(fork3 == 0){
dup2(fd2[0], STDIN_FILENO);
close(fd2[1]);
close(fd1[0]);
close(fd1[1]);
execvp(com[2][0], com[2]);
perror("execvp 3");
exit(EXIT_FAILURE);
}
close(fd1[0]);
close(fd1[1]);
close(fd2[0]);
close(fd2[1]);
waitpid(-1, NULL, 0);
waitpid(-1, NULL, 0);
waitpid(-1, NULL, 0);
return 0;
}
How do I make to com[n][3], in a for loop?
"To iterate is human, to recurse is divine" -- Anon.
I'd attack this with a recursive approach. This is one of those very rare occasions when being a Three Star programmer is almost justified. ;)
This is completely untested, but should get you pointed in the correct direction.
// You'll need to rearrange your command strings into this three dimensional array
// of pointers, but by doing so you allow an arbitrary number of commands, each with
// an arbitrary number of arguments.
int executePipe(char ***commands, int inputfd)
{
// commands is NULL terminated
if (commands[1] == NULL)
{
// If we get here there's no further commands to execute, so run the
// current one, and send its result back.
pid_t pid;
int status;
if ((pid = fork()) == 0)
{
// Set up stdin for this process. Leave stdout alone so output goes to the
// terminal. If you want '>' / '>>' redirection to work, you'd do that here
if (inputfd != -1)
{
dup2(inputfd, STDIN_FILENO);
close(inputfd);
}
execvp(commands[0][0], commands[0]);
perror("execvp");
exit(EXIT_FAILURE);
}
else if (pid < 0)
{
perror("fork");
exit(EXIT_FAILURE);
}
waitpid(pid, &status, 0);
return status;
}
else
{
// Somewhat similar to the above, except we also redirect stdout for the
// next process in the chain
int fds[2];
if (pipe(fds) != 0)
{
perror("pipe");
exit(EXIT_FAILURE);
}
pid_t pid;
int status;
if ((pid = fork()) == 0)
{
// Redirect stdin if needed
if (inputfd != -1)
{
dup2(inputfd, STDIN_FILENO);
close(inputfd);
}
dup2(fds[1], STDOUT_FILENO);
close(fds[1]);
execvp(commands[0][0], commands[0]);
perror("execvp");
exit(EXIT_FAILURE);
}
else if (pid < 0)
{
perror("fork");
exit(EXIT_FAILURE);
}
// This is where we handle piped commands. We've just executed
// commands[0], and we know there's another command in the chain.
// We have everything needed to execute that next command, so call
// ourselves recursively to do the heavy lifting.
status = executePipe(++commands, fds[0]);
// As written, this returns the exit status of the very last command
// in the chain. If you pass &status as the second parameter here
// to waitpid, you'll get the exit status of the first command.
// It is left as an exercise to the reader to figure how to get the
// the complete list of exit statuses
waitpid(pid, NULL, 0);
return status;
}
}
To use this, call it initially with the commands array set up as described, and inputfd initially -1.
If you want to handle < type redirection, you probably want to check for inputfd == -1 at the very top, do redirection if requested and replace inputfd with the appropriate value before entering the remainder of the body.
"ulimit -c unlimited" has been done. Here is the code:
main()
{
do
{
pid_t pid = fork();
int stat_loc;
if(pid < 0)
exit(1);
else if(pid > 0)
{
waitpid(pid, &stat_loc, 0);
sleep(5);
}
else
break;
}
while(1);
assert(0);
}
If I replace sleep(5) with assert(0) the parent process dumps core.
Calling assert(0) on a debug build of your application should cause an abort:
If the argument expression of this macro with functional form compares equal to zero (i.e., the expression is false), a message is written to the standard error device and abort is called, terminating the program execution.
What are you actually looking to do here? It looks like there may be a problem with your forking logic. Typically you test to see if pid == 0 to see if you're in the child process and pid > 0 to see if you're in the parent process, like this:
pid_t pid = fork();
if (pid == 0) {
// child process because return value zero
printf("Hello from Child!\n");
} else if (pid > 0) {
// parent process because return value non-zero.
printf("Hello from Parent!\n");
} else {
printf("Error occurred.\n");
}
In your question you're checking for > 0 and < 0.
Edit: Added error checking branch.
I have a function in C which creates a child process and makes it run execvp.
int Execute(char **arg)
{
pid_t pid;
int status;
if ((pid=fork()) == 0)
{
execvp(arg[0],arg);
perror("Execvp error");
exit(1);
}
else if (pid > 0)
{
waitpid(pid, &status, 0);
}
else
{
perror("Fork error");
exit(2);
}
}
Now I want to alter the function to actually run execvp several times (for example 5), and make the parent process wait for all the children to finish. Tried wrapping it all in for loop, but execvp gets executed just once. I know that basically execvp 'replaces' the current program code, but have no idea whether the iteration does not go on.
Thank you for your help!
First, loop around the process creation collecting the child PIDs
pid_t pid[5];
int i;
for (i = 0; i < 5; i++) {
if ((pid[i]=fork()) == 0) {
execvp(arg[0],arg);
perror("Execvp error");
_exit(1);
}
if (pid[i] < 0) {
perror("Fork error");
}
}
Second, loop around the waitpid call for every valid PID.
for (i = 0; i < 5; i++) {
if (pid[i] > 0) {
int status;
waitpid(pid[i], &status, 0);
if (status > 0) {
// handle a process sent exit status error
}
} else {
// handle a proccess was not started
}
}
Here is my code for the evaluate function, which is called in the main.
void eval(char *cmdline)
{
char *argv[MAXARGS]; /* argv for execve() */
int bg; /* should the job run in bg or fg? */
pid_t pid; /* process id */
bg = parseline(cmdline, argv);
struct job_t tempJob;
if (builtin_cmd(argv) == 0)
{
if ((pid = fork()) == 0)
{ /* child runs user job */
if (execve(argv[0], argv, environ) < 0)
{
printf("%s: Command not found.\n", argv[0]);
exit(0);
}
}
if (!bg)
{ /* parent waits for fg job to terminate */
int status;
if (waitpid(pid, &status, 0) < 0)
unix_error("waitfg: waitpid error");
}
else /* otherwise, don’t wait for bg job */
{
printf("%d %s", pid, cmdline);
}
}
return;
}
Now when I run a background job, I expect that the pid of the job get printed twice twice, once in parent and once for child.I just need to understand what is going on in the code. It works the way it is supposed to but why?
Both the parent and child return from fork, but the condition == 0 is true only for the child:
if ((pid = fork()) == 0)
Thus only the child runs this:
if (execve(argv[0], argv, environ) < 0)
execve replaces the current process, and thus does not return if there is no error, i.e., the child's execution of this program ends either here or at the exit(0); that follows from the error condition.
The rest of the function is run only by the parent in all cases.