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