Where is my parent process sending it's STDERR?

146 views Asked by At

I tried to make the title succinct, but couldn't think of a way to totally encapsulate the question. Here's what I want to do: when running a perl script, I want to know if there are any other processes other than 'myself' that have a connection to the same STDERR stream (in the current tty or potentially appended/redirected to the same STDERR file) and if so, my goal is to be able to tell the difference between my STDERR errors/warnings/verbose messages and any others from other concurrently running programs. When I detect this as a possibility, I want to prepend my script name to all messages I print to STDERR so that the user knows which process the message came from (or at least which ones were from a script I wrote). At the moment, I don't care how I accomplish this or whether a solution encapsulates all possibilities - for now let's call it a proof of concept that captures a reasonable number of use-cases for a decent default behavior. And I am attempting to do this via system calls.

There are 2 scenarios that I wish to account for: messages from sibling processes run concurrently in a piped series of commands and messages from other child processes run serially by the same parent script. I'm not going to try to handle the case of background processes with a handle on the same STDERR stream, but if those are captured, that would be a bonus.

I believe I have a pretty good handle on the first scenario: sibling processes. I can get all the PIDs of any sibling processes using pgrep -P $ppid. The simple existence of sibling processes is enough to warrant the script-name prepend to my messages, but I could even go a step further and use lsof to find out if they have their stderr going to the same STDERR stream as myself - if for example they are running in the background and have their STDERR going to the same TTY (inferred by file descriptor '2'). I could even check if I'm a part of a series of piped commands with perl's -p or -t functions (though I do not want to prepend in the event that a file has been redirected in or out using '<' or '>', so -p or -t alone won't work). Regardless, I am satisfied with how to handle concurrently running sibling processes.

The scenario that I haven't sufficiently figured out is serially run processes controlled by a parent script. My idea is to try and make a reasonable guess as to whether my parent process is an interactive shell or whether it's a script.

I've tried reading up on lsof to figure out if there was a way to do this. I was sort of guessing that any errors from an interactive shell/terminal would not be printed to the same STDERR stream as my script, but apparently they do, so I can't simply look for whether any output is going to my tty from the parent to distinguish the 2 scenarios.

I created a one-liner to use for testing in different contexts:

perl -e '$ppid=getppid();print("lsof -p $ppid:\n",`lsof -p $ppid`)'

I ran it in 2 contexts: one directly on the command line and the other from inside a shell script. The only difference I could see in the lsof run on the parent's PID was that when run on the command line, there were 5 read/write connections to the tty and when run from in the shell script, there were 3 connections to the tty and one read-only read of the shell script. None of the file descriptors in any case were 0, 1, or 2.

Interactive shell:

...
tcsh    87854 me   15u   CHR   16,2    0t3625    13083 /dev/ttys002
tcsh    87854 me   16u   CHR   16,2    0t3625    13083 /dev/ttys002
tcsh    87854 me   17u   CHR   16,2    0t3625    13083 /dev/ttys002
tcsh    87854 me   18u   CHR   16,2    0t3625    13083 /dev/ttys002
tcsh    87854 me   19u   CHR   16,2    0t3625    13083 /dev/ttys002

Inside shell script:

tcsh    89384 me   16r   REG    1,3       363 19758500 /whatever/tmpdelete2.tcsh
tcsh    89384 me   17u   CHR   16,2    0t4721    13083 /dev/ttys002
tcsh    89384 me   18u   CHR   16,2    0t4721    13083 /dev/ttys002
tcsh    89384 me   19u   CHR   16,2    0t4721    13083 /dev/ttys002

So my question is: is there enough information here to reasonably infer whether or not the parent process is an interactive shell or not?

Could I reasonably infer from the parent process's REGular read-only read from a file that the parent process is not an interactive terminal session? Or could I infer from the presence of 5 read/write connections to the tty that the parent is an interactive shell?

To slightly test this idea, I tried putting a sleep 1 on the line above my one-liner to see if the read of the script would go away from the lsof output at some point during a long script execution. I also tried redirecting into and out from the shell script when I ran it.

In my use case, I can tell the difference, but I'm not sure about how other shells behave. I'm really only concerned about shell scripts. I can't think of any reasonable scenario where someone calls a perl script from inside anything else...

0

There are 0 answers