/*****************************************************************************\
 *  file_functions.c - functions dealing with files that are generated in the
 *                        accounting system.
 *****************************************************************************
 *  Copyright (C) 2008 Lawrence Livermore National Security.
 *  Copyright (C) 2002-2007 The Regents of the University of California.
 *  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 "src/sacctmgr/sacctmgr.h"
#include "src/common/strlcpy.h"
#include "src/common/uid.h"

#define BUFFER_SIZE 4096

typedef struct {
	slurmdb_admin_level_t admin;
	slurmdb_assoc_rec_t assoc_rec;
	uint16_t classification;
	List coord_list; /* char *list */
	char *def_acct;
	char *def_wckey;
	char *desc;

	char *name;
	char *org;
	List wckey_list;
} sacctmgr_file_opts_t;

typedef enum {
	MOD_CLUSTER,
	MOD_ACCT,
	MOD_USER
} sacctmgr_mod_type_t;

static int _init_sacctmgr_file_opts(sacctmgr_file_opts_t *file_opts)
{
	if (!file_opts)
		return SLURM_ERROR;

	memset(file_opts, 0, sizeof(sacctmgr_file_opts_t));
	slurmdb_init_assoc_rec(&file_opts->assoc_rec, 0);
	file_opts->admin = SLURMDB_ADMIN_NOTSET;

	return SLURM_SUCCESS;
}

static int _strip_continuation(char *buf, int len)
{
	char *ptr;
	int bs = 0;

	for (ptr = buf+len-1; ptr >= buf; ptr--) {
		if (*ptr == '\\')
			bs++;
		else if (isspace(*ptr) && bs == 0)
			continue;
		else
			break;
	}
	/* Check for an odd number of contiguous backslashes at
	   the end of the line */
	if (bs % 2 == 1) {
		ptr = ptr + bs;
		*ptr = '\0';
		return (ptr - buf);
	} else {
		return len; /* no continuation */
	}
}

/* Strip comments from a line by terminating the string
 * where the comment begins.
 * Everything after a non-escaped "#" is a comment.
 */
static void _strip_comments(char *line)
{
	int i;
	int len = strlen(line);
	int bs_count = 0;

	for (i = 0; i < len; i++) {
		/* if # character is preceded by an even number of
		 * escape characters '\' */
		if (line[i] == '#' && (bs_count%2) == 0) {
			line[i] = '\0';
 			break;
		} else if (line[i] == '\\') {
			bs_count++;
		} else {
			bs_count = 0;
		}
	}
}

/*
 * Strips any escape characters, "\".  If you WANT a back-slash,
 * it must be escaped, "\\".
 */
static void _strip_escapes(char *line)
{
	int i, j;
	int len = strlen(line);

	for (i = 0, j = 0; i < len+1; i++, j++) {
		if (line[i] == '\\')
			i++;
		line[j] = line[i];
	}
}

/*
 * Reads the next line from the "file" into buffer "buf".
 *
 * Concatenates together lines that are continued on
 * the next line by a trailing "\".  Strips out comments,
 * replaces escaped "\#" with "#", and replaces "\\" with "\".
 */
static int _get_next_line(char *buf, int buf_size, FILE *file)
{
	char *ptr = buf;
	int leftover = buf_size;
	int read_size, new_size;
	int lines = 0;

	while (fgets(ptr, leftover, file)) {
		lines++;
		_strip_comments(ptr);
		read_size = strlen(ptr);
		new_size = _strip_continuation(ptr, read_size);
		if (new_size < read_size) {
			ptr += new_size;
			leftover -= new_size;
		} else { /* no continuation */
			break;
		}
	}
	/* _strip_cr_nl(buf); */ /* not necessary */
	_strip_escapes(buf);

	return lines;
}

static void _destroy_sacctmgr_file_opts(void *object)
{
	sacctmgr_file_opts_t *file_opts = (sacctmgr_file_opts_t *)object;

	if (file_opts) {
		slurmdb_free_assoc_rec_members(&file_opts->assoc_rec);
		FREE_NULL_LIST(file_opts->coord_list);
		xfree(file_opts->def_acct);
		xfree(file_opts->def_wckey);
		xfree(file_opts->desc);
		xfree(file_opts->name);
		xfree(file_opts->org);
		FREE_NULL_LIST(file_opts->wckey_list);
		xfree(file_opts);
	}
}

/*
 * NOTE: make_lower only applies to the first parsed option. This is needed
 * for parsing the User column, which may be case-sensitive if the slurmdbd
 * reports PERSIST_FLAG_P_USER_CASE on the connection. All other options
 * are currently case-insensitive, and will be normalized to lowercase.
 */
static sacctmgr_file_opts_t *_parse_options(char *options, bool make_lower)
{
	int start=0, i=0, end=0, quote = 0;
 	char *sub = NULL;
	sacctmgr_file_opts_t *file_opts = xmalloc(sizeof(sacctmgr_file_opts_t));
	char *option = NULL;
	char quote_c = '\0';
	int command_len = 0;
	int option2 = 0;

	_init_sacctmgr_file_opts(file_opts);

	while (options[i]) {
		quote = 0;
		start=i;

		while (options[i] && options[i] != ':' && options[i] != '\n') {
			if (options[i] == '"' || options[i] == '\'') {
				if (quote) {
					if (options[i] == quote_c)
						quote = 0;
				} else {
					quote = 1;
					quote_c = options[i];
				}
			}
			i++;
		}
		if (quote) {
			while (options[i] && options[i] != quote_c)
				i++;
			if (!options[i])
				fatal("There is a problem with option "
				      "%s with quotes.", option);
			i++;
		}

		if (i-start <= 0)
			goto next_col;

		sub = xstrndup(options+start, i-start);
		end = parse_option_end(sub);
		command_len = end - 1;
		if (sub[end] == '=') {
			option2 = (int)sub[end-1];
			end++;
		}

		option = strip_quotes(sub+end, NULL, make_lower);

		if (!end) {
			if (file_opts->name) {
				exit_code=1;
				fprintf(stderr, " Bad format on %s: "
					"End your option with "
					"an '=' sign\n", sub);
				break;
			}
			file_opts->name = xstrdup(option);

			/* remaining options should be converted to lowercase */
			make_lower = true;
		} else if (end && !strlen(option)) {
			debug("blank field given for %s discarding", sub);
		} else if (!xstrncasecmp(sub, "AdminLevel",
					 MAX(command_len, 2))) {
			file_opts->admin = str_2_slurmdb_admin_level(option);
		} else if (!xstrncasecmp(sub, "Coordinator",
					 MAX(command_len, 2))) {
			if (!file_opts->coord_list)
				file_opts->coord_list = list_create(xfree_ptr);
			slurm_addto_char_list(file_opts->coord_list, option);
		} else if (!xstrncasecmp(sub, "Classification",
					 MAX(command_len, 2))) {
			file_opts->classification =
				str_2_classification(option);
		} else if (!xstrncasecmp(sub, "DefaultAccount",
					 MAX(command_len, 8))) {
			file_opts->def_acct = xstrdup(option);
		} else if (!xstrncasecmp(sub, "DefaultWCKey",
					 MAX(command_len, 8))) {
			file_opts->def_wckey = xstrdup(option);
			if (!file_opts->wckey_list)
				file_opts->wckey_list = list_create(xfree_ptr);
			slurm_addto_char_list(file_opts->wckey_list, option);
		} else if (!xstrncasecmp(sub, "Description",
					 MAX(command_len, 3))) {
			file_opts->desc = xstrdup(option);
		} else if (!xstrncasecmp(sub, "Organization",
					 MAX(command_len, 1))) {
			file_opts->org = xstrdup(option);
		} else if (!xstrncasecmp(sub, "Partition",
					 MAX(command_len, 1))) {
			file_opts->assoc_rec.partition = xstrdup(option);
		} else if (!xstrncasecmp(sub, "WCKeys",
					 MAX(command_len, 2))) {
			if (!file_opts->wckey_list)
				file_opts->wckey_list = list_create(xfree_ptr);
			slurm_addto_char_list(file_opts->wckey_list, option);
		} else if (!sacctmgr_set_assoc_rec(
				   &file_opts->assoc_rec, sub, option,
				   command_len, option2)) {
			exit_code=1;
			fprintf(stderr, " Unknown option: %s\n", sub);
			break;
		}

		xfree(sub);
		xfree(option);

	next_col:
		if (options[i] == ':')
			i++;
		else
			break;
	}

	xfree(sub);
	xfree(option);

	if (!file_opts->name) {
		exit_code = 1;
		fprintf(stderr, " No name given\n");
	}

	if (exit_code) {
		_destroy_sacctmgr_file_opts(file_opts);
		file_opts = NULL;
	}

	return file_opts;
}

static int _print_out_assoc(List assoc_list, bool user, bool add)
{
	List format_list = NULL;
	List print_fields_list = NULL;
	list_itr_t *itr, *itr2;
	print_field_t *field = NULL;
	slurmdb_assoc_rec_t *assoc = NULL;
	int rc = SLURM_SUCCESS;

	if (!assoc_list || !list_count(assoc_list))
		return rc;

	format_list = list_create(xfree_ptr);
	if (user)
		slurm_addto_char_list(format_list,
				      "User,Account");
	else
		slurm_addto_char_list(format_list,
				      "Account,ParentName");
	slurm_addto_char_list(format_list,
			      "Share,GrpTRESM,GrpTRESR,GrpTRES,GrpJ,GrpJobsA,"
			      "GrpMEM,GrpN,GrpS,GrpW,MaxTRESM,MaxTRES,"
			      "MaxTRESPerN,MaxJ,MaxS,MaxN,MaxW,QOS,DefaultQOS");

	print_fields_list = sacctmgr_process_format_list(format_list);
	FREE_NULL_LIST(format_list);

	print_fields_header(print_fields_list);

	itr = list_iterator_create(assoc_list);
	itr2 = list_iterator_create(print_fields_list);
	while ((assoc = list_next(itr))) {
		while ((field = list_next(itr2))) {
			sacctmgr_print_assoc_rec(assoc, field, NULL, 0);
		}
		list_iterator_reset(itr2);
		printf("\n");
	}
	list_iterator_destroy(itr);
	list_iterator_destroy(itr2);
	FREE_NULL_LIST(print_fields_list);
	if (add)
		rc = slurmdb_associations_add(db_conn, assoc_list);
	printf("--------------------------------------------------------------\n\n");

	return rc;
}

