[net.lang.c] exit

zarth@drutx.UUCP (CovartDL) (04/17/85)

I have been trying lately to use exit() in a child process and then have
the parent recieve the exit code. This is so that if the exec fails the
parent will not continue processing(or know to do error processing). The
following is part of the code I am using. I would appreciate comments and/or
suggestions. The printf statement shows rtn_code as 3 when the exec fails
and therefore the error and cleanup code is never executed.

# include <stdio.h>

int pid,wid;
unsigned int rtn_code;

if((pid = fork()) == NULL) {
   perror();
   return(0);
   }
else {
   if(pid == 0) {
      execl("cmd","cmd","arg",0);
      perror();
      exit(16);
      }
   else {
      while((wid = wait((unsigned int *)rtn_code)) != pid);
      printf("%u\n",rtn_code);
      if(rtn_code == 16) {
	 /* error processing and cleanup */
	 return(0);
	 }
      else
	 return(1);
      }
   }


Post to the net or mail to me(drutx!zarth) whichever seems appropriate.
Thanks in advance.

				Zarth Arn
				(alias Dave Coavrt)
				1-303-538-4284

zarth@drutx.UUCP (CovartDL) (04/19/85)

Thanks for all the responses to my previous net news article.
My code contained the line:
      if((pid = fork()) == -1)
when I typed it in I got it wrong. Everyone caught that.

Also, the agrument to wait almost everyone caught.
was:
      while((wid == wait((unsigned int*)rtn_code)) != pid);
should be:
      while((wid == wait(&rtn_code)) != pid);

Several people expressed intreset into why I used a while statement.
This was done because if someone else invokes this procedure from another
procedure which forked of a child but didn't wait for it, that childs
termination could cause this wait to wake up.

Thanks again for all the help I have my program working fine now.
Posted this so others can benifiet too.

				Zarth Arn

gwyn@brl-tgr.ARPA (Doug Gwyn <gwyn>) (04/20/85)

> if((pid = fork()) == NULL) {
Failure is indicated by -1 not by NULL (which is 0).
>    perror();
perror() requires a (char *) argument to be printed.

>       execl("cmd","cmd","arg",0);
The last argument should be (char *)0.
>       perror();
(See previous perror note; also, exec failure is most often
handled in the parent branch of the fork.)
>       exit(16);
No!  exit() flushes the stdio buffers, but does not affect
the same buffered data in the parent branch.  Use _exit(127)
instead.  (_exit() is like exit() without any cleanup actions.)

>       while((wid = wait((unsigned int *)rtn_code)) != pid);
Here is the main problem; you need to pass the ADDRESS of
rtn_code to wait().  This is &rtn_code, not what you have
written (which asks for the CONTENTS of rtn_code to be
interpreted as an address).  As a matter of style, I suggest
also that the null statement ; be written on a separate line.

>       if(rtn_code == 16) {
ANY nonzero rtn_code should be treated as unsuccessful
execution of the child.  The low 8 bits of rtn_code are
a general class of termination (0 for normal exit) and
the next lowest 8 bits are the returned exit status code
(for normal exit; they encode other things for other
classes of termination).  Only a normal exit with 0 exit
status code should be considered successful.

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

This probably belongs in net.unix, but . . .

Anyway, the reason you are getting strange exit stati is that your
code is wrong.  "wait" wants a pointer, not a value.

If you are running 4BSD, there is a nice header file (in different
places in 4.1 and 4.2, grr) that defines exactly what wait() fills
in; for other systems, you just have to use an "int *" and pick out
the fields yourself.  The following code forks and picks up the
return status, handing errors that might crop up too:

#include <sys/types.h>
#include <sys/wait.h>		/* <wait.h> in 4.1 */

f()
{
	register int pid, w;
	union wait status;	/* wait gives us back one of these, */
				/* but can use "int" if you have to */

	if ((pid = fork()) < 0) {
		/* probably out of processes */
		/* try to do something about it here */
		return (-1);
	}
	if (pid == 0) {		/* child */
		/* do exec()y stuff here */
		_exit(16);	/* exit() flushes stdio buffers,
				   which can print stuff twice */
		/* NOTREACHED */
	}
	while ((w = wait (&status)) != pid && w > 0)
		;
	if (w <= 0) {		/* catastrophe? */
		/* probably a program bug */
		/* gripe, perhaps, here */
		return (-1);
	}
	/*
	 * Now have status.w_retcode, which is exit code;
	 * status.w_termsig, which is signal (if any)
	 * that terminated proc; and status.w_coredump,
	 * which is true iff the process left us a core
	 * file.
	 */
	/*
	 * Alternatively, "status" can be an integer, in
	 * which case the low 7 bits are the signal, the
	 * eight bit the core-dump flag, and the next eight
	 * bits the exit code.
	 */
	/* do something here based on exit code */
}

Note that if you are implementing a server which will be running as
root, the only reason fork() would fail is if the proc table is full,
so forks should be retried if necessary and practical.
-- 
In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 4251)
UUCP:	{seismo,allegra,brl-bmd}!umcp-cs!chris
CSNet:	chris@umcp-cs		ARPA:	chris@maryland

chris@umcp-cs.UUCP (Chris Torek) (02/12/86)

In article <1046@decwrl.DEC.COM> dyer@dec-vaxuum.UUCP (Jym Dyer) writes:
>> exit(0);
>
>   This isn't portable to VMS.  (-: Does anybody care about VMS,
>though? :-)  0 is an undefined status code in VMS!

