diff options
Diffstat (limited to 'cpp/src/tests/qrsh_run.cpp')
-rw-r--r-- | cpp/src/tests/qrsh_run.cpp | 321 |
1 files changed, 321 insertions, 0 deletions
diff --git a/cpp/src/tests/qrsh_run.cpp b/cpp/src/tests/qrsh_run.cpp new file mode 100644 index 0000000000..cfdd0cef80 --- /dev/null +++ b/cpp/src/tests/qrsh_run.cpp @@ -0,0 +1,321 @@ +/* + * + * 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; +} + + + + |