views:

106

answers:

3

Hi,

I am trying to debug a C++ application which invokes many command line applications such as grep, etc through a the system() system call. I need to see all the commands the application is executing through the system() call.

I tried to view these commands by enabling history and view the .history file. But these commands are not executed through a terminal. The history file has only the commands executed interactively.

Any idea how this can be done?

+2  A: 

You can use truss or strace (Not sure which one comes with Solaris) to run the program and trace the calls to system.

For truss the relevant command will be something like truss -caf program_name

Steve Weet
Would truss deal with `system()` invocations *per se*, or would it instead, like Linux' strace, show the constituent syscalls (e.g., `fork()` and `exec()`)?
pilcrow
@pilcrow. You are correct it would display the underlying system calls which you could filter to just the exec calls using some truss arguments. It's been a VERY long time since I used it but you can get a list of all execs and the arguments passed to it very easily. Whilst the OP is asking for calls to system() I'm not entirely sure, without knowing the context, whether they would want a specific "fork/exec" instance included or not.
Steve Weet
Solaris truss can actually trace library function calls too, although it won't display their arguments. See my other reply for details.
jlliagre
@jiiagre. Thanks for that. I haven't used truss since about 1993 so my recollection of the syntax was not great.
Steve Weet
+3  A: 

Define a new macro with similar name:

#define system(_x) std::cout << _x << std::endl; (system)(_x);

The system macro replaces the system function and:

  1. It prints the command to the standard output (or elsewhere).
  2. It calls the system function.

Thanks to Hasturkun's suggestion, the following is better:

#define system(_x) (std::cout << (_x) << std::endl, system(_x))

That returns the result of system function call, too ;-)

PC2st
You might want to change it to something like `#define system(_x) (std::cout << (_x) << std::endl, system(_x))` so that it still returns a value.
Hasturkun
@Hasturkun: Thank you. I forgot that the result of `system` function call could be requested in the code.
PC2st
@Hasturkun: In definition of `system` macro, the `system` function call should be surrounded by parentheses to prevent the `system` macro to call itself recursively.
PC2st
@PC2st: that's not necessary -- the C++ standard forbids the preprocessor from expanding the `system` macro recursively.
Ken Bloom
@Ken Bloom: Thanks, that was a good point. :-)
PC2st
A quite intrusive solution albeit working regardless of the OS. Solaris provides easier ways to do the same.
jlliagre
+1  A: 

To trace every command executed by "yourProgram":

truss -s!all -daDf -t exec yourProgram

eg:

$ truss -s!all -daDf -t exec sh -c "/bin/echo hello world;/bin/date" 
Base time stamp:  1282164973.7245  [ Wed Aug 18 22:56:13 CEST 2010 ]
5664:    0.0000  0.0000 execve("/usr/bin/i86/ksh93", 0x080471DC, 0x080471EC)  argc = 3
5664:    argv: sh -c /bin/echo hello world;/bin/date
5665:    0.0106  0.0106 execve("/bin/echo", 0x08067484, 0x080674F8)  argc = 3
5665:    argv: /bin/echo hello world
hello world
5664:    0.0126  0.0126 execve("/bin/date", 0x080674E0, 0x080674F8)  argc = 1
5664:    argv: /bin/date
Wed Aug 18 22:56:13 CEST 2010

If you want to correlate these execs to system() calls, you can use that command:

truss -t execve -f -u 'libc:system' yourProgram

eg:

$ cat a.c
main()
{
system("echo a b c");
system("pwd");
}

$ truss -t execve -f -u 'libc:system' ./a
20073:  execve("a", 0x08047240, 0x08047248)  argc = 1
20073/1@1:  -> libc:system(0x8050a5c, 0x0)
20074/1:    execve("/bin/sh", 0x080471BC, 0x08047248)  argc = 3
a b c
20073/1@1:  <- libc:system() = 0
20073/1@1:  -> libc:system(0x8050a68, 0x0)
20076/1:    execve("/bin/sh", 0x080471BC, 0x08047248)  argc = 3
/tmp
20073/1@1:  <- libc:system() = 0

Finally, if you are using Solaris 10 or newer, you can use Dtrace for this task like this:

dtrace -Z -q -c yourProgram -n ' pid$target:libc:system:entry { printf("system(\"%s\")\n", copyinstr(arg0)); } '

which will give that output with the same "a" code:

a b c
/tmp
system("echo a b c")
system("pwd")

PS: By the way system() isn't a system call but a standard library function.

jlliagre
@jlliagre Exactly what i was looking for! Noted on system() Thanks :)
Raj