spawn(), spawnp() — Spawn a new process

Standards

Standards / Extensions C or C++ Dependencies
POSIX.4b
z/OS® UNIX
both  

Format

#define _POSIX_SOURCE
#include <spawn.h>

pid_t spawn(const char *path,
            const int fd_count,
            const int fd_map[],
            const struct inheritance *inherit,
            const char *argv[],
            const char *envp[]);

pid_t spawnp(const char *file,
             const int fd_count,
             const int fd_map[],
             const struct inheritance *inherit,
             const char *argv[],
             const char *envp[]);

General description

The spawn() and spawnp() functions create a new process from the specified process image. spawn() and spawnp() create the new process image from a regular executable file called the new process image file.

To execute a C program as a result of this call, enter the function call as follows:
         int main (int argc, char *argv[]);
Where argc is the argument count and argv is an array of character pointers to the arguments themselves. In addition, the following variable:
          extern char **environ;
is initialized as a pointer to an array of character pointers to the environment strings. The argv and environ arrays are each terminated by a NULL pointer. The NULL pointer terminating the argv array is not counted in argc.
Supported parameters are:
Parameter
Description
path
Path name used by spawn() that identifies the new process image file to execute.
file
Used by spawnp() to construct path name that identifies the new process image file. If the file parameter contains a slash character, spawnp() uses the file parameter as a path name for the new process image file. Otherwise, spawnp() obtains the path prefix for this file by a search of the directories passed as the environment variable PATH.
fd_count
Specifies the number of file descriptors the child process inherits. It may take values from zero to OPEN_MAX. Except for those file descriptors designated by SPAWN_FDCLOSED, each of the child's file descriptors, x, in the range zero to fd_count-1 inherits descriptor fd_map[x] from the parent process.

The files from fd_count through OPEN_MAX are closed in the child process, as are any elements of fd_map designated as SPAWN_FDCLOSED.

fd_map
If the fd_map parameter is NULL, fd_count and fd_map are ignored. All file descriptors except those with the FD_CLOEXEC or FD_CLOFORK attribute are inherited without reordering. File descriptors with the FD_CLOEXEC or FD_CLOFORK attribute are closed under simple inheritance.

For those file descriptors that remain open, all other attributes of the associated file descriptor object and open file description remain unchanged by this operation.

Directory streams open in the calling process are closed in the new process image.

If an element of fd_map refers to an invalid file descriptor, then the (EBADF) spawn() or spawnp() posts the error status.

The FD_CLOEXEC and FD_CLOFORK file descriptor attributes are never inherited.

The FD_CLOEXEC and FD_CLOFORK file descriptor attributes have no effect on inheritance when the fd_map parameter is not NULL.

Note: For XTI endpoints, fd_map must not map to a number greater than 65535 in the child process.
inherit
The name of a data area that contains the inheritance structure.
The 'struct inheritance' is defined as follows:
struct inheritance {
short flags; --Flags
pid_t pgroup; --Process group
sigset_t sigmask; --Signal mask 
sigset_t sigdefault; --Signals set to SIG_DFL 
int ctlttyfd; --Cntl tty FD for tcsetpgrp() 
}
The inherit.flags effect spawn() and spawnp() as follows:
SPAWN_SETGROUP
If the SPAWN_SETGROUP flag is set in inherit.flags, then the child's process group is as specified in inherit.pgroup.

If the SPAWN_SETGROUP flag is set in inherit.flags and inherit.prgroup is set to SPAWN_NEWPGROUP, then the child is in a new process group with a process group ID equal to its process ID.

If the SPAWN_SETGROUP flag is not set in inherit.flags, the new child process inherits the parent's process group ID.

SPAWN_SETSIGMASK
If the SPAWN_SETSIGMASK flag is set in inherit.flags, the child process initially has the signal mask specified in inherit.sigmask.
SPAWN_SETSIGDEF
If the SPAWN_SETSIGDEF flag is set in inherit.flags, the signals specified in inherit.sigdefault are set to their default actions in the child process. Signals set to the default action in the parent process, are set to the default action in the new process.

Signals set to be caught by the calling process are set to the default action in the child process.

Signals set to be ignored by the calling process are set to be ignored by the new process, unless otherwise specified by the SPAWN_SETSIGDEF flag being set in inherit.flags and the signal being indicated in inherit.sigdefault.

