PageRenderTime 59ms CodeModel.GetById 19ms 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

Large files files are truncated, but you can click here to view the full file

  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);

Large files files are truncated, but you can click here to view the full file