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