SPAWN_SETTCPGRP
If the SPAWN_SETTCPGRP flag is set in inherit.flags, the file descriptor specified in inherit.ctlttyfd is used to set the controlling terminal file descriptor (tcsetpgrp()) for the child's foreground process group. The child's foreground process group is inherited from the parent, unless the SPAWN_SETGROUP flag in inherit.flags is set, indicating that the value specified in inherit.pgroup is to be used to determine the child's process group.
SPAWN_PROCESS_INITTAB
If this flag is set, spawn attempts to read the /etc/inittab file and process the entries found there. This processing involves the spawning of child shell processes to run each of the commands identified in the file. Only the SPAWN_SETSIGMASK flag can be set in combination with this flag. All other flags will be ignored. Use of this flag implies that only file descriptors 0, 1, and 2 will be initially opened in the child process. File descriptor 0 will be initially opened as /dev/null, while file descriptors 1 and 2 will initially opened as /etc/log. The fd_count and fd_map parameters will be ignored. This flag is currently restricted to the /usr/sbin/init process. See z/OS UNIX System Services Planning for more information on the /etc/inittab support.
argv
The value in the first element of argv should point to a file name that is associated with the process being started by the spawn() or spawnp() operation.

The number of bytes available for the new process's combined argument and environment lists is ARG_MAX.

envp
The value envp contains the list of environmental variables that is to be passed to the specified program.

If the set-user-ID mode bit of the new process image file is set, the effective user ID of the new process image is set to the owner id of the new process image file. Similarly, if the set-group-ID mode bit of the new process image file is set, the effective group ID of the new process image is set to the group id of the new process image file. The real user ID, real group ID, and supplementary group IDs of the new process image remain the same as those of the calling process image. The effective user ID and effective group ID of the new process image are saved (as the saved set-user-ID and the saved set-group-ID) for use by the setuid() function.

The new process image inherits the following attributes from the calling process image:
  • Process group ID (unless the SPAWN_SETGROUP flag is set in inherit.flags)
  • Session membership
  • Real user ID
  • Real group ID
  • Supplementary group IDs
  • Priority
  • Current working directory
  • Root directory
  • File creation mask
  • Signal mask (unless the SPAWN_SETSIGMASK flag is set in inherit.flags)
  • Signal actions specified as default (SIG_DFL)
  • Signal actions specified as ignore (SIG_IGN) (except as modified by inherit.sigdefault and the SPAWN_SETSIGDEF flag set in inherit.flags)
The following are differences between the parent process and the child process:
  • Signals set to be caught by the calling process are set to the default action (SIG_DFL).
  • The process and system utilization times for the child are set to zero.
  • Any file locks previously set by the parent are not inherited by the child.
  • The child process has no alarms set.
  • The child process has no interval timers set.
  • The child has no pending signals.
  • Memory mappings established by the parent are not inherited by the child.

If the process image was read from a writable file system, then upon successful completion, the spawn() or spawnp() function mark for update the st_atime field of the new process image file.

If the spawn() or spawnp() function is successful, the new child process image file is opened, with all the effects of the open() function.

Special behavior for z/OS UNIX Services:
Note: If an application spawns a shell command or utility that performs terminal I/O, the command may fail due to the fact that the shell file descriptors are not initialized. The Shell file descriptors must be defined. An example of how these can be defined in a C application are as follows:
stdin = fopen("/tmp/sys.stdin","r");
stdout = fopen("/tmp/sys.stdout","w");
stderr = fopen("/tmp/sys.stderr","w");

Aspects of spawn processing are controlled by environment variables. The environment variables that affect spawn processing are the ones that are passed into the spawn syscall and not the environment variables of the calling process. The environment variables of the calling process do not affect spawn processing unless they are the same as those that are passed in envp.

The _BPXK_JOBLOG environment variable can be used to specify that WTO messages are to be written to an open HFS job log file. The following are the allowable values:
Value
Description
nn
Job log messages are to be written to open file descriptor nn.
STDERR
Job log messages are to be written to the standard error file descriptor, 2.
None
Job log messages are not to be written. This is the default.

The file that is used to capture messages can be changed at any time by calling the oe_env_np service (BPX1ENV) and specifying _BPXK_JOBLOG with a different file descriptor.

Message capturing is turned off if the specified file descriptor is marked for close on a fork or exec.

Message capturing is process-related. All threads under a given process share the same job log file. Message capturing may be initiated by any thread under that process.

