[net.unix-wizards] am I in background?

mo@wgivax.UUCP (Michael O'Shea) (11/05/85)

On a 4.2 system, is there any reliable way in which a c-program can determine
from within itself if it is running in background and/or has its input and/or
output redirected (from/into a file or through a pipe)?

I am aware of the method on Version 7 systems consisting of checking if the
SIGINT signal is turned off initially, indicating a process started in back-
ground.  This does not work under 4.2.

I am trying to implement an automatic audit trail mechanism which allows users
to enter optional comments at the beginning of major system utilities (sort,
awk, sed, etc.)  The problem is that many of our users frequently use pipes,
file redirection, and background processing, thus making the task of knowing
when to query for a comment more complex.

Thank you in advance.

Mike O'Shea  (decvax!mcnc!unccvax!wgivax!mo)

am@vilya.UUCP (MALEK) (11/06/85)

> On a 4.2 system, is there any reliable way in which a c-program can determine
> .......... if it is run directly from a terminal.
> I am trying to implement an automatic audit trail mechanism which allows users
> to enter optional comments at the beginning of major system utilities (sort,
> awk, sed, etc.)  The problem is that many of our users frequently use pipes,
> file redirection, and background processing, thus making the task of knowing
> when to query for a comment more complex.       Mike O'Shea
The best way top solve your problem is to have "aud" (or some other name).
code for "aud":
if test "$#" = 0
then 
echo YOUR SYNTAX MESSAGE
exit 1
fi
<code for auditing goes here. You can check $1 for which command is running>
# now run the command by exec or sh or ksh......
exec $*

This is rather portable and allows the user to turn on logging when desired.
To force logging, you probably need to add lines or to front end each
command separately.
-- 
Avi Malek @ATT Bell Labs Parsippany, NJ

gwyn@brl-tgr.ARPA (Doug Gwyn <gwyn>) (11/08/85)

> I am trying to implement an automatic audit trail mechanism which allows users
> to enter optional comments at the beginning of major system utilities (sort,
> awk, sed, etc.)  The problem is that many of our users frequently use pipes,
> file redirection, and background processing, thus making the task of knowing
> when to query for a comment more complex.

This fellow seems to be serious!!

May I suggest that he instead implement aud_sort, aud_awk, aud_sed,
or maybe even a general "aud" command to collect his audits and
leave the system utilities themselves alone.

And I thought I'd heard them all...

ron@BRL.ARPA (Ron Natalie) (11/08/85)

Being in the background is in the frame of mind of the shell.
If the user is using a standard Bourne Shell, being in the
background also means that either the standard input was
redirected or the shell set it to /dev/null.  On shells
with job control, all it does is switch the terminal process
group to something different than the running process.  The
standard input is not touched.  However if the standard input
is still the terminal, the user will read EOF whenever he tries
to read it, unless he is catching SIGTTIN.  In this case, he
will get the TTIN singal when he tries to read the tty.

You'll have to remember that under job control, things can migrate
from foreground to background to foreground.  All background means
is the shell is not waiting on process completion.

It seems your best bet is to use a combination of isatty() (to check
for redirection) and either checking for EOF or catching the TTIN
signal.

-Ron

phil@RICE.ARPA (William LeFebvre) (11/09/85)

>Ron Natalie:
> On shells with job control, all it does is switch the terminal process
> group to something different than the running process.  The
> standard input is not touched.  However if the standard input
> is still the terminal, the user will read EOF whenever he tries
> to read it, unless he is catching SIGTTIN.

What?  Not with the c-shell.  If the login process (the shell) still
has the control terminal open, then the process doing the read always
gets a SIGTTIN (actually, the whole process group get the TTIN).
Otherwise, the read returns with an EBADF (of course, stdio translates
an EBADF into an EOF).  The default action for TTIN is to stop the
process.  If TTIN is being held or ignored, then the read returns an
EIO.  When a process gets stopped for any reason (in this case, from a
TTIN), the parent process (usually the c-shell) gets a SIGCHLD,
indicating that a child's status has changed.

The result is that when you put a process in the background that then
tries to read from your terminal, the c-shell will say "Stopped (tty
input) ...".  This happens without any unusual action on the part of
the child -- it is the default.  This turns out to be very handy,
especially with an interactive program that has a long startup time
(such as TeX).  One can start the program in the background and go off
and do something else while it starts up (like make small changes to an
input file).  When it is ready, it will get stopped.  Then the user can
simply "fg" it and start typing.  Unfortunately, emacs doesn't benefit
from this since it does an ioctl on the terminal (which has similar
consequences) before it does all of its startup stuff (like reading the
profile).

			William LeFebvre
			Department of Computer Science
			Rice University
			<phil@Rice.arpa>
                        or, for the daring: <phil@Rice.edu>