I would hope that on VMS, exit(0) maps to status code 1 (success,
no error; it is possible on VMS to have failures without errors
and successes with errors), and that anything else maps to a status
that indicates an `unspecified error'.  VMS C should provide another
`exit'-like routine that actually just passes its argument on to
the termination system call.  Use of the *latter* routine would
be unportable, though preferred for VMS system programs.

(It might be feasible to have exit() map values from <sysexits.h>
to VMS status codes, I suppose.)
-- 
In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 1415)
UUCP:	seismo!umcp-cs!chris
CSNet:	chris@umcp-cs		ARPA:	chris@mimsy.umd.edu

minow@decvax.UUCP (Martin Minow) (02/13/86)

In article <3174@umcp-cs.UUCP>, Chris Torek (chris@umcp-cs.UUCP) writes:

>I would hope that on VMS, exit(0) maps to status code 1 (success,
>no error; it is possible on VMS to have failures without errors
>and successes with errors), and that anything else maps to a status
>that indicates an `unspecified error'.

Unfortunately, on VMS, status code 1 means "success", thus the
Unix exit(1) usage to indicate errors fails.

On VMS, there is a very large set of error/status codes -- giving unique
codes for each unique error.  The proper way to return a status code
is to specify its symbolic name; the compiler determines its value.

The following sequence is portable between Unix, VMS (Vax-C) and
Decus C implementations:

#ifdef	vms
#include		<ssdef.h>
#include		<stsdef.h>
/*
 * SS$_NORMAL is "normal completion", STS$M_INHIB_MSG supresses
 * printing a status message.
 * SS$_ABORT is the general abort status code.
 */
#define	IO_SUCCESS	(SS$_NORMAL | STS$M_INHIB_MSG)
#define	IO_ERROR	SS$_ABORT
#endif
/*
 * Note: IO_SUCCESS and IO_ERROR are defined in the Decus C stdio.h file
 */
#ifndef	IO_SUCCESS
#define	IO_SUCCESS	0
#endif
#ifndef	IO_ERROR
#define	IO_ERROR	1
#endif

...
	exit(IO_SUCCESS);	/* Normal exit	*/
	exit(IO_ERROR);		/* Error exit	*/

Martin Minow
decvax!minow

gwyn@brl-smoke.ARPA (Doug Gwyn ) (02/16/86)

In article <178@decvax.UUCP> minow@decvax.UUCP (Martin minow) writes:
>
> Unfortunately, on VMS, status code 1 means "success", thus the
> Unix exit(1) usage to indicate errors fails.

Therefore VMS has incorrectly implemented the exit() function.
Early Whitesmiths C systems tried to pull this switch, too.

VMS could very easily correctly implement exit() using something like:
	void exit( status ) /* agrees with the rest of the world */
		{
		extern void _vms_exit(); /* previously named "exit" */
		_vms_exit( !status );
		}
I get the impression that VMS C was implemented by people who did
not have much practical experience with C programming.

The fact is, correctly-written C applications from non-VMS systems
are most unlikely to be coded as you suggested "for portability";
they invariably return a hard-wired 0 status to indicate success.

Quoting from X3J11 section D.10.4.2: "Finally, control is returned
to the host environment.  If the value of `status' is zero, the status
returned is *successful termination*; otherwise an implementation-
defined form of the status *unsuccessful termination* is returned.

