PageRenderTime 83ms CodeModel.GetById 11ms RepoModel.GetById 0ms app.codeStats 1ms

/src/sbatch/opt.c

https://github.com/cfenoy/slurm
C | 2972 lines | 2708 code | 115 blank | 149 comment | 151 complexity | 71d473eb8a0fe05c4e9dbf46f0db8568 MD5 | raw file
Possible License(s): GPL-2.0, AGPL-1.0
  1. /*****************************************************************************\
  2. * opt.c - options processing for sbatch
  3. *****************************************************************************
  4. * Copyright (C) 2002-2007 The Regents of the University of California.
  5. * Copyright (C) 2008-2010 Lawrence Livermore National Security.
  6. * Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
  7. * Written by Mark Grondona <grondona1@llnl.gov>, et. al.
  8. * CODE-OCEC-09-009. All rights reserved.
  9. *
  10. * This file is part of SLURM, a resource management program.
  11. * For details, see <http://www.schedmd.com/slurmdocs/>.
  12. * Please also read the included file: DISCLAIMER.
  13. *
  14. * SLURM is free software; you can redistribute it and/or modify it under
  15. * the terms of the GNU General Public License as published by the Free
  16. * Software Foundation; either version 2 of the License, or (at your option)
  17. * any later version.
  18. *
  19. * In addition, as a special exception, the copyright holders give permission
  20. * to link the code of portions of this program with the OpenSSL library under
  21. * certain conditions as described in each individual source file, and
  22. * distribute linked combinations including the two. You must obey the GNU
  23. * General Public License in all respects for all of the code used other than
  24. * OpenSSL. If you modify file(s) with this exception, you may extend this
  25. * exception to your version of the file(s), but you are not obligated to do
  26. * so. If you do not wish to do so, delete this exception statement from your
  27. * version. If you delete this exception statement from all source files in
  28. * the program, then also delete it here.
  29. *
  30. * SLURM is distributed in the hope that it will be useful, but WITHOUT ANY
  31. * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
  32. * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
  33. * details.
  34. *
  35. * You should have received a copy of the GNU General Public License along
  36. * with SLURM; if not, write to the Free Software Foundation, Inc.,
  37. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  38. \*****************************************************************************/
  39. #if HAVE_CONFIG_H
  40. # include "config.h"
  41. #endif
  42. #include <string.h> /* strcpy, strncasecmp */
  43. #ifdef HAVE_STRINGS_H
  44. # include <strings.h>
  45. #endif
  46. #ifndef _GNU_SOURCE
  47. # define _GNU_SOURCE
  48. #endif
  49. #if HAVE_GETOPT_H
  50. # include <getopt.h>
  51. #else
  52. # include "src/common/getopt.h"
  53. #endif
  54. #ifdef HAVE_LIMITS_H
  55. # include <limits.h>
  56. #endif
  57. #include <fcntl.h>
  58. #include <stdarg.h> /* va_start */
  59. #include <stdio.h>
  60. #include <stdlib.h> /* getenv */
  61. #include <ctype.h> /* isdigit */
  62. #include <sys/param.h> /* MAXPATHLEN */
  63. #include <sys/stat.h>
  64. #include <unistd.h>
  65. #include <sys/stat.h>
  66. #include <sys/types.h>
  67. #include <sys/utsname.h>
  68. #include "src/common/list.h"
  69. #include "src/common/log.h"
  70. #include "src/common/parse_time.h"
  71. #include "src/common/plugstack.h"
  72. #include "src/common/proc_args.h"
  73. #include "src/common/read_config.h" /* contains getnodename() */
  74. #include "src/common/slurm_protocol_api.h"
  75. #include "src/common/slurm_resource_info.h"
  76. #include "src/common/slurm_rlimits_info.h"
  77. #include "src/common/uid.h"
  78. #include "src/common/xmalloc.h"
  79. #include "src/common/xstring.h"
  80. #include "src/sbatch/opt.h"
  81. /* generic OPT_ definitions -- mainly for use with env vars */
  82. #define OPT_NONE 0x00
  83. #define OPT_INT 0x01
  84. #define OPT_STRING 0x02
  85. #define OPT_DEBUG 0x03
  86. #define OPT_NODES 0x04
  87. #define OPT_BOOL 0x05
  88. #define OPT_CORE 0x06
  89. #define OPT_CONN_TYPE 0x07
  90. #define OPT_DISTRIB 0x08
  91. #define OPT_NO_ROTATE 0x09
  92. #define OPT_GEOMETRY 0x0a
  93. #define OPT_MULTI 0x0b
  94. #define OPT_EXCLUSIVE 0x0c
  95. #define OPT_OVERCOMMIT 0x0d
  96. #define OPT_OPEN_MODE 0x0e
  97. #define OPT_ACCTG_FREQ 0x0f
  98. #define OPT_NO_REQUEUE 0x10
  99. #define OPT_REQUEUE 0x11
  100. #define OPT_CPU_BIND 0x12
  101. #define OPT_MEM_BIND 0x13
  102. #define OPT_WCKEY 0x14
  103. #define OPT_SIGNAL 0x15
  104. #define OPT_GET_USER_ENV 0x16
  105. #define OPT_EXPORT 0x17
  106. #define OPT_CLUSTERS 0x18
  107. #define OPT_TIME_VAL 0x19
  108. /* generic getopt_long flags, integers and *not* valid characters */
  109. #define LONG_OPT_PROPAGATE 0x100
  110. #define LONG_OPT_CPU_BIND 0x101
  111. #define LONG_OPT_MEM_BIND 0x102
  112. #define LONG_OPT_JOBID 0x105
  113. #define LONG_OPT_TMP 0x106
  114. #define LONG_OPT_MEM 0x107
  115. #define LONG_OPT_MINCPU 0x108
  116. #define LONG_OPT_CONT 0x109
  117. #define LONG_OPT_UID 0x10a
  118. #define LONG_OPT_GID 0x10b
  119. #define LONG_OPT_MINSOCKETS 0x10c
  120. #define LONG_OPT_MINCORES 0x10d
  121. #define LONG_OPT_MINTHREADS 0x10e
  122. #define LONG_OPT_CORE 0x10f
  123. #define LONG_OPT_CONNTYPE 0x110
  124. #define LONG_OPT_EXCLUSIVE 0x111
  125. #define LONG_OPT_BEGIN 0x112
  126. #define LONG_OPT_MAIL_TYPE 0x113
  127. #define LONG_OPT_MAIL_USER 0x114
  128. #define LONG_OPT_NICE 0x115
  129. #define LONG_OPT_NO_REQUEUE 0x116
  130. #define LONG_OPT_COMMENT 0x117
  131. #define LONG_OPT_WRAP 0x118
  132. #define LONG_OPT_REQUEUE 0x119
  133. #define LONG_OPT_NETWORK 0x120
  134. #define LONG_OPT_QOS 0x127
  135. #define LONG_OPT_SOCKETSPERNODE 0x130
  136. #define LONG_OPT_CORESPERSOCKET 0x131
  137. #define LONG_OPT_THREADSPERCORE 0x132
  138. #define LONG_OPT_NTASKSPERNODE 0x136
  139. #define LONG_OPT_NTASKSPERSOCKET 0x137
  140. #define LONG_OPT_NTASKSPERCORE 0x138
  141. #define LONG_OPT_MEM_PER_CPU 0x13a
  142. #define LONG_OPT_HINT 0x13b
  143. #define LONG_OPT_BLRTS_IMAGE 0x140
  144. #define LONG_OPT_LINUX_IMAGE 0x141
  145. #define LONG_OPT_MLOADER_IMAGE 0x142
  146. #define LONG_OPT_RAMDISK_IMAGE 0x143
  147. #define LONG_OPT_REBOOT 0x144
  148. #define LONG_OPT_GET_USER_ENV 0x146
  149. #define LONG_OPT_OPEN_MODE 0x147
  150. #define LONG_OPT_ACCTG_FREQ 0x148
  151. #define LONG_OPT_WCKEY 0x149
  152. #define LONG_OPT_RESERVATION 0x14a
  153. #define LONG_OPT_CHECKPOINT 0x14b
  154. #define LONG_OPT_CHECKPOINT_DIR 0x14c
  155. #define LONG_OPT_SIGNAL 0x14d
  156. #define LONG_OPT_TIME_MIN 0x14e
  157. #define LONG_OPT_GRES 0x14f
  158. #define LONG_OPT_WAIT_ALL_NODES 0x150
  159. #define LONG_OPT_EXPORT 0x151
  160. #define LONG_OPT_REQ_SWITCH 0x152
  161. #define LONG_OPT_EXPORT_FILE 0x153
  162. /*---- global variables, defined in opt.h ----*/
  163. opt_t opt;
  164. int error_exit = 1;
  165. /*---- forward declarations of static functions ----*/
  166. typedef struct env_vars env_vars_t;
  167. /* Get a decimal integer from arg */
  168. static int _get_int(const char *arg, const char *what);
  169. static void _help(void);
  170. /* fill in default options */
  171. static void _opt_default(void);
  172. /* set options from batch script */
  173. static void _opt_batch_script(const char *file, const void *body, int size);
  174. /* set options from pbs batch script */
  175. static void _opt_pbs_batch_script(const char *file, const void *body, int size);
  176. /* set options based upon env vars */
  177. static void _opt_env(void);
  178. static void _proc_get_user_env(char *val);
  179. /* list known options and their settings */
  180. static void _opt_list(void);
  181. /* verify options sanity */
  182. static bool _opt_verify(void);
  183. static void _process_env_var(env_vars_t *e, const char *val);
  184. static uint16_t _parse_pbs_mail_type(const char *arg);
  185. static void _usage(void);
  186. static void _fullpath(char **filename, const char *cwd);
  187. static void _set_options(int argc, char **argv);
  188. static void _set_pbs_options(int argc, char **argv);
  189. static void _parse_pbs_resource_list(char *rl);
  190. /*---[ end forward declarations of static functions ]---------------------*/
  191. /*
  192. * print error message to stderr with opt.progname prepended
  193. */
  194. #undef USE_ARGERROR
  195. #if USE_ARGERROR
  196. static void argerror(const char *msg, ...)
  197. __attribute__ ((format (printf, 1, 2)));
  198. static void argerror(const char *msg, ...)
  199. {
  200. va_list ap;
  201. char buf[256];
  202. va_start(ap, msg);
  203. vsnprintf(buf, sizeof(buf), msg, ap);
  204. fprintf(stderr, "%s: %s\n",
  205. opt.progname ? opt.progname : "sbatch", buf);
  206. va_end(ap);
  207. }
  208. #else
  209. # define argerror error
  210. #endif /* USE_ARGERROR */
  211. /*
  212. * If the node list supplied is a file name, translate that into
  213. * a list of nodes, we orphan the data pointed to
  214. * RET true if the node list is a valid one
  215. */
  216. static bool _valid_node_list(char **node_list_pptr)
  217. {
  218. int count = NO_VAL;
  219. /* If we are using Arbitrary and we specified the number of
  220. procs to use then we need exactly this many since we are
  221. saying, lay it out this way! Same for max and min nodes.
  222. Other than that just read in as many in the hostfile */
  223. if(opt.ntasks_set)
  224. count = opt.ntasks;
  225. else if(opt.nodes_set) {
  226. if(opt.max_nodes)
  227. count = opt.max_nodes;
  228. else if(opt.min_nodes)
  229. count = opt.min_nodes;
  230. }
  231. return verify_node_list(node_list_pptr, opt.distribution, count);
  232. }
  233. /*
  234. * _opt_default(): used by initialize_and_process_args to set defaults
  235. */
  236. static void _opt_default()
  237. {
  238. char buf[MAXPATHLEN + 1];
  239. int i;
  240. uid_t uid = getuid();
  241. opt.user = uid_to_string(uid);
  242. if (strcmp(opt.user, "nobody") == 0)
  243. fatal("Invalid user id: %u", uid);
  244. opt.script_argc = 0;
  245. opt.script_argv = NULL;
  246. opt.uid = uid;
  247. opt.gid = getgid();
  248. if ((getcwd(buf, MAXPATHLEN)) == NULL) {
  249. error("getcwd failed: %m");
  250. exit(error_exit);
  251. }
  252. opt.cwd = xstrdup(buf);
  253. opt.clusters = NULL;
  254. opt.progname = NULL;
  255. opt.ntasks = 1;
  256. opt.ntasks_set = false;
  257. opt.cpus_per_task = 0;
  258. opt.cpus_set = false;
  259. opt.min_nodes = 1;
  260. opt.max_nodes = 0;
  261. opt.nodes_set = false;
  262. opt.sockets_per_node = NO_VAL; /* requested sockets */
  263. opt.cores_per_socket = NO_VAL; /* requested cores */
  264. opt.threads_per_core = NO_VAL; /* requested threads */
  265. opt.ntasks_per_node = 0; /* ntask max limits */
  266. opt.ntasks_per_socket = NO_VAL;
  267. opt.ntasks_per_core = NO_VAL;
  268. opt.cpu_bind_type = 0;
  269. opt.cpu_bind = NULL;
  270. opt.mem_bind_type = 0;
  271. opt.mem_bind = NULL;
  272. opt.time_limit = NO_VAL;
  273. opt.time_min = NO_VAL;
  274. opt.partition = NULL;
  275. opt.job_name = NULL;
  276. opt.jobid = NO_VAL;
  277. opt.jobid_set = false;
  278. opt.dependency = NULL;
  279. opt.account = NULL;
  280. opt.comment = NULL;
  281. opt.qos = NULL;
  282. opt.distribution = SLURM_DIST_UNKNOWN;
  283. opt.plane_size = NO_VAL;
  284. opt.shared = (uint16_t)NO_VAL;
  285. opt.no_kill = false;
  286. opt.immediate = false;
  287. opt.requeue = NO_VAL;
  288. opt.overcommit = false;
  289. opt.quiet = 0;
  290. opt.verbose = 0;
  291. opt.warn_signal = 0;
  292. opt.warn_time = 0;
  293. opt.wait_all_nodes = (uint16_t) NO_VAL;
  294. /* constraint default (-1 is no constraint) */
  295. opt.mincpus = -1;
  296. opt.mem_per_cpu = -1;
  297. opt.realmem = -1;
  298. opt.tmpdisk = -1;
  299. opt.hold = false;
  300. opt.constraints = NULL;
  301. opt.gres = NULL;
  302. opt.contiguous = false;
  303. opt.nodelist = NULL;
  304. opt.exc_nodes = NULL;
  305. for (i=0; i<HIGHEST_DIMENSIONS; i++) {
  306. opt.conn_type[i] = (uint16_t) NO_VAL;
  307. opt.geometry[i] = (uint16_t) NO_VAL;
  308. }
  309. opt.reboot = false;
  310. opt.no_rotate = false;
  311. opt.euid = (uid_t) -1;
  312. opt.egid = (gid_t) -1;
  313. opt.propagate = NULL; /* propagate specific rlimits */
  314. opt.ifname = xstrdup("/dev/null");
  315. opt.ofname = NULL;
  316. opt.efname = NULL;
  317. opt.export_env = NULL;
  318. opt.export_file = NULL;
  319. opt.get_user_env_time = -1;
  320. opt.get_user_env_mode = -1;
  321. opt.acctg_freq = -1;
  322. opt.reservation = NULL;
  323. opt.wckey = NULL;
  324. opt.req_switch = -1;
  325. opt.wait4switch = -1;
  326. opt.ckpt_interval = 0;
  327. opt.ckpt_interval_str = NULL;
  328. opt.ckpt_dir = xstrdup(opt.cwd);
  329. }
  330. static void _set_distribution(task_dist_states_t distribution,
  331. char **dist, char **lllp_dist)
  332. {
  333. if (((int)distribution >= 0)
  334. && (distribution != SLURM_DIST_UNKNOWN)) {
  335. switch(distribution) {
  336. case SLURM_DIST_CYCLIC:
  337. *dist = "cyclic";
  338. break;
  339. case SLURM_DIST_BLOCK:
  340. *dist = "block";
  341. break;
  342. case SLURM_DIST_PLANE:
  343. *dist = "plane";
  344. *lllp_dist = "plane";
  345. break;
  346. case SLURM_DIST_ARBITRARY:
  347. *dist = "arbitrary";
  348. break;
  349. case SLURM_DIST_CYCLIC_CYCLIC:
  350. *dist = "cyclic";
  351. *lllp_dist = "cyclic";
  352. break;
  353. case SLURM_DIST_CYCLIC_BLOCK:
  354. *dist = "cyclic";
  355. *lllp_dist = "block";
  356. break;
  357. case SLURM_DIST_BLOCK_CYCLIC:
  358. *dist = "block";
  359. *lllp_dist = "cyclic";
  360. break;
  361. case SLURM_DIST_BLOCK_BLOCK:
  362. *dist = "block";
  363. *lllp_dist = "block";
  364. break;
  365. default:
  366. error("unknown dist, type %d", distribution);
  367. break;
  368. }
  369. }
  370. }
  371. /*---[ env var processing ]-----------------------------------------------*/
  372. /*
  373. * try to use a similar scheme as popt.
  374. *
  375. * in order to add a new env var (to be processed like an option):
  376. *
  377. * define a new entry into env_vars[], if the option is a simple int
  378. * or string you may be able to get away with adding a pointer to the
  379. * option to set. Otherwise, process var based on "type" in _opt_env.
  380. */
  381. struct env_vars {
  382. const char *var;
  383. int type;
  384. void *arg;
  385. void *set_flag;
  386. };
  387. env_vars_t env_vars[] = {
  388. {"SBATCH_ACCOUNT", OPT_STRING, &opt.account, NULL },
  389. {"SBATCH_ACCTG_FREQ", OPT_INT, &opt.acctg_freq, NULL },
  390. {"SBATCH_BLRTS_IMAGE", OPT_STRING, &opt.blrtsimage, NULL },
  391. {"SBATCH_CHECKPOINT", OPT_STRING, &opt.ckpt_interval_str, NULL },
  392. {"SBATCH_CHECKPOINT_DIR",OPT_STRING, &opt.ckpt_dir, NULL },
  393. {"SBATCH_CLUSTERS", OPT_CLUSTERS, &opt.clusters, NULL },
  394. {"SLURM_CLUSTERS", OPT_CLUSTERS, &opt.clusters, NULL },
  395. {"SBATCH_CNLOAD_IMAGE", OPT_STRING, &opt.linuximage, NULL },
  396. {"SBATCH_CONN_TYPE", OPT_CONN_TYPE, NULL, NULL },
  397. {"SBATCH_CPU_BIND", OPT_CPU_BIND, NULL, NULL },
  398. {"SBATCH_DEBUG", OPT_DEBUG, NULL, NULL },
  399. {"SBATCH_DISTRIBUTION", OPT_DISTRIB , NULL, NULL },
  400. {"SBATCH_EXCLUSIVE", OPT_EXCLUSIVE, NULL, NULL },
  401. {"SBATCH_GEOMETRY", OPT_GEOMETRY, NULL, NULL },
  402. {"SBATCH_IMMEDIATE", OPT_BOOL, &opt.immediate, NULL },
  403. {"SBATCH_IOLOAD_IMAGE", OPT_STRING, &opt.ramdiskimage, NULL },
  404. {"SBATCH_JOBID", OPT_INT, &opt.jobid, NULL },
  405. {"SBATCH_JOB_NAME", OPT_STRING, &opt.job_name, NULL },
  406. {"SBATCH_LINUX_IMAGE", OPT_STRING, &opt.linuximage, NULL },
  407. {"SBATCH_MEM_BIND", OPT_MEM_BIND, NULL, NULL },
  408. {"SBATCH_MLOADER_IMAGE", OPT_STRING, &opt.mloaderimage, NULL },
  409. {"SBATCH_NETWORK", OPT_STRING, &opt.network, NULL },
  410. {"SBATCH_NO_REQUEUE", OPT_NO_REQUEUE, NULL, NULL },
  411. {"SBATCH_NO_ROTATE", OPT_BOOL, &opt.no_rotate, NULL },
  412. {"SBATCH_OPEN_MODE", OPT_OPEN_MODE, NULL, NULL },
  413. {"SBATCH_OVERCOMMIT", OPT_OVERCOMMIT, NULL, NULL },
  414. {"SBATCH_PARTITION", OPT_STRING, &opt.partition, NULL },
  415. {"SBATCH_QOS", OPT_STRING, &opt.qos, NULL },
  416. {"SBATCH_RAMDISK_IMAGE", OPT_STRING, &opt.ramdiskimage, NULL },
  417. {"SBATCH_REQUEUE", OPT_REQUEUE, NULL, NULL },
  418. {"SBATCH_SIGNAL", OPT_SIGNAL, NULL, NULL },
  419. {"SBATCH_TIMELIMIT", OPT_STRING, &opt.time_limit_str,NULL },
  420. {"SBATCH_WAIT_ALL_NODES",OPT_INT, &opt.wait_all_nodes,NULL },
  421. {"SBATCH_WCKEY", OPT_STRING, &opt.wckey, NULL },
  422. {"SBATCH_GET_USER_ENV", OPT_GET_USER_ENV, NULL, NULL },
  423. {"SBATCH_EXPORT", OPT_STRING, &opt.export_env, NULL },
  424. {"SBATCH_REQ_SWITCH", OPT_INT, &opt.req_switch, NULL },
  425. {"SBATCH_WAIT4SWITCH", OPT_TIME_VAL, NULL, NULL },
  426. {NULL, 0, NULL, NULL}
  427. };
  428. /*
  429. * _opt_env(): used by initialize_and_process_args to set options via
  430. * environment variables. See comments above for how to
  431. * extend srun to process different vars
  432. */
  433. static void _opt_env()
  434. {
  435. char *val = NULL;
  436. env_vars_t *e = env_vars;
  437. while (e->var) {
  438. if ((val = getenv(e->var)) != NULL)
  439. _process_env_var(e, val);
  440. e++;
  441. }
  442. }
  443. static void
  444. _process_env_var(env_vars_t *e, const char *val)
  445. {
  446. char *end = NULL;
  447. debug2("now processing env var %s=%s", e->var, val);
  448. if (e->set_flag) {
  449. *((bool *) e->set_flag) = true;
  450. }
  451. switch (e->type) {
  452. case OPT_STRING:
  453. *((char **) e->arg) = xstrdup(val);
  454. break;
  455. case OPT_INT:
  456. if (val != NULL) {
  457. *((int *) e->arg) = (int) strtol(val, &end, 10);
  458. if (!(end && *end == '\0')) {
  459. error("%s=%s invalid. ignoring...",
  460. e->var, val);
  461. }
  462. }
  463. break;
  464. case OPT_BOOL:
  465. /* A boolean env variable is true if:
  466. * - set, but no argument
  467. * - argument is "yes"
  468. * - argument is a non-zero number
  469. */
  470. if (val == NULL || strcmp(val, "") == 0) {
  471. *((bool *)e->arg) = true;
  472. } else if (strcasecmp(val, "yes") == 0) {
  473. *((bool *)e->arg) = true;
  474. } else if ((strtol(val, &end, 10) != 0)
  475. && end != val) {
  476. *((bool *)e->arg) = true;
  477. } else {
  478. *((bool *)e->arg) = false;
  479. }
  480. break;
  481. case OPT_DEBUG:
  482. if (val != NULL) {
  483. opt.verbose = (int) strtol(val, &end, 10);
  484. if (!(end && *end == '\0'))
  485. error("%s=%s invalid", e->var, val);
  486. }
  487. break;
  488. case OPT_CPU_BIND:
  489. if (slurm_verify_cpu_bind(val, &opt.cpu_bind,
  490. &opt.cpu_bind_type))
  491. exit(error_exit);
  492. break;
  493. case OPT_MEM_BIND:
  494. if (slurm_verify_mem_bind(val, &opt.mem_bind,
  495. &opt.mem_bind_type))
  496. exit(error_exit);
  497. break;
  498. case OPT_DISTRIB:
  499. opt.distribution = verify_dist_type(val,
  500. &opt.plane_size);
  501. if (opt.distribution == SLURM_DIST_UNKNOWN)
  502. error("distribution type `%s' is invalid", val);
  503. break;
  504. case OPT_NODES:
  505. opt.nodes_set = verify_node_count( val,
  506. &opt.min_nodes,
  507. &opt.max_nodes );
  508. if (opt.nodes_set == false) {
  509. error("\"%s=%s\" -- invalid node count. ignoring...",
  510. e->var, val);
  511. }
  512. break;
  513. case OPT_CONN_TYPE:
  514. verify_conn_type(val, opt.conn_type);
  515. break;
  516. case OPT_NO_ROTATE:
  517. opt.no_rotate = true;
  518. break;
  519. case OPT_GEOMETRY:
  520. if (verify_geometry(val, opt.geometry)) {
  521. error("\"%s=%s\" -- invalid geometry, ignoring...",
  522. e->var, val);
  523. }
  524. break;
  525. case OPT_EXCLUSIVE:
  526. opt.shared = 0;
  527. break;
  528. case OPT_OVERCOMMIT:
  529. opt.overcommit = true;
  530. break;
  531. case OPT_OPEN_MODE:
  532. if ((val[0] == 'a') || (val[0] == 'A'))
  533. opt.open_mode = OPEN_MODE_APPEND;
  534. else if ((val[0] == 't') || (val[0] == 'T'))
  535. opt.open_mode = OPEN_MODE_TRUNCATE;
  536. else
  537. error("Invalid SBATCH_OPEN_MODE: %s. Ignored", val);
  538. break;
  539. case OPT_NO_REQUEUE:
  540. opt.requeue = 0;
  541. break;
  542. case OPT_REQUEUE:
  543. opt.requeue = 1;
  544. break;
  545. case OPT_WCKEY:
  546. xfree(opt.wckey);
  547. opt.wckey = xstrdup(val);
  548. break;
  549. case OPT_SIGNAL:
  550. if (get_signal_opts((char *)val, &opt.warn_signal,
  551. &opt.warn_time)) {
  552. error("Invalid signal specification: %s", val);
  553. exit(error_exit);
  554. }
  555. break;
  556. case OPT_GET_USER_ENV:
  557. if (val)
  558. _proc_get_user_env((char *)val);
  559. else
  560. opt.get_user_env_time = 0;
  561. break;
  562. case OPT_CLUSTERS:
  563. if (!(opt.clusters = slurmdb_get_info_cluster((char *)val))) {
  564. error("'%s' can't be reached now, "
  565. "or it is an invalid entry for "
  566. "--cluster. Use 'sacctmgr --list "
  567. "cluster' to see available clusters.",
  568. optarg);
  569. exit(1);
  570. }
  571. break;
  572. case OPT_TIME_VAL:
  573. opt.wait4switch = time_str2secs(val);
  574. break;
  575. default:
  576. /* do nothing */
  577. break;
  578. }
  579. }
  580. /*---[ command line option processing ]-----------------------------------*/
  581. static struct option long_options[] = {
  582. {"account", required_argument, 0, 'A'},
  583. {"batch", no_argument, 0, 'b'}, /* batch option
  584. is only here for
  585. moab tansition
  586. doesn't do anything */
  587. {"extra-node-info", required_argument, 0, 'B'},
  588. {"cpus-per-task", required_argument, 0, 'c'},
  589. {"constraint", required_argument, 0, 'C'},
  590. {"dependency", required_argument, 0, 'd'},
  591. {"workdir", required_argument, 0, 'D'},
  592. {"error", required_argument, 0, 'e'},
  593. {"nodefile", required_argument, 0, 'F'},
  594. {"geometry", required_argument, 0, 'g'},
  595. {"help", no_argument, 0, 'h'},
  596. {"hold", no_argument, 0, 'H'}, /* undocumented */
  597. {"input", required_argument, 0, 'i'},
  598. {"immediate", no_argument, 0, 'I'},
  599. {"job-name", required_argument, 0, 'J'},
  600. {"no-kill", no_argument, 0, 'k'},
  601. {"licenses", required_argument, 0, 'L'},
  602. {"distribution", required_argument, 0, 'm'},
  603. {"cluster", required_argument, 0, 'M'},
  604. {"clusters", required_argument, 0, 'M'},
  605. {"tasks", required_argument, 0, 'n'},
  606. {"ntasks", required_argument, 0, 'n'},
  607. {"nodes", required_argument, 0, 'N'},
  608. {"output", required_argument, 0, 'o'},
  609. {"overcommit", no_argument, 0, 'O'},
  610. {"partition", required_argument, 0, 'p'},
  611. {"quiet", no_argument, 0, 'Q'},
  612. {"no-rotate", no_argument, 0, 'R'},
  613. {"share", no_argument, 0, 's'},
  614. {"time", required_argument, 0, 't'},
  615. {"usage", no_argument, 0, 'u'},
  616. {"verbose", no_argument, 0, 'v'},
  617. {"version", no_argument, 0, 'V'},
  618. {"nodelist", required_argument, 0, 'w'},
  619. {"exclude", required_argument, 0, 'x'},
  620. {"acctg-freq", required_argument, 0, LONG_OPT_ACCTG_FREQ},
  621. {"begin", required_argument, 0, LONG_OPT_BEGIN},
  622. {"blrts-image", required_argument, 0, LONG_OPT_BLRTS_IMAGE},
  623. {"checkpoint", required_argument, 0, LONG_OPT_CHECKPOINT},
  624. {"checkpoint-dir",required_argument, 0, LONG_OPT_CHECKPOINT_DIR},
  625. {"cnload-image", required_argument, 0, LONG_OPT_LINUX_IMAGE},
  626. {"comment", required_argument, 0, LONG_OPT_COMMENT},
  627. {"conn-type", required_argument, 0, LONG_OPT_CONNTYPE},
  628. {"contiguous", no_argument, 0, LONG_OPT_CONT},
  629. {"cores-per-socket", required_argument, 0, LONG_OPT_CORESPERSOCKET},
  630. {"cpu_bind", required_argument, 0, LONG_OPT_CPU_BIND},
  631. {"exclusive", no_argument, 0, LONG_OPT_EXCLUSIVE},
  632. {"export", required_argument, 0, LONG_OPT_EXPORT},
  633. {"export-file", required_argument, 0, LONG_OPT_EXPORT_FILE},
  634. {"get-user-env", optional_argument, 0, LONG_OPT_GET_USER_ENV},
  635. {"gres", required_argument, 0, LONG_OPT_GRES},
  636. {"gid", required_argument, 0, LONG_OPT_GID},
  637. {"hint", required_argument, 0, LONG_OPT_HINT},
  638. {"ioload-image", required_argument, 0, LONG_OPT_RAMDISK_IMAGE},
  639. {"jobid", required_argument, 0, LONG_OPT_JOBID},
  640. {"linux-image", required_argument, 0, LONG_OPT_LINUX_IMAGE},
  641. {"mail-type", required_argument, 0, LONG_OPT_MAIL_TYPE},
  642. {"mail-user", required_argument, 0, LONG_OPT_MAIL_USER},
  643. {"mem", required_argument, 0, LONG_OPT_MEM},
  644. {"mem-per-cpu", required_argument, 0, LONG_OPT_MEM_PER_CPU},
  645. {"mem_bind", required_argument, 0, LONG_OPT_MEM_BIND},
  646. {"mincores", required_argument, 0, LONG_OPT_MINCORES},
  647. {"mincpus", required_argument, 0, LONG_OPT_MINCPU},
  648. {"minsockets", required_argument, 0, LONG_OPT_MINSOCKETS},
  649. {"minthreads", required_argument, 0, LONG_OPT_MINTHREADS},
  650. {"mloader-image", required_argument, 0, LONG_OPT_MLOADER_IMAGE},
  651. {"network", required_argument, 0, LONG_OPT_NETWORK},
  652. {"nice", optional_argument, 0, LONG_OPT_NICE},
  653. {"no-requeue", no_argument, 0, LONG_OPT_NO_REQUEUE},
  654. {"ntasks-per-core", required_argument, 0, LONG_OPT_NTASKSPERCORE},
  655. {"ntasks-per-node", required_argument, 0, LONG_OPT_NTASKSPERNODE},
  656. {"ntasks-per-socket",required_argument, 0, LONG_OPT_NTASKSPERSOCKET},
  657. {"open-mode", required_argument, 0, LONG_OPT_OPEN_MODE},
  658. {"propagate", optional_argument, 0, LONG_OPT_PROPAGATE},
  659. {"qos", required_argument, 0, LONG_OPT_QOS},
  660. {"ramdisk-image", required_argument, 0, LONG_OPT_RAMDISK_IMAGE},
  661. {"reboot", no_argument, 0, LONG_OPT_REBOOT},
  662. {"requeue", no_argument, 0, LONG_OPT_REQUEUE},
  663. {"reservation", required_argument, 0, LONG_OPT_RESERVATION},
  664. {"signal", required_argument, 0, LONG_OPT_SIGNAL},
  665. {"sockets-per-node", required_argument, 0, LONG_OPT_SOCKETSPERNODE},
  666. {"tasks-per-node",required_argument, 0, LONG_OPT_NTASKSPERNODE},
  667. {"time-min", required_argument, 0, LONG_OPT_TIME_MIN},
  668. {"threads-per-core", required_argument, 0, LONG_OPT_THREADSPERCORE},
  669. {"tmp", required_argument, 0, LONG_OPT_TMP},
  670. {"uid", required_argument, 0, LONG_OPT_UID},
  671. {"wait-all-nodes",required_argument, 0, LONG_OPT_WAIT_ALL_NODES},
  672. {"wckey", required_argument, 0, LONG_OPT_WCKEY},
  673. {"wrap", required_argument, 0, LONG_OPT_WRAP},
  674. {"switches", required_argument, 0, LONG_OPT_REQ_SWITCH},
  675. {NULL, 0, 0, 0}
  676. };
  677. static char *opt_string =
  678. "+bA:B:c:C:d:D:e:F:g:hHi:IJ:kL:m:M:n:N:o:Op:P:QRst:uU:vVw:x:";
  679. char *pos_delimit;
  680. /*
  681. * process_options_first_pass()
  682. *
  683. * In this first pass we only look at the command line options, and we
  684. * will only handle a few options (help, usage, quiet, verbose, version),
  685. * and look for the script name and arguments (if provided).
  686. *
  687. * We will parse the environment variable options, batch script options,
  688. * and all of the rest of the command line options in
  689. * process_options_second_pass().
  690. *
  691. * Return a pointer to the batch script file name is provided on the command
  692. * line, otherwise return NULL, and the script will need to be read from
  693. * standard input.
  694. */
  695. char *process_options_first_pass(int argc, char **argv)
  696. {
  697. int opt_char, option_index = 0;
  698. char *str = NULL;
  699. struct option *optz = spank_option_table_create(long_options);
  700. if (!optz) {
  701. error("Unable to create options table");
  702. exit(error_exit);
  703. }
  704. /* initialize option defaults */
  705. _opt_default();
  706. opt.progname = xbasename(argv[0]);
  707. optind = 0;
  708. while((opt_char = getopt_long(argc, argv, opt_string,
  709. optz, &option_index)) != -1) {
  710. switch (opt_char) {
  711. case '?':
  712. fprintf(stderr, "Try \"sbatch --help\" for more "
  713. "information\n");
  714. exit(error_exit);
  715. break;
  716. case 'h':
  717. _help();
  718. exit(0);
  719. break;
  720. case 'Q':
  721. opt.quiet++;
  722. break;
  723. case 'u':
  724. _usage();
  725. exit(0);
  726. case 'v':
  727. opt.verbose++;
  728. break;
  729. case 'V':
  730. print_slurm_version();
  731. exit(0);
  732. break;
  733. case LONG_OPT_WRAP:
  734. opt.wrap = xstrdup(optarg);
  735. break;
  736. default:
  737. /* will be parsed in second pass function */
  738. break;
  739. }
  740. }
  741. xfree(str);
  742. spank_option_table_destroy(optz);
  743. if (argc > optind && opt.wrap != NULL) {
  744. error("Script arguments are not permitted with the"
  745. " --wrap option.");
  746. exit(error_exit);
  747. }
  748. if (argc > optind) {
  749. int i;
  750. char **leftover;
  751. opt.script_argc = argc - optind;
  752. leftover = argv + optind;
  753. opt.script_argv = (char **) xmalloc((opt.script_argc + 1)
  754. * sizeof(char *));
  755. for (i = 0; i < opt.script_argc; i++)
  756. opt.script_argv[i] = xstrdup(leftover[i]);
  757. opt.script_argv[i] = NULL;
  758. }
  759. if (opt.script_argc > 0) {
  760. char *fullpath;
  761. char *cmd = opt.script_argv[0];
  762. int mode = R_OK;
  763. if ((fullpath = search_path(opt.cwd, cmd, true, mode))) {
  764. xfree(opt.script_argv[0]);
  765. opt.script_argv[0] = fullpath;
  766. }
  767. return opt.script_argv[0];
  768. } else {
  769. return NULL;
  770. }
  771. }
  772. /* process options:
  773. * 1. update options with option set in the script
  774. * 2. update options with env vars
  775. * 3. update options with commandline args
  776. * 4. perform some verification that options are reasonable
  777. */
  778. int process_options_second_pass(int argc, char *argv[], const char *file,
  779. const void *script_body, int script_size)
  780. {
  781. /* set options from batch script */
  782. _opt_batch_script(file, script_body, script_size);
  783. /* set options from pbs batch script */
  784. _opt_pbs_batch_script(file, script_body, script_size);
  785. /* set options from env vars */
  786. _opt_env();
  787. /* set options from command line */
  788. _set_options(argc, argv);
  789. if (!_opt_verify())
  790. exit(error_exit);
  791. if (opt.verbose > 3)
  792. _opt_list();
  793. return 1;
  794. }
  795. /*
  796. * _next_line - Interpret the contents of a byte buffer as characters in
  797. * a file. _next_line will find and return the next line in the buffer.
  798. *
  799. * If "state" is NULL, it will start at the beginning of the buffer.
  800. * _next_line will update the "state" pointer to point at the
  801. * spot in the buffer where it left off.
  802. *
  803. * IN buf - buffer containing file contents
  804. * IN size - size of buffer "buf"
  805. * IN/OUT state - used by _next_line to determine where the last line ended
  806. *
  807. * RET - xmalloc'ed character string, or NULL if no lines remaining in buf.
  808. */
  809. static char *_next_line(const void *buf, int size, void **state)
  810. {
  811. char *line;
  812. char *current, *ptr;
  813. if (*state == NULL) /* initial state */
  814. *state = (void *)buf;
  815. if ((*state - buf) >= size) /* final state */
  816. return NULL;
  817. ptr = current = (char *)*state;
  818. while ((*ptr != '\n') && (ptr < ((char *)buf+size)))
  819. ptr++;
  820. line = xstrndup(current, (ptr-current));
  821. /*
  822. * Advance state past newline
  823. */
  824. *state = (ptr < ((char *) buf + size)) ? ptr+1 : ptr;
  825. return line;
  826. }
  827. /*
  828. * _get_argument - scans a line for something that looks like a command line
  829. * argument, and return an xmalloc'ed string containing the argument.
  830. * Quotes can be used to group characters, including whitespace.
  831. * Quotes can be included in an argument be escaping the quotes,
  832. * preceding the quote with a backslash (\").
  833. *
  834. * IN - line
  835. * OUT - skipped - number of characters parsed from line
  836. * RET - xmalloc'ed argument string (may be shorter than "skipped")
  837. * or NULL if no arguments remaining
  838. */
  839. static char *
  840. _get_argument(const char *file, int lineno, const char *line, int *skipped)
  841. {
  842. const char *ptr;
  843. char argument[BUFSIZ];
  844. char q_char = '\0';
  845. bool escape_flag = false;
  846. bool quoted = false;
  847. int i;
  848. ptr = line;
  849. *skipped = 0;
  850. /* skip whitespace */
  851. while (isspace(*ptr) && *ptr != '\0') {
  852. ptr++;
  853. }
  854. if (*ptr == '\0')
  855. return NULL;
  856. /* copy argument into "argument" buffer, */
  857. i = 0;
  858. while ((quoted || !isspace(*ptr)) && *ptr != '\n' && *ptr != '\0') {
  859. if (escape_flag) {
  860. escape_flag = false;
  861. } else if (*ptr == '\\') {
  862. escape_flag = true;
  863. ptr++;
  864. continue;
  865. } else if (quoted) {
  866. if (*ptr == q_char) {
  867. quoted = false;
  868. ptr++;
  869. continue;
  870. }
  871. } else if (*ptr == '"' || *ptr == '\'') {
  872. quoted = true;
  873. q_char = *(ptr++);
  874. continue;
  875. } else if (*ptr == '#') {
  876. /* found an un-escaped #, rest of line is a comment */
  877. break;
  878. }
  879. argument[i++] = *(ptr++);
  880. }
  881. argument[i] = '\0';
  882. if (quoted) /* Unmatched quote */
  883. fatal("%s: line %d: Unmatched `%c` in [%s]",
  884. file, lineno, q_char, line);
  885. *skipped = ptr - line;
  886. return (i > 0 ? xstrdup (argument) : NULL);
  887. }
  888. /*
  889. * set options from batch script
  890. *
  891. * Build an argv-style array of options from the script "body",
  892. * then pass the array to _set_options for() further parsing.
  893. */
  894. static void _opt_batch_script(const char * file, const void *body, int size)
  895. {
  896. char *magic_word1 = "#SBATCH";
  897. char *magic_word2 = "#SLURM";
  898. int magic_word_len1, magic_word_len2;
  899. int argc;
  900. char **argv;
  901. void *state = NULL;
  902. char *line;
  903. char *option;
  904. char *ptr;
  905. int skipped = 0, warned = 0, lineno = 0;
  906. int i;
  907. magic_word_len1 = strlen(magic_word1);
  908. magic_word_len2 = strlen(magic_word2);
  909. /* getopt_long skips over the first argument, so fill it in */
  910. argc = 1;
  911. argv = xmalloc(sizeof(char *));
  912. argv[0] = "sbatch";
  913. while((line = _next_line(body, size, &state)) != NULL) {
  914. lineno++;
  915. if (!strncmp(line, magic_word1, magic_word_len1))
  916. ptr = line + magic_word_len1;
  917. else if (!strncmp(line, magic_word2, magic_word_len2)) {
  918. ptr = line + magic_word_len2;
  919. if (!warned) {
  920. error("Change from #SLURM to #SBATCH in your "
  921. "script and verify the options are "
  922. "valid in sbatch");
  923. warned = 1;
  924. }
  925. } else {
  926. xfree(line);
  927. continue;
  928. }
  929. /* this line starts with the magic word */
  930. while ((option = _get_argument(file, lineno, ptr, &skipped))) {
  931. debug2("Found in script, argument \"%s\"", option);
  932. argc += 1;
  933. xrealloc(argv, sizeof(char*) * argc);
  934. argv[argc-1] = option;
  935. ptr += skipped;
  936. }
  937. xfree(line);
  938. }
  939. if (argc > 0)
  940. _set_options(argc, argv);
  941. for (i = 1; i < argc; i++)
  942. xfree(argv[i]);
  943. xfree(argv);
  944. }
  945. /*
  946. * set pbs options from batch script
  947. *
  948. * Build an argv-style array of options from the script "body",
  949. * then pass the array to _set_options for() further parsing.
  950. */
  951. static void _opt_pbs_batch_script(const char *file, const void *body, int size)
  952. {
  953. char *magic_word = "#PBS";
  954. int magic_word_len;
  955. int argc;
  956. char **argv;
  957. void *state = NULL;
  958. char *line;
  959. char *option;
  960. char *ptr;
  961. int skipped = 0;
  962. int lineno = 0;
  963. int i;
  964. magic_word_len = strlen(magic_word);
  965. /* getopt_long skips over the first argument, so fill it in */
  966. argc = 1;
  967. argv = xmalloc(sizeof(char *));
  968. argv[0] = "sbatch";
  969. while((line = _next_line(body, size, &state)) != NULL) {
  970. lineno++;
  971. if (strncmp(line, magic_word, magic_word_len) != 0) {
  972. xfree(line);
  973. continue;
  974. }
  975. /* this line starts with the magic word */
  976. ptr = line + magic_word_len;
  977. while ((option = _get_argument(file, lineno, ptr, &skipped))) {
  978. debug2("Found in script, argument \"%s\"", option);
  979. argc += 1;
  980. xrealloc(argv, sizeof(char*) * argc);
  981. argv[argc-1] = option;
  982. ptr += skipped;
  983. }
  984. xfree(line);
  985. }
  986. if (argc > 0)
  987. _set_pbs_options(argc, argv);
  988. for (i = 1; i < argc; i++)
  989. xfree(argv[i]);
  990. xfree(argv);
  991. }
  992. static void _set_options(int argc, char **argv)
  993. {
  994. int opt_char, option_index = 0, max_val = 0;
  995. char *tmp;
  996. struct option *optz = spank_option_table_create(long_options);
  997. if (!optz) {
  998. error("Unable to create options table");
  999. exit(error_exit);
  1000. }
  1001. optind = 0;
  1002. while((opt_char = getopt_long(argc, argv, opt_string,
  1003. optz, &option_index)) != -1) {
  1004. switch (opt_char) {
  1005. case '?':
  1006. error("Try \"sbatch --help\" for more information");
  1007. exit(error_exit);
  1008. break;
  1009. case 'A':
  1010. case 'U': /* backwards compatibility */
  1011. xfree(opt.account);
  1012. opt.account = xstrdup(optarg);
  1013. break;
  1014. case 'b':
  1015. /* Only here for Moab transition not suppose
  1016. to do anything */
  1017. break;
  1018. case 'B':
  1019. opt.extra_set = verify_socket_core_thread_count(
  1020. optarg,
  1021. &opt.sockets_per_node,
  1022. &opt.cores_per_socket,
  1023. &opt.threads_per_core,
  1024. &opt.cpu_bind_type);
  1025. if (opt.extra_set == false) {
  1026. error("invalid resource allocation -B `%s'",
  1027. optarg);
  1028. exit(error_exit);
  1029. }
  1030. break;
  1031. case 'c':
  1032. opt.cpus_set = true;
  1033. opt.cpus_per_task = _get_int(optarg, "cpus-per-task");
  1034. break;
  1035. case 'C':
  1036. xfree(opt.constraints);
  1037. opt.constraints = xstrdup(optarg);
  1038. break;
  1039. case 'd':
  1040. xfree(opt.dependency);
  1041. opt.dependency = xstrdup(optarg);
  1042. break;
  1043. case 'D':
  1044. xfree(opt.cwd);
  1045. opt.cwd = xstrdup(optarg);
  1046. break;
  1047. case 'e':
  1048. xfree(opt.efname);
  1049. if (strcasecmp(optarg, "none") == 0)
  1050. opt.efname = xstrdup("/dev/null");
  1051. else
  1052. opt.efname = xstrdup(optarg);
  1053. break;
  1054. case 'F':
  1055. xfree(opt.nodelist);
  1056. tmp = slurm_read_hostfile(optarg, 0);
  1057. if (tmp != NULL) {
  1058. opt.nodelist = xstrdup(tmp);
  1059. free(tmp);
  1060. } else {
  1061. error("\"%s\" is not a valid node file",
  1062. optarg);
  1063. exit(error_exit);
  1064. }
  1065. break;
  1066. case 'g':
  1067. if (verify_geometry(optarg, opt.geometry))
  1068. exit(error_exit);
  1069. break;
  1070. case 'h':
  1071. _help();
  1072. exit(0);
  1073. case 'H':
  1074. opt.hold = true;
  1075. break;
  1076. case 'i':
  1077. xfree(opt.ifname);
  1078. if (strcasecmp(optarg, "none") == 0)
  1079. opt.ifname = xstrdup("/dev/null");
  1080. else
  1081. opt.ifname = xstrdup(optarg);
  1082. break;
  1083. case 'I':
  1084. opt.immediate = true;
  1085. break;
  1086. case 'J':
  1087. xfree(opt.job_name);
  1088. opt.job_name = xstrdup(optarg);
  1089. break;
  1090. case 'k':
  1091. opt.no_kill = true;
  1092. break;
  1093. case 'L':
  1094. xfree(opt.licenses);
  1095. opt.licenses = xstrdup(optarg);
  1096. break;
  1097. case 'm':
  1098. opt.distribution = verify_dist_type(optarg,
  1099. &opt.plane_size);
  1100. if (opt.distribution == SLURM_DIST_UNKNOWN) {
  1101. error("distribution type `%s' "
  1102. "is not recognized", optarg);
  1103. exit(error_exit);
  1104. }
  1105. break;
  1106. case 'M':
  1107. if (opt.clusters)
  1108. list_destroy(opt.clusters);
  1109. if (!(opt.clusters =
  1110. slurmdb_get_info_cluster(optarg))) {
  1111. error("'%s' can't be reached now, "
  1112. "or it is an invalid entry for "
  1113. "--cluster. Use 'sacctmgr --list "
  1114. "cluster' to see available clusters.",
  1115. optarg);
  1116. exit(1);
  1117. }
  1118. break;
  1119. case 'n':
  1120. opt.ntasks_set = true;
  1121. opt.ntasks =
  1122. _get_int(optarg, "number of tasks");
  1123. break;
  1124. case 'N':
  1125. opt.nodes_set =
  1126. verify_node_count(optarg,
  1127. &opt.min_nodes,
  1128. &opt.max_nodes);
  1129. if (opt.nodes_set == false) {
  1130. error("invalid node count `%s'",
  1131. optarg);
  1132. exit(error_exit);
  1133. }
  1134. break;
  1135. case 'o':
  1136. xfree(opt.ofname);
  1137. if (strcasecmp(optarg, "none") == 0)
  1138. opt.ofname = xstrdup("/dev/null");
  1139. else
  1140. opt.ofname = xstrdup(optarg);
  1141. break;
  1142. case 'O':
  1143. opt.overcommit = true;
  1144. break;
  1145. case 'p':
  1146. xfree(opt.partition);
  1147. opt.partition = xstrdup(optarg);
  1148. break;
  1149. case 'P':
  1150. verbose("-P option is deprecated, use -d instead");
  1151. xfree(opt.dependency);
  1152. opt.dependency = xstrdup(optarg);
  1153. break;
  1154. case 'Q':
  1155. opt.quiet++;
  1156. break;
  1157. case 'R':
  1158. opt.no_rotate = true;
  1159. break;
  1160. case 's':
  1161. opt.shared = 1;
  1162. break;
  1163. case 't':
  1164. xfree(opt.time_limit_str);
  1165. opt.time_limit_str = xstrdup(optarg);
  1166. break;
  1167. case 'u':
  1168. _usage();
  1169. exit(0);
  1170. case 'v':
  1171. opt.verbose++;
  1172. break;
  1173. case 'V':
  1174. print_slurm_version();
  1175. exit(0);
  1176. break;
  1177. case 'w':
  1178. xfree(opt.nodelist);
  1179. opt.nodelist = xstrdup(optarg);
  1180. #ifdef HAVE_BG
  1181. info("\tThe nodelist option should only be used if\n"
  1182. "\tthe block you are asking for can be created.\n"
  1183. "\tIt should also include all the midplanes you\n"
  1184. "\twant to use, partial lists may not\n"
  1185. "\twork correctly.\n"
  1186. "\tPlease consult smap before using this option\n"
  1187. "\tor your job may be stuck with no way to run.");
  1188. #endif
  1189. break;
  1190. case 'x':
  1191. xfree(opt.exc_nodes);
  1192. opt.exc_nodes = xstrdup(optarg);
  1193. if (!_valid_node_list(&opt.exc_nodes))
  1194. exit(error_exit);
  1195. break;
  1196. case LONG_OPT_CONT:
  1197. opt.contiguous = true;
  1198. break;
  1199. case LONG_OPT_EXCLUSIVE:
  1200. opt.shared = 0;
  1201. break;
  1202. case LONG_OPT_CPU_BIND:
  1203. if (slurm_verify_cpu_bind(optarg, &opt.cpu_bind,
  1204. &opt.cpu_bind_type))
  1205. exit(error_exit);
  1206. break;
  1207. case LONG_OPT_MEM_BIND:
  1208. if (slurm_verify_mem_bind(optarg, &opt.mem_bind,
  1209. &opt.mem_bind_type))
  1210. exit(error_exit);
  1211. break;
  1212. case LONG_OPT_MINCPU:
  1213. opt.mincpus = _get_int(optarg, "mincpus");
  1214. if (opt.mincpus < 0) {
  1215. error("invalid mincpus constraint %s",
  1216. optarg);
  1217. exit(error_exit);
  1218. }
  1219. break;
  1220. case LONG_OPT_MINCORES:
  1221. verbose("mincores option has been deprecated, use "
  1222. "cores-per-socket");
  1223. opt.cores_per_socket = _get_int(optarg, "mincores");
  1224. if (opt.cores_per_socket < 0) {
  1225. error("invalid mincores constraint %s",
  1226. optarg);
  1227. exit(error_exit);
  1228. }
  1229. break;
  1230. case LONG_OPT_MINSOCKETS:
  1231. verbose("minsockets option has been deprecated, use "
  1232. "sockets-per-node");
  1233. opt.sockets_per_node = _get_int(optarg, "minsockets");
  1234. if (opt.sockets_per_node < 0) {
  1235. error("invalid minsockets constraint %s",
  1236. optarg);
  1237. exit(error_exit);
  1238. }
  1239. break;
  1240. case LONG_OPT_MINTHREADS:
  1241. verbose("minthreads option has been deprecated, use "
  1242. "threads-per-core");
  1243. opt.threads_per_core = _get_int(optarg, "minthreads");
  1244. if (opt.threads_per_core < 0) {
  1245. error("invalid minthreads constraint %s",
  1246. optarg);
  1247. exit(error_exit);
  1248. }
  1249. break;
  1250. case LONG_OPT_MEM:
  1251. opt.realmem = (int) str_to_mbytes(optarg);
  1252. if (opt.realmem < 0) {
  1253. error("invalid memory constraint %s",
  1254. optarg);
  1255. exit(error_exit);
  1256. }
  1257. break;
  1258. case LONG_OPT_MEM_PER_CPU:
  1259. opt.mem_per_cpu = (int) str_to_mbytes(optarg);
  1260. if (opt.mem_per_cpu < 0) {
  1261. error("invalid memory constraint %s",
  1262. optarg);
  1263. exit(error_exit);
  1264. }
  1265. break;
  1266. case LONG_OPT_TMP:
  1267. opt.tmpdisk = str_to_mbytes(optarg);
  1268. if (opt.tmpdisk < 0) {
  1269. error("invalid tmp value %s", optarg);
  1270. exit(error_exit);
  1271. }
  1272. break;
  1273. case LONG_OPT_JOBID:
  1274. opt.jobid = _get_int(optarg, "jobid");
  1275. opt.jobid_set = true;
  1276. break;
  1277. case LONG_OPT_UID:
  1278. if (opt.euid != (uid_t) -1) {
  1279. error("duplicate --uid option");
  1280. exit(error_exit);
  1281. }
  1282. if (uid_from_string (optarg, &opt.euid) < 0) {
  1283. error("--uid=\"%s\" invalid", optarg);
  1284. exit(error_exit);
  1285. }
  1286. break;
  1287. case LONG_OPT_GID:
  1288. if (opt.egid != (gid_t) -1) {
  1289. error("duplicate --gid option");
  1290. exit(error_exit);
  1291. }
  1292. if (gid_from_string (optarg, &opt.egid) < 0) {
  1293. error("--gid=\"%s\" invalid", optarg);
  1294. exit(error_exit);
  1295. }
  1296. break;
  1297. case LONG_OPT_CONNTYPE:
  1298. verify_conn_type(optarg, opt.conn_type);
  1299. break;
  1300. case LONG_OPT_BEGIN:
  1301. opt.begin = parse_time(optarg, 0);
  1302. if (opt.begin == 0) {
  1303. error("Invalid time specification %s", optarg);
  1304. exit(error_exit);
  1305. }
  1306. break;
  1307. case LONG_OPT_MAIL_TYPE:
  1308. opt.mail_type |= parse_mail_type(optarg);
  1309. if (opt.mail_type == 0) {
  1310. error("--mail-type=%s invalid", optarg);
  1311. exit(error_exit);
  1312. }
  1313. break;
  1314. case LONG_OPT_MAIL_USER:
  1315. xfree(opt.mail_user);
  1316. opt.mail_user = xstrdup(optarg);
  1317. break;
  1318. case LONG_OPT_NICE:
  1319. if (optarg)
  1320. opt.nice = strtol(optarg, NULL, 10);
  1321. else
  1322. opt.nice = 100;
  1323. if (abs(opt.nice) > NICE_OFFSET) {
  1324. error("Invalid nice value, must be between "
  1325. "-%d and %d", NICE_OFFSET, NICE_OFFSET);
  1326. exit(error_exit);
  1327. }
  1328. if (opt.nice < 0) {
  1329. uid_t my_uid = getuid();
  1330. if ((my_uid != 0) &&
  1331. (my_uid != slurm_get_slurm_user_id())) {
  1332. error("Nice value must be "
  1333. "non-negative, value ignored");
  1334. opt.nice = 0;
  1335. }
  1336. }
  1337. break;
  1338. case LONG_OPT_NO_REQUEUE:
  1339. opt.requeue = 0;
  1340. break;
  1341. case LONG_OPT_REQUEUE:
  1342. opt.requeue = 1;
  1343. break;
  1344. case LONG_OPT_COMMENT:
  1345. xfree(opt.comment);
  1346. opt.comment = xstrdup(optarg);
  1347. break;
  1348. case LONG_OPT_QOS:
  1349. xfree(opt.qos);
  1350. opt.qos = xstrdup(optarg);
  1351. break;
  1352. case LONG_OPT_SOCKETSPERNODE:
  1353. max_val = 0;
  1354. get_resource_arg_range( optarg, "sockets-per-node",
  1355. &opt.sockets_per_node,
  1356. &max_val, true );
  1357. if ((opt.sockets_per_node == 1) &&
  1358. (max_val == INT_MAX))
  1359. opt.sockets_per_node = NO_VAL;
  1360. break;
  1361. case LONG_OPT_CORESPERSOCKET:
  1362. max_val = 0;
  1363. get_resource_arg_range( optarg, "cores-per-socket",
  1364. &opt.cores_per_socket,
  1365. &max_val, true );
  1366. if ((opt.cores_per_socket == 1) &&
  1367. (max_val == INT_MAX))
  1368. opt.cores_per_socket = NO_VAL;
  1369. break;
  1370. case LONG_OPT_THREADSPERCORE:
  1371. max_val = 0;
  1372. get_resource_arg_range( optarg, "threads-per-core",
  1373. &opt.threads_per_core,
  1374. &max_val, true );
  1375. if ((opt.threads_per_core == 1) &&
  1376. (max_val == INT_MAX))
  1377. opt.threads_per_core = NO_VAL;
  1378. break;
  1379. case LONG_OPT_NTASKSPERNODE:
  1380. opt.ntasks_per_node = _get_int(optarg,
  1381. "ntasks-per-node");
  1382. setenvf(NULL, "SLURM_NTASKS_PER_NODE", "%d",
  1383. opt.ntasks_per_node);
  1384. break;
  1385. case LONG_OPT_NTASKSPERSOCKET:
  1386. opt.ntasks_per_socket = _get_int(optarg,
  1387. "ntasks-per-socket");
  1388. setenvf(NULL, "SLURM_NTASKS_PER_SOCKET", "%d",
  1389. opt.ntasks_per_socket);
  1390. break;
  1391. case LONG_OPT_NTASKSPERCORE:
  1392. opt.ntasks_per_core = _get_int(optarg,
  1393. "ntasks-per-core");
  1394. setenvf(NULL, "SLURM_NTASKS_PER_CORE", "%d",
  1395. opt.ntasks_per_socket);
  1396. break;
  1397. case LONG_OPT_HINT:
  1398. /* Keep after other options filled in */
  1399. if (verify_hint(optarg,
  1400. &opt.sockets_per_node,
  1401. &opt.cores_per_socket,
  1402. &opt.threads_per_core,
  1403. &opt.ntasks_per_core,
  1404. &opt.cpu_bind_type)) {
  1405. exit(error_exit);
  1406. }
  1407. break;
  1408. case LONG_OPT_BLRTS_IMAGE:
  1409. xfree(opt.blrtsimage);
  1410. opt.blrtsimage = xstrdup(optarg);
  1411. break;
  1412. case LONG_OPT_LINUX_IMAGE:
  1413. xfree(opt.linuximage);
  1414. opt.linuximage = xstrdup(optarg);
  1415. break;
  1416. case LONG_OPT_MLOADER_IMAGE:
  1417. xfree(opt.mloaderimage);
  1418. opt.mloaderimage = xstrdup(optarg);
  1419. break;
  1420. case LONG_OPT_RAMDISK_IMAGE:
  1421. xfree(opt.ramdiskimage);
  1422. opt.ramdiskimage = xstrdup(optarg);
  1423. break;
  1424. case LONG_OPT_REBOOT:
  1425. #if defined HAVE_BG && !defined HAVE_BG_L_P
  1426. info("WARNING: If your job is smaller than the block "
  1427. "it is going to run on and other jobs are "
  1428. "running on it the --reboot option will not be "
  1429. "honored. If this is the case, contact your "
  1430. "admin to reboot the block for you.");
  1431. #endif
  1432. opt.reboot = true;
  1433. break;
  1434. case LONG_OPT_WRAP:
  1435. /* handled in process_options_first_pass() */
  1436. break;
  1437. case LONG_OPT_GET_USER_ENV:
  1438. if (optarg)
  1439. _proc_get_user_env(optarg);
  1440. else
  1441. opt.get_user_env_time = 0;
  1442. break;
  1443. case LONG_OPT_OPEN_MODE:
  1444. if ((optarg[0] == 'a') || (optarg[0] == 'A'))
  1445. opt.open_mode = OPEN_MODE_APPEND;
  1446. else if ((optarg[0] == 't') || (optarg[0] == 'T'))
  1447. opt.open_mode = OPEN_MODE_TRUNCATE;
  1448. else {
  1449. error("Invalid --open-mode argument: %s. "
  1450. "Ignored", optarg);
  1451. }
  1452. break;
  1453. case LONG_OPT_ACCTG_FREQ:
  1454. opt.acctg_freq = _get_int(optarg, "acctg-freq");
  1455. break;
  1456. case LONG_OPT_PROPAGATE:
  1457. xfree(opt.propagate);
  1458. if (optarg)
  1459. opt.propagate = xstrdup(optarg);
  1460. else
  1461. opt.propagate = xstrdup("ALL");
  1462. break;
  1463. case LONG_OPT_NETWORK:
  1464. xfree(opt.network);
  1465. opt.network = xstrdup(optarg);
  1466. break;
  1467. case LONG_OPT_WCKEY:
  1468. xfree(opt.wckey);
  1469. opt.wckey = xstrdup(optarg);
  1470. break;
  1471. case LONG_OPT_RESERVATION:
  1472. xfree(opt.reservation);
  1473. opt.reservation = xstrdup(optarg);
  1474. break;
  1475. case LONG_OPT_CHECKPOINT:
  1476. xfree(opt.ckpt_interval_str);
  1477. opt.ckpt_interval_str = xstrdup(optarg);
  1478. break;
  1479. case LONG_OPT_CHECKPOINT_DIR:
  1480. xfree(opt.ckpt_dir);
  1481. opt.ckpt_dir = xstrdup(optarg);
  1482. break;
  1483. case LONG_OPT_SIGNAL:
  1484. if (get_signal_opts(optarg, &opt.warn_signal,
  1485. &opt.warn_time)) {
  1486. error("Invalid signal specification: %s",
  1487. optarg);
  1488. exit(error_exit);
  1489. }
  1490. break;
  1491. case LONG_OPT_TIME_MIN:
  1492. xfree(opt.time_min_str);
  1493. opt.time_min_str = xstrdup(optarg);
  1494. break;
  1495. case LONG_OPT_GRES:
  1496. if (!strcasecmp(optarg, "help") ||
  1497. !strcasecmp(optarg, "list")) {
  1498. print_gres_help();
  1499. exit(0);
  1500. }
  1501. xfree(opt.gres);
  1502. opt.gres = xstrdup(optarg);
  1503. break;
  1504. case LONG_OPT_WAIT_ALL_NODES:
  1505. opt.wait_all_nodes = strtol(optarg, NULL, 10);
  1506. break;
  1507. case LONG_OPT_EXPORT:
  1508. xfree(opt.export_env);
  1509. opt.export_env = xstrdup(optarg);
  1510. break;
  1511. case LONG_OPT_EXPORT_FILE:
  1512. xfree(opt.export_file);
  1513. opt.export_file = xstrdup(optarg);
  1514. break;
  1515. case LONG_OPT_REQ_SWITCH:
  1516. pos_delimit = strstr(optarg,"@");
  1517. if (pos_delimit != NULL) {
  1518. pos_delimit[0] = '\0';
  1519. pos_delimit++;
  1520. opt.wait4switch = time_str2secs(pos_delimit);
  1521. }
  1522. opt.req_switch = _get_int(optarg, "switches");
  1523. break;
  1524. default:
  1525. if (spank_process_option (opt_char, optarg) < 0) {
  1526. error("Unrecognized command line parameter %c",
  1527. opt_char);
  1528. exit(error_exit);
  1529. }
  1530. }
  1531. }
  1532. if (optind < argc) {
  1533. error("Invalid argument: %s", argv[optind]);
  1534. exit(error_exit);
  1535. }
  1536. spank_option_table_destroy (optz);
  1537. }
  1538. static void _proc_get_user_env(char *optarg)
  1539. {
  1540. char *end_ptr;
  1541. if ((optarg[0] >= '0') && (optarg[0] <= '9'))
  1542. opt.get_user_env_time = strtol(optarg, &end_ptr, 10);
  1543. else {
  1544. opt.get_user_env_time = 0;
  1545. end_ptr = optarg;
  1546. }
  1547. if ((end_ptr == NULL) || (end_ptr[0] == '\0'))
  1548. return;
  1549. if ((end_ptr[0] == 's') || (end_ptr[0] == 'S'))
  1550. opt.get_user_env_mode = 1;
  1551. else if ((end_ptr[0] == 'l') || (end_ptr[0] == 'L'))
  1552. opt.get_user_env_mode = 2;
  1553. }
  1554. static void _set_pbs_options(int argc, char **argv)
  1555. {
  1556. int opt_char, option_index = 0;
  1557. char *pbs_opt_string = "+a:A:c:C:e:hIj:k:l:m:M:N:o:p:q:r:S:u:v:VWz";
  1558. struct option pbs_long_options[] = {
  1559. {"start_time", required_argument, 0, 'a'},
  1560. {"account", required_argument, 0, 'A'},
  1561. {"checkpoint", required_argument, 0, 'c'},
  1562. {"working_dir", required_argument, 0, 'C'},
  1563. {"error", required_argument, 0, 'e'},
  1564. {"hold", no_argument, 0, 'h'},
  1565. {"interactive", no_argument, 0, 'I'},
  1566. {"join", optional_argument, 0, 'j'},
  1567. {"keep", required_argument, 0, 'k'},
  1568. {"resource_list", required_argument, 0, 'l'},
  1569. {"mail_options", required_argument, 0, 'm'},
  1570. {"mail_user_list", required_argument, 0, 'M'},
  1571. {"job_name", required_argument, 0, 'N'},
  1572. {"out", required_argument, 0, 'o'},
  1573. {"priority", required_argument, 0, 'p'},
  1574. {"destination", required_argument, 0, 'q'},
  1575. {"rerunable", required_argument, 0, 'r'},
  1576. {"script_path", required_argument, 0, 'S'},
  1577. {"running_user", required_argument, 0, 'u'},
  1578. {"variable_list", required_argument, 0, 'v'},
  1579. {"all_env", no_argument, 0, 'V'},
  1580. {"attributes", no_argument, 0, 'W'},
  1581. {"no_std", no_argument, 0, 'z'},
  1582. {NULL, 0, 0, 0}
  1583. };
  1584. optind = 0;
  1585. while((opt_char = getopt_long(argc, argv, pbs_opt_string,
  1586. pbs_long_options, &option_index))
  1587. != -1) {
  1588. switch (opt_char) {
  1589. case 'a':
  1590. opt.begin = parse_time(optarg, 0);
  1591. break;
  1592. case 'A':
  1593. xfree(opt.account);
  1594. opt.account = xstrdup(optarg);
  1595. break;
  1596. case 'c':
  1597. break;
  1598. case 'C':
  1599. xfree(opt.cwd);
  1600. opt.cwd = xstrdup(optarg);
  1601. break;
  1602. case 'e':
  1603. xfree(opt.efname);
  1604. if (strcasecmp(optarg, "none") == 0)
  1605. opt.efname = xstrdup("/dev/null");
  1606. else
  1607. opt.efname = xstrdup(optarg);
  1608. break;
  1609. case 'h':
  1610. opt.hold = true;
  1611. break;
  1612. case 'I':
  1613. break;
  1614. case 'j':
  1615. break;
  1616. case 'k':
  1617. break;
  1618. case 'l':
  1619. _parse_pbs_resource_list(optarg);
  1620. break;
  1621. case 'm':
  1622. opt.mail_type |= _parse_pbs_mail_type(optarg);
  1623. if ((opt.mail_type == 0) && strcasecmp(optarg, "n")) {
  1624. error("-m=%s invalid", optarg);
  1625. exit(error_exit);
  1626. }
  1627. break;
  1628. case 'M':
  1629. xfree(opt.mail_user);
  1630. opt.mail_user = xstrdup(optarg);
  1631. break;
  1632. case 'N':
  1633. xfree(opt.job_name);
  1634. opt.job_name = xstrdup(optarg);
  1635. break;
  1636. case 'o':
  1637. xfree(opt.ofname);
  1638. if (strcasecmp(optarg, "none") == 0)
  1639. opt.ofname = xstrdup("/dev/null");
  1640. else
  1641. opt.ofname = xstrdup(optarg);
  1642. break;
  1643. case 'p':
  1644. if (optarg)
  1645. opt.nice = strtol(optarg, NULL, 10);
  1646. else
  1647. opt.nice = 100;
  1648. if (abs(opt.nice) > NICE_OFFSET) {
  1649. error("Invalid nice value, must be between "
  1650. "-%d and %d", NICE_OFFSET, NICE_OFFSET);
  1651. exit(error_exit);
  1652. }
  1653. if (opt.nice < 0) {
  1654. uid_t my_uid = getuid();
  1655. if ((my_uid != 0) &&
  1656. (my_uid != slurm_get_slurm_user_id())) {
  1657. error("Nice value must be "
  1658. "non-negative, value ignored");
  1659. opt.nice = 0;
  1660. }
  1661. }
  1662. break;
  1663. case 'q':
  1664. xfree(opt.partition);
  1665. opt.partition = xstrdup(optarg);
  1666. break;
  1667. case 'r':
  1668. break;
  1669. case 'S':
  1670. break;
  1671. case 'u':
  1672. break;
  1673. case 'v':
  1674. break;
  1675. case 'V':
  1676. break;
  1677. case 'W':
  1678. xfree(opt.constraints);
  1679. opt.constraints = xstrdup(optarg);
  1680. break;
  1681. case 'z':
  1682. break;
  1683. default:
  1684. error("Unrecognized command line parameter %c",
  1685. opt_char);
  1686. exit(error_exit);
  1687. }
  1688. }
  1689. if (optind < argc) {
  1690. error("Invalid argument: %s", argv[optind]);
  1691. exit(error_exit);
  1692. }
  1693. }
  1694. static char *_get_pbs_node_name(char *node_options, int *i)
  1695. {
  1696. int start = (*i);
  1697. char *value = NULL;
  1698. while(node_options[*i]
  1699. && node_options[*i] != '+'
  1700. && node_options[*i] != ':')
  1701. (*i)++;
  1702. value = xmalloc((*i)-start+1);
  1703. memcpy(value, node_options+start, (*i)-start);
  1704. if(node_options[*i])
  1705. (*i)++;
  1706. return value;
  1707. }
  1708. static void _get_next_pbs_node_part(char *node_options, int *i)
  1709. {
  1710. while(node_options[*i]
  1711. && node_options[*i] != '+'
  1712. && node_options[*i] != ':')
  1713. (*i)++;
  1714. if(node_options[*i])
  1715. (*i)++;
  1716. }
  1717. static void _parse_pbs_nodes_opts(char *node_opts)
  1718. {
  1719. int i = 0;
  1720. char *temp = NULL;
  1721. int ppn = 0;
  1722. int node_cnt = 0;
  1723. hostlist_t hl = hostlist_create(NULL);
  1724. while(node_opts[i]) {
  1725. if(!strncmp(node_opts+i, "ppn=", 4)) {
  1726. i+=4;
  1727. ppn += strtol(node_opts+i, NULL, 10);
  1728. _get_next_pbs_node_part(node_opts, &i);
  1729. } else if(isdigit(node_opts[i])) {
  1730. node_cnt += strtol(node_opts+i, NULL, 10);
  1731. _get_next_pbs_node_part(node_opts, &i);
  1732. } else if(isalpha(node_opts[i])) {
  1733. temp = _get_pbs_node_name(node_opts, &i);
  1734. hostlist_push(hl, temp);
  1735. xfree(temp);
  1736. } else
  1737. i++;
  1738. }
  1739. if(!node_cnt)
  1740. node_cnt = 1;
  1741. else {
  1742. opt.nodes_set = true;
  1743. opt.min_nodes = opt.max_nodes = node_cnt;
  1744. }
  1745. if(ppn) {
  1746. ppn *= node_cnt;
  1747. opt.ntasks_set = true;
  1748. opt.ntasks = ppn;
  1749. }
  1750. if(hostlist_count(hl) > 0) {
  1751. xfree(opt.nodelist);
  1752. opt.nodelist = hostlist_ranged_string_xmalloc(hl);
  1753. #ifdef HAVE_BG
  1754. info("\tThe nodelist option should only be used if\n"
  1755. "\tthe block you are asking for can be created.\n"
  1756. "\tPlease consult smap before using this option\n"
  1757. "\tor your job may be stuck with no way to run.");
  1758. #endif
  1759. }
  1760. hostlist_destroy(hl);
  1761. }
  1762. static void _get_next_pbs_option(char *pbs_options, int *i)
  1763. {
  1764. while(pbs_options[*i] && pbs_options[*i] != ',')
  1765. (*i)++;
  1766. if(pbs_options[*i])
  1767. (*i)++;
  1768. }
  1769. static char *_get_pbs_option_value(char *pbs_options, int *i)
  1770. {
  1771. int start = (*i);
  1772. char *value = NULL;
  1773. while(pbs_options[*i] && pbs_options[*i] != ',')
  1774. (*i)++;
  1775. value = xmalloc((*i)-start+1);
  1776. memcpy(value, pbs_options+start, (*i)-start);
  1777. if(pbs_options[*i])
  1778. (*i)++;
  1779. return value;
  1780. }
  1781. static void _parse_pbs_resource_list(char *rl)
  1782. {
  1783. int i = 0;
  1784. char *temp = NULL;
  1785. while(rl[i]) {
  1786. if(!strncmp(rl+i, "arch=", 5)) {
  1787. i+=5;
  1788. _get_next_pbs_option(rl, &i);
  1789. } else if(!strncmp(rl+i, "cput=", 5)) {
  1790. i+=5;
  1791. temp = _get_pbs_option_value(rl, &i);
  1792. if (!temp) {
  1793. error("No value given for cput");
  1794. exit(error_exit);
  1795. }
  1796. xfree(opt.time_limit_str);
  1797. opt.time_limit_str = xstrdup(temp);
  1798. xfree(temp);
  1799. } else if(!strncmp(rl+i, "file=", 5)) {
  1800. int end = 0;
  1801. i+=5;
  1802. temp = _get_pbs_option_value(rl, &i);
  1803. if(!temp) {
  1804. error("No value given for file");
  1805. exit(error_exit);
  1806. }
  1807. end = strlen(temp) - 1;
  1808. if (toupper(temp[end]) == 'B') {
  1809. /* In Torque they do GB or MB on the
  1810. * end of size, we just want G or M so
  1811. * we will remove the b on the end
  1812. */
  1813. temp[end] = '\0';
  1814. }
  1815. opt.tmpdisk = str_to_mbytes(temp);
  1816. if (opt.tmpdisk < 0) {
  1817. error("invalid tmp value %s", temp);
  1818. exit(error_exit);
  1819. }
  1820. xfree(temp);
  1821. } else if(!strncmp(rl+i, "host=", 5)) {
  1822. i+=5;
  1823. _get_next_pbs_option(rl, &i);
  1824. } else if(!strncmp(rl+i, "mem=", 4)) {
  1825. int end = 0;
  1826. i+=4;
  1827. temp = _get_pbs_option_value(rl, &i);
  1828. if(!temp) {
  1829. error("No value given for mem");
  1830. exit(error_exit);
  1831. }
  1832. end = strlen(temp) - 1;
  1833. if (toupper(temp[end]) == 'B') {
  1834. /* In Torque they do GB or MB on the
  1835. * end of size, we just want G or M so
  1836. * we will remove the b on the end
  1837. */
  1838. temp[end] = '\0';
  1839. }
  1840. opt.realmem = (int) str_to_mbytes(temp);
  1841. if (opt.realmem < 0) {
  1842. error("invalid memory constraint %s", temp);
  1843. exit(error_exit);
  1844. }
  1845. xfree(temp);
  1846. #ifdef HAVE_CRAY
  1847. /*
  1848. * NB: no "mppmem" here since it specifies per-PE memory units,
  1849. * whereas SLURM uses per-node and per-CPU memory units.
  1850. */
  1851. } else if (!strncmp(rl + i, "mppdepth=", 9)) {
  1852. /* Cray: number of CPUs (threads) per processing element */
  1853. i += 9;
  1854. temp = _get_pbs_option_value(rl, &i);
  1855. if (temp) {
  1856. opt.cpus_per_task = _get_int(temp, "mppdepth");
  1857. opt.cpus_set = true;
  1858. }
  1859. xfree(temp);
  1860. } else if (!strncmp(rl + i, "mppnodes=", 9)) {
  1861. /* Cray `nodes' variant: hostlist without prefix */
  1862. i += 9;
  1863. temp = _get_pbs_option_value(rl, &i);
  1864. if (!temp) {
  1865. error("No value given for mppnodes");
  1866. exit(error_exit);
  1867. }
  1868. xfree(opt.nodelist);
  1869. opt.nodelist = temp;
  1870. } else if (!strncmp(rl + i, "mppnppn=", 8)) {
  1871. /* Cray: number of processing elements per node */
  1872. i += 8;
  1873. temp = _get_pbs_option_value(rl, &i);
  1874. if (temp)
  1875. opt.ntasks_per_node = _get_int(temp, "mppnppn");
  1876. xfree(temp);
  1877. } else if (!strncmp(rl + i, "mppwidth=", 9)) {
  1878. /* Cray: task width (number of processing elements) */
  1879. i += 9;
  1880. temp = _get_pbs_option_value(rl, &i);
  1881. if (temp) {
  1882. opt.ntasks = _get_int(temp, "mppwidth");
  1883. opt.ntasks_set = true;
  1884. }
  1885. xfree(temp);
  1886. #endif /* HAVE_CRAY */
  1887. } else if(!strncmp(rl+i, "nice=", 5)) {
  1888. i+=5;
  1889. temp = _get_pbs_option_value(rl, &i);
  1890. if (temp)
  1891. opt.nice = strtol(temp, NULL, 10);
  1892. else
  1893. opt.nice = 100;
  1894. if (abs(opt.nice) > NICE_OFFSET) {
  1895. error("Invalid nice value, must be between "
  1896. "-%d and %d", NICE_OFFSET, NICE_OFFSET);
  1897. exit(error_exit);
  1898. }
  1899. if (opt.nice < 0) {
  1900. uid_t my_uid = getuid();
  1901. if ((my_uid != 0) &&
  1902. (my_uid != slurm_get_slurm_user_id())) {
  1903. error("Nice value must be "
  1904. "non-negative, value ignored");
  1905. opt.nice = 0;
  1906. }
  1907. }
  1908. xfree(temp);
  1909. } else if(!strncmp(rl+i, "nodes=", 6)) {
  1910. i+=6;
  1911. temp = _get_pbs_option_value(rl, &i);
  1912. if(!temp) {
  1913. error("No value given for nodes");
  1914. exit(error_exit);
  1915. }
  1916. _parse_pbs_nodes_opts(temp);
  1917. xfree(temp);
  1918. } else if(!strncmp(rl+i, "opsys=", 6)) {
  1919. i+=6;
  1920. _get_next_pbs_option(rl, &i);
  1921. } else if(!strncmp(rl+i, "other=", 6)) {
  1922. i+=6;
  1923. _get_next_pbs_option(rl, &i);
  1924. } else if(!strncmp(rl+i, "pcput=", 6)) {
  1925. i+=6;
  1926. temp = _get_pbs_option_value(rl, &i);
  1927. if(!temp) {
  1928. error("No value given for pcput");
  1929. exit(error_exit);
  1930. }
  1931. xfree(opt.time_limit_str);
  1932. opt.time_limit_str = xstrdup(temp);
  1933. xfree(temp);
  1934. } else if(!strncmp(rl+i, "pmem=", 5)) {
  1935. i+=5;
  1936. _get_next_pbs_option(rl, &i);
  1937. } else if(!strncmp(rl+i, "pvmem=", 6)) {
  1938. i+=6;
  1939. _get_next_pbs_option(rl, &i);
  1940. } else if(!strncmp(rl+i, "software=", 9)) {
  1941. i+=9;
  1942. _get_next_pbs_option(rl, &i);
  1943. } else if(!strncmp(rl+i, "vmem=", 5)) {
  1944. i+=5;
  1945. _get_next_pbs_option(rl, &i);
  1946. } else if(!strncmp(rl+i, "walltime=", 9)) {
  1947. i+=9;
  1948. temp = _get_pbs_option_value(rl, &i);
  1949. if(!temp) {
  1950. error("No value given for walltime");
  1951. exit(error_exit);
  1952. }
  1953. xfree(opt.time_limit_str);
  1954. opt.time_limit_str = xstrdup(temp);
  1955. xfree(temp);
  1956. } else
  1957. i++;
  1958. }
  1959. }
  1960. /*
  1961. * _opt_verify : perform some post option processing verification
  1962. *
  1963. */
  1964. static bool _opt_verify(void)
  1965. {
  1966. bool verified = true;
  1967. char *dist = NULL, *lllp_dist = NULL;
  1968. if (opt.quiet && opt.verbose) {
  1969. error ("don't specify both --verbose (-v) and --quiet (-Q)");
  1970. verified = false;
  1971. }
  1972. _fullpath(&opt.efname, opt.cwd);
  1973. _fullpath(&opt.ifname, opt.cwd);
  1974. _fullpath(&opt.ofname, opt.cwd);
  1975. if ((opt.ntasks_per_node > 0) && (!opt.ntasks_set) &&
  1976. (opt.max_nodes == 0)) {
  1977. opt.ntasks = opt.min_nodes * opt.ntasks_per_node;
  1978. opt.ntasks_set = 1;
  1979. }
  1980. if (opt.cpus_set && (opt.mincpus < opt.cpus_per_task))
  1981. opt.mincpus = opt.cpus_per_task;
  1982. if ((opt.job_name == NULL) && (opt.script_argc > 0))
  1983. opt.job_name = base_name(opt.script_argv[0]);
  1984. if (opt.job_name)
  1985. setenv("SLURM_JOB_NAME", opt.job_name, 0);
  1986. /* check for realistic arguments */
  1987. if (opt.ntasks < 0) {
  1988. error("invalid number of tasks (-n %d)", opt.ntasks);
  1989. verified = false;
  1990. }
  1991. if (opt.cpus_set && (opt.cpus_per_task <= 0)) {
  1992. error("invalid number of cpus per task (-c %d)",
  1993. opt.cpus_per_task);
  1994. verified = false;
  1995. }
  1996. if ((opt.min_nodes < 0) || (opt.max_nodes < 0) ||
  1997. (opt.max_nodes && (opt.min_nodes > opt.max_nodes))) {
  1998. error("invalid number of nodes (-N %d-%d)",
  1999. opt.min_nodes, opt.max_nodes);
  2000. verified = false;
  2001. }
  2002. #ifdef HAVE_BGL
  2003. if (opt.blrtsimage && strchr(opt.blrtsimage, ' ')) {
  2004. error("invalid BlrtsImage given '%s'", opt.blrtsimage);
  2005. verified = false;
  2006. }
  2007. #endif
  2008. if (opt.linuximage && strchr(opt.linuximage, ' ')) {
  2009. #ifdef HAVE_BGL
  2010. error("invalid LinuxImage given '%s'", opt.linuximage);
  2011. #else
  2012. error("invalid CnloadImage given '%s'", opt.linuximage);
  2013. #endif
  2014. verified = false;
  2015. }
  2016. if (opt.mloaderimage && strchr(opt.mloaderimage, ' ')) {
  2017. error("invalid MloaderImage given '%s'", opt.mloaderimage);
  2018. verified = false;
  2019. }
  2020. if (opt.ramdiskimage && strchr(opt.ramdiskimage, ' ')) {
  2021. #ifdef HAVE_BGL
  2022. error("invalid RamDiskImage given '%s'", opt.ramdiskimage);
  2023. #else
  2024. error("invalid IoloadImage given '%s'", opt.ramdiskimage);
  2025. #endif
  2026. verified = false;
  2027. }
  2028. if ((opt.realmem > -1) && (opt.mem_per_cpu > -1)) {
  2029. if (opt.realmem < opt.mem_per_cpu) {
  2030. info("mem < mem-per-cpu - resizing mem to be equal "
  2031. "to mem-per-cpu");
  2032. opt.realmem = opt.mem_per_cpu;
  2033. }
  2034. }
  2035. /* Check to see if user has specified enough resources to
  2036. * satisfy the plane distribution with the specified
  2037. * plane_size.
  2038. * if (n/plane_size < N) and ((N-1) * plane_size >= n) -->
  2039. * problem Simple check will not catch all the problem/invalid
  2040. * cases.
  2041. * The limitations of the plane distribution in the cons_res
  2042. * environment are more extensive and are documented in the
  2043. * SLURM reference guide. */
  2044. if (opt.distribution == SLURM_DIST_PLANE && opt.plane_size) {
  2045. if ((opt.min_nodes <= 0) ||
  2046. ((opt.ntasks/opt.plane_size) < opt.min_nodes)) {
  2047. if (((opt.min_nodes-1)*opt.plane_size) >= opt.ntasks) {
  2048. #if(0)
  2049. info("Too few processes ((n/plane_size) %d < N %d) "
  2050. "and ((N-1)*(plane_size) %d >= n %d)) ",
  2051. opt.ntasks/opt.plane_size, opt.min_nodes,
  2052. (opt.min_nodes-1)*opt.plane_size, opt.ntasks);
  2053. #endif
  2054. error("Too few processes for the requested "
  2055. "{plane,node} distribution");
  2056. exit(error_exit);
  2057. }
  2058. }
  2059. }
  2060. if (opt.cpus_set &&
  2061. setenvf(NULL, "SLURM_CPUS_PER_TASK", "%d", opt.cpus_per_task)) {
  2062. error("Can't set SLURM_CPUS_PER_TASK env variable");
  2063. }
  2064. _set_distribution(opt.distribution, &dist, &lllp_dist);
  2065. if (dist &&
  2066. setenvf(NULL, "SLURM_DISTRIBUTION", "%s", dist)) {
  2067. error("Can't set SLURM_DISTRIBUTION env variable");
  2068. }
  2069. if ((opt.distribution == SLURM_DIST_PLANE) &&
  2070. setenvf(NULL, "SLURM_DIST_PLANESIZE", "%d", opt.plane_size)) {
  2071. error("Can't set SLURM_DIST_PLANESIZE env variable");
  2072. }
  2073. if (lllp_dist && setenvf(NULL, "SLURM_DIST_LLLP", "%s", lllp_dist)) {
  2074. error("Can't set SLURM_DIST_LLLP env variable");
  2075. }
  2076. /* bound threads/cores from ntasks_cores/sockets */
  2077. if (opt.ntasks_per_core > 0) {
  2078. /* if cpu_bind_type doesn't already have a auto pref,
  2079. * choose the level based on the level of ntasks
  2080. */
  2081. if (!(opt.cpu_bind_type & (CPU_BIND_TO_SOCKETS |
  2082. CPU_BIND_TO_CORES |
  2083. CPU_BIND_TO_THREADS))) {
  2084. opt.cpu_bind_type |= CPU_BIND_TO_CORES;
  2085. }
  2086. }
  2087. if (opt.ntasks_per_socket > 0) {
  2088. /* if cpu_bind_type doesn't already have a auto pref,
  2089. * choose the level based on the level of ntasks
  2090. */
  2091. if (!(opt.cpu_bind_type & (CPU_BIND_TO_SOCKETS |
  2092. CPU_BIND_TO_CORES |
  2093. CPU_BIND_TO_THREADS))) {
  2094. opt.cpu_bind_type |= CPU_BIND_TO_SOCKETS;
  2095. }
  2096. }
  2097. /* massage the numbers */
  2098. if ((opt.nodes_set || opt.extra_set) &&
  2099. ((opt.min_nodes == opt.max_nodes) || (opt.max_nodes == 0)) &&
  2100. !opt.ntasks_set) {
  2101. /* 1 proc / node default */
  2102. opt.ntasks = MAX(opt.min_nodes, 1);
  2103. /* 1 proc / min_[socket * core * thread] default */
  2104. if (opt.sockets_per_node != NO_VAL) {
  2105. opt.ntasks *= opt.sockets_per_node;
  2106. opt.ntasks_set = true;
  2107. }
  2108. if (opt.cores_per_socket != NO_VAL) {
  2109. opt.ntasks *= opt.cores_per_socket;
  2110. opt.ntasks_set = true;
  2111. }
  2112. if (opt.threads_per_core != NO_VAL) {
  2113. opt.ntasks *= opt.threads_per_core;
  2114. opt.ntasks_set = true;
  2115. }
  2116. } else if (opt.nodes_set && opt.ntasks_set) {
  2117. /*
  2118. * make sure # of procs >= min_nodes
  2119. */
  2120. if (opt.ntasks < opt.min_nodes) {
  2121. info ("Warning: can't run %d processes on %d "
  2122. "nodes, setting nnodes to %d",
  2123. opt.ntasks, opt.min_nodes, opt.ntasks);
  2124. opt.min_nodes = opt.ntasks;
  2125. if ( opt.max_nodes
  2126. && (opt.min_nodes > opt.max_nodes) )
  2127. opt.max_nodes = opt.min_nodes;
  2128. }
  2129. } /* else if (opt.ntasks_set && !opt.nodes_set) */
  2130. if(!opt.nodelist) {
  2131. if((opt.nodelist = xstrdup(getenv("SLURM_HOSTFILE")))) {
  2132. /* make sure the file being read in has a / in
  2133. it to make sure it is a file in the
  2134. valid_node_list function */
  2135. if(!strstr(opt.nodelist, "/")) {
  2136. char *add_slash = xstrdup("./");
  2137. xstrcat(add_slash, opt.nodelist);
  2138. xfree(opt.nodelist);
  2139. opt.nodelist = add_slash;
  2140. }
  2141. opt.distribution = SLURM_DIST_ARBITRARY;
  2142. if (!_valid_node_list(&opt.nodelist)) {
  2143. error("Failure getting NodeNames from "
  2144. "hostfile");
  2145. exit(error_exit);
  2146. } else {
  2147. debug("loaded nodes (%s) from hostfile",
  2148. opt.nodelist);
  2149. }
  2150. }
  2151. } else {
  2152. if (!_valid_node_list(&opt.nodelist))
  2153. exit(error_exit);
  2154. }
  2155. /* set up the proc and node counts based on the arbitrary list
  2156. of nodes */
  2157. if((opt.distribution == SLURM_DIST_ARBITRARY)
  2158. && (!opt.nodes_set || !opt.ntasks_set)) {
  2159. hostlist_t hl = hostlist_create(opt.nodelist);
  2160. if(!opt.ntasks_set) {
  2161. opt.ntasks_set = 1;
  2162. opt.ntasks = hostlist_count(hl);
  2163. }
  2164. if(!opt.nodes_set) {
  2165. opt.nodes_set = 1;
  2166. hostlist_uniq(hl);
  2167. opt.min_nodes = opt.max_nodes = hostlist_count(hl);
  2168. }
  2169. hostlist_destroy(hl);
  2170. }
  2171. if (opt.time_limit_str) {
  2172. opt.time_limit = time_str2mins(opt.time_limit_str);
  2173. if ((opt.time_limit < 0) && (opt.time_limit != INFINITE)) {
  2174. error("Invalid time limit specification");
  2175. exit(error_exit);
  2176. }
  2177. if (opt.time_limit == 0)
  2178. opt.time_limit = INFINITE;
  2179. }
  2180. if (opt.time_min_str) {
  2181. opt.time_min = time_str2mins(opt.time_min_str);
  2182. if ((opt.time_min < 0) && (opt.time_min != INFINITE)) {
  2183. error("Invalid time-min specification");
  2184. exit(error_exit);
  2185. }
  2186. if (opt.time_min == 0)
  2187. opt.time_min = INFINITE;
  2188. }
  2189. if (opt.ckpt_interval_str) {
  2190. opt.ckpt_interval = time_str2mins(opt.ckpt_interval_str);
  2191. if ((opt.ckpt_interval < 0) &&
  2192. (opt.ckpt_interval != INFINITE)) {
  2193. error("Invalid checkpoint interval specification");
  2194. exit(error_exit);
  2195. }
  2196. }
  2197. if ((opt.euid != (uid_t) -1) && (opt.euid != opt.uid))
  2198. opt.uid = opt.euid;
  2199. if ((opt.egid != (gid_t) -1) && (opt.egid != opt.gid))
  2200. opt.gid = opt.egid;
  2201. if (opt.immediate) {
  2202. char *sched_name = slurm_get_sched_type();
  2203. if (strcmp(sched_name, "sched/wiki") == 0) {
  2204. info("WARNING: Ignoring the -I/--immediate option "
  2205. "(not supported by Maui)");
  2206. opt.immediate = false;
  2207. }
  2208. xfree(sched_name);
  2209. }
  2210. if (opt.open_mode) {
  2211. /* Propage mode to spawned job using environment variable */
  2212. if (opt.open_mode == OPEN_MODE_APPEND)
  2213. setenvf(NULL, "SLURM_OPEN_MODE", "a");
  2214. else
  2215. setenvf(NULL, "SLURM_OPEN_MODE", "t");
  2216. }
  2217. if (opt.dependency)
  2218. setenvfs("SLURM_JOB_DEPENDENCY=%s", opt.dependency);
  2219. if (opt.acctg_freq >= 0)
  2220. setenvf(NULL, "SLURM_ACCTG_FREQ", "%d", opt.acctg_freq);
  2221. #ifdef HAVE_AIX
  2222. if (opt.network == NULL)
  2223. opt.network = "us,sn_all,bulk_xfer";
  2224. setenv("SLURM_NETWORK", opt.network, 1);
  2225. #endif
  2226. if (slurm_verify_cpu_bind(NULL, &opt.cpu_bind,
  2227. &opt.cpu_bind_type))
  2228. exit(error_exit);
  2229. if (opt.cpu_bind_type && (getenv("SBATCH_CPU_BIND") == NULL)) {
  2230. char tmp[64];
  2231. slurm_sprint_cpu_bind_type(tmp, opt.cpu_bind_type);
  2232. if (opt.cpu_bind) {
  2233. setenvf(NULL, "SBATCH_CPU_BIND", "%s:%s",
  2234. tmp, opt.cpu_bind);
  2235. } else {
  2236. setenvf(NULL, "SBATCH_CPU_BIND", "%s", tmp);
  2237. }
  2238. }
  2239. if (opt.mem_bind_type && (getenv("SBATCH_MEM_BIND") == NULL)) {
  2240. char tmp[64];
  2241. slurm_sprint_mem_bind_type(tmp, opt.mem_bind_type);
  2242. if (opt.mem_bind) {
  2243. setenvf(NULL, "SBATCH_MEM_BIND", "%s:%s",
  2244. tmp, opt.mem_bind);
  2245. } else {
  2246. setenvf(NULL, "SBATCH_MEM_BIND", "%s", tmp);
  2247. }
  2248. }
  2249. return verified;
  2250. }
  2251. static uint16_t _parse_pbs_mail_type(const char *arg)
  2252. {
  2253. uint16_t rc;
  2254. if (strcasecmp(arg, "b") == 0)
  2255. rc = MAIL_JOB_BEGIN;
  2256. else if (strcasecmp(arg, "e") == 0)
  2257. rc = MAIL_JOB_END;
  2258. else if (strcasecmp(arg, "a") == 0)
  2259. rc = MAIL_JOB_FAIL;
  2260. else if (strcasecmp(arg, "bea") == 0
  2261. || strcasecmp(arg, "eba") == 0
  2262. || strcasecmp(arg, "eab") == 0
  2263. || strcasecmp(arg, "bae") == 0)
  2264. rc = MAIL_JOB_BEGIN | MAIL_JOB_END | MAIL_JOB_FAIL;
  2265. else if (strcasecmp(arg, "be") == 0
  2266. || strcasecmp(arg, "eb") == 0)
  2267. rc = MAIL_JOB_BEGIN | MAIL_JOB_END;
  2268. else if (strcasecmp(arg, "ba") == 0
  2269. || strcasecmp(arg, "ab") == 0)
  2270. rc = MAIL_JOB_BEGIN | MAIL_JOB_FAIL;
  2271. else if (strcasecmp(arg, "ea") == 0
  2272. || strcasecmp(arg, "ae") == 0)
  2273. rc = MAIL_JOB_END | MAIL_JOB_FAIL;
  2274. else
  2275. rc = 0; /* arg="n" or failure */
  2276. return rc;
  2277. }
  2278. /* Functions used by SPANK plugins to read and write job environment
  2279. * variables for use within job's Prolog and/or Epilog */
  2280. extern char *spank_get_job_env(const char *name)
  2281. {
  2282. int i, len;
  2283. char *tmp_str = NULL;
  2284. if ((name == NULL) || (name[0] == '\0') ||
  2285. (strchr(name, (int)'=') != NULL)) {
  2286. slurm_seterrno(EINVAL);
  2287. return NULL;
  2288. }
  2289. xstrcat(tmp_str, name);
  2290. xstrcat(tmp_str, "=");
  2291. len = strlen(tmp_str);
  2292. for (i=0; i<opt.spank_job_env_size; i++) {
  2293. if (strncmp(opt.spank_job_env[i], tmp_str, len))
  2294. continue;
  2295. xfree(tmp_str);
  2296. return (opt.spank_job_env[i] + len);
  2297. }
  2298. return NULL;
  2299. }
  2300. extern int spank_set_job_env(const char *name, const char *value,
  2301. int overwrite)
  2302. {
  2303. int i, len;
  2304. char *tmp_str = NULL;
  2305. if ((name == NULL) || (name[0] == '\0') ||
  2306. (strchr(name, (int)'=') != NULL)) {
  2307. slurm_seterrno(EINVAL);
  2308. return -1;
  2309. }
  2310. xstrcat(tmp_str, name);
  2311. xstrcat(tmp_str, "=");
  2312. len = strlen(tmp_str);
  2313. xstrcat(tmp_str, value);
  2314. for (i=0; i<opt.spank_job_env_size; i++) {
  2315. if (strncmp(opt.spank_job_env[i], tmp_str, len))
  2316. continue;
  2317. if (overwrite) {
  2318. xfree(opt.spank_job_env[i]);
  2319. opt.spank_job_env[i] = tmp_str;
  2320. } else
  2321. xfree(tmp_str);
  2322. return 0;
  2323. }
  2324. /* Need to add an entry */
  2325. opt.spank_job_env_size++;
  2326. xrealloc(opt.spank_job_env, sizeof(char *) * opt.spank_job_env_size);
  2327. opt.spank_job_env[i] = tmp_str;
  2328. return 0;
  2329. }
  2330. extern int spank_unset_job_env(const char *name)
  2331. {
  2332. int i, j, len;
  2333. char *tmp_str = NULL;
  2334. if ((name == NULL) || (name[0] == '\0') ||
  2335. (strchr(name, (int)'=') != NULL)) {
  2336. slurm_seterrno(EINVAL);
  2337. return -1;
  2338. }
  2339. xstrcat(tmp_str, name);
  2340. xstrcat(tmp_str, "=");
  2341. len = strlen(tmp_str);
  2342. for (i=0; i<opt.spank_job_env_size; i++) {
  2343. if (strncmp(opt.spank_job_env[i], tmp_str, len))
  2344. continue;
  2345. xfree(opt.spank_job_env[i]);
  2346. for (j=(i+1); j<opt.spank_job_env_size; i++, j++)
  2347. opt.spank_job_env[i] = opt.spank_job_env[j];
  2348. opt.spank_job_env_size--;
  2349. if (opt.spank_job_env_size == 0)
  2350. xfree(opt.spank_job_env);
  2351. return 0;
  2352. }
  2353. return 0; /* not found */
  2354. }
  2355. /* helper function for printing options
  2356. *
  2357. * warning: returns pointer to memory allocated on the stack.
  2358. */
  2359. static char *print_constraints()
  2360. {
  2361. char *buf = xstrdup("");
  2362. if (opt.mincpus > 0)
  2363. xstrfmtcat(buf, "mincpus=%d ", opt.mincpus);
  2364. if (opt.minsockets > 0)
  2365. xstrfmtcat(buf, "minsockets=%d ", opt.minsockets);
  2366. if (opt.mincores > 0)
  2367. xstrfmtcat(buf, "mincores=%d ", opt.mincores);
  2368. if (opt.minthreads > 0)
  2369. xstrfmtcat(buf, "minthreads=%d ", opt.minthreads);
  2370. if (opt.realmem > 0)
  2371. xstrfmtcat(buf, "mem=%dM ", opt.realmem);
  2372. if (opt.mem_per_cpu > 0)
  2373. xstrfmtcat(buf, "mem-per-cpu=%dM ", opt.mem_per_cpu);
  2374. if (opt.tmpdisk > 0)
  2375. xstrfmtcat(buf, "tmp=%ld ", opt.tmpdisk);
  2376. if (opt.contiguous == true)
  2377. xstrcat(buf, "contiguous ");
  2378. if (opt.nodelist != NULL)
  2379. xstrfmtcat(buf, "nodelist=%s ", opt.nodelist);
  2380. if (opt.exc_nodes != NULL)
  2381. xstrfmtcat(buf, "exclude=%s ", opt.exc_nodes);
  2382. if (opt.constraints != NULL)
  2383. xstrfmtcat(buf, "constraints=`%s' ", opt.constraints);
  2384. return buf;
  2385. }
  2386. /*
  2387. * Get a decimal integer from arg.
  2388. *
  2389. * Returns the integer on success, exits program on failure.
  2390. *
  2391. */
  2392. static int
  2393. _get_int(const char *arg, const char *what)
  2394. {
  2395. char *p;
  2396. long int result = strtol(arg, &p, 10);
  2397. if ((*p != '\0') || (result < 0L)) {
  2398. error ("Invalid numeric value \"%s\" for %s.", arg, what);
  2399. exit(error_exit);
  2400. }
  2401. if (result > INT_MAX) {
  2402. error ("Numeric argument (%ld) to big for %s.", result, what);
  2403. }
  2404. return (int) result;
  2405. }
  2406. /*
  2407. * Return an absolute path for the "filename". If "filename" is already
  2408. * an absolute path, it returns a copy. Free the returned with xfree().
  2409. */
  2410. static void _fullpath(char **filename, const char *cwd)
  2411. {
  2412. char *ptr = NULL;
  2413. if ((*filename == NULL) || (*filename[0] == '/'))
  2414. return;
  2415. ptr = xstrdup(cwd);
  2416. xstrcat(ptr, "/");
  2417. xstrcat(ptr, *filename);
  2418. xfree(*filename);
  2419. *filename = ptr;
  2420. }
  2421. #define tf_(b) (b == true) ? "true" : "false"
  2422. static void _opt_list(void)
  2423. {
  2424. int i;
  2425. char *str;
  2426. info("defined options for program `%s'", opt.progname);
  2427. info("----------------- ---------------------");
  2428. info("user : `%s'", opt.user);
  2429. info("uid : %ld", (long) opt.uid);
  2430. info("gid : %ld", (long) opt.gid);
  2431. info("cwd : %s", opt.cwd);
  2432. info("ntasks : %d %s", opt.ntasks,
  2433. opt.ntasks_set ? "(set)" : "(default)");
  2434. if (opt.cpus_set)
  2435. info("cpus_per_task : %d", opt.cpus_per_task);
  2436. if (opt.max_nodes) {
  2437. info("nodes : %d-%d",
  2438. opt.min_nodes, opt.max_nodes);
  2439. } else {
  2440. info("nodes : %d %s", opt.min_nodes,
  2441. opt.nodes_set ? "(set)" : "(default)");
  2442. }
  2443. info("jobid : %u %s", opt.jobid,
  2444. opt.jobid_set ? "(set)" : "(default)");
  2445. info("partition : %s",
  2446. opt.partition == NULL ? "default" : opt.partition);
  2447. info("job name : `%s'", opt.job_name);
  2448. info("reservation : `%s'", opt.reservation);
  2449. info("wckey : `%s'", opt.wckey);
  2450. info("distribution : %s",
  2451. format_task_dist_states(opt.distribution));
  2452. if(opt.distribution == SLURM_DIST_PLANE)
  2453. info("plane size : %u", opt.plane_size);
  2454. info("verbose : %d", opt.verbose);
  2455. info("immediate : %s", tf_(opt.immediate));
  2456. if (opt.requeue != NO_VAL)
  2457. info("requeue : %u", opt.requeue);
  2458. info("overcommit : %s", tf_(opt.overcommit));
  2459. if (opt.time_limit == INFINITE)
  2460. info("time_limit : INFINITE");
  2461. else if (opt.time_limit != NO_VAL)
  2462. info("time_limit : %d", opt.time_limit);
  2463. if (opt.time_min != NO_VAL)
  2464. info("time_min : %d", opt.time_min);
  2465. if (opt.nice)
  2466. info("nice : %d", opt.nice);
  2467. info("account : %s", opt.account);
  2468. info("comment : %s", opt.comment);
  2469. info("dependency : %s", opt.dependency);
  2470. if (opt.gres)
  2471. info("gres : %s", opt.gres);
  2472. info("qos : %s", opt.qos);
  2473. str = print_constraints();
  2474. info("constraints : %s", str);
  2475. xfree(str);
  2476. for (i = 0; i < HIGHEST_DIMENSIONS; i++) {
  2477. if (opt.conn_type[i] == (uint16_t) NO_VAL)
  2478. break;
  2479. info("conn_type[%d] : %u", i, opt.conn_type[i]);
  2480. }
  2481. str = print_geometry(opt.geometry);
  2482. info("geometry : %s", str);
  2483. xfree(str);
  2484. info("reboot : %s", opt.reboot ? "no" : "yes");
  2485. info("rotate : %s", opt.no_rotate ? "yes" : "no");
  2486. info("network : %s", opt.network);
  2487. #ifdef HAVE_BGL
  2488. if (opt.blrtsimage)
  2489. info("BlrtsImage : %s", opt.blrtsimage);
  2490. #endif
  2491. if (opt.linuximage)
  2492. #ifdef HAVE_BGL
  2493. info("LinuxImage : %s", opt.linuximage);
  2494. #else
  2495. info("CnloadImage : %s", opt.linuximage);
  2496. #endif
  2497. if (opt.mloaderimage)
  2498. info("MloaderImage : %s", opt.mloaderimage);
  2499. if (opt.ramdiskimage)
  2500. #ifdef HAVE_BGL
  2501. info("RamDiskImage : %s", opt.ramdiskimage);
  2502. #else
  2503. info("IoloadImage : %s", opt.ramdiskimage);
  2504. #endif
  2505. if (opt.begin) {
  2506. char time_str[32];
  2507. slurm_make_time_str(&opt.begin, time_str, sizeof(time_str));
  2508. info("begin : %s", time_str);
  2509. }
  2510. info("mail_type : %s", print_mail_type(opt.mail_type));
  2511. info("mail_user : %s", opt.mail_user);
  2512. info("sockets-per-node : %d", opt.sockets_per_node);
  2513. info("cores-per-socket : %d", opt.cores_per_socket);
  2514. info("threads-per-core : %d", opt.threads_per_core);
  2515. info("ntasks-per-node : %d", opt.ntasks_per_node);
  2516. info("ntasks-per-socket : %d", opt.ntasks_per_socket);
  2517. info("ntasks-per-core : %d", opt.ntasks_per_core);
  2518. info("cpu_bind : %s",
  2519. opt.cpu_bind == NULL ? "default" : opt.cpu_bind);
  2520. info("mem_bind : %s",
  2521. opt.mem_bind == NULL ? "default" : opt.mem_bind);
  2522. info("plane_size : %u", opt.plane_size);
  2523. info("propagate : %s",
  2524. opt.propagate == NULL ? "NONE" : opt.propagate);
  2525. info("switches : %d", opt.req_switch);
  2526. info("wait-for-switches : %d", opt.wait4switch);
  2527. str = print_commandline(opt.script_argc, opt.script_argv);
  2528. info("remote command : `%s'", str);
  2529. xfree(str);
  2530. }
  2531. static void _usage(void)
  2532. {
  2533. printf(
  2534. "Usage: sbatch [-N nnodes] [-n ntasks]\n"
  2535. " [-c ncpus] [-r n] [-p partition] [--hold] [-t minutes]\n"
  2536. " [-D path] [--immediate] [--no-kill] [--overcommit]\n"
  2537. " [--input file] [--output file] [--error file]\n"
  2538. " [--time-min=minutes] [--licenses=names] [--clusters=cluster_names]\n"
  2539. " [--workdir=directory] [--share] [-m dist] [-J jobname]\n"
  2540. " [--jobid=id] [--verbose] [--gid=group] [--uid=user] [-W sec] \n"
  2541. " [--contiguous] [--mincpus=n] [--mem=MB] [--tmp=MB] [-C list]\n"
  2542. " [--account=name] [--dependency=type:jobid] [--comment=name]\n"
  2543. #ifdef HAVE_BG /* Blue gene specific options */
  2544. #ifdef HAVE_BG_L_P
  2545. " [--geometry=XxYxZ] "
  2546. #else
  2547. " [--geometry=AxXxYxZ] "
  2548. #endif
  2549. "[--conn-type=type] [--no-rotate] [--reboot]\n"
  2550. #ifdef HAVE_BGL
  2551. " [--blrts-image=path] [--linux-image=path]\n"
  2552. " [--mloader-image=path] [--ramdisk-image=path]\n"
  2553. #else
  2554. " [--cnload-image=path]\n"
  2555. " [--mloader-image=path] [--ioload-image=path]\n"
  2556. #endif
  2557. #endif
  2558. " [--mail-type=type] [--mail-user=user][--nice[=value]]\n"
  2559. " [--requeue] [--no-requeue] [--ntasks-per-node=n] [--propagate]\n"
  2560. " [--nodefile=file] [--nodelist=hosts] [--exclude=hosts]\n"
  2561. " [--network=type] [--mem-per-cpu=MB] [--qos=qos] [--gres=list]\n"
  2562. " [--cpu_bind=...] [--mem_bind=...] [--reservation=name]\n"
  2563. " [--switches=max-switches{@max-time-to-wait}]\n"
  2564. " [--export[=names]] [--export-file=file|fd] executable [args...]\n");
  2565. }
  2566. static void _help(void)
  2567. {
  2568. slurm_ctl_conf_t *conf;
  2569. printf (
  2570. "Usage: sbatch [OPTIONS...] executable [args...]\n"
  2571. "\n"
  2572. "Parallel run options:\n"
  2573. " -A, --account=name charge job to specified account\n"
  2574. " --begin=time defer job until HH:MM MM/DD/YY\n"
  2575. " -c, --cpus-per-task=ncpus number of cpus required per task\n"
  2576. " --comment=name arbitrary comment\n"
  2577. " -d, --dependency=type:jobid defer job until condition on jobid is satisfied\n"
  2578. " -D, --workdir=directory set working directory for batch script\n"
  2579. " -e, --error=err file for batch script's standard error\n"
  2580. " --export[=names] specify environment variables to export\n"
  2581. " --export-file=file|fd specify environment variables file or file descriptor to export\n"
  2582. " --get-user-env load environment from local cluster\n"
  2583. " --gid=group_id group ID to run job as (user root only)\n"
  2584. " --gres=list required generic resources\n"
  2585. " -H, --hold submit job in held state\n"
  2586. " -i, --input=in file for batch script's standard input\n"
  2587. " -I, --immediate exit if resources are not immediately available\n"
  2588. " --jobid=id run under already allocated job\n"
  2589. " -J, --job-name=jobname name of job\n"
  2590. " -k, --no-kill do not kill job on node failure\n"
  2591. " -L, --licenses=names required license, comma separated\n"
  2592. " -m, --distribution=type distribution method for processes to nodes\n"
  2593. " (type = block|cyclic|arbitrary)\n"
  2594. " -M, --clusters=names Comma separated list of clusters to issue\n"
  2595. " commands to. Default is current cluster.\n"
  2596. " Name of 'all' will submit to run on all clusters.\n"
  2597. " --mail-type=type notify on state change: BEGIN, END, FAIL or ALL\n"
  2598. " --mail-user=user who to send email notification for job state\n"
  2599. " changes\n"
  2600. " -n, --ntasks=ntasks number of tasks to run\n"
  2601. " --nice[=value] decrease scheduling priority by value\n"
  2602. " --no-requeue if set, do not permit the job to be requeued\n"
  2603. " --ntasks-per-node=n number of tasks to invoke on each node\n"
  2604. " -N, --nodes=N number of nodes on which to run (N = min[-max])\n"
  2605. " -o, --output=out file for batch script's standard output\n"
  2606. " -O, --overcommit overcommit resources\n"
  2607. " -p, --partition=partition partition requested\n"
  2608. " --propagate[=rlimits] propagate all [or specific list of] rlimits\n"
  2609. " --qos=qos quality of service\n"
  2610. " -Q, --quiet quiet mode (suppress informational messages)\n"
  2611. " --requeue if set, permit the job to be requeued\n"
  2612. " -t, --time=minutes time limit\n"
  2613. " --time-min=minutes minimum time limit (if distinct)\n"
  2614. " -s, --share share nodes with other jobs\n"
  2615. " --uid=user_id user ID to run job as (user root only)\n"
  2616. " -v, --verbose verbose mode (multiple -v's increase verbosity)\n"
  2617. " --wrap[=command string] wrap commmand string in a sh script and submit\n"
  2618. " --switches=max-switches{@max-time-to-wait}\n"
  2619. " Optimum switches and max time to wait for optimum\n"
  2620. "\n"
  2621. "Constraint options:\n"
  2622. " --contiguous demand a contiguous range of nodes\n"
  2623. " -C, --constraint=list specify a list of constraints\n"
  2624. " -F, --nodefile=filename request a specific list of hosts\n"
  2625. " --mem=MB minimum amount of real memory\n"
  2626. " --mincpus=n minimum number of logical processors (threads) per node\n"
  2627. " --reservation=name allocate resources from named reservation\n"
  2628. " --tmp=MB minimum amount of temporary disk\n"
  2629. " -w, --nodelist=hosts... request a specific list of hosts\n"
  2630. " -x, --exclude=hosts... exclude a specific list of hosts\n"
  2631. "\n"
  2632. "Consumable resources related options:\n"
  2633. " --exclusive allocate nodes in exclusive mode when\n"
  2634. " cpu consumable resource is enabled\n"
  2635. " --mem-per-cpu=MB maximum amount of real memory per allocated\n"
  2636. " cpu required by the job.\n"
  2637. " --mem >= --mem-per-cpu if --mem is specified.\n"
  2638. "\n"
  2639. "Affinity/Multi-core options: (when the task/affinity plugin is enabled)\n"
  2640. " -B --extra-node-info=S[:C[:T]] Expands to:\n"
  2641. " --sockets-per-node=S number of sockets per node to allocate\n"
  2642. " --cores-per-socket=C number of cores per socket to allocate\n"
  2643. " --threads-per-core=T number of threads per core to allocate\n"
  2644. " each field can be 'min' or wildcard '*'\n"
  2645. " total cpus requested = (N x S x C x T)\n"
  2646. "\n"
  2647. " --ntasks-per-core=n number of tasks to invoke on each core\n"
  2648. " --ntasks-per-socket=n number of tasks to invoke on each socket\n");
  2649. conf = slurm_conf_lock();
  2650. if (conf->task_plugin != NULL
  2651. && strcasecmp(conf->task_plugin, "task/affinity") == 0) {
  2652. printf(
  2653. " --cpu_bind= Bind tasks to CPUs\n"
  2654. " (see \"--cpu_bind=help\" for options)\n"
  2655. " --hint= Bind tasks according to application hints\n"
  2656. " (see \"--hint=help\" for options)\n"
  2657. " --mem_bind= Bind memory to locality domains (ldom)\n"
  2658. " (see \"--mem_bind=help\" for options)\n");
  2659. }
  2660. slurm_conf_unlock();
  2661. spank_print_options(stdout, 6, 30);
  2662. printf("\n"
  2663. #ifdef HAVE_AIX /* AIX/Federation specific options */
  2664. "AIX related options:\n"
  2665. " --network=type communication protocol to be used\n"
  2666. "\n"
  2667. #endif
  2668. #ifdef HAVE_BG /* Blue gene specific options */
  2669. "Blue Gene related options:\n"
  2670. #ifdef HAVE_BG_L_P
  2671. " -g, --geometry=XxYxZ geometry constraints of the job\n"
  2672. #else
  2673. " -g, --geometry=AxXxYxZ Midplane geometry constraints of the job,\n"
  2674. " sub-block allocations can not be allocated\n"
  2675. " with the geometry option\n"
  2676. #endif
  2677. " -R, --no-rotate disable geometry rotation\n"
  2678. " --reboot reboot block before starting job\n"
  2679. " --conn-type=type constraint on type of connection, MESH or TORUS\n"
  2680. " if not set, then tries to fit TORUS else MESH\n"
  2681. #ifndef HAVE_BGL
  2682. " If wanting to run in HTC mode (only for 1\n"
  2683. " midplane and below). You can use HTC_S for\n"
  2684. " SMP, HTC_D for Dual, HTC_V for\n"
  2685. " virtual node mode, and HTC_L for Linux mode.\n"
  2686. " --cnload-image=path path to compute node image for bluegene block. Default if not set\n"
  2687. " --mloader-image=path path to mloader image for bluegene block. Default if not set\n"
  2688. " --ioload-image=path path to ioload image for bluegene block. Default if not set\n"
  2689. #else
  2690. " --blrts-image=path path to blrts image for bluegene block. Default\n"
  2691. " if not set\n"
  2692. " --linux-image=path path to linux image for bluegene block. Default\n"
  2693. " if not set\n"
  2694. " --mloader-image=path path to mloader image for bluegene block.\n"
  2695. " Default if not set\n"
  2696. " --ramdisk-image=path path to ramdisk image for bluegene block.\n"
  2697. " Default if not set\n"
  2698. #endif
  2699. #endif
  2700. "\n"
  2701. "Help options:\n"
  2702. " -h, --help show this help message\n"
  2703. " -u, --usage display brief usage message\n"
  2704. "\n"
  2705. "Other options:\n"
  2706. " -V, --version output version information and exit\n"
  2707. "\n"
  2708. );
  2709. }