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