static int _mod_assoc(sacctmgr_file_opts_t *file_opts,
		      slurmdb_assoc_rec_t *assoc,
		      sacctmgr_mod_type_t mod_type,
		      char *parent)
{
	int changed = 0;
	slurmdb_assoc_rec_t mod_assoc;
	slurmdb_assoc_cond_t assoc_cond;
	char *type = NULL;
	char *name = NULL;
	char *my_info = NULL;

	switch(mod_type) {
	case MOD_CLUSTER:
		type = "Cluster";
		name = assoc->cluster;
		break;
	case MOD_ACCT:
		type = "Account";
		name = assoc->acct;
		break;
	case MOD_USER:
		type = "User";
		name = assoc->user;
		break;
	default:
		return 0;
		break;
	}
	slurmdb_init_assoc_rec(&mod_assoc, 0);
	memset(&assoc_cond, 0, sizeof(slurmdb_assoc_cond_t));

	if (file_opts->assoc_rec.comment
	    && xstrcmp(assoc->comment, file_opts->assoc_rec.comment)) {
		mod_assoc.comment = file_opts->assoc_rec.comment;
		changed = 1;
		xstrfmtcat(my_info,
			   "%-30.30s for %-7.7s %-10.10s "
			   "%8s -> %s\n",
			   " Changed Comment",
			   type, name, assoc->comment,
			   file_opts->assoc_rec.comment);
	}

	if ((file_opts->assoc_rec.shares_raw != NO_VAL)
	    && (assoc->shares_raw != file_opts->assoc_rec.shares_raw)) {
		mod_assoc.shares_raw = file_opts->assoc_rec.shares_raw;
		changed = 1;
		xstrfmtcat(my_info,
			   "%-30.30s for %-7.7s %-10.10s %8d -> %d\n",
			   " Changed fairshare",
			   type, name,
			   assoc->shares_raw,
			   file_opts->assoc_rec.shares_raw);
	}

	if (file_opts->assoc_rec.grp_tres_mins
	    && xstrcmp(assoc->grp_tres_mins,
		       file_opts->assoc_rec.grp_tres_mins)) {
		mod_assoc.grp_tres_mins = file_opts->assoc_rec.grp_tres_mins;
		changed = 1;
		xstrfmtcat(my_info,
			   "%-30.30s for %-7.7s %-10.10s "
			   "%8s -> %s\n",
			   " Changed GrpTRESMins",
			   type, name,
			   assoc->grp_tres_mins,
			   file_opts->assoc_rec.grp_tres_mins);
	}

	if (file_opts->assoc_rec.grp_tres_run_mins
	    && xstrcmp(assoc->grp_tres_run_mins,
		file_opts->assoc_rec.grp_tres_run_mins)) {
		mod_assoc.grp_tres_run_mins =
			file_opts->assoc_rec.grp_tres_run_mins;
		changed = 1;
		xstrfmtcat(my_info,
			   "%-30.30s for %-7.7s %-10.10s "
			   "%8s -> %s\n",
			   " Changed GrpTRESRunMins",
			   type, name,
			   assoc->grp_tres_run_mins,
			   file_opts->assoc_rec.grp_tres_run_mins);
	}

	if (file_opts->assoc_rec.grp_tres
	    && xstrcmp(assoc->grp_tres, file_opts->assoc_rec.grp_tres)) {
		mod_assoc.grp_tres = file_opts->assoc_rec.grp_tres;
		changed = 1;
		xstrfmtcat(my_info,
			   "%-30.30s for %-7.7s %-10.10s %8s -> %s\n",
			   " Changed GrpTRES",
			   type, name,
			   assoc->grp_tres,
			   file_opts->assoc_rec.grp_tres);
	}

	if ((file_opts->assoc_rec.grp_jobs != NO_VAL)
	    && (assoc->grp_jobs != file_opts->assoc_rec.grp_jobs)) {
		mod_assoc.grp_jobs = file_opts->assoc_rec.grp_jobs;
		changed = 1;
		xstrfmtcat(my_info,
			   "%-30.30s for %-7.7s %-10.10s %8d -> %d\n",
			   " Changed GrpJobs",
			   type, name,
			   assoc->grp_jobs,
			   file_opts->assoc_rec.grp_jobs);
	}

	if ((file_opts->assoc_rec.grp_jobs_accrue != NO_VAL)
	    && (assoc->grp_jobs_accrue !=
		file_opts->assoc_rec.grp_jobs_accrue)) {
		mod_assoc.grp_jobs_accrue =
			file_opts->assoc_rec.grp_jobs_accrue;
		changed = 1;
		xstrfmtcat(my_info,
			   "%-30.30s for %-7.7s %-10.10s %8d -> %d\n",
			   " Changed GrpJobsAccrue",
			   type, name,
			   assoc->grp_jobs_accrue,
			   file_opts->assoc_rec.grp_jobs_accrue);
	}

	if ((file_opts->assoc_rec.grp_submit_jobs != NO_VAL)
	    && (assoc->grp_submit_jobs !=
		file_opts->assoc_rec.grp_submit_jobs)) {
		mod_assoc.grp_submit_jobs =
			file_opts->assoc_rec.grp_submit_jobs;
		changed = 1;
		xstrfmtcat(my_info,
			   "%-30.30s for %-7.7s %-10.10s %8d -> %d\n",
			   " Changed GrpSubmitJobs",
			   type, name,
			   assoc->grp_submit_jobs,
			   file_opts->assoc_rec.grp_submit_jobs);
	}

	if ((file_opts->assoc_rec.grp_wall != NO_VAL)
	    && (assoc->grp_wall != file_opts->assoc_rec.grp_wall)) {
		mod_assoc.grp_wall = file_opts->assoc_rec.grp_wall;
		changed = 1;
		xstrfmtcat(my_info,
			   "%-30.30s for %-7.7s %-10.10s %8d -> %d\n",
			   " Changed GrpWallDuration",
			   type, name,
			   assoc->grp_wall,
			   file_opts->assoc_rec.grp_wall);
	}

	if (file_opts->assoc_rec.max_tres_mins_pj
	    && xstrcmp(assoc->max_tres_mins_pj,
		       file_opts->assoc_rec.max_tres_mins_pj)) {
		mod_assoc.max_tres_mins_pj =
			file_opts->assoc_rec.max_tres_mins_pj;
		changed = 1;
		xstrfmtcat(my_info,
			   "%-30.30s for %-7.7s %-10.10s "
			   "%8s -> %s\n",
			   " Changed MaxTRESMinsPerJob",
			   type, name,
			   assoc->max_tres_mins_pj,
			   file_opts->assoc_rec.max_tres_mins_pj);
	}

	if (file_opts->assoc_rec.max_tres_run_mins
	    && xstrcmp(assoc->max_tres_run_mins,
		       file_opts->assoc_rec.max_tres_run_mins)) {
		mod_assoc.max_tres_run_mins =
			file_opts->assoc_rec.max_tres_run_mins;
		changed = 1;
		xstrfmtcat(my_info,
			   "%-30.30s for %-7.7s %-10.10s "
			   "%8s -> %s\n",
			   " Changed MaxTRESRunMins",
			   type, name,
			   assoc->max_tres_run_mins,
			   file_opts->assoc_rec.max_tres_run_mins);
	}

	if (file_opts->assoc_rec.max_tres_pj
	    && xstrcmp(assoc->max_tres_pj, file_opts->assoc_rec.max_tres_pj)) {
		mod_assoc.max_tres_pj = file_opts->assoc_rec.max_tres_pj;
		changed = 1;
		xstrfmtcat(my_info,
			   "%-30.30s for %-7.7s %-10.10s %8s -> %s\n",
			   " Changed MaxTRESPerJob",
			   type, name,
			   assoc->max_tres_pj,
			   file_opts->assoc_rec.max_tres_pj);
	}

	if (file_opts->assoc_rec.max_tres_pn
	    && xstrcmp(assoc->max_tres_pn, file_opts->assoc_rec.max_tres_pn)) {
		mod_assoc.max_tres_pn = file_opts->assoc_rec.max_tres_pn;
		changed = 1;
		xstrfmtcat(my_info,
			   "%-30.30s for %-7.7s %-10.10s %8s -> %s\n",
			   " Changed MaxTRESPerNode",
			   type, name,
			   assoc->max_tres_pn,
			   file_opts->assoc_rec.max_tres_pn);
	}

	if ((file_opts->assoc_rec.max_jobs != NO_VAL)
	    && (assoc->max_jobs != file_opts->assoc_rec.max_jobs)) {
		mod_assoc.max_jobs = file_opts->assoc_rec.max_jobs;
		changed = 1;
		xstrfmtcat(my_info,
			   "%-30.30s for %-7.7s %-10.10s %8d -> %d\n",
			   " Changed MaxJobs",
			   type, name,
			   assoc->max_jobs,
			   file_opts->assoc_rec.max_jobs);
	}

	if ((file_opts->assoc_rec.max_jobs_accrue != NO_VAL)
	    && (assoc->max_jobs_accrue !=
		file_opts->assoc_rec.max_jobs_accrue)) {
		mod_assoc.max_jobs_accrue =
			file_opts->assoc_rec.max_jobs_accrue;
		changed = 1;
		xstrfmtcat(my_info,
			   "%-30.30s for %-7.7s %-10.10s %8d -> %d\n",
			   " Changed MaxJobsAccrue",
			   type, name,
			   assoc->max_jobs_accrue,
			   file_opts->assoc_rec.max_jobs_accrue);
	}

	if ((file_opts->assoc_rec.max_submit_jobs != NO_VAL)
	    && (assoc->max_submit_jobs !=
		file_opts->assoc_rec.max_submit_jobs)) {
		mod_assoc.max_submit_jobs =
			file_opts->assoc_rec.max_submit_jobs;
		changed = 1;
		xstrfmtcat(my_info,
			   "%-30.30s for %-7.7s %-10.10s %8d -> %d\n",
			   " Changed MaxSubmitJobs",
			   type, name,
			   assoc->max_submit_jobs,
			   file_opts->assoc_rec.max_submit_jobs);
	}

	if ((file_opts->assoc_rec.max_wall_pj != NO_VAL)
	    && (assoc->max_wall_pj != file_opts->assoc_rec.max_wall_pj)) {
		mod_assoc.max_wall_pj =	file_opts->assoc_rec.max_wall_pj;
		changed = 1;
		xstrfmtcat(my_info,
			   "%-30.30s for %-7.7s %-10.10s %8d -> %d\n",
			   " Changed MaxWallDurationPerJob",
			   type, name,
			   assoc->max_wall_pj,
			   file_opts->assoc_rec.max_wall_pj);
	}
	if (assoc->parent_acct && parent
	    && xstrcmp(assoc->parent_acct, parent)) {
		mod_assoc.parent_acct = parent;
		changed = 1;
		xstrfmtcat(my_info,
			   "%-30.30s for %-7.7s %-10.10s %8s -> %s\n",
			   " Changed Parent",
			   type, name,
			   assoc->parent_acct,
			   parent);
	}

	if ((file_opts->assoc_rec.priority != NO_VAL)
	    && (assoc->priority != file_opts->assoc_rec.priority)) {
		mod_assoc.priority = file_opts->assoc_rec.priority;
		changed = 1;
		xstrfmtcat(my_info,
			   "%-30.30s for %-7.7s %-10.10s %8d -> %d\n",
			   " Changed Priority",
			   type, name,
			   assoc->priority,
			   file_opts->assoc_rec.priority);
	}

	if (assoc->qos_list && list_count(assoc->qos_list) &&
	    file_opts->assoc_rec.qos_list &&
	    list_count(file_opts->assoc_rec.qos_list)) {
		list_itr_t *now_qos_itr =
			list_iterator_create(assoc->qos_list);
		list_itr_t *new_qos_itr =
			list_iterator_create(file_opts->assoc_rec.qos_list);
		char *now_qos = NULL, *new_qos = NULL;

		if (!mod_assoc.qos_list)
			mod_assoc.qos_list = list_create(xfree_ptr);
		while ((new_qos = list_next(new_qos_itr))) {
			while ((now_qos = list_next(now_qos_itr))) {
				if (!xstrcmp(new_qos, now_qos))
					break;
			}
			list_iterator_reset(now_qos_itr);
			if (!now_qos)
				list_append(mod_assoc.qos_list,
					    xstrdup(new_qos));
		}
		list_iterator_destroy(new_qos_itr);
		list_iterator_destroy(now_qos_itr);
		if (mod_assoc.qos_list && list_count(mod_assoc.qos_list))
			new_qos = get_qos_complete_str(g_qos_list,
						       mod_assoc.qos_list);
		if (new_qos) {
			xstrfmtcat(my_info,
				   "%-30.30s for %-7.7s %-10.10s %8s\n",
				   " Added QOS",
				   type, name,
				   new_qos);
			xfree(new_qos);
			changed = 1;
		} else {
			FREE_NULL_LIST(mod_assoc.qos_list);
		}
	} else if (file_opts->assoc_rec.qos_list &&
		   list_count(file_opts->assoc_rec.qos_list)) {
		char *new_qos = get_qos_complete_str(
			g_qos_list, file_opts->assoc_rec.qos_list);

		if (new_qos) {
			xstrfmtcat(my_info,
				   "%-30.30s for %-7.7s %-10.10s %8s\n",
				   " Added QOS",
				   type, name,
				   new_qos);
			xfree(new_qos);
			mod_assoc.qos_list = file_opts->assoc_rec.qos_list;
			file_opts->assoc_rec.qos_list = NULL;
			changed = 1;
		}
	}

	if (changed) {
		List ret_list = NULL;

		assoc_cond.cluster_list = list_create(NULL);
		list_push(assoc_cond.cluster_list, assoc->cluster);

		assoc_cond.acct_list = list_create(NULL);
		list_push(assoc_cond.acct_list, assoc->acct);

		if (mod_type == MOD_USER) {
			assoc_cond.user_list = list_create(NULL);
			list_push(assoc_cond.user_list, assoc->user);
			if (assoc->partition) {
				assoc_cond.partition_list = list_create(NULL);
				list_push(assoc_cond.partition_list,
					  assoc->partition);
			}
		}

		notice_thread_init();
		ret_list = slurmdb_associations_modify(
			db_conn,
			&assoc_cond,
			&mod_assoc);
		notice_thread_fini();

		FREE_NULL_LIST(mod_assoc.qos_list);

		FREE_NULL_LIST(assoc_cond.cluster_list);
		FREE_NULL_LIST(assoc_cond.acct_list);
		FREE_NULL_LIST(assoc_cond.user_list);
		FREE_NULL_LIST(assoc_cond.partition_list);

/* 		if (ret_list && list_count(ret_list)) { */
/* 			char *object = NULL; */
/* 			list_itr_t *itr = list_iterator_create(ret_list); */
/* 			printf(" Modified account defaults for " */
/* 			       "associations...\n"); */
/* 			while ((object = list_next(itr)))  */
/* 				printf("  %s\n", object); */
/* 			list_iterator_destroy(itr); */
/* 		} */

		if (ret_list) {
			printf("%s", my_info);
			FREE_NULL_LIST(ret_list);
		} else
			changed = 0;
		xfree(my_info);
	}

	return changed;
}