ron@BRL.ARPA (Ron Natalie) (11/09/85)

Received: from brl-aos.arpa by SEM.BRL.ARPA id a001336; 8 Nov 85 21:18 EST
Received: from rice2-gateway by AOS.BRL.ARPA id a007522; 8 Nov 85 21:06 EST

> What?  Not with the c-shell.  If the login process (the shell) still
> has the control terminal open, then the process doing the read always
> gets a SIGTTIN (actually, the whole process group get the TTIN).

I was wrong, but you misstate the correction.  It has nothing to do
with whether the shell has the control terminal open.  It depends on
whether the tty process group equals the process group of the process.
This is the surefire way of checking for background status under csh
and the Bourne shell in jobs mode.  However, it falls down for normal
Bourne shell, since the process groups will match even for background
jobs.  If you are ignoring or masking TTIN, you will get a real EOF
however.

What happens when the shell dies on most BSD systems is that the shells
parent or some related process (like rlogind) sends a VHANGUP.  A misnomer,
what this really does is turn off both the READ and WRITE bits on all the
file structures that reference the terminal in question.

-Ron

phil@RICE.ARPA (William LeFebvre) (11/10/85)

(Note:  this discussion concerns only 4.2 BSD)

> I was wrong, but you misstate the correction.  It has nothing to do
> with whether the shell has the control terminal open.  It depends on
> whether the tty process group equals the process group of the process.

Quite right.  I intentionally oversimplified the situation rather than
be precise (when will I learn?).  The process only gets a TTIN when the
tty process group is not the same as this.  If the login process has
exited (causing a VHANGUP to get "sent" to all the children), the
process doing the read never gets the chance to get a TTIN, since the
VHANGUP action turned off both read and write ability for that file
descriptor.  Thus, he gets an EBADF.

> If you are ignoring or masking TTIN, you will get a real EOF however.

From "/sys/sys/tty.c", function "ttread" (lines 1027--1041):

	/*
	 * Hang process if it's in the background.
	 */
#define bit(a) (1<<(a-1))
	while (tp == u.u_ttyp && u.u_procp->p_pgrp != tp->t_pgrp) {
		if ((u.u_procp->p_sigignore & bit(SIGTTIN)) ||
		   (u.u_procp->p_sigmask & bit(SIGTTIN)) ||
/*
		    (u.u_procp->p_flag&SDETACH) ||
*/
		    u.u_procp->p_flag&SVFORK)
			return (EIO);
		gsignal(u.u_procp->p_pgrp, SIGTTIN);
		sleep((caddr_t)&lbolt, TTIPRI);
	}

The read returns EIO, not end of file.  A simple test program will
prove this to be correct.  I leave that as an exercise to the reader.

			William LeFebvre
			Department of Computer Science
			Rice University
			<phil@Rice.arpa>
                        or, for the daring: <phil@Rice.edu>

chris@umcp-cs.UUCP (Chris Torek) (11/11/85)

> Unfortunately, emacs doesn't benefit from this [running until ready
> for input] since it does an ioctl on the terminal (which has similar
> consequences) before it does all of its startup stuff (like reading the
> profile).

Fixable, and fixed even.  Spencer Thomas did some work on Gosling
Emacs long ago to make sure it did not ask for the terminal until
it was ready to use it.

