execl() call succeeds in main(), fails in function - c

I'm a beginner to systems programming and I am currently trying to play around with basic server/client communication using sockets, pipes, etc
More specifically I want to be able to connect as a client and input something like '/bin/echo hello'. The server will then split the string into the command and its arguments, and run the command with a call to a function that calls execl(). For now I'm just testing exec call before trying to pass user input in. Why does the following fail with errno set to EFAULT: bad address?
int do_command(char *command) {
if(strcmp(command, "some_string") == 0) {
pid_t pid = fork();
if(pid == -1) {
perror("fork");
exit(1);
}
if(pid == 0) {
if (execl("/bin/echo", "/bin/echo/", "hello", (char*)NULL) == -1) {
perror("execl");
exit(1);
}
} else {
printf("parent\n");
}
}
}
But running the same code in main() runs just fine with an output of 'hello'
int main() {
pid_t pid = fork();
if(pid == -1) {
perror("fork");
exit(1);
}
if(pid == 0) {
if (execl("/bin/echo", "/bin/echo/", "hello", (char*)NULL) == -1) {
perror("execl");
exit(1);
}
} else {
printf("parent\n");
}
}
Is it not possible to run exec() system calls within functions? Thanks in advance.

Related

simple shell program - background processes do not launch properly

I am trying to write a simple shell program, but have a small bug, which I can't seem to solve.
The program should be capable of launching a background process, but it fails to do so properly. It seems to work at first (program launches & the shell is still responsible) but fails at the second command.
In other words what happens is
launch some background process (browser) - works (launches and keeps working)
launch some regular process - works (lunches & finishes)
launch another process - doesn't work. The shell isn't responsive and waits until the background process is over.
Removing the following line:
waitpid(pid,NULL,0);
Solves this issue, but now all programs are 'background' (shell won't wait for anything to finish).
This is the complete function:
int launchprog(int background, char** arglist){
/* create a background process*/
if(background == 1){
pid_t pid = fork();
if(pid == 0){
/* child*/
arglist[-1] = NULL;
if (execvp(arglist[0], arglist) == -1) {
perror("Error in execvp, cannot init child process");
}
exit(1);
} else if (pid < 0) {
perror("Forking error");
exit(1);
}
return 1;
}
/* create a simple process*/
printf("shalom, %d,%d\n", background,getpid());
pid_t pid = fork();
if (pid == 0) {
/* child*/
struct sigaction saint;
saint.sa_handler = &int_signal_handle_exit;
sigemptyset(&saint.sa_mask);
saint.sa_flags = 0;
if (sigaction(SIGINT, &saint, 0) == -1) {
perror("Sigaction Error");
exit(1);
}
if (execvp(arglist[0], arglist) == -1) {
perror("Error in execvp, cannot init child process");
}
exit(1);
}
else if (pid < 0) {
perror("Forking error");
exit(1);
} else {
if (background == 0){ /* this should always be true*/
waitpid(pid,NULL,0);
}
}
return 1;
}

Create background process in C using sigset()

I am making my own shell in C. This is my basic code for running a process:
pid_t childpid;
int status;
int ret = 0;
if (strcmp(line[0], "exit") == 0) {
return;
}
childpid = fork();
if (childpid >= 0) {
if (childpid == 0) {
ret = execvp(line[0], &line[0]);
if (ret == -1) {
printf("ERROR\n");
exit(0);
}
exit(ret);
} else {
waitpid(childpid, &status, 0);
ret = WEXITSTATUS(status);
}
} else {
perror("fork");
exit(-1);
}
Where line is a "string array" holding the commands to run.
Now say I want to run a background process - I have to use sigset. A parent doesn't wait for a backgrounded child process, right? How do I handle this without the child becoming a background process?

Implementing a subshell Unix C

I'm trying to implement a subshell in C. I already have a normal shell, which looks like this:
int status;
pid = fork();
if (pid < 0) {
exit(1);
}
else if (pid == 0) {
if (execvp(node->command.program, node->command.argv) < 0) {
exit(1);
}
}
else {
waitpid(pid, &status, 0);
}
I'm trying to figure out how a subshell works, and how it differs from the code above.
Thanks in advance.

How to execute arbitrary pipes in c and continue

I'm trying to fork and then execute two or more piped commands in the child process. My idea is to use a while loop to continuously fork and execute the command in one process while continuing the loop in the other. Here's my code:
void
execute_pipe_command(command_t *c)
{
command_t command = *c;
pid_t pid = fork();
if(pid > 0) {
int status;
while(waitpid(pid, &status, 0) < 0)
continue;
if(!WIFEXITED(status))
error(1, errno, "Child exit error");
command->status = WEXITSTATUS(status);
return;
} else if (pid == 0) {
while(command->type == PIPE_COMMAND)
{
int fd[2]; pipe(fd);
pid = fork();
if(pid > 0) {
close(fd[0]);
dup2(fd[1], STDOUT_FILENO);
char **args = command->u.command[1]->u.word;
execvp(args[0], args);
} else if (pid == 0) {
close(fd[1]);
dup2(fd[0], STDIN_FILENO);
command = command->u.command[0];
continue;
} else {
error(1, errno, "forking error");
}
}
char **args = command->u.word;
execvp(args[0], args);
} else {
error(1, errno, "forking error");
}
}
Command is a struct that hold it's type, and if it's a pipe command it holds left and right children commands. Otherwise if it's a simple command it holds an array of strings that make up the command.
When I call this function with a pipe command like ls | cat it should execute the commands, but instead it behaves weirdly. The first two piped commands will run but won't give control back to the program. Instead it'll hang. The subsequent commands are just ignored. So if I give this ls | cat | wc this function will print ls and won't exit until I give a SIGINT.
I'm pretty much confused as to what's going on. I'd appreciate if someone could point out the problem.
while (command->type == PIPE_COMMAND) is always true! This is way it hangs.

Getting the wrong return code from exit() after fork() and wait()

I'm working on unit tests for my little daemon but I'm having trouble getting the right exit code from the forked process. If I only run one of the testcases they work fine, but if I run two in a row the second one fail since it doesn't get EXIT_SUCCESS as a return code. I've checked and the second test case does call exit(EXIT_SUCCESS) so it should return that, but somehow I get another child process.
What am I missing?
bool test_setup() {
pid_t pid = fork();
if(pid < 0) {
fail("Failed to fork", PLACE);
}
else if(pid > 0) { //main thread
//act as client to server, this code might call exit(EXIT_FAILURE)
exit(EXIT_SUCCESS);
}
//child thread
//run server
int retval; //return value from child process
wait(&retval);
return WEXITSTATUS(retval) == EXIT_SUCCESS;
}
bool test_send_one() {
pid_t pid = fork();
if(pid < 0) {
fail("Failed to fork", PLACE);
}
else if(pid > 0) { //main thread
//act as client to server, this code might call exit(EXIT_FAILURE)
cout <<"exit success" <<endl;
exit(EXIT_SUCCESS);
}
//child thread
//run server
int retval; //return value from child process
wait(&retval);
return WEXITSTATUS(retval) == EXIT_SUCCESS;
}
int main(int argc, char** argv) {
test_setup();
test_send_one();
}
I had swapped the if(pid > 0) and if(pid == 0).

Resources