#script executed on the first reserved node
# Exit codes are:
#     - 0: everything worked normally
#     - 1: prologue error (exit value not equal to 0 or timeout exceeded)
#     - 2: epilogue error (exit value not equal to 0 or timeout exceeded)
#     - 3: this script was killed by Leon normally
#     - 4: this script was killed by Leon normally and epilogue was in error (like for 2)
#     - 5: this script was not able to create the node file
#     - 6: this script was not able to create the pid file
#     - 7: cannot get the shell value for the user
#     - 8: this script was not able to create tmp directory
#     - 12: cannot go into the launching directory of the job and epilogue was in error
#     - 10: cannot go into the launching directory of the job
#     - 20: cannot create STDOUT and STDERR files
#     - 22: cannot create STDOUT and STDERR files and epilogue was in error
#     - 30: timeout of the bipbip hashtable send
#     - 33: oarexec was stopped normally via USR1 signal but there was an epilogue error
#     - 34: all worked normally and this is the result of an USR1 signal
#     - 40: all worked normally and the user process received the checkpoint signal
#     - 41: oarexec has sent the checkpoint signal but there was an epilogue error
#     - 42: oarexec has sent the user defined signal (oardel -s)
#
# The exit code is sent to the Almighty via its TCP socket
#
# oarexec read a hashtable from bipbip, execute the prologue and then close STD file descriptor + fork a child and kill itself.
# So the SSH return just after job initialisation and prologue

BEGIN{
    if (!defined(&OAR::Tools::get_all_process_children())){
        require(OAR::Tools);
    }
}

use strict;
use Sys::Hostname;
use POSIX qw(:signal_h :errno_h :sys_wait_h strftime);

my $Old_umask = sprintf("%lo",umask());
umask(oct("022"));

$SIG{PIPE} = 'IGNORE';
$SIG{HUP} = 'IGNORE';
# To deblock sshd father when oardel in suspended state
$SIG{CONT} = sub{
    kill('CONT',getppid());
};

my $Job_id = shift;

$| = 1;
# block signals until we define the handlers
my $sigset   = POSIX::SigSet->new;
my $Blockset = POSIX::SigSet->new(SIGINT, SIGTERM, SIGQUIT, SIGCHLD, SIGUSR2, SIGUSR1);
sigprocmask(SIG_BLOCK, $Blockset, $sigset);

my $Bin_Path = $ENV{OARDIR}."/";
my $Tmp_file_prefix;

my $Debug_mode;
my $Node_file;
my $Res_file;
my $Pid_file;
my $Kill_myself = 0;
my $Oarexec_exit_code = 0;
my $Exit_script_code = 'N';

# Run script: prologue, epilogue or passive job hook
sub run_script($$$) {
    my $script_name = shift;
    my $script_cmd = shift;
    my $script_timeout = shift;
    my $script_error = -1;
    eval {
        my $pid;
        $SIG{ALRM} = sub { kill(9,$pid); die "alarm\n" };
        print("[oarexec] LAUNCH $script_name: $script_cmd\n");
        alarm($script_timeout);
        my $sigchld_handler = $SIG{CHLD};
        $SIG{CHLD} = 'DEFAULT';
        $pid = fork();
        if($pid == 0){
            #CHILD
            $SIG{ALRM} = 'DEFAULT';
            exec($script_cmd);
            warn("[ERROR] cannot execute $script_name\n");
            exit(-1);
        }
        my $wait_res = -1;
        # Avoid being disturbed by a signal
        while ((defined($pid)) and ($wait_res != $pid)){
            $wait_res = waitpid($pid,0);
            $script_error = $?;
        }
        $SIG{CHLD} = $sigchld_handler;
        alarm(0);
        print("[oarexec] END $script_name\n");
    };
    return ($script_error, $@);
}

