1 /*
2 * Copyright 2004-2019 the Pacemaker project contributors
3 *
4 * The version control history for this file may have further details.
5 *
6 * This source code is licensed under the GNU Lesser General Public License
7 * version 2.1 or later (LGPLv2.1+) WITHOUT ANY WARRANTY.
8 */
9
10 #include <crm_internal.h>
11 #include <dlfcn.h>
12
13 #ifndef _GNU_SOURCE
14 # define _GNU_SOURCE
15 #endif
16
17 #include <sys/types.h>
18 #include <sys/wait.h>
19 #include <sys/stat.h>
20 #include <sys/utsname.h>
21
22 #include <stdio.h>
23 #include <unistd.h>
24 #include <string.h>
25 #include <stdlib.h>
26 #include <limits.h>
27 #include <pwd.h>
28 #include <time.h>
29 #include <libgen.h>
30 #include <signal.h>
31
32 #include <qb/qbdefs.h>
33
34 #include <crm/crm.h>
35 #include <crm/services.h>
36 #include <crm/msg_xml.h>
37 #include <crm/cib/internal.h>
38 #include <crm/common/xml.h>
39 #include <crm/common/util.h>
40 #include <crm/common/ipc.h>
41 #include <crm/common/iso8601.h>
42 #include <crm/common/mainloop.h>
43 #include <libxml2/libxml/relaxng.h>
44
45 #ifndef MAXLINE
46 # define MAXLINE 512
47 #endif
48
49 #ifdef HAVE_GETOPT_H
50 # include <getopt.h>
51 #endif
52
53 #ifndef PW_BUFFER_LEN
54 # define PW_BUFFER_LEN 500
55 #endif
56
57 CRM_TRACE_INIT_DATA(common);
58
59 gboolean crm_config_error = FALSE;
60 gboolean crm_config_warning = FALSE;
61 char *crm_system_name = NULL;
62
63 int node_score_red = 0;
64 int node_score_green = 0;
65 int node_score_yellow = 0;
66 int node_score_infinity = INFINITY;
67
68 static struct crm_option *crm_long_options = NULL;
69 static const char *crm_app_description = NULL;
70 static char *crm_short_options = NULL;
71 static const char *crm_app_usage = NULL;
72
73 int
crm_exit(int rc)74 crm_exit(int rc)
75 {
76 mainloop_cleanup();
77
78 #if HAVE_LIBXML2
79 crm_trace("cleaning up libxml");
80 crm_xml_cleanup();
81 #endif
82
83 crm_trace("exit %d", rc);
84 qb_log_fini();
85
86 free(crm_short_options);
87 free(crm_system_name);
88
89 exit(ABS(rc)); /* Always exit with a positive value so that it can be passed to crm_error
90 *
91 * Otherwise the system wraps it around and people
92 * have to jump through hoops figuring out what the
93 * error was
94 */
95 return rc; /* Can never happen, but allows return crm_exit(rc)
96 * where "return rc" was used previously - which
97 * keeps compilers happy.
98 */
99 }
100
101 gboolean
check_time(const char * value)102 check_time(const char *value)
103 {
104 if (crm_get_msec(value) < 5000) {
105 return FALSE;
106 }
107 return TRUE;
108 }
109
110 gboolean
check_timer(const char * value)111 check_timer(const char *value)
112 {
113 if (crm_get_msec(value) < 0) {
114 return FALSE;
115 }
116 return TRUE;
117 }
118
119 gboolean
check_boolean(const char * value)120 check_boolean(const char *value)
121 {
122 int tmp = FALSE;
123
124 if (crm_str_to_boolean(value, &tmp) != 1) {
125 return FALSE;
126 }
127 return TRUE;
128 }
129
130 gboolean
check_number(const char * value)131 check_number(const char *value)
132 {
133 errno = 0;
134 if (value == NULL) {
135 return FALSE;
136
137 } else if (safe_str_eq(value, MINUS_INFINITY_S)) {
138
139 } else if (safe_str_eq(value, INFINITY_S)) {
140
141 } else {
142 crm_int_helper(value, NULL);
143 }
144
145 if (errno != 0) {
146 return FALSE;
147 }
148 return TRUE;
149 }
150
151 gboolean
check_positive_number(const char * value)152 check_positive_number(const char* value)
153 {
154 if (safe_str_eq(value, INFINITY_S) || (crm_int_helper(value, NULL))) {
155 return TRUE;
156 }
157 return FALSE;
158 }
159
160 gboolean
check_quorum(const char * value)161 check_quorum(const char *value)
162 {
163 if (safe_str_eq(value, "stop")) {
164 return TRUE;
165
166 } else if (safe_str_eq(value, "freeze")) {
167 return TRUE;
168
169 } else if (safe_str_eq(value, "ignore")) {
170 return TRUE;
171
172 } else if (safe_str_eq(value, "suicide")) {
173 return TRUE;
174 }
175 return FALSE;
176 }
177
178 gboolean
check_script(const char * value)179 check_script(const char *value)
180 {
181 struct stat st;
182
183 if(safe_str_eq(value, "/dev/null")) {
184 return TRUE;
185 }
186
187 if(stat(value, &st) != 0) {
188 crm_err("Script %s does not exist", value);
189 return FALSE;
190 }
191
192 if(S_ISREG(st.st_mode) == 0) {
193 crm_err("Script %s is not a regular file", value);
194 return FALSE;
195 }
196
197 if( (st.st_mode & (S_IXUSR | S_IXGRP )) == 0) {
198 crm_err("Script %s is not executable", value);
199 return FALSE;
200 }
201
202 return TRUE;
203 }
204
205 gboolean
check_utilization(const char * value)206 check_utilization(const char *value)
207 {
208 char *end = NULL;
209 long number = strtol(value, &end, 10);
210
211 if(end && end[0] != '%') {
212 return FALSE;
213 } else if(number < 0) {
214 return FALSE;
215 }
216
217 return TRUE;
218 }
219
220 int
char2score(const char * score)221 char2score(const char *score)
222 {
223 int score_f = 0;
224
225 if (score == NULL) {
226
227 } else if (safe_str_eq(score, MINUS_INFINITY_S)) {
228 score_f = -node_score_infinity;
229
230 } else if (safe_str_eq(score, INFINITY_S)) {
231 score_f = node_score_infinity;
232
233 } else if (safe_str_eq(score, "+" INFINITY_S)) {
234 score_f = node_score_infinity;
235
236 } else if (safe_str_eq(score, "red")) {
237 score_f = node_score_red;
238
239 } else if (safe_str_eq(score, "yellow")) {
240 score_f = node_score_yellow;
241
242 } else if (safe_str_eq(score, "green")) {
243 score_f = node_score_green;
244
245 } else {
246 score_f = crm_parse_int(score, NULL);
247 if (score_f > 0 && score_f > node_score_infinity) {
248 score_f = node_score_infinity;
249
250 } else if (score_f < 0 && score_f < -node_score_infinity) {
251 score_f = -node_score_infinity;
252 }
253 }
254
255 return score_f;
256 }
257
258 char *
score2char_stack(int score,char * buf,size_t len)259 score2char_stack(int score, char *buf, size_t len)
260 {
261 if (score >= node_score_infinity) {
262 strncpy(buf, INFINITY_S, 9);
263 } else if (score <= -node_score_infinity) {
264 strncpy(buf, MINUS_INFINITY_S , 10);
265 } else {
266 return crm_itoa_stack(score, buf, len);
267 }
268
269 return buf;
270 }
271
272 char *
score2char(int score)273 score2char(int score)
274 {
275 if (score >= node_score_infinity) {
276 return strdup(INFINITY_S);
277
278 } else if (score <= -node_score_infinity) {
279 return strdup("-" INFINITY_S);
280 }
281 return crm_itoa(score);
282 }
283
284 const char *
cluster_option(GHashTable * options,gboolean (* validate)(const char *),const char * name,const char * old_name,const char * def_value)285 cluster_option(GHashTable * options, gboolean(*validate) (const char *),
286 const char *name, const char *old_name, const char *def_value)
287 {
288 const char *value = NULL;
289 char *new_value = NULL;
290
291 CRM_ASSERT(name != NULL);
292
293 if (options) {
294 value = g_hash_table_lookup(options, name);
295
296 if ((value == NULL) && old_name) {
297 value = g_hash_table_lookup(options, old_name);
298 if (value != NULL) {
299 crm_config_warn("Support for legacy name '%s' for cluster option '%s'"
300 " is deprecated and will be removed in a future release",
301 old_name, name);
302
303 // Inserting copy with current name ensures we only warn once
304 new_value = strdup(value);
305 g_hash_table_insert(options, strdup(name), new_value);
306 value = new_value;
307 }
308 }
309
310 if (value && validate && (validate(value) == FALSE)) {
311 crm_config_err("Resetting cluster option '%s' to default: value '%s' is invalid",
312 name, value);
313 value = NULL;
314 }
315
316 if (value) {
317 return value;
318 }
319 }
320
321 // No value found, use default
322 value = def_value;
323
324 if (value == NULL) {
325 crm_trace("No value or default provided for cluster option '%s'",
326 name);
327 return NULL;
328 }
329
330 if (validate) {
331 CRM_CHECK(validate(value) != FALSE,
332 crm_err("Bug: default value for cluster option '%s' is invalid", name);
333 return NULL);
334 }
335
336 crm_trace("Using default value '%s' for cluster option '%s'",
337 value, name);
338 if (options) {
339 new_value = strdup(value);
340 g_hash_table_insert(options, strdup(name), new_value);
341 value = new_value;
342 }
343 return value;
344 }
345
346 const char *
get_cluster_pref(GHashTable * options,pe_cluster_option * option_list,int len,const char * name)347 get_cluster_pref(GHashTable * options, pe_cluster_option * option_list, int len, const char *name)
348 {
349 const char *value = NULL;
350
351 for (int lpc = 0; lpc < len; lpc++) {
352 if (safe_str_eq(name, option_list[lpc].name)) {
353 value = cluster_option(options,
354 option_list[lpc].is_valid,
355 option_list[lpc].name,
356 option_list[lpc].alt_name,
357 option_list[lpc].default_value);
358 return value;
359 }
360 }
361 CRM_CHECK(FALSE, crm_err("Bug: looking for unknown option '%s'", name));
362 return NULL;
363 }
364
365 void
config_metadata(const char * name,const char * version,const char * desc_short,const char * desc_long,pe_cluster_option * option_list,int len)366 config_metadata(const char *name, const char *version, const char *desc_short,
367 const char *desc_long, pe_cluster_option * option_list, int len)
368 {
369 int lpc = 0;
370
371 fprintf(stdout, "<?xml version=\"1.0\"?>"
372 "<!DOCTYPE resource-agent SYSTEM \"ra-api-1.dtd\">\n"
373 "<resource-agent name=\"%s\">\n"
374 " <version>%s</version>\n"
375 " <longdesc lang=\"en\">%s</longdesc>\n"
376 " <shortdesc lang=\"en\">%s</shortdesc>\n"
377 " <parameters>\n", name, version, desc_long, desc_short);
378
379 for (lpc = 0; lpc < len; lpc++) {
380 if (option_list[lpc].description_long == NULL && option_list[lpc].description_short == NULL) {
381 continue;
382 }
383 fprintf(stdout, " <parameter name=\"%s\" unique=\"0\">\n"
384 " <shortdesc lang=\"en\">%s</shortdesc>\n"
385 " <content type=\"%s\" default=\"%s\"/>\n"
386 " <longdesc lang=\"en\">%s%s%s</longdesc>\n"
387 " </parameter>\n",
388 option_list[lpc].name,
389 option_list[lpc].description_short,
390 option_list[lpc].type,
391 option_list[lpc].default_value,
392 option_list[lpc].description_long ? option_list[lpc].
393 description_long : option_list[lpc].description_short,
394 option_list[lpc].values ? " Allowed values: " : "",
395 option_list[lpc].values ? option_list[lpc].values : "");
396 }
397 fprintf(stdout, " </parameters>\n</resource-agent>\n");
398 }
399
400 void
verify_all_options(GHashTable * options,pe_cluster_option * option_list,int len)401 verify_all_options(GHashTable * options, pe_cluster_option * option_list, int len)
402 {
403 int lpc = 0;
404
405 for (lpc = 0; lpc < len; lpc++) {
406 cluster_option(options,
407 option_list[lpc].is_valid,
408 option_list[lpc].name,
409 option_list[lpc].alt_name, option_list[lpc].default_value);
410 }
411 }
412
413 char *
generate_hash_key(const char * crm_msg_reference,const char * sys)414 generate_hash_key(const char *crm_msg_reference, const char *sys)
415 {
416 char *hash_key = crm_concat(sys ? sys : "none", crm_msg_reference, '_');
417
418 crm_trace("created hash key: (%s)", hash_key);
419 return hash_key;
420 }
421
422
423 int
crm_user_lookup(const char * name,uid_t * uid,gid_t * gid)424 crm_user_lookup(const char *name, uid_t * uid, gid_t * gid)
425 {
426 int rc = pcmk_ok;
427 char *buffer = NULL;
428 struct passwd pwd;
429 struct passwd *pwentry = NULL;
430
431 buffer = calloc(1, PW_BUFFER_LEN);
432 rc = getpwnam_r(name, &pwd, buffer, PW_BUFFER_LEN, &pwentry);
433 if (pwentry) {
434 if (uid) {
435 *uid = pwentry->pw_uid;
436 }
437 if (gid) {
438 *gid = pwentry->pw_gid;
439 }
440 crm_trace("User %s has uid=%d gid=%d", name, pwentry->pw_uid, pwentry->pw_gid);
441
442 } else {
443 rc = rc? -rc : -EINVAL;
444 crm_info("User %s lookup: %s", name, pcmk_strerror(rc));
445 }
446
447 free(buffer);
448 return rc;
449 }
450
451 static int
crm_version_helper(const char * text,char ** end_text)452 crm_version_helper(const char *text, char **end_text)
453 {
454 int atoi_result = -1;
455
456 CRM_ASSERT(end_text != NULL);
457
458 errno = 0;
459
460 if (text != NULL && text[0] != 0) {
461 atoi_result = (int)strtol(text, end_text, 10);
462
463 if (errno == EINVAL) {
464 crm_err("Conversion of '%s' %c failed", text, text[0]);
465 atoi_result = -1;
466 }
467 }
468 return atoi_result;
469 }
470
471 /*
472 * version1 < version2 : -1
473 * version1 = version2 : 0
474 * version1 > version2 : 1
475 */
476 int
compare_version(const char * version1,const char * version2)477 compare_version(const char *version1, const char *version2)
478 {
479 int rc = 0;
480 int lpc = 0;
481 char *ver1_copy = NULL, *ver2_copy = NULL;
482 char *rest1 = NULL, *rest2 = NULL;
483
484 if (version1 == NULL && version2 == NULL) {
485 return 0;
486 } else if (version1 == NULL) {
487 return -1;
488 } else if (version2 == NULL) {
489 return 1;
490 }
491
492 ver1_copy = strdup(version1);
493 ver2_copy = strdup(version2);
494 rest1 = ver1_copy;
495 rest2 = ver2_copy;
496
497 while (1) {
498 int digit1 = 0;
499 int digit2 = 0;
500
501 lpc++;
502
503 if (rest1 == rest2) {
504 break;
505 }
506
507 if (rest1 != NULL) {
508 digit1 = crm_version_helper(rest1, &rest1);
509 }
510
511 if (rest2 != NULL) {
512 digit2 = crm_version_helper(rest2, &rest2);
513 }
514
515 if (digit1 < digit2) {
516 rc = -1;
517 break;
518
519 } else if (digit1 > digit2) {
520 rc = 1;
521 break;
522 }
523
524 if (rest1 != NULL && rest1[0] == '.') {
525 rest1++;
526 }
527 if (rest1 != NULL && rest1[0] == 0) {
528 rest1 = NULL;
529 }
530
531 if (rest2 != NULL && rest2[0] == '.') {
532 rest2++;
533 }
534 if (rest2 != NULL && rest2[0] == 0) {
535 rest2 = NULL;
536 }
537 }
538
539 free(ver1_copy);
540 free(ver2_copy);
541
542 if (rc == 0) {
543 crm_trace("%s == %s (%d)", version1, version2, lpc);
544 } else if (rc < 0) {
545 crm_trace("%s < %s (%d)", version1, version2, lpc);
546 } else if (rc > 0) {
547 crm_trace("%s > %s (%d)", version1, version2, lpc);
548 }
549
550 return rc;
551 }
552
553 gboolean do_stderr = FALSE;
554
555 #ifndef NUMCHARS
556 # define NUMCHARS "0123456789."
557 #endif
558
559 #ifndef WHITESPACE
560 # define WHITESPACE " \t\n\r\f"
561 #endif
562
563 unsigned long long
crm_get_interval(const char * input)564 crm_get_interval(const char *input)
565 {
566 unsigned long long msec = 0;
567
568 if (input == NULL) {
569 return msec;
570
571 } else if (input[0] != 'P') {
572 long long tmp = crm_get_msec(input);
573
574 if(tmp > 0) {
575 msec = tmp;
576 }
577
578 } else {
579 crm_time_t *interval = crm_time_parse_duration(input);
580
581 msec = 1000 * crm_time_get_seconds(interval);
582 crm_time_free(interval);
583 }
584
585 return msec;
586 }
587
588 long long
crm_get_msec(const char * input)589 crm_get_msec(const char *input)
590 {
591 const char *cp = input;
592 const char *units;
593 long long multiplier = 1000;
594 long long divisor = 1;
595 long long msec = -1;
596 char *end_text = NULL;
597
598 /* double dret; */
599
600 if (input == NULL) {
601 return msec;
602 }
603
604 cp += strspn(cp, WHITESPACE);
605 units = cp + strspn(cp, NUMCHARS);
606 units += strspn(units, WHITESPACE);
607
608 if (strchr(NUMCHARS, *cp) == NULL) {
609 return msec;
610 }
611
612 if (strncasecmp(units, "ms", 2) == 0 || strncasecmp(units, "msec", 4) == 0) {
613 multiplier = 1;
614 divisor = 1;
615 } else if (strncasecmp(units, "us", 2) == 0 || strncasecmp(units, "usec", 4) == 0) {
616 multiplier = 1;
617 divisor = 1000;
618 } else if (strncasecmp(units, "s", 1) == 0 || strncasecmp(units, "sec", 3) == 0) {
619 multiplier = 1000;
620 divisor = 1;
621 } else if (strncasecmp(units, "m", 1) == 0 || strncasecmp(units, "min", 3) == 0) {
622 multiplier = 60 * 1000;
623 divisor = 1;
624 } else if (strncasecmp(units, "h", 1) == 0 || strncasecmp(units, "hr", 2) == 0) {
625 multiplier = 60 * 60 * 1000;
626 divisor = 1;
627 } else if (*units != EOS && *units != '\n' && *units != '\r') {
628 return msec;
629 }
630
631 msec = crm_int_helper(cp, &end_text);
632 if (msec > LLONG_MAX/multiplier) {
633 /* arithmetics overflow while multiplier/divisor mutually exclusive */
634 return LLONG_MAX;
635 }
636 msec *= multiplier;
637 msec /= divisor;
638 /* dret += 0.5; */
639 /* msec = (long long)dret; */
640 return msec;
641 }
642
643 extern bool crm_is_daemon;
644
645 /* coverity[+kill] */
646 void
crm_abort(const char * file,const char * function,int line,const char * assert_condition,gboolean do_core,gboolean do_fork)647 crm_abort(const char *file, const char *function, int line,
648 const char *assert_condition, gboolean do_core, gboolean do_fork)
649 {
650 int rc = 0;
651 int pid = 0;
652 int status = 0;
653
654 /* Implied by the parent's error logging below */
655 /* crm_write_blackbox(0); */
656
657 if(crm_is_daemon == FALSE) {
658 /* This is a command line tool - do not fork */
659
660 /* crm_add_logfile(NULL); * Record it to a file? */
661 crm_enable_stderr(TRUE); /* Make sure stderr is enabled so we can tell the caller */
662 do_fork = FALSE; /* Just crash if needed */
663 }
664
665 if (do_core == FALSE) {
666 crm_err("%s: Triggered assert at %s:%d : %s", function, file, line, assert_condition);
667 return;
668
669 } else if (do_fork) {
670 pid = fork();
671
672 } else {
673 crm_err("%s: Triggered fatal assert at %s:%d : %s", function, file, line, assert_condition);
674 }
675
676 if (pid == -1) {
677 crm_crit("%s: Cannot create core for non-fatal assert at %s:%d : %s",
678 function, file, line, assert_condition);
679 return;
680
681 } else if(pid == 0) {
682 /* Child process */
683 abort();
684 return;
685 }
686
687 /* Parent process */
688 crm_err("%s: Forked child %d to record non-fatal assert at %s:%d : %s",
689 function, pid, file, line, assert_condition);
690 crm_write_blackbox(SIGTRAP, NULL);
691
692 do {
693 rc = waitpid(pid, &status, 0);
694 if(rc == pid) {
695 return; /* Job done */
696 }
697
698 } while(errno == EINTR);
699
700 if (errno == ECHILD) {
701 /* crm_mon does this */
702 crm_trace("Cannot wait on forked child %d - SIGCHLD is probably set to SIG_IGN", pid);
703 return;
704 }
705 crm_perror(LOG_ERR, "Cannot wait on forked child %d", pid);
706 }
707
708 int
crm_pid_active(long pid,const char * daemon)709 crm_pid_active(long pid, const char *daemon)
710 {
711 static int last_asked_pid = 0; /* log spam prevention */
712 #if SUPPORT_PROCFS
713 static int have_proc_pid = 0;
714 #else
715 static int have_proc_pid = -1;
716 #endif
717 int rc = 0;
718
719 if (have_proc_pid == 0) {
720 /* evaluation of /proc/PID/exe applicability via self-introspection */
721 char proc_path[PATH_MAX], exe_path[PATH_MAX];
722 snprintf(proc_path, sizeof(proc_path), "/proc/%lu/exe",
723 (long unsigned int) getpid());
724 have_proc_pid = 1;
725 if (readlink(proc_path, exe_path, sizeof(exe_path) - 1) < 0) {
726 have_proc_pid = -1;
727 }
728 }
729
730 if (pid <= 0) {
731 return -1;
732
733 } else if ((rc = kill(pid, 0)) < 0 && errno == ESRCH) {
734 return 0; /* no such PID detected */
735
736 } else if (rc < 0 && (daemon == NULL || have_proc_pid == -1)) {
737 if (last_asked_pid != pid) {
738 crm_info("Cannot examine PID %ld: %s", pid, strerror(errno));
739 last_asked_pid = pid;
740 }
741 return -2; /* errno != ESRCH */
742
743 } else if (rc == 0 && (daemon == NULL || have_proc_pid == -1)) {
744 return 1; /* kill as the only indicator, cannot double check */
745
746 } else if (daemon != NULL) {
747 /* make sure PID hasn't been reused by another process
748 XXX: might still be just a zombie, which could confuse decisions */
749 bool checked_through_kill = (rc == 0);
750 char proc_path[PATH_MAX], exe_path[PATH_MAX], myexe_path[PATH_MAX];
751 snprintf(proc_path, sizeof(proc_path), "/proc/%ld/exe", pid);
752
753 rc = readlink(proc_path, exe_path, sizeof(exe_path) - 1);
754 if ((rc < 0) && (errno == EACCES)) {
755 if (last_asked_pid != pid) {
756 crm_info("Could not read from %s: %s", proc_path,
757 strerror(errno));
758 last_asked_pid = pid;
759 }
760 return checked_through_kill ? 1 : -2;
761 } else if (rc < 0) {
762 if (last_asked_pid != pid) {
763 crm_err("Could not read from %s: %s (%d)", proc_path,
764 strerror(errno), errno);
765 last_asked_pid = pid;
766 }
767 return 0; /* most likely errno == ENOENT */
768 }
769 exe_path[rc] = '\0';
770
771 if (daemon[0] != '/') {
772 rc = snprintf(myexe_path, sizeof(myexe_path), CRM_DAEMON_DIR"/%s",
773 daemon);
774 } else {
775 rc = snprintf(myexe_path, sizeof(myexe_path), "%s", daemon);
776 }
777
778 if (rc > 0 && rc < sizeof(myexe_path) && !strcmp(exe_path, myexe_path)) {
779 return 1;
780 }
781 }
782
783 return 0;
784 }
785
786 #define LOCKSTRLEN 11
787
788 long
crm_read_pidfile(const char * filename)789 crm_read_pidfile(const char *filename)
790 {
791 int fd;
792 struct stat sbuf;
793 long pid = -ENOENT;
794 char buf[LOCKSTRLEN + 1];
795
796 if ((fd = open(filename, O_RDONLY)) < 0) {
797 goto bail;
798 }
799
800 if (fstat(fd, &sbuf) >= 0 && sbuf.st_size < LOCKSTRLEN) {
801 sleep(2); /* if someone was about to create one,
802 * give'm a sec to do so
803 */
804 }
805
806 if (read(fd, buf, sizeof(buf)) < 1) {
807 goto bail;
808 }
809
810 if (sscanf(buf, "%lu", &pid) > 0) {
811 if (pid <= 0) {
812 pid = -ESRCH;
813 } else {
814 crm_trace("Got pid %lu from %s\n", pid, filename);
815 }
816 }
817
818 bail:
819 if (fd >= 0) {
820 close(fd);
821 }
822 return pid;
823 }
824
825 long
crm_pidfile_inuse(const char * filename,long mypid,const char * daemon)826 crm_pidfile_inuse(const char *filename, long mypid, const char *daemon)
827 {
828 long pid = crm_read_pidfile(filename);
829
830 if (pid < 2) {
831 /* Invalid pid */
832 pid = -ENOENT;
833 unlink(filename);
834
835 } else if (mypid && pid == mypid) {
836 /* In use by us */
837 pid = pcmk_ok;
838
839 } else if (crm_pid_active(pid, daemon) == FALSE) {
840 /* Contains a stale value */
841 unlink(filename);
842 pid = -ENOENT;
843
844 } else if (mypid && pid != mypid) {
845 /* locked by existing process - give up */
846 pid = -EEXIST;
847 }
848
849 return pid;
850 }
851
852 static int
crm_lock_pidfile(const char * filename,const char * name)853 crm_lock_pidfile(const char *filename, const char *name)
854 {
855 long mypid = 0;
856 int fd = 0, rc = 0;
857 char buf[LOCKSTRLEN + 1];
858
859 mypid = (unsigned long)getpid();
860
861 rc = crm_pidfile_inuse(filename, 0, name);
862 if (rc == -ENOENT) {
863 /* exists but the process is not active */
864
865 } else if (rc != pcmk_ok) {
866 /* locked by existing process - give up */
867 return rc;
868 }
869
870 if ((fd = open(filename, O_CREAT | O_WRONLY | O_EXCL, 0644)) < 0) {
871 /* Hmmh, why did we fail? Anyway, nothing we can do about it */
872 return -errno;
873 }
874
875 snprintf(buf, sizeof(buf), "%*lu\n", LOCKSTRLEN - 1, mypid);
876 rc = write(fd, buf, LOCKSTRLEN);
877 close(fd);
878
879 if (rc != LOCKSTRLEN) {
880 crm_perror(LOG_ERR, "Incomplete write to %s", filename);
881 return -errno;
882 }
883
884 return crm_pidfile_inuse(filename, mypid, name);
885 }
886
887 void
crm_make_daemon(const char * name,gboolean daemonize,const char * pidfile)888 crm_make_daemon(const char *name, gboolean daemonize, const char *pidfile)
889 {
890 int rc;
891 long pid;
892 const char *devnull = "/dev/null";
893
894 if (daemonize == FALSE) {
895 return;
896 }
897
898 /* Check before we even try... */
899 rc = crm_pidfile_inuse(pidfile, 1, name);
900 if(rc < pcmk_ok && rc != -ENOENT) {
901 pid = crm_read_pidfile(pidfile);
902 crm_err("%s: already running [pid %ld in %s]", name, pid, pidfile);
903 printf("%s: already running [pid %ld in %s]\n", name, pid, pidfile);
904 crm_exit(rc);
905 }
906
907 pid = fork();
908 if (pid < 0) {
909 fprintf(stderr, "%s: could not start daemon\n", name);
910 crm_perror(LOG_ERR, "fork");
911 crm_exit(EINVAL);
912
913 } else if (pid > 0) {
914 crm_exit(pcmk_ok);
915 }
916
917 rc = crm_lock_pidfile(pidfile, name);
918 if(rc < pcmk_ok) {
919 crm_err("Could not lock '%s' for %s: %s (%d)", pidfile, name, pcmk_strerror(rc), rc);
920 printf("Could not lock '%s' for %s: %s (%d)\n", pidfile, name, pcmk_strerror(rc), rc);
921 crm_exit(rc);
922 }
923
924 umask(S_IWGRP | S_IWOTH | S_IROTH);
925
926 close(STDIN_FILENO);
927 (void)open(devnull, O_RDONLY); /* Stdin: fd 0 */
928 close(STDOUT_FILENO);
929 (void)open(devnull, O_WRONLY); /* Stdout: fd 1 */
930 close(STDERR_FILENO);
931 (void)open(devnull, O_WRONLY); /* Stderr: fd 2 */
932 }
933
934 char *
crm_meta_name(const char * field)935 crm_meta_name(const char *field)
936 {
937 int lpc = 0;
938 int max = 0;
939 char *crm_name = NULL;
940
941 CRM_CHECK(field != NULL, return NULL);
942 crm_name = crm_concat(CRM_META, field, '_');
943
944 /* Massage the names so they can be used as shell variables */
945 max = strlen(crm_name);
946 for (; lpc < max; lpc++) {
947 switch (crm_name[lpc]) {
948 case '-':
949 crm_name[lpc] = '_';
950 break;
951 }
952 }
953 return crm_name;
954 }
955
956 const char *
crm_meta_value(GHashTable * hash,const char * field)957 crm_meta_value(GHashTable * hash, const char *field)
958 {
959 char *key = NULL;
960 const char *value = NULL;
961
962 key = crm_meta_name(field);
963 if (key) {
964 value = g_hash_table_lookup(hash, key);
965 free(key);
966 }
967
968 return value;
969 }
970
971 static struct option *
crm_create_long_opts(struct crm_option * long_options)972 crm_create_long_opts(struct crm_option *long_options)
973 {
974 struct option *long_opts = NULL;
975
976 #ifdef HAVE_GETOPT_H
977 int index = 0, lpc = 0;
978
979 /*
980 * A previous, possibly poor, choice of '?' as the short form of --help
981 * means that getopt_long() returns '?' for both --help and for "unknown option"
982 *
983 * This dummy entry allows us to differentiate between the two in crm_get_option()
984 * and exit with the correct error code
985 */
986 long_opts = realloc_safe(long_opts, (index + 1) * sizeof(struct option));
987 long_opts[index].name = "__dummmy__";
988 long_opts[index].has_arg = 0;
989 long_opts[index].flag = 0;
990 long_opts[index].val = '_';
991 index++;
992
993 for (lpc = 0; long_options[lpc].name != NULL; lpc++) {
994 if (long_options[lpc].name[0] == '-') {
995 continue;
996 }
997
998 long_opts = realloc_safe(long_opts, (index + 1) * sizeof(struct option));
999 /*fprintf(stderr, "Creating %d %s = %c\n", index,
1000 * long_options[lpc].name, long_options[lpc].val); */
1001 long_opts[index].name = long_options[lpc].name;
1002 long_opts[index].has_arg = long_options[lpc].has_arg;
1003 long_opts[index].flag = long_options[lpc].flag;
1004 long_opts[index].val = long_options[lpc].val;
1005 index++;
1006 }
1007
1008 /* Now create the list terminator */
1009 long_opts = realloc_safe(long_opts, (index + 1) * sizeof(struct option));
1010 long_opts[index].name = NULL;
1011 long_opts[index].has_arg = 0;
1012 long_opts[index].flag = 0;
1013 long_opts[index].val = 0;
1014 #endif
1015
1016 return long_opts;
1017 }
1018
1019 void
crm_set_options(const char * short_options,const char * app_usage,struct crm_option * long_options,const char * app_desc)1020 crm_set_options(const char *short_options, const char *app_usage, struct crm_option *long_options,
1021 const char *app_desc)
1022 {
1023 if (short_options) {
1024 crm_short_options = strdup(short_options);
1025
1026 } else if (long_options) {
1027 int lpc = 0;
1028 int opt_string_len = 0;
1029 char *local_short_options = NULL;
1030
1031 for (lpc = 0; long_options[lpc].name != NULL; lpc++) {
1032 if (long_options[lpc].val && long_options[lpc].val != '-' && long_options[lpc].val < UCHAR_MAX) {
1033 local_short_options = realloc_safe(local_short_options, opt_string_len + 4);
1034 local_short_options[opt_string_len++] = long_options[lpc].val;
1035 /* getopt(3) says: Two colons mean an option takes an optional arg; */
1036 if (long_options[lpc].has_arg == optional_argument) {
1037 local_short_options[opt_string_len++] = ':';
1038 }
1039 if (long_options[lpc].has_arg >= required_argument) {
1040 local_short_options[opt_string_len++] = ':';
1041 }
1042 local_short_options[opt_string_len] = 0;
1043 }
1044 }
1045 crm_short_options = local_short_options;
1046 crm_trace("Generated short option string: '%s'", local_short_options);
1047 }
1048
1049 if (long_options) {
1050 crm_long_options = long_options;
1051 }
1052 if (app_desc) {
1053 crm_app_description = app_desc;
1054 }
1055 if (app_usage) {
1056 crm_app_usage = app_usage;
1057 }
1058 }
1059
1060 int
crm_get_option(int argc,char ** argv,int * index)1061 crm_get_option(int argc, char **argv, int *index)
1062 {
1063 return crm_get_option_long(argc, argv, index, NULL);
1064 }
1065
1066 int
crm_get_option_long(int argc,char ** argv,int * index,const char ** longname)1067 crm_get_option_long(int argc, char **argv, int *index, const char **longname)
1068 {
1069 #ifdef HAVE_GETOPT_H
1070 static struct option *long_opts = NULL;
1071
1072 if (long_opts == NULL && crm_long_options) {
1073 long_opts = crm_create_long_opts(crm_long_options);
1074 }
1075
1076 *index = 0;
1077 if (long_opts) {
1078 int flag = getopt_long(argc, argv, crm_short_options, long_opts, index);
1079
1080 switch (flag) {
1081 case 0:
1082 if (long_opts[*index].val) {
1083 return long_opts[*index].val;
1084 } else if (longname) {
1085 *longname = long_opts[*index].name;
1086 } else {
1087 crm_notice("Unhandled option --%s", long_opts[*index].name);
1088 return flag;
1089 }
1090 case -1: /* End of option processing */
1091 break;
1092 case ':':
1093 crm_trace("Missing argument");
1094 crm_help('?', 1);
1095 break;
1096 case '?':
1097 crm_help('?', *index ? 0 : 1);
1098 break;
1099 }
1100 return flag;
1101 }
1102 #endif
1103
1104 if (crm_short_options) {
1105 return getopt(argc, argv, crm_short_options);
1106 }
1107
1108 return -1;
1109 }
1110
1111 int
crm_help(char cmd,int exit_code)1112 crm_help(char cmd, int exit_code)
1113 {
1114 int i = 0;
1115 FILE *stream = (exit_code ? stderr : stdout);
1116
1117 if (cmd == 'v' || cmd == '$') {
1118 fprintf(stream, "Pacemaker %s\n", PACEMAKER_VERSION);
1119 fprintf(stream, "Written by Andrew Beekhof\n");
1120 goto out;
1121 }
1122
1123 if (cmd == '!') {
1124 fprintf(stream, "Pacemaker %s (Build: %s): %s\n", PACEMAKER_VERSION, BUILD_VERSION, CRM_FEATURES);
1125 goto out;
1126 }
1127
1128 fprintf(stream, "%s - %s\n", crm_system_name, crm_app_description);
1129
1130 if (crm_app_usage) {
1131 fprintf(stream, "Usage: %s %s\n", crm_system_name, crm_app_usage);
1132 }
1133
1134 if (crm_long_options) {
1135 fprintf(stream, "Options:\n");
1136 for (i = 0; crm_long_options[i].name != NULL; i++) {
1137 if (crm_long_options[i].flags & pcmk_option_hidden) {
1138
1139 } else if (crm_long_options[i].flags & pcmk_option_paragraph) {
1140 fprintf(stream, "%s\n\n", crm_long_options[i].desc);
1141
1142 } else if (crm_long_options[i].flags & pcmk_option_example) {
1143 fprintf(stream, "\t#%s\n\n", crm_long_options[i].desc);
1144
1145 } else if (crm_long_options[i].val == '-' && crm_long_options[i].desc) {
1146 fprintf(stream, "%s\n", crm_long_options[i].desc);
1147
1148 } else {
1149 /* is val printable as char ? */
1150 if (crm_long_options[i].val && crm_long_options[i].val <= UCHAR_MAX) {
1151 fprintf(stream, " -%c,", crm_long_options[i].val);
1152 } else {
1153 fputs(" ", stream);
1154 }
1155 fprintf(stream, " --%s%s\t%s\n", crm_long_options[i].name,
1156 crm_long_options[i].has_arg == optional_argument ? "[=value]" :
1157 crm_long_options[i].has_arg == required_argument ? "=value" : "",
1158 crm_long_options[i].desc ? crm_long_options[i].desc : "");
1159 }
1160 }
1161
1162 } else if (crm_short_options) {
1163 fprintf(stream, "Usage: %s - %s\n", crm_system_name, crm_app_description);
1164 for (i = 0; crm_short_options[i] != 0; i++) {
1165 int has_arg = no_argument /* 0 */;
1166
1167 if (crm_short_options[i + 1] == ':') {
1168 if (crm_short_options[i + 2] == ':')
1169 has_arg = optional_argument /* 2 */;
1170 else
1171 has_arg = required_argument /* 1 */;
1172 }
1173
1174 fprintf(stream, " -%c %s\n", crm_short_options[i],
1175 has_arg == optional_argument ? "[value]" :
1176 has_arg == required_argument ? "{value}" : "");
1177 i += has_arg;
1178 }
1179 }
1180
1181 fprintf(stream, "\nReport bugs to %s\n", PACKAGE_BUGREPORT);
1182
1183 out:
1184 return crm_exit(exit_code);
1185 }
1186
cib_ipc_servers_init(qb_ipcs_service_t ** ipcs_ro,qb_ipcs_service_t ** ipcs_rw,qb_ipcs_service_t ** ipcs_shm,struct qb_ipcs_service_handlers * ro_cb,struct qb_ipcs_service_handlers * rw_cb)1187 void cib_ipc_servers_init(qb_ipcs_service_t **ipcs_ro,
1188 qb_ipcs_service_t **ipcs_rw,
1189 qb_ipcs_service_t **ipcs_shm,
1190 struct qb_ipcs_service_handlers *ro_cb,
1191 struct qb_ipcs_service_handlers *rw_cb)
1192 {
1193 *ipcs_ro = mainloop_add_ipc_server(cib_channel_ro, QB_IPC_NATIVE, ro_cb);
1194 *ipcs_rw = mainloop_add_ipc_server(cib_channel_rw, QB_IPC_NATIVE, rw_cb);
1195 *ipcs_shm = mainloop_add_ipc_server(cib_channel_shm, QB_IPC_SHM, rw_cb);
1196
1197 if (*ipcs_ro == NULL || *ipcs_rw == NULL || *ipcs_shm == NULL) {
1198 crm_err("Failed to create cib servers: exiting and inhibiting respawn.");
1199 crm_warn("Verify pacemaker and pacemaker_remote are not both enabled.");
1200 crm_exit(DAEMON_RESPAWN_STOP);
1201 }
1202 }
1203
cib_ipc_servers_destroy(qb_ipcs_service_t * ipcs_ro,qb_ipcs_service_t * ipcs_rw,qb_ipcs_service_t * ipcs_shm)1204 void cib_ipc_servers_destroy(qb_ipcs_service_t *ipcs_ro,
1205 qb_ipcs_service_t *ipcs_rw,
1206 qb_ipcs_service_t *ipcs_shm)
1207 {
1208 qb_ipcs_destroy(ipcs_ro);
1209 qb_ipcs_destroy(ipcs_rw);
1210 qb_ipcs_destroy(ipcs_shm);
1211 }
1212
1213 qb_ipcs_service_t *
crmd_ipc_server_init(struct qb_ipcs_service_handlers * cb)1214 crmd_ipc_server_init(struct qb_ipcs_service_handlers *cb)
1215 {
1216 return mainloop_add_ipc_server(CRM_SYSTEM_CRMD, QB_IPC_NATIVE, cb);
1217 }
1218
1219 void
attrd_ipc_server_init(qb_ipcs_service_t ** ipcs,struct qb_ipcs_service_handlers * cb)1220 attrd_ipc_server_init(qb_ipcs_service_t **ipcs, struct qb_ipcs_service_handlers *cb)
1221 {
1222 *ipcs = mainloop_add_ipc_server(T_ATTRD, QB_IPC_NATIVE, cb);
1223
1224 if (*ipcs == NULL) {
1225 crm_err("Failed to create attrd servers: exiting and inhibiting respawn.");
1226 crm_warn("Verify pacemaker and pacemaker_remote are not both enabled.");
1227 crm_exit(DAEMON_RESPAWN_STOP);
1228 }
1229 }
1230
1231 void
stonith_ipc_server_init(qb_ipcs_service_t ** ipcs,struct qb_ipcs_service_handlers * cb)1232 stonith_ipc_server_init(qb_ipcs_service_t **ipcs, struct qb_ipcs_service_handlers *cb)
1233 {
1234 *ipcs = mainloop_add_ipc_server_with_prio("stonith-ng", QB_IPC_NATIVE, cb,
1235 QB_LOOP_HIGH);
1236
1237 if (*ipcs == NULL) {
1238 crm_err("Failed to create stonith-ng servers: exiting and inhibiting respawn.");
1239 crm_warn("Verify pacemaker and pacemaker_remote are not both enabled.");
1240 crm_exit(DAEMON_RESPAWN_STOP);
1241 }
1242 }
1243
1244 void *
find_library_function(void ** handle,const char * lib,const char * fn,gboolean fatal)1245 find_library_function(void **handle, const char *lib, const char *fn, gboolean fatal)
1246 {
1247 char *error;
1248 void *a_function;
1249
1250 if (*handle == NULL) {
1251 *handle = dlopen(lib, RTLD_LAZY);
1252 }
1253
1254 if (!(*handle)) {
1255 crm_err("%sCould not open %s: %s", fatal ? "Fatal: " : "", lib, dlerror());
1256 if (fatal) {
1257 crm_exit(DAEMON_RESPAWN_STOP);
1258 }
1259 return NULL;
1260 }
1261
1262 a_function = dlsym(*handle, fn);
1263 if (a_function == NULL) {
1264 error = dlerror();
1265 crm_err("%sCould not find %s in %s: %s", fatal ? "Fatal: " : "", fn, lib, error);
1266 if (fatal) {
1267 crm_exit(DAEMON_RESPAWN_STOP);
1268 }
1269 }
1270
1271 return a_function;
1272 }
1273
1274 #ifdef HAVE_UUID_UUID_H
1275 # include <uuid/uuid.h>
1276 #endif
1277
1278 char *
crm_generate_uuid(void)1279 crm_generate_uuid(void)
1280 {
1281 unsigned char uuid[16];
1282 char *buffer = malloc(37); /* Including NUL byte */
1283
1284 uuid_generate(uuid);
1285 uuid_unparse(uuid, buffer);
1286 return buffer;
1287 }
1288
1289 /*!
1290 * \brief Check whether a string represents a cluster daemon name
1291 *
1292 * \param[in] name String to check
1293 *
1294 * \return TRUE if name is standard client name used by daemons, FALSE otherwise
1295 */
1296 bool
crm_is_daemon_name(const char * name)1297 crm_is_daemon_name(const char *name)
1298 {
1299 return (name &&
1300 (!strcmp(name, CRM_SYSTEM_CRMD)
1301 || !strcmp(name, CRM_SYSTEM_STONITHD)
1302 || !strcmp(name, T_ATTRD)
1303 || !strcmp(name, CRM_SYSTEM_CIB)
1304 || !strcmp(name, CRM_SYSTEM_MCP)
1305 || !strcmp(name, CRM_SYSTEM_DC)
1306 || !strcmp(name, CRM_SYSTEM_TENGINE)
1307 || !strcmp(name, CRM_SYSTEM_LRMD)));
1308 }
1309
1310 #include <md5.h>
1311
1312 char *
crm_md5sum(const char * buffer)1313 crm_md5sum(const char *buffer)
1314 {
1315 int lpc = 0, len = 0;
1316 char *digest = NULL;
1317 unsigned char raw_digest[MD5_DIGEST_SIZE];
1318
1319 if (buffer == NULL) {
1320 buffer = "";
1321 }
1322 len = strlen(buffer);
1323
1324 crm_trace("Beginning digest of %d bytes", len);
1325 digest = malloc(2 * MD5_DIGEST_SIZE + 1);
1326 if(digest) {
1327 md5_buffer(buffer, len, raw_digest);
1328 for (lpc = 0; lpc < MD5_DIGEST_SIZE; lpc++) {
1329 sprintf(digest + (2 * lpc), "%02x", raw_digest[lpc]);
1330 }
1331 digest[(2 * MD5_DIGEST_SIZE)] = 0;
1332 crm_trace("Digest %s.", digest);
1333
1334 } else {
1335 crm_err("Could not create digest");
1336 }
1337 return digest;
1338 }
1339
1340 #ifdef HAVE_GNUTLS_GNUTLS_H
1341 void
crm_gnutls_global_init(void)1342 crm_gnutls_global_init(void)
1343 {
1344 signal(SIGPIPE, SIG_IGN);
1345 gnutls_global_init();
1346 }
1347 #endif
1348