Исходные коды спецификаций для LSB Core 3.1

/*
 * 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