Multiple processes in a single address space can each have different files active as the JOBLOG file; some or all of them can share the same file; and some processes can have message capturing active while others do not.

Only files that can be represented by file descriptors may be used as job log files; MVS™ data sets are not supported.

Message capturing will be propagated on a fork() or spawn(). In the case where a file descriptor was specified, the physical file must be the same for message capturing to continue in the forked or spawned process. If STDERR was specified, the file descriptor may be re-mapped to a different physical file.

Message capturing may be overridden on exec() or spawn() by specifying the _BPXK_JOBLOG environment variable as a parameter to the exec() or spawn().

Message capturing will only work in forked (BPXAS) address spaces.
Note: This is not true joblog support, messages that would normally go to the JESYSMSG data set are captured, but messages that go to JESMSGLG are not captured.

For more information on the use of environment variables, see z/OS UNIX System Services Programming: Assembler Callable Services Reference.

Security information from the parent's address space is propagated to the child's address space, unless the _BPX_USERID environment variable specifies otherwise. As a result, the child has a security environment equivalent to that of the parent.

The TASKLIB, STEPLIB, or JOBLIB DD data set allocations that are active for the current task are propagated to the child's address space, unless the STEPLIB environment variable specifies otherwise. This causes the child address space to have the same exact MVS program search order as the calling parent task.

The accounting information of the parent's address space is propagated to the child's address space. See z/OS UNIX System Services Planning.

The jobname of the parent is propagated to the child and appended with a numeric value in the range of 1-9 if the jobname is 7 characters or less. If the jobname is 8 characters, then it is propagated as-is. When a jobname is appended with a numeric value, the count wraps back to 1 when it exceeds 9.

If the calling parent task is in a WLM enclave, the child is joined to the same WLM enclave. This allows WLM to manage the parent and child as one "business unit of work" entity for system accounting and management purposes.

To allow the caller to control whether the spawned child process runs in a separate address space from the parent address space or in the same address space, the spawn service allows for the specification of the _BPX_SHAREAS environment variable. The following are the accepted values for the _BPX_SHAREAS environment variable, and the actions taken for each value:
  1. _BPX_SHAREAS=YES - Indicates that the child process that is to be created is to run in the same address space as the parent. In the following circumstances, the _BPX_SHAREAS=YES value cannot be honored, and the child process is created in its own address space:
    • If the program to be run is a set-user-ID or set-group-ID program that would cause the effective user-ID or group-ID of the child process to be different from that of the parent process.
    • If the program to be run is an APF-authorized HFS or MVS program and the caller is not running APF authorized.
    • If the program to be run is an unauthorized HFS or MVS program and the caller is running APF authorized.
    • If the specified file name represents an external link or a sticky bit file. However, if the program that is to be run is a shell script and _BPX_SPAWN_SCRIPT=YES is set, the process runs in the same address space. _BPX_SPAWN_SCRIPT only has an effect while running in the z/OS shell (/bin/sh... NOT /bin/tcsh).
    • If the address space of the parent lacks the necessary resources to create another process within the address space.

    Note that only one local spawned process per TSO address space is supported at a given time. This is done to reduce conflict among multiple shells running in the same address space.

  2. _BPX_SHAREAS=MUST - Indicates that the child process that is to be created must run in the same address space as the parent, or the spawn request will fail. In the following circumstances, the _BPX_SHAREAS=MUST value cannot be honored, and the spawn invocation fails:
    • If the program to be run is a set-user-ID or set-group-ID program that would cause the effective user ID or group ID of the child process to be different from that of the parent process.
    • If the program to be run is an APF-authorized HFS or MVS program and the caller is not running APF authorized.
    • If the program to be run is an unauthorized HFS or MVS program and the caller is running APF authorized.
    • If the address space of the parent lacks the necessary resources to create another process within the address space.
  3. _BPX_SHAREAS=REUSE - Indicates that the child process to be created is to run in the same address space as the parent; also, that it will be created as a medium-weight process. Specifying REUSE allows the caller to indicate that it wants to reuse the existing process structure for locally spawned processes.
    The same rules that apply to the creation of a local spawn process apply to the specification of a local spawn medium-weight process. In addition, in the following circumstances, the _BPX_SHAREAS=REUSE value cannot be honored, and the child process will be created as a non-medium weight local spawn process:
    • If PTRACE is active for the process.
    • If the program to execute is a REXX exec.

    For performance reasons, the STEPLIB that is specified for each medium-weight process that is created for the address space should be the same.

  4. _BPX_SHAREAS=NO - Indicates that the child process that is to be created is to run in a separate address space from the address space of the parent. This is the default behavior for the spawn service if the _BPX_SHAREAS environment variable is not specified, or if it contains an unsupported value.

