I'm trying to fork() a new process and exec() the the user program in newly created process.
This code works in user space. I'm not sure how to do the similar thing in kernel space. As per my debugging, seems like fork() never returns 0 in kernel space.
Additional question: How can I execute the user program from kernel space. Is it possible to do that with exec()?
int
main(int argc, char *argv[])
{
int pid = fork();
if(pid == 0){
// child
char *argv[2];
argv[0] = "echo";
argv[1] = "CHILD";
exec("/bin/echo", argv);
exit();
}
if(pid > 0) {
wait();
printf("parent");
}
else {
printf("ERROR");
}
exit();
}
Related
So I've been trying to fork a process two times, first fork is to let the main process continue working and the second is to let the child capture the output of the execution of the grand child process. The code is as follow:
void execute_run(char **parameters) {
task_t* task = create_task();
tasks[task_number] = *task;
int pipe_stdout[2];
ASSERT_SYS_OK(pipe(pipe_stdout)); // creating a pipe for stdout
pid_t pid = fork();
ASSERT_SYS_OK(pid);
if (pid == 0) {
// child process
char buffer[MAXLENGTH_OUTPUT];
pid = fork();
ASSERT_SYS_OK(pid);
if (pid == 0) {
// this process will redirect stdout to buffer
const char* program_name = parameters[0];
char** program_args = ¶meters[1];
ASSERT_SYS_OK(close(pipe_stdout[0]));
ASSERT_SYS_OK(dup2(pipe_stdout[1], STDOUT_FILENO));
// redirecting stdout to pipe
ASSERT_SYS_OK(close(pipe_stdout[1]));
ASSERT_SYS_OK(execvp(program_name, program_args));
}
else {
ASSERT_SYS_OK(close(pipe_stdout[1]));
int status;
do
{
// this loop runs forever
} while (waitpid(pid, &status, WNOHANG) == 0);
ASSERT_SYS_OK(close(pipe_stdout[0]));
// this is never printed
fprintf(stderr, "Child process finished with status %d\n", status);
}
} else {
// parent process won't use any of the pipe ends
ASSERT_SYS_OK(close(pipe_stdout[0]));
ASSERT_SYS_OK(close(pipe_stdout[1]));
}
}
char** parameters are ['cat', 'in.txt'] in the example i'm trying to run (and file exists).
Thanks in advance!
I've tried debugging it and running with different commands like 'ls' for which it works fine, nevertheless I can't figure out why with 'cat' it doesn't work
I am creating a child process with a fork in program y. In that child, I run another program with exec, in which I want the function in that program (let's call it program x) to return something to me. Is there a way to pass this returned value to the parent?
I provided some sort of a pseudo-code that demonstrates what I want to do below.
program.x:
int main(int argc, char** argv)
{
if(argc != 2)
{
printf("argument count does not match\n");
return -1;
}
printf("task1!\n");
...
char *value = "want this"; // how to pass this to the parent in the program y?
...
}
program y:
int main(int argc, char *argv[])
{
int fd[2];
pipe(fd);
pid_t p;
p = fork();
if(p==-1)
{
printf("There is an error while calling fork()");
}
if(p==0)
{
printf("We are in the child process\n");
printf("Calling hello.c from child process\n");
char *args[] = {"Hello", "C", "Programming", NULL};
execv("./hello", args);
close(fd[0]);
write(fd[1], ???, ??);
close(fd[0]);
}
else
{
printf("We are in the parent process");
wait(NULL);
close(fd[1]);
read(fd[0], ???,???);
close(fd[0]);
}
return 0;
}
The only thing you can pass directly is the exit code of the child (via wait()).
To pass a string between two processes, you need an IPC data structure like pipes. See the pipe() function in unistd.h.
For the simple case where there is one-way communication from a child to a parent), you can use popen. It's high level, simple to use, and has little overhead (if any) over fork/exec
int main(...)
{
...
FILE *fp = popen("./hello 'Hello', 'C', 'Programming'", "r") ;
char resp[200] ;
if ( fgets(resp, sizeof(resp, fp) ) {
// Do something
}
int result = pclose(fp) ;
}
Note that the way to pass command line arguments follows shell rules - arguments may need to be quoted (usually, single quote) to pass any special characters.
The 'pclose' result is the exit code of the executed program.
I have the following code:
int main(int argc, char **argv)
{
char *program;
char stringa[1000] = "";
int num = 123;
char snum[5];
program = argv[1];
sprintf(stringa, "./%s", program);
pid_t pid = fork();
if (pid < 0 ) {
perror("fork failed.");
exit(1); }
else if (pid == 0) {
char* args[] = {stringa, NULL};
execv(args[0], args);
}
else {
char procmon_str[] = "./procmon ";
num = pid;
sprintf(snum, "%d",num);
printf("PID of child is %s", snum);
char* args2[] = {procmon_str, snum, NULL};
execv(args2[0], args2);
sleep(20);
kill(num, SIGTERM);
sleep(2);
int parent_pid = getpid();
printf("PID of parent is %d", parent_pid);
kill(parent_pid, SIGTERM);
}
wait(NULL);
return 0;
}
The idea is to call with program with 1 command line argument which is a name of another compiled C program in the same folder.
I want to execute that program from within the C code (hence the use of fork()), and at the same time i want to launch another program from within the parent part of the fork().
The part that is in the child part of fork() works perfectly, but when i run it through the shell it says Terminated right after and does not execute the code in the parent part of the fork().
Why is that?
Your program call fork(). Now the execution of the parent process and the child process proceeds in parallel.
The child:
Builds the argument array args[].
Calls execv() and is replaced by the program supplied as argument.
The parent, in parallel with the child:
Builds the argument array args2[].
Calls execv() and is replaced by ./procmon.
The code from sleep(20) onwards in not reached unless the execv() fails (which you did not check for).
Read the manual page for fork() again, and redo the logic of the program.
int spawn( char* program, char** args) {
pid_t child_pid;
child_pid = fork();
if( child_pid!= 0) { // so this returns if the forking fails? Why would a fork fail?
return (int)child_pid;
}
else {
execvp(program, args);
return (int)child_pid;
}
}
I have the following code I am trying to debug. The problem is, when the parent calls it the child_pid value in my watchlist is some big number (bigger than zero) but the program itself does go in the else block.
I want to see how it goes in that else block buy my gdb debugger seems to stop after the child_pid returns its big number
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 7 years ago.
Improve this question
I want to create as many child processes as the user sends in the argument. And I succeeded. However, I have to create child processes using the exec function, I do not know how to do it. Childs process are to be created as separate programs and run
by exec. In addition, I would like every child process to communicate with the main process (parent) using pipe. I do not know how to do it. So far I managed to write something like this:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
int main(int argc, char **argv)
{
pid_t pid;
if(argc < 3)
{
printf("Not enought arguments");
exit(0);
}
int number = atoi(argv[2]); // number of childern
pid_t pids[number],pid_s;
int i,n=number,status;
int pipes[number*2];
char buff[512];
if(strcmp("-p", argv[1]) == 0)
{
//
}
if(strcmp("-f", argv[1]) == 0)
{
//
}
switch (pid = fork()) {
case -1:
perror("Error in fork");
exit(0);
break;
case 0:
for(i=0; i < n; i++)
{
if((pids[i] = fork()) < 0)
{
perror("error fork");
}
else if(pids[i] == 0)
{
close(pipes[0]);
char *reply = "message";
write(pipes[1], reply, strlen(reply)+1);
execvp(argv[0],NULL);
}
}
while(n > 0)
{
pid_s = wait(&status);
--n;
}
break;
default:
close(pipes[1]);
read(pipes[0],buff,80);
printf("Message: %s", buff);
if(wait(0) == -1)
{
}
break;
}
return 0;
}
I correct the code, the child creates a new process by the exec. I would like to the child communicated with the main process by pipe. Do it in a loop best?
this example code, snipped from: http://www.cs.ecu.edu/karl/4630/sum01/example1.html shows how to use the execvp() function, with minor modifications by me.
It uses function parsecmd(cmd,argv), which is not writtten here, but which breaks cmd at spaces and stores the pieces into (local array) argv[], followed by a null pointer. For example, parsecmd("eat the banana", argv) will set argv as follows.
argv[0] = "eat"
argv[1] = "the"
argv[2] = "banana"
argv[3] = NULL
This example also presumes that there might be other child processes running in background, and that they might terminate while the shell is waiting for the current command to stop. A function called process_terminated is use to handle the termination of a background process. It is not written here.
int runcmd(char *cmd)
{
char* argv[MAX_ARGS];
pid_t child_pid;
int child_status;
parsecmd(cmd,argv);
child_pid = fork();
if(child_pid == 0) {
/* This is done by the child process. */
execvp(argv[0], argv);
/* If execvp returns, it must have failed. */
fprintf( stderr, "execvp failed due to %s\n", strerror(errno) );
exit(0);
}
else {
/* This is run by the parent. Wait for the child
to terminate. */
do {
pid_t tpid = wait(&child_status);
if(tpid != child_pid) process_terminated(tpid);
} while(tpid != child_pid);
return child_status;
}
}