views:

116

answers:

3

I'm using the execl function to run a Linux process from C. When I do, for example:

int cmd_quem() { 
  int result; 
  result = fork();
  if(result < 0) {
    exit(-1);
  }

  if (result == 0) {
    execl("/usr/bin/who", "who", NULL);
    sleep(4); //checking if father is being polite 
    exit(1); 
  } 
  else { 
    // father's time
    wait();
  }

  return 0;
}

I get on the console the result of doing "who" on the terminal. What I'd like to know is if there is any function to "catch" the output result from a command. What I mean is, if there is anyway to catch this:

feuplive tty5         2009-11-21 18:20

Which is one of the lines resulting from the who command.

+1  A: 

The exec() family of functions creates a new process image from a regular, executable file. This file is either an executable object file, or an interpreter script. There is no return from a successful call to an exec() function, because the calling process is functionally replaced by the new process.

So any code after exec() is never executed unless it is failed.

If you want to capture output of a shell command you need popen.

Neeraj
+1 for mentioning popen()
Jonathan Leffler
+3  A: 

First, execl does not return unless there's a problem like the executable is not found. That sleep(4) is probably never executed.

As for redirecting and getting the output, check out the Unix Programming FAQ. Look for *spawn_background_command*.

Gonzalo
+1  A: 

To do this, you need to open a pipe. You then replace the child's stdout with the writing end of the pipe, and read from the reading end of the pipe in the parent. Like this modified version of your code:

int cmd_quem(void) {
  int result;
  int pipefd[2];
  FILE *cmd_output;
  char buf[1024];
  int status;

  result = pipe(pipefd);
  if (result < 0) {
    perror("pipe");
    exit(-1);
  }

  result = fork();
  if(result < 0) {
    exit(-1);
  }

  if (result == 0) {
    dup2(pipefd[1], STDOUT_FILENO); /* Duplicate writing end to stdout */
    close(pipefd[0]);
    close(pipefd[1]);

    execl("/usr/bin/who", "who", NULL);
    _exit(1);
  }

  /* Parent process */
  close(pipefd[1]); /* Close writing end of pipe */

  cmd_output = fdopen(pipefd[0], "r");

  if (fgets(buf, sizeof buf, cmd_output)) {
    printf("Data from who command: %s\n", buf);
  } else {
    printf("No data received.\n");
  }

  wait(&status);
  printf("Child exit status = %d\n", status);

  return 0;
}
caf
Good job on cleaning up the plumbing correctly - so few get it right.
Jonathan Leffler