#Notify Almighty.
#arg1 --> exit value
sub quit_oarexec($$){
    my $exit_value = shift;
    my $job_data = shift;
    
    if ($job_data->{detach_oarexec} == 1){
        # We must contact Almighty
        my $max_wait_time = 900;
        my $wait_time = 30;
        my $max_retry = 48;
        my $nb_retry = 0;
    
        while (1){
            my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst)=localtime(time);
            my $string = sprintf("%02d:%02d:%02d", $hour,$min,$sec);
            if (!defined(OAR::Tools::notify_tcp_socket($job_data->{almighty_hostname},$job_data->{almighty_port},"OAREXEC_$job_data->{job_id}"."_$exit_value"."_$Exit_script_code"."_$job_data->{challenge}"))){
                if ((defined($job_data->{cpuset_full_path})) and ($nb_retry < $max_retry)){
                    print("[oarexec] [$string] notified Almighty with exit value $exit_value and retry in $max_wait_time seconds if not killed by the cpuset_manager before\n");
                    $wait_time = $max_wait_time;
                }else{
                    print("[oarexec] [$string] notified Almighty with exit value $exit_value and exit\n");
                    exit($exit_value);
                }
                $nb_retry++;
            }else{
                print("[oarexec] cannot notify Almighty: server down or network error\n");
            }
            sleep($wait_time);
            if ($wait_time < $max_wait_time){
                $wait_time = 2 * $wait_time;
                if ($wait_time > $max_wait_time){
                    $wait_time = $max_wait_time;
                }
            }
        }
    }
    
    exit($exit_value);
}