static int _mod_cluster(sacctmgr_file_opts_t *file_opts,
			slurmdb_cluster_rec_t *cluster, char *parent)
{
	int changed = 0;
	char *my_info = NULL;
	slurmdb_cluster_rec_t mod_cluster;
	slurmdb_cluster_cond_t cluster_cond;

	slurmdb_init_cluster_rec(&mod_cluster, 0);
	slurmdb_init_cluster_cond(&cluster_cond, 0);

	if (file_opts->classification
	    && (file_opts->classification != cluster->classification)) {
		xstrfmtcat(my_info,
			   "%-30.30s for %-7.7s %-10.10s %8s -> %s\n",
			   " Changed Classification", "Cluster",
			   cluster->name,
			   get_classification_str(cluster->classification),
			   get_classification_str(file_opts->classification));
		mod_cluster.classification = file_opts->classification;
		changed = 1;
	}

	if (changed) {
		List ret_list = NULL;

		cluster_cond.cluster_list = list_create(NULL);

		list_append(cluster_cond.cluster_list, cluster->name);

		notice_thread_init();
		ret_list = slurmdb_clusters_modify(db_conn,
						   &cluster_cond,
						   &mod_cluster);
		notice_thread_fini();

		FREE_NULL_LIST(cluster_cond.cluster_list);

/* 		if (ret_list && list_count(ret_list)) { */
/* 			char *object = NULL; */
/* 			list_itr_t *itr = list_iterator_create(ret_list); */
/* 			printf(" Modified account defaults for " */
/* 			       "associations...\n"); */
/* 			while ((object = list_next(itr)))  */
/* 				printf("  %s\n", object); */
/* 			list_iterator_destroy(itr); */
/* 		} */

		if (ret_list) {
			printf("%s", my_info);
			FREE_NULL_LIST(ret_list);
		} else
			changed = 0;
		xfree(my_info);
	}
	if (!cluster->root_assoc || !cluster->root_assoc->cluster) {
		error("Cluster %s doesn't appear to have a root association.  "
		      "Try removing this cluster and then re-run load.",
		      cluster->name);
		exit(1);
	}

	changed += _mod_assoc(file_opts, cluster->root_assoc,
			      MOD_CLUSTER, parent);

	return changed;
}

static int _mod_acct(sacctmgr_file_opts_t *file_opts,
		     slurmdb_account_rec_t *acct, char *parent)
{
	int changed = 0;
	char *desc = NULL, *org = NULL, *my_info = NULL;
	slurmdb_account_rec_t mod_acct;
	slurmdb_account_cond_t acct_cond;
	slurmdb_assoc_cond_t assoc_cond;

	memset(&mod_acct, 0, sizeof(slurmdb_account_rec_t));
	memset(&acct_cond, 0, sizeof(slurmdb_account_cond_t));
	memset(&assoc_cond, 0, sizeof(slurmdb_assoc_cond_t));

	if (file_opts->desc)
		desc = xstrdup(file_opts->desc);

	if (desc && xstrcmp(desc, acct->description)) {
		xstrfmtcat(my_info,
			   "%-30.30s for %-7.7s %-10.10s %8s -> %s\n",
			   " Changed description", "Account",
			   acct->name,
			   acct->description,
			   desc);
		mod_acct.description = desc;
		changed = 1;
	} else
		xfree(desc);

	if (file_opts->org)
		org = xstrdup(file_opts->org);

	if (org && xstrcmp(org, acct->organization)) {
		xstrfmtcat(my_info,
			   "%-30.30s for %-7.7s %-10.10s %8s -> %s\n",
			   " Changed organization", "Account",
			   acct->name,
			   acct->organization,
			   org);
		mod_acct.organization = org;
		changed = 1;
	} else
		xfree(org);

	if (changed) {
		List ret_list = NULL;

		assoc_cond.acct_list = list_create(NULL);
		list_append(assoc_cond.acct_list, acct->name);
		acct_cond.assoc_cond = &assoc_cond;

		notice_thread_init();
		ret_list = slurmdb_accounts_modify(db_conn,
						   &acct_cond,
						   &mod_acct);
		notice_thread_fini();

		FREE_NULL_LIST(assoc_cond.acct_list);

/* 		if (ret_list && list_count(ret_list)) { */
/* 			char *object = NULL; */
/* 			list_itr_t *itr = list_iterator_create(ret_list); */
/* 			printf(" Modified account defaults for " */
/* 			       "associations...\n"); */
/* 			while ((object = list_next(itr)))  */
/* 				printf("  %s\n", object); */
/* 			list_iterator_destroy(itr); */
/* 		} */

		if (ret_list) {
			printf("%s", my_info);
			FREE_NULL_LIST(ret_list);
		} else
			changed = 0;
		xfree(my_info);
	}
	xfree(desc);
	xfree(org);
	return changed;
}

