void parse_command_line(int argc, char **argv) { extern int optind; int c, i, optionIndex = 0; char *end = NULL, *start = NULL, *acct_type = NULL; slurmdb_selected_step_t *selected_step = NULL; ListIterator itr = NULL; struct stat stat_buf; char *dot = NULL; bool brief_output = FALSE, long_output = FALSE; bool all_users = 0; bool all_clusters = 0; slurmdb_job_cond_t *job_cond = params.job_cond; log_options_t opts = LOG_OPTS_STDERR_ONLY ; int verbosity; /* count of -v options */ bool set; static struct option long_options[] = { {"allusers", no_argument, 0, 'a'}, {"accounts", required_argument, 0, 'A'}, {"allocations", no_argument, ¶ms.opt_allocs, OPT_LONG_ALLOCS}, {"brief", no_argument, 0, 'b'}, {"completion", no_argument, ¶ms.opt_completion, 'c'}, {"duplicates", no_argument, ¶ms.opt_dup, OPT_LONG_DUP}, {"helpformat", no_argument, 0, 'e'}, {"help-fields", no_argument, 0, 'e'}, {"endtime", required_argument, 0, 'E'}, {"file", required_argument, 0, 'f'}, {"gid", required_argument, 0, 'g'}, {"group", required_argument, 0, 'g'}, {"help", no_argument, 0, 'h'}, {"helpformat", no_argument, ¶ms.opt_help, OPT_LONG_HELP}, {"name", required_argument, 0, OPT_LONG_NAME}, {"nnodes", required_argument, 0, 'i'}, {"ncpus", required_argument, 0, 'I'}, {"jobs", required_argument, 0, 'j'}, {"timelimit-min", required_argument, 0, 'k'}, {"timelimit-max", required_argument, 0, 'K'}, {"long", no_argument, 0, 'l'}, {"allclusters", no_argument, 0, 'L'}, {"cluster", required_argument, 0, 'M'}, {"clusters", required_argument, 0, 'M'}, {"nodelist", required_argument, 0, 'N'}, {"noheader", no_argument, 0, 'n'}, {"fields", required_argument, 0, 'o'}, {"format", required_argument, 0, 'o'}, {"parsable", no_argument, 0, 'p'}, {"parsable2", no_argument, 0, 'P'}, {"qos", required_argument, 0, 'q'}, {"partition", required_argument, 0, 'r'}, {"state", required_argument, 0, 's'}, {"starttime", required_argument, 0, 'S'}, {"truncate", no_argument, 0, 'T'}, {"uid", required_argument, 0, 'u'}, {"usage", no_argument, ¶ms.opt_help, OPT_LONG_USAGE}, {"user", required_argument, 0, 'u'}, {"verbose", no_argument, 0, 'v'}, {"version", no_argument, 0, 'V'}, {"wckeys", required_argument, 0, 'W'}, {"associations", required_argument, 0, 'x'}, {0, 0, 0, 0}}; params.opt_uid = getuid(); params.opt_gid = getgid(); verbosity = 0; log_init("sacct", opts, SYSLOG_FACILITY_DAEMON, NULL); opterr = 1; /* Let getopt report problems to the user */ while (1) { /* now cycle through the command line */ c = getopt_long(argc, argv, "aA:bcC:dDeE:f:g:hi:I:j:k:K:lLM:nN:o:OpPq:r:s:S:Ttu:vVW:x:X", long_options, &optionIndex); if (c == -1) break; switch (c) { case 'a': all_users = 1; break; case 'A': if(!job_cond->acct_list) job_cond->acct_list = list_create(slurm_destroy_char); slurm_addto_char_list(job_cond->acct_list, optarg); break; case 'b': brief_output = true; break; case 'c': params.opt_completion = 1; break; case 'C': /* 'C' is deprecated since 'M' is cluster on everything else. */ case 'M': if(!strcasecmp(optarg, "-1")) { all_clusters = 1; break; } all_clusters=0; if(!job_cond->cluster_list) job_cond->cluster_list = list_create(slurm_destroy_char); slurm_addto_char_list(job_cond->cluster_list, optarg); break; case 'D': params.opt_dup = 1; break; case 'e': params.opt_help = 2; break; case 'E': job_cond->usage_end = parse_time(optarg, 1); if (errno == ESLURM_INVALID_TIME_VALUE) exit(1); break; case 'f': xfree(params.opt_filein); params.opt_filein = xstrdup(optarg); break; case 'g': if(!job_cond->groupid_list) job_cond->groupid_list = list_create(slurm_destroy_char); _addto_id_char_list(job_cond->groupid_list, optarg, 1); break; case 'h': params.opt_help = 1; break; case 'i': set = get_resource_arg_range( optarg, "requested node range", (int *)&job_cond->nodes_min, (int *)&job_cond->nodes_max, true); if (set == false) { error("invalid node range -i '%s'", optarg); exit(1); } break; case 'I': set = get_resource_arg_range( optarg, "requested cpu range", (int *)&job_cond->cpus_min, (int *)&job_cond->cpus_max, true); if (set == false) { error("invalid cpu range -i '%s'", optarg); exit(1); } break; case 'j': if ((strspn(optarg, "0123456789, ") < strlen(optarg)) && (strspn(optarg, ".batch0123456789, ") < strlen(optarg))) { fprintf(stderr, "Invalid jobs list: %s\n", optarg); exit(1); } if(!job_cond->step_list) job_cond->step_list = list_create( slurmdb_destroy_selected_step); _addto_step_list(job_cond->step_list, optarg); break; case 'k': job_cond->timelimit_min = time_str2mins(optarg); if (((int32_t)job_cond->timelimit_min <= 0) && (job_cond->timelimit_min != INFINITE)) fatal("Invalid time limit specification"); break; case 'K': job_cond->timelimit_max = time_str2mins(optarg); if (((int32_t)job_cond->timelimit_max <= 0) && (job_cond->timelimit_max != INFINITE)) fatal("Invalid time limit specification"); break; case 'L': all_clusters = 1; break; case 'l': long_output = true; break; case 'n': print_fields_have_header = 0; break; case 'N': if(job_cond->used_nodes) { error("Aleady asked for nodes '%s'", job_cond->used_nodes); break; } job_cond->used_nodes = xstrdup(optarg); break; case OPT_LONG_NAME: if(!job_cond->jobname_list) job_cond->jobname_list = list_create(slurm_destroy_char); slurm_addto_char_list(job_cond->jobname_list, optarg); break; case 'o': xstrfmtcat(params.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 'q': if (!g_qos_list) { slurmdb_qos_cond_t qos_cond; memset(&qos_cond, 0, sizeof(slurmdb_qos_cond_t)); qos_cond.with_deleted = 1; g_qos_list = slurmdb_qos_get( acct_db_conn, &qos_cond); } if(!job_cond->qos_list) job_cond->qos_list = list_create(slurm_destroy_char); if(!slurmdb_addto_qos_char_list(job_cond->qos_list, g_qos_list, optarg, 0)) fatal("problem processing qos list"); break; case 'r': if(!job_cond->partition_list) job_cond->partition_list = list_create(slurm_destroy_char); slurm_addto_char_list(job_cond->partition_list, optarg); break; case 's': if(!job_cond->state_list) job_cond->state_list = list_create(slurm_destroy_char); _addto_state_char_list(job_cond->state_list, optarg); break; case 'S': job_cond->usage_start = parse_time(optarg, 1); if (errno == ESLURM_INVALID_TIME_VALUE) exit(1); break; case 'T': job_cond->without_usage_truncation = 0; break; case 'U': params.opt_help = 3; break; case 'u': if(!strcmp(optarg, "-1")) { all_users = 1; break; } all_users = 0; if(!job_cond->userid_list) job_cond->userid_list = list_create(slurm_destroy_char); _addto_id_char_list(job_cond->userid_list, optarg, 0); break; case 'v': /* Handle -vvv thusly... */ verbosity++; break; case 'W': if(!job_cond->wckey_list) job_cond->wckey_list = list_create(slurm_destroy_char); slurm_addto_char_list(job_cond->wckey_list, optarg); break; case 'V': print_slurm_version(); exit(0); case 'x': if(!job_cond->associd_list) job_cond->associd_list = list_create(slurm_destroy_char); slurm_addto_char_list(job_cond->associd_list, optarg); break; case 't': case 'X': params.opt_allocs = 1; break; case ':': case '?': /* getopt() has explained it */ exit(1); } } if (verbosity) { opts.stderr_level += verbosity; opts.prefix_level = 1; log_alter(opts, 0, NULL); } /* Now set params.opt_dup, unless they've already done so */ if (params.opt_dup < 0) /* not already set explicitly */ params.opt_dup = 0; job_cond->duplicates = params.opt_dup; job_cond->without_steps = params.opt_allocs; if(!job_cond->usage_start && !job_cond->step_list) { struct tm start_tm; job_cond->usage_start = time(NULL); if (!localtime_r(&job_cond->usage_start, &start_tm)) { error("Couldn't get localtime from %ld", (long)job_cond->usage_start); return; } start_tm.tm_sec = 0; start_tm.tm_min = 0; start_tm.tm_hour = 0; start_tm.tm_isdst = -1; job_cond->usage_start = mktime(&start_tm); } if(verbosity > 0) { char *start_char =NULL, *end_char = NULL; start_char = xstrdup(ctime(&job_cond->usage_start)); /* remove the new line */ start_char[strlen(start_char)-1] = '\0'; if(job_cond->usage_end) { end_char = xstrdup(ctime(&job_cond->usage_end)); /* remove the new line */ end_char[strlen(end_char)-1] = '\0'; } else end_char = xstrdup("Now"); info("Jobs eligible from %s - %s", start_char, end_char); xfree(start_char); xfree(end_char); } debug("Options selected:\n" "\topt_completion=%d\n" "\topt_dup=%d\n" "\topt_field_list=%s\n" "\topt_help=%d\n" "\topt_allocs=%d", params.opt_completion, params.opt_dup, params.opt_field_list, params.opt_help, params.opt_allocs); if(params.opt_completion) { g_slurm_jobcomp_init(params.opt_filein); acct_type = slurm_get_jobcomp_type(); if ((strcmp(acct_type, "jobcomp/none") == 0) && (stat(params.opt_filein, &stat_buf) != 0)) { fprintf(stderr, "SLURM job completion is disabled\n"); exit(1); } xfree(acct_type); } else { slurm_acct_storage_init(params.opt_filein); acct_type = slurm_get_accounting_storage_type(); if ((strcmp(acct_type, "accounting_storage/none") == 0) && (stat(params.opt_filein, &stat_buf) != 0)) { fprintf(stderr, "SLURM accounting storage is disabled\n"); exit(1); } xfree(acct_type); acct_db_conn = slurmdb_connection_get(); if(errno != SLURM_SUCCESS) { error("Problem talking to the database: %m"); exit(1); } } /* specific clusters requested? */ if(all_clusters) { if(job_cond->cluster_list && list_count(job_cond->cluster_list)) { list_destroy(job_cond->cluster_list); job_cond->cluster_list = NULL; } debug2("Clusters requested:\tall"); } else if (job_cond->cluster_list && list_count(job_cond->cluster_list)) { debug2( "Clusters requested:"); itr = list_iterator_create(job_cond->cluster_list); while((start = list_next(itr))) debug2("\t: %s", start); list_iterator_destroy(itr); } else if(!job_cond->cluster_list || !list_count(job_cond->cluster_list)) { if(!job_cond->cluster_list) job_cond->cluster_list = list_create(slurm_destroy_char); if((start = slurm_get_cluster_name())) { list_append(job_cond->cluster_list, start); debug2("Clusters requested:\t%s", start); } } /* if any jobs or nodes are specified set to look for all users if none are set */ if(!job_cond->userid_list || !list_count(job_cond->userid_list)) if((job_cond->step_list && list_count(job_cond->step_list)) || job_cond->used_nodes) all_users=1; /* set all_users for user root if not requesting any */ if(!job_cond->userid_list && !params.opt_uid) all_users = 1; if(all_users) { if(job_cond->userid_list && list_count(job_cond->userid_list)) { list_destroy(job_cond->userid_list); job_cond->userid_list = NULL; } debug2("Userids requested:\tall"); } else if (job_cond->userid_list && list_count(job_cond->userid_list)) { debug2("Userids requested:"); itr = list_iterator_create(job_cond->userid_list); while((start = list_next(itr))) debug2("\t: %s", start); list_iterator_destroy(itr); } else if(!job_cond->userid_list || !list_count(job_cond->userid_list)) { if(!job_cond->userid_list) job_cond->userid_list = list_create(slurm_destroy_char); start = xstrdup_printf("%u", params.opt_uid); list_append(job_cond->userid_list, start); debug2("Userid requested\t: %s", start); } if (job_cond->groupid_list && list_count(job_cond->groupid_list)) { debug2("Groupids requested:"); itr = list_iterator_create(job_cond->groupid_list); while((start = list_next(itr))) debug2("\t: %s", start); list_iterator_destroy(itr); } /* specific partitions requested? */ if (job_cond->partition_list && list_count(job_cond->partition_list)) { debug2("Partitions requested:"); itr = list_iterator_create(job_cond->partition_list); while((start = list_next(itr))) debug2("\t: %s", start); list_iterator_destroy(itr); } /* specific qos' requested? */ if (job_cond->qos_list && list_count(job_cond->qos_list)) { start = get_qos_complete_str(g_qos_list, job_cond->qos_list); debug2("QOS requested\t: %s\n", start); xfree(start); } /* specific jobs requested? */ if (job_cond->step_list && list_count(job_cond->step_list)) { debug2("Jobs requested:"); itr = list_iterator_create(job_cond->step_list); while((selected_step = list_next(itr))) { if(selected_step->stepid != NO_VAL) debug2("\t: %d.%d", selected_step->jobid, selected_step->stepid); else debug2("\t: %d", selected_step->jobid); } list_iterator_destroy(itr); } /* specific states (completion state) requested? */ if (job_cond->state_list && list_count(job_cond->state_list)) { debug2("States requested:"); itr = list_iterator_create(job_cond->state_list); while((start = list_next(itr))) { debug2("\t: %s", job_state_string(atoi(start))); } list_iterator_destroy(itr); } if (job_cond->wckey_list && list_count(job_cond->wckey_list)) { debug2("Wckeys requested:"); itr = list_iterator_create(job_cond->wckey_list); while((start = list_next(itr))) debug2("\t: %s\n", start); list_iterator_destroy(itr); } if (job_cond->timelimit_min) { char time_str[128], tmp1[32], tmp2[32]; mins2time_str(job_cond->timelimit_min, tmp1, sizeof(tmp1)); sprintf(time_str, "%s", tmp1); if(job_cond->timelimit_max) { int len = strlen(tmp1); mins2time_str(job_cond->timelimit_max, tmp2, sizeof(tmp2)); sprintf(time_str+len, " - %s", tmp2); } debug2("Timelimit requested\t: %s", time_str); } /* specific jobnames requested? */ if (job_cond->jobname_list && list_count(job_cond->jobname_list)) { debug2("Jobnames requested:"); itr = list_iterator_create(job_cond->jobname_list); while((start = list_next(itr))) { debug2("\t: %s", start); } list_iterator_destroy(itr); } /* select the output fields */ if(brief_output) { if(params.opt_completion) dot = BRIEF_COMP_FIELDS; else dot = BRIEF_FIELDS; xstrfmtcat(params.opt_field_list, "%s,", dot); } if(long_output) { if(params.opt_completion) dot = LONG_COMP_FIELDS; else dot = LONG_FIELDS; xstrfmtcat(params.opt_field_list, "%s,", dot); } if (params.opt_field_list==NULL) { if(params.opt_completion) dot = DEFAULT_COMP_FIELDS; else dot = DEFAULT_FIELDS; xstrfmtcat(params.opt_field_list, "%s,", dot); } start = params.opt_field_list; while ((end = strstr(start, ","))) { char *tmp_char = NULL; int command_len = 0; int newlen = 0; *end = 0; while (isspace(*start)) start++; /* discard whitespace */ if(!(int)*start) continue; if((tmp_char = strstr(start, "\%"))) { newlen = atoi(tmp_char+1); tmp_char[0] = '\0'; } command_len = strlen(start); for (i = 0; fields[i].name; i++) { if (!strncasecmp(fields[i].name, start, command_len)) goto foundfield; } error("Invalid field requested: \"%s\"", start); exit(1); foundfield: if(newlen) fields[i].len = newlen; list_append(print_fields_list, &fields[i]); start = end + 1; }
int main(int argc, char **argv) { int error_code = SLURM_SUCCESS, i, opt_char, input_field_count; char **input_fields; log_options_t opts = LOG_OPTS_STDERR_ONLY ; int local_exit_code = 0; char *temp = NULL; int option_index; static struct option long_options[] = { {"help", 0, 0, 'h'}, {"usage", 0, 0, 'h'}, {"immediate",0, 0, 'i'}, {"noheader",0, 0, 'n'}, {"oneliner", 0, 0, 'o'}, {"parsable", 0, 0, 'p'}, {"parsable2", 0, 0, 'P'}, {"quiet", 0, 0, 'Q'}, {"readonly", 0, 0, 'r'}, {"associations", 0, 0, 's'}, {"verbose", 0, 0, 'v'}, {"version", 0, 0, 'V'}, {NULL, 0, 0, 0} }; command_name = argv[0]; rollback_flag = 1; exit_code = 0; exit_flag = 0; input_field_count = 0; quiet_flag = 0; readonly_flag = 0; verbosity = 0; slurm_conf_init(NULL); log_init("sacctmgr", opts, SYSLOG_FACILITY_DAEMON, NULL); while((opt_char = getopt_long(argc, argv, "hionpPQrsvV", long_options, &option_index)) != -1) { switch (opt_char) { case (int)'?': fprintf(stderr, "Try \"sacctmgr --help\" " "for more information\n"); exit(1); break; case (int)'h': _usage (); exit(exit_code); break; case (int)'i': rollback_flag = 0; break; case (int)'o': one_liner = 1; break; case (int)'n': print_fields_have_header = 0; break; case (int)'p': print_fields_parsable_print = PRINT_FIELDS_PARSABLE_ENDING; break; case (int)'P': print_fields_parsable_print = PRINT_FIELDS_PARSABLE_NO_ENDING; break; case (int)'Q': quiet_flag = 1; break; case (int)'r': readonly_flag = 1; break; case (int)'s': with_assoc_flag = 1; break; case (int)'v': quiet_flag = -1; verbosity++; break; case (int)'V': _print_version(); exit(exit_code); break; default: exit_code = 1; fprintf(stderr, "getopt error, returned %c\n", opt_char); exit(exit_code); } } if (argc > MAX_INPUT_FIELDS) /* bogus input, but continue anyway */ input_words = argc; else input_words = 128; input_fields = (char **) xmalloc (sizeof (char *) * input_words); if (optind < argc) { for (i = optind; i < argc; i++) { input_fields[input_field_count++] = argv[i]; } } if (verbosity) { opts.stderr_level += verbosity; opts.prefix_level = 1; log_alter(opts, 0, NULL); } /* Check to see if we are running a supported accounting plugin */ temp = slurm_get_accounting_storage_type(); if (xstrcasecmp(temp, "accounting_storage/slurmdbd") && xstrcasecmp(temp, "accounting_storage/mysql")) { fprintf (stderr, "You are not running a supported " "accounting_storage plugin\n(%s).\n" "Only 'accounting_storage/slurmdbd' " "and 'accounting_storage/mysql' are supported.\n", temp); xfree(temp); exit(1); } xfree(temp); errno = 0; db_conn = slurmdb_connection_get(); if (errno != SLURM_SUCCESS) { int tmp_errno = errno; if ((input_field_count == 2) && (!strncasecmp(argv[2], "Configuration", strlen(argv[1]))) && ((!strncasecmp(argv[1], "list", strlen(argv[0]))) || (!strncasecmp(argv[1], "show", strlen(argv[0]))))) { if (tmp_errno == ESLURM_DB_CONNECTION) { tmp_errno = 0; sacctmgr_list_config(true); } else sacctmgr_list_config(false); } errno = tmp_errno; if (errno) error("Problem talking to the database: %m"); exit(1); } my_uid = getuid(); if (input_field_count) exit_flag = 1; else error_code = _get_command (&input_field_count, input_fields); while (error_code == SLURM_SUCCESS) { error_code = _process_command (input_field_count, input_fields); if (error_code || exit_flag) break; error_code = _get_command (&input_field_count, input_fields); /* This is here so if someone made a mistake we allow * them to fix it and let the process happen since there * are checks for global exit_code we need to reset it. */ if (exit_code) { local_exit_code = exit_code; exit_code = 0; } } /* readline library writes \n when echoes the input string, it does * not when it sees the EOF, so in that case we have to print it to * align the terminal prompt. */ if (exit_flag == 2) putchar('\n'); if (local_exit_code) exit_code = local_exit_code; acct_storage_g_close_connection(&db_conn); slurm_acct_storage_fini(); FREE_NULL_LIST(g_qos_list); FREE_NULL_LIST(g_res_list); FREE_NULL_LIST(g_tres_list); exit(exit_code); }
int main (int argc, char **argv) { int error_code = SLURM_SUCCESS, i, opt_char, input_field_count; char **input_fields; log_options_t opts = LOG_OPTS_STDERR_ONLY ; char *temp = NULL; int option_index; static struct option long_options[] = { {"all_clusters", 0, 0, 'a'}, {"cluster", 1, 0, 'M'}, {"help", 0, 0, 'h'}, {"immediate",0, 0, 'i'}, {"noheader", 0, 0, 'n'}, {"parsable", 0, 0, 'p'}, {"parsable2",0, 0, 'P'}, {"quiet", 0, 0, 'Q'}, {"sort", 0, 0, 's'}, {"tres", 1, 0, 'T'}, {"usage", 0, 0, 'h'}, {"verbose", 0, 0, 'v'}, {"version", 0, 0, 'V'}, {NULL, 0, 0, 0} }; command_name = argv[0]; exit_code = 0; exit_flag = 0; input_field_count = 0; quiet_flag = 0; slurm_conf_init(NULL); log_init("sreport", opts, SYSLOG_FACILITY_DAEMON, NULL); /* Check to see if we are running a supported accounting plugin */ temp = slurm_get_accounting_storage_type(); if (xstrcasecmp(temp, "accounting_storage/slurmdbd") && xstrcasecmp(temp, "accounting_storage/mysql")) { fprintf (stderr, "You are not running a supported " "accounting_storage plugin\n(%s).\n" "Only 'accounting_storage/slurmdbd' " "and 'accounting_storage/mysql' are supported.\n", temp); xfree(temp); exit(1); } xfree(temp); temp = getenv("SREPORT_TRES"); if (temp) tres_str = xstrdup(temp); while ((opt_char = getopt_long(argc, argv, "aM:hnpPQs:t:T:vV", long_options, &option_index)) != -1) { switch (opt_char) { case (int)'?': fprintf(stderr, "Try \"sreport --help\" " "for more information\n"); exit(1); break; case (int)'h': _usage (); exit(exit_code); break; case (int)'a': all_clusters_flag = 1; break; case (int) 'M': cluster_flag = xstrdup(optarg); break; case (int)'n': print_fields_have_header = 0; break; case (int)'p': print_fields_parsable_print = PRINT_FIELDS_PARSABLE_ENDING; break; case (int)'P': print_fields_parsable_print = PRINT_FIELDS_PARSABLE_NO_ENDING; break; case (int)'Q': quiet_flag = 1; break; case (int)'s': _set_sort(optarg); break; case (int)'t': _set_time_format(optarg); break; case (int)'T': xfree(tres_str); tres_str = xstrdup(optarg); break; case (int)'v': quiet_flag = -1; break; case (int)'V': _print_version(); exit(exit_code); break; default: exit_code = 1; fprintf(stderr, "getopt error, returned %c\n", opt_char); exit(exit_code); } } if (argc > MAX_INPUT_FIELDS) /* bogus input, but continue anyway */ input_words = argc; else input_words = 128; input_fields = (char **) xmalloc (sizeof (char *) * input_words); if (optind < argc) { for (i = optind; i < argc; i++) { input_fields[input_field_count++] = argv[i]; } } my_uid = getuid(); db_conn = slurmdb_connection_get(); if (errno) { fatal("Problem connecting to the database: %m"); exit(1); } tres_list = _build_tres_list(tres_str); if (input_field_count) exit_flag = 1; else error_code = _get_command (&input_field_count, input_fields); while (error_code == SLURM_SUCCESS) { error_code = _process_command (input_field_count, input_fields); if (error_code || exit_flag) break; error_code = _get_command (&input_field_count, input_fields); } if (exit_flag == 2) putchar('\n'); /* Free the cluster grabbed from the -M option */ xfree(cluster_flag); slurmdb_connection_close(&db_conn); slurm_acct_storage_fini(); exit(exit_code); }