/****** shepherd/shepconf/shepconf_has_notify_signal() ************************ * NAME * shepconf_has_notify_signal() -- Do we have a notification signal * * SYNOPSIS * int shepconf_has_notify_signal(char *notify_name, int *signal) * * FUNCTION * This function checks if the notification mechanism is enabled. * In this case the function will retuen 'true' and it will * return the default signal or the user defined signal for * the given "notify_name". * * INPUTS * char *notify_name - "notify_susp" or "notify_kill" * int *signal - signal id * * RESULT * int - true or false *******************************************************************************/ int shepconf_has_notify_signal(const char *notify_name, int *signal) { const char *notify_array[] = { "notify_susp", "notify_kill", NULL }; int signal_array[] = { SIGUSR1, SIGUSR2, 0 }; dstring param_name = DSTRING_INIT; char *conf_type = NULL; int conf_id; int ret = 0; /* * There are three possibilities: * a) There is a user defined signal which should be used * b) Default signal should be used * c) Notification mechanism is disabled */ sge_dstring_sprintf(¶m_name, "%s%s", notify_name, "_type"); conf_type = search_conf_val(sge_dstring_get_string(¶m_name)); sge_dstring_free(¶m_name); if (conf_type != NULL) { conf_id = atol(conf_type); } else { conf_id = 1; /* Default signal should be used */ } if (conf_id == 0) { char *conf_signal = search_conf_val(notify_name); if (conf_signal != NULL) { *signal = sge_sys_str2signal(conf_signal); ret = 1; } } else if (conf_id == 1) { int i; for (i = 0; notify_array[i] != NULL; i++) { if (!strcmp(notify_array[i], notify_name)) { break; } } *signal = signal_array[i]; ret = 1; } else { *signal = 0; ret = 0; } return ret; }
/****** shepherd/qrsh/get_exit_code_of_qrsh_starter() ************************* * NAME * get_exit_code_of_qrsh_starter -- short description * * SYNOPSIS * #include "qlogin_starter.h" * int get_exit_code_of_qrsh_starter(int* exit_code); * * FUNCTION * Reads the exit code from a process started via qrsh - qrsh_starter * from a file in the jobs TMPDIR. * * INPUTS * exit_code - exit code of qrsh_starter * * RESULT * 0, success * 1, if an error occured while trying to get the exit code ******************************************************************************/ int get_exit_code_of_qrsh_starter(int* exit_code) { char buffer[1024]; int ret = 1; *exit_code = 1; *buffer = 0; /* rshd exited with OK: try to get returncode from qrsh_starter file */ /* we only have an error file in TMPDIR in case of rsh, * otherwise pass exit_code */ if (search_conf_val("rsh_daemon") != NULL) { char *tmpdir; char *taskid; FILE *errorfile; tmpdir = search_conf_val("qrsh_tmpdir"); taskid = search_conf_val("pe_task_id"); shepherd_trace("get_exit_code_of_qrsh_starter - TMPDIR = %s, pe_task_id = %s", tmpdir ? tmpdir : "0", taskid ? taskid : "0"); if (tmpdir != NULL) { if (taskid != NULL) { sprintf(buffer, "%s/qrsh_exit_code.%s", tmpdir, taskid); } else { sprintf(buffer, "%s/qrsh_exit_code", tmpdir); } errorfile = fopen(buffer, "r"); if (errorfile != NULL) { ret = 0; if (fscanf(errorfile, "%d", exit_code) == 1) { shepherd_trace("error code from remote command is %d", *exit_code); } FCLOSE(errorfile); if (unlink(buffer) != 0) { shepherd_trace("can't delete %s", buffer); } } else { shepherd_trace("can't open file %s: %s", buffer, strerror(errno)); } } else { shepherd_trace("unable to get qrsh_tmpdir"); } } return ret; FCLOSE_ERROR: shepherd_trace(MSG_FILE_NOCLOSE_SS, buffer, strerror(errno)); return ret; }
/****** Interactive/qrsh/qrsh_error() ****************************************** * NAME * qrsh_error() -- propagate qrsh startup error to shepherd and qrsh client * * SYNOPSIS * static * void qrsh_error(const char *fmt, ...) * * FUNCTION * Writes the passed error message to a special error file in the jobs * temporary directory. * Separate error files are written for jobs and tasks (started by * qrsh -inherit). * * INPUTS * const char *fmt - format string * ... - arguments to be formatted using the format string * *******************************************************************************/ static void qrsh_error(const char *fmt, ...) { char *tmpdir = NULL; char *taskid = NULL; int file; char fileName[SGE_PATH_MAX]; va_list ap; char message[MAX_STRING_SIZE]; va_start(ap, fmt); if (fmt == NULL || *fmt == '\0') { return; } vsnprintf(message, MAX_STRING_SIZE, fmt, ap); va_end(ap); if ((tmpdir = search_conf_val("qrsh_tmpdir")) == NULL) { fprintf(stderr, "%s\n", message); fprintf(stderr, MSG_CONF_NOCONFVALUE_S, "qrsh_tmpdir"); fprintf(stderr, "\n"); return; } taskid = search_conf_val("qrsh_task_id"); if (taskid != NULL) { snprintf(fileName, SGE_PATH_MAX, "%s/qrsh_error.%s", tmpdir, taskid); } else { snprintf(fileName, SGE_PATH_MAX, "%s/qrsh_error", tmpdir); } if ((file = SGE_OPEN3(fileName, O_WRONLY | O_APPEND | O_CREAT, 00744)) == -1) { fprintf(stderr, "%s\n", message); fprintf(stderr, MSG_QRSH_STARTER_CANNOTOPENFILE_SS, fileName, strerror(errno)); fprintf(stderr, "\n"); return; } if (write(file, message, strlen(message)) != strlen(message)) { dstring ds = DSTRING_INIT; fprintf(stderr, MSG_FILE_CANNOT_WRITE_SS, fileName, sge_strerror(errno, &ds)); sge_dstring_free(&ds); } close(file); }
/****** shepherd/qrsh/get_error_of_qrsh_starter() ************************* * NAME * get_error_of_qrsh_starter -- get error message from qrsh_starter * * SYNOPSIS * #include "qlogin_starter.h" * const char * * get_error_of_qrsh_starter(void); * * FUNCTION * Reads an error message that qrsh_starter may have written to the * qrsh jobs tmpdir due to an error in the startup phase of the qrsh job. * * RESULT * the error message from qrsh_starter or * NULL, if no error was generated (the job started up without problems) * * NOTE * The returned string is dynamically allocated. It is in the responsibility * of the caller to free it. ******************************************************************************/ const char *get_error_of_qrsh_starter(void) { char buffer[SGE_PATH_MAX]; char *ret = NULL; *buffer = 0; /* rshd exited with OK: try to get error messages from qrsh_starter file */ shepherd_trace("get_error_of_qrsh_starter()"); /* we only have an error file in TMPDIR in case of rsh */ if (search_conf_val("rsh_daemon") != NULL) { char *tmpdir; char *taskid; FILE *errorfile; tmpdir = search_conf_val("qrsh_tmpdir"); taskid = search_conf_val("qrsh_task_id"); shepherd_trace("get_error_of_qrsh_starter - TMPDIR = %s, qrsh_task_id = %s", tmpdir ? tmpdir : "0", taskid ? taskid : "0"); if (tmpdir != NULL) { if (taskid != NULL) { sprintf(buffer, "%s/qrsh_error.%s", tmpdir, taskid); } else { sprintf(buffer, "%s/qrsh_error", tmpdir); } errorfile = fopen(buffer, "r"); if (errorfile != NULL) { char buffer[MAX_STRING_SIZE]; if (fgets(buffer, MAX_STRING_SIZE, errorfile) != NULL) { shepherd_trace("error string from qrsh_starter is %s", buffer); ret = strdup(buffer); } FCLOSE(errorfile); if (unlink(buffer) != 0) { shepherd_trace("can't delete %s", buffer); } } } } return ret; FCLOSE_ERROR: shepherd_trace(MSG_FILE_NOCLOSE_SS, buffer, strerror(errno)); return ret; }
/****** Interactive/qrsh/write_pid_file() *************************************** * * NAME * write_pid_file() -- write a pid to file pid in $TMPDIR * * SYNOPSIS * static int write_pid_file(pid_t pid); * * FUNCTION * Writes the given pid to a file named pid in the directory * contained in environment variable TMPDIR * * INPUTS * pid - the pid to write * * RESULT * 1, if all actions could be performed * 0, if an error occured. Possible error situations are: * - the environement variable TMPDIR cannot be read * - the file cannot be opened * **************************************************************************** */ static int write_pid_file(pid_t pid) { char *pid_file_name = NULL; int pid_file; char pid_str[20]; if((pid_file_name = search_conf_val("qrsh_pid_file")) == NULL) { qrsh_error(MSG_CONF_NOCONFVALUE_S, "qrsh_pid_file"); return 0; } if((pid_file = SGE_OPEN3(pid_file_name, O_WRONLY | O_APPEND | O_CREAT, 00744)) == -1) { dstring ds = DSTRING_INIT; qrsh_error(MSG_QRSH_STARTER_CANNOTWRITEPID_SS, pid_file_name, sge_strerror(errno, &ds)); sge_dstring_free(&ds); return 0; } snprintf(pid_str, 20, pid_t_fmt, pid); if (write(pid_file, pid_str, strlen(pid_str)) != strlen(pid_str)) { dstring ds = DSTRING_INIT; qrsh_error(MSG_FILE_CANNOT_WRITE_SS, pid_file_name, sge_strerror(errno, &ds)); sge_dstring_free(&ds); } SGE_CLOSE(pid_file); return 1; }
/****** Interactive/qrsh/writeExitCode() *************************************** * * NAME * writeExitCode() -- write exit code of child process to file * * SYNOPSIS * static int writeExitCode(int myExitCode, int programExitCode) * * FUNCTION * If myExitCode != EXIT_SUCCESS, that means, if an error occured in * qrsh_starter, write this exit code to file, * else write the exit code of the child process (programExitCode). * The exit code is written to a file "qrsh_exit_code" in the * directory $TMPDIR. * * INPUTS * myExitCode - status of qrsh_starter * programExitCode - status of the child process * * RESULT * EXIT_SUCCESS, if all actions could be performed, * EXIT_FAILURE, if one of the following errors occured: * - the environment variable TMPDIR cannot be read * - the file $TMPDIR/qrsh_exit_code cannot be written * **************************************************************************** */ static int writeExitCode(int myExitCode, int programExitCode) { int exitCode; char exitCode_str[20]; char *tmpdir = NULL; char *taskid = NULL; int file; char fileName[SGE_PATH_MAX]; if(myExitCode != EXIT_SUCCESS) { exitCode = MAKEEXITSTATUS(myExitCode); } else { exitCode = programExitCode; } if((tmpdir = search_conf_val("qrsh_tmpdir")) == NULL) { qrsh_error(MSG_CONF_NOCONFVALUE_S, "qrsh_tmpdir"); return EXIT_FAILURE; } taskid = get_conf_val("pe_task_id"); if(taskid != NULL) { snprintf(fileName, SGE_PATH_MAX, "%s/qrsh_exit_code.%s", tmpdir, taskid); } else { snprintf(fileName, SGE_PATH_MAX, "%s/qrsh_exit_code", tmpdir); } if((file = SGE_OPEN3(fileName, O_WRONLY | O_APPEND | O_CREAT, 00744)) == -1) { dstring ds = DSTRING_INIT; qrsh_error(MSG_QRSH_STARTER_CANNOTOPENFILE_SS, fileName, sge_strerror(errno, &ds)); sge_dstring_free(&ds); return EXIT_FAILURE; } snprintf(exitCode_str, 20, "%d", exitCode); if (write(file, exitCode_str, strlen(exitCode_str)) != strlen(exitCode_str)) { dstring ds = DSTRING_INIT; qrsh_error(MSG_FILE_CANNOT_WRITE_SS, fileName, sge_strerror(errno, &ds)); sge_dstring_free(&ds); } SGE_CLOSE(file); return EXIT_SUCCESS; }
/****** qrsh_starter/delete_qrsh_pid_file() ***************************************** * NAME * delete_qrsh_pid_file() -- delete the pid file from $TMPDIR * * SYNOPSIS * static int delete_qrsh_pid_file() * * FUNCTION * Delete the pid file created by qrsh_starter * * RESULT * 1, if the file could be deleted * 0, if and error occured. Possible error situations are: * - the environment variable TMPDIR cannot be read * - the file cannot be deleted * * SEE ALSO * qrsh_starter *******************************************************************************/ int delete_qrsh_pid_file() { char *pid_file_name = NULL; int ret = 1; if((pid_file_name = search_conf_val("qrsh_pid_file")) == NULL) { shepherd_trace("cannot get variable %s", pid_file_name); return 0; } if (unlink(pid_file_name) != 0) { shepherd_trace("cannot delete qrsh pid file %s", pid_file_name); ret = 0; } return ret; }
/****** shepherd_error ******************************************************** * NAME * shepherd_error() -- Write a line to the error file and exit program. * * SYNOPSIS * void shepherd_error(bool do_exit, const char *format, ...) * * FUNCTION * Writes a line to the error file, preceding it with a * date, time, uid and pid stamp, and exits the program. stops execution. * * INPUTS * do_exit: If true, this function calls exit(2). * format: The format string of the line to be written to the error file. * ...: The parameters to the format string. See printf(3c). * * RESULT * void - none *******************************************************************************/ void shepherd_error(int do_exit, const char *format, ...) { dstring ds; dstring message = DSTRING_INIT; char buffer[128]; char header_str[256]; struct stat statbuf; if (format != NULL) { va_list ap; va_start(ap, format); sge_dstring_vsprintf(&message, format, ap); va_end(ap); } shepherd_trace(sge_dstring_get_string(&message)); /* File was closed (e.g. by an exec()) but fp was not set to NULL */ if (shepherd_error_fp && fstat(fileno(shepherd_error_fp), &statbuf) == -1 && errno==EBADF) { shepherd_error_fp = NULL; } if (shepherd_error_fp == NULL) { shepherd_error_fp = shepherd_trace_init_intern(st_error); } if (shepherd_error_fp != NULL) { sge_dstring_init(&ds, buffer, sizeof(buffer)); sprintf(header_str, "%s ["uid_t_fmt":"pid_t_fmt"]: ", sge_ctime(0, &ds), geteuid(), getpid()); sh_str2file(header_str, sge_dstring_get_string(&message), shepherd_error_fp); } if (foreground) { fprintf(stderr, "%s%s\n", header_str, sge_dstring_get_string(&message)); } /* File was closed (e.g. by an exec()) but fp was not set to NULL */ if (shepherd_exit_status_fp && fstat(fileno(shepherd_exit_status_fp), &statbuf) == -1 && errno==EBADF ) { shepherd_exit_status_fp = NULL; } if (shepherd_exit_status_fp == NULL) { shepherd_exit_status_fp = shepherd_trace_init_intern(st_exit_status); } if (shepherd_exit_status_fp != NULL) { sprintf(header_str, "%d", shepherd_state); sh_str2file(header_str, NULL, shepherd_exit_status_fp); } if (coshepherd_pid > 0) { sge_switch2start_user(); kill(coshepherd_pid, SIGTERM); sge_switch2admin_user(); } if (g_new_interactive_job_support == false && search_conf_val("qrsh_control_port") != NULL) { char buffer[1024]; snprintf(buffer, sizeof(buffer), "1:%s", sge_dstring_get_string(&message)); write_to_qrsh(buffer); } sge_dstring_free(&message); if (do_exit) { /* close all trace files before exit */ shepherd_trace_exit(); exit(shepherd_state); } /* There are cases where we have to open and close the files * for every write. */ if (!g_keep_files_open) { shepherd_error_exit(); } }
void setosjobid(pid_t sid, gid_t *add_grp_id_ptr, struct passwd *pw) { FILE *fp=NULL; shepherd_trace("setosjobid: uid = "pid_t_fmt", euid = "pid_t_fmt, getuid(), geteuid()); # if defined(SOLARIS) || defined(ALPHA) || defined(LINUX) || defined(FREEBSD) || defined(DARWIN) /* Read SgeId from config-File and create Addgrpid-File */ { char *cp; if ((cp = search_conf_val("add_grp_id"))) *add_grp_id_ptr = atol(cp); else *add_grp_id_ptr = 0; } if ((fp = fopen("addgrpid", "w")) == NULL) { shepherd_error(1, "can't open \"addgrpid\" file"); } fprintf(fp, gid_t_fmt"\n", *add_grp_id_ptr); FCLOSE(fp); # elif defined(HP1164) || defined(AIX) { if ((fp = fopen("addgrpid", "w")) == NULL) { shepherd_error(1, "can't open \"addgrpid\" file"); } fprintf(fp, pid_t_fmt"\n", getpgrp()); FCLOSE(fp); } # else { char osjobid[100]; if ((fp = fopen("osjobid", "w")) == NULL) { shepherd_error(1, "can't open \"osjobid\" file"); } if(sge_switch2start_user() == 0) { # if defined(IRIX) { /* The following block contains the operations necessary for * IRIX6.2 (and later) to set array session handles (ASHs) and * service provider info (SPI) records */ struct acct_spi spi; int ret; char *cp; shepherd_trace("in irix code"); /* get _local_ array session id */ if ((ret=newarraysess())) { shepherd_error(1, "error: can't create ASH; errno=%d", ret); } /* retrieve array session id we just assigned to the process and * write it to the os-jobid file */ sprintf(osjobid, "%lld", getash()); shepherd_trace(osjobid); /* set service provider information (spi) record */ strncpy(spi.spi_company, "SGE", 8); strncpy(spi.spi_initiator, get_conf_val("spi_initiator"), 8); strncpy(spi.spi_origin, get_conf_val("queue"),16); strcpy(spi.spi_spi, "Job "); strncat(spi.spi_spi, get_conf_val("job_id"),11); if ((ret=setspinfo(&spi))) { shepherd_error(1, "error: can't set SPI; errno=%d", ret); } if ((cp = search_conf_val("acct_project"))) { prid_t proj; if (strcasecmp(cp, "none") && ((proj = projid(cp)) >= 0)) { shepherd_trace("setting project \"%s\" to id %lld", cp, proj); if (setprid(proj) == -1) shepherd_trace("failed setting project id"); } else { shepherd_trace("can't get id for project \"%s\"", cp); } } else { shepherd_trace("can't get configuration entry for projects"); } } # elif defined(CRAY) { char *cp; { int jobid; if ((jobid=setjob(pw->pw_uid, 0)) < 0) { shepherd_error(1, "error: can't set job ID; errno = %d", errno); } if (sesscntl(jobid, S_ADDFL, S_BATCH) == -1) { shepherd_error(1, "error: sesscntl(%d, S_ADDFL, S_BATCH) failed," " errno = %d", sid, errno); } sprintf(osjobid, "%d", jobid); } if ((cp = search_conf_val("acct_project"))) { int proj; if (strcasecmp(cp, "none") && ((proj = nam2acid(cp)) >= 0)) { shephed_trace("setting project \"%s\" to acid %d", cp, proj); if (acctid(0, proj) == -1) { shepherd_trace("failed setting project id (acctid)"); } } else { shepherd_trace("can't get id for project \"%s\"", cp); } } else { shepherd_trace("can't get configuration entry for projects"); } } # elif defined(NECSX4) || defined(NECSX5) { id_t jobid = 0; dispset2_t attr; int value; /* * Create new Super-UX job */ if (setjid() == -1) { shepherd_trace("ERROR: can't set jobid: %s[%d]", strerror(errno), errno); } else { jobid = getjid(0); shepherd_trace("Created job with id: "sge_u32, (u_long32) jobid); } sprintf(osjobid, sge_u32, (u_long32) jobid); /* * We will use limits for the whole job */ set_rlimits_os_job_id(jobid); /* * The job will use the resources of the configured * Resource Sharing Group (rsg) */ { char *rsg_id_string; int rsg_id; char fsg_dev_string[256]; rsg_id_string = get_conf_val("processors"); rsg_id = atoi(rsg_id_string); if (rsg_id) { int fd; sprintf(fsg_dev_string, "/dev/rsg/%d", rsg_id); fd = open(fsg_dev_string, O_RDONLY); if (fd <= 0) { shepherd_trace("ERROR: can't switch to rsg%d because can't open" "device: %s[%d]", rsg_id, strerror(errno), errno); } else { if (ioctl(fd, RSG_JUMP, NULL) == -1) { close(fd); shepherd_trace("ERROR: can't switch to rsg%d: %s[%d]", rsg_id, strerror(errno), errno); return; } else { close(fd); shepherd_trace("switched to rsg%d", rsg_id); } } } else { shepherd_trace("using default rsg", rsg_id); } } /* * Set scheduling parameter for job */ if (((attr.basepri = atoi(get_conf_val("nec_basepriority"))) != NEC_UNDEF_VALUE) && ((attr.modcpu = atoi(get_conf_val("nec_modcpu"))) != NEC_UNDEF_VALUE) && ((attr.tickcnt = atoi(get_conf_val("nec_tickcnt"))) != NEC_UNDEF_VALUE) && ((attr.dcyfctr = atoi(get_conf_val("nec_dcyfctr"))) != NEC_UNDEF_VALUE) && ((attr.dcyintvl = atoi(get_conf_val("nec_dcyintvl"))) != NEC_UNDEF_VALUE) && ((attr.tmslice = atoi(get_conf_val("nec_timeslice"))) != NEC_UNDEF_VALUE) && ((attr.mempri = atoi(get_conf_val("nec_memorypriority"))) != NEC_UNDEF_VALUE) && ((attr.szefctmrt = atoi(get_conf_val("nec_mrt_size_effct"))) != NEC_UNDEF_VALUE) && ((attr.priefctmrt = atoi(get_conf_val("nec_mrt_pri_effct"))) != NEC_UNDEF_VALUE) && ((attr.minmrt = atoi(get_conf_val("nec_mrt_minimum"))) != NEC_UNDEF_VALUE) && ((attr.agrange = atoi(get_conf_val("nec_aging_range"))) != NEC_UNDEF_VALUE) && ((attr.spinherit = atoi(get_conf_val("nec_slavepriority"))) != NEC_UNDEF_VALUE) && ((attr.concpu = atoi(get_conf_val("nec_cpu_count"))) != NEC_UNDEF_VALUE)) { if (dispcntl(SG_JID, getjid(0), DCNTL_SET2, &attr) == -1) { shepherd_trace("ERROR: can't set scheduling parameter: %s[%d]", strerror(errno), errno); } else { shepherd_trace("control parameters for active process scheduling modified"); print_scheduling_parameters(attr); } } else { shepherd_trace("we do not control active process scheduling"); } } # else /* write a default os-jobid to file */ sprintf(osjobid, pid_t_fmt, sid); # endif sge_switch2admin_user(); } else /* not running as super user --> we want a default os-jobid */ sprintf(osjobid, "0"); if(fprintf(fp, "%s\n", osjobid) < 0) shepherd_trace("error writing osjobid file"); FCLOSE(fp); /* Close os-jobid file */ } # endif return; FCLOSE_ERROR: shepherd_error(1, "can't close file"); }
/****** Interactive/qrsh/startJob() *************************************** * * NAME * startJob() -- start a shell with commands to execute * * SYNOPSIS * static int startJob(char *command, char *wrapper, int noshell); * * FUNCTION * Starts the commands and arguments to be executed as * specified in parameter <command>. * If the parameter noshell is set to 1, the command is directly called * by exec. * If a wrapper is specified (parameter wrapper, set by environment * variable QRSH_WRAPPER), this wrapper is called and is passed the * command to execute as commandline parameters. * If neither noshell nor wrapper is set, a users login shell is called * with the parameters -c <command>. * The child process creates an own process group. * The pid of the child process is written to a pid file in $TMPDIR. * * INPUTS * command - commandline to be executed * wrapper - name and path of a wrapper script * noshell - if != 0, call the command directly without shell * * RESULT * status of the child process after it terminated * or EXIT_FAILURE, if the process of starting the child * failed because of one of the following error situations: * - fork failed * - the pid of the child process cannot be written to pid file * - the name of actual user cannot be determined * - info about the actual user cannot be determined (getpwnam) * - necessary memory cannot be allocated * - executing the shell failed * * SEE ALSO * Interactive/qrsh/write_pid_file() * Interactive/qrsh/split_command() * Interactive/qrsh/join_command() * **************************************************************************** */ static int startJob(char *command, char *wrapper, int noshell) { child_pid = fork(); if(child_pid == -1) { qrsh_error(MSG_QRSH_STARTER_CANNOTFORKCHILD_S, strerror(errno)); return EXIT_FAILURE; } if(child_pid) { /* parent */ int status; #if defined(LINUX) int ttyfd; #endif signal(SIGINT, forward_signal); signal(SIGQUIT, forward_signal); signal(SIGTERM, forward_signal); /* preserve pseudo terminal */ #if defined(LINUX) ttyfd = open("/dev/tty", O_RDWR); if (ttyfd != -1) { tcsetpgrp(ttyfd, child_pid); close(ttyfd); } #endif while(waitpid(child_pid, &status, 0) != child_pid && errno == EINTR); return(status); } else { /* child */ char *buffer = NULL; int size; struct passwd pw_struct; char *shell = NULL; char *userName = NULL; int argc = 0; const char **args = NULL; char *cmd = NULL; int cmdargc; char **cmdargs = NULL; int i; if(!write_pid_file(getpid())) { exit(EXIT_FAILURE); } cmdargc = split_command(command, &cmdargs); if(cmdargc == 0) { qrsh_error(MSG_QRSH_STARTER_INVALIDCOMMAND); exit(EXIT_FAILURE); } if(!noshell) { struct passwd *pw = NULL; if((userName = search_conf_val("job_owner")) == NULL) { qrsh_error(MSG_QRSH_STARTER_CANNOTGETLOGIN_S, strerror(errno)); exit(EXIT_FAILURE); } size = get_pw_buffer_size(); buffer = sge_malloc(size); if ((pw = sge_getpwnam_r(userName, &pw_struct, buffer, size)) == NULL) { qrsh_error(MSG_QRSH_STARTER_CANNOTGETUSERINFO_S, strerror(errno)); exit(EXIT_FAILURE); } shell = pw->pw_shell; if(shell == NULL) { qrsh_error(MSG_QRSH_STARTER_CANNOTDETERMSHELL_S, "/bin/sh"); shell = "/bin/sh"; } } if((args = malloc((cmdargc + 3) * sizeof(char *))) == NULL) { qrsh_error(MSG_QRSH_STARTER_MALLOCFAILED_S, strerror(errno)); exit(EXIT_FAILURE); } if(wrapper == NULL) { if(noshell) { cmd = cmdargs[0]; for(i = 0; i < cmdargc; i++) { args[argc++] = cmdargs[i]; } } else { cmd = shell; args[argc++] = sge_basename(shell, '/'); args[argc++] = "-c"; args[argc++] = join_command(cmdargc, cmdargs); } } else { cmd = wrapper; args[argc++] = sge_basename(wrapper, '/'); for(i = 0; i < cmdargc; i++) { args[argc++] = cmdargs[i]; } } args[argc++] = NULL; #if 0 { /* debug code */ int i; fflush(stdout) ; fflush(stderr); printf("qrsh_starter: executing %s\n", cmd); for(i = 1; args[i] != NULL; i++) { printf("args[%d] = %s\n", i, args[i]); } printf("\n"); fflush(stdout) ; fflush(stderr); } #endif SETPGRP; execvp(cmd, (char *const *)args); /* exec failed */ fprintf(stderr, MSG_QRSH_STARTER_EXECCHILDFAILED_S, args[0], strerror(errno)); fprintf(stderr, "\n"); exit(EXIT_FAILURE); } /* will never be reached */ return EXIT_FAILURE; }