0

I can't use the Linux command tee at the time the C program gets executed since I can't find which line of the code in a big project precisely that runs this program. I am struggling to come up with a way to call the tee command inside the C program to redirect its printf statement to a log file also. The problem is that I can't call tee without an executable like "./exe | tee some.log" since the program is already executed. I did some research on how to get the stdout of a running process and saw some answers suggesting to check out /proc//fd/1. But I don't know why "1"(stdout) file is empty, and I was expecting the file should store the printf output of the process.

Sincerely appreciate for any help!

Ian Huang
  • 3
  • 2
  • Using command-line tools within C programs is sort of missing the point of C. There's easy ways to write a logging function that outputs to one or more filehandles, like stdout and/or a file. – tadman Mar 07 '19 at 21:54
  • 1
    *..since the program is already executed.* - what? Then how do you intend to "call" `tee` from within the program which is already executed? – Eugene Sh. Mar 07 '19 at 21:54
  • @EugeneSh. You can call tee using the system(). – Ian Huang Mar 07 '19 at 22:01
  • @tadman If I understand correctly, are you suggesting to for example customize a my_printf()? If so, it wouldn't work for me since then I will need to change every printf in the project, and it is just undoable... – Ian Huang Mar 07 '19 at 22:04
  • EugeneSh is saying that if the program is already running, then making changes to it won't affect the running process; you'd need to recompile and start the process again. And if you're restarting it anyway, you can just pipe it to tee instead of modifying the source. – Ray Mar 07 '19 at 22:10
  • Why not just wrap the program in another program that launches it and does whatever you want done with its output? This could even be a simple script. – David Schwartz Mar 07 '19 at 22:11
  • What I'm saying is it's pretty easy to write a `log()` type function that works just like `printf` using varargs and you can drop it in anywhere you have `printf`. You can also write a macro if you're really opposed to this. – tadman Mar 07 '19 at 22:29
  • Possible duplicate of [How can I implement 'tee' programmatically in C?](https://stackoverflow.com/q/1761950/608639) – jww Mar 08 '19 at 00:33
  • @jww Yes! The answer from there solved my question! Thank you for mentioning it! – Ian Huang Mar 08 '19 at 15:07

1 Answers1

3

A shell sets up a pipeline using pipe and dup2 before invoking the program. There's no reason why you couldn't do it after:

void pipeto(char** cmd) {
  int fds[2];
  pipe(fds);
  if(fork()) {
    // Set up stdout as the write end of the pipe
    dup2(fds[1], 1);
    close(fds[0]);
    close(fds[1]);
  } else {
    // Double fork to not be a direct child
    if(fork()) exit(0);
    // Set up stdin as the read end of the pipe, and run tee
    dup2(fds[0], 0);
    close(fds[0]);
    close(fds[1]);
    execvp(cmd[0], cmd);
  }
}

int main() {
  char* cmd[] = { "tee", "myfile.txt", NULL };
  pipeto(cmd);
  printf("This is a test\n");
}

Result:

$ ./foo
This is a test

$ cat myfile.txt
This is a test

Note that since the shell is no longer aware that there's a tee being piped to, it will not wait for it. This means that output can get a bit jumbled if the program exits and the shell redraws the prompt before tee has finished writing. Output like this is purely a cosmetic problem:

user@host $ ./foo
user@host $ This is a test

It does not mean that the command is hanging, the prompt still works and you can type commands or just hit Enter to redraw.

that other guy
  • 116,971
  • 11
  • 170
  • 194
  • This seems like exactly what I am looking for, thank you! But please allow me some time to take a look at it, and I will come back and accept it at latest tomorrow! Anyway, thank you again for your answer! – Ian Huang Mar 07 '19 at 22:25
  • You can avoid the premature exiting problem by having the program wait for the child before it exits... – Chris Dodd Mar 08 '19 at 00:25
  • @ChrisDodd Yes, though that assumes having an extra child does not interfere with the program. I conservatively assumed it would and double-forked – that other guy Mar 08 '19 at 03:17