#!/usr/bin/probevue /* pnamesnoop.e - Snoops characters input by the read() system call on stdin Requires a single paramater for the name of the process to "snoop" on. Remember to escape the quotes when passing a string. For example: ./pnamesnoop.e \"ksh\" */ int read(int fd, char *buf, unsigned int size); int write(int fd, char *buf, unsigned int size); @@BEGIN { printf("Script starting.\n"); printf("Watching reads on processes named %s.\n", $1); } /* By checking for arg1 in the prediacte we can limit ourselves to stdin */ @@syscall:*:read:entry when( (__pname == $1) && (__arg1 == 0) ) { __thread char *bufptr; __thread int fd; /* On the use of fd: I use a "keyed" fd value. Originally I used the file descriptor but since we are looking for fd = 0 (stdin) it will be indistinguishable from an initialized (to 0) version. I could check for the process name again, but this sounds expensive (more so than a simple integer comparison). If I use the real fd (and then test for it to be 0 in the exit probe) then probevue dies with the following error: Probevue session has been aborted 0x000000008c284163 (The above error is a bad pointer passed to get_userstring().) A better solution may be to check that bufptr is not NULL in the predicate - This would effectively be the same as checking for fd not set to the default initialized (0) value. */ fd = 1; /* __arg2 is the buffer */ bufptr = __arg2; } @@syscall:*:read:exit when( (__rv > 0) && ( thread:fd == 1) ) { String readbuffer[2048]; /* For stdin we should *always* be less than 2048 */ if (__rv < 2048) readbuffer = get_userstring(thread:bufptr, __rv); else readbuffer = get_userstring(thread:bufptr, 2048); printf("%s", readbuffer); /* For some reason we capture a (decimal) 13 CR instead of a (decimal) 10 LF from the shell input. Here I convert back so that it displays properly. This *may* be a result of the TERM that I am using. I just look for \r anywhere in the line and print a LF. The expectation (when watching stdin from a shell or similar app) is that we will always see the EOL character at the end of the buffer (and never in the middle). read() in this case is really grabbing individual chars and never binary- like blocks of data that may have an EOL in the middle. */ if(NULL != strstr(readbuffer, "\r")) printf("\n"); }