static int _mod_user(sacctmgr_file_opts_t *file_opts,
		     slurmdb_user_rec_t *user, char *cluster, char *parent)
{
	int set = 0;
	int changed = 0;
	char *def_acct = NULL, *def_wckey = NULL, *my_info = NULL;
	slurmdb_user_rec_t mod_user;
	slurmdb_user_cond_t user_cond;
	List ret_list = NULL;
	slurmdb_assoc_cond_t assoc_cond;

	if (!user || !user->name) {
		fatal(" We need a user name in _mod_user");
	}

	memset(&mod_user, 0, sizeof(slurmdb_user_rec_t));
	memset(&user_cond, 0, sizeof(slurmdb_user_cond_t));
	memset(&assoc_cond, 0, sizeof(slurmdb_assoc_cond_t));

	assoc_cond.user_list = list_create(NULL);
	list_append(assoc_cond.user_list, user->name);
	user_cond.assoc_cond = &assoc_cond;

	if (file_opts->def_acct)
		def_acct = xstrdup(file_opts->def_acct);

	if (def_acct &&
	    (!user->default_acct || xstrcmp(def_acct, user->default_acct))) {
		xstrfmtcat(my_info,
			   "%-30.30s for %-7.7s %-10.10s %8s -> %s\n",
			   " Changed Default Account", "User",
			   user->name,
			   user->default_acct,
			   def_acct);
		mod_user.default_acct = def_acct;
		changed = 1;
	}

	if (file_opts->def_wckey)
		def_wckey = xstrdup(file_opts->def_wckey);

	if (def_wckey &&
	    (!user->default_wckey || xstrcmp(def_wckey, user->default_wckey))) {
		xstrfmtcat(my_info,
			   "%-30.30s for %-7.7s %-10.10s %8s -> %s\n",
			   " Changed Default WCKey", "User",
			   user->name,
			   user->default_wckey,
			   def_wckey);
		mod_user.default_wckey = def_wckey;
		changed = 1;
	}

	if (user->admin_level != SLURMDB_ADMIN_NOTSET
	    && file_opts->admin != SLURMDB_ADMIN_NOTSET
	    && user->admin_level != file_opts->admin) {
		xstrfmtcat(my_info,
			   "%-30.30s for %-7.7s %-10.10s %8s -> %s\n",
			   " Changed Admin Level", "User",
			   user->name,
			   slurmdb_admin_level_str(
				   user->admin_level),
			   slurmdb_admin_level_str(
				   file_opts->admin));
		mod_user.admin_level = file_opts->admin;
		changed = 1;
	}

	if (changed) {
		notice_thread_init();
		ret_list = slurmdb_users_modify(
			db_conn,
			&user_cond,
			&mod_user);
		notice_thread_fini();

/* 		if (ret_list && list_count(ret_list)) { */
/* 			char *object = NULL; */
/* 			list_itr_t *itr = list_iterator_create(ret_list); */
/* 			printf(" Modified user defaults for " */
/* 			       "associations...\n"); */
/* 			while ((object = list_next(itr)))  */
/* 				printf("  %s\n", object); */
/* 			list_iterator_destroy(itr); */
/* 		} */

		if (ret_list) {
			printf("%s", my_info);
			FREE_NULL_LIST(ret_list);
			set = 1;
		}
		xfree(my_info);
	}
	xfree(def_acct);
	xfree(def_wckey);

	if ((!user->coord_accts || !list_count(user->coord_accts))
	    && (file_opts->coord_list
		&& list_count(file_opts->coord_list))) {
		list_itr_t *coord_itr = NULL;
		char *temp_char = NULL;
		slurmdb_coord_rec_t *coord = NULL;
		int first = 1;
		notice_thread_init();
		(void) slurmdb_coord_add(db_conn,
					 file_opts->coord_list,
					 &user_cond);
		notice_thread_fini();

		user->coord_accts = list_create(slurmdb_destroy_coord_rec);
		coord_itr = list_iterator_create(file_opts->coord_list);
		printf(" Making User '%s' coordinator for account(s)",
		       user->name);
		while ((temp_char = list_next(coord_itr))) {
			coord = xmalloc(sizeof(slurmdb_coord_rec_t));
			coord->name = xstrdup(temp_char);
			coord->direct = 1;
			list_push(user->coord_accts, coord);

			if (first) {
				printf(" %s", temp_char);
				first = 0;
			} else
				printf(", %s", temp_char);
		}
		list_iterator_destroy(coord_itr);
		printf("\n");
		set = 1;
	} else if ((user->coord_accts && list_count(user->coord_accts))
		   && (file_opts->coord_list
		       && list_count(file_opts->coord_list))) {
		list_itr_t *coord_itr = NULL;
		list_itr_t *char_itr = NULL;
		char *temp_char = NULL;
		slurmdb_coord_rec_t *coord = NULL;
		List add_list = list_create(NULL);

		coord_itr = list_iterator_create(user->coord_accts);
		char_itr = list_iterator_create(file_opts->coord_list);

		while ((temp_char = list_next(char_itr))) {
			while ((coord = list_next(coord_itr))) {
				if (!coord->direct)
					continue;
				if (!xstrcmp(coord->name, temp_char)) {
					break;
				}
			}
			if (!coord) {
				printf(" Making User '%s' coordinator of "
				       "account '%s'\n",
				       user->name,
				       temp_char);

				list_append(add_list, temp_char);
			}
			list_iterator_reset(coord_itr);
		}

		list_iterator_destroy(char_itr);
		list_iterator_destroy(coord_itr);

		if (list_count(add_list)) {
			notice_thread_init();
			(void) slurmdb_coord_add(db_conn,
						 add_list, &user_cond);
			notice_thread_fini();
			set = 1;
		}
		FREE_NULL_LIST(add_list);
	}

	if ((!user->wckey_list || !list_count(user->wckey_list))
	    && (file_opts->wckey_list
		&& list_count(file_opts->wckey_list))) {
		list_itr_t *wckey_itr = NULL;
		char *temp_char = NULL;
		slurmdb_wckey_rec_t *wckey = NULL;
		int first = 1;

		user->wckey_list = list_create(slurmdb_destroy_wckey_rec);
		wckey_itr = list_iterator_create(file_opts->wckey_list);
		printf(" Adding WCKey(s) ");
		while ((temp_char = list_next(wckey_itr))) {
			wckey = xmalloc(sizeof(slurmdb_wckey_rec_t));
			wckey->name = xstrdup(temp_char);
			wckey->cluster = xstrdup(cluster);
			wckey->user = xstrdup(user->name);
			if (!xstrcmp(wckey->name, user->default_wckey))
				wckey->is_def = 1;
			list_push(user->wckey_list, wckey);

			if (first) {
				printf("'%s'", temp_char);
				first = 0;
			} else
				printf(", '%s'", temp_char);
		}
		list_iterator_destroy(wckey_itr);
		printf(" for user '%s'\n", user->name);
		set = 1;
		notice_thread_init();
		slurmdb_wckeys_add(db_conn, user->wckey_list);
		notice_thread_fini();
	} else if ((user->wckey_list && list_count(user->wckey_list))
		   && (file_opts->wckey_list
		       && list_count(file_opts->wckey_list))) {
		list_itr_t *wckey_itr = NULL;
		list_itr_t *char_itr = NULL;
		char *temp_char = NULL;
		slurmdb_wckey_rec_t *wckey = NULL;
		List add_list = list_create(slurmdb_destroy_wckey_rec);

		wckey_itr = list_iterator_create(user->wckey_list);
		char_itr = list_iterator_create(file_opts->wckey_list);

		while ((temp_char = list_next(char_itr))) {
			while ((wckey = list_next(wckey_itr))) {
				if (!xstrcmp(wckey->name, temp_char))
					break;
			}
			if (!wckey) {
				printf(" Adding WCKey '%s' to User '%s'\n",
				       temp_char, user->name);
				wckey = xmalloc(sizeof(slurmdb_wckey_rec_t));
				wckey->name = xstrdup(temp_char);
				wckey->cluster = xstrdup(cluster);
				wckey->user = xstrdup(user->name);
				if (!xstrcmp(wckey->name, user->default_wckey))
					wckey->is_def = 1;

				list_append(add_list, wckey);
			}
			list_iterator_reset(wckey_itr);
		}

		list_iterator_destroy(char_itr);
		list_iterator_destroy(wckey_itr);

		if (list_count(add_list)) {
			notice_thread_init();
			slurmdb_wckeys_add(db_conn, add_list);
			notice_thread_fini();
			set = 1;
		}
		list_transfer(user->wckey_list, add_list);
		FREE_NULL_LIST(add_list);
	}

	FREE_NULL_LIST(assoc_cond.user_list);

	return set;
}

