/* Convert a composite cpu governor enum to its equivalent string * * Input: - buf - buffer to contain string * - bufsz - size of buffer * - gpvs - composite enum of governors */ extern void cpu_freq_govlist_to_string(char* buf, uint16_t bufsz, uint32_t govs) { char *list = NULL; if ((govs & CPU_FREQ_CONSERVATIVE) == CPU_FREQ_CONSERVATIVE) { if (list == NULL) list = xstrdup("Conservative"); else { xstrcatchar(list,','); xstrcat(list,"Conservative"); } } if ((govs & CPU_FREQ_PERFORMANCE) == CPU_FREQ_PERFORMANCE) { if (list == NULL) list = xstrdup("Performance"); else { xstrcatchar(list,','); xstrcat(list,"Performance"); } } if ((govs & CPU_FREQ_POWERSAVE) == CPU_FREQ_POWERSAVE) { if (list == NULL) list = xstrdup("PowerSave"); else { xstrcatchar(list,','); xstrcat(list,"PowerSave"); } } if ((govs & CPU_FREQ_ONDEMAND) == CPU_FREQ_ONDEMAND) { if (list == NULL) list = xstrdup("OnDemand"); else { xstrcatchar(list,','); xstrcat(list,"OnDemand"); } } if ((govs & CPU_FREQ_USERSPACE) == CPU_FREQ_USERSPACE) { if (list == NULL) list = xstrdup("UserSpace"); else { xstrcatchar(list,','); xstrcat(list,"UserSpace"); } } if (list) { if (strlen(list) < bufsz) strcpy(buf, list); else strncpy(buf, list, bufsz-1); xfree(list); } else { strncpy(buf,"No Governors defined", bufsz-1); } }
void log_set_fpfx(char *prefix) { slurm_mutex_lock(&log_lock); xfree(log->fpfx); if (!prefix) log->fpfx = xstrdup(""); else { log->fpfx = xstrdup(prefix); xstrcatchar(log->fpfx, ' '); } slurm_mutex_unlock(&log_lock); }
/* Create an IO filename from job parameters and the filename format * sent from client. Used by slurmd for prolog errors. */ extern char *fname_create2(batch_job_launch_msg_t *req) { stepd_step_rec_t job; char *esc, *name = NULL, *orig = NULL; if (req->std_err) orig = xstrdup(req->std_err); else if (req->std_out) orig = xstrdup(req->std_out); else xstrfmtcat(orig, "slurm-%u.out", req->job_id); esc = is_path_escaped(orig); /* If format doesn't specify an absolute pathname, use cwd */ if (orig[0] != '/') { xstrcat(name, req->work_dir); if (esc) { xstrcat(name, esc); goto fini; } if (name[strlen(name)-1] != '/') xstrcatchar(name, '/'); } if (esc) { /* esc is malloc */ name = esc; goto fini; } memset(&job, 0, sizeof(stepd_step_rec_t)); job.array_job_id = req->array_job_id; job.array_task_id = req->array_task_id; job.jobid = req->job_id; // job->nodeid = TBD; job.stepid = req->step_id; job.uid = req->uid; job.user_name = req->user_name; name = _create_batch_fname(name, orig, &job, 0); fini: xfree(orig); return name; }
/* Create an IO filename from job parameters and the filename format * sent from client */ char * fname_create(stepd_step_rec_t *job, const char *format, int taskid) { char *name = NULL; char *orig = xstrdup(format); int id; char *esc; if (((id = fname_single_task_io (format)) >= 0) && (taskid != id)) return (xstrdup ("/dev/null")); esc = is_path_escaped(orig); /* If format doesn't specify an absolute pathname, use cwd */ if (orig[0] != '/') { xstrcat(name, job->cwd); if (esc) { xstrcat(name, esc); goto fini; } if (name[strlen(name)-1] != '/') xstrcatchar(name, '/'); } if (esc) { /* esc is malloc */ name = esc; goto fini; } if (job->batch) name = _create_batch_fname(name, orig, job, taskid); else name = _create_step_fname(name, orig, job, taskid); fini: xfree(orig); return name; }
/* return a heap allocated string formed from fmt and ap arglist * returned string is allocated with xmalloc, so must free with xfree. * * args are like printf, with the addition of the following format chars: * - %m expands to strerror(errno) * - %t expands to strftime("%x %X") [ locally preferred short date/time ] * - %T expands to rfc2822 date time [ "dd, Mon yyyy hh:mm:ss GMT offset" ] * * simple format specifiers are handled explicitly to avoid calls to * vsnprintf and allow dynamic sizing of the message buffer. If a call * is made to vsnprintf, however, the message will be limited to 1024 bytes. * (inc. newline) * */ static char *vxstrfmt(const char *fmt, va_list ap) { char *buf = NULL; char *p = NULL; size_t len = (size_t) 0; char tmp[LINEBUFSIZE]; int unprocessed = 0; int long_long = 0; while (*fmt != '\0') { if ((p = (char *)strchr(fmt, '%')) == NULL) { /* no more format chars */ xstrcat(buf, fmt); break; } else { /* *p == '%' */ /* take difference from fmt to just before `%' */ len = (size_t) ((long)(p) - (long)fmt); /* append from fmt to p into buf if there's * anythere there */ if (len > 0) xstrncat(buf, fmt, len); switch (*(++p)) { case '%': /* "%%" => "%" */ xstrcatchar(buf, '%'); break; case 'm': /* "%m" => strerror(errno) */ xslurm_strerrorcat(buf); break; case 't': /* "%t" => locally preferred date/time*/ xstrftimecat(buf, "%x %X"); break; case 'T': /* "%T" => "dd, Mon yyyy hh:mm:ss off" */ xstrftimecat(buf, "%a, %d %b %Y %H:%M:%S %z"); break; #if defined USE_USEC_CLOCK case 'M': /* "%M" => "usec" */ snprintf(tmp, sizeof(tmp), "%ld", clock()); xstrcat(buf, tmp); break; #elif defined USE_RFC5424_TIME case 'M': /* "%M" => "yyyy-mm-ddThh:mm:ss(+/-)hh:mm" */ xrfc5424timecat(buf); break; #elif defined USE_ISO_8601 case 'M': /* "%M" => "yyyy-mm-ddThh:mm:ss" */ xstrftimecat(buf, "%Y-%m-%dT%T"); break; #else case 'M': /* "%M" => "Mon DD hh:mm:ss" */ xstrftimecat(buf, "%b %d %T"); break; #endif case 's': /* "%s" => append string */ /* we deal with this case for efficiency */ if (unprocessed == 0) xstrcat(buf, va_arg(ap, char *)); else xstrcat(buf, "%s"); break; case 'f': /* "%f" => append double */ /* again, we only handle this for efficiency */ if (unprocessed == 0) { snprintf(tmp, sizeof(tmp), "%f", va_arg(ap, double)); xstrcat(buf, tmp); } else xstrcat(buf, "%f"); break; case 'd': if (unprocessed == 0) { snprintf(tmp, sizeof(tmp), "%d", va_arg(ap, int)); xstrcat(buf, tmp); } else
static int _parse_resv_tres(char *val, resv_desc_msg_t *resv_msg_ptr, int *free_tres_license, int *free_tres_bb, int *free_tres_corecnt, int *free_tres_nodecnt) { int i, ret, len; char *tres_bb = NULL, *tres_license = NULL, *tres_corecnt = NULL, *tres_nodecnt = NULL, *token, *type = NULL, *saveptr1 = NULL, *value_str = NULL, *name = NULL, *compound = NULL, *tmp = NULL; bool discard, first; *free_tres_license = 0; *free_tres_bb = 0; *free_tres_corecnt = 0; *free_tres_nodecnt = 0; token = strtok_r(val, ",", &saveptr1); while (token) { compound = strtok_r(token, "=", &value_str); if (!value_str || !*value_str) { error("TRES component '%s' has an invalid value '%s'", type, token); goto error; } if (strchr(compound, '/')) { tmp = xstrdup(compound); type = strtok_r(tmp, "/", &name); } else type = compound; if (_is_configured_tres(compound) < 0) goto error; if (!strcasecmp(type, "license")) { if (tres_license && tres_license[0] != '\0') xstrcatchar(tres_license, ','); xstrfmtcat(tres_license, "%s:%s", name, value_str); token = strtok_r(NULL, ",", &saveptr1); if (tmp) xfree(tmp); } else if (strcasecmp(type, "bb") == 0) { if (tres_bb && tres_bb[0] != '\0') xstrcatchar(tres_bb, ','); xstrfmtcat(tres_bb, "%s:%s", name, value_str); token = strtok_r(NULL, ",", &saveptr1); if (tmp) xfree(tmp); } else if (strcasecmp(type, "cpu") == 0) { first = true; discard = false; do { len = strlen(value_str); for (i = 0; i < len; i++) { if (!isdigit(value_str[i])) { if (first) { error("TRES value '%s' " "is invalid", value_str); goto error; } else discard = true; break; } } first = false; if (!discard) { if (tres_corecnt && tres_corecnt[0] != '\0') xstrcatchar(tres_corecnt, ','); xstrcat(tres_corecnt, value_str); token = strtok_r(NULL, ",", &saveptr1); value_str = token; } } while (!discard && token); } else if (strcasecmp(type, "node") == 0) { if (tres_nodecnt && tres_nodecnt[0] != '\0') xstrcatchar(tres_nodecnt, ','); xstrcat(tres_nodecnt, value_str); token = strtok_r(NULL, ",", &saveptr1); } else { error("TRES type '%s' not supported with reservations", compound); goto error; } } if (tres_corecnt && tres_corecnt[0] != '\0') { ret = _parse_resv_core_cnt(resv_msg_ptr, tres_corecnt, true); xfree(tres_corecnt); if (ret != SLURM_SUCCESS) goto error; *free_tres_corecnt = 1; } if (tres_nodecnt && tres_nodecnt[0] != '\0') { ret = _parse_resv_node_cnt(resv_msg_ptr, tres_nodecnt, true); xfree(tres_nodecnt); if (ret != SLURM_SUCCESS) goto error; *free_tres_nodecnt = 1; } if (tres_license && tres_license[0] != '\0') { resv_msg_ptr->licenses = tres_license; *free_tres_license = 1; } if (tres_bb && tres_bb[0] != '\0') { resv_msg_ptr->burst_buffer = tres_bb; *free_tres_bb = 1; } return SLURM_SUCCESS; error: xfree(tres_nodecnt); xfree(tres_corecnt); exit_code = 1; return SLURM_ERROR; }
/* * Fill in as much of filename as possible from srun, update * filename type to one of the io types ALL, NONE, PER_TASK, ONE */ fname_t * fname_create(srun_job_t *job, char *format) { unsigned int wid = 0; unsigned long int taskid = 0; fname_t *fname = NULL; char *p, *q, *name, *tmp_env; uint32_t array_job_id = job->jobid; uint32_t array_task_id = NO_VAL; char *esc; char *end; fname = xmalloc(sizeof(*fname)); fname->type = IO_ALL; fname->name = NULL; fname->taskid = -1; /* Handle special cases */ if ((format == NULL) || (strncasecmp(format, "all", (size_t) 3) == 0) || (strncmp(format, "-", (size_t) 1) == 0) ) { /* "all" explicitly sets IO_ALL and is the default */ return fname; } if (strcasecmp(format, "none") == 0) { /* * Set type to IO_PER_TASK so that /dev/null is opened * on every node, which should be more efficient */ fname->type = IO_PER_TASK; fname->name = xstrdup ("/dev/null"); return fname; } taskid = strtoul(format, &p, 10); if ((*p == '\0') && ((int) taskid < opt.ntasks)) { fname->type = IO_ONE; fname->taskid = (uint32_t) taskid; /* Set the name string to pass to slurmd * to the taskid requested, so that tasks with * no IO can open /dev/null. */ fname->name = xstrdup (format); return fname; } /* Check if path has escaped characters * in it and prevent them to be expanded. */ esc = _is_path_escaped(format); if (esc) { fname->name = esc; return fname; } name = NULL; q = p = format; while (*p != '\0') { if (*p == '%') { if (isdigit(*(++p))) { unsigned long in_width = 0; xmemcat(name, q, p - 1); if ((in_width = strtoul(p, &p, 10)) > MAX_WIDTH) wid = MAX_WIDTH; else wid = in_width; q = p - 1; if (*p == '\0') break; } switch (*p) { case 'a': /* '%a' => array task id */ tmp_env = getenv("SLURM_ARRAY_TASK_ID"); if (tmp_env) array_task_id = strtoul(tmp_env, &end, 10); xmemcat(name, q, p - 1); xstrfmtcat(name, "%0*u", wid, array_task_id); q = ++p; break; case 'A': /* '%A' => array master job id */ tmp_env = getenv("SLURM_ARRAY_JOB_ID"); if (tmp_env) array_job_id = strtoul(tmp_env, &end, 10); xmemcat(name, q, p - 1); xstrfmtcat(name, "%0*u", wid, array_job_id); q = ++p; break; case 't': /* '%t' => taskid */ case 'n': /* '%n' => nodeid */ case 'N': /* '%N' => node name */ fname->type = IO_PER_TASK; if (wid) xstrcatchar(name, '%'); p++; break; case 'J': /* '%J' => "jobid.stepid" */ case 'j': /* '%j' => jobid */ xmemcat(name, q, p - 1); xstrfmtcat(name, "%0*d", wid, job->jobid); if ((*p == 'J') && (job->stepid != NO_VAL)) xstrfmtcat(name, ".%d", job->stepid); q = ++p; break; case 's': /* '%s' => stepid */ xmemcat(name, q, p - 1); xstrfmtcat(name, "%0*d", wid, job->stepid); q = ++p; break; case 'u': /* '%u' => username */ xmemcat(name, q, p - 1); xstrfmtcat(name, "%s", opt.user); q = ++p; break; default: break; } wid = 0; } else p++; } if (q != p) xmemcat(name, q, p); fname->name = name; return fname; }
/* Create an IO filename from job parameters and the filename format * sent from client */ char * fname_create(slurmd_job_t *job, const char *format, int taskid) { unsigned int wid = 0; char *name = NULL; char *orig = xstrdup(format); char *p, *q; int id; if (((id = fname_single_task_io (format)) >= 0) && (taskid != id)) return (xstrdup ("/dev/null")); /* If format doesn't specify an absolute pathname, * use cwd */ if (orig[0] != '/') { xstrcat(name, job->cwd); if (name[strlen(name)-1] != '/') xstrcatchar(name, '/'); } q = p = orig; while (*p != '\0') { if (*p == '%') { if (isdigit(*(++p))) { unsigned long in_width = 0; xmemcat(name, q, p - 1); if ((in_width = strtoul(p, &p, 10)) > MAX_WIDTH) wid = MAX_WIDTH; else wid = (unsigned int)in_width; q = p - 1; if (*p == '\0') break; } switch (*p) { case 'a': /* '%a' => array task id */ xmemcat(name, q, p - 1); xstrfmtcat(name, "%0*d", wid, job->array_task_id); q = ++p; break; case 'A': /* '%A' => array master job id */ xmemcat(name, q, p - 1); xstrfmtcat(name, "%0*d", wid, job->array_job_id); q = ++p; break; case 's': /* '%s' => step id */ xmemcat(name, q, p - 1); xstrfmtcat(name, "%0*d", wid, job->stepid); q = ++p; break; case 't': /* '%t' => taskid */ xmemcat(name, q, p - 1); xstrfmtcat(name, "%0*d", wid, taskid); q = ++p; break; case 'n': /* '%n' => nodeid */ xmemcat(name, q, p - 1); xstrfmtcat(name, "%0*d", wid, job->nodeid); q = ++p; break; case 'N': /* '%N' => node name */ xmemcat(name, q, p - 1); xstrfmtcat(name, "%s", conf->hostname); q = ++p; break; case 'J': case 'j': xmemcat(name, q, p - 1); xstrfmtcat(name, "%0*d", wid, job->jobid); if ((*p == 'J') && (job->stepid != NO_VAL)) xstrfmtcat(name, ".%d", job->stepid); q = ++p; break; default: break; } wid = 0; } else p++; } if (q != p) xmemcat(name, q, p); xfree(orig); return name; }
extern int state_control_parse_resv_tres(char *val, resv_desc_msg_t *resv_msg_ptr, int *free_tres_license, int *free_tres_bb, int *free_tres_corecnt, int *free_tres_nodecnt, char **err_msg) { int i, ret, len; char *tres_bb = NULL, *tres_license = NULL, *tres_corecnt = NULL, *tres_nodecnt = NULL, *token, *type = NULL, *saveptr1 = NULL, *value_str = NULL, *name = NULL, *compound = NULL, *tmp = NULL; bool discard, first; *free_tres_license = 0; *free_tres_bb = 0; *free_tres_corecnt = 0; *free_tres_nodecnt = 0; token = strtok_r(val, ",", &saveptr1); while (token) { compound = strtok_r(token, "=", &value_str); if (!compound || !value_str || !*value_str) { xstrfmtcat(*err_msg, "invalid TRES '%s'", token); goto error; } if (strchr(compound, '/')) { tmp = xstrdup(compound); type = strtok_r(tmp, "/", &name); } else type = compound; if (state_control_configured_tres(compound) != SLURM_SUCCESS) { xstrfmtcat(*err_msg, "couldn't identify configured TRES '%s'", compound); goto error; } if (!xstrcasecmp(type, "license")) { if (tres_license && tres_license[0] != '\0') xstrcatchar(tres_license, ','); xstrfmtcat(tres_license, "%s:%s", name, value_str); token = strtok_r(NULL, ",", &saveptr1); } else if (xstrcasecmp(type, "bb") == 0) { if (tres_bb && tres_bb[0] != '\0') xstrcatchar(tres_bb, ','); xstrfmtcat(tres_bb, "%s:%s", name, value_str); token = strtok_r(NULL, ",", &saveptr1); } else if (xstrcasecmp(type, "cpu") == 0) { first = true; discard = false; do { len = strlen(value_str); for (i = 0; i < len; i++) { if (!isdigit(value_str[i])) { if (first) { xstrfmtcat(*err_msg, "invalid TRES cpu value '%s'", value_str); goto error; } else discard = true; break; } } first = false; if (!discard) { if (tres_corecnt && tres_corecnt[0] != '\0') xstrcatchar(tres_corecnt, ','); xstrcat(tres_corecnt, value_str); token = strtok_r(NULL, ",", &saveptr1); value_str = token; } } while (!discard && token); } else if (xstrcasecmp(type, "node") == 0) { if (tres_nodecnt && tres_nodecnt[0] != '\0') xstrcatchar(tres_nodecnt, ','); xstrcat(tres_nodecnt, value_str); token = strtok_r(NULL, ",", &saveptr1); } else { xstrfmtcat(*err_msg, "TRES type '%s' not supported with reservations", compound); goto error; } } if (tres_corecnt && tres_corecnt[0] != '\0') { /* only have this on a cons_res machine */ ret = state_control_corecnt_supported(); if (ret != SLURM_SUCCESS) { xstrfmtcat(*err_msg, "CoreCnt or CPUCnt is only supported when SelectType includes select/cons_res or SelectTypeParameters includes OTHER_CONS_RES on a Cray."); goto error; } ret = state_control_parse_resv_corecnt(resv_msg_ptr, tres_corecnt, free_tres_corecnt, true, err_msg); xfree(tres_corecnt); if (ret != SLURM_SUCCESS) goto error; } if (tres_nodecnt && tres_nodecnt[0] != '\0') { ret = parse_resv_nodecnt(resv_msg_ptr, tres_nodecnt, free_tres_nodecnt, true, err_msg); xfree(tres_nodecnt); if (ret != SLURM_SUCCESS) goto error; } if (tres_license && tres_license[0] != '\0') { resv_msg_ptr->licenses = tres_license; *free_tres_license = 1; } if (tres_bb && tres_bb[0] != '\0') { resv_msg_ptr->burst_buffer = tres_bb; *free_tres_bb = 1; } xfree(tmp); return SLURM_SUCCESS; error: xfree(tmp); xfree(tres_nodecnt); xfree(tres_corecnt); return SLURM_ERROR; }
int setup_env(env_t *env, bool preserve_env) { int rc = SLURM_SUCCESS; char *dist = NULL, *lllp_dist = NULL; char addrbuf[INET_ADDRSTRLEN]; uint32_t cluster_flags = slurmdb_setup_cluster_flags(); if (env == NULL) return SLURM_ERROR; if (env->task_pid && setenvf(&env->env, "SLURM_TASK_PID", "%d", (int)env->task_pid)) { error("Unable to set SLURM_TASK_PID environment variable"); rc = SLURM_FAILURE; } if (!preserve_env && env->ntasks) { if(setenvf(&env->env, "SLURM_NTASKS", "%d", env->ntasks)) { error("Unable to set SLURM_NTASKS " "environment variable"); rc = SLURM_FAILURE; } if(setenvf(&env->env, "SLURM_NPROCS", "%d", env->ntasks)) { error("Unable to set SLURM_NPROCS " "environment variable"); rc = SLURM_FAILURE; } } if (env->cpus_per_task && setenvf(&env->env, "SLURM_CPUS_PER_TASK", "%d", env->cpus_per_task) ) { error("Unable to set SLURM_CPUS_PER_TASK"); rc = SLURM_FAILURE; } if (env->ntasks_per_node && setenvf(&env->env, "SLURM_NTASKS_PER_NODE", "%d", env->ntasks_per_node) ) { error("Unable to set SLURM_NTASKS_PER_NODE"); rc = SLURM_FAILURE; } if (env->ntasks_per_socket && setenvf(&env->env, "SLURM_NTASKS_PER_SOCKET", "%d", env->ntasks_per_socket) ) { error("Unable to set SLURM_NTASKS_PER_SOCKET"); rc = SLURM_FAILURE; } if (env->ntasks_per_core && setenvf(&env->env, "SLURM_NTASKS_PER_CORE", "%d", env->ntasks_per_core) ) { error("Unable to set SLURM_NTASKS_PER_CORE"); rc = SLURM_FAILURE; } if (env->cpus_on_node && setenvf(&env->env, "SLURM_CPUS_ON_NODE", "%d", env->cpus_on_node) ) { error("Unable to set SLURM_CPUS_ON_NODE"); rc = SLURM_FAILURE; } _set_distribution(env->distribution, &dist, &lllp_dist); if(dist) if (setenvf(&env->env, "SLURM_DISTRIBUTION", "%s", dist)) { error("Can't set SLURM_DISTRIBUTION env variable"); rc = SLURM_FAILURE; } if(env->distribution == SLURM_DIST_PLANE) if (setenvf(&env->env, "SLURM_DIST_PLANESIZE", "%u", env->plane_size)) { error("Can't set SLURM_DIST_PLANESIZE " "env variable"); rc = SLURM_FAILURE; } if(lllp_dist) if (setenvf(&env->env, "SLURM_DIST_LLLP", "%s", lllp_dist)) { error("Can't set SLURM_DIST_LLLP env variable"); rc = SLURM_FAILURE; } if (env->cpu_bind_type) { char *str_verbose, *str_bind_type, *str_bind_list; char *str_bind; int len; if (env->batch_flag) { unsetenvp(env->env, "SBATCH_CPU_BIND_VERBOSE"); unsetenvp(env->env, "SBATCH_CPU_BIND_TYPE"); unsetenvp(env->env, "SBATCH_CPU_BIND_LIST"); unsetenvp(env->env, "SBATCH_CPU_BIND"); } else { unsetenvp(env->env, "SLURM_CPU_BIND_VERBOSE"); unsetenvp(env->env, "SLURM_CPU_BIND_TYPE"); unsetenvp(env->env, "SLURM_CPU_BIND_LIST"); unsetenvp(env->env, "SLURM_CPU_BIND"); } str_verbose = xstrdup (""); if (env->cpu_bind_type & CPU_BIND_VERBOSE) { xstrcat(str_verbose, "verbose"); } else { xstrcat(str_verbose, "quiet"); } str_bind_type = xstrdup (""); if (env->cpu_bind_type & CPU_BIND_TO_THREADS) { xstrcat(str_bind_type, "threads,"); } else if (env->cpu_bind_type & CPU_BIND_TO_CORES) { xstrcat(str_bind_type, "cores,"); } else if (env->cpu_bind_type & CPU_BIND_TO_SOCKETS) { xstrcat(str_bind_type, "sockets,"); } else if (env->cpu_bind_type & CPU_BIND_TO_LDOMS) { xstrcat(str_bind_type, "ldoms,"); } if (env->cpu_bind_type & CPU_BIND_NONE) { xstrcat(str_bind_type, "none"); } else if (env->cpu_bind_type & CPU_BIND_RANK) { xstrcat(str_bind_type, "rank"); } else if (env->cpu_bind_type & CPU_BIND_MAP) { xstrcat(str_bind_type, "map_cpu:"); } else if (env->cpu_bind_type & CPU_BIND_MASK) { xstrcat(str_bind_type, "mask_cpu:"); } else if (env->cpu_bind_type & CPU_BIND_LDRANK) { xstrcat(str_bind_type, "rank_ldom"); } else if (env->cpu_bind_type & CPU_BIND_LDMAP) { xstrcat(str_bind_type, "map_ldom:"); } else if (env->cpu_bind_type & CPU_BIND_LDMASK) { xstrcat(str_bind_type, "mask_ldom:"); } len = strlen(str_bind_type); if (len) { /* remove a possible trailing ',' */ if (str_bind_type[len-1] == ',') { str_bind_type[len-1] = '\0'; } } str_bind_list = xstrdup (""); if (env->cpu_bind) { xstrcat(str_bind_list, env->cpu_bind); } str_bind = xstrdup (""); xstrcat(str_bind, str_verbose); if (str_bind[0] && str_bind_type && str_bind_type[0]) xstrcatchar(str_bind, ','); xstrcat(str_bind, str_bind_type); xstrcat(str_bind, str_bind_list); if (env->batch_flag) { if (setenvf(&env->env, "SBATCH_CPU_BIND_VERBOSE", str_verbose)) { error("Unable to set SBATCH_CPU_BIND_VERBOSE"); rc = SLURM_FAILURE; } if (setenvf(&env->env, "SBATCH_CPU_BIND_TYPE", str_bind_type)) { error("Unable to set SBATCH_CPU_BIND_TYPE"); rc = SLURM_FAILURE; } if (setenvf(&env->env, "SBATCH_CPU_BIND_LIST", str_bind_list)) { error("Unable to set SBATCH_CPU_BIND_LIST"); rc = SLURM_FAILURE; } if (setenvf(&env->env, "SBATCH_CPU_BIND", str_bind)) { error("Unable to set SBATCH_CPU_BIND"); rc = SLURM_FAILURE; } } else { if (setenvf(&env->env, "SLURM_CPU_BIND_VERBOSE", str_verbose)) { error("Unable to set SLURM_CPU_BIND_VERBOSE"); rc = SLURM_FAILURE; } if (setenvf(&env->env, "SLURM_CPU_BIND_TYPE", str_bind_type)) { error("Unable to set SLURM_CPU_BIND_TYPE"); rc = SLURM_FAILURE; } if (setenvf(&env->env, "SLURM_CPU_BIND_LIST", str_bind_list)) { error("Unable to set SLURM_CPU_BIND_LIST"); rc = SLURM_FAILURE; } if (setenvf(&env->env, "SLURM_CPU_BIND", str_bind)) { error("Unable to set SLURM_CPU_BIND"); rc = SLURM_FAILURE; } } } if (env->mem_bind_type) { char *str_verbose, *str_bind_type, *str_bind_list; char *str_bind; if (env->batch_flag) { unsetenvp(env->env, "SBATCH_MEM_BIND_VERBOSE"); unsetenvp(env->env, "SBATCH_MEM_BIND_TYPE"); unsetenvp(env->env, "SBATCH_MEM_BIND_LIST"); unsetenvp(env->env, "SBATCH_MEM_BIND"); } else { unsetenvp(env->env, "SLURM_MEM_BIND_VERBOSE"); unsetenvp(env->env, "SLURM_MEM_BIND_TYPE"); unsetenvp(env->env, "SLURM_MEM_BIND_LIST"); unsetenvp(env->env, "SLURM_MEM_BIND"); } str_verbose = xstrdup (""); if (env->mem_bind_type & MEM_BIND_VERBOSE) { xstrcat(str_verbose, "verbose"); } else { xstrcat(str_verbose, "quiet"); } str_bind_type = xstrdup (""); if (env->mem_bind_type & MEM_BIND_NONE) { xstrcat(str_bind_type, "none"); } else if (env->mem_bind_type & MEM_BIND_RANK) { xstrcat(str_bind_type, "rank"); } else if (env->mem_bind_type & MEM_BIND_MAP) { xstrcat(str_bind_type, "map_mem:"); } else if (env->mem_bind_type & MEM_BIND_MASK) { xstrcat(str_bind_type, "mask_mem:"); } else if (env->mem_bind_type & MEM_BIND_LOCAL) { xstrcat(str_bind_type, "local"); } str_bind_list = xstrdup (""); if (env->mem_bind) { xstrcat(str_bind_list, env->mem_bind); } str_bind = xstrdup (""); xstrcat(str_bind, str_verbose); if (str_bind[0]) { /* add ',' if str_verbose */ xstrcatchar(str_bind, ','); } xstrcat(str_bind, str_bind_type); xstrcat(str_bind, str_bind_list); if (env->batch_flag) { if (setenvf(&env->env, "SBATCH_MEM_BIND_VERBOSE", str_verbose)) { error("Unable to set SBATCH_MEM_BIND_VERBOSE"); rc = SLURM_FAILURE; } if (setenvf(&env->env, "SBATCH_MEM_BIND_TYPE", str_bind_type)) { error("Unable to set SBATCH_MEM_BIND_TYPE"); rc = SLURM_FAILURE; } if (setenvf(&env->env, "SBATCH_MEM_BIND_LIST", str_bind_list)) { error("Unable to set SBATCH_MEM_BIND_LIST"); rc = SLURM_FAILURE; } if (setenvf(&env->env, "SBATCH_MEM_BIND", str_bind)) { error("Unable to set SBATCH_MEM_BIND"); rc = SLURM_FAILURE; } } else { if (setenvf(&env->env, "SLURM_MEM_BIND_VERBOSE", str_verbose)) { error("Unable to set SLURM_MEM_BIND_VERBOSE"); rc = SLURM_FAILURE; } if (setenvf(&env->env, "SLURM_MEM_BIND_TYPE", str_bind_type)) { error("Unable to set SLURM_MEM_BIND_TYPE"); rc = SLURM_FAILURE; } if (setenvf(&env->env, "SLURM_MEM_BIND_LIST", str_bind_list)) { error("Unable to set SLURM_MEM_BIND_LIST"); rc = SLURM_FAILURE; } if (setenvf(&env->env, "SLURM_MEM_BIND", str_bind)) { error("Unable to set SLURM_MEM_BIND"); rc = SLURM_FAILURE; } } } if (env->overcommit && (setenvf(&env->env, "SLURM_OVERCOMMIT", "1"))) { error("Unable to set SLURM_OVERCOMMIT environment variable"); rc = SLURM_FAILURE; } if (env->slurmd_debug && setenvf(&env->env, "SLURMD_DEBUG", "%d", env->slurmd_debug)) { error("Can't set SLURMD_DEBUG environment variable"); rc = SLURM_FAILURE; } if (env->labelio && setenvf(&env->env, "SLURM_LABELIO", "1")) { error("Unable to set SLURM_LABELIO environment variable"); rc = SLURM_FAILURE; } if (env->select_jobinfo) { _setup_particulars(cluster_flags, &env->env, env->select_jobinfo); } if (env->jobid >= 0) { if (setenvf(&env->env, "SLURM_JOB_ID", "%d", env->jobid)) { error("Unable to set SLURM_JOB_ID environment"); rc = SLURM_FAILURE; } /* and for backwards compatability... */ if (setenvf(&env->env, "SLURM_JOBID", "%d", env->jobid)) { error("Unable to set SLURM_JOBID environment"); rc = SLURM_FAILURE; } } if (env->nodeid >= 0 && setenvf(&env->env, "SLURM_NODEID", "%d", env->nodeid)) { error("Unable to set SLURM_NODEID environment"); rc = SLURM_FAILURE; } if (env->procid >= 0 && setenvf(&env->env, "SLURM_PROCID", "%d", env->procid)) { error("Unable to set SLURM_PROCID environment"); rc = SLURM_FAILURE; } if (env->localid >= 0 && setenvf(&env->env, "SLURM_LOCALID", "%d", env->localid)) { error("Unable to set SLURM_LOCALID environment"); rc = SLURM_FAILURE; } if (env->stepid >= 0 && setenvf(&env->env, "SLURM_STEPID", "%d", env->stepid)) { error("Unable to set SLURM_STEPID environment"); rc = SLURM_FAILURE; } if (!preserve_env && env->nhosts && setenvf(&env->env, "SLURM_NNODES", "%d", env->nhosts)) { error("Unable to set SLURM_NNODES environment var"); rc = SLURM_FAILURE; } if (env->nodelist && setenvf(&env->env, "SLURM_NODELIST", "%s", env->nodelist)) { error("Unable to set SLURM_NODELIST environment var."); rc = SLURM_FAILURE; } if (!preserve_env && env->task_count && setenvf (&env->env, "SLURM_TASKS_PER_NODE", "%s", env->task_count)) { error ("Can't set SLURM_TASKS_PER_NODE env variable"); rc = SLURM_FAILURE; } if (env->comm_port && setenvf (&env->env, "SLURM_SRUN_COMM_PORT", "%u", env->comm_port)) { error ("Can't set SLURM_SRUN_COMM_PORT env variable"); rc = SLURM_FAILURE; } if (env->cli) { slurm_print_slurm_addr (env->cli, addrbuf, INET_ADDRSTRLEN); /* * XXX: Eventually, need a function for slurm_addrs that * returns just the IP address (not addr:port) */ if ((dist = strchr (addrbuf, ':')) != NULL) *dist = '\0'; setenvf (&env->env, "SLURM_LAUNCH_NODE_IPADDR", "%s", addrbuf); } if (env->sgtids && setenvf(&env->env, "SLURM_GTIDS", "%s", env->sgtids)) { error("Unable to set SLURM_GTIDS environment variable"); rc = SLURM_FAILURE; } if(cluster_flags & CLUSTER_FLAG_AIX) { char res_env[128]; char *debug_env = (char *)getenv("SLURM_LL_API_DEBUG"); int debug_num = 0; /* MP_POERESTART_ENV causes a warning message for "poe", but * is needed for "poerestart". Presently we have no means to * determine what command a user will execute. We could * possibly add a "srestart" command which would set * MP_POERESTART_ENV, but that presently seems unnecessary. */ /* setenvf(&env->env, "MP_POERESTART_ENV", res_env); */ if (debug_env) debug_num = atoi(debug_env); snprintf(res_env, sizeof(res_env), "SLURM_LL_API_DEBUG=%d", debug_num); /* Required for AIX/POE systems indicating pre-allocation */ setenvf(&env->env, "LOADLBATCH", "yes"); setenvf(&env->env, "LOADL_ACTIVE", "3.2.0"); } if (env->pty_port && setenvf(&env->env, "SLURM_PTY_PORT", "%hu", env->pty_port)) { error("Can't set SLURM_PTY_PORT env variable"); rc = SLURM_FAILURE; } if (env->ws_col && setenvf(&env->env, "SLURM_PTY_WIN_COL", "%hu", env->ws_col)) { error("Can't set SLURM_PTY_WIN_COL env variable"); rc = SLURM_FAILURE; } if (env->ws_row && setenvf(&env->env, "SLURM_PTY_WIN_ROW", "%hu", env->ws_row)) { error("Can't set SLURM_PTY_WIN_ROW env variable"); rc = SLURM_FAILURE; } if (env->ckpt_dir && setenvf(&env->env, "SLURM_CHECKPOINT_IMAGE_DIR", "%s", env->ckpt_dir)) { error("Can't set SLURM_CHECKPOINT_IMAGE_DIR env variable"); rc = SLURM_FAILURE; } if (env->restart_cnt && setenvf(&env->env, "SLURM_RESTART_COUNT", "%u", env->restart_cnt)) { error("Can't set SLURM_RESTART_COUNT env variable"); rc = SLURM_FAILURE; } return rc; }
/* * FIXME - It would be nice to parse the multi-prog array just once * to retrieve the argv arrays for each task on this node, rather * than calling multi_prog_get_argv once for each task. */ extern int multi_prog_get_argv(char *config_data, char **prog_env, int task_rank, uint32_t *argc, char ***argv, int global_argc, char **global_argv) { char *line = NULL; int i, line_num = 0; int task_offset; char *p = NULL, *ptrptr = NULL; char *rank_spec = NULL, *args_spec = NULL; int prog_argc = 0; char **prog_argv = NULL; char *local_data = NULL; size_t tmp_buf_len = 256; char tmp_buf[tmp_buf_len]; char *arg_buf = NULL; bool last_line_break = false, line_break = false; int line_len; prog_argv = (char **)xmalloc(sizeof(char *) * MAX_ARGC); if (task_rank < 0) { error("Invalid task rank %d", task_rank); *argc = 1; *argv = prog_argv; return -1; } local_data = xstrdup(config_data); line = strtok_r(local_data, "\n", &ptrptr); while (line) { if (line_num > 0) line = strtok_r(NULL, "\n", &ptrptr); if (line == NULL) { error("No executable program specified for this task"); goto fail; } line_num++; line_len = strlen(line); if ((line_len > 0) && (line[line_len - 1] == '\\')) line_break = true; else line_break = false; if (last_line_break) { last_line_break = line_break; continue; } last_line_break = line_break; p = line; while ((*p != '\0') && isspace (*p)) /* remove leading spaces */ p++; if (*p == '#') /* only whole-line comments handled */ continue; if (*p == '\0') /* blank line ignored */ continue; rank_spec = p; while ((*p != '\0') && !isspace (*p)) p++; if (*p == '\0') { error("Invalid MPMD configuration line %d", line_num); goto fail; } *p++ = '\0'; if (!_in_range(task_rank, rank_spec, &task_offset)) continue; /* skip all whitspace after the range spec */ while ((*p != '\0') && isspace (*p)) p++; args_spec = p; while (*args_spec != '\0') { /* Only simple quote and escape supported */ if (arg_buf) { prog_argv[prog_argc++] = arg_buf; arg_buf=NULL; } if ((prog_argc + 1) >= MAX_ARGC) { info("Exceeded multi-prog argc limit"); break; } CONT: p = args_spec; while ((*args_spec != '\0') && (*args_spec != '\\') && (*args_spec != '%') && (*args_spec != '\'') && !isspace(*args_spec)) { args_spec++; } xstrncat(arg_buf, p, (args_spec - p)); if (*args_spec == '\0') { /* the last argument */ break; } else if (*args_spec == '%') { args_spec++; if (*args_spec == 't') { /* task rank */ snprintf(tmp_buf, tmp_buf_len, "%d", task_rank); xstrcat(arg_buf, tmp_buf); } else if (*args_spec == 'o') { /* task offset */ snprintf(tmp_buf, tmp_buf_len, "%d", task_offset); xstrcat(arg_buf, tmp_buf); } args_spec++; goto CONT; } else if (*args_spec == '\\') { /* escape, just remove the backslash */ args_spec++; if (*args_spec != '\0') { xstrcatchar(arg_buf, *args_spec); args_spec++; } else { line = strtok_r(NULL, "\n", &ptrptr); if (!line) break; line_num++; args_spec = line; } goto CONT; } else if (*args_spec == '\'') { /* single quote, * preserve all characters quoted. */ p = ++args_spec; LINE_BREAK: while ((*args_spec != '\0') && (*args_spec != '\'')) { args_spec++; } if (*args_spec == '\0') { /* closing quote not found */ if (*(args_spec - 1) == '\\') { line = strtok_r(NULL, "\n", &ptrptr); if (line) { line_num++; args_spec = line; goto LINE_BREAK; } } error("Program arguments specification format invalid: %s.", prog_argv[prog_argc - 1]); goto fail; } xstrncat(arg_buf, p, (args_spec - p)); args_spec++; goto CONT; } else { /* space */ while ((*args_spec != '\0') && isspace(*args_spec)) { args_spec++; } } } if (arg_buf) { prog_argv[prog_argc++] = arg_buf; arg_buf = NULL; } for (i = 2; i < global_argc; i++) { if ((prog_argc + 1) >= MAX_ARGC) { info("Exceeded multi-prog argc limit"); break; } prog_argv[prog_argc++] = xstrdup(global_argv[i]); } prog_argv[prog_argc] = NULL; *argc = prog_argc; *argv = prog_argv; xfree(local_data); return 0; } error("Program for task rank %d not specified.", task_rank); fail: xfree(local_data); *argc = 1; prog_argv[0] = NULL; *argv = prog_argv; return -1; }