[comp.unix.wizards] Is process <n> alive?

jc@minya.UUCP (John Chambers) (12/10/87)

> > On SV, non-root users may kill(2) processes having the same uid and
> > their children.
> > 
> > On BSD, non-root users may only kill(2) processes having the same uid
> > (modulo the setpgrp bug recently mentioned in this group.).  This makes
> > it awkward to kill setuid subprocesses.

This reminds me of a question I'd like to pose to all the wizards out there.
Is there a universal way that will work on any Unix to write a function
	isprocess(n)
which returns TRUE if process n is alive, and FALSE if it isn't alive?

Note that I have said nothing about the relationship of process n (if it
exists) to the process that is asking.  They might or might not be related.
They might or might not have the same uid and gid.  I don't want to kill
the process (or even upset it in any way).  I just want to know if it is
alive.

On this SysV, this can be done (with some difficulty) by doing a kill(0,n),
which doesn't actually do anything to the process (as far as I can tell),
but it does return different values in errno for no-such-process and for
wrong-uid.  I.e., you can examine the return value (0 or -1) and errno,
and from them you can determine whether the process exists or not.

So far, I haven't tried to solve the problem on BSD, but the above remark
implies that my SysV code won't work.

It'd be useful to have a portable subroutine (presumably with an #ifdef or
three) to answer this question.

-- 
John Chambers <{adelie,ima,maynard,mit-eddie}!minya!{jc,root}> (617/484-6393)

dave@spool.wisc.edu (Dave Cohrs) (12/10/87)

In article <429@minya.UUCP> jc@minya.UUCP (John Chambers) writes:
>Is there a universal way that will work on any Unix to write a function
>	isprocess(n)
>which returns TRUE if process n is alive, and FALSE if it isn't alive?

Any Unix?  Well, if the Unix acts like either 4.3BSD or SysV, the
following should work:

int
isprocess(n)
	int n;
{
	extern int errno;

	return (kill(n,0) == 0 || errno != ESRCH);
}

If you read the 4.3BSD kill(2) man page, you see that kill still
does permission checks, so you have to check errno upon return
to make sure that the error isn't EPERM, meaning the process is
alive, but you can't send it signals.

This works on SysV as well.  I tested it.

Dave Cohrs
+1 608 262-6617                        UW-Madison Computer Sciences Department
dave@cs.wisc.edu                 ...!{harvard,ihnp4,rutgers,ucbvax}!uwvax!dave

andrew@frip.gwd.tek.com (Andrew Klossner) (12/11/87)

	"On this SysV, this can be done (with some difficulty) by doing
	a kill(0,n), which doesn't actually do anything to the process
	(as far as I can tell), but it does return different values in
	errno for no-such-process and for wrong-uid ...  So far, I
	haven't tried to solve the problem on BSD, but the above remark
	implies that my SysV code won't work."

Your code will work.  BSD kill(2) guarantees that validity checking
happens in this order: first that the signal number is valid (and 0
is); next that the target process exists; next that you're allowed to
send the signal; next (other irrelevancies).  Thus, kill(pid,0) will
always return errno==ESRCH if pid doesn't exist.

  -=- Andrew Klossner   (decvax!tektronix!tekecs!andrew)       [UUCP]
                        (andrew%tekecs.tek.com@relay.cs.net)   [ARPA]

bak@csd_v.UUCP (Bruce) (12/11/87)

In article <429@minya.UUCP>, jc@minya.UUCP (John Chambers) writes:
> Is there a universal way that will work on any Unix to write a function
> 	isprocess(n)
> which returns TRUE if process n is alive, and FALSE if it isn't alive?
> 
> Note that I have said nothing about the relationship of process n (if it
> exists) to the process that is asking.  They might or might not be related.
> They might or might not have the same uid and gid.  I don't want to kill
> the process (or even upset it in any way).  I just want to know if it is
> alive.
> 

This solution is a little awkward but will definitely work.

