/* * OpenPBS (Portable Batch System) v2.3 Software License * * Copyright (c) 1999-2000 Veridian Information Solutions, Inc. * All rights reserved. * * --------------------------------------------------------------------------- * For a license to use or redistribute the OpenPBS software under conditions * other than those described below, or to purchase support for this software, * please contact Veridian Systems, PBS Products Department ("Licensor") at: * * www.OpenPBS.org +1 650 967-4675 sales@OpenPBS.org * 877 902-4PBS (US toll-free) * --------------------------------------------------------------------------- * * This license covers use of the OpenPBS v2.3 software (the "Software") at * your site or location, and, for certain users, redistribution of the * Software to other sites and locations. Use and redistribution of * OpenPBS v2.3 in source and binary forms, with or without modification, * are permitted provided that all of the following conditions are met. * After December 31, 2001, only conditions 3-6 must be met: * * 1. Commercial and/or non-commercial use of the Software is permitted * provided a current software registration is on file at www.OpenPBS.org. * If use of this software contributes to a publication, product, or * service, proper attribution must be given; see www.OpenPBS.org/credit.html * * 2. Redistribution in any form is only permitted for non-commercial, * non-profit purposes. There can be no charge for the Software or any * software incorporating the Software. Further, there can be no * expectation of revenue generated as a consequence of redistributing * the Software. * * 3. Any Redistribution of source code must retain the above copyright notice * and the acknowledgment contained in paragraph 6, this list of conditions * and the disclaimer contained in paragraph 7. * * 4. Any Redistribution in binary form must reproduce the above copyright * notice and the acknowledgment contained in paragraph 6, this list of * conditions and the disclaimer contained in paragraph 7 in the * documentation and/or other materials provided with the distribution. * * 5. Redistributions in any form must be accompanied by information on how to * obtain complete source code for the OpenPBS software and any * modifications and/or additions to the OpenPBS software. The source code * must either be included in the distribution or be available for no more * than the cost of distribution plus a nominal fee, and all modifications * and additions to the Software must be freely redistributable by any party * (including Licensor) without restriction. * * 6. All advertising materials mentioning features or use of the Software must * display the following acknowledgment: * * "This product includes software developed by NASA Ames Research Center, * Lawrence Livermore National Laboratory, and Veridian Information * Solutions, Inc. * Visit www.OpenPBS.org for OpenPBS software support, * products, and information." * * 7. DISCLAIMER OF WARRANTY * * THIS SOFTWARE IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND. ANY EXPRESS * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT * ARE EXPRESSLY DISCLAIMED. * * IN NO EVENT SHALL VERIDIAN CORPORATION, ITS AFFILIATED COMPANIES, OR THE * U.S. GOVERNMENT OR ANY OF ITS AGENCIES BE LIABLE FOR ANY DIRECT OR INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * This license will be governed by the laws of the Commonwealth of Virginia, * without reference to its choice of law rules. */ /* * * qsub - (PBS) submit batch job * * Authors: * Terry Heidelberg * Livermore Computing * * Bruce Kelly * National Energy Research Supercomputer Center * * Lawrence Livermore National Laboratory * University of California */ #include /* the master config generated by configure */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef sun #include #endif /* sun */ #if defined(HAVE_SYS_IOCTL_H) #include #endif /* HAVE_SYS_IOCTL_H */ #if defined(HAVE_SYS_TTY_H) #include #endif #if defined(FD_SET_IN_SYS_SELECT_H) # include #endif #include "cmds.h" #include "net_connect.h" #include "log.h" #include "port_forwarding.h" #include "utils.h" int load_config(char *config_buf, int buffer_size); /* DefaultFilterPath is used to fall back on in order to maintain backwards compatibility. the new preferred path for the submit filter is ${libexecdir}/qsub_filter */ /* NOTE: submitfilter specified using SUBMITFILTER in $TORQUEHOME/torque.cfg */ static char *DefaultFilterPath = "/usr/local/sbin/torque_submitfilter"; static char *DefaultXauthPath = XAUTH_PATH; #define SUBMIT_FILTER_ADMIN_REJECT_CODE -1 #define MAX_QSUB_PREFIX_LEN 32 #define MAX_PROCS_DIGITS 15 /* A 15 digit number is a lot of processors. 100 trillion will this be enough for the future? */ static char PBS_DPREFIX_DEFAULT[] = "#PBS"; char PBS_Filter[256]; char PBS_InitDir[MAXLINE*2]; char PBS_RootDir[MAXLINE*2]; char PBS_WorkDir[MAXLINE*2]; char xauth_path[256]; char default_ckpt[256]; int validate_path = 1; int rerunnable_by_default = 1; int fault_tolerant_by_default = 0; int interactivechild = 0; int x11child = 0; int do_dir(char *); int process_opts(int, char **, int); int have_terminal = TRUE; int validate_group = FALSE; char *checkpoint_strings = "n,c,s,u,none,shutdown,periodic,enabled,interval,depth,dir"; /* adapted from openssh */ static char *x11_get_proto( char *EMsg) /* O (optional,minsize=1024) */ { char line[512]; char proto[512], data[512], screen[512]; char *authstring; FILE *f; int got_data = 0; char *display, *p; struct stat st; proto[0] = '\0'; data[0] = '\0'; screen[0] = '\0'; if (EMsg != NULL) EMsg[0] = '\0'; if ((display = getenv("DISPLAY")) == NULL) { fprintf(stderr, "qsub: DISPLAY not set\n"); return(NULL); } if (stat(xauth_path, &st)) { perror("qsub: xauth: "); return(NULL); } /* Try to get Xauthority information for the display. */ if (strncmp(display, "localhost:", 10) == 0) { /* * Handle FamilyLocal case where $DISPLAY does * not match an authorization entry. For this we * just try "xauth list unix:displaynum.screennum". * XXX: "localhost" match to determine FamilyLocal * is not perfect. */ snprintf(line, sizeof(line), "%s list unix:%s 2>/dev/null", xauth_path, display + 10); } else { snprintf(line, sizeof(line), "%s list %.200s 2>/dev/null", xauth_path, display); } p = strchr(display, ':'); if (p != NULL) p = strchr(p, '.'); if (p != NULL) strncpy(screen, p + 1, sizeof(screen)); else strcpy(screen, "0"); if (getenv("PBSDEBUG") != NULL) fprintf(stderr, "x11_get_proto: %s\n", line); f = popen(line, "r"); if (f == NULL) { fprintf(stderr, "execution of '%s' failed, errno=%d (%s)\n", line, errno, pbs_strerror(errno)); } else if (fgets(line, sizeof(line), f) == 0) { fprintf(stderr, "cannot read data from '%s', errno=%d (%s)\n", line, errno, pbs_strerror(errno)); } else if (sscanf(line, "%*s %511s %511s", proto, data) != 2) { fprintf(stderr, "cannot parse output from '%s'\n", line); } else { /* SUCCESS */ got_data = 1; } if (f != NULL) pclose(f); #if 0 /* we aren't inspecting the returned xauth data yet */ /* * If we didn't get authentication data, just make up some * data. The forwarding code will check the validity of the * response anyway, and substitute this data. The X11 * server, however, will ignore this fake data and use * whatever authentication mechanisms it was using otherwise * for the local connection. */ if (!got_data) { u_int32_t _rand = 0; int i; fprintf(stderr, "Warning: No xauth data; using fake authentication data for X11 forwarding.\n"); strncpy(proto, "MIT-MAGIC-COOKIE-1", sizeof proto); for (i = 0; i < 16; i++) { if (i % 4 == 0) _rand = rand(); snprintf(data + 2 * i, sizeof data - 2 * i, "%02x", _rand & 0xff); _rand >>= 8; } } #endif if (!got_data) { /* FAILURE */ return(NULL); } authstring = malloc(strlen(proto) + strlen(data) + strlen(screen) + 4); if (authstring == NULL) { /* FAILURE */ return(NULL); } sprintf(authstring, "%s:%s:%s", proto, data, screen); return(authstring); } /* END x11_get_proto() */ char *smart_strtok( char *line, /* I */ char *delims, /* I */ char **ptrPtr, /* O */ int ign_backslash) /* I */ { char *head = NULL; char *start = NULL; int dindex; int ignchar; int ignore; int sq_count = 0; int dq_count = 0; int sb_count = 0; char *tmpLine = NULL; int tmpLineSize; int tindex; char *ptr; if (ptrPtr == NULL) { /* FAILURE */ return(head); } else if (line != NULL) { *ptrPtr = line; } else if (*ptrPtr == NULL) { /* FAILURE */ return(head); } start = *ptrPtr; tmpLineSize = (line == NULL) ? strlen(*ptrPtr) + 1 : strlen(line) + 1; tmpLine = (char *)malloc(tmpLineSize * sizeof(char)); tmpLine[0] = '\0'; tindex = 0; ignchar = FALSE; ptr = *ptrPtr; while (*ptr != '\0') { if (*ptr == '\'') { sq_count++; if ((head != NULL) && !(sq_count % 2) && !(dq_count % 2)) { ptr++; ignchar = TRUE; } else { ignore = TRUE; if (ign_backslash == TRUE) { /* check if backslash precedes delimiter */ if ((ptr > start) && (*(ptr-1) == '\\')) { /* check if backslash is backslashed */ if ((ptr > start + 1) && (*(ptr-2) != '\\')) { /* delimiter is backslashed, ignore */ ignore = FALSE; sq_count--; } } } if (ignore == TRUE) { ptr++; ignchar = TRUE; } } } else if (*ptr == '\"') { dq_count++; if ((head != NULL) && !(sq_count % 2) && !(dq_count % 2)) { ptr++; ignchar = TRUE; } else { ignore = TRUE; if (ign_backslash == TRUE) { /* check if backslash precedes delimiter */ if ((ptr > start) && (*(ptr-1) == '\\')) { /* check if backslash is backslashed */ if ((ptr > start + 1) && (*(ptr-2) != '\\')) { /* delimiter is backslashed, ignore */ ignore = FALSE; dq_count--; } } } if (ignore == TRUE) { ptr++; ignchar = TRUE; } } } else if (*ptr == '[' ) { sb_count = 1; } else if (*ptr == ']') { sb_count = 0; } else if (*ptr == '{') { sb_count = 1; } else if (*ptr == '}') { sb_count = 0; } else if (!(sq_count % 2) && !(dq_count % 2) && (sb_count == 0)) { /* not in quotations, locate delimiter */ for (dindex = 0; delims[dindex] != '\0'; dindex++) { if (*ptr != delims[dindex]) continue; if ((ign_backslash == TRUE) && (head != NULL)) { /* check if backslash precedes delimiter */ if ((ptr > head) && (*(ptr-1) == '\\')) { /* check if backslash is backslashed */ if ((ptr > head + 1) && (*(ptr-1) != '\\')) { /* delimiter is backslashed, ignore */ continue; } } } /* delimiter found */ *ptr = '\0'; ptr++; if (head != NULL) { *ptrPtr = ptr; tmpLine[tindex] = '\0'; if (tindex > 0) strcpy(head,tmpLine); free(tmpLine); return(head); } ignchar = TRUE; break; } /* END for (dindex) */ } if ((ignchar != TRUE) && (*ptr != '\0')) { if (head == NULL) head = ptr; tmpLine[tindex++] = ptr[0]; ptr++; } ignchar = FALSE; } /* END while (*ptr != '\0') */ tmpLine[tindex] = '\0'; if (tindex > 0) strcpy(head,tmpLine); free(tmpLine); *ptrPtr = ptr; return(head); } /* END smart_strtok */ int get_name_value(start, name, value) char *start; char **name; char **value; { static char *tok_ptr; char *curr_ptr; char *equals; static char tmpLine[65536]; /* we've reached the end */ if ((start == NULL) && (*tok_ptr == '\0')) return(0); if (start != NULL) strcpy(tmpLine, start); curr_ptr = smart_strtok(tmpLine,"",&tok_ptr,FALSE); if ((curr_ptr == NULL)) return(0); if ((*curr_ptr == '=') || (*curr_ptr == '\0')) { /* no name, fail */ return(-1); } /* skip leading spaces */ while (isspace((int)*curr_ptr) && (*curr_ptr)) curr_ptr++; *name = curr_ptr; equals = *name; /* skip over name */ while ((*equals) && (!isspace((int)*equals)) && (*equals != '=')) equals++; /* strip blanks */ while ((*equals) && (isspace((int)*equals))) *equals++ = '\0'; if (*equals != '=') return (-1); /* should have found a = as first non blank */ *equals++ = '\0'; /* skip leading white space */ while (isspace((int)*equals) && *equals) equals++; if (*equals == '\0') return(-1); *value = equals; return (1); } char *set_dir_prefix( char *prefix, int diropt) { char *s; if (notNULL(prefix)) { return(prefix); } if (diropt == TRUE) { return(""); } if ((s = getenv("PBS_DPREFIX")) != NULL) { return(s); } return(PBS_DPREFIX_DEFAULT); } /* END set_dir_prefix() */ int isexecutable( char *s) /* I */ { char *c; c = s; if ((*c == ':') || ((*c == '#') && (*(c + 1) == '!'))) { return(FALSE); } while (isspace(*c)) c++; if (notNULL(c)) { return(*c != '#'); } return(FALSE); } char *ispbsdir( char *s, char *prefix) { char *it; int l; it = s; while (isspace(*it)) it++; l = strlen(prefix); if ((l > 0) && (strncmp(it, prefix, l) == 0)) { return(it + l); } return((char *)NULL); } #define MMAX_VERIFY_BYTES 50 int istext( FILE *fd, /* I */ int *IsText) /* O (optional) */ { int i; int c; if (IsText != NULL) *IsText = FALSE; if (fd == NULL) { return(0); } if (fd == stdin) { return(1); } /* read first characters to ensure this is ASCII text */ for (i = 0;i < MMAX_VERIFY_BYTES;i++) { c = fgetc(fd); if (c == EOF) break; if (!isprint(c) && !isspace(c)) { fseek(fd, 0, SEEK_SET); return(0); } } /* END for (i) */ if (IsText != NULL) *IsText = TRUE; fseek(fd, 0, SEEK_SET); return(1); } /* END FileIsText() */ /* return 3, 4, 5, 6, -1 on FAILURE, 0 on success */ int get_script( int ArgC, /* I */ char **ArgV, /* I */ FILE *file, /* I */ char *script, /* O (minsize=X) */ char *prefix) /* I */ { char s[MAX_LINE_LEN + 1]; char *sopt; int exec = FALSE; char *cont; char tmp_name[] = "/tmp/qsub.XXXXXX"; FILE *TMP_FILE; char *in; int tmpfd; int index; /* START WRAPPER */ char cfilter[MAXPATHLEN + 1024]; char tmp_name2[] = "/tmp/qsub.XXXXXX"; struct stat sfilter; FILE *filesaved; FILE *filter_pipe; int rc; /* if the submitfilter exists, run it. */ /* check that the file is text */ if (istext(file, NULL) == 0) { fprintf(stderr, "qsub: file must be an ascii script\n"); return(4); } if (stat(PBS_Filter, &sfilter) != -1) { /* run the copy through the submit filter. */ if ((tmpfd = mkstemp(tmp_name2)) < 0) { fprintf(stderr, "qsub: could not create filter o/p %s\n", tmp_name2); return(4); } close(tmpfd); strcpy(cfilter, PBS_Filter); for (index = 1;index < ArgC;index++) { if (ArgV[index] != NULL) { strcat(cfilter, " "); strcat(cfilter, ArgV[index]); } } /* END for (index) */ strcat(cfilter, " >"); strcat(cfilter, tmp_name2); filter_pipe = popen(cfilter, "w"); while ((in = fgets(s, MAX_LINE_LEN, file)) != NULL) { if (fputs(in, filter_pipe) < 0) { fprintf(stderr, "qsub: error writing to filter stdin\n"); fclose(filter_pipe); unlink(tmp_name2); return(3); } } rc = pclose(filter_pipe); if (WEXITSTATUS(rc) == (unsigned char)SUBMIT_FILTER_ADMIN_REJECT_CODE) { fprintf(stderr, "qsub: Your job has been administratively rejected by the queueing system.\n"); fprintf(stderr, "qsub: There may be a more detailed explanation prior to this notice.\n"); unlink(tmp_name2); return(3); } if (WEXITSTATUS(rc)) { fprintf(stderr, "qsub: submit filter returned an error code, aborting job submission.\n"); unlink(tmp_name2); return(3); } /* get rid of the i/p copy. */ /* preserve the original pointer. */ filesaved = file; /* open the filtered script. */ if ((file = fopen(tmp_name2, "r")) == NULL) { fprintf(stderr, "qsub: could not open filter o/p %s\n", tmp_name2); unlink(tmp_name2); file = filesaved; return(3); } /* Get rid of the filtered o/p; data remains accessible until */ /* file is closed. */ unlink(tmp_name2); /* Complete redirection. */ fclose(filesaved); } /* END if (stat(PBS_Filter,&sfilter) != -1) */ /* END WRAPPER */ if ((tmpfd = mkstemp(tmp_name)) < 0) { fprintf(stderr, "qsub: could not create copy of script %s\n", tmp_name); return(4); } if ((TMP_FILE = fdopen(tmpfd, "w+")) == NULL) { fprintf(stderr, "qsub: could not create copy of script %s\n", tmp_name); unlink(tmp_name); return(4); } while ((in = fgets(s, MAX_LINE_LEN, file)) != NULL) { int len; /* replace DOS EOL ('^M') characters */ len = strlen(in); if ((len >= 2) && (in[len - 2] == '\r') && (in[len - 1] == '\n')) { in[len - 2] = '\n'; in[len - 1] = '\0'; } if (!exec && ((sopt = ispbsdir(s, prefix)) != NULL)) { while ((*(cont = in + strlen(in) - 2) == '\\') && (*(cont + 1) == '\n')) { /* next line is continuation of this line */ *cont = '\0'; /* clear newline from our copy */ if (fputs(in, TMP_FILE) < 0) { fprintf(stderr, "qsub: error writing copy of script, %s\n", tmp_name); fclose(TMP_FILE); unlink(tmp_name); return(3); } in = cont; if ((in = fgets(in, MAX_LINE_LEN - (in - s), file)) == NULL) { fprintf(stderr, "qsub: unexpected end-of-file or read error in script\n"); fclose(TMP_FILE); unlink(tmp_name); return(6); } } /* END while ((*(cont = in + strlen(in) - 2) == '\\') && (*(cont + 1) == '\n')) */ if (do_dir(sopt) != 0) { return(-1); } } /* END if (!exec && ((sopt = ispbsdir(s,prefix)) != NULL)) */ else if (!exec && isexecutable(s)) { exec = TRUE; } if (fputs(in, TMP_FILE) < 0) { fprintf(stderr, "qsub: error writing copy of script, %s\n", tmp_name); fclose(TMP_FILE); unlink(tmp_name); return(3); } } /* END while ((in = fgets(s,MAX_LINE_LEN,file)) != NULL) */ fclose(TMP_FILE); if (ferror(file)) { fprintf(stderr, "qsub: error reading script file\n"); return(5); } strcpy(script, tmp_name); return(0); } /* END get_script() */ void make_argv( int *argc, char *argv[], char *line) { char *l, *b, *c, *buffer; int len; char quote; buffer = malloc(strlen(line) + 1); if (buffer == NULL) { fprintf(stderr, "qsub: out of memory\n"); exit(2); } *argc = 0; argv[(*argc)++] = "qsub"; l = line; b = buffer; while (isspace(*l)) l++; c = l; while (*c != '\0') { if ((*c == '"') || (*c == '\'')) { if ((*c == '\'') && (strchr(c+1,'\'') == NULL) && (!strcmp(argv[*argc-1],"-M"))) { /* if this is an email list and it has a single quote, this is a legal character, * so allow unmatched quotes as part of the qsub */ *b++ = *c++; } else { quote = *c; c++; while ((*c != quote) && *c) *b++ = *c++; if (*c == '\0') { fprintf(stderr, "qsub: unmatched %c\n", *c); exit(1); } c++; } } else if (*c == '\\') { c++; *b++ = *c++; } else if (isspace(*c)) { len = c - l; assert(len > 0); if (argv[*argc] != NULL) free(argv[*argc]); argv[*argc] = (char *)malloc(len + 1); if (argv[*argc] == NULL) { fprintf(stderr, "qsub: out of memory\n"); exit(2); } *b = '\0'; strcpy(argv[(*argc)++], buffer); while (isspace(*c)) c++; l = c; b = buffer; } else { *b++ = *c++; } } if (c != l) { len = c - l; assert(len > 0); if (argv[*argc] != NULL) free(argv[*argc]); argv[*argc] = (char *) malloc(len + 1); if (argv[*argc] == NULL) { fprintf(stderr, "qsub: out of memory\n"); exit(2); } *b = '\0'; strcpy(argv[(*argc)++], buffer); } free(buffer); return; } /* END make_argv() */ int do_dir( char *opts) { static int opt_pass = 1; int argc; #define MAX_ARGV_LEN 128 static char *vect[MAX_ARGV_LEN + 1]; if (opt_pass == 1) { argc = 0; while (argc < MAX_ARGV_LEN + 1) vect[argc++] = NULL; } make_argv(&argc, vect, opts); return(process_opts(argc, vect, opt_pass++)); } /* END do_dir() */ /* globals */ int inter_sock = -1; struct termios oldtio; struct attrl *attrib = NULL; char *new_jobname; /* return from submit request */ char dir_prefix[MAX_QSUB_PREFIX_LEN + 1]; char path_out[MAXPATHLEN + 1]; char destination[PBS_MAXDEST]; static char server_out[PBS_MAXSERVERNAME + PBS_MAXPORTNUM + 2]; char server_host[PBS_MAXHOSTNAME + 1]; char qsub_host[PBS_MAXHOSTNAME + 1]; char owner_uid[MAXPATHLEN + 1]; long cnt2server_retry = -100; /* state booleans for protecting already-set options */ int a_opt = FALSE; int b_opt = FALSE; int c_opt = FALSE; int e_opt = FALSE; int f_opt = FALSE; int h_opt = FALSE; int j_opt = FALSE; int J_opt = FALSE; int k_opt = FALSE; int l_opt = FALSE; int m_opt = FALSE; int o_opt = FALSE; int p_opt = FALSE; int P_opt = FALSE; int q_opt = FALSE; int r_opt = FALSE; int t_opt = FALSE; int T_opt = FALSE; int u_opt = FALSE; int v_opt = FALSE; int z_opt = FALSE; int A_opt = FALSE; int C_opt = FALSE; int F_opt = FALSE; int M_opt = FALSE; int N_opt = FALSE; int S_opt = FALSE; int V_opt = FALSE; int Depend_opt = FALSE; int Interact_opt = FALSE; int Run_Inter_opt = FALSE; int Stagein_opt = FALSE; int Stageout_opt = FALSE; int Grouplist_opt = FALSE; int Forwardx11_opt = FALSE; int Umask_opt = FALSE; char *v_value = NULL; char *copy_env_value( char *dest, /* destination */ char *pv, /* value string */ int quote_flg) /* non-zero then assume single word (quoting on) */ { int go = 1; int q_ch = 0; while (*dest) ++dest; while (go && *pv) { switch (*pv) { case '"': case '\'': if (q_ch) { /* local quoting is in progress */ if (q_ch == (int)*pv) { q_ch = 0; /* end quote */ } else { *dest++ = '\\'; /* escape quote */ *dest++ = *pv; } } else if (quote_flg) { /* global quoting is on */ *dest++ = '\\'; /* escape quote */ *dest++ = *pv; } else { q_ch = (int) * pv; /* turn local quoting on */ } break; case '\\': *dest++ = '\\'; /* escape back-slash */ *dest++ = *pv; break; case '\n': *dest++ = '\\'; /* escape newline */ *dest++ = *pv; break; case ',': if (q_ch || quote_flg) { *dest++ = '\\'; *dest++ = *pv; } else { go = 0; /* end of value string */ } break; default: *dest++ = *pv; break; } pv++; } /* END while (go && *pv) */ *dest = '\0'; if (q_ch) return(NULL); /* error-unterminated quote */ return(pv); } int set_job_env( char **envp) /* I */ { char **evp; char *job_env; char *s, *c, *env, l; unsigned len; #ifdef QSUBHOSTNAME int rc = 0; #endif int eindex; const char *EList[] = { "HOME", "LANG", "LOGNAME", "MAIL", "PATH", "SHELL", "TZ", NULL }; /* Calculate how big to make the variable string. */ len = PBS_MAXHOSTNAME * 2 + MAXPATHLEN; if (v_opt) { len += strlen(v_value); } if (V_opt) { evp = envp; while (notNULL(*evp)) { /* add 1 for ',' */ len += strlen(*evp) + 1; evp++; } } for (eindex = 0;EList[eindex] != NULL;eindex++) { env = getenv(EList[eindex]); if (env == NULL) continue; /* prepend 'PBS_O_' to each var and add '2' for ',' and '=' */ len += strlen(env) + strlen(EList[eindex]) + strlen("PBS_O_") + 2; } /* END for (eindex) */ if (PBS_InitDir[0] != '\0') { len += strlen("PBS_O_INITDIR=") + strlen(PBS_InitDir) + 1; } if (PBS_RootDir[0] != '\0') { len += strlen("PBS_O_ROOTDIR=") + strlen(PBS_RootDir) + 1; } if (PBS_WorkDir[0] != '\0') { len += strlen("PBS_O_WORKDIR=") + strlen(PBS_WorkDir) + 1; set_attr(&attrib, ATTR_init_work_dir, PBS_WorkDir); } len += strlen("PBS_SERVER=") + 1; len++; /* Terminating '0' */ if ((job_env = (char *)malloc(len)) == NULL) { return(FALSE); } *job_env = '\0'; /* Send the required variables with the job. */ c = getenv("HOME"); strcat(job_env, "PBS_O_HOME="); if (c != NULL) strcat(job_env, c); else strcat(job_env, "/"); c = getenv("LANG"); if (c != NULL) { strcat(job_env, ",PBS_O_LANG="); strcat(job_env, c); } c = getenv("LOGNAME"); if (c != NULL) { strcat(job_env, ",PBS_O_LOGNAME="); strcat(job_env, c); } c = getenv("PATH"); if (c != NULL) { strcat(job_env, ",PBS_O_PATH="); strcat(job_env, c); } c = getenv("MAIL"); if (c != NULL) { strcat(job_env, ",PBS_O_MAIL="); strcat(job_env, c); } c = getenv("SHELL"); if (c != NULL) { strcat(job_env, ",PBS_O_SHELL="); strcat(job_env, c); } c = getenv("TZ"); if (c != NULL) { strcat(job_env, ",PBS_O_TZ="); strcat(job_env, c); } /* * Commented out by dbeer * This isn't a reliable way to find the hostname because it doesn't * account for the interface over which the connection is happening, * or any aliasing on that interface. Letting the server discover * PBS_O_HOST works better and the code is already there. * * Unless you are certain CRAY sites that want this value for PBS_O_HOST */ #ifdef QSUBHOSTNAME if (qsub_host[0] != '\0' || (rc = gethostname(qsub_host, PBS_MAXHOSTNAME + 1)) == 0) { if ((rc = get_fullhostname(qsub_host, qsub_host, PBS_MAXHOSTNAME, NULL)) == 0) { s = job_env + strlen(job_env); strcat(job_env, ",PBS_O_HOST="); strcat(job_env, qsub_host); s++; set_attr(&attrib, ATTR_submit_host, qsub_host); s = 0; } } if (rc != 0) { fprintf(stderr, "qsub: cannot get (full) local host name\n"); exit(3); } #endif if (server_host[0] != '\0') { if (get_fullhostname(server_host, server_host, PBS_MAXHOSTNAME, NULL) == 0) { strcat(job_env,",PBS_SERVER="); strcat(job_env,server_host); } else { fprintf(stderr,"qsub: cannot get full server host name\n"); exit(3); } } else { c = pbs_default(); if (*c != '\0') { strncpy(server_host, c, sizeof(server_host)); strcat(job_env,",PBS_SERVER="); strcat(job_env,server_host); } else { strcat(job_env,",PBS_SERVER="); strcat(job_env,qsub_host); } } if (owner_uid[0] != '\0') { strcat(job_env, ",PBS_O_UID="); strcat(job_env, owner_uid); } /* load init dir into env if specified */ if (PBS_InitDir[0] != '\0') { /* load init dir into env */ strcat(job_env, ",PBS_O_INITDIR="); strcat(job_env, PBS_InitDir); } if (PBS_RootDir[0] != '\0') { /* load init dir into env */ strcat(job_env, ",PBS_O_ROOTDIR="); strcat(job_env, PBS_RootDir); } /* get current working directory, use $PWD if available, it is more */ /* NFS automounter "friendly". But must double check that is right */ /* load work dir into env if specified */ if (PBS_WorkDir[0] != '\0') { /* load work dir into env */ strcat(job_env, ",PBS_O_WORKDIR="); strcat(job_env, PBS_WorkDir); set_attr(&attrib, ATTR_init_work_dir, PBS_WorkDir); } else { s = job_env + strlen(job_env); strcat(job_env, ",PBS_O_WORKDIR="); c = getenv("PWD"); if (c != NULL) { struct stat statbuf; dev_t dev; ino_t ino; if (stat(c, &statbuf) < 0) { c = NULL; /* cannot stat, cannot trust it */ } else { dev = statbuf.st_dev; ino = statbuf.st_ino; if (stat(".", &statbuf) < 0) { /* compare against "." */ perror("qsub: cannot stat current directory: "); exit(3); } if (!memcmp(&dev, &statbuf.st_dev, sizeof(dev_t)) && !memcmp(&ino, &statbuf.st_ino, sizeof(ino_t))) { strcat(job_env, c); set_attr(&attrib, ATTR_init_work_dir, c); } else { c = NULL; } } } /* END if (c != NULL) */ if (c == NULL) { /* fall back to using the cwd */ c = job_env + strlen(job_env); if (getcwd(c, MAXPATHLEN + 1) == NULL) { *s = '\0'; } else { set_attr(&attrib, ATTR_init_work_dir, PBS_WorkDir); } } } /* Send these variables with the job. */ /* POSIX requirement: If a variable is given without a value, supply the value from the environment. */ /* MY requirement: There can be no white space in -v value. */ if (v_opt) { c = v_value; state1: /* goto label : Initial state comes here */ switch (*c) { case ',': case '=': return FALSE; /*NOTREACHED*/ break; case '\0': goto final; /*NOTRREACHED*/ break; } s = c; /* pass through to next case */ state2: /* goto label : Variable name */ switch (*c) { case ',': case '\0': goto state3; /*NOTREACHED*/ break; case '=': /* if we just have the '=' and no value after it then we look in the environment same as if the '=' was not there */ if ((c[1] == ',') || (c[1] == '\0')) { *c = '\0'; c++; goto state3; /*NOTREACHED*/ } goto state4; /*NOTREACHED*/ break; default: c++; goto state2; /*NOTREACHED*/ break; } /* END switch (*c) */ state3: /* No value - get it from qsub environment */ l = *c; *c = '\0'; env = getenv(s); if (env == NULL) { env = ""; } if (strlen(job_env) + 2 + strlen(s) + 2*strlen(env) >= len) { /* increase size of job env buffer */ len += 2 * strlen(env) + 1; job_env = (char *)realloc(job_env, len); if (job_env == NULL) { return(FALSE); } } strcat(job_env, ","); strcat(job_env, s); strcat(job_env, "="); if (copy_env_value(job_env, env, 1) == NULL) { return(FALSE); } if (l == ',') c++; goto state1; state4: /* goto label - Value specified */ *c++ = '\0'; if (strlen(job_env) + 2 + strlen(s) + 2*strlen(c) >= len) { /* increase size of job env buffer */ len += 2 * strlen(c) + 1; job_env = (char *)realloc(job_env, len); if (job_env == NULL) { return(FALSE); } } strcat(job_env, ","); strcat(job_env, s); strcat(job_env, "="); if ((c = copy_env_value(job_env, c, 0)) == NULL) { return(FALSE); } goto state1; } /* END if (v_opt) */ final: if (V_opt != 0) { /* Send every environment variable with the job. */ evp = envp; while (notNULL(*evp)) { s = *evp; while ((*s != '=') && *s) ++s; if (!*s) { evp++; continue; } *s = '\0'; /* NOTE: *s is clobbering our current, real, environ */ if (strlen(job_env) + 2 + strlen(*evp) + 2*strlen(s + 1) >= len) { /* increase size of job env buffer */ len += 2 * strlen(s + 1) + 1; job_env = (char *)realloc(job_env, len); if (job_env == NULL) { *s = '='; /* restore our existing environ */ return(FALSE); } } strcat(job_env, ","); strcat(job_env, *evp); strcat(job_env, "="); copy_env_value(job_env, s + 1, 1); *s = '='; /* restore our existing environ */ evp++; } } /* END if (V_opt) */ set_attr(&attrib, ATTR_v, job_env); free(job_env); return(TRUE); } /* END set_job_env() */ /* * The following bunch of functions support the "Interactive Job" * capability of PBS. */ /* * interactive_port - get a socket to listen to for "interactive" job * When the "interactive" job is run, its standard in, out, and error * will be connected to this socket. */ char *interactive_port(int *sock) { torque_socklen_t namelen; static char portstring[8]; struct sockaddr_in myaddr; unsigned short port; *sock = socket(AF_INET, SOCK_STREAM, 0); if (*sock < 0) { perror("qsub: unable to obtain socket"); exit(1); } namelen = sizeof(myaddr); myaddr.sin_family = AF_INET; myaddr.sin_addr.s_addr = INADDR_ANY; myaddr.sin_port = 0; if (bind(*sock, (struct sockaddr *)&myaddr, namelen) < 0) { perror("qsub: unable to bind to socket"); exit(1); } /* get port number assigned */ if (getsockname(*sock, (struct sockaddr *)&myaddr, &namelen) < 0) { perror("qsub: unable to get port number"); exit(1); } port = ntohs(myaddr.sin_port); sprintf(portstring, "%u", (unsigned int)port); if (listen(*sock, 1) < 0) { perror("qsub: listen on interactive socket"); exit(1); } return(portstring); } /* END interactive_port() */ /* * settermraw - set terminal into "raw" mode */ void settermraw( struct termios *ptio) { struct termios tio; tio = *ptio; tio.c_lflag &= ~(ICANON | ISIG | ECHO | ECHOE | ECHOK); tio.c_iflag &= ~(IGNBRK | INLCR | ICRNL | IXON | IXOFF); tio.c_oflag = 0; tio.c_oflag |= (OPOST); /* TAB3 */ tio.c_cc[VMIN] = 1; tio.c_cc[VTIME] = 0; #if defined(TABDLY) && defined(TAB3) if ((tio.c_oflag & TABDLY) == TAB3) tio.c_oflag &= ~TABDLY; #endif tio.c_cc[VKILL] = -1; tio.c_cc[VERASE] = -1; if (tcsetattr(0, TCSANOW, &tio) < 0) perror("qsub: set terminal mode"); return; } /* END settermraw() */ /* * stopme - suspend process on ~^Z or ~^Y * on suspend, reset terminal to normal "cooked" mode; * when resumed, again set terminal to raw. */ void stopme( pid_t p) /* pid of 0 (process group) or just myself (writer) */ { tcsetattr(0, TCSANOW, &oldtio); /* reset terminal */ kill(p, SIGTSTP); settermraw(&oldtio); /* back to raw when we resume */ return; } /* * Interactive Reader process: reads from the remote socket, * and writes that out to the stdout */ int reader( int s, /* I - reading socket */ int d) /* I - writing socket */ { char buf[4096]; int c; char *p; int wc; /* read from the socket, and write to d */ /* NOTE: s should be blocking */ while (1) { c = read(s, buf, sizeof(buf)); if (c > 0) { p = buf; while (c) { if ((wc = write(d, p, c)) < 0) { if (errno == EINTR) { continue; } perror("qsub: write error"); return(-1); } c -= wc; p += wc; } } else if (c == 0) { return(0); /* EOF - all done */ } else { if (errno == EINTR) continue; if (errno == EAGAIN) { sleep(1); continue; } perror("qsub: read error"); return(-1); } } /* END while (1) */ return(0); } /* END reader() */ /* * Writer process: reads from stdin, and writes * data out to the rem socket */ void writer( int s, /* writing socket */ int d) /* reader socket */ { char c; int i; int newline = 1; char tilde = '~'; int wi; /* read from stdin, and write to the socket */ while (1) { i = read(d, &c, 1); if (i > 0) { /* read data */ if (newline) { if (c == tilde) { /* maybe escape character */ /* read next character to check */ while ((i = read(d, &c, 1)) != 1) { if ((i == -1) && (errno == EINTR)) continue; break; } if (i != 1) break; if (c == '.') /* termination character */ break; if (c == oldtio.c_cc[VSUSP]) { stopme(0); /* ^Z suspend all */ continue; #ifdef VDSUSP } else if (c == oldtio.c_cc[VDSUSP]) { stopme(getpid()); continue; #endif /* VDSUSP */ } else { /* not escape, write out tilde */ while ((wi = write(s, &tilde, 1)) != 1) { if ((wi == -1) && (errno == EINTR)) continue; break; } if (wi != 1) break; } } newline = 0; /* no longer at start of line */ } else { /* reset to newline if \n \r kill or interrupt */ newline = (c == '\n') || (c == oldtio.c_cc[VKILL]) || (c == oldtio.c_cc[VINTR]) || (c == '\r'); } while ((wi = write(s, &c, 1)) != 1) { /* write out character */ if ((wi == -1) && (errno == EINTR)) continue; break; } if (wi != 1) break; } else if (i == 0) { /* EOF */ break; } else if (i < 0) { /* error */ if (errno == EAGAIN) { sleep(1); continue; } if (errno == EAGAIN) { sleep(1); continue; } if (errno != EINTR) { perror("qsub: read error"); return; } } } /* END while (1) */ return; } /* END writer() */ /* * getwinsize - get the current window size */ int getwinsize( struct winsize *wsz) { if (ioctl(0, TIOCGWINSZ, wsz) < 0) { perror("qsub: unable to get window size"); return(-1); } return(0); } /* * send_winsize = send the current tty's window size */ void send_winsize( int sock, struct winsize *wsz) { char buf[PBS_TERM_BUF_SZ]; sprintf(buf, "WINSIZE %hu,%hu,%hu,%hu", wsz->ws_row, wsz->ws_col, wsz->ws_xpixel, wsz->ws_ypixel); if (write(sock, buf, PBS_TERM_BUF_SZ) != PBS_TERM_BUF_SZ) { perror("sending winsize"); exit(2); } return; } /* * send_term - send the current TERM type and certain control characters */ void send_term( int sock) { char buf[PBS_TERM_BUF_SZ]; char *term; char cc_array[PBS_TERM_CCA]; strcpy(buf, "TERM="); term = getenv("TERM"); if (term == NULL) strcat(buf, "unknown"); else strncat(buf, term, PBS_TERM_BUF_SZ - 5); if (write(sock, buf, PBS_TERM_BUF_SZ) != PBS_TERM_BUF_SZ) { perror("sending term type"); exit(2); } cc_array[0] = oldtio.c_cc[VINTR]; cc_array[1] = oldtio.c_cc[VQUIT]; cc_array[2] = oldtio.c_cc[VERASE]; cc_array[3] = oldtio.c_cc[VKILL]; cc_array[4] = oldtio.c_cc[VEOF]; cc_array[5] = oldtio.c_cc[VSUSP]; if (write(sock, cc_array, PBS_TERM_CCA) != PBS_TERM_CCA) { perror("sending term options"); exit(2); } return; } /* * catchchild = signal handler for Death of Child */ void catchchild( int sig) { int status; int pid; while (1) { pid = waitpid(-1, &status, WNOHANG | WUNTRACED); if (pid == 0) { return; } if ((pid > 0) && (WIFSTOPPED(status) == 0)) break; if ((pid == -1) && (errno != EINTR)) { perror("qsub: bad status in catchchild: "); return; } } if (interactivechild > 0) kill(interactivechild, SIGTERM); if (x11child > 0) kill(x11child, SIGTERM); /* reset terminal to cooked mode */ if(have_terminal) tcsetattr(0, TCSANOW, &oldtio); exit(0); /*NOTREACHED*/ return; } /* END catchchild() */ void no_suspend( int sig) { fprintf(stderr, "Sorry, you cannot suspend qsub until the job is started\n"); fflush(stderr); } /* does not return */ void bailout(void) { int c; shutdown(inter_sock, 2); close(inter_sock); printf("Job %s is being deleted\n", new_jobname); c = cnt2server(server_out); if (c <= 0) { fprintf(stderr, "qsub: cannot connect to server %s (errno=%d) %s\n", pbs_server, pbs_errno, pbs_strerror(pbs_errno)); if (getenv("PBSDEBUG") != NULL) { fprintf(stderr, "qsub: pbs_server daemon may not be running on host %s or hostname in file '$TORQUEHOME/server_name' may be incorrect)\n", pbs_server); } exit(1); } pbs_deljob(c, new_jobname, NULL); pbs_disconnect(c); exit(0); } void toolong( int sig) { printf("Timeout -- deleting job\n"); bailout(); /*NOTREACHED*/ exit(0); } void catchint( int sig) { int c; printf("Do you wish to terminate the job and exit (y|[n])? "); fflush(stdout); while (1) { alarm(60); /* give a minute to think about it */ c = getchar(); if ((c == 'n') || (c == 'N') || (c == '\n')) break; if ((c == 'y') || (c == 'Y')) { bailout(); /*NOTREACHED*/ exit(0); } if (printf("yes or no please\n") < 0) { /* terminal probably went away */ bailout(); /*NOTREACHED*/ exit(0); } while ((c != '\n') && (c != EOF)) c = getchar(); } /* END while (1) */ alarm(0); /* reset alarm */ while ((c != '\n') && (c != EOF)) c = getchar(); return; } /* END catchint() */ void x11handler( int inter_sock) { struct pfwdsock *socks; int n; char *display; socks = calloc(sizeof(struct pfwdsock), NUM_SOCKS); if (!socks) { perror("x11handler malloc: "); exit(EXIT_FAILURE); } for (n = 0;n < NUM_SOCKS;n++) (socks + n)->active = 0; (socks + 0)->sock = inter_sock; (socks + 0)->active = 1; (socks + 0)->listening = 1; /* Try to open a socket for the local X server. */ display = getenv("DISPLAY"); if (!display) { fprintf(stderr, "DISPLAY not set."); return; } port_forwarder(socks, x11_connect_display, display, 0, NULL); exit(EXIT_FAILURE); } /* * interactive - set up for interactive communication with job */ void interactive(void) { int amt; char cur_server[PBS_MAXSERVERNAME + PBS_MAXPORTNUM + 2]; char momjobid[LOG_BUF_SIZE+1]; int news; int nsel; char *pc; fd_set selset; struct sigaction act; struct sockaddr_in from; torque_socklen_t fromlen; struct timeval timeout; struct winsize wsz; /* Catch SIGINT and SIGTERM, and */ /* setup to catch Death of child */ sigemptyset(&act.sa_mask); act.sa_handler = catchint; act.sa_flags = 0; if ((sigaction(SIGINT, &act, (struct sigaction *)0) < 0) || (sigaction(SIGTERM, &act, (struct sigaction *)0) < 0)) { perror("unable to catch signals"); exit(1); } act.sa_handler = toolong; if ((sigaction(SIGALRM, &act, NULL) < 0)) { perror("cannot catch alarm"); exit(2); } /* save the old terminal setting */ if (have_terminal && tcgetattr(0, &oldtio) < 0) { perror("qsub: unable to get terminal settings"); exit(1); } /* Get the current window size, to be sent to MOM later */ if (!have_terminal || getwinsize(&wsz)) { wsz.ws_row = 20; /* unable to get actual values */ wsz.ws_col = 80; /* set defaults */ wsz.ws_xpixel = 0; wsz.ws_ypixel = 0; } printf("qsub: waiting for job %s to start\n", new_jobname); /* Accept connection on socket set up earlier */ nsel = 0; while (nsel == 0) { FD_ZERO(&selset); FD_SET(inter_sock, &selset); timeout.tv_usec = 0; timeout.tv_sec = 30; nsel = select(FD_SETSIZE, &selset, NULL, NULL, &timeout); if (nsel > 0) { break; } else if (nsel == -1) { if (errno == EINTR) { nsel = 0; } else { perror("qsub: select failed"); exit(1); } } /* connect to server, status job to see if still there */ if (!locate_job(new_jobname, server_out, cur_server)) { fprintf(stderr, "qsub: job %s apparently deleted\n", new_jobname); exit(1); } } /* apparently someone is attempting to connect to us */ fromlen = sizeof(from); if ((news = accept(inter_sock, (struct sockaddr *) & from, &fromlen)) < 0) { perror("qsub: accept error"); exit(1); } /* When MOM connects, she will send the job id for us to verify */ amt = LOG_BUF_SIZE + 1; pc = momjobid; while (amt > 0) { /* The mom is going to send us the job id for validation */ fromlen = read(news, pc, amt); if (fromlen <= 0) break; pc += fromlen; if (*(pc - 1) == '\0') break; amt -= fromlen; } if (strncmp(momjobid, "PBS:", 4) == 0) { fprintf(stderr, "qsub: %s\n", momjobid); shutdown(news, 2); exit(1); } if (strncmp(momjobid, new_jobname, PBS_MAXSVRJOBID) != 0) { fprintf(stderr, "qsub: invalid job name from execution server\n"); shutdown(news, 2); exit(1); } /* * got the right job, send: * terminal type as "TERM=xxxx" * window size as "WINSIZE=r,c,x,y" */ send_term(news); send_winsize(news, &wsz); printf("qsub: job %s ready\n\n", new_jobname); /* set SIGINT, SIGTERM processing to ignore */ act.sa_handler = SIG_IGN; if ((sigaction(SIGINT, &act, (struct sigaction *)0) < 0) || (sigaction(SIGTERM, &act, (struct sigaction *)0) < 0) || (sigaction(SIGALRM, &act, (struct sigaction *)0) < 0) || (sigaction(SIGTSTP, &act, (struct sigaction *)0) < 0)) { perror("unable to reset signals"); exit(1); } fflush(NULL); interactivechild = fork(); if (interactivechild == 0) { /* * child process - start the reader function * set terminal into raw mode */ if (have_terminal) settermraw(&oldtio); reader(news, fileno(stdout)); /* reset terminal */ if (have_terminal) tcsetattr(0, TCSANOW, &oldtio); printf("\nqsub: job %s completed\n", new_jobname); exit(0); } else if (interactivechild > 0) { /* parent - start the writer function */ act.sa_handler = catchchild; if (sigaction(SIGCHLD, &act, (struct sigaction *)0) < 0) { exit(1); } if (Forwardx11_opt) { if ((x11child = fork()) == 0) { act.sa_handler = SIG_DFL; sigaction(SIGTERM, &act, (struct sigaction *)0); x11handler(inter_sock); } } writer(news, fileno(stdin)); /* all done - make sure reader child is gone and reset terminal */ if (interactivechild > 0) kill(interactivechild, SIGTERM); if (x11child > 0) kill(x11child, SIGTERM); shutdown(inter_sock, SHUT_RDWR); close(inter_sock); if (have_terminal) tcsetattr(0, TCSANOW, &oldtio); exit(0); } else { perror("qsub: unable to fork"); exit(1); } return; } /* END interactive() */ int validate_group_list( char *glist) { /* check each group to determine if it is a valid group that the user can be a part of. * group list is of the form group[@host][,group[@host]...] */ char *groups = strdup(glist); char *delims = ","; char *tmp_group = strtok(groups,delims); char *at; char *u_name; char **pmem; struct group *grent; struct passwd *pwent; pwent = getpwuid(getuid()); u_name = pwent->pw_name; while (tmp_group != NULL) { if ((at = strchr(tmp_group,'@')) != NULL) *at = '\0'; if ((grent = getgrnam(tmp_group)) == NULL) return(FALSE); pmem = grent->gr_mem; if (pmem == NULL) return(FALSE); while (*pmem != NULL) { if (!strcmp(*pmem,u_name)) break; pmem++; } if (*pmem == NULL) { /* match not found */ return(FALSE); } tmp_group = strtok(NULL,delims); } return(TRUE); } /** * Process command line options. * * @see main() - parent * * NOTE: return 0 on success * NOTE: only run submitfilter if pass < 10 */ int process_opts( int argc, /* I */ char **argv, /* I */ int pass) /* I */ { int i; int c; int errflg = 0; int passet; time_t after; char a_value[80]; char *keyword; char *valuewd; char *pc; char *pdepend; FILE *fP = NULL; char tmp_name[] = "/tmp/qsub.XXXXXX"; char tmp_name2[] = "/tmp/qsub.XXXXXX"; char cline[4096]; char tmpLine[1024]; char flag; /* submitfilter flag character */ char *vptr; /* submitfilter flag value */ char tmpResources[4096] = ""; char *cP; char *ptr; struct stat sfilter; int tmpfd; int nitems; char search_string[256]; #if !defined(PBS_NO_POSIX_VIOLATION) #define GETOPT_ARGS "a:A:b:c:C:d:D:e:fF:hIJ:j:k:l:m:M:N:o:p:P:q:r:S:t:T:u:v:Vw:W:Xxz-:" #else #define GETOPT_ARGS "a:A:c:C:e:F:hJ:j:k:l:m:M:N:o:p:q:r:S:u:v:VW:z" #endif /* PBS_NO_POSIX_VIOLATION */ /* The following macro, together the value of passet (pass + 1) is used */ /* to enforce the following rules: 1. option on the command line take */ /* precedence over those in script directives. 2. With in the command */ /* line or within the script, the last occurance of an option takes */ /* precedence over the earlier occurance. */ #define if_cmd_line(x) if ((pass == 0) || (x != 1)) passet = pass + 1; if (pass > 0) { #ifdef linux optind = 0; /* prime getopt's starting point */ #else optind = 1; /* prime getopt's starting point */ #endif } while ((c = getopt(argc, argv, GETOPT_ARGS)) != EOF) { switch (c) { case '-': if ((optarg != NULL) && !strcmp(optarg, "version")) { fprintf(stderr, "version: %s\n", PACKAGE_VERSION); exit(0); } else if ((optarg != NULL) && !strcmp(optarg, "about")) { TShowAbout(); exit(0); } else if ((optarg != NULL) && !strncmp(optarg, "port=", strlen("port="))) { /* NOTE: mothballed, server can be specified via '-q' */ int PBSPort; /* FORMAT: --port=X */ ptr = optarg + strlen("port="); PBSPort = (int)strtol(ptr, NULL, 0); } else { errflg = 1; } break; case 'a': if_cmd_line(a_opt) { a_opt = passet; if ((after = cvtdate(optarg)) < 0) { fprintf(stderr, "qsub: illegal -a value\n"); errflg++; break; } sprintf(a_value, "%ld", (long)after); set_attr(&attrib, ATTR_a, a_value); } break; case 'A': if_cmd_line(A_opt) { A_opt = passet; set_attr(&attrib, ATTR_A, optarg); } break; case 'b': if_cmd_line(b_opt) { b_opt = passet; cnt2server_retry = atoi(optarg); } break; case 'c': if_cmd_line(c_opt) { c_opt = passet; /* remove whitespace */ while (isspace((int)*optarg)) optarg++; if (strlen(optarg) == 0) { fprintf(stderr, "qsub: illegal -c value\n"); errflg++; break; } pc = optarg; /* OLD FORMAT: -c { n | s | c | c=X } * New format: -c [ { | } ',' ] * new items: none | shutdown | checkpoint | name=xyz | dir=xyz | interval=X */ #if 0 if (strlen(optarg) == 1) { if ((*pc != 'n') && (*pc != 's') && (*pc != 'c')) { fprintf(stderr, "qsub: illegal -c value\n"); errflg++; break; } } else { if (strncmp(optarg, "c=", 2) != 0) { fprintf(stderr, "qsub: illegal -c value\n"); errflg++; break; } pc += 2; if (*pc == '\0') { fprintf(stderr, "qsub: illegal -c value\n"); errflg++; break; } while (isdigit(*pc)) pc++; if (*pc != '\0') { fprintf(stderr, "qsub: illegal -c value\n"); errflg++; break; } } #else nitems = csv_length(optarg); for (i = 0; i < nitems; i++) { if ((ptr = csv_nth(optarg, i)) != NULL) { strcpy(search_string, ptr); ptr = strchr(search_string, '='); if (ptr) *ptr = 0; else ptr = &search_string[strlen(search_string)]; while (ptr > search_string && *(ptr - 1) == ' ') *--ptr = 0; if (csv_find_string(checkpoint_strings, search_string) == NULL) { fprintf(stderr, "qsub: illegal -c value \"%s\"\n", ptr); errflg++; goto err; } } } #endif set_attr(&attrib, ATTR_c, optarg); } /* END if_cmd_line() */ break; case 'C': if_cmd_line(C_opt) { C_opt = passet; strcpy(dir_prefix, optarg); } break; case 'd': if (optarg != NULL) { if (optarg[0] != '/') { /* make '-d' relative to current directory, not $HOME */ char tmpPWD[1024]; char *mypwd; mypwd = getcwd(tmpPWD, sizeof(tmpPWD)); if (mypwd == NULL) { fprintf(stderr, "qsub: unable to get cwd: %d (%s)\n", errno, strerror(errno)); errflg++; /* we don't want to return yet, but we also don't want a segfault either */ /* NOTE: if cwd cannot be resolved, set errflag which will cause exit later */ tmpPWD[0] = '\0'; mypwd = tmpPWD; } if ((strlen(mypwd) + strlen(optarg)) >= sizeof(PBS_InitDir)) { fprintf(stderr, "qsub: -d arg is longer than %ld characters\n", (long)sizeof(PBS_InitDir)); errflg++; } snprintf(PBS_InitDir, sizeof(PBS_InitDir), "%s/%s", mypwd, optarg); } /* END if (optarg[0] != '/') */ else { if (strlen(optarg) >= sizeof(PBS_InitDir)) { fprintf(stderr, "qsub: -d arg is longer than %ld characters\n", (long)sizeof(PBS_InitDir)); errflg++; } strncpy(PBS_InitDir, optarg, sizeof(PBS_InitDir)); } /* end optarg[1] != '/' */ if (validate_path != 0) { /* validate local existence of '-d' working directory */ if (chdir(PBS_InitDir) == -1) { fprintf(stderr, "qsub: cannot chdir to '%s' errno: %d (%s)\n", optarg, errno, strerror(errno)); errflg++; } } } /* END if (optarg != NULL) */ else { fprintf(stderr, "qsub: illegal -d value\n"); errflg++; } break; case 'D': if (optarg != NULL) { strncpy(PBS_RootDir, optarg, sizeof(PBS_RootDir)); } else { fprintf(stderr, "qsub: illegal -D value\n"); errflg++; } break; case 'e': if_cmd_line(e_opt) { int rc = 0; e_opt = passet; if (qsub_host[0] != '\0') rc = prepare_path(optarg,path_out,qsub_host); else rc = prepare_path(optarg,path_out,NULL); if ((rc == 0) || (rc == 3)) { set_attr(&attrib, ATTR_e, path_out); } else { fprintf(stderr, "qsub: illegal -e value\n"); errflg++; } } break; case 'F': if_cmd_line(F_opt) { F_opt = passet; set_attr(&attrib, ATTR_args, optarg); } break; #if !defined(PBS_NO_POSIX_VIOLATION) case 'f': if_cmd_line(f_opt) { f_opt = passet; set_attr(&attrib, ATTR_f, "TRUE"); } break; #endif case 'h': if_cmd_line(h_opt) { h_opt = passet; set_attr(&attrib, ATTR_h, "u"); } break; #if !defined(PBS_NO_POSIX_VIOLATION) case 'I': if_cmd_line(Interact_opt) { Interact_opt = passet; set_attr(&attrib, ATTR_inter, interactive_port(&inter_sock)); } break; #endif /* PBS_NO_POSIX_VIOLATION */ case 'j': /* FORMAT: {oe|eo|n} */ if_cmd_line(j_opt) { j_opt = passet; if (strcmp(optarg, "oe") != 0 && strcmp(optarg, "eo") != 0 && strcmp(optarg, "n") != 0) { fprintf(stderr, "qsub: illegal -j value\n"); errflg++; break; } set_attr(&attrib, ATTR_j, optarg); } break; case 'J': if_cmd_line(J_opt) { J_opt = passet; set_attr(&attrib,ATTR_J,optarg); } break; case 'k': /* FORMAT: {o|e} */ if_cmd_line(k_opt) { k_opt = passet; if (strcmp(optarg, "o") != 0 && strcmp(optarg, "e") != 0 && strcmp(optarg, "oe") != 0 && strcmp(optarg, "eo") != 0 && strcmp(optarg, "n") != 0) { fprintf(stderr, "qsub: illegal -k value\n"); errflg++; break; } set_attr(&attrib, ATTR_k, optarg); } break; case 'l': l_opt = passet; /* a ,procs= in the node spec is illegal. Validate the node spec */ if ((strstr(optarg, ",procs=") != NULL) && (strstr(optarg, "nodes=") != NULL)) { printf("illegal node spec: %s\n", optarg); return(-1); } /* Normal evaluation of batch job resources. */ if (attrib) { if (attrib->resource) { /* right here we are looking for a +procs=x in the node spec */ char *proc_ptr = NULL; char *patch_ptr; /* struct attrl *proc_attrib = NULL; */ char proc_val[MAX_PROCS_DIGITS + 1]; int i = 0; proc_val[0] = 0; /* Initialize */ proc_ptr = strstr(attrib->value, "procs="); if(proc_ptr) { /* we have the procs keyword in the node_spec. We need to take it out and install it to the Resource_List */ patch_ptr = proc_ptr; /* Get the procs value */ patch_ptr = strchr(patch_ptr, '='); if(patch_ptr == NULL) { return(-1); } else { patch_ptr++; while(*patch_ptr != '+' && !isspace((int) *patch_ptr) && *patch_ptr != '\0' && i < MAX_PROCS_DIGITS) { proc_val[i++] = *patch_ptr++; } proc_val[i] = 0; /* we have a procs=x in our node spec. Add the resources */ sprintf(tmpLine, "procs=%s", proc_val); if (set_resources(&attrib, tmpLine, (pass == 0)) != 0) { fprintf(stderr, "qsub: illegal -l value\n"); errflg++; } } while(*patch_ptr != '+' && !isspace((int) *patch_ptr) && *patch_ptr != '\0') { patch_ptr++; } /* remove the procs=x from the node spec. If patch_ptr has a '+' then the procs=x is followed by more specificaitons. Remove the procs=x from the spec and splice the rest of the specification back together */ if(*patch_ptr == '+') { patch_ptr++; *proc_ptr = 0; strcat(attrib->value, patch_ptr); } else { /* Remove the procs=x from the node spec. If we are here procs=x is at the end of the node specification */ if(*(proc_ptr - 1) == '+') { proc_ptr--; } *proc_ptr = 0; } } /* END if(proc_ptr)*/ } /* END if(attrib->resource ) */ } /* END if(attrib) */ if (set_resources(&attrib, optarg, (pass == 0)) != 0) { fprintf(stderr, "qsub: illegal -l value\n"); errflg++; } if (strstr(optarg, "walltime") != NULL) { struct attrl *attr; char *ptr; /* if walltime range specified, break into minwclimit and walltime resources */ for (attr = attrib;attr != NULL;attr = attr->next) { if (!strcmp(attr->name, "walltime")) { if ((ptr = strchr(attr->value, '-'))) { *ptr = '\0'; ptr++; /* set minwclimit to min walltime range value */ snprintf(tmpLine, sizeof(tmpLine), "minwclimit=%s", attr->value); if (set_resources(&attrib, tmpLine, (pass == 0)) != 0) { fprintf(stderr, "qsub: illegal -l value\n"); errflg++; } /* set walltime to max walltime range value */ strcpy(tmpLine, ptr); strcpy(attr->value, tmpLine); } break; } } /* END for (attr) */ } /* END ORNL WRAPPER */ break; case 'm': if_cmd_line(m_opt) { /* FORMAT: {a|b|e|n} */ m_opt = passet; while (isspace((int)*optarg)) optarg++; if (strlen(optarg) == 0) { fprintf(stderr, "qsub: illegal -m value\n"); errflg++; break; } if (strcmp(optarg, "n") != 0) { pc = optarg; while (*pc) { if ((*pc != 'a') && (*pc != 'b') && (*pc != 'e')) { fprintf(stderr, "qsub: illegal -m value\n"); errflg++; break; } pc++; } } /* END if (strcmp(optarg,"n") != 0) */ set_attr(&attrib, ATTR_m, optarg); } break; case 'M': if_cmd_line(M_opt) { M_opt = passet; if (parse_at_list(optarg, FALSE, FALSE)) { fprintf(stderr, "qsub: illegal -M value\n"); errflg++; break; } set_attr(&attrib, ATTR_M, optarg); } break; case 'N': if_cmd_line(N_opt) { N_opt = passet; /* NOTE: did enforce alpha start previously - relax this constraint allowing numeric job names (CRI - 6/26/07) */ if (check_job_name(optarg, 0) == 0) { set_attr(&attrib, ATTR_N, optarg); } else { fprintf(stderr, "qsub: illegal -N value\n"); errflg++; } } break; case 'o': if_cmd_line(o_opt) { int rc = 0; o_opt = passet; if (qsub_host[0] != '\0') rc = prepare_path(optarg,path_out,qsub_host); else rc = prepare_path(optarg,path_out,NULL); if ((rc == 0) || (rc == 3)) { set_attr(&attrib, ATTR_o, path_out); } else { fprintf(stderr, "qsub: illegal -o value\n"); errflg++; } } break; case 'p': if_cmd_line(p_opt) { p_opt = passet; while (isspace((int)*optarg)) optarg++; pc = optarg; if ((*pc == '-') || (*pc == '+')) pc++; if (strlen(pc) == 0) { fprintf(stderr, "qsub: illegal -p value\n"); errflg++; break; } while (*pc != '\0') { if (!isdigit(*pc)) { fprintf(stderr, "qsub: illegal -p value\n"); errflg++; break; } pc++; } i = atoi(optarg); if ((i < -1024) || (i > 1023)) { fprintf(stderr, "qsub: illegal -p value\n"); errflg++; break; } set_attr(&attrib, ATTR_p, optarg); } break; #if !defined(PBS_NO_POSIX_VIOLATION) case 'P': if_cmd_line(P_opt) { P_opt = passet; if (strlen(optarg) > 0) { char *user; char *group; char *colon; /* don't check privileges, this happens on the server side as managers are allowed to submit jobs on behalf of other users */ user = optarg; colon = strchr(user,':'); if (colon != NULL) { group = colon+1; *colon = '\0'; set_attr(&attrib, ATTR_g, group); } set_attr(&attrib, ATTR_P, user); } else { fprintf(stderr, "qsub: -P requires a user name\n"); errflg++; } } break; #endif /* PBS_NO_POSIX_VIOLATION */ case 'q': if_cmd_line(q_opt) { q_opt = passet; strcpy(destination, optarg); } break; case 'r': if_cmd_line(r_opt) { r_opt = passet; if (strlen(optarg) != 1) { fprintf(stderr, "qsub: illegal -r value\n"); errflg++; break; } if ((*optarg != 'y') && (*optarg != 'n')) { fprintf(stderr, "qsub: illegal -r value\n"); errflg++; break; } set_attr(&attrib, ATTR_r, optarg); } break; case 'S': if_cmd_line(S_opt) { S_opt = passet; if (parse_at_list(optarg, TRUE, TRUE)) { fprintf(stderr, "qsub: illegal -S value\n"); errflg++; break; } set_attr(&attrib, ATTR_S, optarg); } break; #if !defined(PBS_NO_POSIX_VIOLATION) case 't': if_cmd_line(t_opt) { t_opt = passet; /* validate before sending request to server? */ set_attr(&attrib, ATTR_t, optarg); } break; case 'T': if_cmd_line(T_opt) { T_opt = passet; /* validate before sending request to server? */ set_attr(&attrib,ATTR_jobtype,optarg); } break; #endif case 'u': if_cmd_line(u_opt) { u_opt = passet; if (parse_at_list(optarg, TRUE, FALSE)) { fprintf(stderr, "qsub: illegal -u value\n"); errflg++; break; } set_attr(&attrib, ATTR_u, optarg); } break; case 'v': if_cmd_line(v_opt) { v_opt = passet; if (v_value != NULL) free(v_value); v_value = (char *)malloc(strlen(optarg) + 1); if (v_value == NULL) { fprintf(stderr, "qsub: out of memory\n"); errflg++; break; } strcpy(v_value, optarg); } break; case 'V': if_cmd_line(V_opt) { V_opt = passet; } break; case 'w': if (optarg != NULL) { strncpy(PBS_WorkDir, optarg, sizeof(PBS_WorkDir)); } else { fprintf(stderr, "qsub: illegal -w value\n"); errflg++; } break; case 'W': while (isspace((int)*optarg)) optarg++; if (strlen(optarg) == 0) { /* value is empty */ fprintf(stderr, "qsub: illegal -W value\n"); errflg++; break; } i = get_name_value(optarg, &keyword, &valuewd); if (i != 1) { char tmpLine[65536]; /* assume resource manager extension */ snprintf(tmpLine, sizeof(tmpLine), "x=%s", optarg); i = get_name_value(tmpLine, &keyword, &valuewd); } while (i == 1) { if (!strcmp(keyword, ATTR_depend)) { if_cmd_line(Depend_opt) { int rtn = 0; Depend_opt = passet; pdepend = malloc(PBS_DEPEND_LEN); if ((pdepend == NULL) || (rtn = parse_depend_list(valuewd,pdepend,PBS_DEPEND_LEN))) { /* cannot parse 'depend' value */ if (rtn == 2) { fprintf(stderr,"qsub: -W value exceeded max length (%d)\n", PBS_DEPEND_LEN); } else { fprintf(stderr,"qsub: illegal -W value\n"); } errflg++; break; } set_attr(&attrib, ATTR_depend, pdepend); } } else if (!strcmp(keyword, ATTR_stagein)) { if_cmd_line(Stagein_opt) { Stagein_opt = passet; if (parse_stage_list(valuewd)) { /* cannot parse 'stagein' value */ fprintf(stderr, "qsub: illegal -W value\n"); errflg++; break; } set_attr(&attrib, ATTR_stagein, valuewd); } } else if (!strcmp(keyword, ATTR_stageout)) { if_cmd_line(Stageout_opt) { Stageout_opt = passet; if (parse_stage_list(valuewd)) { /* cannot parse 'stageout' value */ fprintf(stderr, "qsub: illegal -W value\n"); errflg++; break; } set_attr(&attrib, ATTR_stageout, valuewd); } } else if (!strcmp(keyword, ATTR_t)) { if_cmd_line(t_opt) { t_opt = passet; set_attr(&attrib, ATTR_t, valuewd); } } else if (!strcmp(keyword, ATTR_g)) { if_cmd_line(Grouplist_opt) { Grouplist_opt = passet; if (parse_at_list(valuewd, TRUE, FALSE)) { /* cannot parse 'grouplist' value */ fprintf(stderr, "qsub: illegal -W value\n"); errflg++; break; } if (validate_group == TRUE) { if (validate_group_list(valuewd) == FALSE) { fprintf(stderr,"qsub: User isn't a member of one or more groups in %s\n", valuewd); errflg++; break; } } set_attr(&attrib, ATTR_g, valuewd); } } else if (!strcmp(keyword, ATTR_inter)) { /* specify interactive job */ if_cmd_line(Interact_opt) { Interact_opt = passet; if (strcmp(valuewd, "true") != 0) { fprintf(stderr, "qsub: illegal -W value\n"); errflg++; break; } set_attr(&attrib, ATTR_inter, interactive_port(&inter_sock)); } } else if (!strcmp(keyword, ATTR_umask)) { int len; len = strlen(valuewd); if (valuewd[0] == '0') --len; if (len > 3) { fprintf(stderr, "Invalid umask value, too many digits: %s\n", valuewd); errflg++; break; } Umask_opt = passet; if (valuewd[0] == '0') { /* value is octal, convert to decimal */ long mask; char buf[4]; mask = strtol(valuewd, NULL, 8); snprintf(buf, 4, "%ld", mask); /* value is octal, convert to decimal */ set_attr(&attrib,ATTR_umask,buf); } else { set_attr(&attrib,ATTR_umask,valuewd); } } else if (!strcmp(keyword, ATTR_f)) { switch (valuewd[0]) { /*accept 1, TRUE,true,YES,yes, 0, FALSE, false, NO, no */ case 1: case 'T': case 't': case 'Y': case 'y': f_opt = passet; set_attr(&attrib, ATTR_f, "TRUE"); break; case 0: case 'F': case 'f': case 'N': case 'n': f_opt = passet; set_attr(&attrib, ATTR_f, "FALSE"); break; default: fprintf(stderr, "invalid %s value: %s\n", ATTR_f, valuewd); errflg++; } } else { /* generic job attribute specified */ set_attr(&attrib, keyword, valuewd); } i = get_name_value(NULL, &keyword, &valuewd); } /* END while (i == 1) */ if (i == -1) { fprintf(stderr, "qsub: illegal -W value\n"); errflg++; } break; #if !defined(PBS_NO_POSIX_VIOLATION) case 'X': if_cmd_line(Forwardx11_opt) { Forwardx11_opt = passet; if (!getenv("DISPLAY")) { fprintf(stderr, "qsub: DISPLAY not set\n"); errflg++; } } break; case 'x': if_cmd_line(Run_Inter_opt) { Run_Inter_opt = passet; } break; #endif case 'z': if_cmd_line(z_opt) z_opt = passet; break; case '?': default : errflg++; break; } } /* END while ((c = getopt(argc,argv,GETOPT_ARGS)) != EOF) */ /* make sure that only root users are using the -J option */ if ((J_opt) && (!P_opt)) { fprintf(stderr,"The -J option can only be used in conjunction with -P\n"); errflg++; goto err; } /* ORNL WRAPPER */ if ((pass < 10) && (Interact_opt == 1)) { int original_optind = optind; int rc = 0; /* Evaluate resources for interactive submission here. */ if ((tmpfd = mkstemp(tmp_name)) < 1) { fprintf(stderr, "qsub: could not create tmp job file %s\n", tmp_name); errflg++; goto err; } if ((fP = fdopen(tmpfd, "w+")) == NULL) { fprintf(stderr, "qsub: could not create tmp job file %s\n", tmp_name); unlink(tmp_name); errflg++; goto err; } if (fprintf(fP, "%s\n\n", tmpResources) < 0) { fprintf(stderr, "qsub: unable to write to tmp job file %s\n", tmp_name); fclose(fP); unlink(tmp_name); errflg++; goto err; } fclose(fP); if (stat(PBS_Filter, &sfilter) != -1) { int index; if ((tmpfd = mkstemp(tmp_name2)) < 1) { fprintf(stderr, "qsub: could not create tmp job file %s\n", tmp_name2); errflg++; goto err; } close(tmpfd); /* run the specified resources through the submitfilter. */ strcpy(cline, PBS_Filter); for (index = 1;index < argc;index++) { if (argv[index] != NULL) { strcat(cline, " "); strcat(cline, argv[index]); } } /* END for (index) */ strcat(cline, " <"); strcat(cline, tmp_name); strcat(cline, " >"); strcat(cline, tmp_name2); rc = system(cline); if (rc == -1) { fprintf(stderr, "qsub: error writing filter o/p, %s\n", tmp_name2); exit(1); } if (WEXITSTATUS(rc) == (unsigned char)SUBMIT_FILTER_ADMIN_REJECT_CODE) { fprintf(stderr, "qsub: Your job has been administratively rejected by the queueing system.\n"); fprintf(stderr, "qsub: There may be a more detailed explanation prior to this notice.\n"); unlink(tmp_name2); unlink(tmp_name); exit(1); } if (WEXITSTATUS(rc)) { fprintf(stderr, "qsub: submit filter returned an error code, aborting job submission.\n"); unlink(tmp_name2); unlink(tmp_name); exit(1); } fP = fopen(tmp_name2, "r+"); unlink(tmp_name2); unlink(tmp_name); } /* END if (stat(PBS_Filter,&sfilter) != -1) */ else { fP = fopen(tmp_name, "r+"); unlink(tmp_name); } /* evaluate the resources */ while (fgets(cline, sizeof(cline), fP) != NULL) { if (strlen(cline) < 5) break; for (cP = cline;cP < cline + strlen(cline);cP++) { if (*cP == '\n') { *cP = '\0'; } } /* NOTE: allow for job attributes other than '-l' */ /* FORMAT: '#PBS - ' */ if (strncasecmp(cline, "#pbs -", strlen("#pbs -"))) { /* invalid line specified */ continue; } /* NOTE: a better design would be to process the submitfilter outside of process_opts(), add valid args to ArgC/ArgV, and call process_opts() once. (NYI) */ /* NOTE: can we utilize 'process_opts' to process submit filter lines? (NYI) */ flag = cline[strlen("#pbs -")]; vptr = cline + strlen("#pbs -x "); switch (flag) { case 'l': if (set_resources(&attrib, vptr, (pass == 0))) { fprintf(stderr, "qsub: illegal -l value\n"); errflg++; } break; default: { char FlagString[3]; char *tmpArgV[4]; int aindex; FlagString[0] = '-'; FlagString[1] = flag; FlagString[2] = '\0'; #ifdef linux aindex = 1; /* prime getopt's starting point */ tmpArgV[0] = ""; #else aindex = 1; /* prime getopt's starting point */ tmpArgV[0] = ""; #endif tmpArgV[aindex] = FlagString; tmpArgV[aindex + 1] = vptr; tmpArgV[aindex + 2] = NULL; tmpArgV[3] = NULL; /* fprintf(stderr,"PLINE: '%s' '%s' '%s'\n", tmpArgV[0], tmpArgV[1], cline); */ /* set pass to 10 to allow submit filter to override user-specified values and to prevent recursive calling of submit filter processing */ if (process_opts(aindex + 2, tmpArgV, 10) != 0) { fprintf(stderr, "submitfilter line '%s' ignored\n", cline); } } break; } /* END switch (cptr[0]) */ } /* END while (fgets(cline,sizeof(cline),fP) != NULL) */ /* restore optind */ optind = original_optind; fclose(fP); } /* END if (Interact_opt == 1) */ /* END ORNL WRAPPER */ err: if (!errflg && pass) { errflg = (optind != argc); if (errflg) { fprintf(stderr, "qsub: directive error: "); for (optind = 1;optind < argc;optind++) fprintf(stderr, "%s ", argv[optind]); fprintf(stderr, "\n"); } } return(errflg); } /* END process_opts() */ /* * set_opt_defaults - if not already set, set certain job attributes to * their default value */ void set_opt_defaults(void) { if (c_opt == FALSE) set_attr(&attrib, ATTR_c, default_ckpt); if (h_opt == FALSE) set_attr(&attrib, ATTR_h, NO_HOLD); if (j_opt == FALSE) set_attr(&attrib, ATTR_j, NO_JOIN); if (k_opt == FALSE) set_attr(&attrib, ATTR_k, NO_KEEP); if (m_opt == FALSE) set_attr(&attrib, ATTR_m, MAIL_AT_ABORT); if (p_opt == FALSE) set_attr(&attrib, ATTR_p, "0"); if (r_opt == FALSE) { if (rerunnable_by_default) set_attr(&attrib, ATTR_r, "TRUE"); else set_attr(&attrib, ATTR_r, "FALSE"); } if (f_opt == FALSE) { if (fault_tolerant_by_default) set_attr(&attrib, ATTR_f, "TRUE"); else set_attr(&attrib, ATTR_f, "FALSE"); } return; } /* END set_opt_defaults() */ char *get_param( char *param, /* I */ char *config_buf) /* I */ { char tmpLine[1024]; char *param_val; char *new_val = NULL; /* FORMAT: \n */ /* NOTE: does not support comments */ /* if (strcasestr() == NULL) */ /* NOTE: currently case-sensitive (FIXME) */ if ((param_val = strstr(config_buf, param)) == NULL) { return(NULL); } strncpy(tmpLine, param_val, sizeof(tmpLine)); strtok(tmpLine, " \t\n"); if ((new_val = (char *)strtok(NULL, "\t \n")) == NULL) { return(NULL); } return(new_val); } /* END get_param() */ /** * qsub main * * @see process_opts() - child */ int main( int argc, /* I */ char **argv, /* I */ char **envp) /* I */ { int errflg; /* option error */ static char script[MAXPATHLEN + 1] = ""; /* name of script file */ char script_tmp[MAXPATHLEN + 1] = ""; /* name of script file copy */ char *bnp; FILE *f; /* FILE pointer to the script */ char *q_n_out; /* queue part of destination */ char *s_n_out; /* server part of destination */ /* server:port to send request to */ int connect; /* return from pbs_connect */ char *errmsg; /* return from pbs_geterrmsg */ struct stat statbuf; struct sigaction act; char config_buf[MAX_LINE_LEN]; /* Buffer holds config file */ char *param_val; /* value of parameter returned from config */ char *submit_args_str = NULL; /* buffer to hold args */ int argi, argslen = 0; int idx; int have_intr_cmd = FALSE; if ((param_val = getenv("PBS_CLIENTRETRY")) != NULL) { cnt2server_retry = atoi(param_val); } /* set the submit_args */ for (argi = 1;argi < argc;argi++) { argslen += strlen(argv[argi]) + 1; } if (argslen > 0) { submit_args_str = malloc(sizeof(char) * argslen); if (submit_args_str == NULL) { fprintf(stderr, "qsub: out of memory\n"); exit(2); } *submit_args_str = '\0'; for (argi = 1;argi < argc;argi++) { strcat(submit_args_str, argv[argi]); if (argi != argc - 1) { strcat(submit_args_str, " "); } } } /* check TORQUE config settings */ strncpy(PBS_Filter, SUBMIT_FILTER_PATH, 255); /* check to see if PBS_Filter exists. If not then fall back to the default hard-coded file */ if (stat(PBS_Filter, &statbuf) == -1) { strncpy(PBS_Filter, DefaultFilterPath, 255); } strncpy(xauth_path, DefaultXauthPath, 255); strncpy(default_ckpt, CHECKPOINT_UNSPECIFIED, sizeof(default_ckpt)); validate_path = 1; /* boolean - by default verify '-d' working dir locally */ server_host[0] = '\0'; qsub_host[0] = '\0'; owner_uid[0] = '\0'; if (getenv("PBSDEBUG") != NULL) { fprintf(stderr, "xauth_path=%s\n", xauth_path); } if (load_config(config_buf, sizeof(config_buf)) == 0) { if ((param_val = get_param("QSUBSLEEP", config_buf)) != NULL) { sleep(atoi(param_val)); } if ((param_val = get_param("SUBMITFILTER", config_buf)) != NULL) { strncpy(PBS_Filter, param_val, sizeof(PBS_Filter)); PBS_Filter[sizeof(PBS_Filter) - 1] = '\0'; } if ((param_val = get_param("SERVERHOST", config_buf)) != NULL) { strncpy(server_host, param_val, sizeof(server_host)); server_host[sizeof(server_host) - 1] = '\0'; } if ((param_val = get_param("QSUBHOST", config_buf)) != NULL) { strncpy(qsub_host, param_val, sizeof(qsub_host)); qsub_host[sizeof(qsub_host) - 1] = '\0'; } if ((param_val = get_param("QSUBSENDUID", config_buf)) != NULL) { sprintf(owner_uid, "%d", (int)getuid()); } if ((param_val = get_param("QSUBSENDGROUPLIST", config_buf)) != NULL) { gid_t group_id = getgid(); struct group *gpent = getgrgid(group_id); if (gpent != NULL) { set_attr(&attrib, ATTR_g, gpent->gr_name); } } if ((param_val = get_param("QSUBSENDGROUPLIST", config_buf)) != NULL) { gid_t group_id = getgid(); struct group *gpent = getgrgid(group_id); if (gpent != NULL) { set_attr(&attrib, ATTR_g, gpent->gr_name); } } if ((param_val = get_param("XAUTHPATH", config_buf)) != NULL) { strncpy(xauth_path, param_val, sizeof(xauth_path)); xauth_path[sizeof(xauth_path) - 1] = '\0'; } if ((param_val = get_param("CLIENTRETRY", config_buf)) != NULL) { if (cnt2server_retry == -100) cnt2server_retry = atoi(param_val); } if ((param_val = get_param("VALIDATEGROUP", config_buf)) != NULL) { if (getgrgid(getgid()) == NULL) { fprintf(stderr, "qsub: cannot validate submit group.\n"); exit(1); } validate_group = TRUE; } if ((param_val = get_param("DEFAULTCKPT", config_buf)) != NULL) { strncpy(default_ckpt, param_val, sizeof(default_ckpt)); } if ((param_val = get_param("VALIDATEPATH", config_buf)) != NULL) { if (!strcasecmp(param_val, "false")) validate_path = 0; } if ((param_val = get_param("RERUNNABLEBYDEFAULT", config_buf)) != NULL) { if (!strcasecmp(param_val, "false")) rerunnable_by_default = 0; } if ((param_val = get_param("FAULT_TOLERANT_BY_DEFAULT", config_buf)) != NULL) { if (!strcasecmp(param_val, "true")) fault_tolerant_by_default = 1; } } /* END if (load_config(config_buf,sizeof(config_buf)) == 0) */ /* NOTE: load config before processing opts since config may modify how opts are handled */ errflg = process_opts(argc, argv, 0); /* get cmd-line options */ if (errflg || (((optind + 1) < argc) && !Interact_opt)) { static char usage[] = "usage: qsub [-a date_time] [-A account_string] [-b secs]\n\ [-c [ none | { enabled | periodic | shutdown |\n\ depth= | dir= | interval=}... ]\n\ [-C directive_prefix] [-d path] [-D path]\n\ [-e path] [-h] [-I] [-j oe] [-k {oe}] [-l resource_list] [-m n|{abe}]\n\ [-M user_list] [-N jobname] [-o path] [-p priority] [-P proxy_user] [-q queue] \n\ [-r y|n] [-S path] [-t number_to_submit] [-T type] [-u user_list] [-w] path\n"; /* need secondary usage since there appears to be a 512 byte size limit */ static char usage2[] = " [-W additional_attributes] [-v variable_list] [-V ] [-x] [-X] [-z] [script]\n"; fprintf(stderr,"%s%s", usage, usage2); exit(2); } /* check to see if PBS_Filter exists. If not then fall back to the old hard-coded file */ if (stat(PBS_Filter, &statbuf) == -1) { strncpy(PBS_Filter, DefaultFilterPath, 255); } if (optind < argc) strcpy(script, argv[optind]); argi = argc - optind; if (Interact_opt) { for (idx = 1; idx < argi; idx++) { strcat(script," "); strcat(script, argv[optind + idx]); } } /* store the saved args string in "submit_args" attribute */ if (submit_args_str != NULL) { set_attr(&attrib, ATTR_submit_args, submit_args_str); free(submit_args_str); } /* end setting submit_args */ if (Forwardx11_opt) { char *x11authstr; /* get the DISPLAY's auth proto, data, and screen number */ if ((x11authstr = x11_get_proto(NULL)) != NULL) { /* stuff this info into the job */ set_attr(&attrib, ATTR_forwardx11, x11authstr); if (getenv("PBSDEBUG") != NULL) fprintf(stderr, "x11auth string: %s\n", x11authstr); } else { fprintf(stderr, "qsub: Failed to get xauth data (check $DISPLAY variable)\n"); exit(1); } } /* if script is empty, get standard input */ if (!strcmp(script, "") || !strcmp(script, "-")) { if (!N_opt) set_attr(&attrib, ATTR_N, "STDIN"); if (Interact_opt == FALSE) { if ((errflg = get_script( argc, argv, stdin, script_tmp, /* O */ set_dir_prefix(dir_prefix, C_opt))) > 0) { unlink(script_tmp); exit(1); } if (errflg < 0) { unlink(script_tmp); exit(1); } } } /* END if (!strcmp(script,"") || !strcmp(script,"-")) */ else if ((Interact_opt != FALSE) && (Run_Inter_opt)) { set_attr(&attrib, ATTR_intcmd, script); have_intr_cmd = TRUE; } else { /* non-empty script, read it for directives */ if (stat(script, &statbuf) < 0) { fprintf(stderr, "qsub: script file '%s' cannot be loaded - %s\n", script, strerror(errno)); exit(1); } if (!S_ISREG(statbuf.st_mode)) { fprintf(stderr, "qsub: script not a file\n"); exit(1); } if ((f = fopen(script, "r")) != NULL) { if (!N_opt) { if ((bnp = strrchr(script, (int)'/'))) bnp++; else bnp = script; if (check_job_name(bnp, 0) == 0) { set_attr(&attrib, ATTR_N, bnp); } else { fprintf(stderr, "qsub: cannot form a valid job name from the script name\n"); exit(1); } } if ((errflg = get_script( argc, argv, f, script_tmp, /* O */ set_dir_prefix(dir_prefix, C_opt))) > 0) { unlink(script_tmp); exit(1); } if (errflg < 0) { unlink(script_tmp); exit(1); } } /* END if ((f = fopen(script,"r")) != NULL) */ else { perror("qsub: opening script file:"); unlink(script_tmp); exit(8); } } /* END else (!strcmp(script,"") || !strcmp(script,"-")) */ /* interactive job can not be job array */ if (Interact_opt && t_opt) { fprintf(stderr, "qsub: interactive job can not be job array.\n"); unlink(script_tmp); exit(2); } if (Interact_opt && ((isatty(0) == 0) || (isatty(1) == 0))) { if (have_intr_cmd) { have_terminal = FALSE; } else { fprintf(stderr, "qsub:\tstandard input and output must be a terminal for \n\tinteractive job submission\n"); unlink(script_tmp); close(inter_sock); exit(1); } } set_opt_defaults(); /* set option default values */ server_out[0] = '\0'; if (parse_destination_id(destination, &q_n_out, &s_n_out)) { fprintf(stderr, "qsub: illegally formed destination: %s\n", destination); unlink(script_tmp); exit(2); } if (notNULL(s_n_out)) { strcpy(server_out, s_n_out); } /* connect to the server */ if (cnt2server_retry != -100) cnt2server_conf(cnt2server_retry); /* set number of seconds to retry */ connect = cnt2server(server_out); if (connect <= 0) { fprintf(stderr, "qsub: cannot connect to server %s (errno=%d) %s\n", pbs_server, pbs_errno, pbs_strerror(pbs_errno)); if (getenv("PBSDEBUG") != NULL) { fprintf(stderr, "qsub: pbs_server daemon may not be running on host %s or hostname in file '$TORQUEHOME/server_name' may be incorrect)\n", pbs_server); } unlink(script_tmp); exit(pbs_errno); } /* Get required environment variables to be sent to the server. */ if (!set_job_env(envp)) { fprintf(stderr, "qsub: cannot send environment with the job\n"); unlink(script_tmp); exit(3); } /* disallow ^Z which hangs up MOM starting an interactive job */ sigemptyset(&act.sa_mask); act.sa_handler = no_suspend; act.sa_flags = 0; if (sigaction(SIGTSTP, &act, (struct sigaction *)0) < 0) { perror("unable to catch signals"); unlink(script_tmp); exit(1); } /* Send submit request to the server. */ pbs_errno = 0; new_jobname = pbs_submit( connect, (struct attropl *)attrib, script_tmp, destination, NULL); if (new_jobname == NULL) { errmsg = pbs_geterrmsg(connect); if (errmsg != NULL) { fprintf(stderr, "qsub: %s\n", errmsg); } else { fprintf(stderr, "qsub: Error (%d - %s) submitting job\n", pbs_errno, pbs_strerror(pbs_errno)); } unlink(script_tmp); exit(pbs_errno); } else { if (!z_opt && !Interact_opt) { printf("%s\n", new_jobname); } } /* disconnet from the server. */ pbs_disconnect(connect); unlink(script_tmp); /* is this an interactive job ??? */ if (Interact_opt == 1) interactive(); exit(0); } /* END main() */