If you specify the _BPX_USERID environment variable, then spawn() creates the new address space and image with the specified userid's identity. The invoker of spawn() must be authorized to change MVS identity. The resulting spawn() image will emerge as if a program had done a fork(), setgid(), initgroups(), setuid(), and exec.

The value of _BPX_USERID can be any 1-to-8-character XPG4 compliant username. If you specify both _BPX_USERID and _BPX_SHAREAS, then spawn() ignores _BPX_SHAREAS, and creates a new address space with the new identity.

If the caller of the spawn() function is the z/OS UNIX shell (i.e /bin/sh), then the setting of the _BPX_SPAWN_SCRIPT= environment variable to YES is recommended. The setting of this variable to YES provides a more efficient mechanism to invoke z/OS UNIX shell scripts.

To support the creation and propagation of a STEPLIB environment to the new process image, spawn() and spawnp() allow for the specification of a STEPLIB environment variable. The following are the accepted values for the STEPLIB environment variable and the actions taken for each:
  • STEPLIB=NONE. No Steplib DD is to be created for the new process image.
  • STEPLIB=CURRENT. The TASKLIB, STEPLIB or JOBLIB DD data set allocations that are active for the calling task at the time of the call to spawn() and spawnp() are propagated to the new process image, if found to be cataloged. Uncataloged data sets are not propagated to the new process image.
  • STEPLIB=Dsn1:Dsn2:,...DsnN. The specified data sets, Dsn1:Dsn2:...DsnN, are built into a STEPLIB DD in the new process image.
    Note: The actual name of the DD is not STEPLIB, but is a system-generated name that has the same effect as a STEPLIB DD.
The data sets are concatenated in the order specified. The specified data sets must follow standard MVS data set naming conventions. Data sets found to be in violation of this standard are ignored. If the data sets do follow the standard, but:
  • The caller does not have the proper security access to a data set.
  • A data set is uncataloged or is not in load library format.
then the data set is ignored. Because the data sets in error are ignored, the executable file may run without the proper STEPLIB environment. If a data set is in error due to improper security access a X'913' abend is generated. The dump for this abend can be suppressed by your installation.

If the STEPLIB environment variable is not specified, spawn() and spawnp() default behavior is the same as if STEPLIB=CURRENT were specified.

If the program to be invoked is a set-user-ID or set-group-ID file and the user-ID or group-ID of the file is different from that of the current process image, then the data sets to be built into the STEPLIB environment for the new process image must be found in the system sanction list for set-user-id and set-group-id programs. Only those data sets that are found in the sanction list are built into the STEPLIB environment for the new process image. For detailed information regarding the sanction list, and for information on STEPLIB performance considerations, see z/OS UNIX System Services Planning.

Notes:
  1. A prior loaded copy of an HFS program in the same address space is reused under the same circumstances that apply to the reuse of a prior loaded MVS unauthorized program from an unauthorized library by the MVS XCTL service with the following exceptions:
    • If the calling process is in Ptrace debug mode, a prior loaded copy is not reused.
    • If the calling process is not in Ptrace debug mode, but the only prior loaded usable copy found of the HFS program is in storage modifiable by the caller, the prior copy is not reused.
  2. If the specified file name represents an external link or a sticky bit file, the program is loaded from the caller's MVS load library search order. For an external link, the external name is only used if the name is eight characters or less, otherwise the caller receives an error from the loadhfs service. For a sticky bit program, the file name is used if it is eight characters or less. Otherwise, the program is loaded from the HFS, and the following restriction exists for sticky bit programs that have the set-user-ID or set-group-ID attribute:

    If the program is found in the MVS program search order, the MVS program name must have a BPX.STICKYSUG.program_name resource profile defined in the RACF® FACILITY class. See z/OS UNIX System Services Planning for details on defining the resource profile. Failure to follow this restriction will cause the abend EC6 with code xxxxE055.

  3. If the calling task is in a WLM enclave, the resulting task in the new process image is joined to the same WLM enclave. This allows WLM to manage the old and new process images as one "business unit of work" entity for system accounting and management purposes.
