blob: cfdd0cef809e7883524845fbaefd83ff36b0d73f [file] [log] [blame]
/*
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.
*
*/
#include <iostream>
#include <sstream>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/wait.h>
using namespace std;
int
main ( int argc, char ** argv )
{
int exit_code = -1;
int fd[2];
int my_pid = getpid();
int child_pid;
pipe(fd);
char const * root_dir = argv[1]; // This arg is prepended by qrsh_server.
char const * child_name = argv[2]; // This arg comes from qrsh.
char const * child_path = argv[3]; // This arg comes from qrsh.
// This is the problem..
fprintf ( stderr, "MDEBUG qrsh_run: root_dir: |%s|\n", root_dir );
fprintf ( stderr, "MDEBUG qrsh_run: child_name: |%s|\n", child_name );
fprintf ( stderr, "MDEBUG qrsh_run: child_path: |%s|\n", child_path );
/*
* A named child is one for whom we will create a directory and
* store information. There are some magic names that are not
* real symbolic names -- but are instead the names of actions.
*/
bool named_child = true;
if ( ! strcmp ( child_name, "exec" ) )
named_child = false;
else
if ( ! strcmp ( child_name, "exec_wait" ) )
named_child = false;
else
if ( ! strcmp ( child_name, "exited" ) )
named_child = false;
else
named_child = true;
stringstream child_dir_name;
if ( named_child )
{
child_dir_name << root_dir
<< '/'
<< child_name;
/*
* Make the child directory before forking, or there is
* a race in which the child might be trying to make its
* stdout and stderr files while we are tring to make
* the directory.
*/
if ( -1 == mkdir ( child_dir_name.str().c_str(), 0777 ) )
{
fprintf ( stderr,
"qrsh_run error: Can't mkdir |%s|\n",
child_dir_name.str().c_str()
);
exit ( 1 );
}
}
else
/*
* If this is an 'exited' command that means we are
* waiting for a pre-existing child.
*/
if ( ! strcmp ( child_name, "exited" ) )
{
int wait_pid = atoi(child_path);
// Find the child's symbolic name.
stringstream pid_to_name_file_name;
pid_to_name_file_name << root_dir
<< '/'
<< wait_pid;
FILE * fp = fopen ( pid_to_name_file_name.str().c_str(), "r" );
if (! fp)
{
fprintf ( stderr,
"qrsh_run %d error: Can't open pid2name file |%s|.\n",
my_pid,
pid_to_name_file_name.str().c_str()
);
exit(1);
}
char symbolic_name[1000];
strcpy ( symbolic_name, "qrsh_no_name" );
fscanf ( fp, "%s", symbolic_name );
fclose ( fp );
// Make the name of the child's exit code file.
stringstream exit_code_file_name;
exit_code_file_name << root_dir
<< '/'
<< symbolic_name
<< "/exit_code";
struct stat stat_buf;
int file_does_not_exist = stat ( exit_code_file_name.str().c_str(), & stat_buf );
/*
* If the result of stat is zero, the file exists, which means that
* the command has exited. The question we are being asked here is
* "has it exited yet?"
*/
if ( ! file_does_not_exist )
return 1;
else
if ( errno == ENOENT )
return 0;
else
return 2 ;
}
// We are not waiting on a pre-wxiting child: we have a
// new child to create.
child_pid = fork();
if ( child_pid == 0 )
{
// This code is executed in the child process.
// If it's a *named* child, then redirect its stdout and stderr.
if ( named_child )
{
stringstream stdout_path,
stderr_path;
// Redirect the child's stdout. -----------------
stdout_path << root_dir
<< '/'
<< child_name
<< '/'
<< "stdout";
int redirected_stdout = open ( stdout_path.str().c_str(),
O_WRONLY|O_CREAT|O_TRUNC,
S_IRWXU|S_IRWXG|S_IRWXO
);
if ( redirected_stdout < 0 )
{
perror ( "qrsh_run: error opening redirected_stdout: " );
fprintf ( stderr, "stdout path: |%s|\n", stdout_path.str().c_str() );
exit ( 1 );
}
if ( -1 == dup2 ( redirected_stdout, 1 ) )
{
perror ( "qrsh_run: dup2 (stdout) error: " );
exit(1);
}
// Redirect the child's stderr. -----------------
stderr_path << root_dir
<< '/'
<< child_name
<< '/'
<< "stderr";
int redirected_stderr = open ( stderr_path.str().c_str(),
O_WRONLY|O_CREAT|O_TRUNC,
S_IRWXU|S_IRWXG|S_IRWXO
);
if ( redirected_stderr < 0 )
{
perror ( "qrsh_run: error opening redirected_stderr: " );
fprintf ( stderr, "stderr path: |%s|\n", stderr_path.str().c_str() );
exit ( 1 );
}
if(-1 == dup2 ( redirected_stderr, 2 ) )
{
perror ( "qrsh_run: dup2 (stderr) error: " );
exit(1);
}
}
fprintf ( stderr, "MDEBUG ------------- qrsh_run argv -------------\n" );
for ( int i = 0; i < argc; ++ i )
fprintf ( stderr, "MDEBUG argv[%d] : |%s|\n", i, argv[i] );
execv ( child_path, argv + 2 );
perror ( "qrsh_run: execv error: " );
fprintf ( stderr, "on path |%s|\n", child_path );
exit ( 1 );
}
else
{
// This code is executed in the parent process.
if ( named_child )
{
// Write the name-to-pid mapping.
stringstream pid_file_name;
pid_file_name << child_dir_name.str()
<< "/pid";
FILE * fp;
if ( ! (fp = fopen ( pid_file_name.str().c_str(), "w") ) )
{
fprintf ( stderr,
"qrsh_run %d error: Can't open file |%s|\n",
my_pid,
pid_file_name.str().c_str()
);
exit(1);
}
fprintf ( fp, "%d\n", child_pid );
fclose ( fp );
// Write the pid-to-name mapping.
stringstream name_to_pid_file_name;
name_to_pid_file_name << root_dir
<< '/'
<< child_pid;
if(! (fp = fopen ( name_to_pid_file_name.str().c_str(), "w")))
{
fprintf ( stderr,
"qrsh_run %d error: Can't open file |%s|\n",
my_pid,
name_to_pid_file_name.str().c_str()
);
exit(1);
}
fprintf ( fp, "%s\n", child_name );
fclose(fp);
}
pid_t awaited_pid;
while ( 0 == (awaited_pid = waitpid ( child_pid, & exit_code, WNOHANG)) )
{
fprintf ( stderr,
"qrsh_run %d info: parent: waiting for child %d...\n",
my_pid,
child_pid
);
sleep(1);
}
if ( -1 == awaited_pid )
{
fprintf ( stderr, "qrsh_run error awaiting child!\n" );
exit ( 1 );
}
/*
* Write the exit code.
*/
exit_code >>= 8;
if ( named_child )
{
if ( child_pid == awaited_pid )
{
stringstream exit_code_file_name;
exit_code_file_name << child_dir_name.str()
<< "/exit_code";
FILE * fp;
if ( ! (fp = fopen ( exit_code_file_name.str().c_str(), "w") ) )
{
fprintf ( stderr,
"qrsh_run error: Can't open file |%s|\n",
exit_code_file_name.str().c_str()
);
exit(1);
}
fprintf ( fp, "%d\n", exit_code );
fclose ( fp );
}
}
}
fprintf ( stderr, "MDEBUG qrsh_run returning exit code %d\n", exit_code );
return exit_code;
}