/*****************************************************************************\ * src/srun/fname.h - IO filename type implementation (srun specific) ***************************************************************************** * Copyright (C) 2002 The Regents of the University of California. * Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER). * Written by Mark Grondona . * CODE-OCEC-09-009. All rights reserved. * * This file is part of Slurm, a resource management program. * For details, see . * Please also read the included file: DISCLAIMER. * * Slurm is free software; you can redistribute it and/or modify it under * the terms of the GNU General Public License as published by the Free * Software Foundation; either version 2 of the License, or (at your option) * any later version. * * In addition, as a special exception, the copyright holders give permission * to link the code of portions of this program with the OpenSSL library under * certain conditions as described in each individual source file, and * distribute linked combinations including the two. You must obey the GNU * General Public License in all respects for all of the code used other than * OpenSSL. If you modify file(s) with this exception, you may extend this * exception to your version of the file(s), but you are not obligated to do * so. If you do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source files in * the program, then also delete it here. * * Slurm is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License along * with Slurm; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. \*****************************************************************************/ #include #include #include #include #include #include "fname.h" #include "opt.h" #include "src/common/xmalloc.h" #include "src/common/xstring.h" #include "src/common/xassert.h" /* * Max zero-padding width allowed */ #define MAX_WIDTH 10 static char *_remove_path_slashes(char *); /* * Fill in as much of filename as possible from srun, update * filename type to one of the io types ALL, NONE, PER_TASK, ONE * These options should mirror those used with "sbatch" (parsed in * _batch_path_check found in src/slurmd/common/fname.c) */ extern fname_t *fname_create(srun_job_t *job, char *format, int task_count) { unsigned int wid = 0; unsigned long int taskid = 0; fname_t *fname = NULL; char *p, *q, *name, *tmp_env, *tmp_perc; uint32_t array_job_id = job->jobid; uint32_t array_task_id = NO_VAL; char *esc; char *end; bool double_p = false; fname = xmalloc(sizeof(*fname)); fname->type = IO_ALL; fname->name = NULL; fname->taskid = -1; /* Handle special cases */ if ((format == NULL) || (xstrncasecmp(format, "all", (size_t) 3) == 0) || (xstrncmp(format, "-", (size_t) 1) == 0) ) { /* "all" explicitly sets IO_ALL and is the default */ return fname; } if (xstrcasecmp(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 < task_count)) { 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 = _remove_path_slashes(format); if (esc) { fname->name = esc; return fname; } tmp_perc = NULL; name = NULL; q = p = format; while (*p != '\0') { if (*p == '%') { if (*(p+1) == '%') { p++; double_p = true; xmemcat(name, q, p); /* Save the removed % just in case */ xstrcat(tmp_perc, "%"); q = ++p; continue; } 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); xfree(tmp_perc); tmp_perc = NULL; 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); xfree(tmp_perc); tmp_perc = NULL; q = ++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); xfree(tmp_perc); tmp_perc = NULL; q = ++p; break; case 's': /* '%s' => stepid */ xmemcat(name, q, p - 1); xstrfmtcat(name, "%0*d", wid, job->stepid); xfree(tmp_perc); tmp_perc = NULL; q = ++p; break; case 'u': /* '%u' => username */ case 't': /* '%t' => taskid */ case 'n': /* '%n' => nodeid */ case 'N': /* '%N' => node name */ fname->type = IO_PER_TASK; if (double_p) xstrcat(name, tmp_perc); if (wid) { /* Put the width back and * the removed %, so the * slurmstepd can remove it */ xstrcat(name, xstrdup_printf("%%%u", wid)); } else { xmemcat(name, q, p); } xfree(tmp_perc); tmp_perc = NULL; q = p; p++; break; case 'x': xmemcat(name, q, p - 1); xstrfmtcat(name, "%s", getenv("SLURM_JOB_NAME")); q = ++p; break; default: break; } double_p = false; } else if (double_p) { /* special case when there is a * double percent and a t, n, or N */ double_p = false; if (isdigit(*p)) wid = strtoul(p, &p, 10); switch (*p) { case 'u': /* '%u' => username */ case 't': /* '%t' => taskid */ case 'n': /* '%n' => nodeid */ case 'N': /* '%N' => node name */ fname->type = IO_PER_TASK; /* Put back all the removed % */ xstrcat(name, tmp_perc); if (wid) { /* Put the width back and * the removed %, so the * step can remove it */ xstrcat(name, xstrdup_printf("%u", wid)); q = p; } xfree(tmp_perc); tmp_perc = NULL; p++; break; default: break; } } else p++; wid = 0; } if (q != p) xmemcat(name, q, p); xfree(tmp_perc); fname->name = name; return fname; } void fname_destroy(fname_t *f) { if (f->name) xfree(f->name); xfree(f); } char * fname_remote_string (fname_t *f) { if ((f->type == IO_PER_TASK) || (f->type == IO_ONE)) return (xstrdup (f->name)); return (NULL); } /* remove_path_slashes() * * If there are \ chars in the path strip them. * The new path will tell the caller not to * translate escaped characters. */ static char * _remove_path_slashes(char *p) { char *buf; bool t; int i; if (p == NULL) return NULL; buf = xmalloc(strlen(p) + 1); t = false; i = 0; while (*p) { if (*p == '\\') { t = true; ++p; continue; } buf[i] = *p; ++i; ++p; } if (t == false) { xfree(buf); return NULL; } return buf; }