Open a read-only pipe to the "ps -ef" command ( "-al" on BSD I believe, anyway
there are your #ifdefs ) and read the output searching the PID field for the
process of interest to you.  

I have a routine (from Kernighan and Pike) called zap which matches any string
in the line and then does a kill -9 to the pid, thereby allowing me to kill
processes mneumonically rather than PID.  Thus

	$ tail -f abc &
	9803
	.
	.
	many screenfulls of junk later
	.
	$ zap abc
     bak  1632  1354  0 19:51:13 cons2    0:58 tail -f ggg ? n   
     bak  1648  1354  0 19:51:13 cons2    0:58 tail -f abc ? y
	$
	ksh: 1648 Killed


The same idea is applicable to just looking at the PID field for your case.
Of course ps is not the quickest command to execute and if there are a lot
of processes running quite a bit of winnowing has to be done.  But if no
better solutions come along, this will do the job and is highly portable.
One other thing it will absolutely be transparent ot the running process
on all flavors of unix.
-- 
Bruce Kern                                      | uunet!swlabs!csd_v!bak
Computer Systems Design                         | 1-203-270-0399
29 High Rock Rd., Sandy Hook, Ct. 06482         | This space for rent.

ado@elsie.UUCP (Arthur David Olson) (12/11/87)

# Is there a universal way that will work on any Unix to write a function
# 	isprocess(n)
# which returns TRUE if process n is alive, and FALSE if it isn't alive?

echo Here's source for a command we've found useful here at elsie.

: To unbundle, sh this file
echo 'adopt.1' 1>&2
cat >'adopt.1' <<'End of adopt.1'
.LC @(#)adopt.1	1.1
.TH ADOPT 1E \*(eH
.SH NAME
adopt \- wait for process
.SH SYNOPSIS
.B adopt
[
.B \-v
] [ processid ... ]
.= adopt
.SH DESCRIPTION
.I Adopt
waits for completion of the process(es) identified by the ID number(s)
given on the command line.
It differs from
.IR wait (1),
which can only be used to wait for completion of a shell's own child processes.
.PP
This option is available:
.TP
.B \-v
Warn about processes that are not running when
.I adopt
begins execution.
End of adopt.1
echo 'adopt.c' 1>&2
cat >'adopt.c' <<'End of adopt.c'
#

#include "stdio.h"

#if !defined lint && !defined NOID
static char	sccsid[] = "@(#)adopt.c	1.2";
#endif /* !defined lint && !defined NOID */

#include "errno.h"
#include "ctype.h"

#ifndef SLEEPTIME
#define SLEEPTIME	5
#endif /* !SLEEPTIME */

extern int	errno;
extern int	optind;

static
exists(s)
char *	s;
{
	char *	cp;
	int	pid;

	if (s == NULL || *s == '\0')
		return -1;
	for (cp = s; *cp != '\0'; ++cp)
		if (!isascii(*cp) || !isdigit(*cp))
			return -1;
	if (sscanf(s, "%d", &pid) != 1 || pid < 0)
		return -1;
	return kill(pid, 0) == 0 || errno != ESRCH;
}

main(argc, argv)
int	argc;
char *	argv[];
{
	int	vflag;
	int	i;
	int	c;
	int	result;
	int	ok;

	vflag = 0;
	while ((c = getopt(argc, argv, "v")) == 'v')
		vflag = 1;
	if (c != EOF ||
		optind == (argc - 1) && strcmp(argv[optind], "=") == 0) {
			(void) fprintf(stderr,
				"%s: usage is %s [-v] processid ...\n",
				argv[0], argv[0]);
			return 1;
	}
	/*
	** Initial checks.
	*/
	ok = 1;
	for (i = optind; c != EOF || i < argc; ++i) {
		result = exists(argv[i]);
		if (result < 0) {
			(void) fprintf(stderr, "%s: wild argument '%s'\n",
				argv[0], argv[i]);
			return 1;
		}
		if (vflag && result != 1) {
			(void) fprintf(stderr,
				"%s: process %s does not exist\n",
				argv[0], argv[i]);
			ok = 0;
		}
	}
	/*
	** Wait loop.
	*/
	for (i = optind; i < argc; ++i)
		while (exists(argv[i]) == 1)
			(void) sleep(SLEEPTIME);
	return ok ? 0 : 1;
}
End of adopt.c
exit
-- 
ado@vax2.nlm.nih.gov		ADO, VAX, and NIH are Ampex and DEC trademarks

rjd@occrsh.ATT.COM (12/12/87)

> Is there a universal way that will work on any Unix to write a function
> 	isprocess(n)
> which returns TRUE if process n is alive, and FALSE if it isn't alive?
> 
> Note that I have said nothing about the relationship of process n (if it
> exists) to the process that is asking.  They might or might not be related.
> They might or might not have the same uid and gid.  I don't want to kill
> the process (or even upset it in any way).  I just want to know if it is
> alive.

  I don't have the base note for this, just the above.  If you have the
process number (such as saving it when it went into background) either
(in shell) a ps -p <process number> will give you a status code, or
(in C) kill(0,<processnumber>) will also give you a status code.
  If you don't have a process number, it gets a little more difficult.

Randy

pdg@ihdev.ATT.COM (Joe Isuzu) (12/17/87)

All of these answers about kill(0,procid) to probe are almost correct.
Various flavours of UNIX will return success for a probe of a zombie
(sys Vr0, BSD, amdahl UTS to name a few), while others (SysVrX (X>=2))
will return ESRCH.  I'm not sure how important this is, but someone is
sure to get caught by this sometime.

-- 

Paul Guthrie		Zippy the Pinhead - Zen for the American masses
ihnp4!ihdev!pdg				    -- me.

rml@hpfcdc.HP.COM (Bob Lenk) (12/18/87)

> int
> isprocess(n)
> 	int n;
> {
> 	extern int errno;
> 
> 	return (kill(n,0) == 0 || errno != ESRCH);
> }

As several people have pointed out, this approach works on System V and
recent BSD systems.  One important note is that the semantics are not
identical on those systems.  If the process in question is a zombie,
System V will tell you it exists while BSD will tell you it doesn't.

A couple of other points:  Older systems (eg. V7) don't support signal 0.
Systems meeting certain levels of security won't permit this sort of thing
in any form.

		Bob Lenk
		{ihnp4, hplabs}!hpfcla!rml