/*
* Copyright (c) 2005-2006 Institute for System Programming
* Russian Academy of Sciences
* All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
* Portions of this text are reprinted and reproduced in electronic form
* from IEEE Std 1003.1, 2004 Edition, Standard for Information Technology
* -- Portable Operating System Interface (POSIX), The Open Group Base
* Specifications Issue 6, Copyright (C) 2001-2004 by the Institute of
* Electrical and Electronics Engineers, Inc and The Open Group. In the
* event of any discrepancy between this version and the original IEEE and
* The Open Group Standard, the original IEEE and The Open Group Standard
* is the referee document. The original Standard can be obtained online at
* http://www.opengroup.org/unix/online.html.
*/
#include "config/system_config.seh"
#include "process/process/process_config.h"
#include "process/pgroup/pgroup_config.h"
#include "process/process/process_model.seh"
#include "process/process/process_common.seh"
#include "process/fenv/fenv_model.seh"
#include "process/meta/user_model.seh"
#include "system/system/system_model.seh"
#include "fs/dir/dir_model.seh"
#include "fs/meta/access_model.seh"
#include "data/sys/wait_model.seh"
#include "data/stdlib_model.seh"
#include "locale/locale/locale_model.seh"
#pragma SEC subsystem process "process.process"
/*
The group of functions 'process.process' consists of:
_Exit [1]
__cxa_atexit [2]
__libc_start_main [1]
__register_atfork(GLIBC_2.3.2) [1]
_exit [1]
abort [1]
daemon [2]
execl [2]
execle [2]
execlp [2]
execv [2]
execve [2]
execvp [2]
exit [2]
fork [2]
forkpty [1]
pclose [2]
popen [2]
return_from_main_spec
system [2]
vfork [2]
wait [2]
wait4 [1]
waitpid [1]
*/
/********************************************************************/
/** Interface Functions **/
/********************************************************************/
/*
* common for exit group and return_from_main
*/
specification typedef struct ExitCall ExitCall = {};
ExitCall * create_ExitCall( CallContext context, IntT status )
{
return create( & type_ExitCall, context, status );
}
void onExit( CallContext context, IntT status )
{
startCommand( context, "exit", create_ExitCall( context, status ) );
}
specification typedef struct ExitReturnType ExitReturnType = {};
ExitReturnType * create_ExitReturnType(
String * name,
CallContext context
)
{
return create(&type_ExitReturnType,
name,
context);
}
reaction ExitReturnType * exitCalledProcess_return( void )
{
post
{
String * name = exitCalledProcess_return->name;
/*
* These functions do not return.
*/
req4( name, "_Exit.05" , "These functions do not return", false );
req4( name, "_exit.05" , "These functions do not return", false );
req4( name, "exit.05" , "These functions do not return", false );
req4( name, "return_from_main.05", "These functions do not return", false );
return true;
}
}
reaction ExitReturnType * exit_processTerminated( void )
{
post
{
String * name = exit_processTerminated->name ;
CallContext context = exit_processTerminated->context;
ExitCall * blocked_call = showCommand( @getBlockedCalls(), context, "exit" );
IntT status = blocked_call->status;
SystemState * systemState = getSystemState( context.system );
int i;
bool checkResult;
/*
* The _Exit() [CX] and _exit() functions shall not call functions registered
* with atexit() nor any registered signal handlers.
*/
req4( name, "_Exit.01", "", TODO_REQ() );
req4( name, "_exit.01", "", TODO_REQ() );
/*
* The exit() function shall first call all functions registered by atexit(), in
* the reverse order of their registration, except that a function is called after
* any previously registered functions that had already been called at the time it
* was registered. Each function is called as many times as it was registered.
*/
req4( name, "exit.01" , "", TODO_REQ());
req4( name, "return_from_main.01", "", TODO_REQ());
/*
* If a function registered by a call to atexit() fails to return, the remaining
* registered functions shall not be called and the rest of the exit() processing
* shall not be completed.
*/
req4( name, "exit.02" , "", TODO_REQ() );
req4( name, "return_from_main.02", "", TODO_REQ() );
/*
* The exit() function shall then flush all open streams with unwritten buffered
* data, close all open streams, and remove all files created by tmpfile().
*/
req4( name, "exit.03" , "", TODO_REQ() );
req4( name, "return_from_main.03", "", TODO_REQ() );
/*
* These functions shall terminate the calling process [CX] with the following
* consequences:
*
* All of the file descriptors, directory streams, [XSI] conversion descriptors,
* and message catalog descriptors open in the calling process shall be closed.
*/
req4( name, "_Exit.04.01" , "", TODO_REQ() );
req4( name, "_exit.04.01" , "", TODO_REQ() );
req4( name, "exit.04.01" , "", TODO_REQ() );
req4( name, "return_from_main.04.01", "", TODO_REQ() );
/*
* These functions shall terminate the calling process [CX] with the following
* consequences:
*
* If the parent process of the calling process is executing a wait() or waitpid(),
* [XSI] and has neither set its SA_NOCLDWAIT flag nor set SIGCHLD to SIG_IGN,
* it shall be notified of the calling process' termination and the low-order
* eight bits (that is, bits 0377) of status shall be made available to it. If the
* parent is not waiting, the child's status shall be made available to it when
* the parent subsequently executes wait() or waitpid().
*/
req4( name, "_Exit.04.02" , "", TODO_REQ() );
req4( name, "_exit.04.02" , "", TODO_REQ() );
req4( name, "exit.04.02" , "", TODO_REQ() );
req4( name, "return_from_main.04.02", "", TODO_REQ() );
/*
* These functions shall terminate the calling process [CX] with the following
* consequences:
*
* If the parent process of the calling process is not executing a wait() or
* waitpid(), [XSI] and has neither set its SA_NOCLDWAIT flag nor set SIGCHLD to
* SIG_IGN, the calling process shall be transformed into a zombie process. A
* zombie process is an inactive process and it shall be deleted at some later
* time when its parent process executes wait() or waitpid().
*/
req4( name, "_Exit.04.03" , "", TODO_REQ() );
req4( name, "_exit.04.03" , "", TODO_REQ() );
req4( name, "exit.04.03" , "", TODO_REQ() );
req4( name, "return_from_main.04.03", "", TODO_REQ() );
/*
* These functions shall terminate the calling process [CX] with the following
* consequences:
*
* Termination of a process does not directly terminate its children. The sending
* of a SIGHUP signal as described below indirectly terminates children in some
* circumstances.
*/
req4( name, "_Exit.04.04" , "", TODO_REQ() );
req4( name, "_exit.04.04" , "", TODO_REQ() );
req4( name, "exit.04.04" , "", TODO_REQ() );
req4( name, "return_from_main.04.04", "", TODO_REQ() );
/*
* These functions shall terminate the calling process [CX] with the following
* consequences:
*
* The parent process ID of all of the calling process' existing child processes
* and zombie processes shall be set to the process ID of an implementation-
* defined system process. That is, these processes shall be inherited by a
* special system process.
*/
checkResult = true;
for ( i = 0; i < size_Map( systemState->processes ); i++ ) {
ProcessIdObj * key = key_Map( systemState->processes, i );
ProcessState * processState = get_Map( systemState->processes, key );
if ( processState->meta.parent.process == context.process ) {
checkResult = false;
break;
}
}
req4( name, "_Exit.04.05" , "Parent process ID of existing child and zombie processes", checkResult );
req4( name, "_exit.04.05" , "Parent process ID of existing child and zombie processes", checkResult );
req4( name, "exit.04.05" , "Parent process ID of existing child and zombie processes", checkResult );
req4( name, "return_from_main.04.05", "Parent process ID of existing child and zombie processes", checkResult );
/*
* These functions shall terminate the calling process [CX] with the following
* consequences:
*
* [XSI] Each attached shared-memory segment is detached and the value of
* shm_nattch (see shmget()) in the data structure associated with its shared
* memory ID shall be decremented by 1.
*/
req4( name, "_Exit.04.06" , "", TODO_REQ() );
req4( name, "_exit.04.06" , "", TODO_REQ() );
req4( name, "exit.04.06" , "", TODO_REQ() );
req4( name, "return_from_main.04.06", "", TODO_REQ() );
/*
* These functions shall terminate the calling process [CX] with the following
* consequences:
*
* [XSI] For each semaphore for which the calling process has set a semadj value (
* see semop() ), that value shall be added to the semval of the specified
* semaphore.
*/
req4( name, "_Exit.04.07" , "", TODO_REQ() );
req4( name, "_exit.04.07" , "", TODO_REQ() );
req4( name, "exit.04.07" , "", TODO_REQ() );
req4( name, "return_from_main.04.07", "", TODO_REQ() );
/*
* These functions shall terminate the calling process [CX] with the following
* consequences:
*
* If the process is a controlling process, the SIGHUP signal shall be sent to
* each process in the foreground process group of the controlling terminal
* belonging to the calling process.
*/
req4( name, "_Exit.04.08" , "", TODO_REQ() );
req4( name, "_exit.04.08" , "", TODO_REQ() );
req4( name, "exit.04.08" , "", TODO_REQ() );
req4( name, "return_from_main.04.08", "", TODO_REQ() );
/*
* These functions shall terminate the calling process [CX] with the following
* consequences:
*
* If the process is a controlling process, the controlling terminal associated
* with the session shall be disassociated from the session, allowing it to be
* acquired by a new controlling process.
*/
checkResult = true;
req4( name, "_Exit.04.09" , "The controlling terminal shall be disassociated", checkResult );
req4( name, "_exit.04.09" , "The controlling terminal shall be disassociated", checkResult );
req4( name, "exit.04.09" , "The controlling terminal shall be disassociated", checkResult );
req4( name, "return_from_main.04.09", "The controlling terminal shall be disassociated", checkResult );
/*
* These functions shall terminate the calling process [CX] with the following
* consequences:
*
* If the exit of the process causes a process group to become orphaned, and if
* any member of the newly-orphaned process group is stopped, then a SIGHUP signal
* followed by a SIGCONT signal shall be sent to each process in the newly-
* orphaned process group.
*/
req4( name, "_Exit.04.10" , "", TODO_REQ() );
req4( name, "_exit.04.10" , "", TODO_REQ() );
req4( name, "exit.04.10" , "", TODO_REQ() );
req4( name, "return_from_main.04.10", "", TODO_REQ() );
/*
* These functions shall terminate the calling process [CX] with the following
* consequences:
*
* [SEM] All open named semaphores in the calling process shall be closed as if
* by appropriate calls to sem_close().
*/
req4( name, "_Exit.04.11" , "", TODO_REQ() );
req4( name, "_exit.04.11" , "", TODO_REQ() );
req4( name, "exit.04.11" , "", TODO_REQ() );
req4( name, "return_from_main.04.11", "", TODO_REQ() );
/*
* These functions shall terminate the calling process [CX] with the following
* consequences:
*
* [ML] Any memory locks established by the process via calls to mlockall() or
* mlock() shall be removed. If locked pages in the address space of the calling
* process are also mapped into the address spaces of other processes and are
* locked by those processes, the locks established by the other processes shall
* be unaffected by the call by this process to _Exit() or _exit().
*/
req4( name, "_Exit.04.12" , "", TODO_REQ() );
req4( name, "_exit.04.12" , "", TODO_REQ() );
req4( name, "exit.04.12" , "", TODO_REQ() );
req4( name, "return_from_main.04.12", "", TODO_REQ() );
/*
* These functions shall terminate the calling process [CX] with the following
* consequences:
*
* [MF|SHM] Memory mappings that were created in the process shall be unmapped
* before the process is destroyed.
*/
req4( name, "_Exit.04.13" , "", TODO_REQ() );
req4( name, "_exit.04.13" , "", TODO_REQ() );
req4( name, "exit.04.13" , "", TODO_REQ() );
req4( name, "return_from_main.04.13", "", TODO_REQ() );
/*
* These functions shall terminate the calling process [CX] with the following
* consequences:
*
* [TYM] Any blocks of typed memory that were mapped in the calling process shall
* be unmapped, as if munmap() was implicitly called to unmap them.
*/
req4( name, "_Exit.04.14" , "", TODO_REQ() );
req4( name, "_exit.04.14" , "", TODO_REQ() );
req4( name, "exit.04.14" , "", TODO_REQ() );
req4( name, "return_from_main.04.14", "", TODO_REQ() );
/*
* These functions shall terminate the calling process [CX] with the following
* consequences:
*
* [MSG] All open message queue descriptors in the calling process shall be
* closed as if by appropriate calls to mq_close().
*/
req4( name, "_Exit.04.15" , "", TODO_REQ() );
req4( name, "_exit.04.15" , "", TODO_REQ() );
req4( name, "exit.04.15" , "", TODO_REQ() );
req4( name, "return_from_main.04.15", "", TODO_REQ() );
/*
* These functions shall terminate the calling process [CX] with the following
* consequences:
*
* [AIO] Any outstanding cancelable asynchronous I/O operations may be canceled.
* Those asynchronous I/O operations that are not canceled shall complete as if
* the _Exit() or _exit() operation had not yet occurred, but any associated
* signal notifications shall be suppressed. The _Exit() or _exit() operation may
* block awaiting such I/O completion. Whether any I/O is canceled, and which I/O
* may be canceled upon _Exit() or _exit(), is implementation-defined.
*/
req4( name, "_Exit.04.16" , "", TODO_REQ() );
req4( name, "_exit.04.16" , "", TODO_REQ() );
req4( name, "exit.04.16" , "", TODO_REQ() );
req4( name, "return_from_main.04.16", "", TODO_REQ() );
/*
* These functions shall terminate the calling process [CX] with the following
* consequences:
*
* Threads terminated by a call to _Exit() or _exit() shall not invoke their
* cancellation cleanup handlers or per-thread data destructors.
*/
req4( name, "_Exit.04.17", "", true );
req4( name, "_exit.04.17", "", true );
/*
* These functions shall terminate the calling process [CX] with the following
* consequences:
*
* [TRC] If the calling process is a trace controller process, any trace streams
* that were created by the calling process shall be shut down as described by the
* posix_trace_shutdown() function, and any process' mapping of trace event names
* to trace event type identifiers built for these trace streams may be
* deallocated.
*/
req4( name, "_Exit.04.18" , "", TODO_REQ() );
req4( name, "_exit.04.18" , "", TODO_REQ() );
req4( name, "exit.04.18" , "", TODO_REQ() );
req4( name, "return_from_main.04.18", "", TODO_REQ() );
/*
* If the implementation supports the SIGCHLD signal, a SIGCHLD shall be sent to
* the parent process.
*/
req4( name, "_Exit.04.19.01" , "", TODO_REQ() );
req4( name, "_exit.04.19.01" , "", TODO_REQ() );
req4( name, "exit.04.19.01" , "", TODO_REQ() );
req4( name, "return_from_main.04.19.01", "", TODO_REQ() );
/*
* If the parent process has set its SA_NOCLDWAIT flag, or set SIGCHLD to SIG_IGN,
* the status shall be discarded, and the lifetime of the calling process shall
* end immediately.
*/
req4( name, "_Exit.04.19.02" , "", TODO_REQ() );
req4( name, "_exit.04.19.02" , "", TODO_REQ() );
req4( name, "exit.04.19.02" , "", TODO_REQ() );
req4( name, "return_from_main.04.19.02", "", TODO_REQ() );
/*
* If SA_NOCLDWAIT is set, it is implementation-defined whether a SIGCHLD signal
* is sent to the parent process.
*/
req4( name, "_Exit.04.19.03" , "", TODO_REQ() );
req4( name, "_exit.04.19.03" , "", TODO_REQ() );
req4( name, "exit.04.19.03" , "", TODO_REQ() );
req4( name, "return_from_main.04.19.03", "", TODO_REQ() );
/*
* The value of status may be 0, EXIT_SUCCESS, EXIT_FAILURE, [CX] or any other
* value, though only the least significant 8 bits (that is, status & 0377) shall
* be available to a waiting parent process.
*/
checkResult = true;
req4( name, "_Exit.06" , "Only the least significant 8 bits of status shall be available", checkResult );
req4( name, "_exit.06" , "Only the least significant 8 bits of status shall be available", checkResult );
req4( name, "exit.06" , "Only the least significant 8 bits of status shall be available", checkResult );
req4( name, "return_from_main.06", "Only the least significant 8 bits of status shall be available", checkResult );
/*
* Whether open streams are flushed or closed, or temporary files are removed is
* implementation-defined.
*/
req4( name, "_Exit.07", "", TODO_REQ() );
req4( name, "_exit.07", "", TODO_REQ() );
return true;
}
}
void onExitCalledProcessReturn( CallContext context )
{
endCommand( context, "exit" );
}
void onExitProcessTerminated( CallContext context )
{
ExitCall * blocked_call = endCommand( context, "exit" );
IntT status = blocked_call->status;
SystemState * systemState = getSystemState( context.system );
ProcessState * processState = getProcessState_CallContext( context );
ProcessId processId = create_ProcessId( context.system, context.process );
ProcessId specialSystemParent = getSpecialSystemParent( context.system );
int i;
if ( processState->childInCreation != NULL ) {
// exit after vfork
processState->childInCreation = NULL;
} else {
ProcessState * parent = getProcessState( processState->meta.parent );
Set /* ProcessState */ * children = getChildren_CallContext( context );
add_Set( parent->finishedChildren, create_FinishedChild( processState, status ) );
for ( i = 0; i < size_Set( children ); i++ ) {
ProcessState * child = get_Set( children, i );
if ( child->meta.parent.process == context.process ) { child->meta.parent = specialSystemParent; }
}
remove_Map( systemState->processes, create_ProcessIdObj( processId ) );
}
}
/*
Linux Standard Base Core Specification 3.1
Copyright (c) 2004, 2005 Free Standards Group
refers
The Open Group Base Specifications Issue 6
IEEE Std 1003.1, 2004 Edition
Copyright (c) 2001-2004 The IEEE and The Open Group, All Rights reserved.
NAME
exit, _Exit, _exit - terminate a process
SYNOPSIS
#include <stdlib.h>
void exit(int status);
void _Exit(int status);
#include <unistd.h>
void _exit(int status);
DESCRIPTION
For exit() and _Exit(): The functionality described on this reference page
is aligned with the ISO C standard. Any conflict between the requirements
described here and the ISO C standard is unintentional. This volume of IEEE
Std 1003.1-2001 defers to the ISO C standard.
The value of status may be 0, EXIT_SUCCESS, EXIT_FAILURE, or any other
value, though only the least significant 8 bits (that is, status & 0377)
shall be available to a waiting parent process.
The exit() function shall first call all functions registered by atexit(),
in the reverse order of their registration, except that a function is called
after any previously registered functions that had already been called at
the time it was registered. Each function is called as many times as it was
registered. If, during the call to any such function, a call to the
longjmp() function is made that would terminate the call to the registered
function, the behavior is undefined.
If a function registered by a call to atexit() fails to return, the
remaining registered functions shall not be called and the rest of the
exit() processing shall not be completed. If exit() is called more than
once, the behavior is undefined.
The exit() function shall then flush all open streams with unwritten
buffered data, close all open streams, and remove all files created by
tmpfile(). Finally, control shall be terminated with the consequences
described below.
The _Exit() and _exit() functions shall be functionally equivalent.
The _Exit() and _exit() functions shall not call functions registered with
atexit() nor any registered signal handlers. Whether open streams are
flushed or closed, or temporary files are removed is implementation-defined.
Finally, the calling process is terminated with the consequences described
below.
These functions shall terminate the calling process with the following
consequences:
Note:
These consequences are all extensions to the ISO C standard and are not
further CX shaded. However, XSI extensions are shaded.
All of the file descriptors, directory streams, conversion descriptors,
and message catalog descriptors open in the calling process shall be
closed.
If the parent process of the calling process is executing a wait() or
waitpid(), and has neither set its SA_NOCLDWAIT flag nor set SIGCHLD to
SIG_IGN, it shall be notified of the calling process' termination and
the low-order eight bits (that is, bits 0377) of status shall be made
available to it. If the parent is not waiting, the child's status shall
be made available to it when the parent subsequently executes wait() or
waitpid().
The semantics of the waitid() function shall be equivalent to wait().
If the parent process of the calling process is not executing a wait()
or waitpid(), and has neither set its SA_NOCLDWAIT flag nor set SIGCHLD
to SIG_IGN, the calling process shall be transformed into a zombie
process. A zombie process is an inactive process and it shall be deleted
at some later time when its parent process executes wait() or waitpid().
The semantics of the waitid() function shall be equivalent to wait().
Termination of a process does not directly terminate its children. The
sending of a SIGHUP signal as described below indirectly terminates
children in some circumstances.
Either:
If the implementation supports the SIGCHLD signal, a SIGCHLD shall be
sent to the parent process.
Or:
If the parent process has set its SA_NOCLDWAIT flag, or set SIGCHLD to
SIG_IGN, the status shall be discarded, and the lifetime of the calling
process shall end immediately. If SA_NOCLDWAIT is set, it is
implementation-defined whether a SIGCHLD signal is sent to the parent
process.
The parent process ID of all of the calling process' existing child
processes and zombie processes shall be set to the process ID of an
implementation-defined system process. That is, these processes shall be
inherited by a special system process.
Each attached shared-memory segment is detached and the value of
shm_nattch (see shmget()) in the data structure associated with its
shared memory ID shall be decremented by 1.
For each semaphore for which the calling process has set a semadj value
(see semop() ), that value shall be added to the semval of the specified
semaphore.
If the process is a controlling process, the SIGHUP signal shall be sent
to each process in the foreground process group of the controlling
terminal belonging to the calling process.
If the process is a controlling process, the controlling terminal
associated with the session shall be disassociated from the session,
allowing it to be acquired by a new controlling process.
If the exit of the process causes a process group to become orphaned,
and if any member of the newly-orphaned process group is stopped, then a
SIGHUP signal followed by a SIGCONT signal shall be sent to each process
in the newly-orphaned process group.
All open named semaphores in the calling process shall be closed as if
by appropriate calls to sem_close().
Any memory locks established by the process via calls to mlockall() or
mlock() shall be removed. If locked pages in the address space of the
calling process are also mapped into the address spaces of other
processes and are locked by those processes, the locks established by
the other processes shall be unaffected by the call by this process to
_Exit() or _exit().
Memory mappings that were created in the process shall be unmapped
before the process is destroyed.
Any blocks of typed memory that were mapped in the calling process shall
be unmapped, as if munmap() was implicitly called to unmap them.
All open message queue descriptors in the calling process shall be
closed as if by appropriate calls to mq_close().
Any outstanding cancelable asynchronous I/O operations may be canceled.
Those asynchronous I/O operations that are not canceled shall complete
as if the _Exit() or _exit() operation had not yet occurred, but any
associated signal notifications shall be suppressed. The _Exit() or
_exit() operation may block awaiting such I/O completion. Whether any
I/O is canceled, and which I/O may be canceled upon _Exit() or _exit(),
is implementation-defined.
Threads terminated by a call to _Exit() or _exit() shall not invoke
their cancellation cleanup handlers or per-thread data destructors.
If the calling process is a trace controller process, any trace streams
that were created by the calling process shall be shut down as described
by the posix_trace_shutdown() function, and any process' mapping of
trace event names to trace event type identifiers built for these trace
streams may be deallocated.
RETURN VALUE
These functions do not return.
ERRORS
No errors are defined.
*/
specification
void _Exit_spec( CallContext context, IntT status )
{
IntTObj * exitFailure; // EXIT_FAILURE
pre
{
/* [Local variable initialization] */
exitFailure = readIntValueByName( context, "EXIT_FAILURE" );
/* [Consistency of test suite] */
REQ( "", "Value for EXIT_FAILURE is known", exitFailure != NULL );
return true;
}
coverage C_Priority
{
if ( processReallyHaveHighPriority( context ) )
{
return { PriorityIsReallyHigh, "Process with high priority" };
}
else if ( processReallyHaveLowPriority( context ) )
{
return { PriorityIsReallyLow, "Process with low priority" };
}
else
{
return { PriorityIsUnknown, "Process with unknown priority" };
}
}
coverage C_Status
{
if ( status == SUT_EXIT_SUCCESS )
{
return { StatusIsExitSuccess, "status is EXIT_SUCCESS" };
}
else if ( status == * exitFailure )
{
return { StatusIsExitFailure, "status is EXIT_FAILURE" };
}
else if ( status <= 0xFF )
{
return { StatusIsNotGreaterThanFF, "status is not greater than 0xFF" };
}
else
{
return { StatusIsGreaterThanFF, "status is greater than 0xFF" };
}
}
post
{
return true;
}
}
/*
Linux Standard Base Core Specification 3.1
Copyright (c) 2004, 2005 Free Standards Group
NAME
__cxa_atexit -- register a function to be called by exit or when a shared
library is unloaded
SYNOPSIS
int __cxa_atexit(void (*func) (void *), void * arg, void * dso_handle);
DESCRIPTION
As described in the Itanium C++ ABI, __cxa_atexit() registers a destructor
function to be called by exit() or when a shared library is unloaded. When
a shared library is unloaded, any destructor function associated with that
shared library, identified by dso_handle, shall be called with the single
argument arg, and then that function shall be removed, or marked as
complete, from the list of functions to run at exit(). On a call to exit(),
any remaining functions registered shall be called with the single argument
arg. Destructor functions shall always be called in the reverse order to
their registration (i.e. the most recently registered function shall be
called first),
The __cxa_atexit() function is used to implement atexit(), as described in
ISO POSIX (2003). Calling atexit(func) from the statically linked part of an
application shall be equivalent to __cxa_atexit(func, NULL, NULL).
__cxa_atexit() is not in the source standard; it is only in the binary
standard.
Note: atexit() is not in the binary standard; it is only in the source
standard.
*/
specification
IntT __cxa_atexit_spec( CallContext context, CString * func, VoidTPtr arg, VoidTPtr dso_handle )
{
ProcessState * process_state;
List /* CString */ * registeredForCallAtExit;
pre
{
process_state = getProcessState_CallContext( context );
registeredForCallAtExit = clone( process_state->registeredForCallAtExit );
/* [Consistency of test suite] */
REQ( "", "Process state exists", process_state != NULL );
return true;
}
coverage C_Priority
{
if ( processReallyHaveHighPriority( context ) )
{
return { PriorityIsReallyHigh, "Process with high priority" };
}
else if ( processReallyHaveLowPriority( context ) )
{
return { PriorityIsReallyLow, "Process with low priority" };
}
else
{
return { PriorityIsUnknown, "Process with unknown priority" };
}
}
post
{
if ( __cxa_atexit_spec != 0 )
{
/*
* [Upon successful completion, atexit() shall return 0]
* otherwise, it shall return a non-zero value
*/
REQ( "__cxa_atexit.07.02", "return a non-zero value", true );
return true;
}
/*
* As described in the Itanium C++ ABI, __cxa_atexit() registers a destructor
* function to be called by exit() or when a shared library is unloaded.
*/
append_List( registeredForCallAtExit, func );
REQ( "__cxa_atexit.01", "__cxa_atexit() registers a destructor function",
equals( registeredForCallAtExit, process_state->registeredForCallAtExit )
);
/*
* When a shared library is unloaded, any destructor function associated with that
* shared library, identified by dso_handle, shall be called with the single
* argument arg, and then that function shall be removed, or marked as complete,
* from the list of functions to run at exit().
*/
REQ("__cxa_atexit.02", "", TODO_REQ());
/*
* On a call to exit(), any remaining functions registered shall be called with
* the single argument arg.
*/
REQ("__cxa_atexit.03", "", TODO_REQ());
/*
* Destructor functions shall always be called in the reverse order to their
* registration (i.e. the most recently registered function shall be called
* first),
*/
REQ("__cxa_atexit.04", "", TODO_REQ());
/*
* The __cxa_atexit() function is used to implement atexit(), as described in ISO
* POSIX (2003).
*/
REQ("__cxa_atexit.05", "", TODO_REQ());
/*
* Calling atexit(func) from the statically linked part of an application shall
* be equivalent to __cxa_atexit(func, NULL, NULL).
*/
REQ("__cxa_atexit.06", "", TODO_REQ());
/*
* Upon successful completion, atexit() shall return 0
*/
REQ( "__cxa_atexit.07.01", "Upon successful completion, atexit() shall return 0", __cxa_atexit_spec == 0 );
return true;
}
}
/*
Linux Standard Base Core Specification 3.1
Copyright (c) 2004, 2005 Free Standards Group
NAME
__libc_start_main -- initialization routine
SYNOPSIS
int __libc_start_main(int *(main) (int, char * *, char * *),
int argc, char * * ubp_av, void (*init) (void), void (*fini) (void), void
(*rtld_fini) (void), void (* stack_end));
DESCRIPTION
The __libc_start_main() function shall perform any necessary initialization
of the execution environment, call the main function with appropriate
arguments, and handle the return from main(). If the main() function
returns, the return value shall be passed to the exit() function.
Note: While this specification is intended to be implementation independent,
process and library initialization may include:
performing any necessary security checks if the effective user ID is not
the same as the real user ID.
initialize the threading subsystem.
registering the rtld_fini to release resources when this dynamic shared
object exits (or is unloaded).
registering the fini handler to run at program exit.
calling the initializer function (*init)().
calling main() with appropriate arguments.
calling exit() with the return value from main().
This list is an example only.
__libc_start_main() is not in the source standard; it is only in the binary
standard.
See Also
The section on Process Initialization in each of the architecture specific
supplements.
*/
specification
IntT __libc_start_main_spec( CallContext context, CString * main, IntT argc, List /* CString */ * ubp_av,
CString * init, CString * fini, CString * rtld_fini,
VoidTPtr stack_end
)
{
pre
{
/* [Consistency of test suite] */
REQ( "", "Process state exists", getProcessState_CallContext( context ) != NULL );
return true;
}
coverage C_Priority
{
if ( processReallyHaveHighPriority( context ) )
{
return { PriorityIsReallyHigh, "Process with high priority" };
}
else if ( processReallyHaveLowPriority( context ) )
{
return { PriorityIsReallyLow, "Process with low priority" };
}
else
{
return { PriorityIsUnknown, "Process with unknown priority" };
}
}
post
{
/*
* The __libc_start_main() function shall
*
* perform any necessary initialization of the execution environment
*/
REQ("__libc_start_main.01.01", "", TODO_REQ());
/*
* The __libc_start_main() function shall
*
* call the main function with appropriate arguments
*/
REQ("__libc_start_main.01.02", "", TODO_REQ());
/*
* The __libc_start_main() function shall
*
* handle the return from main()
*/
REQ("__libc_start_main.01.03", "", TODO_REQ());
/*
* If the main() function returns, the return value shall be passed to the exit()
* function.
*/
REQ("__libc_start_main.02", "", TODO_REQ());
return true;
}
}
/*
Linux Standard Base Core Specification 3.1
Copyright (c) 2004, 2005 Free Standards Group
NAME
__register_atfork -- alias for register_atfork
SYNOPSIS
int __register_atfork(void (*prepare) (void), void (*parent) (void),
void (*child) (void), void * __dso_handle);
DESCRIPTION
__register_atfork() implements pthread_atfork() as specified in ISO POSIX
(2003). The additional parameter __dso_handle allows a shared object to pass
in it's handle so that functions registered by __register_atfork() can be
unregistered by the runtime when the shared object is unloaded.
*/
specification
IntT __register_atfork_spec( CallContext context,
CString * prepare, CString * parent, CString * child, VoidTPtr __dso_handle
)
{
pre
{
/* [Consistency of test suite] */
REQ( "", "Process state exists", getProcessState_CallContext( context ) != NULL );
return true;
}
coverage C_Priority
{
if ( processReallyHaveHighPriority( context ) )
{
return { PriorityIsReallyHigh, "Process with high priority" };
}
else if ( processReallyHaveLowPriority( context ) )
{
return { PriorityIsReallyLow, "Process with low priority" };
}
else
{
return { PriorityIsUnknown, "Process with unknown priority" };
}
}
post
{
/*
* [Upon successful completion, pthread_atfork() shall return a value of zero]
* otherwise, an error number shall be returned to indicate the error
*/
REQ("__register_atfork.09.02", "", TODO_REQ());
ERROR_BEGIN(LSB___REGISTER_ATFORK, "__register_atfork.10.01", __register_atfork_spec != 0, __register_atfork_spec )
/*
* The pthread_atfork() function shall fail if:
*
* [ENOMEM]
* Insufficient table space exists to record the fork handler addresses.
*/
ERROR_UNCHECKABLE( LSB___REGISTER_ATFORK, ENOMEM, "__register_atfork.10.01", "" )
/*
* The pthread_atfork() function shall not return an error code of [EINTR].
*/
ERROR_NEVER( LSB___REGISTER_ATFORK, EINTR, "__register_atfork.11" )
ERROR_END()
/*
* __register_atfork() implements pthread_atfork() as specified in ISO POSIX
* (2003).
*/
REQ("__register_atfork.01", "", TODO_REQ());
/*
* The additional parameter __dso_handle allows a shared object to pass in it's
* handle so that functions registered by __register_atfork() can be unregistered
* by the runtime when the shared object is unloaded.
*/
REQ("__register_atfork.02", "", TODO_REQ());
/*
* The pthread_atfork() function shall declare fork handlers to be called before
* and after fork(), in the context of the thread that called fork().
*/
REQ("__register_atfork.03", "", TODO_REQ());
/*
* The prepare fork handler shall be called before fork() processing commences.
*/
REQ("__register_atfork.04", "", TODO_REQ());
/*
* The parent fork handle shall be called after fork() processing completes in the
* parent process.
*/
REQ("__register_atfork.05", "", TODO_REQ());
/*
* The child fork handler shall be called after fork() processing completes in
* the child process.
*/
REQ("__register_atfork.06", "", TODO_REQ());
/*
* If no handling is desired at one or more of these three points, the
* corresponding fork handler address(es) may be set to NULL.
*/
REQ("__register_atfork.07", "", TODO_REQ());
/*
* The order of calls to pthread_atfork() is significant.
*
* The parent and child fork handlers shall be called in the order in which they
* were established by calls to pthread_atfork().
*/
REQ("__register_atfork.08.01", "", TODO_REQ());
/*
* The order of calls to pthread_atfork() is significant.
*
* The prepare fork handlers shall be called in the opposite order.
*/
REQ("__register_atfork.08.02", "", TODO_REQ());
/*
* Upon successful completion, pthread_atfork() shall return a value of zero
*/
REQ("__register_atfork.09.01", "", TODO_REQ());
return true;
}
}
/*
Linux Standard Base Core Specification 3.1
Copyright (c) 2004, 2005 Free Standards Group
refers
The Open Group Base Specifications Issue 6
IEEE Std 1003.1, 2004 Edition
Copyright (c) 2001-2004 The IEEE and The Open Group, All Rights reserved.
NAME
exit, _Exit, _exit - terminate a process
SYNOPSIS
#include <stdlib.h>
void exit(int status);
void _Exit(int status);
#include <unistd.h>
void _exit(int status);
DESCRIPTION
For exit() and _Exit(): The functionality described on this reference page
is aligned with the ISO C standard. Any conflict between the requirements
described here and the ISO C standard is unintentional. This volume of IEEE
Std 1003.1-2001 defers to the ISO C standard.
The value of status may be 0, EXIT_SUCCESS, EXIT_FAILURE, or any other
value, though only the least significant 8 bits (that is, status & 0377)
shall be available to a waiting parent process.
The exit() function shall first call all functions registered by atexit(),
in the reverse order of their registration, except that a function is called
after any previously registered functions that had already been called at
the time it was registered. Each function is called as many times as it was
registered. If, during the call to any such function, a call to the
longjmp() function is made that would terminate the call to the registered
function, the behavior is undefined.
If a function registered by a call to atexit() fails to return, the
remaining registered functions shall not be called and the rest of the
exit() processing shall not be completed. If exit() is called more than
once, the behavior is undefined.
The exit() function shall then flush all open streams with unwritten
buffered data, close all open streams, and remove all files created by
tmpfile(). Finally, control shall be terminated with the consequences
described below.
The _Exit() and _exit() functions shall be functionally equivalent.
The _Exit() and _exit() functions shall not call functions registered with
atexit() nor any registered signal handlers. Whether open streams are
flushed or closed, or temporary files are removed is implementation-defined.
Finally, the calling process is terminated with the consequences described
below.
These functions shall terminate the calling process with the following
consequences:
Note:
These consequences are all extensions to the ISO C standard and are not
further CX shaded. However, XSI extensions are shaded.
All of the file descriptors, directory streams, conversion descriptors,
and message catalog descriptors open in the calling process shall be
closed.
If the parent process of the calling process is executing a wait() or
waitpid(), and has neither set its SA_NOCLDWAIT flag nor set SIGCHLD to
SIG_IGN, it shall be notified of the calling process' termination and
the low-order eight bits (that is, bits 0377) of status shall be made
available to it. If the parent is not waiting, the child's status shall
be made available to it when the parent subsequently executes wait() or
waitpid().
The semantics of the waitid() function shall be equivalent to wait().
If the parent process of the calling process is not executing a wait()
or waitpid(), and has neither set its SA_NOCLDWAIT flag nor set SIGCHLD
to SIG_IGN, the calling process shall be transformed into a zombie
process. A zombie process is an inactive process and it shall be deleted
at some later time when its parent process executes wait() or waitpid().
The semantics of the waitid() function shall be equivalent to wait().
Termination of a process does not directly terminate its children. The
sending of a SIGHUP signal as described below indirectly terminates
children in some circumstances.
Either:
If the implementation supports the SIGCHLD signal, a SIGCHLD shall be
sent to the parent process.
Or:
If the parent process has set its SA_NOCLDWAIT flag, or set SIGCHLD to
SIG_IGN, the status shall be discarded, and the lifetime of the calling
process shall end immediately. If SA_NOCLDWAIT is set, it is
implementation-defined whether a SIGCHLD signal is sent to the parent
process.
The parent process ID of all of the calling process' existing child
processes and zombie processes shall be set to the process ID of an
implementation-defined system process. That is, these processes shall be
inherited by a special system process.
Each attached shared-memory segment is detached and the value of
shm_nattch (see shmget()) in the data structure associated with its
shared memory ID shall be decremented by 1.
For each semaphore for which the calling process has set a semadj value
(see semop() ), that value shall be added to the semval of the specified
semaphore.
If the process is a controlling process, the SIGHUP signal shall be sent
to each process in the foreground process group of the controlling
terminal belonging to the calling process.
If the process is a controlling process, the controlling terminal
associated with the session shall be disassociated from the session,
allowing it to be acquired by a new controlling process.
If the exit of the process causes a process group to become orphaned,
and if any member of the newly-orphaned process group is stopped, then a
SIGHUP signal followed by a SIGCONT signal shall be sent to each process
in the newly-orphaned process group.
All open named semaphores in the calling process shall be closed as if
by appropriate calls to sem_close().
Any memory locks established by the process via calls to mlockall() or
mlock() shall be removed. If locked pages in the address space of the
calling process are also mapped into the address spaces of other
processes and are locked by those processes, the locks established by
the other processes shall be unaffected by the call by this process to
_Exit() or _exit().
Memory mappings that were created in the process shall be unmapped
before the process is destroyed.
Any blocks of typed memory that were mapped in the calling process shall
be unmapped, as if munmap() was implicitly called to unmap them.
All open message queue descriptors in the calling process shall be
closed as if by appropriate calls to mq_close().
Any outstanding cancelable asynchronous I/O operations may be canceled.
Those asynchronous I/O operations that are not canceled shall complete
as if the _Exit() or _exit() operation had not yet occurred, but any
associated signal notifications shall be suppressed. The _Exit() or
_exit() operation may block awaiting such I/O completion. Whether any
I/O is canceled, and which I/O may be canceled upon _Exit() or _exit(),
is implementation-defined.
Threads terminated by a call to _Exit() or _exit() shall not invoke
their cancellation cleanup handlers or per-thread data destructors.
If the calling process is a trace controller process, any trace streams
that were created by the calling process shall be shut down as described
by the posix_trace_shutdown() function, and any process' mapping of
trace event names to trace event type identifiers built for these trace
streams may be deallocated.
RETURN VALUE
These functions do not return.
ERRORS
No errors are defined.
*/
specification
void _exit_spec( CallContext context, IntT status )
{
IntTObj * exitFailure; // EXIT_FAILURE
pre
{
/* [Local variable initialization] */
exitFailure = readIntValueByName( context, "EXIT_FAILURE" );
/* [Consistency of test suite] */
REQ( "", "Value for EXIT_FAILURE is known", exitFailure != NULL );
return true;
}
coverage C_Priority
{
if ( processReallyHaveHighPriority( context ) )
{
return { PriorityIsReallyHigh, "Process with high priority" };
}
else if ( processReallyHaveLowPriority( context ) )
{
return { PriorityIsReallyLow, "Process with low priority" };
}
else
{
return { PriorityIsUnknown, "Process with unknown priority" };
}
}
coverage C_Status
{
if ( status == SUT_EXIT_SUCCESS )
{
return { StatusIsExitSuccess, "status is EXIT_SUCCESS" };
}
else if ( status == * exitFailure )
{
return { StatusIsExitFailure, "status is EXIT_FAILURE" };
}
else if ( status <= 0xFF )
{
return { StatusIsNotGreaterThanFF, "status is not greater than 0xFF" };
}
else
{
return { StatusIsGreaterThanFF, "status is greater than 0xFF" };
}
}
post
{
return true;
}
}
/*
Linux Standard Base Core Specification 3.1
Copyright (c) 2004, 2005 Free Standards Group
refers
The Open Group Base Specifications Issue 6
IEEE Std 1003.1, 2004 Edition
Copyright (c) 2001-2004 The IEEE and The Open Group, All Rights reserved.
NAME
abort - generate an abnormal process abort
SYNOPSIS
#include <stdlib.h>
void abort(void);
DESCRIPTION
The functionality described on this reference page is aligned with the ISO C
standard. Any conflict between the requirements described here and the ISO C
standard is unintentional. This volume of IEEE Std 1003.1-2001 defers to the
ISO C standard.
The abort() function shall cause abnormal process termination to occur,
unless the signal SIGABRT is being caught and the signal handler does not
return.
The abnormal termination processing shall include the default actions
defined for SIGABRT and may include an attempt to effect fclose() on all
open streams.
The SIGABRT signal shall be sent to the calling process as if by means of
raise() with the argument SIGABRT.
The status made available to wait() or waitpid() by abort() shall be that of
a process terminated by the SIGABRT signal. The abort() function shall
override blocking or ignoring the SIGABRT signal.
RETURN VALUE
The abort() function shall not return.
ERRORS
No errors are defined.
*/
specification typedef struct AbortCall AbortCall = {};
AbortCall * create_AbortCall( CallContext context )
{
return create( & type_AbortCall, context );
}
specification
void abort_spec( CallContext context )
{
pre
{
return true;
}
coverage C_Priority
{
if ( processReallyHaveHighPriority( context ) )
{
return { PriorityIsReallyHigh, "Process with high priority" };
}
else if ( processReallyHaveLowPriority( context ) )
{
return { PriorityIsReallyLow, "Process with low priority" };
}
else
{
return { PriorityIsUnknown, "Process with unknown priority" };
}
}
post
{
return true;
}
}
void onAbort( CallContext context )
{
startBlockedCall( context, create_AbortCall( context ) );
}
specification typedef struct AbortReturnType AbortReturnType = {};
AbortReturnType * create_AbortReturnType(CallContext context)
{
return create(&type_AbortReturnType, context);
}
reaction AbortReturnType * abortCalledProcess_return( void )
{
post
{
/*
* The abort() function shall not return.
*/
REQ( "abort.02", "abort() function shall not return", false );
return true;
}
}
reaction AbortReturnType * abort_processTerminated( void )
{
post
{
CallContext context = abort_processTerminated->context;
AbortCall * blocked_call = findBlockedCall( @getBlockedCalls(), context );
/*
* The status made available to wait() or waitpid() by abort() shall be that of a
* process terminated by the SIGABRT signal.
*/
REQ("abort.01", "", TODO_REQ());
/*
* The abnormal termination processing shall include the default actions defined
* for SIGABRT
*/
REQ("abort.03", "", TODO_REQ());
/*
* may include an attempt to effect fclose() on all open streams.
*/
REQ("abort.04", "", TODO_REQ());
/*
* The SIGABRT signal shall be sent to the calling process as if by means of raise(
* ) with the argument SIGABRT.
*/
REQ("abort.05", "", TODO_REQ());
/*
* The abort() function shall cause abnormal process termination to occur, unless
* the signal SIGABRT is being caught and the signal handler does not return.
*/
REQ("abort.06", "", TODO_REQ());
/*
* The abort() function shall override blocking or ignoring the SIGABRT signal.
*/
REQ("abort.07", "", TODO_REQ());
return true;
}
}
void onAbortCalledProcessReturn( CallContext context )
{
}
void onAbortProcessTerminated( CallContext context )
{
AbortCall * blocked_call = finishBlockedCall( context );
SystemState * systemState = getSystemState( context.system );
ProcessId processId = create_ProcessId( context.system, context.process );
ProcessId specialSystemParent = getSpecialSystemParent( context.system );
int i;
remove_Map( systemState->processes, create_ProcessIdObj( processId ) );
for ( i = 0; i < size_Map( systemState->processes ); i++ ) {
ProcessIdObj * key = key_Map( systemState->processes, i );
ProcessState * processState = get_Map( systemState->processes, key );
if ( processState->meta.parent.process == context.process ) { processState->meta.parent = specialSystemParent; }
}
}
/*
* common for daemon, fork and vfork
*/
specification typedef struct ForkCall ForkCall = {};
ForkCall * create_ForkCall( CallContext context )
{
return create( & type_ForkCall, context );
}
void onFork( CallContext context )
{
ProcessState * process_state = getProcessState_CallContext( context );
process_state->childInCreation = clone( process_state );
startCommand( context, "fork", create_ForkCall( context ) );
startCommand( context, "fork", create_ForkCall( context ) ); // for possible child
}
specification typedef struct ForkReturnType ForkReturnType = {};
ForkReturnType * create_ForkReturnType(
String * name,
CallContext context,
ProcessId returned_value,
ErrorCode * error_code,
PThreadT childThread
)
{
return create(&type_ForkReturnType,
name,
context,
returned_value,
error_code,
childThread);
}
reaction ForkReturnType * fork_return( void )
{
post
{
String * name = fork_return->name ;
CallContext context = fork_return->context ;
ProcessId fork_spec = fork_return->returned_value;
ErrorCode * errno = fork_return->error_code ;
ForkCall * blocked_call = showCommand( @getBlockedCalls(), context, "fork" );
ProcessState * parent_state = getProcessState_CallContext( context );
ProcessState * child_state = getProcessState ( fork_spec );
if ( equals( create_String( "daemon" ), name ) )
{
/*
* On error, -1 is returned, and the global variable errno is set to any of the
* errors specified for the library functions fork() and setsid().
*/
ERROR_BEGIN( LSB_DAEMON, "daemon.02.02", fork_spec.process == -1, * errno )
/*
* The fork() function shall fail if:
*
* [EAGAIN]
*
* The system lacked the necessary resources to create another process, or the
* system-imposed limit on the total number of processes under execution system-
* wide or by a single user {CHILD_MAX} would be exceeded.
*/
ERROR_UNCHECKABLE(LSB_DAEMON, EAGAIN, "daemon.03.01", "")
/*
* The fork() function may fail if:
*
* [ENOMEM]
*
* Insufficient storage space is available.
*/
ERROR_UNCHECKABLE(LSB_DAEMON, ENOMEM, "daemon.04.01", "")
ERROR_END()
}
else if ( equals( create_String( "fork" ), name ) )
{
/*
* [Upon successful completion, fork() shall return 0 to the child process and
* shall return the process ID of the child process to the parent process. Both
* processes shall continue to execute from the fork() function.]
* Otherwise, -1 shall be returned to the parent process, no child process shall
* be created, and errno shall be set to indicate the error.
*/
ERROR_BEGIN( POSIX_FORK, "fork.02.02", fork_spec.process == -1, * errno )
/*
* The fork() function shall fail if:
*
* [EAGAIN]
*
* The system lacked the necessary resources to create another process, or the
* system-imposed limit on the total number ofprocesses under execution system-
* wide or by a single user {CHILD_MAX} would be exceeded.
*/
ERROR_UNCHECKABLE(POSIX_FORK, EAGAIN, "fork.03.01", "")
/*
* The fork() function may fail if:
*
* [ENOMEM]
*
* Insufficient storage space is available.
*/
ERROR_UNCHECKABLE(POSIX_FORK, ENOMEM, "fork.04.01", "")
ERROR_END()
/*
* Upon successful completion, fork() shall return 0 to the child process and
* shall return the process ID of the child process to the parent process. Both
* processes shall continue to execute from the fork() function.
*/
// verbose( "fork_return : fork_spec [%d|%d]\n", fork_spec.system , fork_spec.process );
// verbose( "fork_return : child_state->processid [%d|%d]\n", child_state->processid.system , child_state->processid.process );
// verbose( "fork_return : child_state->meta.parent [%d|%d]\n", child_state->meta.parent.system, child_state->meta.parent.process );
// verbose( "fork_return : parent_state->processid [%d|%d]\n", parent_state->processid.system , parent_state->processid.process );
REQ( "fork.02.01", "fork() shall return the process ID of the child process to the parent process",
T( child_state != NULL ) &&
T( child_state->meta.parent.system == parent_state->processid.system ) &&
T( child_state->meta.parent.process == parent_state->processid.process )
);
}
else if ( equals( create_String( "forkpty" ), name ) )
{
/*
* On error, no new process shall be created, -1 shall be returned, and errno
* shall be set appropriately.
*/
ERROR_BEGIN( LSB_FORKPTY, "forkpty.02.02", fork_spec.process == -1, * errno )
/*
* Errors
*
* [EAGAIN]
* Unable to create a new process.
*/
ERROR_SHALL(LSB_FORKPTY, EAGAIN, "forkpty.06.01", TODO_ERR(EAGAIN) )
/*
* Errors
*
* [ENOENT]
* There are no available pseudo-terminals.
*/
ERROR_SHALL(LSB_FORKPTY, ENOENT, "forkpty.06.02", TODO_ERR(ENOENT) )
/*
* Errors
*
* [ENOMEM]
* Insufficient memory was available.
*/
ERROR_SHALL(LSB_FORKPTY, ENOMEM, "forkpty.06.03", TODO_ERR(ENOMEM) )
ERROR_END()
/*
* On success, the parent process shall return the process id of the child, and
* the child shall return 0.
*/
REQ( "forkpty.02.01", "the parent process shall return the process id of the child",
T( child_state != NULL ) &&
T( child_state->meta.parent.system == parent_state->processid.system ) &&
T( child_state->meta.parent.process == parent_state->processid.process )
);
/*
* On success, the parent process shall receive
*
* the file descriptor of the master side of the pseudo-terminal in the location
* referenced by amaster
*/
REQ("forkpty.05.01", "", TODO_REQ());
/*
* On success, the parent process shall receive
*
* if name is not NULL, the filename of the slave device in name
*/
REQ("forkpty.05.02", "", TODO_REQ());
}
else if ( equals( create_String( "vfork" ), name ) )
{
/*
* [Upon successful completion, vfork() shall return 0 to the child process and
* return the process ID of the child process to the parent process.]
* Otherwise, -1 shall be returned to the parent, no child process shall be created,
* and errno shall be set to indicate the error.
*/
ERROR_BEGIN( POSIX_VFORK, "vfork.02.02", fork_spec.process == -1, * errno )
/*
* The vfork() function shall fail if:
*
* [EAGAIN]
*
* The system-wide limit on the total number of processes under execution would be
* exceeded, or the system-imposed limit on the total number of processes under
* execution by a single user would be exceeded.
*/
ERROR_UNCHECKABLE(POSIX_VFORK, EAGAIN, "vfork.03.01", "")
/*
* The vfork() function shall fail if:
*
* [ENOMEM]
*
* There is insufficient swap space for the new process.
*/
ERROR_UNCHECKABLE(POSIX_VFORK, ENOMEM, "vfork.03.02", "")
ERROR_END()
/*
* Upon successful completion, vfork() shall return 0 to the child process and
* return the process ID of the child process to the parent process.
*
* [After vfork must be called _exit() or one of the exec family of functions.]
*/
if ( child_state == NULL )
{
/* [After vfork was called _exit().] */
REQ( "vfork.02.01", "vfork() shall return the process ID of the child process to the parent process",
true
);
}
else
{
/* [After vfork was called one of the exec family of functions.] */
REQ( "vfork.02.01", "vfork() shall return the process ID of the child process to the parent process",
T( child_state->meta.parent.system == parent_state->processid.system ) &&
T( child_state->meta.parent.process == parent_state->processid.process )
);
}
}
else
{
REQTRACE( "fork_return : unknown name" );
return false;
}
/*
* After fork(), both the parent and the child processes shall be capable of
* executing independently before either one terminates.
*/
req4( name, "fork.07" , "", TODO_REQ() );
req4( name, "vfork.07", "", TODO_REQ() );
return true;
}
}
reaction ForkReturnType * forkToChild_return( void )
{
post
{
String * name = forkToChild_return->name ;
CallContext context = forkToChild_return->context ;
ProcessId fork_spec = forkToChild_return->returned_value;
ErrorCode * errno = forkToChild_return->error_code ;
ForkCall * blocked_call = showCommand( @getBlockedCalls(), context, "fork" );
ProcessState * parent_state;
ProcessState * child_state ;
ProcessState * process_state = getProcessState_CallContext( context );
if ( process_state->childInCreation != NULL )
{
parent_state = process_state ;
child_state = process_state->childInCreation;
}
else
{
parent_state = getProcessState( process_state->meta.parent );
child_state = process_state ;
}
/* [Consistency of test suite] */
REQ( "", "Child process state exists" , child_state != NULL );
/*
* The fork() function shall create a new process. The new process (child process)
* shall be an exact copy of the calling process (parent process) except as
* detailed below:
*
* The child process shall have a unique process ID.
*/
req4( name, "daemon.01.01", "The child process shall have a unique process ID", parent_state != NULL );
req4( name, "fork.01.01" , "The child process shall have a unique process ID", parent_state != NULL );
req4( name, "vfork.01.01" , "The child process shall have a unique process ID", parent_state != NULL );
/*
* The fork() function shall create a new process. The new process (child process)
* shall be an exact copy of the calling process (parent process) except as
* detailed below:
*
* The child process ID also shall not match any active process group ID.
*/
req4( name, "daemon.01.02", "The child process ID also shall not match any active process group ID.", TODO_REQ() );
req4( name, "fork.01.02" , "The child process ID also shall not match any active process group ID.", TODO_REQ() );
req4( name, "vfork.01.02" , "The child process ID also shall not match any active process group ID.", TODO_REQ() );
/*
* The fork() function shall create a new process. The new process (child process)
* shall be an exact copy of the calling process (parent process) except as
* detailed below:
*
* The child process shall have a different parent process ID, which shall be the
* process ID of the calling process.
*/
req4( name, "daemon.01.03", "The child process shall have a different parent process ID", parent_state != NULL );
req4( name, "fork.01.03" , "The child process shall have a different parent process ID", parent_state != NULL );
req4( name, "vfork.01.03" , "The child process shall have a different parent process ID", parent_state != NULL );
/*
* The fork() function shall create a new process. The new process (child process)
* shall be an exact copy of the calling process (parent process) except as
* detailed below:
*
* The child process shall have its own copy of the parent's file descriptors.
* Each of the child's file descriptors shall refer to the same open file
* description with the corresponding file descriptor of the parent.
*/
req4( name, "daemon.01.04", "The child process shall have its own copy of the parent's file descriptors",
TODO_REQ()
);
req4( name, "fork.01.04" , "The child process shall have its own copy of the parent's file descriptors",
TODO_REQ()
);
req4( name, "vfork.01.04" , "The child process shall have its own copy of the parent's file descriptors",
TODO_REQ()
);
/*
* The fork() function shall create a new process. The new process (child process)
* shall be an exact copy of the calling process (parent process) except as
* detailed below:
*
* The child process shall have its own copy of the parent's open directory
* streams. Each open directory stream in the child process may share directory
* stream positioning with the corresponding directory stream of the parent.
*/
req4( name, "daemon.01.05", "The child process shall have its own copy of the parent's open directory streams",
TODO_REQ()
);
req4( name, "fork.01.05" , "The child process shall have its own copy of the parent's open directory streams",
TODO_REQ()
);
req4( name, "vfork.01.05" , "The child process shall have its own copy of the parent's open directory streams",
TODO_REQ()
);
/*
* The fork() function shall create a new process. The new process (child process)
* shall be an exact copy of the calling process (parent process) except as
* detailed below:
*
* The child process shall have its own copy of the parent's message catalog
* descriptors.
*/
req4( name, "daemon.01.06", "", TODO_REQ() );
req4( name, "fork.01.06" , "", TODO_REQ() );
req4( name, "vfork.01.06" , "", TODO_REQ() );
/*
* The fork() function shall create a new process. The new process (child process)
* shall be an exact copy of the calling process (parent process) except as
* detailed below:
*
* The child process' values of tms_utime, tms_stime, tms_cutime, and tms_cstime
* shall be set to 0.
*/
req4( name, "daemon.01.07", "", TODO_REQ() );
req4( name, "fork.01.07" , "", TODO_REQ() );
req4( name, "vfork.01.07" , "", TODO_REQ() );
/*
* The fork() function shall create a new process. The new process (child process)
* shall be an exact copy of the calling process (parent process) except as
* detailed below:
*
* The time left until an alarm clock signal shall be reset to zero, and the alarm,
* if any, shall be canceled; see alarm().
*/
req4( name, "daemon.01.08", "", TODO_REQ() );
req4( name, "fork.01.08" , "", TODO_REQ() );
req4( name, "vfork.01.08" , "", TODO_REQ() );
/*
* The fork() function shall create a new process. The new process (child process)
* shall be an exact copy of the calling process (parent process) except as
* detailed below:
*
* All semadj values shall be cleared.
*/
req4( name, "daemon.01.09", "", TODO_REQ() );
req4( name, "fork.01.09" , "", TODO_REQ() );
req4( name, "vfork.01.09" , "", TODO_REQ() );
/*
* The fork() function shall create a new process. The new process (child process)
* shall be an exact copy of the calling process (parent process) except as
* detailed below:
*
* File locks set by the parent process shall not be inherited by the child
* process.
*/
req4( name, "daemon.01.10", "", TODO_REQ() );
req4( name, "fork.01.10" , "", TODO_REQ() );
req4( name, "vfork.01.10" , "", TODO_REQ() );
/*
* The fork() function shall create a new process. The new process (child process)
* shall be an exact copy of the calling process (parent process) except as
* detailed below:
*
* The set of signals pending for the child process shall be initialized to the
* empty set.
*/
req4( name, "daemon.01.11", "", TODO_REQ() );
req4( name, "fork.01.11" , "", TODO_REQ() );
req4( name, "vfork.01.11" , "", TODO_REQ() );
/*
* The fork() function shall create a new process. The new process (child process)
* shall be an exact copy of the calling process (parent process) except as
* detailed below:
*
* Interval timers shall be reset in the child process.
*/
req4( name, "daemon.01.12", "", TODO_REQ() );
req4( name, "fork.01.12" , "", TODO_REQ() );
req4( name, "vfork.01.12" , "", TODO_REQ() );
/*
* The fork() function shall create a new process. The new process (child process)
* shall be an exact copy of the calling process (parent process) except as
* detailed below:
*
* Any semaphores that are open in the parent process shall also be open in the
* child process.
*/
req4( name, "daemon.01.13", "", TODO_REQ() );
req4( name, "fork.01.13" , "", TODO_REQ() );
req4( name, "vfork.01.13" , "", TODO_REQ() );
/*
* The fork() function shall create a new process. The new process (child process)
* shall be an exact copy of the calling process (parent process) except as
* detailed below:
*
* The child process shall not inherit any address space memory locks established
* by the parent process via calls to mlockall() or mlock().
*/
req4( name, "daemon.01.14", "", TODO_REQ() );
req4( name, "fork.01.14" , "", TODO_REQ() );
req4( name, "vfork.01.14" , "", TODO_REQ() );
/*
* The fork() function shall create a new process. The new process (child process)
* shall be an exact copy of the calling process (parent process) except as
* detailed below:
*
* Memory mappings created in the parent shall be retained in the child process.
* MAP_PRIVATE mappings inherited from the parent shall also be MAP_PRIVATE
* mappings in the child, and any modifications to the data in these mappings made
* by the parent prior to calling fork() shall be visible to the child. Any
* modifications to the data in MAP_PRIVATE mappings made by the parent after
* fork() returns shall be visible only to the parent. Modifications to the data
* in MAP_PRIVATE mappings made by the child shall be visible only to the child.
*/
req4( name, "daemon.01.15", "", TODO_REQ() );
req4( name, "fork.01.15" , "", TODO_REQ() );
req4( name, "vfork.01.15" , "", TODO_REQ() );
/*
* The fork() function shall create a new process. The new process (child process)
* shall be an exact copy of the calling process (parent process) except as
* detailed below:
*
* For the SCHED_FIFO and SCHED_RR scheduling policies, the child process shall
* inherit the policy and priority settings of the parent process during a fork()
* function. For other scheduling policies, the policy and priority settings on
* fork() are implementation-defined.
*/
req4( name, "daemon.01.16", "", TODO_REQ() );
req4( name, "fork.01.16" , "", TODO_REQ() );
req4( name, "vfork.01.16" , "", TODO_REQ() );
/*
* The fork() function shall create a new process. The new process (child process)
* shall be an exact copy of the calling process (parent process) except as
* detailed below:
*
* Per-process timers created by the parent shall not be inherited by the child
* process.
*/
req4( name, "daemon.01.17", "", TODO_REQ() );
req4( name, "fork.01.17" , "", TODO_REQ() );
req4( name, "vfork.01.17" , "", TODO_REQ() );
/*
* The fork() function shall create a new process. The new process (child process)
* shall be an exact copy of the calling process (parent process) except as
* detailed below:
*
* The child process shall have its own copy of the message queue descriptors of
* the parent. Each of the message descriptors of the child shall refer to the
* same open message queue description as the corresponding message descriptor of
* the parent.
*/
req4( name, "daemon.01.18", "", TODO_REQ() );
req4( name, "fork.01.18" , "", TODO_REQ() );
req4( name, "vfork.01.18" , "", TODO_REQ() );
/*
* The fork() function shall create a new process. The new process (child process)
* shall be an exact copy of the calling process (parent process) except as
* detailed below:
*
* No asynchronous input or asynchronous output operations shall be inherited by
* the child process.
*/
req4( name, "daemon.01.19", "", TODO_REQ() );
req4( name, "fork.01.19" , "", TODO_REQ() );
req4( name, "vfork.01.19" , "", TODO_REQ() );
/*
* The fork() function shall create a new process. The new process (child process)
* shall be an exact copy of the calling process (parent process) except as
* detailed below:
*
* A process shall be created with a single thread. If a multi-threaded process
* calls fork(), the new process shall contain a replica of the calling thread and
* its entire address space, possibly including the states of mutexes and other
* resources. Consequently, to avoid errors, the child process may only execute
* async-signal-safe operations until such time as one of the exec functions is
* called. [THR] Fork handlers may be established by means of the pthread_atfork(
* ) function in order to maintain application invariants across fork() calls.
*
* When the application calls fork() from a signal handler and any of the fork
* handlers registered by pthread_atfork() calls a function that is not asynch-
* signal-safe, the behavior is undefined.
*/
req4( name, "daemon.01.20", "", TODO_REQ() );
req4( name, "fork.01.20" , "", TODO_REQ() );
req4( name, "vfork.01.20" , "", TODO_REQ() );
/*
* The fork() function shall create a new process. The new process (child process)
* shall be an exact copy of the calling process (parent process) except as
* detailed below:
*
* [TRC TRI] If the Trace option and the Trace Inherit option are both supported:
*
* If the calling process was being traced in a trace stream that had its
* inheritance policy set to POSIX_TRACE_INHERITED, the child process shall be
* traced into that trace stream, and the child process shall inherit the parent's
* mapping of trace event names to trace event type identifiers. If the trace
* stream in which the calling process was being traced had its inheritance policy
* set to POSIX_TRACE_CLOSE_FOR_CHILD, the child process shall not be traced into
* that trace stream. The inheritance policy is set by a call to the
* posix_trace_attr_setinherited() function.
*/
req4( name, "daemon.01.21", "", TODO_REQ() );
req4( name, "fork.01.21" , "", TODO_REQ() );
req4( name, "vfork.01.21" , "", TODO_REQ() );
/*
* The fork() function shall create a new process. The new process (child process)
* shall be an exact copy of the calling process (parent process) except as
* detailed below:
*
* [TRC] If the Trace option is supported, but the Trace Inherit option is not
* supported:
*
* The child process shall not be traced into any of the trace streams of its
* parent process.
*/
req4( name, "daemon.01.22", "", TODO_REQ() );
req4( name, "fork.01.22" , "", TODO_REQ() );
req4( name, "vfork.01.22" , "", TODO_REQ() );
/*
* The fork() function shall create a new process. The new process (child process)
* shall be an exact copy of the calling process (parent process) except as
* detailed below:
*
* If the Trace option is supported, the child process of a trace controller
* process shall not control the trace streams controlled by its parent process.
*/
req4( name, "daemon.01.23", "", TODO_REQ() );
req4( name, "fork.01.23" , "", TODO_REQ() );
req4( name, "vfork.01.23" , "", TODO_REQ() );
/*
* The fork() function shall create a new process. The new process (child process)
* shall be an exact copy of the calling process (parent process) except as
* detailed below:
*
* The initial value of the CPU-time clock of the child process shall be set to
* zero.
*/
req4( name, "daemon.01.24", "", TODO_REQ() );
req4( name, "fork.01.24" , "", TODO_REQ() );
req4( name, "vfork.01.24" , "", TODO_REQ() );
/*
* The fork() function shall create a new process. The new process (child process)
* shall be an exact copy of the calling process (parent process) except as
* detailed below:
*
* The initial value of the CPU-time clock of the single thread of the child
* process shall be set to zero.
*/
req4( name, "daemon.01.25", "", TODO_REQ() );
req4( name, "fork.01.25" , "", TODO_REQ() );
req4( name, "vfork.01.25" , "", TODO_REQ() );
/*
* Upon successful completion, fork() shall return 0 to the child process and
* shall return the process ID of the child process to the parent process. Both
* processes shall continue to execute from the fork() function. Otherwise, -1
* shall be returned to the parent process, no child process shall be created, and
* errno shall be set to indicate the error.
*
* On success, the parent process shall return the process id of the child, and
* the child shall return 0.
*
* Upon successful completion, vfork() shall return 0 to the child process and
* return the process ID of the child process to the parent process. Otherwise, -1
* shall be returned to the parent, no child process shall be created, and errno
* shall be set to indicate the error.
*/
req4( name, "daemon.02.01" , "fork() shall return 0 to the child process" , fork_spec.process == 0 );
req4( name, "fork.02.01" , "fork() shall return 0 to the child process" , fork_spec.process == 0 );
req4( name, "forkpty.02.01", "the child shall return 0" , fork_spec.process == 0 );
req4( name, "vfork.02.01" , "vfork() shall return 0 to the child process", fork_spec.process == 0 );
/*
* All other process characteristics defined by IEEE Std 1003.1-2001 shall be the
* same in the parent and child processes.
*/
req4( name, "daemon.05", "", TODO_REQ() );
req4( name, "fork.05" , "", TODO_REQ() );
req4( name, "vfork.05" , "", TODO_REQ() );
/*
* The inheritance of process characteristics not defined by IEEE Std 1003.1-2001
* is unspecified by IEEE Std 1003.1-2001.
*/
req4( name, "daemon.06", "", TODO_REQ() );
req4( name, "fork.06" , "", TODO_REQ() );
req4( name, "vfork.06" , "", TODO_REQ() );
/*
* After fork(), both the parent and the child processes shall be capable of
* executing independently before either one terminates.
*/
req4( name, "daemon.07", "", TODO_REQ() );
req4( name, "fork.07" , "", TODO_REQ() );
req4( name, "vfork.07" , "", TODO_REQ() );
/*
* The forkpty() function shall find and open a pseudo-terminal device pair in
* the same manner as the openpty() function.
*/
req4( name, "forkpty.01", "", TODO_REQ() );
/*
* If a pseudo-terminal is available, forkpty() shall create a new process in
* the same manner as the fork() function
*/
req4( name, "forkpty.03", "", TODO_REQ() );
/*
* prepares the new process for login in the same manner as login_tty().
*/
req4( name, "forkpty.04", "", TODO_REQ() );
return true;
}
}
void onForkReturn( String * name, CallContext context, ProcessId fork_spec, ErrorCode * error_code )
{
ProcessState * parentState;
endCommand( context, "fork" );
parentState = getProcessState_CallContext( context );
if ( fork_spec.process == -1 ) {
// no child
endCommand( context, "fork" );
} else {
// complete and register child info
ThreadIdObj * threadIdObj;
ThreadState * oldThreadState;
if ( parentState->childInCreation == NULL ) { return; } // vfork + _exit || vfork + execl
// verbose( "onForkReturn : fork_spec [%d|%d]\n", fork_spec.system , fork_spec.process );
// verbose( "onForkReturn : parentState->childInCreation->processid [%d|%d]\n", parentState->childInCreation->processid.system , parentState->childInCreation->processid.process );
// verbose( "onForkReturn : parentState->childInCreation->meta.parent [%d|%d]\n", parentState->childInCreation->meta.parent.system, parentState->childInCreation->meta.parent.process );
// verbose( "onForkReturn : parentState->processid [%d|%d]\n", parentState->processid.system , parentState->processid.process );
parentState->childInCreation->processid = fork_spec;
parentState->childInCreation->meta.parent = parentState->processid;
threadIdObj = key_Map( parentState->childInCreation->threads, 0 );
oldThreadState = get_Map( parentState->childInCreation->threads, threadIdObj );
threadIdObj->process = fork_spec.process; // threadIdObj->thread was or will be set in onForkToChildReturn
clear_Map( parentState->childInCreation->threads );
if ( getProcessState_ThreadId( * threadIdObj ) == NULL ) {
// threadIdObj not fully created
// verbose( "onForkReturn : threadIdObj not fully created\n" );
put_Map( parentState->childInCreation->threads, threadIdObj, oldThreadState );
} else {
// threadIdObj fully created
// verbose( "onForkReturn : threadIdObj fully created\n" );
put_Map( parentState->childInCreation->threads, threadIdObj, create_DefaultThreadState( * threadIdObj ) );
}
registerProcessState( fork_spec, parentState->childInCreation );
// for daemon remove parent info
if ( equals( name, create_String( "daemon" ) ) ) {
SystemState * systemState = getSystemState( context.system );
ProcessId processId = create_ProcessId( context.system, context.process );
ProcessId specialSystemParent = getSpecialSystemParent( context.system );
int i;
remove_Map( systemState->processes, create_ProcessIdObj( processId ) );
for ( i = 0; i < size_Map( systemState->processes ); i++ ) {
ProcessIdObj * key = key_Map( systemState->processes, i );
ProcessState * processState = get_Map( systemState->processes, key );
if ( processState->meta.parent.process == context.process ) {
processState->meta.parent = specialSystemParent;
}
}
}
}
parentState->childInCreation = NULL;
}
void onForkToChildReturn( CallContext context, PThreadT childThread )
{
ProcessState * parentState;
ProcessState * childState;
ThreadIdObj * threadIdObj;
ThreadState * oldThreadState;
endCommand( context, "fork" );
parentState = getProcessState_CallContext( context );
if ( parentState->childInCreation != NULL ) {
// onForkToChildReturn before onForkReturn
childState = parentState->childInCreation;
} else {
// onForkToChildReturn after onForkReturn
Set /* ProcessState */ * children = getChildren_CallContext( context );
childState = get_Set( children, 0 );
}
threadIdObj = key_Map( childState->threads, 0 );
oldThreadState = get_Map( childState->threads, threadIdObj );
threadIdObj->thread = childThread; // threadIdObj->process will be or was set in onForkReturn
clear_Map( childState->threads );
if ( getProcessState_ThreadId( * threadIdObj ) == NULL ) {
// threadIdObj not fully created
// verbose( "onForkToChildReturn : threadIdObj not fully created\n" );
put_Map( childState->threads, threadIdObj, oldThreadState );
} else {
// threadIdObj fully created
// verbose( "onForkToChildReturn : threadIdObj fully created\n" );
put_Map( childState->threads, threadIdObj, create_DefaultThreadState( * threadIdObj ) );
}
}
/*
Linux Standard Base Core Specification 3.1
Copyright (c) 2004, 2005 Free Standards Group
NAME
daemon -- run in the background
SYNOPSIS
#include <unistd.h>
int daemon(int nochdir, int noclose);
DESCRIPTION
The daemon() function shall create a new process, detached from the
controlling terminal. If successful, the calling process shall exit and the
new process shall continue to execute the application in the background. If
nochdir evaluates to true, the current directory shall not be changed.
Otherwise, daemon() shall change the current working directory to the root
(`/'). If noclose evaluates to true the standard input, standard output, and
standard error file descriptors shall not be altered. Otherwise, daemon()
shall close the standard input, standard output and standard error file
descriptors and reopen them attached to /dev/null.
RETURN VALUE
On error, -1 is returned, and the global variable errno is set to any of the
errors specified for the library functions fork() and setsid().
*/
specification
void daemon_spec( CallContext context, IntT nochdir, IntT noclose )
{
pre
{
/* [Local variable initialization] */
ProcessState * process_state = getProcessState_CallContext( context );
/* [Consistency of test suite] */
REQ( "", "Process state exists", process_state != NULL );
return true;
}
coverage C_Priority
{
if ( processReallyHaveHighPriority( context ) )
{
return { PriorityIsReallyHigh, "Process with high priority" };
}
else if ( processReallyHaveLowPriority( context ) )
{
return { PriorityIsReallyLow, "Process with low priority" };
}
else
{
return { PriorityIsUnknown, "Process with unknown priority" };
}
}
coverage C_NoChdir
{
if ( nochdir == 0 )
{
return { Zero, "nochdir is equal to zero" };
}
else
{
return { NotZero, "nochdir is not equal to zero" };
}
}
coverage C_NoClose
{
if ( noclose == 0 )
{
return { Zero, "noclose is equal to zero" };
}
else
{
return { NotZero, "noclose is not equal to zero" };
}
}
post
{
return true;
}
}
/*
* common for exec group
*/
specification typedef struct ExecCall ExecCall = {};
ExecCall * create_ExecCall( String * name,
CallContext context, CString * path, List /* CString */ * argv, List /* CString */ * envp
)
{
return create( & type_ExecCall, name, context, path, argv, envp );
}
void onExec( String * name, CallContext context, CString * path, List /* CString */ * argv, List /* CString */ * envp )
{
ProcessState * process_state = getProcessState_CallContext( context );
process_state->inExecCall = true;
startCommand( context, "exec", create_ExecCall( name, context, path, argv, envp ) );
}
specification typedef struct ExecReturnType ExecReturnType = {};
ExecReturnType * create_ExecReturnType(
CallContext context,
IntT returned_value,
CString * path,
List /* CString */ * argv,
List /* CString */ * envp,
ErrorCode * error_code
)
{
return create(&type_ExecReturnType,
context,
returned_value,
path,
argv,
envp,
error_code);
}
CallContext findCorrespondContext( CallContext context, Map * systems ) {
int i, j;
for ( i = 0; i < size_Map( systems ); i++ ) {
Long * key = key_Map( systems, i );
if ( * key == context.system ) {
SystemState * systemState = get_Map( systems, key );
for ( j = 0; j < size_Map( systemState->processes ); j++ ) {
ProcessIdObj * key = key_Map( systemState->processes, j );
if ( key->process == context.process ) {
ProcessState * processState = get_Map( systemState->processes, key );
if ( size_Map( processState->threads ) != 1 ) {
return WrongThreadId;
} else {
ThreadIdObj * key = key_Map( processState->threads, 0 );
context.thread = key->thread;
return context;
}
}
} // for j
}
} // for i
return WrongThreadId;
}
reaction ExecReturnType * execOldProcess_return( void )
{
post
{
CallContext context = execOldProcess_return->context ;
IntT exec_spec = execOldProcess_return->returned_value;
CString * post_path = execOldProcess_return->path ;
List * post_argv = execOldProcess_return->argv ;
List * post_envp = execOldProcess_return->envp ;
ErrorCode * errno = execOldProcess_return->error_code ;
ExecCall * blocked_call = showCommand( @getBlockedCalls(), context, "exec" );
String * name = blocked_call->name;
CString * pre_path = blocked_call->path;
List * pre_argv = blocked_call->argv;
List * pre_envp = blocked_call->envp;
bool checkResult, checkResult1, checkResult2;
ErrorCode * tempErrno = requestErrorCode();
ERROR_BEGIN( POSIX_EXECL, "execl.27.01", exec_spec == -1, * errno )
if ( equals( create_String( "execl" ), name ) ) { extraCodes = HAS_EXTRA_ERROR_CODES( POSIX_EXECL ); }
else if ( equals( create_String( "execv" ), name ) ) { extraCodes = HAS_EXTRA_ERROR_CODES( POSIX_EXECV ); }
else if ( equals( create_String( "execle" ), name ) ) { extraCodes = HAS_EXTRA_ERROR_CODES( POSIX_EXECLE ); }
else if ( equals( create_String( "execve" ), name ) ) { extraCodes = HAS_EXTRA_ERROR_CODES( POSIX_EXECVE ); }
else if ( equals( create_String( "execlp" ), name ) ) { extraCodes = HAS_EXTRA_ERROR_CODES( POSIX_EXECLP ); }
else if ( equals( create_String( "execvp" ), name ) ) { extraCodes = HAS_EXTRA_ERROR_CODES( POSIX_EXECVP ); }
else
{
REQTRACE( "execOldProcess_return : unknown name" );
return false;
}
/*
* The exec functions shall fail if:
*
* [E2BIG]
*
* The number of bytes used by the new process image's argument list and
* environment list is greater than the system-imposed limit of {ARG_MAX} bytes.
*/
error_shall4( name, POSIX_EXECL , E2BIG, "execl.27.01" , TODO_ERR( E2BIG ) )
error_shall4( name, POSIX_EXECV , E2BIG, "execv.27.01" , TODO_ERR( E2BIG ) )
error_shall4( name, POSIX_EXECLE, E2BIG, "execle.27.01", TODO_ERR( E2BIG ) )
error_shall4( name, POSIX_EXECVE, E2BIG, "execve.27.01", TODO_ERR( E2BIG ) )
error_shall4( name, POSIX_EXECLP, E2BIG, "execlp.27.01", TODO_ERR( E2BIG ) )
error_shall4( name, POSIX_EXECVP, E2BIG, "execvp.27.01", TODO_ERR( E2BIG ) )
/*
* The exec functions shall fail if:
*
* [EACCES]
*
* Search permission is denied for a directory listed in the new process image
* file's path prefix
*/
checkResult = false;
error_shall4( name, POSIX_EXECL , EACCES, "execl.27.02.01" , checkResult )
error_shall4( name, POSIX_EXECV , EACCES, "execv.27.02.01" , checkResult )
error_shall4( name, POSIX_EXECLE, EACCES, "execle.27.02.01", checkResult )
error_shall4( name, POSIX_EXECVE, EACCES, "execve.27.02.01", checkResult )
error_shall4( name, POSIX_EXECLP, EACCES, "execlp.27.02.01", checkResult )
error_shall4( name, POSIX_EXECVP, EACCES, "execvp.27.02.01", checkResult )
/*
* The exec functions shall fail if:
*
* [EACCES]
*
* the new process image file denies execution permission
*/
checkResult = false;
error_shall4( name, POSIX_EXECL , EACCES, "execl.27.02.02" , checkResult )
error_shall4( name, POSIX_EXECV , EACCES, "execv.27.02.02" , checkResult )
error_shall4( name, POSIX_EXECLE, EACCES, "execle.27.02.02", checkResult )
error_shall4( name, POSIX_EXECVE, EACCES, "execve.27.02.02", checkResult )
error_shall4( name, POSIX_EXECLP, EACCES, "execlp.27.02.02", checkResult )
error_shall4( name, POSIX_EXECVP, EACCES, "execvp.27.02.02", checkResult )
/*
* The exec functions shall fail if:
*
* [EACCES]
*
* the new process image file is not a regular file and the implementation does
* not support execution of files of its type.
*/
error_shall4( name, POSIX_EXECL , EACCES, "execl.27.02.03" , TODO_ERR( EACCES ) )
error_shall4( name, POSIX_EXECV , EACCES, "execv.27.02.03" , TODO_ERR( EACCES ) )
error_shall4( name, POSIX_EXECLE, EACCES, "execle.27.02.03", TODO_ERR( EACCES ) )
error_shall4( name, POSIX_EXECVE, EACCES, "execve.27.02.03", TODO_ERR( EACCES ) )
error_shall4( name, POSIX_EXECLP, EACCES, "execlp.27.02.03", TODO_ERR( EACCES ) )
error_shall4( name, POSIX_EXECVP, EACCES, "execvp.27.02.03", TODO_ERR( EACCES ) )
/*
* The exec functions shall fail if:
*
* [EINVAL]
*
* The new process image file has the appropriate permission and has a recognized
* executable binary format, but the system does not support execution of a file
* with this format.
*/
error_shall4( name, POSIX_EXECL , EINVAL, "execl.27.03" , TODO_ERR( EINVAL ) )
error_shall4( name, POSIX_EXECV , EINVAL, "execv.27.03" , TODO_ERR( EINVAL ) )
error_shall4( name, POSIX_EXECLE, EINVAL, "execle.27.03", TODO_ERR( EINVAL ) )
error_shall4( name, POSIX_EXECVE, EINVAL, "execve.27.03", TODO_ERR( EINVAL ) )
error_shall4( name, POSIX_EXECLP, EINVAL, "execlp.27.03", TODO_ERR( EINVAL ) )
error_shall4( name, POSIX_EXECVP, EINVAL, "execvp.27.03", TODO_ERR( EINVAL ) )
/*
* The exec functions shall fail if:
*
* [ELOOP]
*
* A loop exists in symbolic links encountered during resolution of the path or
* file argument.
*/
checkResult = false;
error_shall4( name, POSIX_EXECL , ELOOP, "execl.27.04" , checkResult )
error_shall4( name, POSIX_EXECV , ELOOP, "execv.27.04" , checkResult )
error_shall4( name, POSIX_EXECLE, ELOOP, "execle.27.04", checkResult )
error_shall4( name, POSIX_EXECVE, ELOOP, "execve.27.04", checkResult )
error_shall4( name, POSIX_EXECLP, ELOOP, "execlp.27.04", checkResult )
error_shall4( name, POSIX_EXECVP, ELOOP, "execvp.27.04", checkResult )
/*
* The exec functions shall fail if:
*
* [ENAMETOOLONG]
*
* The length of the path or file arguments exceeds {PATH_MAX} or a pathname
* component is longer than {NAME_MAX}.
*/
checkResult = false;
error_shall4( name, POSIX_EXECL , ENAMETOOLONG, "execl.27.05" , checkResult )
error_shall4( name, POSIX_EXECV , ENAMETOOLONG, "execv.27.05" , checkResult )
error_shall4( name, POSIX_EXECLE, ENAMETOOLONG, "execle.27.05", checkResult )
error_shall4( name, POSIX_EXECVE, ENAMETOOLONG, "execve.27.05", checkResult )
error_shall4( name, POSIX_EXECLP, ENAMETOOLONG, "execlp.27.05", checkResult )
error_shall4( name, POSIX_EXECVP, ENAMETOOLONG, "execvp.27.05", checkResult )
/*
* The exec functions shall fail if:
*
* [ENOENT]
*
* A component of path or file does not name an existing file or path or file is
* an empty string.
*/
checkResult1 = false;
checkResult2 = ( length_CString( pre_path ) == 0 );
error_shall4( name, POSIX_EXECL , ENOENT, "execl.27.06" , checkResult1 || checkResult2 )
error_shall4( name, POSIX_EXECV , ENOENT, "execv.27.06" , checkResult1 || checkResult2 )
error_shall4( name, POSIX_EXECLE, ENOENT, "execle.27.06", checkResult1 || checkResult2 )
error_shall4( name, POSIX_EXECVE, ENOENT, "execve.27.06", checkResult1 || checkResult2 )
error_shall4( name, POSIX_EXECLP, ENOENT, "execlp.27.06", checkResult1 || checkResult2 )
error_shall4( name, POSIX_EXECVP, ENOENT, "execvp.27.06", checkResult1 || checkResult2 )
/*
* The exec functions shall fail if:
*
* [ENOTDIR]
*
* A component of the new process image file's path prefix is not a directory.
*/
checkResult = false;
error_shall4( name, POSIX_EXECL , ENOTDIR, "execl.27.07" , checkResult )
error_shall4( name, POSIX_EXECV , ENOTDIR, "execv.27.07" , checkResult )
error_shall4( name, POSIX_EXECLE, ENOTDIR, "execle.27.07", checkResult )
error_shall4( name, POSIX_EXECVE, ENOTDIR, "execve.27.07", checkResult )
error_shall4( name, POSIX_EXECLP, ENOTDIR, "execlp.27.07", checkResult )
error_shall4( name, POSIX_EXECVP, ENOTDIR, "execvp.27.07", checkResult )
/*
* The exec functions, except for execlp() and execvp(), shall fail if:
*
* [ENOEXEC]
*
* The new process image file has the appropriate access permission but has an
* unrecognized format.
*/
error_shall4( name, POSIX_EXECL , ENOEXEC, "execl.28" , TODO_ERR( ENOEXEC ) )
error_shall4( name, POSIX_EXECV , ENOEXEC, "execv.28" , TODO_ERR( ENOEXEC ) )
error_shall4( name, POSIX_EXECLE, ENOEXEC, "execle.28", TODO_ERR( ENOEXEC ) )
error_shall4( name, POSIX_EXECVE, ENOEXEC, "execve.28", TODO_ERR( ENOEXEC ) )
/*
* The exec functions may fail if:
*
* [ELOOP]
*
* More than {SYMLOOP_MAX} symbolic links were encountered during resolution of
* the path or file argument.
*/
checkResult = false;
error_may4( name, POSIX_EXECL , ELOOP, "execl.29.01" , checkResult )
error_may4( name, POSIX_EXECV , ELOOP, "execv.29.01" , checkResult )
error_may4( name, POSIX_EXECLE, ELOOP, "execle.29.01", checkResult )
error_may4( name, POSIX_EXECVE, ELOOP, "execve.29.01", checkResult )
error_may4( name, POSIX_EXECLP, ELOOP, "execlp.29.01", checkResult )
error_may4( name, POSIX_EXECVP, ELOOP, "execvp.29.01", checkResult )
/*
* The exec functions may fail if:
*
* [ENAMETOOLONG]
*
* As a result of encountering a symbolic link in resolution of the path argument,
* the length of the substituted pathname string exceeded {PATH_MAX}.
*/
checkResult = false;
error_may4( name, POSIX_EXECL , ENAMETOOLONG, "execl.29.02" , checkResult )
error_may4( name, POSIX_EXECV , ENAMETOOLONG, "execv.29.02" , checkResult )
error_may4( name, POSIX_EXECLE, ENAMETOOLONG, "execle.29.02", checkResult )
error_may4( name, POSIX_EXECVE, ENAMETOOLONG, "execve.29.02", checkResult )
error_may4( name, POSIX_EXECLP, ENAMETOOLONG, "execlp.29.02", checkResult )
error_may4( name, POSIX_EXECVP, ENAMETOOLONG, "execvp.29.02", checkResult )
/*
* The exec functions may fail if:
*
* [ENOMEM]
*
* The new process image requires more memory than is allowed by the hardware or
* system-imposed memory management constraints.
*/
error_may4( name, POSIX_EXECL , ENOMEM, "execl.29.03" , TODO_ERR( ENOMEM ) )
error_may4( name, POSIX_EXECV , ENOMEM, "execv.29.03" , TODO_ERR( ENOMEM ) )
error_may4( name, POSIX_EXECLE, ENOMEM, "execle.29.03", TODO_ERR( ENOMEM ) )
error_may4( name, POSIX_EXECVE, ENOMEM, "execve.29.03", TODO_ERR( ENOMEM ) )
error_may4( name, POSIX_EXECLP, ENOMEM, "execlp.29.03", TODO_ERR( ENOMEM ) )
error_may4( name, POSIX_EXECVP, ENOMEM, "execvp.29.03", TODO_ERR( ENOMEM ) )
/*
* The exec functions may fail if:
*
* [ETXTBSY]
*
* The new process image file is a pure procedure (shared text) file that is
* currently open for writing by some process.
*/
error_may4( name, POSIX_EXECL , ETXTBSY, "execl.29.04" , TODO_ERR( ETXTBSY ) )
error_may4( name, POSIX_EXECV , ETXTBSY, "execv.29.04" , TODO_ERR( ETXTBSY ) )
error_may4( name, POSIX_EXECLE, ETXTBSY, "execle.29.04", TODO_ERR( ETXTBSY ) )
error_may4( name, POSIX_EXECVE, ETXTBSY, "execve.29.04", TODO_ERR( ETXTBSY ) )
error_may4( name, POSIX_EXECLP, ETXTBSY, "execlp.29.04", TODO_ERR( ETXTBSY ) )
error_may4( name, POSIX_EXECVP, ETXTBSY, "execvp.29.04", TODO_ERR( ETXTBSY ) )
ERROR_END()
/* [reads path */
REQ( "", "reads path", equals( pre_path, post_path ) );
/*
* If one of the exec functions returns to the calling process image, an error has
* occurred; the return value shall be -1, and errno shall be set to indicate the
* error.
*/
checkResult = ( exec_spec == -1 );
req4( name, "execl.26" , "Return shall value be -1", checkResult );
req4( name, "execle.26", "Return shall value be -1", checkResult );
req4( name, "execlp.26", "Return shall value be -1", checkResult );
req4( name, "execv.26" , "Return shall value be -1", checkResult );
req4( name, "execve.26", "Return shall value be -1", checkResult );
req4( name, "execvp.26", "Return shall value be -1", checkResult );
/*
* The argv[] and envp[] arrays of pointers and the strings to which those arrays
* point shall not be modified by a call to one of the exec functions, except as a
* consequence of replacing the process image.
*/
checkResult1 = equals( pre_argv, post_argv );
checkResult2 = equals( pre_envp, post_envp );
req4( name, "execl.46" , "The argv[] and envp[] shall not be modified", T( checkResult1 ) && T( checkResult2 ) );
req4( name, "execle.46", "The argv[] and envp[] shall not be modified", T( checkResult1 ) && T( checkResult2 ) );
req4( name, "execlp.46", "The argv[] and envp[] shall not be modified", T( checkResult1 ) && T( checkResult2 ) );
req4( name, "execv.46" , "The argv[] and envp[] shall not be modified", T( checkResult1 ) && T( checkResult2 ) );
req4( name, "execve.46", "The argv[] and envp[] shall not be modified", T( checkResult1 ) && T( checkResult2 ) );
req4( name, "execvp.46", "The argv[] and envp[] shall not be modified", T( checkResult1 ) && T( checkResult2 ) );
return true;
}
}
reaction ExecReturnType * execNewProcess_return( void )
{
post
{
CallContext context = findCorrespondContext( execNewProcess_return->context, @systems );
CString * new_path = execNewProcess_return->path ;
List * new_argv = execNewProcess_return->argv ;
List * new_envp = execNewProcess_return->envp ;
ExecCall * blocked_call = showCommand( @getBlockedCalls(), context, "exec" );
String * name = blocked_call->name;
CString * pre_path = blocked_call->path;
List * pre_argv = blocked_call->argv;
List * pre_envp = blocked_call->envp;
ThreadId oldThreadId = context;
ProcessId oldProcessId = create_ProcessId( oldThreadId.system, oldThreadId.process );
SystemState * oldSystemState = get_Map( @systems, create_Long( oldThreadId.system ) );
ProcessState * oldProcessState = get_Map( oldSystemState->processes, create_ProcessIdObj( oldProcessId ) );
ThreadId newThreadId = execNewProcess_return->context;
ProcessState * newProcessState = getProcessState_CallContext( newThreadId );
ThreadState * newThreadState = getThreadState_CallContext( newThreadId );
bool checkResult;
bool checkResult1, checkResult2;
/*
* [
* The arguments represented by arg0,... are pointers to null-terminated character strings.
* The argument argv is an array of character pointers to null-terminated strings.
* ]
* These strings shall constitute the argument list available to the new process
* image.
*/
checkResult = equals( pre_argv, new_argv );
req4( name, "execl.01" , "Check argument list available to the new process image", checkResult );
req4( name, "execle.01", "Check argument list available to the new process image", checkResult );
req4( name, "execlp.01", "Check argument list available to the new process image", checkResult );
req4( name, "execv.01" , "Check argument list available to the new process image", checkResult );
req4( name, "execve.01", "Check argument list available to the new process image", checkResult );
req4( name, "execvp.01", "Check argument list available to the new process image", checkResult );
/*
* File descriptors open in the calling process image shall remain open in the new
* process image, except for those whose close-on- exec flag FD_CLOEXEC is set.
* For those file descriptors that remain open, all attributes of the open file
* description remain unchanged. For any file descriptor that is closed for this
* reason, file locks are removed as a result of the close as described in close().
* Locks that are not removed by closing of file descriptors remain unchanged.
*/
req4( name, "execl.02" , "", TODO_REQ() );
req4( name, "execle.02", "", TODO_REQ() );
req4( name, "execlp.02", "", TODO_REQ() );
req4( name, "execv.02" , "", TODO_REQ() );
req4( name, "execve.02", "", TODO_REQ() );
req4( name, "execvp.02", "", TODO_REQ() );
/*
* Directory streams open in the calling process image shall be closed in the new
* process image.
*/
checkResult = isEmpty_Set( newProcessState->dir_descriptors );
req4( name, "execl.03" , "Directory streams shall be closed in the new process image", checkResult );
req4( name, "execle.03", "Directory streams shall be closed in the new process image", checkResult );
req4( name, "execlp.03", "Directory streams shall be closed in the new process image", checkResult );
req4( name, "execv.03" , "Directory streams shall be closed in the new process image", checkResult );
req4( name, "execve.03", "Directory streams shall be closed in the new process image", checkResult );
req4( name, "execvp.03", "Directory streams shall be closed in the new process image", checkResult );
/*
* The state of the floating-point environment in the new process image [THR] or
* in the initial thread of the new process image shall be set to the default.
*/
req4( name, "execl.04" , "", TODO_REQ() );
req4( name, "execle.04", "", TODO_REQ() );
req4( name, "execlp.04", "", TODO_REQ() );
req4( name, "execv.04" , "", TODO_REQ() );
req4( name, "execve.04", "", TODO_REQ() );
req4( name, "execvp.04", "", TODO_REQ() );
/*
* Signals set to the default action (SIG_DFL) in the calling process image shall
* be set to the default action in the new process image. Except for SIGCHLD,
* signals set to be ignored (SIG_IGN) by the calling process image shall be set
* to be ignored by the new process image. Signals set to be caught by the calling
* process image shall be set to the default action in the new process image (see &
* lt;signal.h>). If the SIGCHLD signal is set to be ignored by the calling
* process image, it is unspecified whether the SIGCHLD signal is set to be
* ignored or to the default action in the new process image. [XSI] After a
* successful call to any of the exec functions, alternate signal stacks are not
* preserved and the SA_ONSTACK flag shall be cleared for all signals.
*/
req4( name, "execl.05" , "", TODO_REQ() );
req4( name, "execle.05", "", TODO_REQ() );
req4( name, "execlp.05", "", TODO_REQ() );
req4( name, "execv.05" , "", TODO_REQ() );
req4( name, "execve.05", "", TODO_REQ() );
req4( name, "execvp.02", "", TODO_REQ() );
/*
* After a successful call to any of the exec functions, any functions previously
* registered by atexit() [THR] or pthread_atfork() are no longer registered.
*/
req4( name, "execl.06" , "", TODO_REQ() );
req4( name, "execle.06", "", TODO_REQ() );
req4( name, "execlp.06", "", TODO_REQ() );
req4( name, "execv.06" , "", TODO_REQ() );
req4( name, "execve.06", "", TODO_REQ() );
req4( name, "execvp.06", "", TODO_REQ() );
/*
* [XSI] If the ST_NOSUID bit is set for the file system containing the new
* process image file, then the effective user ID, effective group ID, saved set-
* user-ID, and saved set-group-ID are unchanged in the new process image.
* Otherwise, if the set-user-ID mode bit of the new process image file is set,
* the effective user ID of the new process image shall be set to the user 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
* shall be 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 shall
* remain the same as those of the calling process image. The effective user ID
* and effective group ID of the new process image shall be saved (as the saved
* set-user-ID and the saved set-group-ID) for use by setuid().
*/
req4( name, "execl.07" , "", TODO_REQ() );
req4( name, "execle.07", "", TODO_REQ() );
req4( name, "execlp.07", "", TODO_REQ() );
req4( name, "execv.07" , "", TODO_REQ() );
req4( name, "execve.07", "", TODO_REQ() );
req4( name, "execvp.07", "", TODO_REQ() );
/*
* [XSI] Any shared memory segments attached to the calling process image shall
* not be attached to the new process image.
*/
req4( name, "execl.08" , "", TODO_REQ() );
req4( name, "execle.08", "", TODO_REQ() );
req4( name, "execlp.08", "", TODO_REQ() );
req4( name, "execv.08" , "", TODO_REQ() );
req4( name, "execve.08", "", TODO_REQ() );
req4( name, "execvp.08", "", TODO_REQ() );
/*
* [SEM] Any named semaphores open in the calling process shall be closed as if
* by appropriate calls to sem_close().
*/
req4( name, "execl.09" , "", TODO_REQ() );
req4( name, "execle.09", "", TODO_REQ() );
req4( name, "execlp.09", "", TODO_REQ() );
req4( name, "execv.09" , "", TODO_REQ() );
req4( name, "execve.09", "", TODO_REQ() );
req4( name, "execvp.09", "", TODO_REQ() );
/*
* [TYM] Any blocks of typed memory that were mapped in the calling process are
* unmapped, as if munmap() was implicitly called to unmap them.
*/
req4( name, "execl.10" , "", TODO_REQ() );
req4( name, "execle.10", "", TODO_REQ() );
req4( name, "execlp.10", "", TODO_REQ() );
req4( name, "execv.10" , "", TODO_REQ() );
req4( name, "execve.10", "", TODO_REQ() );
req4( name, "execvp.10", "", TODO_REQ() );
/*
* [ML] Memory locks established by the calling process via calls to mlockall()
* or mlock() shall be removed. If locked pages in the address space of the
* calling process are also mapped into the address spaces of other processes and
* are locked by those processes, the locks established by the other processes
* shall be unaffected by the call by this process to the exec function. If the
* exec function fails, the effect on memory locks is unspecified.
*/
req4( name, "execl.11" , "", TODO_REQ() );
req4( name, "execle.11", "", TODO_REQ() );
req4( name, "execlp.11", "", TODO_REQ() );
req4( name, "execv.11" , "", TODO_REQ() );
req4( name, "execve.11", "", TODO_REQ() );
req4( name, "execvp.11", "", TODO_REQ() );
/*
* [MF|SHM] Memory mappings created in the process are unmapped before the
* address space is rebuilt for the new process image.
*/
req4( name, "execl.12" , "", TODO_REQ() );
req4( name, "execle.12", "", TODO_REQ() );
req4( name, "execlp.12", "", TODO_REQ() );
req4( name, "execv.12" , "", TODO_REQ() );
req4( name, "execve.12", "", TODO_REQ() );
req4( name, "execvp.12", "", TODO_REQ() );
/*
* [PS] When the calling process image uses the SCHED_FIFO, SCHED_RR, or
* SCHED_SPORADIC scheduling policies, the process policy and scheduling parameter
* settings shall not be changed by a call to an exec function. [TPS] The
* initial thread in the new process image shall inherit the process scheduling
* policy and parameters. It shall have the default system contention scope, but
* shall inherit its allocation domain from the calling process image.
*/
req4( name, "execl.13" , "", TODO_REQ() );
req4( name, "execle.13", "", TODO_REQ() );
req4( name, "execlp.13", "", TODO_REQ() );
req4( name, "execv.13" , "", TODO_REQ() );
req4( name, "execve.13", "", TODO_REQ() );
req4( name, "execvp.13", "", TODO_REQ() );
/*
* [TMR] Per-process timers created by the calling process shall be deleted
* before replacing the current process image with the new process image.
*/
req4( name, "execl.14" , "", TODO_REQ() );
req4( name, "execle.14", "", TODO_REQ() );
req4( name, "execlp.14", "", TODO_REQ() );
req4( name, "execv.14" , "", TODO_REQ() );
req4( name, "execve.14", "", TODO_REQ() );
req4( name, "execvp.14", "", TODO_REQ() );
/*
* [MSG] All open message queue descriptors in the calling process shall be
* closed, as described in mq_close().
*/
req4( name, "execl.15" , "", TODO_REQ() );
req4( name, "execle.15", "", TODO_REQ() );
req4( name, "execlp.15", "", TODO_REQ() );
req4( name, "execv.15" , "", TODO_REQ() );
req4( name, "execve.15", "", TODO_REQ() );
req4( name, "execvp.15", "", TODO_REQ() );
/*
* [CPT] The new process image shall inherit the CPU-time clock of the calling
* process image. This inheritance means that the process CPU-time clock of the
* process being exec-ed shall not be reinitialized or altered as a result of the
* exec function other than to reflect the time spent by the process executing the
* exec function itself.
*/
req4( name, "execl.16" , "", TODO_REQ() );
req4( name, "execle.16", "", TODO_REQ() );
req4( name, "execlp.16", "", TODO_REQ() );
req4( name, "execv.16" , "", TODO_REQ() );
req4( name, "execve.16", "", TODO_REQ() );
req4( name, "execvp.16", "", TODO_REQ() );
/*
* [TCT] The initial value of the CPU-time clock of the initial thread of the new
* process image shall be set to zero.
*/
req4( name, "execl.17" , "", TODO_REQ() );
req4( name, "execle.17", "", TODO_REQ() );
req4( name, "execlp.17", "", TODO_REQ() );
req4( name, "execv.17" , "", TODO_REQ() );
req4( name, "execve.17", "", TODO_REQ() );
req4( name, "execvp.17", "", TODO_REQ() );
/*
* [TRC] If the calling process is being traced, the new process image shall
* continue to be traced into the same trace stream as the original process image,
* but the new process image shall not inherit the mapping of trace event names to
* trace event type identifiers that was defined by calls to the
* posix_trace_eventid_open() or the posix_trace_trid_eventid_open() functions in
* the calling process image.
*
* If the calling process is a trace controller process, any trace streams that
* were created by the calling process shall be shut down as described in the
* posix_trace_shutdown() function.
*/
req4( name, "execl.18" , "", TODO_REQ() );
req4( name, "execle.18", "", TODO_REQ() );
req4( name, "execlp.18", "", TODO_REQ() );
req4( name, "execv.18" , "", TODO_REQ() );
req4( name, "execve.18", "", TODO_REQ() );
req4( name, "execvp.18", "", TODO_REQ() );
/*
* The initial thread in the new process image shall have its cancellation type
* set to PTHREAD_CANCEL_DEFERRED and its cancellation state set to
* PTHREAD_CANCEL_ENABLED.
*/
req4( name, "execl.19" , "", TODO_REQ() );
req4( name, "execle.19", "", TODO_REQ() );
req4( name, "execlp.19", "", TODO_REQ() );
req4( name, "execv.19" , "", TODO_REQ() );
req4( name, "execve.19", "", TODO_REQ() );
req4( name, "execvp.19", "", TODO_REQ() );
/*
* The initial thread in the new process image shall have all thread-specific data
* values set to NULL and all thread-specific data keys shall be removed by the
* call to exec without running destructors.
*/
checkResult1 = ( size_Map( newProcessState->threads ) == 1 ) ;
checkResult2 = equals( newThreadState, create_DefaultThreadState( newThreadId ) );
req4( name, "execl.20" , "Check thread-specific data", T( checkResult1 ) && T( checkResult2 ) );
req4( name, "execle.20", "Check thread-specific data", T( checkResult1 ) && T( checkResult2 ) );
req4( name, "execlp.20", "Check thread-specific data", T( checkResult1 ) && T( checkResult2 ) );
req4( name, "execv.20" , "Check thread-specific data", T( checkResult1 ) && T( checkResult2 ) );
req4( name, "execve.20", "Check thread-specific data", T( checkResult1 ) && T( checkResult2 ) );
req4( name, "execvp.20", "Check thread-specific data", T( checkResult1 ) && T( checkResult2 ) );
/*
* The initial thread in the new process image shall be joinable, as if created
* with the detachstate attribute set to PTHREAD_CREATE_JOINABLE.
*/
checkResult = ( newThreadState->attr->detachstate == SUT_PTHREAD_CREATE_JOINABLE );
req4( name, "execl.21" , "The initial thread in the new process image shall be joinable", checkResult );
req4( name, "execle.21", "The initial thread in the new process image shall be joinable", checkResult );
req4( name, "execlp.21", "The initial thread in the new process image shall be joinable", checkResult );
req4( name, "execv.21" , "The initial thread in the new process image shall be joinable", checkResult );
req4( name, "execve.21", "The initial thread in the new process image shall be joinable", checkResult );
req4( name, "execvp.21", "The initial thread in the new process image shall be joinable", checkResult );
/*
* The new process shall inherit at least the following attributes from the
* calling process image:
*
* [XSI] Nice value (see nice())
*/
req4( name, "execl.22.01" , "", TODO_REQ() );
req4( name, "execle.22.01", "", TODO_REQ() );
req4( name, "execlp.22.01", "", TODO_REQ() );
req4( name, "execv.22.01" , "", TODO_REQ() );
req4( name, "execve.22.01", "", TODO_REQ() );
req4( name, "execvp.22.01", "", TODO_REQ() );
/*
* The new process shall inherit at least the following attributes from the
* calling process image:
*
* [XSI] semadj values (see semop())
*/
req4( name, "execl.22.02" , "", TODO_REQ() );
req4( name, "execle.22.02", "", TODO_REQ() );
req4( name, "execlp.22.02", "", TODO_REQ() );
req4( name, "execv.22.02" , "", TODO_REQ() );
req4( name, "execve.22.02", "", TODO_REQ() );
req4( name, "execvp.22.02", "", TODO_REQ() );
/*
* The new process shall inherit at least the following attributes from the
* calling process image:
*
* Process ID
*/
checkResult = ( oldProcessState->processid.system == newProcessState->processid.system &&
oldProcessState->processid.process == newProcessState->processid.process
);
req4( name, "execl.22.03" , "The new process shall inherit process ID", checkResult );
req4( name, "execle.22.03", "The new process shall inherit process ID", checkResult );
req4( name, "execlp.22.03", "The new process shall inherit process ID", checkResult );
req4( name, "execv.22.03" , "The new process shall inherit process ID", checkResult );
req4( name, "execve.22.03", "The new process shall inherit process ID", checkResult );
req4( name, "execvp.22.03", "The new process shall inherit process ID", checkResult );
/*
* The new process shall inherit at least the following attributes from the
* calling process image:
*
* Parent process ID
*/
checkResult = ( oldProcessState->meta.parent.system == newProcessState->meta.parent.system &&
oldProcessState->meta.parent.process == newProcessState->meta.parent.process
);
req4( name, "execl.22.04" , "The new process shall inherit parent process ID", checkResult );
req4( name, "execle.22.04", "The new process shall inherit parent process ID", checkResult );
req4( name, "execlp.22.04", "The new process shall inherit parent process ID", checkResult );
req4( name, "execv.22.04" , "The new process shall inherit parent process ID", checkResult );
req4( name, "execve.22.04", "The new process shall inherit parent process ID", checkResult );
req4( name, "execvp.22.04", "The new process shall inherit parent process ID", checkResult );
/*
* The new process shall inherit at least the following attributes from the
* calling process image:
*
* Process group ID
*/
checkResult = ( oldProcessState->meta.pgroup.system == newProcessState->meta.pgroup.system &&
oldProcessState->meta.pgroup.process == newProcessState->meta.pgroup.process
);
req4( name, "execl.22.05" , "The new process shall inherit process group ID", checkResult );
req4( name, "execle.22.05", "The new process shall inherit process group ID", checkResult );
req4( name, "execlp.22.05", "The new process shall inherit process group ID", checkResult );
req4( name, "execv.22.05" , "The new process shall inherit process group ID", checkResult );
req4( name, "execve.22.05", "The new process shall inherit process group ID", checkResult );
req4( name, "execvp.22.05", "The new process shall inherit process group ID", checkResult );
/*
* The new process shall inherit at least the following attributes from the
* calling process image:
*
* Session membership
*/
checkResult = ( oldProcessState->meta.session.system == newProcessState->meta.session.system &&
oldProcessState->meta.session.process == newProcessState->meta.session.process
);
req4( name, "execl.22.06" , "The new process shall inherit session membership", checkResult );
req4( name, "execle.22.06", "The new process shall inherit session membership", checkResult );
req4( name, "execlp.22.06", "The new process shall inherit session membership", checkResult );
req4( name, "execv.22.06" , "The new process shall inherit session membership", checkResult );
req4( name, "execve.22.06", "The new process shall inherit session membership", checkResult );
req4( name, "execvp.22.06", "The new process shall inherit session membership", checkResult );
/*
* The new process shall inherit at least the following attributes from the
* calling process image:
*
* Real user ID
*/
checkResult = ( oldProcessState->meta.real_userid == newProcessState->meta.real_userid );
req4( name, "execl.22.07" , "The new process shall inherit real user ID", checkResult );
req4( name, "execle.22.07", "The new process shall inherit real user ID", checkResult );
req4( name, "execlp.22.07", "The new process shall inherit real user ID", checkResult );
req4( name, "execv.22.07" , "The new process shall inherit real user ID", checkResult );
req4( name, "execve.22.07", "The new process shall inherit real user ID", checkResult );
req4( name, "execvp.22.07", "The new process shall inherit real user ID", checkResult );
/*
* The new process shall inherit at least the following attributes from the
* calling process image:
*
* Real group ID
*/
checkResult = ( oldProcessState->meta.real_groupid == newProcessState->meta.real_groupid );
req4( name, "execl.22.08" , "The new process shall inherit real group ID", checkResult );
req4( name, "execle.22.08", "The new process shall inherit real group ID", checkResult );
req4( name, "execlp.22.08", "The new process shall inherit real group ID", checkResult );
req4( name, "execv.22.08" , "The new process shall inherit real group ID", checkResult );
req4( name, "execve.22.08", "The new process shall inherit real group ID", checkResult );
req4( name, "execvp.22.08", "The new process shall inherit real group ID", checkResult );
/*
* The new process shall inherit at least the following attributes from the
* calling process image:
*
* Supplementary group IDs
*/
checkResult = equals( oldProcessState->meta.groups, newProcessState->meta.groups );
req4( name, "execl.22.09" , "The new process shall inherit supplementary group IDs", checkResult );
req4( name, "execle.22.09", "The new process shall inherit supplementary group IDs", checkResult );
req4( name, "execlp.22.09", "The new process shall inherit supplementary group IDs", checkResult );
req4( name, "execv.22.09" , "The new process shall inherit supplementary group IDs", checkResult );
req4( name, "execve.22.09", "The new process shall inherit supplementary group IDs", checkResult );
req4( name, "execvp.22.09", "The new process shall inherit supplementary group IDs", checkResult );
/*
* The new process shall inherit at least the following attributes from the
* calling process image:
*
* Time left until an alarm clock signal (see alarm())
*/
req4( name, "execl.22.10" , "", TODO_REQ() );
req4( name, "execle.22.10", "", TODO_REQ() );
req4( name, "execlp.22.10", "", TODO_REQ() );
req4( name, "execv.22.10" , "", TODO_REQ() );
req4( name, "execve.22.10", "", TODO_REQ() );
req4( name, "execvp.22.10", "", TODO_REQ() );
/*
* The new process shall inherit at least the following attributes from the
* calling process image:
*
* Current working directory
*/
checkResult = ( oldProcessState->meta.workdir.system == newProcessState->meta.workdir.system &&
oldProcessState->meta.workdir.file == newProcessState->meta.workdir.file
);
req4( name, "execl.22.11" , "The new process shall inherit current working directory", checkResult );
req4( name, "execle.22.11", "The new process shall inherit current working directory", checkResult );
req4( name, "execlp.22.11", "The new process shall inherit current working directory", checkResult );
req4( name, "execv.22.11" , "The new process shall inherit current working directory", checkResult );
req4( name, "execve.22.11", "The new process shall inherit current working directory", checkResult );
req4( name, "execvp.22.11", "The new process shall inherit current working directory", checkResult );
/*
* The new process shall inherit at least the following attributes from the
* calling process image:
*
* Root directory
*/
checkResult = ( oldProcessState->meta.root.system == newProcessState->meta.root.system &&
oldProcessState->meta.root.file == newProcessState->meta.root.file
);
req4( name, "execl.22.12" , "The new process shall inherit root directory", checkResult );
req4( name, "execle.22.12", "The new process shall inherit root directory", checkResult );
req4( name, "execlp.22.12", "The new process shall inherit root directory", checkResult );
req4( name, "execv.22.12" , "The new process shall inherit root directory", checkResult );
req4( name, "execve.22.12", "The new process shall inherit root directory", checkResult );
req4( name, "execvp.22.12", "The new process shall inherit root directory", checkResult );
/*
* The new process shall inherit at least the following attributes from the
* calling process image:
*
* File mode creation mask (see umask())
*/
checkResult = equals( oldProcessState->meta.umask, newProcessState->meta.umask );
req4( name, "execl.22.13" , "The new process shall inherit file mode creation mask", checkResult );
req4( name, "execle.22.13", "The new process shall inherit file mode creation mask", checkResult );
req4( name, "execlp.22.13", "The new process shall inherit file mode creation mask", checkResult );
req4( name, "execv.22.13" , "The new process shall inherit file mode creation mask", checkResult );
req4( name, "execve.22.13", "The new process shall inherit file mode creation mask", checkResult );
req4( name, "execvp.22.13", "The new process shall inherit file mode creation mask", checkResult );
/*
* The new process shall inherit at least the following attributes from the
* calling process image:
*
* [XSI] File size limit (see ulimit())
*/
req4( name, "execl.22.14" , "", TODO_REQ() );
req4( name, "execle.22.14", "", TODO_REQ() );
req4( name, "execlp.22.14", "", TODO_REQ() );
req4( name, "execv.22.14" , "", TODO_REQ() );
req4( name, "execve.22.14", "", TODO_REQ() );
req4( name, "execvp.22.14", "", TODO_REQ() );
/*
* The new process shall inherit at least the following attributes from the
* calling process image:
*
* Process signal mask (see sigprocmask())
*/
req4( name, "execl.22.15" , "", TODO_REQ() );
req4( name, "execle.22.15", "", TODO_REQ() );
req4( name, "execlp.22.15", "", TODO_REQ() );
req4( name, "execv.22.15" , "", TODO_REQ() );
req4( name, "execve.22.15", "", TODO_REQ() );
req4( name, "execvp.22.15", "", TODO_REQ() );
/*
* The new process shall inherit at least the following attributes from the
* calling process image:
*
* Pending signal (see sigpending())
*/
req4( name, "execl.22.16" , "", TODO_REQ() );
req4( name, "execle.22.16", "", TODO_REQ() );
req4( name, "execlp.22.16", "", TODO_REQ() );
req4( name, "execv.22.16" , "", TODO_REQ() );
req4( name, "execve.22.16", "", TODO_REQ() );
req4( name, "execvp.22.16", "", TODO_REQ() );
/*
* The new process shall inherit at least the following attributes from the
* calling process image:
*
* tms_utime, tms_stime, tms_cutime, and tms_cstime (see times())
*/
req4( name, "execl.22.17" , "", TODO_REQ() );
req4( name, "execle.22.17", "", TODO_REQ() );
req4( name, "execlp.22.17", "", TODO_REQ() );
req4( name, "execv.22.17" , "", TODO_REQ() );
req4( name, "execve.22.17", "", TODO_REQ() );
req4( name, "execvp.22.17", "", TODO_REQ() );
/*
* The new process shall inherit at least the following attributes from the
* calling process image:
*
* [XSI] Resource limits
*/
req4( name, "execl.22.18" , "", TODO_REQ() );
req4( name, "execle.22.18", "", TODO_REQ() );
req4( name, "execlp.22.18", "", TODO_REQ() );
req4( name, "execv.22.18" , "", TODO_REQ() );
req4( name, "execve.22.18", "", TODO_REQ() );
req4( name, "execvp.22.18", "", TODO_REQ() );
/*
* The new process shall inherit at least the following attributes from the
* calling process image:
*
* [XSI] Controlling terminal
*/
checkResult = equals( oldProcessState->meta.cterm, newProcessState->meta.cterm );
req4( name, "execl.22.19" , "The new process shall inherit controlling terminal", checkResult );
req4( name, "execle.22.19", "The new process shall inherit controlling terminal", checkResult );
req4( name, "execlp.22.19", "The new process shall inherit controlling terminal", checkResult );
req4( name, "execv.22.19" , "The new process shall inherit controlling terminal", checkResult );
req4( name, "execve.22.19", "The new process shall inherit controlling terminal", checkResult );
req4( name, "execvp.22.19", "The new process shall inherit controlling terminal", checkResult );
/*
* The new process shall inherit at least the following attributes from the
* calling process image:
*
* [XSI] Interval timers
*/
req4( name, "execl.22.20" , "", TODO_REQ() );
req4( name, "execle.22.20", "", TODO_REQ() );
req4( name, "execlp.22.20", "", TODO_REQ() );
req4( name, "execv.22.20" , "", TODO_REQ() );
req4( name, "execve.22.20", "", TODO_REQ() );
req4( name, "execvp.22.20", "", TODO_REQ() );
/*
* The initial thread of the new process shall inherit at least the following
* attributes from the calling thread:
*
* Signal mask (see sigprocmask() and pthread_sigmask())
*/
req4( name, "execl.23.01" , "", TODO_REQ() );
req4( name, "execle.23.01", "", TODO_REQ() );
req4( name, "execlp.23.01", "", TODO_REQ() );
req4( name, "execv.23.01" , "", TODO_REQ() );
req4( name, "execve.23.01", "", TODO_REQ() );
req4( name, "execvp.23.01", "", TODO_REQ() );
/*
* The initial thread of the new process shall inherit at least the following
* attributes from the calling thread:
*
* Pending signals (see sigpending())
*/
req4( name, "execl.23.02" , "", TODO_REQ() );
req4( name, "execle.23.02", "", TODO_REQ() );
req4( name, "execlp.23.02", "", TODO_REQ() );
req4( name, "execv.23.02" , "", TODO_REQ() );
req4( name, "execve.23.02", "", TODO_REQ() );
req4( name, "execvp.23.02", "", TODO_REQ() );
/*
* [THR] A call to any exec function from a process with more than one thread
* shall result in all threads being terminated and the new executable image being
* loaded and executed. No destructor functions or cleanup handlers shall be
* called.
*/
req4( name, "execl.24" , "", TODO_REQ() );
req4( name, "execle.24", "", TODO_REQ() );
req4( name, "execlp.24", "", TODO_REQ() );
req4( name, "execv.24" , "", TODO_REQ() );
req4( name, "execve.24", "", TODO_REQ() );
req4( name, "execvp.24", "", TODO_REQ() );
/*
* [XSI] The saved resource limits in the new process image are set to be a copy
* of the process' corresponding hard and soft limits.
*/
req4( name, "execl.25" , "", TODO_REQ() );
req4( name, "execle.25", "", TODO_REQ() );
req4( name, "execlp.25", "", TODO_REQ() );
req4( name, "execv.25" , "", TODO_REQ() );
req4( name, "execve.25", "", TODO_REQ() );
req4( name, "execvp.25", "", TODO_REQ() );
/*
* The argument file is used to construct a pathname that identifies the new
* process image file.
*/
if ( indexOfChar_CString( pre_path, '/' ) != -1 )
{
/*
* If the file argument contains a slash character, the file argument shall be
* used as the pathname for this file.
*/
checkResult = ( new_path == NULL ? true : equals( new_path, pre_path ) );
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ may be not enough
req4( name, "execlp.30.01", "The file argument shall be used as the pathname", checkResult );
req4( name, "execvp.30.01", "The file argument shall be used as the pathname", checkResult );
}
else
{
/*
* Otherwise, the path prefix for this file is obtained by a search of the
* directories passed as the environment variable PATH (see the Base Definitions
* volume of IEEE Std 1003.1-2001, Chapter 8, Environment Variables).
*/
req4( name, "execlp.30.02", "", TODO_REQ() );
req4( name, "execvp.30.02", "", TODO_REQ() );
}
/*
* There are two distinct ways in which the contents of the process image file may
* cause the execution to fail, distinguished by the setting of errno to either [
* ENOEXEC] or [EINVAL] (see the ERRORS section). In the cases where the other
* members of the exec family of functions would fail and set errno to [ENOEXEC],
* the execlp() and execvp() functions shall execute a command interpreter and the
* environment of the executed command shall be as if the process invoked the sh
* utility using execl() as follows:
*
* execl(<shell path>, arg0, file, arg1, ..., (char *)0);
*
* where
*
* shell path> is an unspecified pathname for the sh utility, file is the process
* image file, and for execvp(), where arg0, arg1, and so on correspond to the
* values passed to execvp() in argv[0], argv[1], and so on.
*/
req4( name, "execlp.31", "", TODO_REQ());
req4( name, "execvp.31", "", TODO_REQ());
/*
* For those forms not containing an envp pointer ( execl(), execv(), execlp(),
* and execvp()), the environment for the new process image shall be taken from
* the external variable environ in the calling process.
*/
checkResult = equals( new_envp, pre_envp );
{
String * newEnvpAsString = toString( new_envp );
String * preEnvpAsString = toString( pre_envp );
if ( checkResult ) { traceUserInfo( "equals( new_envp, pre_envp ) is true\n" ); }
else { traceUserInfo( "equals( new_envp, pre_envp ) is false\n" ); }
traceUserInfo( "newEnvpAsString\n" );
traceUserInfo( toCharArray_String( newEnvpAsString ) );
traceUserInfo( "\npreEnvpAsString\n" );
traceUserInfo( toCharArray_String( preEnvpAsString ) );
traceUserInfo( "\n" );
}
req4( name, "execl.32" , "The environment shall be taken from the environ in the calling process", checkResult );
req4( name, "execlp.32", "The environment shall be taken from the environ in the calling process", checkResult );
req4( name, "execv.32" , "The environment shall be taken from the environ in the calling process", checkResult );
req4( name, "execvp.32", "The environment shall be taken from the environ in the calling process", checkResult );
/*
* These strings shall constitute the environment for the new process image.
*/
checkResult = equals( new_envp, pre_envp );
req4( name, "execle.32", "The environment shall be taken from the environ in the calling process", checkResult );
req4( name, "execve.32", "The environment shall be taken from the environ in the calling process", checkResult );
/*
* If file descriptors 0, 1, and 2 would otherwise be closed after a successful
* call to one of the exec family of functions, and the new process image file has
* the set-user-ID or set-group-ID file mode bits set, [XSI] and the ST_NOSUID
* bit is not set for the file system containing the new process image file,
* implementations may open an unspecified file for each of these file descriptors
* in the new process image.
*/
req4( name, "execl.34" , "", TODO_REQ() );
req4( name, "execle.34", "", TODO_REQ() );
req4( name, "execlp.34", "", TODO_REQ() );
req4( name, "execv.34" , "", TODO_REQ() );
req4( name, "execve.34", "", TODO_REQ() );
req4( name, "execvp.34", "", TODO_REQ() );
/*
* setlocale(LC_ALL, "C")
*
* shall be executed at start-up.
*/
req4( name, "execl.35" , "", TODO_REQ() );
req4( name, "execle.35", "", TODO_REQ() );
req4( name, "execlp.35", "", TODO_REQ() );
req4( name, "execv.35" , "", TODO_REQ() );
req4( name, "execve.35", "", TODO_REQ() );
req4( name, "execvp.35", "", TODO_REQ() );
/*
* When the calling process image does not use the SCHED_FIFO, SCHED_RR, or
* SCHED_SPORADIC scheduling policies, the scheduling policy and parameters of the
* new process image and the initial thread in that new process image are
* implementation-defined.
*/
req4( name, "execl.36" , "", TODO_REQ() );
req4( name, "execle.36", "", TODO_REQ() );
req4( name, "execlp.36", "", TODO_REQ() );
req4( name, "execv.36" , "", TODO_REQ() );
req4( name, "execve.36", "", TODO_REQ() );
req4( name, "execvp.36", "", TODO_REQ() );
/*
* [AIO] Any outstanding asynchronous I/O operations may be canceled. Those
* asynchronous I/O operations that are not canceled shall complete as if the exec
* function had not yet occurred, but any associated signal notifications shall be
* suppressed. It is unspecified whether the exec function itself blocks awaiting
* such I/O completion. In no event, however, shall the new process image created
* by the exec function be affected by the presence of outstanding asynchronous I/
* O operations at the time the exec function is called. Whether any I/O is
* canceled, and which I/O may be canceled upon exec, is implementation-defined.
*/
req4( name, "execl.37" , "", TODO_REQ() );
req4( name, "execle.37", "", TODO_REQ() );
req4( name, "execlp.37", "", TODO_REQ() );
req4( name, "execv.37" , "", TODO_REQ() );
req4( name, "execve.37", "", TODO_REQ() );
req4( name, "execvp.37", "", TODO_REQ() );
/*
* [THR] The thread ID of the initial thread in the new process image is
* unspecified.
*/
checkResult = true;
req4( name, "execl.38" , "The thread ID of the initial thread in the new process is unspecified", checkResult );
req4( name, "execle.38", "The thread ID of the initial thread in the new process is unspecified", checkResult );
req4( name, "execlp.38", "The thread ID of the initial thread in the new process is unspecified", checkResult );
req4( name, "execv.38" , "The thread ID of the initial thread in the new process is unspecified", checkResult );
req4( name, "execve.38", "The thread ID of the initial thread in the new process is unspecified", checkResult );
req4( name, "execvp.38", "The thread ID of the initial thread in the new process is unspecified", checkResult );
/*
* The size and location of the stack on which the initial thread in the new
* process image runs is unspecified.
*/
checkResult = true;
req4( name, "execl.39" , "The size and location of the stack is unspecified", checkResult );
req4( name, "execle.39", "The size and location of the stack is unspecified", checkResult );
req4( name, "execlp.39", "The size and location of the stack is unspecified", checkResult );
req4( name, "execv.39" , "The size and location of the stack is unspecified", checkResult );
req4( name, "execve.39", "The size and location of the stack is unspecified", checkResult );
req4( name, "execvp.39", "The size and location of the stack is unspecified", checkResult );
/*
* All other process attributes defined in this volume of IEEE Std 1003.1-2001
* shall be inherited in the new process image from the old process image.
*/
req4( name, "execl.40" , "", TODO_REQ() );
req4( name, "execle.40", "", TODO_REQ() );
req4( name, "execlp.40", "", TODO_REQ() );
req4( name, "execv.40" , "", TODO_REQ() );
req4( name, "execve.40", "", TODO_REQ() );
req4( name, "execvp.40", "", TODO_REQ() );
/*
* All other thread attributes defined in this volume of IEEE Std 1003.1-2001
* shall be inherited in the initial thread in the new process image from the
* calling thread in the old process image.
*/
req4( name, "execl.41" , "", TODO_REQ() );
req4( name, "execle.41", "", TODO_REQ() );
req4( name, "execlp.41", "", TODO_REQ() );
req4( name, "execv.41" , "", TODO_REQ() );
req4( name, "execve.41", "", TODO_REQ() );
req4( name, "execvp.41", "", TODO_REQ() );
/*
* The inheritance of process or thread attributes not defined by this volume of
* IEEE Std 1003.1-2001 is implementation-defined.
*/
req4( name, "execl.42" , "", TODO_REQ() );
req4( name, "execle.42", "", TODO_REQ() );
req4( name, "execlp.42", "", TODO_REQ() );
req4( name, "execv.42" , "", TODO_REQ() );
req4( name, "execve.42", "", TODO_REQ() );
req4( name, "execvp.42", "", TODO_REQ() );
/*
* Upon successful completion, the exec functions shall mark for update the
* st_atime field of the file.
*/
req4( name, "execl.43" , "", TODO_REQ() );
req4( name, "execle.43", "", TODO_REQ() );
req4( name, "execlp.43", "", TODO_REQ() );
req4( name, "execv.43" , "", TODO_REQ() );
req4( name, "execve.43", "", TODO_REQ() );
req4( name, "execvp.43", "", TODO_REQ() );
/*
* If an exec function failed but was able to locate the process image file,
* whether the st_atime field is marked for update is unspecified.
*/
req4( name, "execl.44" , "", TODO_REQ() );
req4( name, "execle.44", "", TODO_REQ() );
req4( name, "execlp.44", "", TODO_REQ() );
req4( name, "execv.44" , "", TODO_REQ() );
req4( name, "execve.44", "", TODO_REQ() );
req4( name, "execvp.44", "", TODO_REQ() );
/*
* Should the exec function succeed, the process image file shall be considered to
* have been opened with open(). The corresponding close() shall be considered to
* occur at a time after this open, but before process termination or successful
* completion of a subsequent call to one of the exec functions, posix_spawn(), or
* posix_spawnp().
*/
req4( name, "execl.45" , "", TODO_REQ() );
req4( name, "execle.45", "", TODO_REQ() );
req4( name, "execlp.45", "", TODO_REQ() );
req4( name, "execv.45" , "", TODO_REQ() );
req4( name, "execve.45", "", TODO_REQ() );
req4( name, "execvp.45", "", TODO_REQ() );
return true;
}
}
void onExecOldProcessReturn( CallContext context )
{
ExecCall * blocked_call = endCommand( context, "exec" );
ProcessState * processState = getProcessState_CallContext( context );
processState->inExecCall = false;
}
void onExecNewProcessReturn( CallContext context )
{
CallContext oldContext = findCorrespondContext( context, systems );
ExecCall * blocked_call = endCommand( oldContext, "exec" );
ProcessState * processState = getProcessState_CallContext( oldContext );
ThreadIdObj * threadIdObj;
processState->inExecCall = false;
if ( processState->childInCreation != NULL ) {
// exec after vfork
processState->childInCreation->processid.system = context.system ;
processState->childInCreation->processid.process = context.process;
processState->childInCreation->inExecCall = false;
processState->childInCreation->wasSuccessfulExecCall = true;
processState->childInCreation->meta.parent = processState->processid;
registerProcessState( processState->childInCreation->processid, processState->childInCreation );
processState->childInCreation = NULL;
initAtExec_Locale(processState->childInCreation->processid);
} else {
processState->wasSuccessfulExecCall = true;
clear_Set( processState->dir_descriptors );
threadIdObj = key_Map( processState->threads, 0 );
threadIdObj->thread = context.thread;
clear_Map( processState->threads );
put_Map( processState->threads, threadIdObj, create_DefaultThreadState( * threadIdObj ) );
}
}
/*
Linux Standard Base Core Specification 3.1
Copyright (c) 2004, 2005 Free Standards Group
refers
The Open Group Base Specifications Issue 6
IEEE Std 1003.1, 2004 Edition
Copyright (c) 2001-2004 The IEEE and The Open Group, All Rights reserved.
NAME
environ, execl, execv, execle, execve, execlp, execvp - execute a file
SYNOPSIS
#include <unistd.h>
extern char **environ;
int execl(const char *path, const char *arg0, ... /*, (char *)0 * /);
int execv(const char *path, char *const argv[]);
int execle(const char *path, const char *arg0, ... /*,
(char *)0, char *const envp[]* /);
int execve(const char *path, char *const argv[], char *const envp[]);
int execlp(const char *file, const char *arg0, ... /*, (char *)0 * /);
int execvp(const char *file, char *const argv[]);
DESCRIPTION
The exec family of functions shall replace the current process image with a
new process image. The new image shall be constructed from a regular,
executable file called the new process image file. There shall be no return
from a successful exec, because the calling process image is overlaid by the
new process image.
When a C-language program is executed as a result of this call, it shall be
entered as a C-language 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.
Conforming multi-threaded applications shall not use the environ variable to
access or modify any environment variable while any other thread is
concurrently modifying any environment variable. A call to any function
dependent on any environment variable shall be considered a use of the
environ variable to access that environment variable.
The arguments specified by a program with one of the exec functions shall be
passed on to the new process image in the corresponding main() arguments.
The argument path points to a pathname that identifies the new process image
file.
The argument file is used to construct a pathname that identifies the new
process image file. If the file argument contains a slash character, the
file argument shall be used as the pathname for this file. Otherwise, the
path prefix for this file is obtained by a search of the directories passed
as the environment variable PATH (see the Base Definitions volume of IEEE
Std 1003.1-2001, Chapter 8, Environment Variables). If this environment
variable is not present, the results of the search are
implementation-defined.
There are two distinct ways in which the contents of the process image file
may cause the execution to fail, distinguished by the setting of errno to
either [ENOEXEC] or [EINVAL] (see the ERRORS section). In the cases where
the other members of the exec family of functions would fail and set errno
to [ENOEXEC], the execlp() and execvp() functions shall execute a command
interpreter and the environment of the executed command shall be as if the
process invoked the sh utility using execl() as follows:
execl(<shell path>, arg0, file, arg1, ..., (char *)0);
where <shell path> is an unspecified pathname for the sh utility, file is
the process image file, and for execvp(), where arg0, arg1, and so on
correspond to the values passed to execvp() in argv[0], argv[1], and so on.
The arguments represented by arg0,... are pointers to null-terminated
character strings. These strings shall constitute the argument list
available to the new process image. The list is terminated by a null
pointer. The argument arg0 should point to a filename that is associated
with the process being started by one of the exec functions.
The argument argv is an array of character pointers to null-terminated
strings. The application shall ensure that the last member of this array is
a null pointer. These strings shall constitute the argument list available
to the new process image. The value in argv[0] should point to a filename
that is associated with the process being started by one of the exec
functions.
The argument envp is an array of character pointers to null-terminated
strings. These strings shall constitute the environment for the new process
image. The envp array is terminated by a null pointer.
For those forms not containing an envp pointer ( execl(), execv(), execlp(),
and execvp()), the environment for the new process image shall be taken from
the external variable environ in the calling process.
The number of bytes available for the new process' combined argument and
environment lists is {ARG_MAX}. It is implementation-defined whether null
terminators, pointers, and/or any alignment bytes are included in this
total.
File descriptors open in the calling process image shall remain open in the
new process image, except for those whose close-on- exec flag FD_CLOEXEC is
set. For those file descriptors that remain open, all attributes of the open
file description remain unchanged. For any file descriptor that is closed
for this reason, file locks are removed as a result of the close as
described in close(). Locks that are not removed by closing of file
descriptors remain unchanged.
If file descriptors 0, 1, and 2 would otherwise be closed after a successful
call to one of the exec family of functions, and the new process image file
has the set-user-ID or set-group-ID file mode bits set, and the ST_NOSUID
bit is not set for the file system containing the new process image file,
implementations may open an unspecified file for each of these file
descriptors in the new process image.
Directory streams open in the calling process image shall be closed in the
new process image.
The state of the floating-point environment in the new process image or in
the initial thread of the new process image shall be set to the default.
The state of conversion descriptors and message catalog descriptors in the
new process image is undefined. For the new process image, the equivalent
of:
setlocale(LC_ALL, "C")
shall be executed at start-up.
Signals set to the default action (SIG_DFL) in the calling process image
shall be set to the default action in the new process image. Except for
SIGCHLD, signals set to be ignored (SIG_IGN) by the calling process image
shall be set to be ignored by the new process image. Signals set to be
caught by the calling process image shall be set to the default action in
the new process image (see <signal.h>). If the SIGCHLD signal is set to be
ignored by the calling process image, it is unspecified whether the SIGCHLD
signal is set to be ignored or to the default action in the new process
image. After a successful call to any of the exec functions, alternate
signal stacks are not preserved and the SA_ONSTACK flag shall be cleared for
all signals.
After a successful call to any of the exec functions, any functions
previously registered by atexit() or pthread_atfork() are no longer
registered.
If the ST_NOSUID bit is set for the file system containing the new process
image file, then the effective user ID, effective group ID, saved
set-user-ID, and saved set-group-ID are unchanged in the new process image.
Otherwise, if the set-user-ID mode bit of the new process image file is set,
the effective user ID of the new process image shall be set to the user 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 shall be 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
shall remain the same as those of the calling process image. The effective
user ID and effective group ID of the new process image shall be saved (as
the saved set-user-ID and the saved set-group-ID) for use by setuid().
Any shared memory segments attached to the calling process image shall not
be attached to the new process image.
Any named semaphores open in the calling process shall be closed as if by
appropriate calls to sem_close().
Any blocks of typed memory that were mapped in the calling process are
unmapped, as if munmap() was implicitly called to unmap them.
Memory locks established by the calling process via calls to mlockall() or
mlock() shall be removed. If locked pages in the address space of the
calling process are also mapped into the address spaces of other processes
and are locked by those processes, the locks established by the other
processes shall be unaffected by the call by this process to the exec
function. If the exec function fails, the effect on memory locks is
unspecified.
Memory mappings created in the process are unmapped before the address space
is rebuilt for the new process image.
When the calling process image does not use the SCHED_FIFO, SCHED_RR, or
SCHED_SPORADIC scheduling policies, the scheduling policy and parameters of
the new process image and the initial thread in that new process image are
implementation-defined.
When the calling process image uses the SCHED_FIFO, SCHED_RR, or
SCHED_SPORADIC scheduling policies, the process policy and scheduling
parameter settings shall not be changed by a call to an exec function. The
initial thread in the new process image shall inherit the process scheduling
policy and parameters. It shall have the default system contention scope,
but shall inherit its allocation domain from the calling process image.
Per-process timers created by the calling process shall be deleted before
replacing the current process image with the new process image.
All open message queue descriptors in the calling process shall be closed,
as described in mq_close().
Any outstanding asynchronous I/O operations may be canceled. Those
asynchronous I/O operations that are not canceled shall complete as if the
exec function had not yet occurred, but any associated signal notifications
shall be suppressed. It is unspecified whether the exec function itself
blocks awaiting such I/O completion. In no event, however, shall the new
process image created by the exec function be affected by the presence of
outstanding asynchronous I/O operations at the time the exec function is
called. Whether any I/O is canceled, and which I/O may be canceled upon
exec, is implementation-defined.
The new process image shall inherit the CPU-time clock of the calling
process image. This inheritance means that the process CPU-time clock of the
process being exec-ed shall not be reinitialized or altered as a result of
the exec function other than to reflect the time spent by the process
executing the exec function itself.
The initial value of the CPU-time clock of the initial thread of the new
process image shall be set to zero.
If the calling process is being traced, the new process image shall continue
to be traced into the same trace stream as the original process image, but
the new process image shall not inherit the mapping of trace event names to
trace event type identifiers that was defined by calls to the
posix_trace_eventid_open() or the posix_trace_trid_eventid_open() functions
in the calling process image.
If the calling process is a trace controller process, any trace streams that
were created by the calling process shall be shut down as described in the
posix_trace_shutdown() function.
The thread ID of the initial thread in the new process image is unspecified.
The size and location of the stack on which the initial thread in the new
process image runs is unspecified.
The initial thread in the new process image shall have its cancellation type
set to PTHREAD_CANCEL_DEFERRED and its cancellation state set to
PTHREAD_CANCEL_ENABLED.
The initial thread in the new process image shall have all thread-specific
data values set to NULL and all thread-specific data keys shall be removed
by the call to exec without running destructors.
The initial thread in the new process image shall be joinable, as if created
with the detachstate attribute set to PTHREAD_CREATE_JOINABLE.
The new process shall inherit at least the following attributes from the
calling process image:
Nice value (see nice())
semadj values (see semop())
Process ID
Parent process ID
Process group ID
Session membership
Real user ID
Real group ID
Supplementary group IDs
Time left until an alarm clock signal (see alarm())
Current working directory
Root directory
File mode creation mask (see umask())
File size limit (see ulimit())
Process signal mask (see sigprocmask())
Pending signal (see sigpending())
tms_utime, tms_stime, tms_cutime, and tms_cstime (see times())
Resource limits
Controlling terminal
Interval timers
The initial thread of the new process shall inherit at least the following
attributes from the calling thread:
Signal mask (see sigprocmask() and pthread_sigmask())
Pending signals (see sigpending())
All other process attributes defined in this volume of IEEE Std 1003.1-2001
shall be inherited in the new process image from the old process image. All
other thread attributes defined in this volume of IEEE Std 1003.1-2001 shall
be inherited in the initial thread in the new process image from the calling
thread in the old process image. The inheritance of process or thread
attributes not defined by this volume of IEEE Std 1003.1-2001 is
implementation-defined.
A call to any exec function from a process with more than one thread shall
result in all threads being terminated and the new executable image being
loaded and executed. No destructor functions or cleanup handlers shall be
called.
Upon successful completion, the exec functions shall mark for update the
st_atime field of the file. If an exec function failed but was able to
locate the process image file, whether the st_atime field is marked for
update is unspecified. Should the exec function succeed, the process image
file shall be considered to have been opened with open(). The corresponding
close() shall be considered to occur at a time after this open, but before
process termination or successful completion of a subsequent call to one of
the exec functions, posix_spawn(), or posix_spawnp(). The argv[] and envp[]
arrays of pointers and the strings to which those arrays point shall not be
modified by a call to one of the exec functions, except as a consequence of
replacing the process image.
The saved resource limits in the new process image are set to be a copy of
the process' corresponding hard and soft limits.
RETURN VALUE
If one of the exec functions returns to the calling process image, an error
has occurred; the return value shall be -1, and errno shall be set to
indicate the error.
ERRORS
The exec functions shall fail if:
[E2BIG]
The number of bytes used by the new process image's argument list and
environment list is greater than the system-imposed limit of {ARG_MAX}
bytes.
[EACCES]
Search permission is denied for a directory listed in the new process
image file's path prefix, 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.
[EINVAL]
The new process image file has the appropriate permission and has a
recognized executable binary format, but the system does not support
execution of a file with this format.
[ELOOP]
A loop exists in symbolic links encountered during resolution of the
path or file argument.
[ENAMETOOLONG]
The length of the path or file arguments exceeds {PATH_MAX} or a
pathname component is longer than {NAME_MAX}.
[ENOENT]
A component of path or file does not name an existing file or path or
file is an empty string.
[ENOTDIR]
A component of the new process image file's path prefix is not a
directory.
The exec functions, except for execlp() and execvp(), shall fail if:
[ENOEXEC]
The new process image file has the appropriate access permission but has
an unrecognized format.
The exec functions may fail if:
[ELOOP]
More than {SYMLOOP_MAX} symbolic links were encountered during
resolution of the path or file argument.
[ENAMETOOLONG]
As a result of encountering a symbolic link in resolution of the path
argument, the length of the substituted pathname string exceeded
{PATH_MAX}.
[ENOMEM]
The new process image requires more memory than is allowed by the
hardware or system-imposed memory management constraints.
[ETXTBSY]
The new process image file is a pure procedure (shared text) file that
is currently open for writing by some process.
*/
specification
void execl_spec( CallContext context, CString * path, List /* CString */ * argv )
{
pre
{
/* [Local variable initialization] */
ProcessState * process_state = getProcessState_CallContext( context );
/* [Consistency of test suite] */
REQ( "", "Process state exists" , process_state != NULL );
REQ( "", "path point to pathname" , path != NULL );
REQ( "", "argv correspond to array", argv != NULL );
/*
* The arguments represented by arg0,... are pointers to null-terminated character
* strings.
*/
REQ( "app.execl.01.01", "", true );
/*
* These strings shall constitute the argument list available to the new process
* image.
*
* The list is terminated by a null pointer.
*/
REQ( "app.execl.01.02", "", true );
/*
* These strings shall constitute the argument list available to the new process
* image.
*
* The argument arg0 should point to a filename that is associated with the
* process being started by one of the exec functions.
*/
REQ( "app.execl.01.03",
"arg0 should point to a filename",
T( size_List( argv ) >= 1 ) && T( equals( get_List( argv, 0 ), create_CString( "agent" ) ) )
);
/* [Restriction from agent] */
REQ( "", "Restriction from agent on argv", size_List( argv ) <= 10 );
return true;
}
coverage C_Priority
{
if ( processReallyHaveHighPriority( context ) )
{
return { PriorityIsReallyHigh, "Process with high priority" };
}
else if ( processReallyHaveLowPriority( context ) )
{
return { PriorityIsReallyLow, "Process with low priority" };
}
else
{
return { PriorityIsUnknown, "Process with unknown priority" };
}
}
coverage C_Path
{
if ( length_CString( path ) == 0 )
{
return { PathIsEmpty, "path is empty" };
}
else
{
return { PathIsNotEmpty, "path is not empty" };
}
}
coverage C_Argv
{
if ( size_List( argv ) == 1 )
{
return { OnlyProgramName, "only program name" };
}
else
{
return { ProgramNameAndArguments, "program name and arguments" };
}
}
post
{
return true;
}
}
/*
Linux Standard Base Core Specification 3.1
Copyright (c) 2004, 2005 Free Standards Group
refers
The Open Group Base Specifications Issue 6
IEEE Std 1003.1, 2004 Edition
Copyright (c) 2001-2004 The IEEE and The Open Group, All Rights reserved.
NAME
environ, execl, execv, execle, execve, execlp, execvp - execute a file
SYNOPSIS
#include <unistd.h>
extern char **environ;
int execl(const char *path, const char *arg0, ... /*, (char *)0 * /);
int execv(const char *path, char *const argv[]);
int execle(const char *path, const char *arg0, ... /*,
(char *)0, char *const envp[]* /);
int execve(const char *path, char *const argv[], char *const envp[]);
int execlp(const char *file, const char *arg0, ... /*, (char *)0 * /);
int execvp(const char *file, char *const argv[]);
DESCRIPTION
The exec family of functions shall replace the current process image with a
new process image. The new image shall be constructed from a regular,
executable file called the new process image file. There shall be no return
from a successful exec, because the calling process image is overlaid by the
new process image.
When a C-language program is executed as a result of this call, it shall be
entered as a C-language 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.
Conforming multi-threaded applications shall not use the environ variable to
access or modify any environment variable while any other thread is
concurrently modifying any environment variable. A call to any function
dependent on any environment variable shall be considered a use of the
environ variable to access that environment variable.
The arguments specified by a program with one of the exec functions shall be
passed on to the new process image in the corresponding main() arguments.
The argument path points to a pathname that identifies the new process image
file.
The argument file is used to construct a pathname that identifies the new
process image file. If the file argument contains a slash character, the
file argument shall be used as the pathname for this file. Otherwise, the
path prefix for this file is obtained by a search of the directories passed
as the environment variable PATH (see the Base Definitions volume of IEEE
Std 1003.1-2001, Chapter 8, Environment Variables). If this environment
variable is not present, the results of the search are
implementation-defined.
There are two distinct ways in which the contents of the process image file
may cause the execution to fail, distinguished by the setting of errno to
either [ENOEXEC] or [EINVAL] (see the ERRORS section). In the cases where
the other members of the exec family of functions would fail and set errno
to [ENOEXEC], the execlp() and execvp() functions shall execute a command
interpreter and the environment of the executed command shall be as if the
process invoked the sh utility using execl() as follows:
execl(<shell path>, arg0, file, arg1, ..., (char *)0);
where <shell path> is an unspecified pathname for the sh utility, file is
the process image file, and for execvp(), where arg0, arg1, and so on
correspond to the values passed to execvp() in argv[0], argv[1], and so on.
The arguments represented by arg0,... are pointers to null-terminated
character strings. These strings shall constitute the argument list
available to the new process image. The list is terminated by a null
pointer. The argument arg0 should point to a filename that is associated
with the process being started by one of the exec functions.
The argument argv is an array of character pointers to null-terminated
strings. The application shall ensure that the last member of this array is
a null pointer. These strings shall constitute the argument list available
to the new process image. The value in argv[0] should point to a filename
that is associated with the process being started by one of the exec
functions.
The argument envp is an array of character pointers to null-terminated
strings. These strings shall constitute the environment for the new process
image. The envp array is terminated by a null pointer.
For those forms not containing an envp pointer ( execl(), execv(), execlp(),
and execvp()), the environment for the new process image shall be taken from
the external variable environ in the calling process.
The number of bytes available for the new process' combined argument and
environment lists is {ARG_MAX}. It is implementation-defined whether null
terminators, pointers, and/or any alignment bytes are included in this
total.
File descriptors open in the calling process image shall remain open in the
new process image, except for those whose close-on- exec flag FD_CLOEXEC is
set. For those file descriptors that remain open, all attributes of the open
file description remain unchanged. For any file descriptor that is closed
for this reason, file locks are removed as a result of the close as
described in close(). Locks that are not removed by closing of file
descriptors remain unchanged.
If file descriptors 0, 1, and 2 would otherwise be closed after a successful
call to one of the exec family of functions, and the new process image file
has the set-user-ID or set-group-ID file mode bits set, and the ST_NOSUID
bit is not set for the file system containing the new process image file,
implementations may open an unspecified file for each of these file
descriptors in the new process image.
Directory streams open in the calling process image shall be closed in the
new process image.
The state of the floating-point environment in the new process image or in
the initial thread of the new process image shall be set to the default.
The state of conversion descriptors and message catalog descriptors in the
new process image is undefined. For the new process image, the equivalent
of:
setlocale(LC_ALL, "C")
shall be executed at start-up.
Signals set to the default action (SIG_DFL) in the calling process image
shall be set to the default action in the new process image. Except for
SIGCHLD, signals set to be ignored (SIG_IGN) by the calling process image
shall be set to be ignored by the new process image. Signals set to be
caught by the calling process image shall be set to the default action in
the new process image (see <signal.h>). If the SIGCHLD signal is set to be
ignored by the calling process image, it is unspecified whether the SIGCHLD
signal is set to be ignored or to the default action in the new process
image. After a successful call to any of the exec functions, alternate
signal stacks are not preserved and the SA_ONSTACK flag shall be cleared for
all signals.
After a successful call to any of the exec functions, any functions
previously registered by atexit() or pthread_atfork() are no longer
registered.
If the ST_NOSUID bit is set for the file system containing the new process
image file, then the effective user ID, effective group ID, saved
set-user-ID, and saved set-group-ID are unchanged in the new process image.
Otherwise, if the set-user-ID mode bit of the new process image file is set,
the effective user ID of the new process image shall be set to the user 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 shall be 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
shall remain the same as those of the calling process image. The effective
user ID and effective group ID of the new process image shall be saved (as
the saved set-user-ID and the saved set-group-ID) for use by setuid().
Any shared memory segments attached to the calling process image shall not
be attached to the new process image.
Any named semaphores open in the calling process shall be closed as if by
appropriate calls to sem_close().
Any blocks of typed memory that were mapped in the calling process are
unmapped, as if munmap() was implicitly called to unmap them.
Memory locks established by the calling process via calls to mlockall() or
mlock() shall be removed. If locked pages in the address space of the
calling process are also mapped into the address spaces of other processes
and are locked by those processes, the locks established by the other
processes shall be unaffected by the call by this process to the exec
function. If the exec function fails, the effect on memory locks is
unspecified.
Memory mappings created in the process are unmapped before the address space
is rebuilt for the new process image.
When the calling process image does not use the SCHED_FIFO, SCHED_RR, or
SCHED_SPORADIC scheduling policies, the scheduling policy and parameters of
the new process image and the initial thread in that new process image are
implementation-defined.
When the calling process image uses the SCHED_FIFO, SCHED_RR, or
SCHED_SPORADIC scheduling policies, the process policy and scheduling
parameter settings shall not be changed by a call to an exec function. The
initial thread in the new process image shall inherit the process scheduling
policy and parameters. It shall have the default system contention scope,
but shall inherit its allocation domain from the calling process image.
Per-process timers created by the calling process shall be deleted before
replacing the current process image with the new process image.
All open message queue descriptors in the calling process shall be closed,
as described in mq_close().
Any outstanding asynchronous I/O operations may be canceled. Those
asynchronous I/O operations that are not canceled shall complete as if the
exec function had not yet occurred, but any associated signal notifications
shall be suppressed. It is unspecified whether the exec function itself
blocks awaiting such I/O completion. In no event, however, shall the new
process image created by the exec function be affected by the presence of
outstanding asynchronous I/O operations at the time the exec function is
called. Whether any I/O is canceled, and which I/O may be canceled upon
exec, is implementation-defined.
The new process image shall inherit the CPU-time clock of the calling
process image. This inheritance means that the process CPU-time clock of the
process being exec-ed shall not be reinitialized or altered as a result of
the exec function other than to reflect the time spent by the process
executing the exec function itself.
The initial value of the CPU-time clock of the initial thread of the new
process image shall be set to zero.
If the calling process is being traced, the new process image shall continue
to be traced into the same trace stream as the original process image, but
the new process image shall not inherit the mapping of trace event names to
trace event type identifiers that was defined by calls to the
posix_trace_eventid_open() or the posix_trace_trid_eventid_open() functions
in the calling process image.
If the calling process is a trace controller process, any trace streams that
were created by the calling process shall be shut down as described in the
posix_trace_shutdown() function.
The thread ID of the initial thread in the new process image is unspecified.
The size and location of the stack on which the initial thread in the new
process image runs is unspecified.
The initial thread in the new process image shall have its cancellation type
set to PTHREAD_CANCEL_DEFERRED and its cancellation state set to
PTHREAD_CANCEL_ENABLED.
The initial thread in the new process image shall have all thread-specific
data values set to NULL and all thread-specific data keys shall be removed
by the call to exec without running destructors.
The initial thread in the new process image shall be joinable, as if created
with the detachstate attribute set to PTHREAD_CREATE_JOINABLE.
The new process shall inherit at least the following attributes from the
calling process image:
Nice value (see nice())
semadj values (see semop())
Process ID
Parent process ID
Process group ID
Session membership
Real user ID
Real group ID
Supplementary group IDs
Time left until an alarm clock signal (see alarm())
Current working directory
Root directory
File mode creation mask (see umask())
File size limit (see ulimit())
Process signal mask (see sigprocmask())
Pending signal (see sigpending())
tms_utime, tms_stime, tms_cutime, and tms_cstime (see times())
Resource limits
Controlling terminal
Interval timers
The initial thread of the new process shall inherit at least the following
attributes from the calling thread:
Signal mask (see sigprocmask() and pthread_sigmask())
Pending signals (see sigpending())
All other process attributes defined in this volume of IEEE Std 1003.1-2001