bjorn@dataioDataio.UUCP (Bjorn Benson) (02/17/86)

In article <3174@umcp-cs.UUCP> chris@umcp-cs.UUCP (Chris Torek) writes:
>>   This isn't portable to VMS.
>I would hope that on VMS, exit(0) maps to status code 1...

No such luck.  Here is what we use in exit():

	__UNIX__	__VMS__
Success	   0		   1
Failure	   1		0x10000002

Ugly but true under VMS with VAX-11 C.

			Bjorn Benson
			Software Engineer
			FutureNet - a Data I/O company

dyer@dec-vaxuum.UUCP (02/19/86)

Re: exit() on VMS_________________________________________________

> I get the impression that VMS C was implemented by people who
> did not have much practical experience with C programming.

    Bad impression, one that certainly does not follow from an
incompatible exit() function.  I work in the same building as
the VAX C people, and they are all brave and heroic, with IQs of
at least 170.  They all know what they're doing, too.
    I've had very few problems compiling and running Unix-written
programs with VAX C.  The exit() inconsistency is, after all,
quite minor.

> Quoting from X3J11 section D.10.4.2: "Finally, control is
> returned to the host environment.  If the value of `status' is
> zero, the status returned is *successful termination*; otherwise
> an implementation-defined form of the status *unsuccessful
> termination* is returned.

    This standard wasn't around when the VAX C exit() routine was
written, but I agree that the exit() routine should be changed
now that this behavior has been cast in ANSI concrete.
		<_Jym_>
P.S.:  I have no connection with the VAX C group outside of an ad-
miration for their bravery, heroism, and high IQs.  I also do not
presume to speak for DEC, only for myself.
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
::::'  ::  `::::             Jym Dyer             ::::'  ::  `::::
::'    ::    `::       Dracut, Massachusetts      ::'    ::    `::
::     ::     ::::::::::::::::::::::::::::::::::::::     ::     ::
::   .::::.   ::   DYER%VAXUUM.DEC@DECWRL.ARPA    ::   .::::.   ::
::..:' :: `:..::  {allegra|decvax|ihnp4|ucbvax}   ::..:' :: `:..::
::::.  ::  .:::: decwrl!dec-rhea!dec-vaxuum!dyer  ::::'  ::  `::::
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::

minow@decvax.UUCP (Martin Minow) (02/20/86)

First, for the record, I have no connection with the Ultrix
or Vax C groups (I work on DECtalk) and am offering only
my own opinions.

In a previous note, I pointed out that the Vax C developers
used exit() to return a VMS system status code to the parent
process.  Several people suggested that this is incorrect,
and doesn't conform to the Draft Standard.

The Vax C development predates the Draft Standard by about 5
years.  Decus C, which also made the same "mistake", was
first publicly distributed in 1978, so it, too, predates
the Draft Standard's implementation by a number of years.

I would imagine that the Vax C developers used Kernighan and
Ritchie for their language reference, and the Unix V6 manuals
for the library.  The description of exit is quite explicit:

  Exit closes all the process's files and notifies the
  parent process if it is exeucting a wait.  The low byte
  of r0 (resp. the argument to exit) is available as status
  to the parent process.

The manual page dates from 1973.

Whether exit() will change is not for me to say.  One possible
solution would be, say,

	exit(code) {
	    switch (code) {
	    case 0:	code = SS$_NORMAL;	break;
	    case 1:	code = SS$_ABORT;	break;
	    }
	    _exit(code);
	}

Exit codes provide an example where existing practice differs
on different operating systems.  The Draft Standard may change
before it is approved, and existing programs may have to change
to conform to the standard, once adapted.

Martin Minow
decvax!minow