Note: If you are expecting this function to take advantage of the z/OS UNIX magic number support, the Language Environment® runtime option to POSIX(ON) must have been set when the process was initialized. Attempting to use magic number support with a process initialized with POSIX(OFF) may produce undesirable effects. See z/OS UNIX System Services Planning and z/OS UNIX System Services User's Guide for details and uses of the z/OS UNIX magic number.

Returned value

If successful, spawn() and spawnp() return the value of the process ID of the child process to the parent process.

If unsuccessful, spawn() and spawnp() return -1, no child process is created, and they set errno to one of the following values:
Error Code
Description
E2BIG
The number of bytes used by the argument and environment list of the new process image is greater than the system-imposed limit of ARG_MAX bytes.
EACCES
Search permission is denied for a directory in the path of the new process image file or the new process image file denies execution permission, or the new process image file is not a regular file and the implementation does not support execution of files of its type.
EAGAIN
The system lacked the necessary resources to create another process or the system-imposed limit on the total number of processes or UIDs under execution by a single user would be exceeded.
EBADF
An entry in the fd_map array refers to an invalid file descriptor or the controlling terminal file descriptor specified in the inherit.ctlttyfd is not valid.
EFAULT
The system detected an invalid address in attempting to use a parameter of the call.
EINVAL
One or more of the following conditions were detected:
  • The username that was specified on the _BPX_USERID environment variable has an incorrect length.
  • An attribute that was specified in the inheritance structure (BPXYINHE) is not valid or contains an unsupported value.
  • The version number that was specified for the inheritance structure (BPXYINHE) is not valid.
  • The inheritance structure length that was specified by the Inherit_area_len parameter or within the inheritance structure does not contain a length that is appropriate for the BPXYINHE version.
  • The process group ID that was specified in the inheritance structure is less than zero or has some other unsupported value.

The following reason codes can accompany the return code: JROK, JRUserNameLenError, JRJsRacXtr, JRInheUserid, JRInheRegion, JRInheCPUTime, JRInheDynamber, JRInheAccountData, JRInheCWD, JRInheSetPgrp, JRInheVersion, and JRInheLength.

ELOOP
A loop exists in symbolic links encountered during resolution file argument. This error is issued if more than 8 symbolic links are detected in the resolution of file name.
EMVSERR
An MVS internal error has occurred. This may indicate a problem with security permissions for the user calling spawn() or spawnp().
EMVSSAF2ERR
The executable file is a set-user-ID or set-group-ID file and the file owner's UID or GID is not defined to the Security Authorization Facility (SAF), or _BPX_USERID was specified and the specified username was not defined to SAF with a z/OS UNIX segment.
ENAMETOOLONG
The length of the path or file arguments, or an element of the environment variable PATH prefixed to file exceeds PATH_MAX, or a path name component is longer than NAME_MAX and {_POSIX_NO_TRUNC} is in effect for that file.
ENOENT
One or more components of the path name of the new process image file do not exist or the path or file argument is empty.
ENOEXEC
The new process image file has the appropriate access permission but is not in the proper format.
Note: Reason codes further qualify the errno. For most of the reason codes, see z/OS UNIX System Services Messages and Codes.
For ENOEXEC, the reason codes are:
Reason Code Explanation
X'xxxx0C27' The target HFS file is not in the correct format to be an executable file.
X'xxxx0C31' The target HFS file is built at a level that is higher than that supported by the running system.
ENOMEM
The new process requires more memory than is permitted by the hardware or the operating system.
ENOTDIR
A component of the path prefix of the new process image file is not a directory.
ENOTTY
The tcsetpgrp() failed for the specified controlling terminal file descriptor in inherit.ctlttyfd. The failure occurred because the calling process does not have a controlling terminal, or the specified file descriptor is not associated with the controlling terminal, or the controlling terminal is no longer associated with the session of the calling process.
EPERM
The spawn failed for one of the following reasons:
  • The spawned process is not a process group leader.
  • The _BPX_USERID environment variable was specified, but the invoker does not have appropriate privileges to change the MVS identity.
  • The invoker does not have the appropriate privileges to change one or more of the attributes specified in the inheritance structure (BPXYINHE).

The following reason codes can accompany the return code: JROK, JRNoChangeIdentity, JRInheUserid, JRInheRegion, JRInheCPUTime, JRInheUmask, and JRInheCWD.