#delete temporary file
sub clean_all(){
    #system("rm -f $OAR_FILE_NODES $oarPidFile");
    unlink($Node_file,$Res_file,$Pid_file,OAR::Tools::get_oar_user_signal_file_name($Job_id));
    # Kill oarsub connections
    my $file = OAR::Tools::get_oarsub_connections_file_name($Job_id);
    if (open(OARSUBS,$file)){
        while ($_ = <OARSUBS>){
            if ($_ =~ m/^(\d+)$/m){
                my $ppid = $1;
                my ($children,$cmd_name) = OAR::Tools::get_one_process_children($ppid);
                my @pid_list = @{$children};
                if ($cmd_name =~ /OAR_JOBID=$Job_id\D/m){
                    # remove ppid
                    print("[oarexec] kill oarsub processes: @pid_list\n");
                    system({"oardodo"} "oardodo","kill","-9",@pid_list) if ($#pid_list >= 0);
                }else{
                    print("[oarexec] want to kill oarsub connections @pid_list BUT it seems there is no OAR oarsub processes\n");
                }
            }
        }
        close(OARSUBS);
    }
    unlink($file);

    # Delete unwanted children
    my ($children,$cmd_name) = OAR::Tools::get_one_process_children($$);
    shift(@{$children});
    kill(9,@{$children});
}

#kill all child of the pid
# arg1 --> child pid
sub kill_children($){
    my $child_pid = shift;

    my ($children, $cmd_name) = OAR::Tools::get_one_process_children($child_pid);
    system({"oardodo"} "oardodo","kill","-9",@{$children});
}

sub send_kill_signal_to_myself($){
    my $signal_to_send = shift;

    my $father = $$;
    my $pid=fork;
    if($pid==0){
        sleep(5);
        kill($signal_to_send, $father);
        exit();
    }
}

# Append a string to a file owned by a user
sub append_string_to_user_file($$$$){
    my ($user, $file, $dir, $str) = @_;
   
    $str = "## OAR [".strftime("%F %T",localtime())."] $str ##";
    system({"bash"} "bash","-c","echo '$str' | OARDO_BECOME_USER=$user oardodo bash --noprofile --norc -c \"cd '$dir' && tee -a '$file'\"");
}

# Retrieve job information from bipbip
my $Job;
my $tmp = "";
eval {
    $SIG{ALRM} = sub { die "alarm\n" };
    alarm(OAR::Tools::get_bipbip_ssh_hashtable_send_timeout());
    while (<STDIN>){
        $tmp .= $_;
    }
    $Job = eval($tmp);
    alarm(0);
};
if( $@ ){
    print("[oarexec] timeout in the job hashtable retrieval\n");
    exit(30);
}
if (!defined($Job->{job_id})){
    print("[oarexec] received dump\n");
    print("[oarexec] $tmp\n");
    print("[oarexec] end of dump\n");
    print("[oarexec] invalid job hashtable transfered\n");
    exit(31);
}

my $host = hostname();

print("[oarexec] user: $Job->{job_user}, launch directory: $Job->{launching_directory}\n");

OAR::Tools::set_default_oarexec_directory($Job->{tmp_directory});
$Tmp_file_prefix = OAR::Tools::get_default_oarexec_directory();
# Test if OAR directory exists and is owned by oar or if we can create it
if (!(((-d $Tmp_file_prefix) and (-O $Tmp_file_prefix)) or (mkdir($Tmp_file_prefix)))){
    print("[oarexec] directory $Tmp_file_prefix does not exist, cannot create it\n");
    exit(8);
}
chdir($Tmp_file_prefix);

#create node set file
$Node_file = "$Tmp_file_prefix/$Job_id";
if (! open(FILE,">$Node_file")){
    print("[oarexec] cannot write file $Node_file\n");
    exit(5);
}
#Feed the node file
my @tmp_res;
my %tmp_already_there;
foreach my $r (@{$Job->{resources}}){
    if (($r->{$Job->{node_file_db_fields}} ne "") and ($r->{type} eq "default")){
        if (($r->{$Job->{node_file_db_fields_distinct_values}} ne "") and (!defined($tmp_already_there{$r->{$Job->{node_file_db_fields_distinct_values}}}))){
            push(@tmp_res, $r->{$Job->{node_file_db_fields}});
            $tmp_already_there{$r->{$Job->{node_file_db_fields_distinct_values}}} = 1;
        }
    }
}
foreach my $f (sort(@tmp_res)){
    print(FILE "$f\n") or exit(5);
}
close(FILE);

#create resource set file
$Res_file = "$Tmp_file_prefix/$Job_id"."_resources";
if (! open(FILE,">$Res_file")){
    print("[oarexec] cannot write file $Res_file\n");
    exit(5);
}
#Feed the resource file
foreach my $r (@{$Job->{resources}}){
    my $line = "";
    foreach my $p (keys(%{$r})){
        if(OAR::Tools::check_resource_system_property($p) != 1){
            $r->{$p} = "" if (!defined($r->{$p}));
            $line .= " $p = '$r->{$p}' ,"
        }
    }
    chop($line);
    print(FILE "$line\n") or exit(5);
}
close(FILE);

print("[oarexec] job command name: [$Job->{command}]\n");

if (defined($Job->{prologue})){
    # Launch prologue script
    my ($script_error, $eval_error) = run_script("prologue", "$Job->{prologue} $Job_id $Job->{job_user} $Node_file $Job->{walltime_seconds}", $Job->{pro_epi_timeout});
    if( $eval_error || ($script_error != 0)){
        print("[oarexec] prologue error: $eval_error; return code = $script_error\n");
        clean_all();
        exit(1);
    }
}

# Get user shell
my @pass_info = getpwnam($Job->{job_user});
my $shell = $pass_info[8];
if (!defined($shell)){
    clean_all();
    print("[oarexec] error: user $Job->{job_user} does not exist on this node, $host\n");
    exit(7);
}
my $uid = $pass_info[2];

my @cmd;
my $stdin_script_to_send;
my $oardo_become_user = $Job->{job_user};
if ( $Job->{mode} eq "PASSIVE" ){
    my $str;
    ($str, $stdin_script_to_send) = OAR::Tools::get_oarexecuser_perl_script_for_oarexec($Node_file,$Job_id,$Job->{array_id},$Job->{array_index},$Job->{user},$shell,$Job->{launching_directory},$Job->{stdout_file},$Job->{stderr_file},$Res_file,$Job->{name},$Job->{project},$Job->{walltime},$Job->{walltime_seconds},$Job->{job_env},$Job->{command});
    @cmd = ("oardodo","perl","-e",$str);
    if ((defined($Job->{types}->{deploy}) or defined($Job->{types}->{cosystem})) and defined($Job->{deploy_cosystem_job_exec_system})) {
        if ($Job->{deploy_cosystem_job_exec_system} eq "systemd-run") {
            $oardo_become_user = "";
            @cmd = ("oardodo","systemd-run","-q","--uid=$uid","--scope","--collect","--slice=user-$uid.slice","perl","-e",$str);
        } elsif ($Job->{deploy_cosystem_job_exec_system} eq "none") {
            # Use regular command by default
        }
    }
}

#resolve terminal type problems
my $terminal = $ENV{TERM};
if (($terminal ne "") and ($terminal ne "unknown")){
    $ENV{TERM} = $terminal;
}else{
    $ENV{TERM} = "xterm";
}

#oar own the tty
#so we must change owner for the user
system({"bash"} "bash","-c","TTY=\$(tty) && test -e \$TTY && oardodo chown $Job->{job_user}:oar \$TTY && oardodo chmod 660 \$TTY");

# pipe for notify the end of a child process
pipe(pipe_child_read,pipe_child_write);
autoflush pipe_child_write 1;
autoflush pipe_child_read 1;

sub child_signal_handler {
    $SIG{CHLD} = \&child_signal_handler;
    
    my $wait_pid_ret ;
    while (($wait_pid_ret = waitpid(-1,WNOHANG)) > 0){
        my $exit_value = $? >> 8;
        print(pipe_child_write "$wait_pid_ret $exit_value\n");
    }
}
$SIG{CHLD} = \&child_signal_handler;

#For kill signal
pipe(pipe_kill_read,pipe_kill_write);
autoflush pipe_kill_write 1;
autoflush pipe_kill_read 1;

sub user_defined_signal_handler {
    $SIG{URG} = \&user_defined_signal_handler;

    print("[oarexec] user defined signal handler of @_\n");
    my $signal;
    open(FILE, OAR::Tools::get_oar_user_signal_file_name($Job_id));
    while (<FILE>) {
        $signal = $_;
    }
    close(FILE);
    print(pipe_kill_write "SIGNAL_$signal\n");
}
$SIG{URG} = \&user_defined_signal_handler;

sub kill_signal_handler {
    $SIG{TERM} = \&kill_signal_handler;
    $SIG{INT} = \&kill_signal_handler;
    $SIG{QUIT} = \&kill_signal_handler;

    print("[oarexec] kill signal handler of @_\n");
    print(pipe_kill_write "KILL\n");
}

$SIG{TERM} = \&kill_signal_handler;
$SIG{INT} = \&kill_signal_handler;
$SIG{QUIT} = \&kill_signal_handler;

sub stop_signal_handler {
    $SIG{USR1} = \&stop_signal_handler;

    print("[oarexec] stop signal handler of @_\n");
    print(pipe_kill_write "STOP\n");
}

$SIG{USR1} = \&stop_signal_handler;

sub checkpoint_signal_handler {
    $SIG{USR2} = \&checkpoint_signal_handler;

    print("[oarexec] checkpoint signal handler of @_\n");
    print(pipe_kill_write "CHECKPOINT\n");
}

$SIG{USR2} = \&checkpoint_signal_handler;

if ($Job->{detach_oarexec} == 1){
    #Detach process from bipbip SSH
    print("[oarexec] detaching the oarexec process\n");

    if(fork() != 0){
        print(OAR::Tools::get_bipbip_oarexec_rendez_vous());
        # Exit from main oarexec
        exit(0);
    }
    # We must redirect STD to close SSH
    open(STDIN, "/dev/zero");
    if ($Job->{debug_mode} > 0){
        open(STDOUT, ">>$Tmp_file_prefix/oar.log");
        open(STDERR, ">>$Tmp_file_prefix/oar.log");
    }else{
        open(STDOUT, ">/dev/null");
        open(STDERR, ">/dev/null");
    }
}else{
    print(OAR::Tools::get_bipbip_oarexec_rendez_vous());
}

#Write file with this oarexec pid
$Pid_file = OAR::Tools::get_oar_pid_file_name($Job_id);
if ((!open(FILEPID,">$Pid_file")) or (!print(FILEPID "$$"))){
    print("[oarexec] cannot write file $Pid_file\n");
    clean_all();
    quit_oarexec(6,$Job);
}
close(FILEPID);

sigprocmask(SIG_UNBLOCK, $Blockset);

my $pid = $$;
my $rin_script = '';
if ($Job->{mode} eq "PASSIVE"){
    # For parsing script outputs
    pipe(pipe_script_read,pipe_script_write);
    autoflush pipe_script_write 1;
    autoflush pipe_script_read 1;
    vec($rin_script,fileno(pipe_script_read),1) = 1;
    # To send command line
    pipe(pipe_stdin_read,pipe_stdin_write);
    autoflush pipe_stdin_write 1;
    autoflush pipe_stdin_read 1;
    #print("[oarexec] Launch the command: $cmd\n");
    $pid = fork;
    if($pid == 0){
        #CHILD
        # Run the job script hook if any
        if (defined($Job->{passive_job_hook}) && -x $Job->{passive_job_hook}) {
            my ($script_error, $eval_error) = run_script("passive job hook", "oardodo $Job->{passive_job_hook} \$PPID,\$\$:$Job->{user}:$Job_id:$Job->{name}:$Job->{project}:$Job->{walltime_seconds}", $Job->{pro_epi_timeout});
            if ($eval_error || ($script_error != 0)){
                warn("[oarexec] passive job hook error: $eval_error; return code = $script_error\n");
                exit(-1);
            }
        }
        # Setup the environment for the job script execution 
        $SIG{CHLD} = 'DEFAULT';
        $SIG{TERM} = 'DEFAULT';
        $SIG{INT}  = 'DEFAULT';
        $SIG{QUIT} = 'DEFAULT';
        $SIG{USR1} = 'DEFAULT';
        $SIG{USR2} = 'DEFAULT';
        $SIG{PIPE} = 'DEFAULT';
        $SIG{HUP} = 'DEFAULT';

        print("[oarexec] child exec: @cmd\n");
        close(pipe_script_read);
        close(STDOUT);
        # Redirect script output into the pipe
        open(STDOUT, ">& pipe_script_write");
        
        # Use the child STDIN to send the user command
        close(pipe_stdin_write);
        close(STDIN);
        open(STDIN, "<& pipe_stdin_read");

        $ENV{OARDO_BECOME_USER} = $oardo_become_user;
        umask(oct($Old_umask));
        exec(@cmd);
        warn("[ERROR] Cannot find @cmd\n");
        exit(-1);
    }
    close(pipe_script_write);
    close(pipe_stdin_read);
    # Send user command without any interpretation security isssue!!!
    #print("[oarexec] ########### $stdin_script_to_send\n");
    # This is the most secure manner that I find
    print(pipe_stdin_write $stdin_script_to_send."\n");
    open(pipe_stdin_write,"<& /dev/null");
}

print("[oarexec] child pid = $pid\n");

my $res_read;
my $line_read;
my $rin = '';
my $rin_sig = '';
my $rin_pipe = '';
vec($rin_sig,fileno(pipe_kill_read),1) = 1;
vec($rin_pipe,fileno(pipe_child_read),1) = 1;
$rin = $rin_sig | $rin_pipe | $rin_script;
my $rin_tmp;
my $Stop_signal = 0;
my $Checkpoint_signal = 0;
my $user_signal = 0;
my $stop_loop = 0;
my $user_cmd_pid = -1;
# wait end of the child process or KILL notification
while (($line_read != $pid) and ($Stop_signal == 0) and ($stop_loop == 0)){
    print("[oarexec] wait end of child process or kill notification\n");
    select($rin_tmp = $rin, undef, undef, undef);
    
    if (vec($rin_tmp, fileno(pipe_script_read), 1)){
        ($res_read,$line_read) = OAR::Tools::read_socket_line(\*pipe_script_read,1);
        if (($res_read == 1) and ($line_read eq "")){
            # Script is finished
            close(pipe_script_read);
            close(pipe_stdin_write);
        }else{
            print("[oarexec] PIPE writes: $res_read,$line_read\n");
            if ($line_read =~ /^EXIT_CODE\s(\d+)$/){
                $Exit_script_code = $1;
                print("OAREXEC_SCRIPT_EXIT_VALUE $Exit_script_code\n");
            }elsif ($line_read =~ /^USER_CMD_PID\s(\d+)$/){
                $user_cmd_pid = $1;
                print("[oarexec] user command PID = $user_cmd_pid\n");
            }
        }
    }elsif (vec($rin_tmp, fileno(pipe_child_read), 1)){
        ($res_read,$line_read) = OAR::Tools::read_socket_line(\*pipe_child_read,1);
        print("[oarexec] PIPE reads: $res_read,$line_read\n");
        if ($line_read =~ m/(\d+) (\d+)/m){
            if ($1 == $pid){
                print("[oarexec] reset CHLD signal handler\n");
                $line_read = $pid;
                $Oarexec_exit_code = $2 * 10;
            }
        }
    }elsif (vec($rin_tmp, fileno(pipe_kill_read), 1)){
        ($res_read,$line_read) = OAR::Tools::read_socket_line(\*pipe_kill_read,1);
        print("[oarexec] pipe kill signal: $res_read,$line_read\n");
        if ($line_read eq "KILL"){
            print("[oarexec] kill children\n");
            if ($Job->{mode} eq "INTERACTIVE"){
                $stop_loop = 1;
            }else{
                kill_children($pid);
                if (defined($Job->{stderr_file}) and ($Job->{stderr_file} ne "")){
                    append_string_to_user_file($Job->{job_user}, $Job->{stderr_file}, $Job->{launching_directory}, "Job $Job_id KILLED");
                }
            }
            $Kill_myself = 1;
        }elsif ($line_read eq "STOP"){
            print("[oarexec] received STOP notification\n");
            if ($Job->{mode} eq "INTERACTIVE"){
                $Stop_signal = 1;
            }else{
                print("[oarexec] Received USR1 signal: someone wants to finish the job but it is not INTERACTIVE\n");
            }
        }elsif ($line_read eq "CHECKPOINT"){
            #We must send the signal defined by oarsub to the child of $pid
            if ($user_cmd_pid >= 0){
                print("[oarexec] checkpoint received, send signal $Job->{checkpoint_signal} to the pid $user_cmd_pid\n");
                system({"oardodo"} "oardodo","kill","-s",$Job->{checkpoint_signal},$user_cmd_pid);
                if (defined($Job->{stderr_file}) and ($Job->{stderr_file} ne "")){
                    append_string_to_user_file($Job->{job_user}, $Job->{stderr_file}, $Job->{launching_directory}, "Job $Job_id CHECKPOINTED with signal $Job->{checkpoint_signal}");
                }
            }else{
                print("[oarexec] cannot find pid of user process, retry in 5 seconds\n");
                send_kill_signal_to_myself('SIGUSR2');
            }
            $Checkpoint_signal = 1;
        }elsif ($line_read =~ m/^SIGNAL_(.*)/){
            my $signal = $1;
            #We must send $signal to the child of $pid
            if ($user_cmd_pid >= 0){
                print("[oarexec] signal URG received, send signal $signal to the pid $user_cmd_pid\n");
                system({"oardodo"} "oardodo","kill","-s",$signal,$user_cmd_pid);
                if (defined($Job->{stderr_file}) and ($Job->{stderr_file} ne "")){
                    append_string_to_user_file($Job->{job_user}, $Job->{stderr_file}, $Job->{launching_directory}, "Job $Job_id SIGNALED with $signal");
                }
            }else{
                print("[oarexec] cannot find pid of user process, will retry in 5 seconds\n");
                send_kill_signal_to_myself('URG');
            }
            $user_signal = 1;
        }
    }    
}

$SIG{CHLD} = 'DEFAULT';
$SIG{TERM} = 'IGNORE';
$SIG{INT}  = 'IGNORE';
$SIG{QUIT} = 'IGNORE';
$SIG{USR1} = 'DEFAULT';
$SIG{USR2} = 'DEFAULT';
close(pipe_script_read) if ($rin_script ne '');
close(pipe_child_write);
close(pipe_child_read);
close(pipe_kill_write);
close(pipe_kill_read);

print("[oarexec] job terminated\n");

if (defined($Job->{epilogue})){
    # Launch epilogue script
    my ($script_error, $eval_error) = run_script("epilogue", "$Job->{epilogue} $Job_id $Job->{job_user} $Node_file", $Job->{pro_epi_timeout});
    if( $eval_error || ($script_error != 0)){
        print("[oarexec] epilogue error: $eval_error; return code = $script_error\n");
        clean_all();
        if ($Kill_myself == 1){
            quit_oarexec(4,$Job);
        }elsif($Stop_signal == 1){
            quit_oarexec(33,$Job);
        }elsif($Checkpoint_signal == 1){
            quit_oarexec(41,$Job);
        }else{
            quit_oarexec(2+$Oarexec_exit_code,$Job);
        }
    }
}

clean_all();
if ($Kill_myself == 1){
    quit_oarexec(3,$Job);
}elsif($Stop_signal == 1){
    quit_oarexec(34,$Job);
}elsif($Checkpoint_signal == 1){
    quit_oarexec(40,$Job);
}elsif($user_signal == 1){
    quit_oarexec(42,$Job);
}else{
    quit_oarexec(0+$Oarexec_exit_code,$Job);
}