static slurmdb_user_rec_t *_set_user_up(sacctmgr_file_opts_t *file_opts,
					char *cluster, char *parent)
{
	slurmdb_user_rec_t *user = xmalloc(sizeof(slurmdb_user_rec_t));

	user->assoc_list = NULL;
	user->name = xstrdup(file_opts->name);

	if (file_opts->def_acct)
		user->default_acct = xstrdup(file_opts->def_acct);
	else
		user->default_acct = xstrdup(parent);

	if (file_opts->def_wckey)
		user->default_wckey = xstrdup(file_opts->def_wckey);
	else
		user->default_wckey = xstrdup("");

	user->admin_level = file_opts->admin;

	if (file_opts->coord_list) {
		slurmdb_user_cond_t user_cond;
		slurmdb_assoc_cond_t assoc_cond;
		list_itr_t *coord_itr = NULL;
		char *temp_char = NULL;
		slurmdb_coord_rec_t *coord = NULL;

		memset(&user_cond, 0, sizeof(slurmdb_user_cond_t));
		memset(&assoc_cond, 0, sizeof(slurmdb_assoc_cond_t));
		assoc_cond.user_list = list_create(NULL);
		list_append(assoc_cond.user_list, user->name);
		user_cond.assoc_cond = &assoc_cond;

		notice_thread_init();
		slurmdb_coord_add(db_conn,
				  file_opts->coord_list,
				  &user_cond);
		notice_thread_fini();
		FREE_NULL_LIST(assoc_cond.user_list);
		user->coord_accts = list_create(slurmdb_destroy_coord_rec);
		coord_itr = list_iterator_create(file_opts->coord_list);
		while ((temp_char = list_next(coord_itr))) {
			coord = xmalloc(sizeof(slurmdb_coord_rec_t));
			coord->name = xstrdup(temp_char);
			coord->direct = 1;
			list_push(user->coord_accts, coord);
		}
		list_iterator_destroy(coord_itr);
	}

	if (file_opts->wckey_list) {
		list_itr_t *wckey_itr = NULL;
		char *temp_char = NULL;
		slurmdb_wckey_rec_t *wckey = NULL;

		user->wckey_list = list_create(slurmdb_destroy_wckey_rec);
		wckey_itr = list_iterator_create(file_opts->wckey_list);
		while ((temp_char = list_next(wckey_itr))) {
			wckey = xmalloc(sizeof(slurmdb_wckey_rec_t));
			wckey->name = xstrdup(temp_char);
			wckey->user = xstrdup(user->name);
			wckey->cluster = xstrdup(cluster);
			if (!xstrcmp(wckey->name, user->default_wckey))
				wckey->is_def = 1;
			list_push(user->wckey_list, wckey);
		}
		list_iterator_destroy(wckey_itr);
		notice_thread_init();
		slurmdb_wckeys_add(db_conn, user->wckey_list);
		notice_thread_fini();
	}
	return user;
}


static slurmdb_account_rec_t *_set_acct_up(sacctmgr_file_opts_t *file_opts,
					   char *parent)
{
	slurmdb_account_rec_t *acct = xmalloc(sizeof(slurmdb_account_rec_t));
	acct->assoc_list = NULL;
	acct->name = xstrdup(file_opts->name);
	if (file_opts->desc)
		acct->description = xstrdup(file_opts->desc);
	else
		acct->description = xstrdup(file_opts->name);
	if (file_opts->org)
		acct->organization = xstrdup(file_opts->org);
	else if (xstrcmp(parent, "root"))
		acct->organization = xstrdup(parent);
	else
		acct->organization = xstrdup(file_opts->name);
	/* info("adding account %s (%s) (%s)", */
/* 		acct->name, acct->description, */
/* 		acct->organization); */

	return acct;
}

static slurmdb_assoc_rec_t *_set_assoc_up(sacctmgr_file_opts_t *file_opts,
						sacctmgr_mod_type_t mod_type,
						char *cluster, char *parent)
{
	slurmdb_assoc_rec_t *assoc = NULL;

	if (!cluster) {
		error("No cluster name was given for _set_assoc_up");
		return NULL;
	}

	if (!parent && (mod_type != MOD_CLUSTER)) {
		error("No parent was given for _set_assoc_up");
		return NULL;
	}

	assoc = xmalloc(sizeof(slurmdb_assoc_rec_t));
	slurmdb_init_assoc_rec(assoc, 0);

	switch(mod_type) {
	case MOD_CLUSTER:
		assoc->acct = xstrdup(parent);
		assoc->cluster = xstrdup(cluster);
		break;
	case MOD_ACCT:
		assoc->acct = xstrdup(file_opts->name);
		assoc->cluster = xstrdup(cluster);
		assoc->parent_acct = xstrdup(parent);
		break;
	case MOD_USER:
		assoc->acct = xstrdup(parent);
		assoc->cluster = xstrdup(cluster);
		assoc->partition = xstrdup(file_opts->assoc_rec.partition);
		assoc->user = xstrdup(file_opts->name);
		if (!xstrcmp(assoc->acct, file_opts->def_acct))
			assoc->is_def = 1;
		break;
	default:
		error("Unknown mod type for _set_assoc_up %d", mod_type);
		slurmdb_destroy_assoc_rec(assoc);
		assoc = NULL;
		break;
	}

	assoc->shares_raw = file_opts->assoc_rec.shares_raw;

	assoc->def_qos_id = file_opts->assoc_rec.def_qos_id;

	slurmdb_copy_assoc_rec_limits(assoc, &file_opts->assoc_rec);

	return assoc;
}

static int _print_file_slurmdb_hierarchical_rec_children(
	FILE *fd, List slurmdb_hierarchical_rec_list,
	List user_list, List acct_list)
{
	list_itr_t *itr = NULL;
	slurmdb_hierarchical_rec_t *slurmdb_hierarchical_rec = NULL;
	char *line = NULL;
	slurmdb_user_rec_t *user_rec = NULL;
	slurmdb_account_rec_t *acct_rec = NULL;

	itr = list_iterator_create(slurmdb_hierarchical_rec_list);
	while ((slurmdb_hierarchical_rec = list_next(itr))) {
		if (slurmdb_hierarchical_rec->assoc->user) {
			user_rec = sacctmgr_find_user_from_list(
				user_list,
				slurmdb_hierarchical_rec->assoc->user);
			line = xstrdup_printf(
				"User - '%s'",
				slurmdb_hierarchical_rec->sort_name);
			if (slurmdb_hierarchical_rec->assoc->partition)
				xstrfmtcat(line, ":Partition='%s'",
					   slurmdb_hierarchical_rec->
					   assoc->partition);
			if (user_rec) {
				xstrfmtcat(line, ":DefaultAccount='%s'",
					   user_rec->default_acct);
				if (user_rec->default_wckey
				    && user_rec->default_wckey[0])
					xstrfmtcat(line, ":DefaultWCKey='%s'",
						   user_rec->default_wckey);

				if (user_rec->admin_level > SLURMDB_ADMIN_NONE)
					xstrfmtcat(line, ":AdminLevel='%s'",
						   slurmdb_admin_level_str(
							   user_rec->
							   admin_level));
				if (user_rec->coord_accts
				    && list_count(user_rec->coord_accts)) {
					list_itr_t *itr2 = NULL;
					slurmdb_coord_rec_t *coord = NULL;
					int first_coord = 1;
					list_sort(user_rec->coord_accts,
						  (ListCmpF)sort_coord_list);
					itr2 = list_iterator_create(
						user_rec->coord_accts);
					while ((coord = list_next(itr2))) {
						/* We only care about
						 * the direct accounts here
						 */
						if (!coord->direct)
							continue;
						if (first_coord) {
							xstrfmtcat(
								line,
								":Coordinator"
								"='%s",
								coord->name);
							first_coord = 0;
						} else {
							xstrfmtcat(line, ",%s",
								   coord->name);
						}
					}
					if (!first_coord)
						xstrcat(line, "'");
					list_iterator_destroy(itr2);
				}

				if (user_rec->wckey_list
				    && list_count(user_rec->wckey_list)) {
					list_itr_t *itr2 = NULL;
					slurmdb_wckey_rec_t *wckey = NULL;
					int first_wckey = 1;
					itr2 = list_iterator_create(
						user_rec->wckey_list);
					while ((wckey = list_next(itr2))) {
						/* Avoid sending
						   non-legitimate wckeys.
						*/
						if (!wckey->name ||
						    !wckey->name[0] ||
						    wckey->name[0] == '*')
							continue;
						if (first_wckey) {
							xstrfmtcat(
								line,
								":WCKeys='%s",
								wckey->name);
							first_wckey = 0;
						} else {
							xstrfmtcat(line, ",%s",
								   wckey->name);
						}
					}
					if (!first_wckey)
						xstrcat(line, "'");
					list_iterator_destroy(itr2);
				}
			}
			if (slurmdb_hierarchical_rec->assoc->comment)
				xstrfmtcat(line, ":Comment='%s'",
					   slurmdb_hierarchical_rec->
					   assoc->comment);
		} else {
			acct_rec = sacctmgr_find_account_from_list(
				acct_list,
				slurmdb_hierarchical_rec->assoc->acct);
			line = xstrdup_printf(
				"Account - '%s'",
				slurmdb_hierarchical_rec->sort_name);
			if (acct_rec) {
				xstrfmtcat(line, ":Description='%s'",
					   acct_rec->description);
				xstrfmtcat(line, ":Organization='%s'",
					   acct_rec->organization);
			}
		}

		print_file_add_limits_to_line(&line,
					      slurmdb_hierarchical_rec->assoc);

		if (fprintf(fd, "%s\n", line) < 0) {
			exit_code=1;
			fprintf(stderr, " Can't write to file");
			xfree(line);
			return SLURM_ERROR;
		}
		info("%s", line);
		xfree(line);
	}
	list_iterator_destroy(itr);
	print_file_slurmdb_hierarchical_rec_list(fd,
						 slurmdb_hierarchical_rec_list,
						 user_list, acct_list);

	return SLURM_SUCCESS;
}