ESRCH
The process group ID specified in inherit.pgroup is not that of a process group in the session of the calling process.

Example

The following is an example of a parent program that uses spawn to create a child process.
#define _XOPEN_SOURCE_EXTENDED 1
#include <unistd.h>
#include <spawn.h>
#include <stdio.h>
#include <errno.h>
#include <sys/types.h>

/* This program uses spawn instead of fork/exec to create a child
 * process and uses unnamed pipes to allow the parent and child to
 * exchange communication.
 */


void main(int argc, char *argv[])  {
	pid_t child;
	int fd_count, fd_map[10];
	struct inheritance inherit;
	const char *c_argv[10], *c_envp[10];
	char buf[256];
	int nbytes;

	int c_stdin[2], c_stdout[2], c_stderr[2];  /* Pipes for child
        * communication */

	/* Create pipes to communicate with child via stdin/stdout/stderr */
	if(pipe(c_stdin)  ||
	   pipe(c_stdout) ||
	   pipe(c_stderr) ) {
		perror("Bad pipe");
                exit(-1);
                }

	/* Set up file descriptor map for child process */
	fd_map[0]=dup(c_stdin[0]);  /* child stdin is read end of pipe */
	fd_map[1]=dup(c_stdout[1]); /* child stdout is write end of pipe */
	fd_map[2]=dup(c_stderr[1]); /* child stderr is write end of pipe */
	fd_count=3;

	/* Close unused end of pipes for the parent */
        close(c_stdin[0]); close(c_stdout[1]); close(c_stderr[1]);

	/* Build the argument structure for child arguments.
        *  [0] is the program name */
	c_argv[0]="spawnc";
	c_argv[1]="arg1"; c_argv[2]="arg2"; c_argv[3]=NULL;

	/* Build the environment structure which defines the child's
        * environment variables */
	c_envp[0]="TEST_ENV=YES"; c_envp[1]="BPX_SHAREAS=NO"; c_envp[2]=NULL;
	
	/* Spawn the child process */
	child=spawnp("spawnc", fd_count, fd_map, &inherit, c_argv, c_envp);
	if(child==-1) {
		perror("Error on spawn");
		exit(-1);
		}
	else printf("Spawned %i\n", child);

	/* Test interaction with the child process */
	printf("parent: Asking child, \"what are you doing?\\n\"\n");
	strcpy(buf, "child from parent: what are you doing?\n");
	if(write(c_stdin[1], buf, sizeof(buf))==-1)  {
		perror("write stdout");
		exit(-1);
		}

	memset(buf, 0, 255);  /* Just zeroing out the buffer */
	printf("parent: reading from child now\n");
	if((nbytes=read(c_stdout[0], buf, 255))==-1) {
		perror("read error:");
		exit(-1);
		}
	printf("parent: child says, \"%s\"\n", buf);
	
	/* Cleanup pipes before exiting */
	close(c_stdin[1]); close(c_stdout[0]); close(c_stderr[0]);

 	exit(0);
}

Example

The following is an example of a child program used by spawn.
#include <stdlib.h>
#include <stdio.h>

/* This is a sample child program used by spawn.  This program will
 * work stand-alone as well as from spawn or fork/exec. */

extern char ** environ; /* External used to access the environment
			   directly instead of using getenv */

void main(int argc, char *argv[]) {

	char *e, **env=environ;  /* Used to step through the environment
				  * to write out to file. */
	char buf[256]={0};
	FILE *fp=fopen("spawntest.out","w");
 	int i;

	/* Print out the environment variables */
	i=0;
	fprintf(fp, "Environment:\n");
	while(e=env[i++])  fprintf(fp, "%s\n", e);
	fprintf(fp, "\n\n");

	/* Just to prove getenv works */
	fprintf(fp, "TEST_ENV envvar = %s", getenv("TEST_ENV"));

	/* Print out the command line arguments */
	i=0;
	fprintf(fp,"Args:\n");
	while(e=argv[i++]) fprintf(fp,"%s\n", e);
	fprintf(fp, "\n\n");
	
	/* Print out what was sent on stdin */
	fprintf(fp, "Child/parent\n");
	if(!gets(buf)) {
		ferror(stdin);
		exit(-1);
		}
	fprintf(fp, "child from parent: %i bytes,[%s]\n", strlen(buf), buf);

	/* Send something to stdout */	
	printf("nothing");

	fclose(fp);
	exit(0);
}

Related information