This source file includes following definitions.
- crm_glib_handler
- crm_trigger_blackbox
- crm_log_deinit
- set_format_string
- logfile_disabled
- chown_logfile
- chmod_logfile
- set_logfile_permissions
- enable_logfile
- disable_logfile
- setenv_logfile
- pcmk__add_logfile
- pcmk__add_logfiles
- blackbox_logger
- crm_control_blackbox
- crm_enable_blackbox
- crm_disable_blackbox
- crm_write_blackbox
- crm_quark_to_string
- crm_log_filter_source
- strchrnul
- crm_log_filter
- crm_is_callsite_active
- crm_update_callsites
- crm_tracing_enabled
- crm_priority2int
- set_identity
- crm_log_preinit
- crm_log_init
- set_crm_log_level
- crm_enable_stderr
- crm_bump_log_level
- get_crm_log_level
- crm_log_args
- crm_log_output_fn
- pcmk__cli_init_logging
- pcmk_log_xml_as
- pcmk__log_xml_changes_as
- pcmk__log_xml_patchset_as
- pcmk__free_common_logger
- crm_log_cli_init
- crm_add_logfile
- pcmk_log_xml_impl
- pcmk__set_config_error_handler
- pcmk__set_config_warning_handler
1
2
3
4
5
6
7
8
9
10 #include <crm_internal.h>
11
12 #include <sys/param.h>
13 #include <sys/types.h>
14 #include <sys/wait.h>
15 #include <sys/stat.h>
16 #include <sys/utsname.h>
17
18 #include <stdio.h>
19 #include <unistd.h>
20 #include <string.h>
21 #include <stdlib.h>
22 #include <limits.h>
23 #include <ctype.h>
24 #include <pwd.h>
25 #include <grp.h>
26 #include <time.h>
27 #include <libgen.h>
28 #include <signal.h>
29 #include <bzlib.h>
30
31 #include <qb/qbdefs.h>
32
33 #include <crm/crm.h>
34 #include <crm/common/mainloop.h>
35
36
37 #ifdef QB_FEATURE_LOG_HIRES_TIMESTAMPS
38 #define TIMESTAMP_FORMAT_SPEC "%%T"
39 typedef struct timespec *log_time_t;
40 #else
41 #define TIMESTAMP_FORMAT_SPEC "%%t"
42 typedef time_t log_time_t;
43 #endif
44
45 unsigned int crm_log_level = LOG_INFO;
46 unsigned int crm_trace_nonlog = 0;
47 bool pcmk__is_daemon = false;
48 char *pcmk__our_nodename = NULL;
49
50 static unsigned int crm_log_priority = LOG_NOTICE;
51 static GLogFunc glib_log_default = NULL;
52 static pcmk__output_t *logger_out = NULL;
53
54 pcmk__config_error_func pcmk__config_error_handler = NULL;
55 pcmk__config_warning_func pcmk__config_warning_handler = NULL;
56 void *pcmk__config_error_context = NULL;
57 void *pcmk__config_warning_context = NULL;
58
59 static gboolean crm_tracing_enabled(void);
60
61 static void
62 crm_glib_handler(const gchar * log_domain, GLogLevelFlags flags, const gchar * message,
63 gpointer user_data)
64 {
65 int log_level = LOG_WARNING;
66 GLogLevelFlags msg_level = (flags & G_LOG_LEVEL_MASK);
67 static struct qb_log_callsite *glib_cs = NULL;
68
69 if (glib_cs == NULL) {
70 glib_cs = qb_log_callsite_get(__func__, __FILE__, "glib-handler",
71 LOG_DEBUG, __LINE__, crm_trace_nonlog);
72 }
73
74 switch (msg_level) {
75 case G_LOG_LEVEL_CRITICAL:
76 log_level = LOG_CRIT;
77
78 if (!crm_is_callsite_active(glib_cs, LOG_DEBUG, crm_trace_nonlog)) {
79
80 crm_abort(__FILE__, __func__, __LINE__, message, TRUE, TRUE);
81 }
82 break;
83
84 case G_LOG_LEVEL_ERROR:
85 log_level = LOG_ERR;
86 break;
87 case G_LOG_LEVEL_MESSAGE:
88 log_level = LOG_NOTICE;
89 break;
90 case G_LOG_LEVEL_INFO:
91 log_level = LOG_INFO;
92 break;
93 case G_LOG_LEVEL_DEBUG:
94 log_level = LOG_DEBUG;
95 break;
96
97 case G_LOG_LEVEL_WARNING:
98 case G_LOG_FLAG_RECURSION:
99 case G_LOG_FLAG_FATAL:
100 case G_LOG_LEVEL_MASK:
101 log_level = LOG_WARNING;
102 break;
103 }
104
105 do_crm_log(log_level, "%s: %s", log_domain, message);
106 }
107
108 #ifndef NAME_MAX
109 # define NAME_MAX 256
110 #endif
111
112
113
114
115
116
117
118
119
120 static void
121 crm_trigger_blackbox(int nsig)
122 {
123 if(nsig == SIGTRAP) {
124
125 crm_enable_blackbox(nsig);
126 }
127 crm_write_blackbox(nsig, NULL);
128 }
129
130 void
131 crm_log_deinit(void)
132 {
133 if (glib_log_default != NULL) {
134 g_log_set_default_handler(glib_log_default, NULL);
135 }
136 }
137
138 #define FMT_MAX 256
139
140
141
142
143
144
145
146
147
148
149
150
151
152 static void
153 set_format_string(int method, const char *daemon, pid_t use_pid,
154 const char *use_nodename)
155 {
156 if (method == QB_LOG_SYSLOG) {
157
158 crm_extended_logging(method, QB_FALSE);
159 qb_log_format_set(method, "%g %p: %b");
160
161 } else {
162
163
164 int offset = 0;
165 char fmt[FMT_MAX];
166
167 if (method > QB_LOG_STDERR) {
168
169 offset += snprintf(fmt + offset, FMT_MAX - offset,
170 TIMESTAMP_FORMAT_SPEC " %s %-20s[%lu] ",
171 use_nodename, daemon, (unsigned long) use_pid);
172 }
173
174
175 offset += snprintf(fmt + offset, FMT_MAX - offset, "(%%n");
176 if (crm_tracing_enabled()) {
177
178 offset += snprintf(fmt + offset, FMT_MAX - offset, "@%%f:%%l");
179 }
180 offset += snprintf(fmt + offset, FMT_MAX - offset, ")");
181
182
183 offset += snprintf(fmt + offset, FMT_MAX - offset, " %%g\t%%p: %%b");
184
185 CRM_LOG_ASSERT(offset > 0);
186 qb_log_format_set(method, fmt);
187 }
188 }
189
190 #define DEFAULT_LOG_FILE CRM_LOG_DIR "/pacemaker.log"
191
192 static bool
193 logfile_disabled(const char *filename)
194 {
195 return pcmk__str_eq(filename, PCMK__VALUE_NONE, pcmk__str_casei)
196 || pcmk__str_eq(filename, "/dev/null", pcmk__str_none);
197 }
198
199
200
201
202
203
204
205
206
207
208 static int
209 chown_logfile(const char *filename, int logfd)
210 {
211 uid_t pcmk_uid = 0;
212 gid_t pcmk_gid = 0;
213 struct stat st;
214 int rc;
215
216
217 if (fstat(logfd, &st) < 0) {
218 return errno;
219 }
220
221
222
223 rc = pcmk_daemon_user(&pcmk_uid, &pcmk_gid);
224 if (rc != pcmk_ok) {
225 rc = pcmk_legacy2rc(rc);
226 crm_warn("Not changing '%s' ownership because user information "
227 "unavailable: %s", filename, pcmk_rc_str(rc));
228 return pcmk_rc_ok;
229 }
230 if ((st.st_gid == pcmk_gid)
231 && ((st.st_mode & S_IRWXG) == (S_IRGRP|S_IWGRP))) {
232 return pcmk_rc_ok;
233 }
234 if (fchown(logfd, pcmk_uid, pcmk_gid) < 0) {
235 crm_warn("Couldn't change '%s' ownership to user %s gid %d: %s",
236 filename, CRM_DAEMON_USER, pcmk_gid, strerror(errno));
237 }
238 return pcmk_rc_ok;
239 }
240
241
242 static void
243 chmod_logfile(const char *filename, int logfd)
244 {
245 const char *modestr = pcmk__env_option(PCMK__ENV_LOGFILE_MODE);
246 mode_t filemode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP;
247
248 if (modestr != NULL) {
249 long filemode_l = strtol(modestr, NULL, 8);
250
251 if ((filemode_l != LONG_MIN) && (filemode_l != LONG_MAX)) {
252 filemode = (mode_t) filemode_l;
253 }
254 }
255 if ((filemode != 0) && (fchmod(logfd, filemode) < 0)) {
256 crm_warn("Couldn't change '%s' mode to %04o: %s",
257 filename, filemode, strerror(errno));
258 }
259 }
260
261
262 static int
263 set_logfile_permissions(const char *filename, FILE *logfile)
264 {
265 if (geteuid() == 0) {
266 int logfd = fileno(logfile);
267 int rc = chown_logfile(filename, logfd);
268
269 if (rc != pcmk_rc_ok) {
270 return rc;
271 }
272 chmod_logfile(filename, logfd);
273 }
274 return pcmk_rc_ok;
275 }
276
277
278 static void
279 enable_logfile(int fd)
280 {
281 qb_log_ctl(fd, QB_LOG_CONF_ENABLED, QB_TRUE);
282 #if 0
283 qb_log_ctl(fd, QB_LOG_CONF_FILE_SYNC, 1);
284 #endif
285
286 #ifdef HAVE_qb_log_conf_QB_LOG_CONF_MAX_LINE_LEN
287
288 qb_log_ctl(fd, QB_LOG_CONF_MAX_LINE_LEN, 800);
289 #endif
290
291 crm_update_callsites();
292 }
293
294 static inline void
295 disable_logfile(int fd)
296 {
297 qb_log_ctl(fd, QB_LOG_CONF_ENABLED, QB_FALSE);
298 }
299
300 static void
301 setenv_logfile(const char *filename)
302 {
303
304 if (pcmk__env_option(PCMK__ENV_LOGFILE) == NULL) {
305 pcmk__set_env_option(PCMK__ENV_LOGFILE, filename, true);
306 }
307 }
308
309
310
311
312
313
314
315
316 int
317 pcmk__add_logfile(const char *filename)
318 {
319
320
321
322
323
324 int fd = 0;
325 int rc = pcmk_rc_ok;
326 FILE *logfile = NULL;
327 bool is_default = false;
328
329 static int default_fd = -1;
330 static bool have_logfile = false;
331
332
333 if (filename == NULL) {
334 if (have_logfile) {
335 return pcmk_rc_ok;
336 }
337 filename = DEFAULT_LOG_FILE;
338 }
339
340
341 if (logfile_disabled(filename)) {
342 return pcmk_rc_ok;
343 }
344
345
346 is_default = pcmk__str_eq(filename, DEFAULT_LOG_FILE, pcmk__str_none);
347 if (is_default && (default_fd >= 0)) {
348 return pcmk_rc_ok;
349 }
350
351
352 logfile = fopen(filename, "a");
353 if (logfile == NULL) {
354 rc = errno;
355 crm_warn("Logging to '%s' is disabled: %s " CRM_XS " uid=%u gid=%u",
356 filename, strerror(rc), geteuid(), getegid());
357 return rc;
358 }
359
360 rc = set_logfile_permissions(filename, logfile);
361 if (rc != pcmk_rc_ok) {
362 crm_warn("Logging to '%s' is disabled: %s " CRM_XS " permissions",
363 filename, strerror(rc));
364 fclose(logfile);
365 return rc;
366 }
367
368
369 fclose(logfile);
370 fd = qb_log_file_open(filename);
371 if (fd < 0) {
372 crm_warn("Logging to '%s' is disabled: %s " CRM_XS " qb_log_file_open",
373 filename, strerror(-fd));
374 return -fd;
375 }
376
377 if (is_default) {
378 default_fd = fd;
379 setenv_logfile(filename);
380
381 } else if (default_fd >= 0) {
382 crm_notice("Switching logging to %s", filename);
383 disable_logfile(default_fd);
384 }
385
386 crm_notice("Additional logging available in %s", filename);
387 enable_logfile(fd);
388 have_logfile = true;
389 return pcmk_rc_ok;
390 }
391
392
393
394
395
396
397
398
399
400 void
401 pcmk__add_logfiles(gchar **log_files, pcmk__output_t *out)
402 {
403 if (log_files == NULL) {
404 return;
405 }
406
407 for (gchar **fname = log_files; *fname != NULL; fname++) {
408 int rc = pcmk__add_logfile(*fname);
409
410 if (rc != pcmk_rc_ok) {
411 out->err(out, "Logging to %s is disabled: %s",
412 *fname, pcmk_rc_str(rc));
413 }
414 }
415 }
416
417 static int blackbox_trigger = 0;
418 static volatile char *blackbox_file_prefix = NULL;
419
420 static void
421 blackbox_logger(int32_t t, struct qb_log_callsite *cs, log_time_t timestamp,
422 const char *msg)
423 {
424 if(cs && cs->priority < LOG_ERR) {
425 crm_write_blackbox(SIGTRAP, cs);
426 } else {
427 crm_write_blackbox(0, cs);
428 }
429 }
430
431 static void
432 crm_control_blackbox(int nsig, bool enable)
433 {
434 int lpc = 0;
435
436 if (blackbox_file_prefix == NULL) {
437 pid_t pid = getpid();
438
439 blackbox_file_prefix = crm_strdup_printf("%s/%s-%lu",
440 CRM_BLACKBOX_DIR,
441 crm_system_name,
442 (unsigned long) pid);
443 }
444
445 if (enable && qb_log_ctl(QB_LOG_BLACKBOX, QB_LOG_CONF_STATE_GET, 0) != QB_LOG_STATE_ENABLED) {
446 qb_log_ctl(QB_LOG_BLACKBOX, QB_LOG_CONF_SIZE, 5 * 1024 * 1024);
447 qb_log_ctl(QB_LOG_BLACKBOX, QB_LOG_CONF_ENABLED, QB_TRUE);
448
449
450 for (lpc = QB_LOG_BLACKBOX; lpc < QB_LOG_TARGET_MAX; lpc++) {
451 qb_log_ctl(lpc, QB_LOG_CONF_FILE_SYNC, QB_TRUE);
452 }
453
454 crm_notice("Initiated blackbox recorder: %s", blackbox_file_prefix);
455
456
457 crm_signal_handler(SIGSEGV, crm_trigger_blackbox);
458 crm_signal_handler(SIGABRT, crm_trigger_blackbox);
459 crm_signal_handler(SIGILL, crm_trigger_blackbox);
460 crm_signal_handler(SIGBUS, crm_trigger_blackbox);
461 crm_signal_handler(SIGFPE, crm_trigger_blackbox);
462
463 crm_update_callsites();
464
465 blackbox_trigger = qb_log_custom_open(blackbox_logger, NULL, NULL, NULL);
466 qb_log_ctl(blackbox_trigger, QB_LOG_CONF_ENABLED, QB_TRUE);
467 crm_trace("Trigger: %d is %d %d", blackbox_trigger,
468 qb_log_ctl(blackbox_trigger, QB_LOG_CONF_STATE_GET, 0), QB_LOG_STATE_ENABLED);
469
470 crm_update_callsites();
471
472 } else if (!enable && qb_log_ctl(QB_LOG_BLACKBOX, QB_LOG_CONF_STATE_GET, 0) == QB_LOG_STATE_ENABLED) {
473 qb_log_ctl(QB_LOG_BLACKBOX, QB_LOG_CONF_ENABLED, QB_FALSE);
474
475
476 for (lpc = QB_LOG_BLACKBOX; lpc < QB_LOG_TARGET_MAX; lpc++) {
477 qb_log_ctl(lpc, QB_LOG_CONF_FILE_SYNC, QB_FALSE);
478 }
479 }
480 }
481
482 void
483 crm_enable_blackbox(int nsig)
484 {
485 crm_control_blackbox(nsig, TRUE);
486 }
487
488 void
489 crm_disable_blackbox(int nsig)
490 {
491 crm_control_blackbox(nsig, FALSE);
492 }
493
494
495
496
497
498
499
500
501
502
503
504 void
505 crm_write_blackbox(int nsig, const struct qb_log_callsite *cs)
506 {
507 static volatile int counter = 1;
508 static volatile time_t last = 0;
509
510 char buffer[NAME_MAX];
511 time_t now = time(NULL);
512
513 if (blackbox_file_prefix == NULL) {
514 return;
515 }
516
517 switch (nsig) {
518 case 0:
519 case SIGTRAP:
520
521
522 if (nsig == 0 && now == last) {
523
524 return;
525 }
526
527 snprintf(buffer, NAME_MAX, "%s.%d", blackbox_file_prefix, counter++);
528 if (nsig == SIGTRAP) {
529 crm_notice("Blackbox dump requested, please see %s for contents", buffer);
530
531 } else if (cs) {
532 syslog(LOG_NOTICE,
533 "Problem detected at %s:%d (%s), please see %s for additional details",
534 cs->function, cs->lineno, cs->filename, buffer);
535 } else {
536 crm_notice("Problem detected, please see %s for additional details", buffer);
537 }
538
539 last = now;
540 qb_log_blackbox_write_to_file(buffer);
541
542
543
544
545 qb_log_ctl(QB_LOG_BLACKBOX, QB_LOG_CONF_ENABLED, QB_FALSE);
546 qb_log_ctl(QB_LOG_BLACKBOX, QB_LOG_CONF_ENABLED, QB_TRUE);
547 break;
548
549 default:
550
551
552
553 crm_signal_handler(nsig, SIG_DFL);
554 qb_log_blackbox_write_to_file((const char *)blackbox_file_prefix);
555 qb_log_ctl(QB_LOG_BLACKBOX, QB_LOG_CONF_ENABLED, QB_FALSE);
556 raise(nsig);
557 break;
558 }
559 }
560
561 static const char *
562 crm_quark_to_string(uint32_t tag)
563 {
564 const char *text = g_quark_to_string(tag);
565
566 if (text) {
567 return text;
568 }
569 return "";
570 }
571
572 static void
573 crm_log_filter_source(int source, const char *trace_files, const char *trace_fns,
574 const char *trace_fmts, const char *trace_tags, const char *trace_blackbox,
575 struct qb_log_callsite *cs)
576 {
577 if (qb_log_ctl(source, QB_LOG_CONF_STATE_GET, 0) != QB_LOG_STATE_ENABLED) {
578 return;
579 } else if (cs->tags != crm_trace_nonlog && source == QB_LOG_BLACKBOX) {
580
581 qb_bit_set(cs->targets, source);
582
583 } else if (source == blackbox_trigger && blackbox_trigger > 0) {
584
585 if (cs->priority <= LOG_ERR) {
586 qb_bit_set(cs->targets, source);
587
588 } else if (trace_blackbox) {
589 char *key = crm_strdup_printf("%s:%d", cs->function, cs->lineno);
590
591 if (strstr(trace_blackbox, key) != NULL) {
592 qb_bit_set(cs->targets, source);
593 }
594 free(key);
595 }
596
597 } else if (source == QB_LOG_SYSLOG) {
598 if (cs->priority <= crm_log_priority && cs->priority <= crm_log_level) {
599 qb_bit_set(cs->targets, source);
600 }
601
602 } else if (cs->priority <= crm_log_level) {
603 qb_bit_set(cs->targets, source);
604 } else if (trace_files && strstr(trace_files, cs->filename) != NULL) {
605 qb_bit_set(cs->targets, source);
606 } else if (trace_fns && strstr(trace_fns, cs->function) != NULL) {
607 qb_bit_set(cs->targets, source);
608 } else if (trace_fmts && strstr(trace_fmts, cs->format) != NULL) {
609 qb_bit_set(cs->targets, source);
610 } else if (trace_tags
611 && cs->tags != 0
612 && cs->tags != crm_trace_nonlog && g_quark_to_string(cs->tags) != NULL) {
613 qb_bit_set(cs->targets, source);
614 }
615 }
616
617 #ifndef HAVE_STRCHRNUL
618
619
620
621 static const char *
622 strchrnul(const char *s, int c)
623 {
624 while ((*s != c) && (*s != '\0')) {
625 ++s;
626 }
627 return s;
628 }
629 #endif
630
631 static void
632 crm_log_filter(struct qb_log_callsite *cs)
633 {
634 int lpc = 0;
635 static int need_init = 1;
636 static const char *trace_fns = NULL;
637 static const char *trace_tags = NULL;
638 static const char *trace_fmts = NULL;
639 static const char *trace_files = NULL;
640 static const char *trace_blackbox = NULL;
641
642 if (need_init) {
643 need_init = 0;
644 trace_fns = pcmk__env_option(PCMK__ENV_TRACE_FUNCTIONS);
645 trace_fmts = pcmk__env_option(PCMK__ENV_TRACE_FORMATS);
646 trace_tags = pcmk__env_option(PCMK__ENV_TRACE_TAGS);
647 trace_files = pcmk__env_option(PCMK__ENV_TRACE_FILES);
648 trace_blackbox = pcmk__env_option(PCMK__ENV_TRACE_BLACKBOX);
649
650 if (trace_tags != NULL) {
651 uint32_t tag;
652 char token[500];
653 const char *offset = NULL;
654 const char *next = trace_tags;
655
656 do {
657 offset = next;
658 next = strchrnul(offset, ',');
659 snprintf(token, sizeof(token), "%.*s", (int)(next - offset), offset);
660
661 tag = g_quark_from_string(token);
662 crm_info("Created GQuark %u from token '%s' in '%s'", tag, token, trace_tags);
663
664 if (next[0] != 0) {
665 next++;
666 }
667
668 } while (next != NULL && next[0] != 0);
669 }
670 }
671
672 cs->targets = 0;
673 for (lpc = QB_LOG_SYSLOG; lpc < QB_LOG_TARGET_MAX; lpc++) {
674 crm_log_filter_source(lpc, trace_files, trace_fns, trace_fmts, trace_tags, trace_blackbox,
675 cs);
676 }
677 }
678
679 gboolean
680 crm_is_callsite_active(struct qb_log_callsite *cs, uint8_t level, uint32_t tags)
681 {
682 gboolean refilter = FALSE;
683
684 if (cs == NULL) {
685 return FALSE;
686 }
687
688 if (cs->priority != level) {
689 cs->priority = level;
690 refilter = TRUE;
691 }
692
693 if (cs->tags != tags) {
694 cs->tags = tags;
695 refilter = TRUE;
696 }
697
698 if (refilter) {
699 crm_log_filter(cs);
700 }
701
702 if (cs->targets == 0) {
703 return FALSE;
704 }
705 return TRUE;
706 }
707
708 void
709 crm_update_callsites(void)
710 {
711 static gboolean log = TRUE;
712
713 if (log) {
714 log = FALSE;
715 crm_debug
716 ("Enabling callsites based on priority=%d, files=%s, functions=%s, formats=%s, tags=%s",
717 crm_log_level, pcmk__env_option(PCMK__ENV_TRACE_FILES),
718 pcmk__env_option(PCMK__ENV_TRACE_FUNCTIONS),
719 pcmk__env_option(PCMK__ENV_TRACE_FORMATS),
720 pcmk__env_option(PCMK__ENV_TRACE_TAGS));
721 }
722 qb_log_filter_fn_set(crm_log_filter);
723 }
724
725 static gboolean
726 crm_tracing_enabled(void)
727 {
728 return (crm_log_level == LOG_TRACE)
729 || (pcmk__env_option(PCMK__ENV_TRACE_FILES) != NULL)
730 || (pcmk__env_option(PCMK__ENV_TRACE_FUNCTIONS) != NULL)
731 || (pcmk__env_option(PCMK__ENV_TRACE_FORMATS) != NULL)
732 || (pcmk__env_option(PCMK__ENV_TRACE_TAGS) != NULL);
733 }
734
735 static int
736 crm_priority2int(const char *name)
737 {
738 struct syslog_names {
739 const char *name;
740 int priority;
741 };
742 static struct syslog_names p_names[] = {
743 {"emerg", LOG_EMERG},
744 {"alert", LOG_ALERT},
745 {"crit", LOG_CRIT},
746 {"error", LOG_ERR},
747 {"warning", LOG_WARNING},
748 {"notice", LOG_NOTICE},
749 {"info", LOG_INFO},
750 {"debug", LOG_DEBUG},
751 {NULL, -1}
752 };
753 int lpc;
754
755 for (lpc = 0; name != NULL && p_names[lpc].name != NULL; lpc++) {
756 if (pcmk__str_eq(p_names[lpc].name, name, pcmk__str_none)) {
757 return p_names[lpc].priority;
758 }
759 }
760 return crm_log_priority;
761 }
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780 static void
781 set_identity(const char *entity, int argc, char *const *argv)
782 {
783 if (crm_system_name != NULL) {
784 return;
785 }
786
787 if (entity != NULL) {
788 crm_system_name = strdup(entity);
789
790 } else if ((argc > 0) && (argv != NULL)) {
791 char *mutable = strdup(argv[0]);
792 char *modified = basename(mutable);
793
794 if (strstr(modified, "lt-") == modified) {
795 modified += 3;
796 }
797 crm_system_name = strdup(modified);
798 free(mutable);
799
800 } else {
801 crm_system_name = strdup("Unknown");
802 }
803
804 CRM_ASSERT(crm_system_name != NULL);
805
806
807 pcmk__set_env_option(PCMK__ENV_SERVICE, crm_system_name, false);
808 }
809
810 void
811 crm_log_preinit(const char *entity, int argc, char *const *argv)
812 {
813
814
815 struct utsname res;
816 int lpc = 0;
817 int32_t qb_facility = 0;
818 pid_t pid = getpid();
819 const char *nodename = "localhost";
820 static bool have_logging = false;
821
822 if (have_logging) {
823 return;
824 }
825
826 have_logging = true;
827
828 crm_xml_init();
829
830 if (crm_trace_nonlog == 0) {
831 crm_trace_nonlog = g_quark_from_static_string("Pacemaker non-logging tracepoint");
832 }
833
834 umask(S_IWGRP | S_IWOTH | S_IROTH);
835
836
837 glib_log_default = g_log_set_default_handler(crm_glib_handler, NULL);
838
839
840 g_log_set_always_fatal((GLogLevelFlags) 0);
841
842
843
844
845 set_identity(entity, argc, argv);
846
847 qb_facility = qb_log_facility2int("local0");
848 qb_log_init(crm_system_name, qb_facility, LOG_ERR);
849 crm_log_level = LOG_CRIT;
850
851
852 qb_log_ctl(QB_LOG_SYSLOG, QB_LOG_CONF_ENABLED, QB_FALSE);
853 #ifdef HAVE_qb_log_conf_QB_LOG_CONF_MAX_LINE_LEN
854
855 qb_log_ctl(QB_LOG_SYSLOG, QB_LOG_CONF_MAX_LINE_LEN, 256);
856 #endif
857 if (uname(memset(&res, 0, sizeof(res))) == 0 && *res.nodename != '\0') {
858 nodename = res.nodename;
859 }
860
861
862
863
864 qb_log_tags_stringify_fn_set(crm_quark_to_string);
865 for (lpc = QB_LOG_SYSLOG; lpc < QB_LOG_TARGET_MAX; lpc++) {
866 qb_log_ctl(lpc, QB_LOG_CONF_THREADED, QB_FALSE);
867 #ifdef HAVE_qb_log_conf_QB_LOG_CONF_ELLIPSIS
868
869 qb_log_ctl(lpc, QB_LOG_CONF_ELLIPSIS, QB_TRUE);
870 #endif
871 set_format_string(lpc, crm_system_name, pid, nodename);
872 }
873
874 #ifdef ENABLE_NLS
875
876
877
878
879
880
881
882 setlocale(LC_ALL, "");
883
884
885 CRM_ASSERT(bindtextdomain(PACKAGE, PCMK__LOCALE_DIR) != NULL);
886
887
888 CRM_ASSERT(textdomain(PACKAGE) != NULL);
889
890
891 bind_textdomain_codeset(PACKAGE, "UTF-8");
892 #endif
893 }
894
895 gboolean
896 crm_log_init(const char *entity, uint8_t level, gboolean daemon, gboolean to_stderr,
897 int argc, char **argv, gboolean quiet)
898 {
899 const char *syslog_priority = NULL;
900 const char *facility = pcmk__env_option(PCMK__ENV_LOGFACILITY);
901 const char *f_copy = facility;
902
903 pcmk__is_daemon = daemon;
904 crm_log_preinit(entity, argc, argv);
905
906 if (level > LOG_TRACE) {
907 level = LOG_TRACE;
908 }
909 if(level > crm_log_level) {
910 crm_log_level = level;
911 }
912
913
914 if (facility == NULL) {
915 if (pcmk__is_daemon) {
916 facility = "daemon";
917 } else {
918 facility = PCMK__VALUE_NONE;
919 }
920 pcmk__set_env_option(PCMK__ENV_LOGFACILITY, facility, true);
921 }
922
923 if (pcmk__str_eq(facility, PCMK__VALUE_NONE, pcmk__str_casei)) {
924 quiet = TRUE;
925
926
927 } else {
928 qb_log_ctl(QB_LOG_SYSLOG, QB_LOG_CONF_FACILITY, qb_log_facility2int(facility));
929 }
930
931 if (pcmk__env_option_enabled(crm_system_name, PCMK__ENV_DEBUG)) {
932
933 crm_log_level = LOG_DEBUG;
934 }
935
936
937 syslog_priority = pcmk__env_option(PCMK__ENV_LOGPRIORITY);
938 if (syslog_priority) {
939 crm_log_priority = crm_priority2int(syslog_priority);
940 }
941 qb_log_filter_ctl(QB_LOG_SYSLOG, QB_LOG_FILTER_ADD, QB_LOG_FILTER_FILE, "*",
942 crm_log_priority);
943
944
945 if (!quiet) {
946 qb_log_ctl(QB_LOG_SYSLOG, QB_LOG_CONF_ENABLED, QB_TRUE);
947 }
948
949
950 if (pcmk__env_option_enabled(crm_system_name, PCMK__ENV_STDERR)) {
951
952 to_stderr = TRUE;
953 }
954 crm_enable_stderr(to_stderr);
955
956
957 {
958 const char *logfile = pcmk__env_option(PCMK__ENV_LOGFILE);
959
960 if (!pcmk__str_eq(PCMK__VALUE_NONE, logfile, pcmk__str_casei)
961 && (pcmk__is_daemon || (logfile != NULL))) {
962
963 pcmk__add_logfile(logfile);
964 }
965 }
966
967 if (pcmk__is_daemon
968 && pcmk__env_option_enabled(crm_system_name, PCMK__ENV_BLACKBOX)) {
969 crm_enable_blackbox(0);
970 }
971
972
973 crm_trace("Quiet: %d, facility %s", quiet, f_copy);
974 pcmk__env_option(PCMK__ENV_LOGFILE);
975 pcmk__env_option(PCMK__ENV_LOGFACILITY);
976
977 crm_update_callsites();
978
979
980
981
982 if (pcmk__is_daemon) {
983 const char *user = getenv("USER");
984
985 if (user != NULL && !pcmk__strcase_any_of(user, "root", CRM_DAEMON_USER, NULL)) {
986 crm_trace("Not switching to corefile directory for %s", user);
987 pcmk__is_daemon = false;
988 }
989 }
990
991 if (pcmk__is_daemon) {
992 int user = getuid();
993 struct passwd *pwent = getpwuid(user);
994
995 if (pwent == NULL) {
996 crm_perror(LOG_ERR, "Cannot get name for uid: %d", user);
997
998 } else if (!pcmk__strcase_any_of(pwent->pw_name, "root", CRM_DAEMON_USER, NULL)) {
999 crm_trace("Don't change active directory for regular user: %s", pwent->pw_name);
1000
1001 } else if (chdir(CRM_CORE_DIR) < 0) {
1002 crm_perror(LOG_INFO, "Cannot change active directory to " CRM_CORE_DIR);
1003
1004 } else {
1005 crm_info("Changed active directory to " CRM_CORE_DIR);
1006 }
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017 mainloop_add_signal(SIGUSR1, crm_enable_blackbox);
1018 mainloop_add_signal(SIGUSR2, crm_disable_blackbox);
1019 mainloop_add_signal(SIGTRAP, crm_trigger_blackbox);
1020
1021 } else if (!quiet) {
1022 crm_log_args(argc, argv);
1023 }
1024
1025 return TRUE;
1026 }
1027
1028
1029 unsigned int
1030 set_crm_log_level(unsigned int level)
1031 {
1032 unsigned int old = crm_log_level;
1033
1034 if (level > LOG_TRACE) {
1035 level = LOG_TRACE;
1036 }
1037 crm_log_level = level;
1038 crm_update_callsites();
1039 crm_trace("New log level: %d", level);
1040 return old;
1041 }
1042
1043 void
1044 crm_enable_stderr(int enable)
1045 {
1046 if (enable && qb_log_ctl(QB_LOG_STDERR, QB_LOG_CONF_STATE_GET, 0) != QB_LOG_STATE_ENABLED) {
1047 qb_log_ctl(QB_LOG_STDERR, QB_LOG_CONF_ENABLED, QB_TRUE);
1048 crm_update_callsites();
1049
1050 } else if (enable == FALSE) {
1051 qb_log_ctl(QB_LOG_STDERR, QB_LOG_CONF_ENABLED, QB_FALSE);
1052 }
1053 }
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064 void
1065 crm_bump_log_level(int argc, char **argv)
1066 {
1067 if (qb_log_ctl(QB_LOG_STDERR, QB_LOG_CONF_STATE_GET, 0)
1068 != QB_LOG_STATE_ENABLED) {
1069 crm_enable_stderr(TRUE);
1070 } else {
1071 set_crm_log_level(crm_log_level + 1);
1072 }
1073 }
1074
1075 unsigned int
1076 get_crm_log_level(void)
1077 {
1078 return crm_log_level;
1079 }
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090 void
1091 crm_log_args(int argc, char **argv)
1092 {
1093 static bool logged = false;
1094 gchar *arg_string = NULL;
1095
1096 if ((argc == 0) || (argv == NULL) || logged) {
1097 return;
1098 }
1099 logged = true;
1100 arg_string = g_strjoinv(" ", argv);
1101 crm_notice("Invoked: %s", arg_string);
1102 g_free(arg_string);
1103 }
1104
1105 void
1106 crm_log_output_fn(const char *file, const char *function, int line, int level, const char *prefix,
1107 const char *output)
1108 {
1109 const char *next = NULL;
1110 const char *offset = NULL;
1111
1112 if (level == LOG_NEVER) {
1113 return;
1114 }
1115
1116 if (output == NULL) {
1117 if (level != LOG_STDOUT) {
1118 level = LOG_TRACE;
1119 }
1120 output = "-- empty --";
1121 }
1122
1123 next = output;
1124 do {
1125 offset = next;
1126 next = strchrnul(offset, '\n');
1127 do_crm_log_alias(level, file, function, line, "%s [ %.*s ]", prefix,
1128 (int)(next - offset), offset);
1129 if (next[0] != 0) {
1130 next++;
1131 }
1132
1133 } while (next != NULL && next[0] != 0);
1134 }
1135
1136 void
1137 pcmk__cli_init_logging(const char *name, unsigned int verbosity)
1138 {
1139 crm_log_init(name, LOG_ERR, FALSE, FALSE, 0, NULL, TRUE);
1140
1141 for (int i = 0; i < verbosity; i++) {
1142
1143 crm_bump_log_level(0, NULL);
1144 }
1145 }
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162 void
1163 pcmk_log_xml_as(const char *file, const char *function, uint32_t line,
1164 uint32_t tags, uint8_t level, const char *text, const xmlNode *xml)
1165 {
1166 if (xml == NULL) {
1167 do_crm_log(level, "%s%sNo data to dump as XML",
1168 pcmk__s(text, ""), pcmk__str_empty(text)? "" : " ");
1169
1170 } else {
1171 if (logger_out == NULL) {
1172 CRM_CHECK(pcmk__log_output_new(&logger_out) == pcmk_rc_ok, return);
1173 }
1174
1175 pcmk__output_set_log_level(logger_out, level);
1176 pcmk__output_set_log_filter(logger_out, file, function, line, tags);
1177 pcmk__xml_show(logger_out, text, xml, 1,
1178 pcmk__xml_fmt_pretty
1179 |pcmk__xml_fmt_open
1180 |pcmk__xml_fmt_children
1181 |pcmk__xml_fmt_close);
1182 pcmk__output_set_log_filter(logger_out, NULL, NULL, 0U, 0U);
1183 }
1184 }
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199 void
1200 pcmk__log_xml_changes_as(const char *file, const char *function, uint32_t line,
1201 uint32_t tags, uint8_t level, const xmlNode *xml)
1202 {
1203 if (xml == NULL) {
1204 do_crm_log(level, "No XML to dump");
1205 return;
1206 }
1207
1208 if (logger_out == NULL) {
1209 CRM_CHECK(pcmk__log_output_new(&logger_out) == pcmk_rc_ok, return);
1210 }
1211 pcmk__output_set_log_level(logger_out, level);
1212 pcmk__output_set_log_filter(logger_out, file, function, line, tags);
1213 pcmk__xml_show_changes(logger_out, xml);
1214 pcmk__output_set_log_filter(logger_out, NULL, NULL, 0U, 0U);
1215 }
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230 void
1231 pcmk__log_xml_patchset_as(const char *file, const char *function, uint32_t line,
1232 uint32_t tags, uint8_t level, const xmlNode *patchset)
1233 {
1234 if (patchset == NULL) {
1235 do_crm_log(level, "No patchset to dump");
1236 return;
1237 }
1238
1239 if (logger_out == NULL) {
1240 CRM_CHECK(pcmk__log_output_new(&logger_out) == pcmk_rc_ok, return);
1241 }
1242 pcmk__output_set_log_level(logger_out, level);
1243 pcmk__output_set_log_filter(logger_out, file, function, line, tags);
1244 logger_out->message(logger_out, "xml-patchset", patchset);
1245 pcmk__output_set_log_filter(logger_out, NULL, NULL, 0U, 0U);
1246 }
1247
1248
1249
1250
1251
1252 void
1253 pcmk__free_common_logger(void)
1254 {
1255 if (logger_out != NULL) {
1256 logger_out->finish(logger_out, CRM_EX_OK, true, NULL);
1257 pcmk__output_free(logger_out);
1258 logger_out = NULL;
1259 }
1260 }
1261
1262
1263
1264
1265 #include <crm/common/logging_compat.h>
1266
1267 gboolean
1268 crm_log_cli_init(const char *entity)
1269 {
1270 pcmk__cli_init_logging(entity, 0);
1271 return TRUE;
1272 }
1273
1274 gboolean
1275 crm_add_logfile(const char *filename)
1276 {
1277 return pcmk__add_logfile(filename) == pcmk_rc_ok;
1278 }
1279
1280 void
1281 pcmk_log_xml_impl(uint8_t level, const char *text, const xmlNode *xml)
1282 {
1283 pcmk_log_xml_as(__FILE__, __func__, __LINE__, 0, level, text, xml);
1284 }
1285
1286
1287
1288
1289 void pcmk__set_config_error_handler(pcmk__config_error_func error_handler, void *error_context)
1290 {
1291 pcmk__config_error_handler = error_handler;
1292 pcmk__config_error_context = error_context;
1293 }
1294
1295 void pcmk__set_config_warning_handler(pcmk__config_warning_func warning_handler, void *warning_context)
1296 {
1297 pcmk__config_warning_handler = warning_handler;
1298 pcmk__config_warning_context = warning_context;