extern int print_file_add_limits_to_line(char **line,
					 slurmdb_assoc_rec_t *assoc)
{
	char *tmp_char;
	if (!assoc)
		return SLURM_ERROR;

	if (assoc->def_qos_id && (assoc->def_qos_id != NO_VAL)) {
		if (!g_qos_list)
			g_qos_list = slurmdb_qos_get(
				db_conn, NULL);
		if ((tmp_char = slurmdb_qos_str(g_qos_list, assoc->def_qos_id)))
			xstrfmtcat(*line, ":DefaultQOS='%s'", tmp_char);
	}
	if (assoc->shares_raw != INFINITE)
		xstrfmtcat(*line, ":Fairshare=%u", assoc->shares_raw);

	if (assoc->grp_tres_mins) {
		sacctmgr_initialize_g_tres_list();
		tmp_char = slurmdb_make_tres_string_from_simple(
			assoc->grp_tres_mins, g_tres_list, NO_VAL,
			CONVERT_NUM_UNIT_EXACT, 0, NULL);
		xstrfmtcat(*line, ":GrpTRESMins=%s", tmp_char);
		xfree(tmp_char);
	}

	if (assoc->grp_tres_run_mins) {
		sacctmgr_initialize_g_tres_list();
		tmp_char = slurmdb_make_tres_string_from_simple(
			assoc->grp_tres_run_mins, g_tres_list, NO_VAL,
			CONVERT_NUM_UNIT_EXACT, 0, NULL);
		xstrfmtcat(*line, ":GrpTRESRunMins=%s", tmp_char);
		xfree(tmp_char);
	}

	if (assoc->grp_tres) {
		sacctmgr_initialize_g_tres_list();
		tmp_char = slurmdb_make_tres_string_from_simple(
			assoc->grp_tres, g_tres_list, NO_VAL,
			CONVERT_NUM_UNIT_EXACT, 0, NULL);
		xstrfmtcat(*line, ":GrpTRES=%s", tmp_char);
		xfree(tmp_char);
	}

	if (assoc->grp_jobs != INFINITE)
		xstrfmtcat(*line, ":GrpJobs=%u", assoc->grp_jobs);

	if (assoc->grp_jobs_accrue != INFINITE)
		xstrfmtcat(*line, ":GrpJobsAccrue=%u", assoc->grp_jobs_accrue);

	if (assoc->grp_submit_jobs != INFINITE)
		xstrfmtcat(*line, ":GrpSubmitJobs=%u", assoc->grp_submit_jobs);

	if (assoc->grp_wall != INFINITE)
		xstrfmtcat(*line, ":GrpWall=%u", assoc->grp_wall);

	if (assoc->max_tres_mins_pj) {
		sacctmgr_initialize_g_tres_list();
		tmp_char = slurmdb_make_tres_string_from_simple(
			assoc->max_tres_mins_pj, g_tres_list, NO_VAL,
			CONVERT_NUM_UNIT_EXACT, 0, NULL);
		xstrfmtcat(*line, ":MaxTRESMinsPerJob=%s", tmp_char);
		xfree(tmp_char);
	}

	if (assoc->max_tres_run_mins) {
		sacctmgr_initialize_g_tres_list();
		tmp_char = slurmdb_make_tres_string_from_simple(
			assoc->max_tres_run_mins, g_tres_list, NO_VAL,
			CONVERT_NUM_UNIT_EXACT, 0, NULL);
		xstrfmtcat(*line, ":MaxTRESRunMins=%s", tmp_char);
		xfree(tmp_char);
	}

	if (assoc->max_tres_pj) {
		sacctmgr_initialize_g_tres_list();
		tmp_char = slurmdb_make_tres_string_from_simple(
			assoc->max_tres_pj, g_tres_list, NO_VAL,
			CONVERT_NUM_UNIT_EXACT, 0, NULL);
		xstrfmtcat(*line, ":MaxTRESPerJob=%s", tmp_char);
		xfree(tmp_char);
	}

	if (assoc->max_tres_pn) {
		sacctmgr_initialize_g_tres_list();
		tmp_char = slurmdb_make_tres_string_from_simple(
			assoc->max_tres_pn, g_tres_list, NO_VAL,
			CONVERT_NUM_UNIT_EXACT, 0, NULL);
		xstrfmtcat(*line, ":MaxTRESPerNode=%s", tmp_char);
		xfree(tmp_char);
	}

	if (assoc->max_jobs != INFINITE)
		xstrfmtcat(*line, ":MaxJobs=%u", assoc->max_jobs);

	if (assoc->max_jobs_accrue != INFINITE)
		xstrfmtcat(*line, ":MaxJobsAccrue=%u", assoc->max_jobs_accrue);

	if (assoc->max_submit_jobs != INFINITE)
		xstrfmtcat(*line, ":MaxSubmitJobs=%u", assoc->max_submit_jobs);

	if (assoc->max_wall_pj != INFINITE)
		xstrfmtcat(*line, ":MaxWallDurationPerJob=%u",
			   assoc->max_wall_pj);

	if (assoc->priority != INFINITE)
		xstrfmtcat(*line, ":Priority=%u", assoc->priority);

	if (assoc->qos_list && list_count(assoc->qos_list)) {
		char *temp_char = NULL;
		if (!g_qos_list)
			g_qos_list = slurmdb_qos_get(
				db_conn, NULL);

		temp_char = get_qos_complete_str(g_qos_list, assoc->qos_list);
		xstrfmtcat(*line, ":QOS='%s'", temp_char);
		xfree(temp_char);
	}

	return SLURM_SUCCESS;
}


extern int print_file_slurmdb_hierarchical_rec_list(
	FILE *fd,
	List slurmdb_hierarchical_rec_list,
	List user_list,
	List acct_list)
{
	list_itr_t *itr = NULL;
	slurmdb_hierarchical_rec_t *slurmdb_hierarchical_rec = NULL;

	itr = list_iterator_create(slurmdb_hierarchical_rec_list);
	while ((slurmdb_hierarchical_rec = list_next(itr))) {
/* 		info("got here %d with %d from %s %s",  */
/* 		     depth, list_count(slurmdb_hierarchical_rec->children), */
/* 		     slurmdb_hierarchical_rec->assoc->acct,
		     slurmdb_hierarchical_rec->assoc->user); */
		if (!list_count(slurmdb_hierarchical_rec->children))
			continue;
		if (fprintf(fd, "Parent - '%s'\n",
			    slurmdb_hierarchical_rec->assoc->acct) < 0) {
			error("Can't write to file");
			return SLURM_ERROR;
		}
		info("%s - '%s'", "Parent",
		     slurmdb_hierarchical_rec->assoc->acct);
/* 		info("sending %d from %s", */
/* 		     list_count(slurmdb_hierarchical_rec->children), */
/* 		     slurmdb_hierarchical_rec->assoc->acct); */
		_print_file_slurmdb_hierarchical_rec_children(
			fd, slurmdb_hierarchical_rec->children,
			user_list, acct_list);
	}
	list_iterator_destroy(itr);

	return SLURM_SUCCESS;
}

