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