1 /*****************************************************************************\
2  *  archive_functions.c - functions dealing with archive in the
3  *                        accounting system.
4  *****************************************************************************
5  *  Copyright (C) 2008 Lawrence Livermore National Security.
6  *  Copyright (C) 2002-2007 The Regents of the University of California.
7  *  Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
8  *  Written by Danny Auble <da@llnl.gov>
9  *  CODE-OCEC-09-009. All rights reserved.
10  *
11  *  This file is part of Slurm, a resource management program.
12  *  For details, see <https://slurm.schedmd.com/>.
13  *  Please also read the included file: DISCLAIMER.
14  *
15  *  Slurm is free software; you can redistribute it and/or modify it under
16  *  the terms of the GNU General Public License as published by the Free
17  *  Software Foundation; either version 2 of the License, or (at your option)
18  *  any later version.
19  *
20  *  In addition, as a special exception, the copyright holders give permission
21  *  to link the code of portions of this program with the OpenSSL library under
22  *  certain conditions as described in each individual source file, and
23  *  distribute linked combinations including the two. You must obey the GNU
24  *  General Public License in all respects for all of the code used other than
25  *  OpenSSL. If you modify file(s) with this exception, you may extend this
26  *  exception to your version of the file(s), but you are not obligated to do
27  *  so. If you do not wish to do so, delete this exception statement from your
28  *  version.  If you delete this exception statement from all source files in
29  *  the program, then also delete it here.
30  *
31  *  Slurm is distributed in the hope that it will be useful, but WITHOUT ANY
32  *  WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
33  *  FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
34  *  details.
35  *
36  *  You should have received a copy of the GNU General Public License along
37  *  with Slurm; if not, write to the Free Software Foundation, Inc.,
38  *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA.
39 \*****************************************************************************/
40 
41 #include <sys/stat.h>
42 
43 #include "src/sacctmgr/sacctmgr.h"
44 #include <sys/param.h>		/* MAXPATHLEN */
45 #include "src/common/proc_args.h"
46 #include "src/common/uid.h"
47 #include "src/common/util-net.h"
48 
_string_to_uid(char * name)49 static char *_string_to_uid( char *name )
50 {
51 	uid_t uid;
52 	if ( uid_from_string( name, &uid ) != 0 ) {
53 		fprintf(stderr, "Invalid user id: %s\n", name);
54 		exit(1);
55 	}
56 	xfree(name);
57 	return xstrdup_printf( "%d", (int) uid );
58 }
59 
60 /* returns number of objects added to list */
_addto_uid_char_list(List char_list,char * names)61 extern int _addto_uid_char_list(List char_list, char *names)
62 {
63 	int i=0, start=0;
64 	char *name = NULL, *tmp_char = NULL;
65 	ListIterator itr = NULL;
66 	char quote_c = '\0';
67 	int quote = 0;
68 	int count = 0;
69 
70 	if (!char_list) {
71 		error("No list was given to fill in");
72 		return 0;
73 	}
74 
75 	itr = list_iterator_create(char_list);
76 	if (names) {
77 		if (names[i] == '\"' || names[i] == '\'') {
78 			quote_c = names[i];
79 			quote = 1;
80 			i++;
81 		}
82 		start = i;
83 		while(names[i]) {
84 			//info("got %d - %d = %d", i, start, i-start);
85 			if (quote && names[i] == quote_c)
86 				break;
87 			else if (names[i] == '\"' || names[i] == '\'')
88 				names[i] = '`';
89 			else if (names[i] == ',') {
90 				if ((i-start) > 0) {
91 					name = xmalloc((i-start+1));
92 					memcpy(name, names+start, (i-start));
93 					//info("got %s %d", name, i-start);
94 					name = _string_to_uid( name );
95 
96 					while((tmp_char = list_next(itr))) {
97 						if (!xstrcasecmp(tmp_char,
98 								 name))
99 							break;
100 					}
101 
102 					if (!tmp_char) {
103 						list_append(char_list, name);
104 						count++;
105 					} else
106 						xfree(name);
107 					list_iterator_reset(itr);
108 				}
109 				i++;
110 				start = i;
111 				if (!names[i]) {
112 					info("There is a problem with "
113 					     "your request.  It appears you "
114 					     "have spaces inside your list.");
115 					break;
116 				}
117 			}
118 			i++;
119 		}
120 		if ((i-start) > 0) {
121 			name = xmalloc((i-start)+1);
122 			memcpy(name, names+start, (i-start));
123 			name = _string_to_uid( name );
124 
125 			while((tmp_char = list_next(itr))) {
126 				if (!xstrcasecmp(tmp_char, name))
127 					break;
128 			}
129 
130 			if (!tmp_char) {
131 				list_append(char_list, name);
132 				count++;
133 			} else
134 				xfree(name);
135 		}
136 	}
137 	list_iterator_destroy(itr);
138 	return count;
139 }
140 
_set_cond(int * start,int argc,char ** argv,slurmdb_archive_cond_t * arch_cond)141 static int _set_cond(int *start, int argc, char **argv,
142 		     slurmdb_archive_cond_t *arch_cond)
143 {
144 	int i;
145 	int set = 0;
146 	int end = 0;
147 	int command_len = 0;
148  	uint32_t tmp;
149 	slurmdb_job_cond_t *job_cond = NULL;
150 
151 	if (!arch_cond) {
152 		error("No arch_cond given");
153 		return -1;
154 	}
155 	if (!arch_cond->job_cond)
156 		arch_cond->job_cond = xmalloc(sizeof(slurmdb_job_cond_t));
157 	job_cond = arch_cond->job_cond;
158 
159 	for (i=(*start); i<argc; i++) {
160 		end = parse_option_end(argv[i]);
161 		if (!end)
162 			command_len=strlen(argv[i]);
163 		else {
164 			command_len=end-1;
165 			if (argv[i][end] == '=') {
166 				end++;
167 			}
168 		}
169 
170 		if (!end && !xstrncasecmp(argv[i], "where",
171 					MAX(command_len, 5))) {
172 			continue;
173 		} else if (!end && !xstrncasecmp(argv[i], "events",
174 					  MAX(command_len, 1))) {
175 			arch_cond->purge_event |= SLURMDB_PURGE_ARCHIVE;
176 			set = 1;
177 		} else if (!end && !xstrncasecmp(argv[i], "jobs",
178 					  MAX(command_len, 1))) {
179 			arch_cond->purge_job |= SLURMDB_PURGE_ARCHIVE;
180 			set = 1;
181 		} else if (!end && !xstrncasecmp(argv[i], "reservations",
182 					  MAX(command_len, 1))) {
183 			arch_cond->purge_resv |= SLURMDB_PURGE_ARCHIVE;
184 			set = 1;
185 		} else if (!end && !xstrncasecmp(argv[i], "steps",
186 					  MAX(command_len, 1))) {
187 			arch_cond->purge_step |= SLURMDB_PURGE_ARCHIVE;
188 			set = 1;
189 		} else if (!end && !xstrncasecmp(argv[i], "suspend",
190 					  MAX(command_len, 1))) {
191 			arch_cond->purge_suspend |= SLURMDB_PURGE_ARCHIVE;
192 			set = 1;
193 		} else if (!end && !xstrncasecmp(argv[i], "txn",
194 					  MAX(command_len, 1))) {
195 			arch_cond->purge_txn |= SLURMDB_PURGE_ARCHIVE;
196 			set = 1;
197 		} else if (!end && !xstrncasecmp(argv[i], "usage",
198 					  MAX(command_len, 1))) {
199 			arch_cond->purge_usage |= SLURMDB_PURGE_ARCHIVE;
200 			set = 1;
201 		} else if (!end
202 			  || !xstrncasecmp(argv[i], "Clusters",
203 					  MAX(command_len, 1))) {
204 			if (!job_cond->cluster_list)
205 				job_cond->cluster_list = list_create(xfree_ptr);
206 			slurm_addto_char_list(job_cond->cluster_list,
207 					      argv[i]+end);
208 			set = 1;
209 		} else if (!xstrncasecmp(argv[i], "Accounts",
210 					 MAX(command_len, 2))) {
211 			if (!job_cond->acct_list)
212 				job_cond->acct_list = list_create(xfree_ptr);
213 			slurm_addto_char_list(job_cond->acct_list,
214 					      argv[i]+end);
215 			set = 1;
216 		} else if (!xstrncasecmp(argv[i], "Associations",
217 					 MAX(command_len, 2))) {
218 			if (!job_cond->associd_list)
219 				job_cond->associd_list = list_create(xfree_ptr);
220 			slurm_addto_char_list(job_cond->associd_list,
221 					      argv[i]+end);
222 			set = 1;
223 		} else if (!xstrncasecmp(argv[i], "Directory",
224 					 MAX(command_len, 2))) {
225 			arch_cond->archive_dir =
226 				strip_quotes(argv[i]+end, NULL, 0);
227 			set = 1;
228 		} else if (!xstrncasecmp(argv[i], "End", MAX(command_len, 1))) {
229 			job_cond->usage_end = parse_time(argv[i]+end, 1);
230 			set = 1;
231 		} else if (!xstrncasecmp(argv[i], "Gid", MAX(command_len, 2))) {
232 			if (!job_cond->groupid_list)
233 				job_cond->groupid_list = list_create(xfree_ptr);
234 			slurm_addto_char_list(job_cond->groupid_list,
235 					      argv[i]+end);
236 			set = 1;
237 		} else if (!xstrncasecmp(argv[i], "Jobs",
238 					 MAX(command_len, 1))) {
239 			char *end_char = NULL, *start_char = argv[i] + end;
240 			slurmdb_selected_step_t *selected_step = NULL;
241 			char *dot = NULL;
242 			if (!job_cond->step_list)
243 				job_cond->step_list = list_create(xfree_ptr);
244 
245 			while ((end_char = strstr(start_char, ","))) {
246 				end_char[0] = '\0';
247 				while (isspace(start_char[0]))
248 					start_char++;  /* discard whitespace */
249 				if (start_char[0] == '\0')
250 					continue;
251 				selected_step = xmalloc(
252 					sizeof(slurmdb_selected_step_t));
253 				selected_step->array_task_id = NO_VAL;
254 				selected_step->het_job_offset = NO_VAL;
255 				list_append(job_cond->step_list, selected_step);
256 
257 				dot = strstr(start_char, ".");
258 				if (dot == NULL) {
259 					debug2("No jobstep requested");
260 					selected_step->stepid = NO_VAL;
261 				} else {
262 					*dot++ = 0;
263 					selected_step->stepid = atoi(dot);
264 				}
265 				selected_step->jobid = atoi(start_char);
266 				start_char = end_char + 1;
267 			}
268 
269 			set = 1;
270 		} else if (!xstrncasecmp(argv[i], "Partitions",
271 					 MAX(command_len, 2))) {
272 			if (!job_cond->partition_list)
273 				job_cond->partition_list =
274 					list_create(xfree_ptr);
275 			slurm_addto_char_list(job_cond->partition_list,
276 					      argv[i]+end);
277 			set = 1;
278 		} else if (!xstrncasecmp(argv[i], "PurgeEventAfter",
279 					 MAX(command_len, 10))) {
280 			if ((tmp = slurmdb_parse_purge(argv[i]+end))
281 			    == NO_VAL) {
282 				exit_code = 1;
283 			} else {
284 				arch_cond->purge_event |= tmp;
285 				set = 1;
286 			}
287 		} else if (!xstrncasecmp(argv[i], "PurgeJobAfter",
288 					 MAX(command_len, 10))) {
289 			if ((tmp = slurmdb_parse_purge(argv[i]+end))
290 			    == NO_VAL) {
291 				exit_code = 1;
292 			} else {
293 				arch_cond->purge_job |= tmp;
294 				set = 1;
295 			}
296 		} else if (!xstrncasecmp(argv[i], "PurgeResvAfter",
297 					 MAX(command_len, 10))) {
298 			if ((tmp = slurmdb_parse_purge(argv[i]+end))
299 			    == NO_VAL) {
300 				exit_code = 1;
301 			} else {
302 				arch_cond->purge_resv |= tmp;
303 				set = 1;
304 			}
305 		} else if (!xstrncasecmp(argv[i], "PurgeStepAfter",
306 					 MAX(command_len, 10))) {
307 			if ((tmp = slurmdb_parse_purge(argv[i]+end))
308 			    == NO_VAL) {
309 				exit_code = 1;
310 			} else {
311 				arch_cond->purge_step |= tmp;
312 				set = 1;
313 			}
314 		} else if (!xstrncasecmp(argv[i], "PurgeSuspendAfter",
315 					 MAX(command_len, 10))) {
316 			if ((tmp = slurmdb_parse_purge(argv[i]+end))
317 			    == NO_VAL) {
318 				exit_code = 1;
319 			} else {
320 				arch_cond->purge_suspend |= tmp;
321 				set = 1;
322 			}
323 		} else if (!xstrncasecmp(argv[i], "PurgeTXNAfter",
324 					 MAX(command_len, 10))) {
325 			if ((tmp = slurmdb_parse_purge(argv[i]+end))
326 			    == NO_VAL) {
327 				exit_code = 1;
328 			} else {
329 				arch_cond->purge_txn |= tmp;
330 				set = 1;
331 			}
332 		} else if (!xstrncasecmp(argv[i], "PurgeUsageAfter",
333 					 MAX(command_len, 10))) {
334 			if ((tmp = slurmdb_parse_purge(argv[i]+end))
335 			    == NO_VAL) {
336 				exit_code = 1;
337 			} else {
338 				arch_cond->purge_usage |= tmp;
339 				set = 1;
340 			}
341 		} else if (!xstrncasecmp(argv[i], "PurgeEventMonths",
342 					 MAX(command_len, 6))) {
343 			if (get_uint(argv[i]+end, &tmp, "PurgeEventMonths")
344 			    != SLURM_SUCCESS) {
345 				exit_code = 1;
346 			} else {
347 				arch_cond->purge_event |= tmp;
348 				arch_cond->purge_event |= SLURMDB_PURGE_MONTHS;
349 				set = 1;
350 			}
351 		} else if (!xstrncasecmp(argv[i], "PurgeJobMonths",
352 					 MAX(command_len, 6))) {
353 			if (get_uint(argv[i]+end, &tmp, "PurgeJobMonths")
354 			    != SLURM_SUCCESS) {
355 				exit_code = 1;
356 			} else {
357 				arch_cond->purge_job |= tmp;
358 				arch_cond->purge_job |= SLURMDB_PURGE_MONTHS;
359 				set = 1;
360 			}
361 		} else if (!xstrncasecmp(argv[i], "PurgeResvMonths",
362 					 MAX(command_len, 6))) {
363 			if (get_uint(argv[i]+end, &tmp, "PurgeResvMonths")
364 			    != SLURM_SUCCESS) {
365 				exit_code = 1;
366 			} else {
367 				arch_cond->purge_resv |= tmp;
368 				arch_cond->purge_resv |= SLURMDB_PURGE_MONTHS;
369 				set = 1;
370 			}
371 		} else if (!xstrncasecmp(argv[i], "PurgeStepMonths",
372 					 MAX(command_len, 7))) {
373 			if (get_uint(argv[i]+end, &tmp, "PurgeStepMonths")
374 			    != SLURM_SUCCESS) {
375 				exit_code = 1;
376 			} else {
377 				arch_cond->purge_step |= tmp;
378 				arch_cond->purge_step |= SLURMDB_PURGE_MONTHS;
379 				set = 1;
380 			}
381 		} else if (!xstrncasecmp(argv[i], "PurgeSuspendMonths",
382 					 MAX(command_len, 7))) {
383 			if (get_uint(argv[i]+end, &tmp, "PurgeSuspendMonths")
384 			    != SLURM_SUCCESS) {
385 				exit_code = 1;
386 			} else {
387 				arch_cond->purge_suspend |= tmp;
388 				arch_cond->purge_suspend
389 					|= SLURMDB_PURGE_MONTHS;
390 				set = 1;
391 			}
392 		} else if (!xstrncasecmp(argv[i], "PurgeTXNMonths",
393 					 MAX(command_len, 6))) {
394 			if (get_uint(argv[i]+end, &tmp, "PurgeTXNMonths")
395 			    != SLURM_SUCCESS) {
396 				exit_code = 1;
397 			} else {
398 				arch_cond->purge_txn |= tmp;
399 				arch_cond->purge_txn
400 					|= SLURMDB_PURGE_MONTHS;
401 				set = 1;
402 			}
403 		} else if (!xstrncasecmp(argv[i], "PurgeUsageMonths",
404 					 MAX(command_len, 6))) {
405 			if (get_uint(argv[i]+end, &tmp, "PurgeUsageMonths")
406 			    != SLURM_SUCCESS) {
407 				exit_code = 1;
408 			} else {
409 				arch_cond->purge_usage |= tmp;
410 				arch_cond->purge_usage
411 					|= SLURMDB_PURGE_MONTHS;
412 				set = 1;
413 			}
414 		} else if (!xstrncasecmp(argv[i], "Start",
415 					 MAX(command_len, 2))) {
416 			job_cond->usage_start = parse_time(argv[i]+end, 1);
417 			set = 1;
418 		} else if (!xstrncasecmp(argv[i], "Script",
419 					 MAX(command_len, 2))) {
420 			arch_cond->archive_script =
421 				strip_quotes(argv[i]+end, NULL, 0);
422 			set = 1;
423 		} else if (!xstrncasecmp(argv[i], "Users",
424 					 MAX(command_len, 1))) {
425 			if (!job_cond->userid_list)
426 				job_cond->userid_list = list_create(xfree_ptr);
427 			_addto_uid_char_list(job_cond->userid_list,
428 					     argv[i]+end);
429 			set = 1;
430 		} else {
431 			exit_code=1;
432 			fprintf(stderr, " Unknown condition: %s\n", argv[i]);
433 		}
434 	}
435 
436 	(*start) = i;
437 
438 	return set;
439 }
440 
sacctmgr_archive_dump(int argc,char ** argv)441 extern int sacctmgr_archive_dump(int argc, char **argv)
442 {
443 	char *warning = NULL;
444 	int rc = SLURM_SUCCESS;
445 	slurmdb_archive_cond_t *arch_cond =
446 		xmalloc(sizeof(slurmdb_archive_cond_t));
447 	int i;
448 	struct stat st;
449 
450 	for (i = 0; i < argc; i++) {
451 		int command_len = strlen(argv[i]);
452 		if (!xstrncasecmp(argv[i], "Where", MAX(command_len, 5))
453 		    || !xstrncasecmp(argv[i], "Set", MAX(command_len, 3)))
454 			i++;
455 		_set_cond(&i, argc, argv, arch_cond);
456 	}
457 
458 	if (!arch_cond->purge_event)
459 		arch_cond->purge_event = NO_VAL;
460 	if (!arch_cond->purge_job)
461 		arch_cond->purge_job = NO_VAL;
462 	if (!arch_cond->purge_resv)
463 		arch_cond->purge_resv = NO_VAL;
464 	if (!arch_cond->purge_step)
465 		arch_cond->purge_step = NO_VAL;
466 	if (!arch_cond->purge_suspend)
467 		arch_cond->purge_suspend = NO_VAL;
468 	if (!arch_cond->purge_txn)
469 		arch_cond->purge_txn = NO_VAL;
470 	if (!arch_cond->purge_usage)
471 		arch_cond->purge_usage = NO_VAL;
472 
473 	if (exit_code) {
474 		slurmdb_destroy_archive_cond(arch_cond);
475 		return SLURM_ERROR;
476 	}
477 
478 	if (arch_cond->archive_dir) {
479 		if (stat(arch_cond->archive_dir, &st) < 0) {
480 			exit_code = errno;
481 			fprintf(stderr, " dump: Failed to stat %s: %s\n "
482 				"Note: For archive dump, "
483 				"the directory must be on "
484 				"the calling host.\n",
485 				arch_cond->archive_dir, slurm_strerror(errno));
486 			slurmdb_destroy_archive_cond(arch_cond);
487 			return SLURM_ERROR;
488 		}
489 
490 		if (!(st.st_mode & S_IFDIR)) {
491 			errno = EACCES;
492 			fprintf(stderr, " dump: "
493 				"archive dir %s isn't a directory\n",
494 				arch_cond->archive_dir);
495 			slurmdb_destroy_archive_cond(arch_cond);
496 			return SLURM_ERROR;
497 		}
498 
499 		if (access(arch_cond->archive_dir, W_OK) < 0) {
500 			errno = EACCES;
501 			fprintf(stderr, " dump: "
502 				"archive dir %s is not writable\n",
503 				arch_cond->archive_dir);
504 			slurmdb_destroy_archive_cond(arch_cond);
505 			return SLURM_ERROR;
506 		}
507 	}
508 
509 	if (arch_cond->archive_script) {
510 		if (stat(arch_cond->archive_script, &st) < 0) {
511 			exit_code = errno;
512 			fprintf(stderr, " dump: Failed to stat %s: %s\n "
513 				"Note: For archive dump, the script must be on "
514 				"the calling host.\n",
515 				arch_cond->archive_script,
516 				slurm_strerror(errno));
517 			slurmdb_destroy_archive_cond(arch_cond);
518 			return SLURM_ERROR;
519 		}
520 		if (!(st.st_mode & S_IFREG)) {
521 			errno = EACCES;
522 			fprintf(stderr, " dump: "
523 				"archive script %s isn't a regular file\n",
524 				arch_cond->archive_script);
525 			slurmdb_destroy_archive_cond(arch_cond);
526 			return SLURM_ERROR;
527 		}
528 
529 		if (access(arch_cond->archive_script, X_OK) < 0) {
530 			errno = EACCES;
531 			fprintf(stderr, " dump: "
532 				"archive script %s is not executable\n",
533 				arch_cond->archive_script);
534 			slurmdb_destroy_archive_cond(arch_cond);
535 			return SLURM_ERROR;
536 		}
537 	}
538 
539 	warning = "This may result in loss of accounting database records (if Purge* options enabled).\nAre you sure you want to continue?";
540 	if (commit_check(warning)) {
541 		rc = slurmdb_archive(db_conn, arch_cond);
542 		if (rc != SLURM_SUCCESS) {
543 			exit_code = 1;
544 			fprintf(stderr, " Problem dumping archive: %s\n",
545 				slurm_strerror(rc));
546 			rc = SLURM_ERROR;
547 		}
548 	} else {
549 		printf(" Changes Discarded\n");
550 	}
551 
552 	slurmdb_destroy_archive_cond(arch_cond);
553 
554 	return rc;
555 }
556 
sacctmgr_archive_load(int argc,char ** argv)557 extern int sacctmgr_archive_load(int argc, char **argv)
558 {
559 	int rc = SLURM_SUCCESS;
560 	slurmdb_archive_rec_t *arch_rec =
561 		xmalloc(sizeof(slurmdb_archive_rec_t));
562 	int i, command_len = 0;
563 
564 	for (i = 0; i < argc; i++) {
565 		int end = parse_option_end(argv[i]);
566 		if (!end)
567 			command_len=strlen(argv[i]);
568 		else {
569 			command_len=end-1;
570 			if (argv[i][end] == '=') {
571 				end++;
572 			}
573 		}
574 
575 		if (!end
576 		   || !xstrncasecmp(argv[i], "File", MAX(command_len, 1))) {
577 			arch_rec->archive_file =
578 				strip_quotes(argv[i]+end, NULL, 0);
579 			if (!is_full_path(arch_rec->archive_file)) {
580 				char *file = arch_rec->archive_file;
581 				arch_rec->archive_file =
582 					make_full_path(arch_rec->archive_file);
583 				xfree(file);
584 			}
585 		} else if (!xstrncasecmp(argv[i], "Insert",
586 					 MAX(command_len, 2))) {
587 			arch_rec->insert = strip_quotes(argv[i]+end, NULL, 1);
588 		} else {
589 			exit_code = 1;
590 			fprintf(stderr, " Unknown option: %s\n", argv[i]);
591 		}
592 	}
593 
594 	if (exit_code) {
595 		slurmdb_destroy_archive_rec(arch_rec);
596 		return SLURM_ERROR;
597 	}
598 
599 	rc = slurmdb_archive_load(db_conn, arch_rec);
600 	if (rc == SLURM_SUCCESS) {
601 		if (commit_check("Would you like to commit changes?")) {
602 			slurmdb_connection_commit(db_conn, 1);
603 		} else {
604 			printf(" Changes Discarded\n");
605 			slurmdb_connection_commit(db_conn, 0);
606 		}
607 	} else {
608 		exit_code = 1;
609 		fprintf(stderr, " Problem loading archive file: %s\n",
610 			slurm_strerror(rc));
611 
612 		if (rc == EACCES || rc == EISDIR || rc == ENOENT)
613 			fprintf(stderr, " Note: For archive load, the file must be accessible on the slurmdbd host.\n");
614 
615 		rc = SLURM_ERROR;
616 	}
617 
618 	slurmdb_destroy_archive_rec(arch_rec);
619 
620 	return rc;
621 }
622