extern void load_sacctmgr_cfg_file (int argc, char **argv)
{
	DEF_TIMERS;
	char line[BUFFER_SIZE];
	FILE *fd = NULL;
	char *parent = NULL;
	char *file_name = NULL;
	char *cluster_name = NULL;
	char *user_name = NULL;
	char object[25];
	int start = 0, len = 0, i = 0;
	int lc=0, num_lines=0;
	int start_clean=0;
	int cluster_name_set=0;
	int rc = SLURM_SUCCESS;

	sacctmgr_file_opts_t *file_opts = NULL;
	slurmdb_assoc_rec_t *assoc = NULL, *assoc2 = NULL;
	slurmdb_account_rec_t *acct = NULL, *acct2 = NULL;
	slurmdb_cluster_rec_t *cluster = NULL;
	slurmdb_user_rec_t *user = NULL, *user2 = NULL;
	slurmdb_user_cond_t user_cond;

	List curr_assoc_list = NULL;
	List curr_acct_list = NULL;
	List curr_cluster_list = NULL;
	List curr_user_list = NULL;

	/* This will be freed in their local counter parts */
	List mod_acct_list = NULL;
	List acct_list = NULL;
	List slurmdb_assoc_list = NULL;
	List mod_user_list = NULL;
	List user_list = NULL;
	List user_assoc_list = NULL;
	List mod_assoc_list = NULL;

	list_itr_t *itr;
	list_itr_t *itr2;

	List print_fields_list;
	List format_list = NULL;
	print_field_t *field = NULL;

	int set = 0, command_len = 0;

	if (readonly_flag) {
		exit_code = 1;
		fprintf(stderr, "Can't run this command in readonly mode.\n");
		return;
	}

	/* reset the connection to get the most recent stuff */
	slurmdb_connection_commit(db_conn, 0);

	for (i = 0; i < argc; i++) {
		int end = parse_option_end(argv[i]);
		if (!end)
			command_len=strlen(argv[i]);
		else {
			command_len=end-1;
			if (argv[i][end] == '=') {
				end++;
			}
		}
		if (!end && !xstrncasecmp(argv[i], "clean",
					  MAX(command_len, 3))) {
			start_clean = 1;
		} else if (!end || !xstrncasecmp(argv[i], "File",
						 MAX(command_len, 1))) {
			if (file_name) {
				exit_code=1;
				fprintf(stderr,
					" File name already set to %s\n",
					file_name);
				continue;
			}
			file_name = xstrdup(argv[i]+end);
		} else if (!xstrncasecmp(argv[i], "Cluster",
					 MAX(command_len, 3))) {
			if (cluster_name) {
				exit_code=1;
				fprintf(stderr,
					" Can only do one cluster at a time.  "
					"Already doing %s\n", cluster_name);
				continue;
			}
			cluster_name = xstrdup(argv[i]+end);
			cluster_name_set = 1;
		} else {
			exit_code=1;
			fprintf(stderr, " Unknown option: %s\n", argv[i]);
		}
	}

	if (!file_name) {
		exit_code = 1;
		xfree(cluster_name);
		fprintf(stderr,
			" No filename given, specify one with file=''\n");
		return;

	}

	fd = fopen(file_name, "r");
	xfree(file_name);
	if (fd == NULL) {
		exit_code = 1;
		fprintf(stderr, " Unable to read \"%s\": %s\n", argv[0],
			slurm_strerror(errno));
		xfree(cluster_name);
		return;
	}

	curr_acct_list = slurmdb_accounts_get(db_conn, NULL);

	/* These are new info so they need to be freed here */
	acct_list = list_create(slurmdb_destroy_account_rec);
	slurmdb_assoc_list = list_create(slurmdb_destroy_assoc_rec);
	user_list = list_create(slurmdb_destroy_user_rec);
	user_assoc_list = list_create(slurmdb_destroy_assoc_rec);

	mod_acct_list = list_create(slurmdb_destroy_account_rec);
	mod_user_list = list_create(slurmdb_destroy_user_rec);
	mod_assoc_list = list_create(slurmdb_destroy_assoc_rec);

	format_list = list_create(xfree_ptr);

	while ((num_lines = _get_next_line(line, BUFFER_SIZE, fd)) > 0) {
		lc += num_lines;
		/* skip empty lines */
		if (line[0] == '\0') {
			continue;
		}
		len = strlen(line);

		memset(object, 0, sizeof(object));

		/* first find the object */
		start = 0;
		for (i = 0; i < len; i++) {
			if (line[i] == '-') {
				start = i;
				if (line[i-1] == ' ')
					i--;
				if (i < sizeof(object)) {
					i++;	/* Append '\0' */
					strlcpy(object, line, i);
				}
				break;
			}
		}
		if (!object[0])
			continue;

		while ((line[start] != ' ') && (start < len))
			start++;
		if (start >= len) {
			exit_code=1;
			fprintf(stderr, " Nothing after object "
				"name '%s'. line(%d)\n",
				object, lc);
			rc = SLURM_ERROR;
			break;
		}
		start++;

		if (!xstrcasecmp("Machine", object)
		    || !xstrcasecmp("Cluster", object)) {
			slurmdb_assoc_cond_t assoc_cond;

			if (cluster_name && !cluster_name_set) {
				exit_code = 1;
				fprintf(stderr, " You can only add one cluster "
					"at a time.\n");
				rc = SLURM_ERROR;
				break;
			}

			file_opts = _parse_options(line + start, true);

			if (!file_opts) {
				exit_code = 1;
				fprintf(stderr,
					" error: Problem with line(%d)\n", lc);
				rc = SLURM_ERROR;
				break;
			}

			if (!cluster_name_set)
				cluster_name = xstrdup(file_opts->name);

			/* we have to do this here since this is the
			   first place we have the cluster_name
			*/
			memset(&user_cond, 0, sizeof(slurmdb_user_cond_t));
			user_cond.with_coords = 1;
			user_cond.with_assocs = 1;
			user_cond.with_wckeys = 1;

			memset(&assoc_cond, 0,
			       sizeof(slurmdb_assoc_cond_t));
			assoc_cond.cluster_list = list_create(NULL);
			assoc_cond.with_raw_qos = 1;
			assoc_cond.without_parent_limits = 1;
			list_append(assoc_cond.cluster_list, cluster_name);
			user_cond.assoc_cond = &assoc_cond;
			curr_user_list = slurmdb_users_get(db_conn, &user_cond);

			user_cond.assoc_cond = NULL;
			assoc_cond.only_defs = 0;

			/* make sure this person running is an admin */
			user_name = uid_to_string_cached(my_uid);
			if (!(user = sacctmgr_find_user_from_list(
				      curr_user_list, user_name))) {
				exit_code =1;
				fprintf(stderr, " Your uid (%u) is not in the "
					"accounting system, can't load file.\n",
					my_uid);
				FREE_NULL_LIST(curr_user_list);
				fclose(fd);
				xfree(cluster_name);
				xfree(parent);
				goto end_it;

			} else {
				if ((my_uid != slurm_conf.slurm_user_id)
				    && my_uid != 0
				    && (user->admin_level
					< SLURMDB_ADMIN_SUPER_USER)) {
					exit_code = 1;
					fprintf(stderr,
						" Your user does not have "
						"sufficient "
						"privileges to load files.\n");
					FREE_NULL_LIST(curr_user_list);
					fclose(fd);
					xfree(cluster_name);
					xfree(parent);
					goto end_it;
				}
			}
			xfree(user_name);

			if (start_clean) {
				slurmdb_cluster_cond_t cluster_cond;
				List ret_list = NULL;

				if (!commit_check("You requested to flush "
						  "the cluster before "
						  "adding it again.\n"
						  "Are you sure you want "
						  "to continue?")) {
					printf("Aborted\n");
					break;
				}

				slurmdb_init_cluster_cond(&cluster_cond, 0);
				cluster_cond.cluster_list = list_create(NULL);
				list_append(cluster_cond.cluster_list,
					    cluster_name);

				notice_thread_init();
				ret_list = slurmdb_clusters_remove(
					db_conn, &cluster_cond);
				notice_thread_fini();
				FREE_NULL_LIST(cluster_cond.cluster_list);

				if (!ret_list) {
					exit_code=1;
					fprintf(stderr, " There was a problem "
						"removing the cluster.\n");
					rc = SLURM_ERROR;
					break;
				}
				/* This needs to be committed or
				   problems may arise */
				slurmdb_connection_commit(db_conn, 1);
			}
			curr_cluster_list = slurmdb_clusters_get(
				db_conn, NULL);

			if (cluster_name)
				printf("For cluster %s\n", cluster_name);

			if (!(cluster = sacctmgr_find_cluster_from_list(
				      curr_cluster_list, cluster_name))) {
				List temp_assoc_list = list_create(NULL);
				List cluster_list = list_create(
					slurmdb_destroy_cluster_rec);

				cluster = xmalloc(
					sizeof(slurmdb_cluster_rec_t));
				slurmdb_init_cluster_rec(cluster, 0);
				list_append(cluster_list, cluster);
				cluster->name = xstrdup(cluster_name);
				if (file_opts->classification) {
					cluster->classification =
						file_opts->classification;
					printf("Classification: %s\n",
					       get_classification_str(
						       cluster->
						       classification));
				}

				cluster->root_assoc = _set_assoc_up(
					file_opts, MOD_CLUSTER,
					cluster_name, "root");
				list_append(temp_assoc_list,
					    cluster->root_assoc);

				(void) _print_out_assoc(temp_assoc_list, 0, 0);
				FREE_NULL_LIST(temp_assoc_list);
				notice_thread_init();

				rc = slurmdb_clusters_add(
					db_conn, cluster_list);
				notice_thread_fini();
				FREE_NULL_LIST(cluster_list);

				if (rc != SLURM_SUCCESS) {
					exit_code = 1;
					fprintf(stderr,
						" Problem adding cluster: %s\n",
						slurm_strerror(rc));
					rc = SLURM_ERROR;
					_destroy_sacctmgr_file_opts(file_opts);
					file_opts = NULL;
					break;
				}
				/* This needs to be committed or
				   problems may arise */
				slurmdb_connection_commit(db_conn, 1);
				set = 1;
			} else {
				set = _mod_cluster(file_opts,
						   cluster, parent);
			}

			_destroy_sacctmgr_file_opts(file_opts);
			file_opts = NULL;

			/* assoc_cond if set up above */
			curr_assoc_list = slurmdb_associations_get(
				db_conn, &assoc_cond);
			FREE_NULL_LIST(assoc_cond.cluster_list);

			if (!curr_assoc_list) {
				exit_code = 1;
				fprintf(stderr, " Problem getting assocs "
					"for this cluster\n");
				rc = SLURM_ERROR;
				break;
			}
			//info("got %d assocs", list_count(curr_assoc_list));
			continue;
		} else if (!cluster_name) {
			exit_code = 1;
			fprintf(stderr, " You need to specify a cluster name "
				"first with 'Cluster - $NAME' in your file\n");
			break;
		}

		if (!xstrcasecmp("Parent", object)) {
			file_opts = _parse_options(line + start, true);
			xfree(parent);

			if (!file_opts) {
				exit_code = 1;
				fprintf(stderr, " Problem with line(%d)\n", lc);
				rc = SLURM_ERROR;
				break;
			}

			parent = xstrdup(file_opts->name);
			//info("got parent %s", parent);
			if (!sacctmgr_find_account_base_assoc_from_list(
				    curr_assoc_list, parent, cluster_name)
			    && !sacctmgr_find_account_base_assoc_from_list(
				    slurmdb_assoc_list, parent, cluster_name)) {
				exit_code=1;
				fprintf(stderr, " line(%d) You need to add "
					"this parent (%s) as a child before "
					"you can add children to it.\n",
					lc, parent);
				break;
			}
			_destroy_sacctmgr_file_opts(file_opts);
			file_opts = NULL;
			continue;
		} else if (!parent) {
			parent = xstrdup("root");
			printf(" No parent given creating off root, "
			       "If incorrect specify 'Parent - name' "
			       "before any children in your file\n");
		}

		if (!xstrcasecmp("Project", object)
		    || !xstrcasecmp("Account", object)) {
			file_opts = _parse_options(line + start, true);

			if (!file_opts) {
				exit_code=1;
				fprintf(stderr, " Problem with line(%d)\n", lc);
				rc = SLURM_ERROR;
				break;
			}

			//info("got a project %s of %s", file_opts->name, parent);

			acct = sacctmgr_find_account_from_list(
				curr_acct_list, file_opts->name);
			if (!acct)
				acct = sacctmgr_find_account_from_list(
					acct_list, file_opts->name);

			if (!acct) {
				acct = _set_acct_up(file_opts, parent);
				list_append(acct_list, acct);
				/* don't add anything to the
				   curr_acct_list */

				assoc = _set_assoc_up(file_opts, MOD_ACCT,
						      cluster_name, parent);

				list_append(slurmdb_assoc_list, assoc);
				/* don't add anything to the
				   curr_assoc_list */
			} else if (!(assoc =
				     sacctmgr_find_account_base_assoc_from_list(
					     curr_assoc_list, file_opts->name,
					     cluster_name)) &&
				   !sacctmgr_find_account_base_assoc_from_list(
					   slurmdb_assoc_list, file_opts->name,
					   cluster_name)) {
				acct2 = sacctmgr_find_account_from_list(
					mod_acct_list, file_opts->name);

				if (!acct2) {
					acct2 = xmalloc(
						sizeof(slurmdb_account_rec_t));
					list_append(mod_acct_list, acct2);
					acct2->name = xstrdup(file_opts->name);
					if (_mod_acct(file_opts, acct, parent))
						set = 1;
				} else {
					debug2("already modified this account");
				}

				assoc = _set_assoc_up(file_opts, MOD_ACCT,
						      cluster_name, parent);

				list_append(slurmdb_assoc_list, assoc);
				/* don't add anything to the
				   curr_assoc_list */
			} else if (assoc) {
				acct2 = sacctmgr_find_account_from_list(
					mod_acct_list, file_opts->name);

				if (!acct2) {
					acct2 = xmalloc(
						sizeof(slurmdb_account_rec_t));
					list_append(mod_acct_list, acct2);
					acct2->name = xstrdup(file_opts->name);
					if (_mod_acct(file_opts, acct, parent))
						set = 1;
				} else {
					debug2("already modified this account");
				}

				assoc2 = sacctmgr_find_assoc_from_list(
					mod_assoc_list,
					NULL, file_opts->name,
					cluster_name,
					NULL);

				if (!assoc2) {
					assoc2 = xmalloc(
						sizeof(slurmdb_assoc_rec_t));
					slurmdb_init_assoc_rec(assoc2, 0);
					list_append(mod_assoc_list, assoc2);
					assoc2->cluster = xstrdup(cluster_name);
					assoc2->acct = xstrdup(file_opts->name);
					assoc2->parent_acct =
						xstrdup(assoc->parent_acct);
					if (_mod_assoc(file_opts,
						       assoc, MOD_ACCT, parent))
						set = 1;
				} else {
					debug2("already modified this assoc");
				}
			}
			_destroy_sacctmgr_file_opts(file_opts);
			file_opts = NULL;
			continue;
		} else if (!xstrcasecmp("User", object)) {
			file_opts = _parse_options(line + start,
						   user_case_norm);

			if (!file_opts) {
				exit_code=1;
				fprintf(stderr, " Problem with line(%d)\n", lc);
				rc = SLURM_ERROR;
				break;
			}

			if (!(user = sacctmgr_find_user_from_list(
				      curr_user_list, file_opts->name))
			    && !sacctmgr_find_user_from_list(
				    user_list, file_opts->name)) {

				user = _set_user_up(file_opts, cluster_name,
						    parent);
				list_append(user_list, user);
				/* don't add anything to the
				   curr_user_list */

				assoc = _set_assoc_up(file_opts, MOD_USER,
						      cluster_name, parent);

				list_append(user_assoc_list, assoc);
				/* don't add anything to the
				   curr_assoc_list */
			} else if (!(assoc =
				     sacctmgr_find_assoc_from_list(
					     curr_assoc_list,
					     file_opts->name, parent,
					     cluster_name,
					     file_opts->assoc_rec.partition))
				   && !sacctmgr_find_assoc_from_list(
					   user_assoc_list,
					   file_opts->name, parent,
					   cluster_name,
					   file_opts->assoc_rec.partition)) {

				/* This means the user was added
				 * during this round but this is a new
				 * association we are adding
				 */
				if (!user)
					goto new_assoc;

				/* This means there could be a change
				 * on the user.
				 */
				user2 = sacctmgr_find_user_from_list(
					mod_user_list, file_opts->name);
				if (!user2) {
					user2 = xmalloc(
						sizeof(slurmdb_user_rec_t));
					list_append(mod_user_list, user2);
					user2->name = xstrdup(file_opts->name);
					if (_mod_user(file_opts, user,
						      cluster_name, parent))
						set = 1;
				} else {
					debug2("already modified this user");
				}
			new_assoc:
				assoc = _set_assoc_up(file_opts, MOD_USER,
						      cluster_name, parent);

				list_append(user_assoc_list, assoc);
				/* don't add anything to the
				   curr_assoc_list */
			} else if (assoc) {
				user2 = sacctmgr_find_user_from_list(
					mod_user_list, file_opts->name);
				if (!user2) {
					user2 = xmalloc(
						sizeof(slurmdb_user_rec_t));
					list_append(mod_user_list, user2);
					user2->name = xstrdup(file_opts->name);
					if (_mod_user(file_opts, user,
						      cluster_name, parent))
						set = 1;
				} else {
					debug2("already modified this user");
				}

				assoc2 = sacctmgr_find_assoc_from_list(
					mod_assoc_list,
					file_opts->name, parent,
					cluster_name,
					file_opts->assoc_rec.partition);

				if (!assoc2) {
					assoc2 = xmalloc(
						sizeof(slurmdb_assoc_rec_t));
					slurmdb_init_assoc_rec(assoc2, 0);
					list_append(mod_assoc_list, assoc2);
					assoc2->cluster = xstrdup(cluster_name);
					assoc2->acct = xstrdup(parent);
					assoc2->user = xstrdup(file_opts->name);
					assoc2->partition = xstrdup(
						file_opts->assoc_rec.partition);
					if (_mod_assoc(file_opts,
						       assoc, MOD_USER, parent))
						set = 1;
				} else {
					debug2("already modified this assoc");
				}
			}
			//info("got a user %s", file_opts->name);
			_destroy_sacctmgr_file_opts(file_opts);
			file_opts = NULL;
			continue;
		} else {
			exit_code = 1;
			fprintf(stderr,
				" Misformatted line(%d): %s\n", lc, line);
			rc = SLURM_ERROR;
			break;
		}
	}
	fclose(fd);
	xfree(cluster_name);
	xfree(parent);

	START_TIMER;
	if (rc == SLURM_SUCCESS && list_count(acct_list)) {
		printf("Accounts\n");
		slurm_addto_char_list(format_list,
				      "Name,Description,Organization,QOS");

		print_fields_list = sacctmgr_process_format_list(format_list);
		list_flush(format_list);

		print_fields_header(print_fields_list);

		itr = list_iterator_create(acct_list);
		itr2 = list_iterator_create(print_fields_list);
		while ((acct = list_next(itr))) {
			while ((field = list_next(itr2))) {
				switch(field->type) {
				case PRINT_DESC:
					field->print_routine(
						field, acct->description, 0);
					break;
				case PRINT_NAME:
					field->print_routine(
						field, acct->name, 0);
					break;
				case PRINT_ORG:
					field->print_routine(
						field, acct->organization, 0);
					break;
				default:
					field->print_routine(field, NULL, 0);
					break;
				}
			}
			list_iterator_reset(itr2);
			printf("\n");
		}
		list_iterator_destroy(itr);
		list_iterator_destroy(itr2);
		FREE_NULL_LIST(print_fields_list);
		rc = slurmdb_accounts_add(db_conn, acct_list);
		printf("-----------------------------"
		       "----------------------\n\n");
		set = 1;
	}

	if (rc == SLURM_SUCCESS && list_count(slurmdb_assoc_list)) {
		printf("Account Associations\n");
		rc = _print_out_assoc(slurmdb_assoc_list, 0, 1);
		set = 1;
	}
	if (rc == SLURM_SUCCESS && list_count(user_list)) {
		printf("Users\n");

		slurm_addto_char_list(format_list,
				      "Name,DefaultA,DefaultW,QOS,Admin,Coord");

		print_fields_list = sacctmgr_process_format_list(format_list);
		list_flush(format_list);
		print_fields_header(print_fields_list);

		itr = list_iterator_create(user_list);
		itr2 = list_iterator_create(print_fields_list);
		while ((user = list_next(itr))) {
			while ((field = list_next(itr2))) {
				switch(field->type) {
				case PRINT_ADMIN:
					field->print_routine(
						field,
						slurmdb_admin_level_str(
							user->admin_level),
						0);
					break;
				case PRINT_COORDS:
					field->print_routine(
						field,
						&user->coord_accts,
						0);
					break;
				case PRINT_DACCT:
					field->print_routine(
						field,
						user->default_acct,
						0);
					break;
				case PRINT_DWCKEY:
					field->print_routine(
						field,
						user->default_wckey,
						0);
					break;
				case PRINT_NAME:
					field->print_routine(
						field, user->name, 0);
					break;
				case PRINT_WCKEYS:
					field->print_routine(
						field, &user->wckey_list, 0);
					break;
				default:
					field->print_routine(field, NULL, 0);
					break;
				}
			}
			list_iterator_reset(itr2);
			printf("\n");
		}
		list_iterator_destroy(itr);
		list_iterator_destroy(itr2);
		FREE_NULL_LIST(print_fields_list);

		rc = slurmdb_users_add(db_conn, user_list);
		printf("---------------------------"
		       "------------------------\n\n");
		set = 1;
	}

	if (rc == SLURM_SUCCESS && list_count(user_assoc_list)) {
		printf("User Associations\n");
		rc = _print_out_assoc(user_assoc_list, 1, 1);
		set = 1;
	}
	END_TIMER2("add cluster");

	if (set)
		info("Done adding cluster in %s", TIME_STR);

	if (rc == SLURM_SUCCESS) {
		if (set) {
			if (commit_check("Would you like to commit changes?")) {
				slurmdb_connection_commit(db_conn, 1);
			} else {
				printf(" Changes Discarded\n");
				slurmdb_connection_commit(db_conn, 0);
			}
		} else {
			printf(" Nothing new added.\n");
		}
	} else {
		exit_code=1;
		fprintf(stderr, " Problem with requests: %s\n",
			slurm_strerror(rc));
	}

end_it:
	FREE_NULL_LIST(format_list);
	FREE_NULL_LIST(mod_acct_list);
	FREE_NULL_LIST(acct_list);
	FREE_NULL_LIST(slurmdb_assoc_list);
	FREE_NULL_LIST(mod_user_list);
	FREE_NULL_LIST(user_list);
	FREE_NULL_LIST(user_assoc_list);
	FREE_NULL_LIST(mod_assoc_list);
	FREE_NULL_LIST(curr_acct_list);
	FREE_NULL_LIST(curr_assoc_list);
	FREE_NULL_LIST(curr_cluster_list);
	FREE_NULL_LIST(curr_user_list);
	_destroy_sacctmgr_file_opts(file_opts);
}
