/* * * 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 #include #include #include #include #include #include #include #include #include #include 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; }