blob: f15c626d7115b373243d1678cc2bc6437e742a0e [file] [log] [blame]
/*****************************************************************************\
* sshare.c - tool for listing the shares of association in
* relationship to the cluster running on.
*****************************************************************************
* Copyright (C) 2008 Lawrence Livermore National Security.
* Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
* Written by Danny Auble <da@llnl.gov>
* CODE-OCEC-09-009. All rights reserved.
*
* This file is part of Slurm, a resource management program.
* For details, see <https://slurm.schedmd.com/>.
* Please also read the included file: DISCLAIMER.
*
* Slurm is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by the Free
* Software Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* In addition, as a special exception, the copyright holders give permission
* to link the code of portions of this program with the OpenSSL library under
* certain conditions as described in each individual source file, and
* distribute linked combinations including the two. You must obey the GNU
* General Public License in all respects for all of the code used other than
* OpenSSL. If you modify file(s) with this exception, you may extend this
* exception to your version of the file(s), but you are not obligated to do
* so. If you do not wish to do so, delete this exception statement from your
* version. If you delete this exception statement from all source files in
* the program, then also delete it here.
*
* Slurm is distributed in the hope that it will be useful, but WITHOUT ANY
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along
* with Slurm; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
\*****************************************************************************/
#include <grp.h>
#include "src/common/data.h"
#include "src/common/proc_args.h"
#include "src/common/slurm_protocol_api.h"
#include "src/common/slurm_protocol_defs.h"
#include "src/common/uid.h"
#include "src/interfaces/data_parser.h"
#include "src/interfaces/priority.h"
#include "src/interfaces/serializer.h"
#include "src/sshare/sshare.h"
#define OPT_LONG_HELP 0x100
#define OPT_LONG_USAGE 0x101
#define OPT_LONG_AUTOCOMP 0x102
#define OPT_LONG_JSON 0x103
#define OPT_LONG_YAML 0x104
static int _addto_name_char_list(list_t *char_list, char *names, bool gid);
static int _single_cluster(int argc, char **argv,
shares_request_msg_t *req_msg);
static int _multi_cluster(int argc, char **argv, shares_request_msg_t *req_msg);
static char * _convert_to_name(uint32_t id, bool is_gid);
static void _print_version( void );
static void _usage(void);
static void _help_format_msg(void);
int exit_code; /* sshare's exit code, =1 on any error at any time */
int quiet_flag; /* quiet=1, verbose=-1, normal=0 */
int verbosity; /* count of -v options */
uint32_t my_uid = 0;
list_t *clusters = NULL;
uint16_t options = 0;
int main (int argc, char **argv)
{
int opt_char;
log_options_t opts = LOG_OPTS_STDERR_ONLY;
shares_request_msg_t req_msg;
char *temp = NULL;
int option_index;
bool all_users = 0;
static struct option long_options[] = {
{"autocomplete", required_argument, 0, OPT_LONG_AUTOCOMP},
{"accounts", 1, 0, 'A'},
{"all", 0, 0, 'a'},
{"helpformat",0,0, 'e'},
{"long", 0, 0, 'l'},
{"partition",0, 0, 'm'},
{"cluster", 1, 0, 'M'},
{"clusters", 1, 0, 'M'},
{"noheader", 0, 0, 'n'},
{"format", 1, 0, 'o'},
{"parsable", 0, 0, 'p'},
{"parsable2",0, 0, 'P'},
{"users", 1, 0, 'u'},
{"Users", 0, 0, 'U'},
{"verbose", 0, 0, 'v'},
{"version", 0, 0, 'V'},
{"help", 0, 0, OPT_LONG_HELP},
{"usage", 0, 0, OPT_LONG_USAGE},
{"json", optional_argument, 0, OPT_LONG_JSON},
{"yaml", optional_argument, 0, OPT_LONG_YAML},
{NULL, 0, 0, 0}
};
exit_code = 0;
long_flag = 0;
quiet_flag = 0;
verbosity = 0;
memset(&req_msg, 0, sizeof(shares_request_msg_t));
slurm_init(NULL);
if (priority_g_init() != SLURM_SUCCESS)
fatal("failed to initialize priority plugin");
log_init("sshare", opts, SYSLOG_FACILITY_DAEMON, NULL);
while ((opt_char = getopt_long(argc, argv, "aA:ehlM:no:pPqUu:t:vVm",
long_options, &option_index)) != -1) {
switch (opt_char) {
case (int)'?':
fprintf(stderr, "Try \"sshare --help\" "
"for more information\n");
exit(1);
break;
case 'a':
all_users = 1;
break;
case 'A':
if (!req_msg.acct_list)
req_msg.acct_list = list_create(xfree_ptr);
slurm_addto_char_list(req_msg.acct_list, optarg);
break;
case 'e':
_help_format_msg();
exit(0);
break;
case 'h':
print_fields_have_header = 0;
break;
case 'l':
long_flag = 1;
break;
case 'M':
FREE_NULL_LIST(clusters);
if (slurm_get_cluster_info(&(clusters), optarg, 0)) {
print_db_notok(optarg, 0);
fatal("Could not get cluster information");
}
working_cluster_rec = list_peek(clusters);
break;
case 'm':
options |= PRINT_PARTITIONS;
break;
case 'n':
print_fields_have_header = 0;
break;
case 'o':
xstrfmtcat(opt_field_list, "%s,", optarg);
break;
case 'p':
print_fields_parsable_print =
PRINT_FIELDS_PARSABLE_ENDING;
break;
case 'P':
print_fields_parsable_print =
PRINT_FIELDS_PARSABLE_NO_ENDING;
break;
case 'u':
if (!xstrcmp(optarg, "-1")) {
all_users = 1;
break;
}
all_users = 0;
if (!req_msg.user_list)
req_msg.user_list = list_create(xfree_ptr);
_addto_name_char_list(req_msg.user_list, optarg, 0);
break;
case 'U':
options |= PRINT_USERS_ONLY;
break;
case 'v':
quiet_flag = -1;
verbosity++;
break;
case 'V':
_print_version();
exit(exit_code);
break;
case OPT_LONG_HELP:
case OPT_LONG_USAGE:
_usage();
exit(0);
case OPT_LONG_AUTOCOMP:
suggest_completion(long_options, optarg);
exit(0);
break;
case OPT_LONG_JSON:
mimetype = MIME_TYPE_JSON;
data_parser = optarg;
serializer_required(MIME_TYPE_JSON);
break;
case OPT_LONG_YAML:
mimetype = MIME_TYPE_YAML;
data_parser = optarg;
serializer_required(MIME_TYPE_YAML);
break;
default:
exit_code = 1;
fprintf(stderr, "getopt error, returned %c\n",
opt_char);
exit(exit_code);
}
}
if (verbosity) {
opts.stderr_level += verbosity;
opts.prefix_level = 1;
log_alter(opts, 0, NULL);
}
if (all_users) {
if (req_msg.user_list
&& list_count(req_msg.user_list)) {
FREE_NULL_LIST(req_msg.user_list);
}
if (verbosity)
fprintf(stderr, "Users requested:\n\t: all\n");
} else if (verbosity && req_msg.user_list
&& list_count(req_msg.user_list)) {
fprintf(stderr, "Users requested:\n");
list_itr_t *itr = list_iterator_create(req_msg.user_list);
while ((temp = list_next(itr)))
fprintf(stderr, "\t: %s\n", temp);
list_iterator_destroy(itr);
} else if (!req_msg.user_list || !list_count(req_msg.user_list)) {
char *user = uid_to_string_or_null(getuid());
if (user) {
if (!req_msg.user_list) {
req_msg.user_list = list_create(xfree_ptr);
}
list_append(req_msg.user_list, user);
if (verbosity) {
fprintf(stderr, "Users requested:\n");
fprintf(stderr, "\t: %s\n", user);
}
}
}
if (verbosity && req_msg.acct_list && list_count(req_msg.acct_list)) {
list_itr_t *itr = list_iterator_create(req_msg.acct_list);
fprintf(stderr, "Accounts requested:\n");
while ((temp = list_next(itr)))
fprintf(stderr, "\t: %s\n", temp);
list_iterator_destroy(itr);
} else if (verbosity) {
fprintf(stderr, "Accounts requested:\n\t: all\n");
}
if (clusters)
exit_code = _multi_cluster(argc, argv, &req_msg);
else
exit_code = _single_cluster(argc, argv, &req_msg);
FREE_NULL_LIST(req_msg.acct_list);
FREE_NULL_LIST(req_msg.user_list);
exit(exit_code);
}
static int _single_cluster(int argc, char **argv, shares_request_msg_t *req_msg)
{
int rc = SLURM_SUCCESS;
shares_response_msg_t *resp_msg = NULL;
rc = slurm_associations_get_shares(req_msg, &resp_msg);
if (rc) {
slurm_perror("Couldn't get shares from controller");
return rc;
}
if (mimetype) {
DATA_DUMP_CLI_SINGLE(OPENAPI_SHARES_RESP, resp_msg, argc, argv,
NULL, mimetype, data_parser, rc);
} else {
process(resp_msg, options);
}
slurm_free_shares_response_msg(resp_msg);
return rc;
}
static int _multi_cluster(int argc, char **argv, shares_request_msg_t *req_msg)
{
list_itr_t *itr;
bool first = true;
int rc = 0, rc2;
itr = list_iterator_create(clusters);
while ((working_cluster_rec = list_next(itr))) {
if (first)
first = false;
else
printf("\n");
printf("CLUSTER: %s\n", working_cluster_rec->name);
rc2 = _single_cluster(argc, argv, req_msg);
if (rc2)
rc = 1;
}
list_iterator_destroy(itr);
return rc;
}
/* returns number of objects added to list */
static int _addto_name_char_list_internal(list_t *char_list, char *name,
void *x)
{
char *tmp_name = NULL;
bool gid = *(bool *)x;
if (isdigit(*name)) {
uint32_t id = strtoul(name, NULL, 10);
tmp_name = _convert_to_name(id, gid);
} else
tmp_name = xstrdup(name);
if (!list_find_first(char_list, slurm_find_char_in_list, tmp_name)) {
list_append(char_list, tmp_name);
return 1;
} else {
xfree(tmp_name);
return 0;
}
}
/* returns number of objects added to list */
static int _addto_name_char_list(list_t *char_list, char *names, bool gid)
{
if (!char_list) {
error("No list was given to fill in");
return 0;
}
return slurm_parse_char_list(char_list, names, &gid,
_addto_name_char_list_internal);
}
static char *_convert_to_name(uint32_t id, bool is_gid)
{
char *name = NULL;
if (is_gid) {
if (!(name = gid_to_string_or_null(id))) {
fprintf(stderr, "Invalid group id: %u\n", id);
exit(1);
}
} else {
if (!(name = uid_to_string_or_null(id))) {
fprintf(stderr, "Invalid user id: %u\n", id);
exit(1);
}
}
return name;
}
static void _print_version(void)
{
print_slurm_version();
if (quiet_flag == -1) {
long version = slurm_api_version();
printf("slurm_api_version: %ld, %ld.%ld.%ld\n", version,
SLURM_VERSION_MAJOR(version),
SLURM_VERSION_MINOR(version),
SLURM_VERSION_MICRO(version));
}
}
/* _usage - show the valid sshare options */
void _usage(void){
printf ("\
Usage: sshare [OPTION] \n\
Valid OPTIONs are: \n\
-a or --all list all users \n\
-A or --accounts= display specific accounts (comma separated list)\n\
-e or --helpformat Print a list of fields that can be specified \n\
with the '--format' option \n\
--json[=data_parser] Produce JSON output \n\
-l or --long include normalized usage in output \n\
-m or --partition print the partition part of the association \n\
-M or --cluster=names clusters to issue commands to. \n\
NOTE: SlurmDBD must be up. \n\
-n or --noheader omit header from output \n\
-o or --format= Comma separated list of fields (use \n\
\"--helpformat\" for a list of available fields).\n\
-p or --parsable '|' delimited output with a trailing '|' \n\
-P or --parsable2 '|' delimited output without a trailing '|' \n\
-u or --users= display specific users (comma separated list) \n\
-U or --Users display only user information \n\
-v or --verbose display more information \n\
-V or --version display tool version number \n\
--yaml[=data_parser] Produce YAML output \n\
--help display this usage description \n\
--usage display this usage description \n\
\n\n");
}
static void _help_format_msg(void)
{
int i;
for (i = 0; fields[i].name; i++) {
if (i & 3)
printf(" ");
else if (i)
printf("\n");
printf("%-17s", fields[i].name);
}
printf("\n");
return;
}