Too bad the C shell does not do the same:  Try `csh &' sometime to
see if it will read your .cshrc before stopping.  Nope.
-- 
In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 4251)
UUCP:	seismo!umcp-cs!chris
CSNet:	chris@umcp-cs		ARPA:	chris@mimsy.umd.edu

dv@well.UUCP (David W. Vezie) (11/13/85)

(diving into a discussion, head first)

In article <3072@brl-tgr.ARPA> ron@BRL.ARPA (Ron Natalie) writes:
> ... It depends on
>whether the tty process group equals the process group of the process.
>This is the surefire way of checking for background status under csh
>and the Bourne shell in jobs mode.

Getting back to the original question, if you are running 4.2 BSD,
you can use the getpgrp() function along with the ioctl (TIOCGPGRP)
ioctl, and compare the two values.  Csh, (and probably jobs mode in
Bourne shell, although I can't speak for that), sets the terminal
process group (obtained by TIOCGPGRP) to whatever process is currently
in the foreground (be it the shell or whatever).  The only difference
between "cmd" and "cmd &" is that with "cmd", the terminal process group
is set to the process group of "cmd" (or "cmd | othercmd").

-- 
David W. Vezie		 /!well!dv - Whole Earth 'Lectronics Link, Sausalito, CA
	    {dual|hplabs}
(4 lines, 166 chars)	 \!unicom!dave - College of Marin, Kentfield, CA

jsdy@hadron.UUCP (Joseph S. D. Yao) (11/17/85)

In article <129@wgivax.UUCP> mo@wgivax.UUCP (Michael O'Shea) writes:
>On a 4.2 system, is there any reliable way in which a c-program can determine
>from within itself if it is running in background and/or has its input and/or
>output redirected (from/into a file or through a pipe)?

It sounds (from text not quoted here) like what you really want to know
is whether the standard input is the user's terminal.  Phrased that
way, you've prob'ly already realised the easy way:

#define STDIN	0

	if (isatty(STDIN)) ...

(See man 3 ttyname on BSD4.2; should be similar on all other Unices.)
-- 

	Joe Yao		hadron!jsdy@seismo.{CSS.GOV,ARPA,UUCP}

rs@mirror.UUCP (11/22/85)

/* Written  3:52 pm  Nov  8, 1985 by ron@brl-tgr in mirror:net.unix-wizards */
Being in the background is in the frame of mind of the shell.
...
You'll have to remember that under job control, things can migrate
from foreground to background to foreground.  All background means
is the shell is not waiting on process completion.

-Ron
/* End of text from mirror:net.unix-wizards */

One common test is to check the status of SIGINT, because most
shells set it SIG_IGN for background jobs.  I think that this
also holds for the 4.2 csh IFF the job was started in the background;
STOPping the sending the job into the background isn't the same.

The way to do this (as shown in the Unix Programming paper in Volume 2):
	if (signal(SIGINT, SIG_IGN) == SIG_IGN)
	    background_flag++;
	else
	    (void)signal(SIGINT, SIG_DFL);

--
Rich $alz	{mit-eddie, ihnp4!inmet, wjh12, cca, datacube}!mirror!rs
Mirror Systems	2067 Massachusetts Avenue  Cambridge, MA, 02140
Telephone:	6,176,610,777

guy@sun.uucp (Guy Harris) (11/29/85)

> One common test is to check the status of SIGINT, because most
> shells set it SIG_IGN for background jobs.  I think that this
> also holds for the 4.2 csh IFF the job was started in the background;
> STOPping the sending the job into the background isn't the same.

No, it doesn't hold for the C shell.  The only reason that background jobs
1) have their input redirected to /dev/null and 2) ignore SIGINT is that,
without job control, any attempt by them to read from the terminal will
conflict with the foreground job and any signals sent by hitting your
interrupt key will go to them as well as to the foreground job.  Since job
control permits you to prevent background jobs from reading from their
control terminal (they stop if they try) and causes signals from the
keyboard to be sent *only* to the foreground job, and since you may want to
move a job from the background to the foreground and permit it to read from
the terminal and get signals from the terminal, the C shell can't redirect
the input or ignore interrupts (and Ron Natalie's Bourne shell and probably
the Korn shell can't do this either).

There's no way to tell if you were run in the background that works with all
shells on all systems.  Besides, if you have job control you may have been
in the background 10 minutes ago but may be in the foreground now.  If you
need to know this, think harder about *why* you need to know this; you may
find that you don't really need to know it, or that it isn't really want you
need to know.

	Guy Harris

gwyn@brl-tgr.ARPA (Doug Gwyn <gwyn>) (11/30/85)

> There's no way to tell if you were run in the background that works with all
> shells on all systems.  Besides, if you have job control you may have been
> in the background 10 minutes ago but may be in the foreground now.  If you
> need to know this, think harder about *why* you need to know this; you may
> find that you don't really need to know it, or that it isn't really want you
> need to know.

Yes, yes!  A plea to UNIX software developers:  Please remember
what UNIX is all about, and make your tools as generally useful
as possible.  For example: create a separate computation program
that is unaware of the details of its environment, and create a
separate driver program if you must for interactive use on brain-
damaged video terminals.  (No, ordinary video terminals are NOT
the nicest interactive interface.)  Indeed, it is easy enough to
provide an interactive shell script that prompts the user through
parameter specification and then invokes the real, general-purpose
program with the right arguments and plumbing; often that is quite
user-friendly enough.