/****************************************************************************\ * opts.c - sinfo command line option processing functions ***************************************************************************** * Copyright (C) 2002-2007 The Regents of the University of California. * Copyright (C) 2008-2010 Lawrence Livermore National Security. * Portions Copyright (C) 2010-2017 SchedMD . * Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER). * Written by Joey Ekstrom , Morris Jette * CODE-OCEC-09-009. All rights reserved. * * This file is part of Slurm, a resource management program. * For details, see . * Please also read the included file: DISCLAIMER. * * Slurm is free software; you can redistribute it and/or modify it under * the terms of the GNU General Public License as published by the Free * Software Foundation; either version 2 of the License, or (at your option) * any later version. * * In addition, as a special exception, the copyright holders give permission * to link the code of portions of this program with the OpenSSL library under * certain conditions as described in each individual source file, and * distribute linked combinations including the two. You must obey the GNU * General Public License in all respects for all of the code used other than * OpenSSL. If you modify file(s) with this exception, you may extend this * exception to your version of the file(s), but you are not obligated to do * so. If you do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source files in * the program, then also delete it here. * * Slurm is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License along * with Slurm; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. \*****************************************************************************/ #define _GNU_SOURCE #include #include #include #include "slurm/slurmdb.h" #include "src/common/read_config.h" #include "src/common/xstring.h" #include "src/common/proc_args.h" #include "src/sinfo/print.h" #include "src/sinfo/sinfo.h" /* getopt_long options, integers but not characters */ #define OPT_LONG_HELP 0x100 #define OPT_LONG_USAGE 0x101 #define OPT_LONG_HIDE 0x102 #define OPT_LONG_LOCAL 0x103 #define OPT_LONG_NOCONVERT 0x104 #define OPT_LONG_FEDR 0x105 /* FUNCTIONS */ static List _build_state_list( char* str ); static List _build_all_states_list( void ); static List _build_part_list( char *parts ); static char *_get_prefix(char *token); static void _help( void ); static int _parse_format(char *); static int _parse_long_format(char *); static bool _node_state_equal(int state_id, const char *state_str); static int _node_state_id(char *str); static const char * _node_state_list(void); static void _parse_token(char *token, char *field, int *field_size, bool *right_justify, char **suffix); static void _parse_long_token(char *token, char *sep, int *field_size, bool *right_justify, char **suffix); static void _print_options(void); static void _usage(void); /* * parse_command_line, fill in params data structure with data */ extern void parse_command_line(int argc, char **argv) { char *env_val = NULL; int opt_char; int option_index; hostlist_t host_list; bool long_form = false; bool opt_a_set = false, opt_p_set = false; bool env_a_set = false, env_p_set = false; static struct option long_options[] = { {"all", no_argument, 0, 'a'}, {"dead", no_argument, 0, 'd'}, {"exact", no_argument, 0, 'e'}, {"federation",no_argument, 0, OPT_LONG_FEDR}, {"help", no_argument, 0, OPT_LONG_HELP}, {"hide", no_argument, 0, OPT_LONG_HIDE}, {"iterate", required_argument, 0, 'i'}, {"local", no_argument, 0, OPT_LONG_LOCAL}, {"long", no_argument, 0, 'l'}, {"cluster", required_argument, 0, 'M'}, {"clusters", required_argument, 0, 'M'}, {"nodes", required_argument, 0, 'n'}, {"noconvert", no_argument, 0, OPT_LONG_NOCONVERT}, {"noheader", no_argument, 0, 'h'}, {"Node", no_argument, 0, 'N'}, {"format", required_argument, 0, 'o'}, {"Format", required_argument, 0, 'O'}, {"partition", required_argument, 0, 'p'}, {"responding",no_argument, 0, 'r'}, {"list-reasons", no_argument, 0, 'R'}, {"summarize", no_argument, 0, 's'}, {"sort", required_argument, 0, 'S'}, {"states", required_argument, 0, 't'}, {"reservation",no_argument, 0, 'T'}, {"usage", no_argument, 0, OPT_LONG_USAGE}, {"verbose", no_argument, 0, 'v'}, {"version", no_argument, 0, 'V'}, {NULL, 0, 0, 0} }; params.convert_flags = CONVERT_NUM_UNIT_EXACT; if (slurmctld_conf.fed_params && strstr(slurmctld_conf.fed_params, "fed_display")) params.federation_flag = true; if (getenv("SINFO_ALL")) { env_a_set = true; params.all_flag = true; } if (getenv("SINFO_FEDERATION")) params.federation_flag = true; if (getenv("SINFO_LOCAL")) params.local = true; if ( ( env_val = getenv("SINFO_PARTITION") ) ) { env_p_set = true; params.partition = xstrdup(env_val); params.part_list = _build_part_list(env_val); params.all_flag = true; } if (env_a_set && env_p_set) { error("Conflicting options, SINFO_ALL and SINFO_PARTITION, specified. " "Please choose one or the other."); exit(1); } if ( ( env_val = getenv("SINFO_SORT") ) ) params.sort = xstrdup(env_val); if ( ( env_val = getenv("SLURM_CLUSTERS") ) ) { if (!(params.clusters = slurmdb_get_info_cluster(env_val))) { print_db_notok(env_val, 1); exit(1); } working_cluster_rec = list_peek(params.clusters); params.local = true; } while ((opt_char = getopt_long(argc, argv, "adehi:lM:n:No:O:p:rRsS:t:TvV", long_options, &option_index)) != -1) { switch (opt_char) { case (int)'?': fprintf(stderr, "Try \"sinfo --help\" for more information\n"); exit(1); break; case (int)'a': opt_a_set = true; xfree(params.partition); FREE_NULL_LIST(params.part_list); params.all_flag = true; break; case (int)'d': params.dead_nodes = true; break; case (int)'e': params.exact_match = true; break; case (int)'h': params.no_header = true; break; case (int) 'i': params.iterate= atoi(optarg); if (params.iterate <= 0) { error ("Error: invalid entry for " "--iterate=%s", optarg); exit(1); } break; case (int) 'l': params.long_output = true; break; case (int) 'M': FREE_NULL_LIST(params.clusters); if (!(params.clusters = slurmdb_get_info_cluster(optarg))) { print_db_notok(optarg, 0); exit(1); } working_cluster_rec = list_peek(params.clusters); params.local = true; break; case OPT_LONG_NOCONVERT: params.convert_flags |= CONVERT_NUM_UNIT_NO; break; case (int) 'n': xfree(params.nodes); params.nodes = xstrdup(optarg); /* * confirm valid nodelist entry */ host_list = hostlist_create(params.nodes); if (!host_list) { error("'%s' invalid entry for --nodes", optarg); exit(1); } if (hostlist_count(host_list) == 1) { params.node_name_single = true; xfree(params.nodes); params.nodes = hostlist_deranged_string_xmalloc(host_list); } else params.node_name_single = false; hostlist_destroy(host_list); break; case (int) 'N': params.node_flag = true; break; case (int) 'o': xfree(params.format); params.format = xstrdup(optarg); break; case (int) 'O': long_form = true; xfree(params.format); params.format = xstrdup(optarg); break; case (int) 'p': opt_p_set = true; xfree(params.partition); FREE_NULL_LIST(params.part_list); params.partition = xstrdup(optarg); params.part_list = _build_part_list(optarg); params.all_flag = true; break; case (int) 'r': params.responding_nodes = true; break; case (int) 'R': params.list_reasons = true; break; case (int) 's': params.summarize = true; break; case (int) 'S': xfree(params.sort); params.sort = xstrdup(optarg); break; case (int) 't': xfree(params.states); params.states = xstrdup(optarg); if (!(params.state_list = _build_state_list(optarg))) { error ("valid states: %s", _node_state_list ()); exit (1); } break; case (int) 'T': params.reservation_flag = true; break; case (int) 'v': params.verbose++; break; case (int) 'V': print_slurm_version (); exit(0); case (int) OPT_LONG_FEDR: params.federation_flag = true; break; case (int) OPT_LONG_HELP: _help(); exit(0); case (int) OPT_LONG_USAGE: _usage(); exit(0); case OPT_LONG_HIDE: params.all_flag = false; break; case OPT_LONG_LOCAL: params.local = true; break; } } if (params.long_output && params.format) fatal("Options -o(--format) and -l(--long) are mutually exclusive. Please remove one and retry."); if (opt_a_set && opt_p_set) { error("Conflicting options, -a and -p, specified. " "Please choose one or the other."); exit(1); } params.cluster_flags = slurmdb_setup_cluster_flags(); if (params.federation_flag && !params.clusters && !params.local) { void *ptr = NULL; char *cluster_name = slurm_get_cluster_name(); if (slurm_load_federation(&ptr) || !cluster_in_federation(ptr, cluster_name)) { /* Not in federation */ params.local = true; slurm_destroy_federation_rec(ptr); } else { params.fed = (slurmdb_federation_rec_t *) ptr; } xfree(cluster_name); } if ( params.format == NULL ) { params.def_format = true; if ( params.summarize ) { long_form = true; params.part_field_flag = true; /* compute size later */ params.format = "partition:9 ,available:.5 ,time:.10 ,nodeaiot:.16 ,nodelist:0"; } else if ( params.node_flag ) { long_form = true; params.node_field_flag = true; /* compute size later */ params.part_field_flag = true; /* compute size later */ params.format = params.long_output ? "nodelist:0 ,nodes:.6 ,partition:.9 ,statelong:.11 ,cpus:4 ,socketcorethread:.8 ,memory:.6 ,disk:.8 ,weight:.6 ,features:.8 ,reason:20" : "nodelist:0 ,nodes:.6 ,partition:.9 ,statecompact:6"; } else if (params.list_reasons) { long_form = true; params.format = params.long_output ? "reason:20 ,userlong:12 ,timestamp:19 ,statecompact:6 ,nodelist:0" : "reason:20 ,user:9 ,timestamp:19 ,nodelist:0"; } else if ((env_val = getenv ("SINFO_FORMAT"))) { params.format = xstrdup(env_val); } else if (params.fed) { long_form = true; params.part_field_flag = true; /* compute size later */ params.format = params.long_output ? "partition:9 ,cluster:8 ,available:.5 ,time:.10 ,size:.10 ,root:.4 ,oversubscribe:.8 ,groups:.10 ,nodes:.6 ,statelong:.11 ,nodelist:0" : "partition:9 ,cluster:8 ,available:.5 ,time:.10 ,nodes:.6 ,statecompact:.6 ,nodelist:0"; } else { long_form = true; params.part_field_flag = true; /* compute size later */ params.format = params.long_output ? "partition:9 ,available:.5 ,time:.10 ,size:.10 ,root:.4 ,oversubscribe:.8 ,groups:.10 ,nodes:.6 ,statelong:.11 ,nodelist:0" : "partition:9 ,available:.5 ,time:.10 ,nodes:.6 ,statecompact:.6 ,nodelist:0"; } } if (long_form) _parse_long_format(params.format); else _parse_format(params.format); if (params.list_reasons && (params.state_list == NULL)) { params.states = xstrdup("down,fail,drain"); if (!(params.state_list = _build_state_list (params.states))) fatal ("Unable to build state list for -R!"); } if (params.dead_nodes || params.nodes || params.partition || params.responding_nodes ||params.state_list) params.filtering = true; if (params.verbose) _print_options(); } static char * _next_tok (char *sep, char **str) { char *tok; /* push str past any leading separators */ while ((**str != '\0') && (strchr(sep, **str) != NULL)) (*str)++; if (**str == '\0') return NULL; /* assign token ptr */ tok = *str; /* push str past token and leave pointing to first separator */ while ((**str != '\0') && (strchr(sep, **str) == NULL)) (*str)++; /* nullify consecutive separators and push str beyond them */ while ((**str != '\0') && (strchr(sep, **str) != NULL)) *(*str)++ = '\0'; return (tok); } /* * _build_state_list - build a list of node states * IN str - comma separated list of job states * RET List of enum job_states values */ static List _build_state_list (char *state_str) { List state_ids; char *orig, *str, *state; if (state_str == NULL) return NULL; if (xstrcasecmp (state_str, "all") == 0 ) return _build_all_states_list (); orig = str = xstrdup (state_str); state_ids = list_create (NULL); while ((state = _next_tok (",", &str))) { int *id = xmalloc (sizeof (*id)); if ((*id = _node_state_id (state)) < 0) { error ("Bad state string: \"%s\"", state); return (NULL); } list_append (state_ids, id); } xfree (orig); return (state_ids); } /* * _build_all_states_list - build a list containing all possible node states * RET List of enum job_states values */ static List _build_all_states_list( void ) { List my_list; int i; uint16_t *state_id; my_list = list_create( NULL ); for (i = 0; i < NODE_STATE_END; i++) { state_id = xmalloc( sizeof( uint16_t ) ); *state_id = (uint16_t) i; list_append( my_list, state_id ); } state_id = xmalloc( sizeof( uint16_t ) ); *state_id = NODE_STATE_DRAIN; list_append( my_list, state_id ); state_id = xmalloc( sizeof( uint16_t ) ); *state_id = NODE_STATE_COMPLETING; list_append( my_list, state_id ); return my_list; } /* * _build_part_list - build a list of partition names * IN parts - comma separated list of partitions * RET List of partition names */ static List _build_part_list(char *parts) { List part_list; char *orig, *str, *part; orig = str = xstrdup(parts); part_list = list_create(NULL); while ((part = _next_tok (",", &str))) { char *tmp_part = xstrdup(part); list_append (part_list, tmp_part); } xfree(orig); return (part_list); } static const char * _node_state_list (void) { int i; static char *all_states = NULL; if (all_states) return (all_states); all_states = xstrdup (node_state_string(0)); for (i = 1; i < NODE_STATE_END; i++) { xstrcat (all_states, ","); xstrcat (all_states, node_state_string(i)); } xstrcat(all_states, ",DRAIN,DRAINED,DRAINING,NO_RESPOND,RESERVED,PERFCTRS"); xstrcat(all_states, ","); xstrcat(all_states, node_state_string(NODE_STATE_COMPLETING)); xstrcat(all_states, ","); xstrcat(all_states, node_state_string(NODE_STATE_POWERING_DOWN)); xstrcat(all_states, ","); xstrcat(all_states, node_state_string(NODE_STATE_POWER_SAVE)); xstrcat(all_states, ","); xstrcat(all_states, node_state_string(NODE_STATE_POWER_UP)); xstrcat(all_states, ","); xstrcat(all_states, node_state_string(NODE_STATE_FAIL)); xstrcat(all_states, ","); xstrcat(all_states, node_state_string(NODE_STATE_MAINT)); xstrcat(all_states, ","); xstrcat(all_states, node_state_string(NODE_STATE_REBOOT)); for (i = 0; i < strlen (all_states); i++) all_states[i] = tolower (all_states[i]); return (all_states); } static bool _node_state_equal (int i, const char *str) { int len = strlen (str); if ((xstrncasecmp(node_state_string_compact(i), str, len) == 0) || (xstrncasecmp(node_state_string(i), str, len) == 0)) return (true); return (false); } /* * _parse_state - convert node state name string to numeric value * IN str - state name * OUT states - node_state value corresponding to str * RET 0 or error code */ static int _node_state_id (char *str) { int i; int len = strlen (str); for (i = 0; i < NODE_STATE_END; i++) { if (_node_state_equal (i, str)) return (i); } if (xstrncasecmp("DRAIN", str, len) == 0) return NODE_STATE_DRAIN; if (xstrncasecmp("DRAINED", str, len) == 0) return NODE_STATE_DRAIN | NODE_STATE_IDLE; if ((xstrncasecmp("RESV", str, len) == 0) || (xstrncasecmp("RESERVED", str, len) == 0)) return NODE_STATE_RES; if ((xstrncasecmp("PERFCTRS", str, len) == 0) || (xstrncasecmp("NPC", str, len) == 0)) return NODE_STATE_NET; if ((xstrncasecmp("DRAINING", str, len) == 0) || (xstrncasecmp("DRNG", str, len) == 0)) return NODE_STATE_DRAIN | NODE_STATE_ALLOCATED; if (_node_state_equal (NODE_STATE_COMPLETING, str)) return NODE_STATE_COMPLETING; if (xstrncasecmp("NO_RESPOND", str, len) == 0) return NODE_STATE_NO_RESPOND; if (_node_state_equal (NODE_STATE_POWERING_DOWN, str)) return NODE_STATE_POWERING_DOWN; if (_node_state_equal (NODE_STATE_POWER_SAVE, str)) return NODE_STATE_POWER_SAVE; if (_node_state_equal (NODE_STATE_POWER_UP, str)) return NODE_STATE_POWER_UP; if (_node_state_equal (NODE_STATE_FAIL, str)) return NODE_STATE_FAIL; if (_node_state_equal (NODE_STATE_MAINT, str)) return NODE_STATE_MAINT; if (_node_state_equal (NODE_STATE_REBOOT, str)) return NODE_STATE_REBOOT; return (-1); } /* Take the user's format specification and use it to build build the * format specifications (internalize it to print.c data structures) */ static int _parse_format( char* format ) { int field_size; bool right_justify; char *prefix = NULL, *suffix = NULL, *token = NULL; char *tmp_char = NULL, *tmp_format = NULL; char field[1]; bool format_all = false; int i; if (format == NULL) { fprintf( stderr, "Format option lacks specification\n" ); exit( 1 ); } params.format_list = list_create( NULL ); if ((prefix = _get_prefix(format))) format_add_prefix( params.format_list, 0, 0, prefix); if (!xstrcasecmp(format, "%all")) { xstrfmtcat(tmp_format, "%c%c", '%', 'a'); for (i = 'b'; i <= 'z'; i++) xstrfmtcat(tmp_format, "|%c%c", '%', (char) i); for (i = 'A'; i <= 'Z'; i++) xstrfmtcat(tmp_format, "|%c%c ", '%', (char) i); format_all = true; } else { tmp_format = xstrdup(format); } token = strtok_r( tmp_format, "%", &tmp_char); if (token && (format[0] != '%')) /* toss header */ token = strtok_r( NULL, "%", &tmp_char ); while (token) { _parse_token( token, field, &field_size, &right_justify, &suffix); if (field[0] == 'a') { params.match_flags.avail_flag = true; format_add_avail( params.format_list, field_size, right_justify, suffix ); } else if (field[0] == 'A') { format_add_nodes_ai( params.format_list, field_size, right_justify, suffix ); } else if (field[0] == 'b') { params.match_flags.features_act_flag = true; format_add_features_act( params.format_list, field_size, right_justify, suffix ); } else if (field[0] == 'B') { params.match_flags.max_cpus_per_node_flag = true; format_add_max_cpus_per_node( params.format_list, field_size, right_justify, suffix ); } else if (field[0] == 'c') { params.match_flags.cpus_flag = true; format_add_cpus( params.format_list, field_size, right_justify, suffix ); } else if (field[0] == 'C') { params.match_flags.cpus_flag = true; format_add_cpus_aiot( params.format_list, field_size, right_justify, suffix ); } else if (field[0] == 'd') { params.match_flags.disk_flag = true; format_add_disk( params.format_list, field_size, right_justify, suffix ); } else if (field[0] == 'D') { format_add_nodes( params.format_list, field_size, right_justify, suffix ); } else if (field[0] == 'e') { params.match_flags.free_mem_flag = true; format_add_free_mem( params.format_list, field_size, right_justify, suffix ); } else if (field[0] == 'E') { params.match_flags.reason_flag = true; format_add_reason( params.format_list, field_size, right_justify, suffix ); } else if (field[0] == 'f') { params.match_flags.features_flag = true; format_add_features( params.format_list, field_size, right_justify, suffix ); } else if (field[0] == 'F') { format_add_nodes_aiot( params.format_list, field_size, right_justify, suffix ); } else if (field[0] == 'g') { params.match_flags.groups_flag = true; format_add_groups( params.format_list, field_size, right_justify, suffix ); } else if (field[0] == 'G') { params.match_flags.gres_flag = true; format_add_gres( params.format_list, field_size, right_justify, suffix ); } else if (field[0] == 'h') { params.match_flags.oversubscribe_flag = true; format_add_oversubscribe( params.format_list, field_size, right_justify, suffix ); } else if (field[0] == 'H') { params.match_flags.reason_timestamp_flag = true; format_add_timestamp( params.format_list, field_size, right_justify, suffix ); } else if (field[0] == 'I') { params.match_flags.priority_job_factor_flag = true; format_add_priority_job_factor(params.format_list, field_size, right_justify, suffix); } else if (field[0] == 'l') { params.match_flags.max_time_flag = true; format_add_time( params.format_list, field_size, right_justify, suffix ); } else if (field[0] == 'L') { params.match_flags.default_time_flag = true; format_add_default_time( params.format_list, field_size, right_justify, suffix ); } else if (field[0] == 'm') { params.match_flags.memory_flag = true; format_add_memory( params.format_list, field_size, right_justify, suffix ); } else if (field[0] == 'M') { params.match_flags.preempt_mode_flag = true; format_add_preempt_mode( params.format_list, field_size, right_justify, suffix ); } else if (field[0] == 'n') { params.match_flags.hostnames_flag = true; format_add_node_hostnames( params.format_list, field_size, right_justify, suffix ); } else if (field[0] == 'N') { format_add_node_list( params.format_list, field_size, right_justify, suffix ); } else if (field[0] == 'o') { params.match_flags.node_addr_flag = true; format_add_node_address( params.format_list, field_size, right_justify, suffix ); } else if (field[0] == 'O') { params.match_flags.cpu_load_flag = true; format_add_cpu_load( params.format_list, field_size, right_justify, suffix ); } else if (field[0] == 'p') { params.match_flags.priority_tier_flag = true; format_add_priority_tier(params.format_list, field_size, right_justify, suffix); } else if (field[0] == 'P') { params.match_flags.partition_flag = true; format_add_partition( params.format_list, field_size, right_justify, suffix ); } else if (field[0] == 'r') { params.match_flags.root_flag = true; format_add_root( params.format_list, field_size, right_justify, suffix ); } else if (field[0] == 'R') { params.match_flags.partition_flag = true; format_add_partition_name( params.format_list, field_size, right_justify, suffix ); } else if (field[0] == 's') { params.match_flags.job_size_flag = true; format_add_size( params.format_list, field_size, right_justify, suffix ); } else if (field[0] == 'S') { format_add_alloc_nodes( params.format_list, field_size, right_justify, suffix ); } else if (field[0] == 't') { params.match_flags.state_flag = true; format_add_state_compact( params.format_list, field_size, right_justify, suffix ); } else if (field[0] == 'T') { params.match_flags.state_flag = true; format_add_state_long( params.format_list, field_size, right_justify, suffix ); } else if (field[0] == 'u') { params.match_flags.reason_user_flag = true; format_add_user( params.format_list, field_size, right_justify, suffix ); } else if (field[0] == 'U') { params.match_flags.reason_user_flag = true; format_add_user_long( params.format_list, field_size, right_justify, suffix ); } else if (field[0] == 'v') { params.match_flags.version_flag = true; format_add_version( params.format_list, field_size, right_justify, suffix); } else if (field[0] == 'V') { format_add_cluster_name(params.format_list, field_size, right_justify, suffix); } else if (field[0] == 'w') { params.match_flags.weight_flag = true; format_add_weight( params.format_list, field_size, right_justify, suffix ); } else if (field[0] == 'X') { params.match_flags.sockets_flag = true; format_add_sockets( params.format_list, field_size, right_justify, suffix ); } else if (field[0] == 'Y') { params.match_flags.cores_flag = true; format_add_cores( params.format_list, field_size, right_justify, suffix ); } else if (field[0] == 'Z') { params.match_flags.threads_flag = true; format_add_threads( params.format_list, field_size, right_justify, suffix ); } else if (field[0] == 'z') { params.match_flags.sct_flag = true; format_add_sct( params.format_list, field_size, right_justify, suffix ); } else if (format_all) { xfree(suffix); /* ignore */ } else { prefix = xstrdup("%"); xstrcat(prefix, token); xfree(suffix); suffix = prefix; format_add_invalid( params.format_list, field_size, right_justify, suffix ); fprintf(stderr, "Invalid node format specification: %c\n", field[0] ); } token = strtok_r( NULL, "%", &tmp_char); } xfree( tmp_format ); return SLURM_SUCCESS; } static int _parse_long_format (char* format_long) { int field_size; bool right_justify, format_all = false; char *tmp_format = NULL, *token = NULL, *str_tmp = NULL; char *sep = NULL; char* suffix = NULL; if (format_long == NULL) { error("Format long option lacks specification"); exit( 1 ); } params.format_list = list_create(NULL); tmp_format = xstrdup(format_long); token = strtok_r(tmp_format, ",",&str_tmp); while (token) { _parse_long_token( token, sep, &field_size, &right_justify, &suffix); if (!xstrcasecmp(token, "all")) { _parse_format ("%all"); } else if (!xstrcasecmp(token, "allocmem")) { params.match_flags.alloc_mem_flag = true; format_add_alloc_mem( params.format_list, field_size, right_justify, suffix ); } else if (!xstrcasecmp(token, "allocnodes")) { format_add_alloc_nodes( params.format_list, field_size, right_justify, suffix ); } else if (!xstrcasecmp(token, "available")) { params.match_flags.avail_flag = true; format_add_avail( params.format_list, field_size, right_justify, suffix ); } else if (!xstrcasecmp(token, "cluster")) { format_add_cluster_name(params.format_list, field_size, right_justify, suffix); } else if (!xstrcasecmp(token, "cpus")) { params.match_flags.cpus_flag = true; format_add_cpus( params.format_list, field_size, right_justify, suffix ); } else if (!xstrcasecmp(token, "cpusload")) { params.match_flags.cpu_load_flag = true; format_add_cpu_load( params.format_list, field_size, right_justify, suffix ); } else if (!xstrcasecmp(token, "freemem")) { params.match_flags.free_mem_flag = true; format_add_free_mem( params.format_list, field_size, right_justify, suffix ); } else if (!xstrcasecmp(token, "cpusstate")) { params.match_flags.cpus_flag = true; format_add_cpus_aiot( params.format_list, field_size, right_justify, suffix ); } else if (!xstrcasecmp(token, "cores")) { params.match_flags.cores_flag = true; format_add_cores( params.format_list, field_size, right_justify, suffix ); } else if (!xstrcasecmp(token, "defaulttime")) { params.match_flags.default_time_flag = true; format_add_default_time( params.format_list, field_size, right_justify, suffix ); } else if (!xstrcasecmp(token, "disk")) { params.match_flags.disk_flag = true; format_add_disk( params.format_list, field_size, right_justify, suffix ); } else if (!xstrcasecmp(token, "features")) { params.match_flags.features_flag = true; format_add_features( params.format_list, field_size, right_justify, suffix ); } else if (!xstrcasecmp(token, "features_act")) { params.match_flags.features_act_flag = true; format_add_features_act( params.format_list, field_size, right_justify, suffix ); } else if (!xstrcasecmp(token, "groups")) { params.match_flags.groups_flag = true; format_add_groups( params.format_list, field_size, right_justify, suffix ); } else if (!xstrcasecmp(token, "gres")) { params.match_flags.gres_flag = true; format_add_gres( params.format_list, field_size, right_justify, suffix ); } else if (!xstrcasecmp(token, "gresused")) { params.match_flags.gres_used_flag = true; format_add_gres_used( params.format_list, field_size, right_justify, suffix ); } else if (!xstrcasecmp(token, "maxcpuspernode")) { params.match_flags.max_cpus_per_node_flag = true; format_add_max_cpus_per_node( params.format_list, field_size, right_justify, suffix ); } else if (!xstrcasecmp(token, "memory")) { params.match_flags.memory_flag = true; format_add_memory( params.format_list, field_size, right_justify, suffix ); } else if (!xstrcasecmp(token, "nodes")) { format_add_nodes( params.format_list, field_size, right_justify, suffix ); } else if (!xstrcasecmp(token, "nodeaddr")) { params.match_flags.node_addr_flag = true; format_add_node_address( params.format_list, field_size, right_justify, suffix ); } else if (!xstrcasecmp(token, "nodeai")) { format_add_nodes_ai( params.format_list, field_size, right_justify, suffix ); } else if (!xstrcasecmp(token, "nodeaiot")) { format_add_nodes_aiot( params.format_list, field_size, right_justify, suffix ); } else if (!xstrcasecmp(token, "nodehost")) { params.match_flags.hostnames_flag = true; format_add_node_hostnames( params.format_list, field_size, right_justify, suffix ); } else if (!xstrcasecmp(token, "nodelist")) { format_add_node_list( params.format_list, field_size, right_justify, suffix ); } else if (!xstrcasecmp(token, "partition")) { params.match_flags.partition_flag = true; format_add_partition( params.format_list, field_size, right_justify, suffix ); } else if (!xstrcasecmp(token, "partitionname")) { params.match_flags.partition_flag = true; format_add_partition_name( params.format_list, field_size, right_justify, suffix ); } else if (!xstrcasecmp(token, "port")) { params.match_flags.port_flag = true; format_add_port( params.format_list, field_size, right_justify, suffix ); } else if (!xstrcasecmp(token, "preemptmode")) { params.match_flags.preempt_mode_flag = true; format_add_preempt_mode( params.format_list, field_size, right_justify, suffix ); } else if (!xstrcasecmp(token, "priorityjobfactor")) { params.match_flags.priority_job_factor_flag = true; format_add_priority_job_factor(params.format_list, field_size, right_justify, suffix ); } else if (!xstrcasecmp(token, "prioritytier")) { params.match_flags.priority_tier_flag = true; format_add_priority_tier(params.format_list, field_size, right_justify, suffix ); } else if (!xstrcasecmp(token, "reason")) { params.match_flags.reason_flag = true; format_add_reason( params.format_list, field_size, right_justify, suffix ); } else if (!xstrcasecmp(token, "root")) { params.match_flags.root_flag = true; format_add_root( params.format_list, field_size, right_justify, suffix ); } else if (!xstrcasecmp(token, "oversubscribe") || !xstrcasecmp(token, "share")) { params.match_flags.oversubscribe_flag = true; format_add_oversubscribe( params.format_list, field_size, right_justify, suffix ); } else if (!xstrcasecmp(token, "size")) { params.match_flags.job_size_flag = true; format_add_size( params.format_list, field_size, right_justify, suffix ); } else if (!xstrcasecmp(token, "statecompact")) { params.match_flags.state_flag = true; format_add_state_compact( params.format_list, field_size, right_justify, suffix ); } else if (!xstrcasecmp(token, "statelong")) { params.match_flags.state_flag = true; format_add_state_long( params.format_list, field_size, right_justify, suffix ); } else if (!xstrcasecmp(token, "sockets")) { params.match_flags.sockets_flag = true; format_add_sockets( params.format_list, field_size, right_justify, suffix ); } else if (!xstrcasecmp(token, "socketcorethread")) { params.match_flags.sct_flag = true; format_add_sct( params.format_list, field_size, right_justify, suffix ); } else if (!xstrcasecmp(token, "time")) { params.match_flags.max_time_flag = true; format_add_time( params.format_list, field_size, right_justify, suffix ); } else if (!xstrcasecmp(token, "timestamp")) { params.match_flags.reason_timestamp_flag = true; format_add_timestamp( params.format_list, field_size, right_justify, suffix ); } else if (!xstrcasecmp(token, "threads")) { params.match_flags.threads_flag = true; format_add_threads( params.format_list, field_size, right_justify, suffix ); } else if (!xstrcasecmp(token, "user")) { params.match_flags.reason_user_flag = true; format_add_user( params.format_list, field_size, right_justify, suffix ); } else if (!xstrcasecmp(token, "userlong")) { params.match_flags.reason_user_flag = true; format_add_user_long( params.format_list, field_size, right_justify, suffix ); } else if (!xstrcasecmp(token, "version")) { params.match_flags.version_flag = true; format_add_version( params.format_list, field_size, right_justify, suffix); } else if (!xstrcasecmp(token, "weight")) { params.match_flags.weight_flag = true; format_add_weight( params.format_list, field_size, right_justify, suffix ); } else if (format_all) { /* ignore */ } else { format_add_invalid( params.format_list, field_size, right_justify, suffix ); error( "Invalid job format specification: %s", token ); } token = strtok_r(NULL, ",", &str_tmp); } xfree(tmp_format); return SLURM_SUCCESS; } /* Take a format specification and copy out it's prefix * IN/OUT token - input specification, everything before "%" is removed * RET - everything before "%" in the token */ static char * _get_prefix( char *token ) { char *pos, *prefix; if (token == NULL) return NULL; pos = strchr(token, (int) '%'); if (pos == NULL) /* everything is prefix */ return xstrdup(token); if (pos == token) /* no prefix */ return NULL; pos[0] = '\0'; /* some prefix */ prefix = xstrdup(token); pos[0] = '%'; memmove(token, pos, (strlen(pos)+1)); return prefix; } /* Take a format specification and break it into its components * IN token - input specification without leading "%", eg. ".5u" * OUT field - the letter code for the data type * OUT field_size - byte count * OUT right_justify - true of field to be right justified * OUT suffix - string containing everthing after the field specification */ static void _parse_token( char *token, char *field, int *field_size, bool *right_justify, char **suffix) { int i = 0; assert (token != NULL); if (token[i] == '.') { *right_justify = true; i++; } else *right_justify = false; *field_size = 0; while ((token[i] >= '0') && (token[i] <= '9')) *field_size = (*field_size * 10) + (token[i++] - '0'); field[0] = token[i++]; *suffix = xstrdup(&token[i]); } static void _parse_long_token( char *token, char *sep, int *field_size, bool *right_justify, char **suffix) { char *end_ptr = NULL, *ptr; xassert(token); ptr = strchr(token, ':'); if (ptr) { ptr[0] = '\0'; if (ptr[1] == '.') { *right_justify = true; ptr++; } else { *right_justify = false; } *field_size = strtol(ptr + 1, &end_ptr, 10); if (end_ptr[0] != '\0') *suffix = xstrdup(end_ptr); } else { *right_justify = false; *field_size = 20; } } /* print the parameters specified */ void _print_options( void ) { printf("-----------------------------\n"); printf("dead = %s\n", params.dead_nodes ? "true" : "false"); printf("exact = %d\n", params.exact_match); printf("filtering = %s\n", params.filtering ? "true" : "false"); printf("format = %s\n", params.format); printf("iterate = %d\n", params.iterate ); printf("long = %s\n", params.long_output ? "true" : "false"); printf("no_header = %s\n", params.no_header ? "true" : "false"); printf("node_field = %s\n", params.node_field_flag ? "true" : "false"); printf("node_format = %s\n", params.node_flag ? "true" : "false"); printf("nodes = %s\n", params.nodes ? params.nodes : "n/a"); printf("part_field = %s\n", params.part_field_flag ? "true" : "false"); printf("partition = %s\n", params.partition ? params.partition: "n/a"); printf("responding = %s\n", params.responding_nodes ? "true" : "false"); printf("states = %s\n", params.states); printf("sort = %s\n", params.sort); printf("summarize = %s\n", params.summarize ? "true" : "false"); printf("verbose = %d\n", params.verbose); printf("-----------------------------\n"); printf("all_flag = %s\n", params.all_flag ? "true" : "false"); printf("alloc_mem_flag = %s\n", params.match_flags.alloc_mem_flag ? "true" : "false"); printf("avail_flag = %s\n", params.match_flags.avail_flag ? "true" : "false"); printf("cpus_flag = %s\n", params.match_flags.cpus_flag ? "true" : "false"); printf("default_time_flag =%s\n", params.match_flags.default_time_flag ? "true" : "false"); printf("disk_flag = %s\n", params.match_flags.disk_flag ? "true" : "false"); printf("features_flag = %s\n", params.match_flags.features_flag ? "true" : "false"); printf("features_flag_act = %s\n", params.match_flags.features_act_flag? "true" : "false"); printf("groups_flag = %s\n", params.match_flags.groups_flag ? "true" : "false"); printf("gres_flag = %s\n", params.match_flags.gres_flag ? "true" : "false"); printf("gres_used_flag = %s\n", params.match_flags.gres_used_flag ? "true" : "false"); printf("job_size_flag = %s\n", params.match_flags.job_size_flag ? "true" : "false"); printf("max_time_flag = %s\n", params.match_flags.max_time_flag ? "true" : "false"); printf("memory_flag = %s\n", params.match_flags.memory_flag ? "true" : "false"); printf("partition_flag = %s\n", params.match_flags.partition_flag ? "true" : "false"); printf("port_flag = %s\n", params.match_flags.port_flag ? "true" : "false"); printf("priority_job_factor_flag = %s\n", params.match_flags.priority_job_factor_flag ? "true" : "false"); printf("priority_tier_flag = %s\n", params.match_flags.priority_tier_flag ? "true" : "false"); printf("reason_flag = %s\n", params.match_flags.reason_flag ? "true" : "false"); printf("reason_timestamp_flag = %s\n", params.match_flags.reason_timestamp_flag ? "true" : "false"); printf("reason_user_flag = %s\n", params.match_flags.reason_user_flag ? "true" : "false"); printf("reservation_flag = %s\n", params.reservation_flag ? "true" : "false"); printf("root_flag = %s\n", params.match_flags.root_flag ? "true" : "false"); printf("oversubscribe_flag = %s\n", params.match_flags.oversubscribe_flag ? "true" : "false"); printf("state_flag = %s\n", params.match_flags.state_flag ? "true" : "false"); printf("weight_flag = %s\n", params.match_flags.weight_flag ? "true" : "false"); printf("-----------------------------\n\n"); } static void _usage( void ) { printf("\ Usage: sinfo [-abdelNRrsTv] [-i seconds] [-t states] [-p partition] [-n nodes]\n\ [-S fields] [-o format] [-O Format] [--federation] [--local]\n"); } static void _help( void ) { printf ("\ Usage: sinfo [OPTIONS]\n\ -a, --all show all partitions (including hidden and those\n\ not accessible)\n\ -d, --dead show only non-responding nodes\n\ -e, --exact group nodes only on exact match of configuration\n\ --federation Report federated information if a member of one\n\ -h, --noheader no headers on output\n\ --hide do not show hidden or non-accessible partitions\n\ -i, --iterate=seconds specify an iteration period\n\ --local show only local cluster in a federation.\n\ Overrides --federation.\n\ -l, --long long output - displays more information\n\ -M, --clusters=names clusters to issue commands to. Implies --local.\n\ NOTE: SlurmDBD must be up.\n\ -n, --nodes=NODES report on specific node(s)\n\ --noconvert don't convert units from their original type\n\ (e.g. 2048M won't be converted to 2G).\n\ -N, --Node Node-centric format\n\ -o, --format=format format specification\n\ -O, --Format=format long format specification\n\ -p, --partition=PARTITION report on specific partition\n\ -r, --responding report only responding nodes\n\ -R, --list-reasons list reason nodes are down or drained\n\ -s, --summarize report state summary only\n\ -S, --sort=fields comma separated list of fields to sort on\n\ -t, --states=node_state specify the what states of nodes to view\n\ -T, --reservation show only reservation information\n\ -v, --verbose verbosity level\n\ -V, --version output version information and exit\n\ \nHelp options:\n\ --help show this help message\n\ --usage display brief usage message\n"); }