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
- blackbox_logger
- crm_control_blackbox
- crm_enable_blackbox
- crm_disable_blackbox
- crm_write_blackbox
- crm_quark_to_string
- crm_log_filter_source
- 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
- crm_log_cli_init
- crm_add_logfile
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
49 static unsigned int crm_log_priority = LOG_NOTICE;
50 static GLogFunc glib_log_default = NULL;
51
52 static gboolean crm_tracing_enabled(void);
53
54 static void
55 crm_glib_handler(const gchar * log_domain, GLogLevelFlags flags, const gchar * message,
56 gpointer user_data)
57 {
58 int log_level = LOG_WARNING;
59 GLogLevelFlags msg_level = (flags & G_LOG_LEVEL_MASK);
60 static struct qb_log_callsite *glib_cs = NULL;
61
62 if (glib_cs == NULL) {
63 glib_cs = qb_log_callsite_get(__func__, __FILE__, "glib-handler",
64 LOG_DEBUG, __LINE__, crm_trace_nonlog);
65 }
66
67
68 switch (msg_level) {
69 case G_LOG_LEVEL_CRITICAL:
70 log_level = LOG_CRIT;
71
72 if (crm_is_callsite_active(glib_cs, LOG_DEBUG, 0) == FALSE) {
73
74 crm_abort(__FILE__, __func__, __LINE__, message, TRUE, TRUE);
75 }
76 break;
77
78 case G_LOG_LEVEL_ERROR:
79 log_level = LOG_ERR;
80 break;
81 case G_LOG_LEVEL_MESSAGE:
82 log_level = LOG_NOTICE;
83 break;
84 case G_LOG_LEVEL_INFO:
85 log_level = LOG_INFO;
86 break;
87 case G_LOG_LEVEL_DEBUG:
88 log_level = LOG_DEBUG;
89 break;
90
91 case G_LOG_LEVEL_WARNING:
92 case G_LOG_FLAG_RECURSION:
93 case G_LOG_FLAG_FATAL:
94 case G_LOG_LEVEL_MASK:
95 log_level = LOG_WARNING;
96 break;
97 }
98
99 do_crm_log(log_level, "%s: %s", log_domain, message);
100 }
101
102 #ifndef NAME_MAX
103 # define NAME_MAX 256
104 #endif
105
106
107
108
109
110
111
112
113
114 static void
115 crm_trigger_blackbox(int nsig)
116 {
117 if(nsig == SIGTRAP) {
118
119 crm_enable_blackbox(nsig);
120 }
121 crm_write_blackbox(nsig, NULL);
122 }
123
124 void
125 crm_log_deinit(void)
126 {
127 if (glib_log_default != NULL) {
128 g_log_set_default_handler(glib_log_default, NULL);
129 }
130 }
131
132 #define FMT_MAX 256
133
134 static void
135 set_format_string(int method, const char *daemon)
136 {
137 if (method == QB_LOG_SYSLOG) {
138
139 crm_extended_logging(method, QB_FALSE);
140 qb_log_format_set(method, "%g %p: %b");
141
142 } else {
143
144
145 int offset = 0;
146 char fmt[FMT_MAX];
147
148 if (method > QB_LOG_STDERR) {
149 struct utsname res;
150 const char *nodename = "localhost";
151
152 if (uname(&res) == 0) {
153 nodename = res.nodename;
154 }
155
156
157 offset += snprintf(fmt + offset, FMT_MAX - offset,
158 TIMESTAMP_FORMAT_SPEC " %s %-20s[%lu] ",
159 nodename, daemon, (unsigned long) getpid());
160 }
161
162
163 offset += snprintf(fmt + offset, FMT_MAX - offset, "(%%n");
164 if (crm_tracing_enabled()) {
165
166 offset += snprintf(fmt + offset, FMT_MAX - offset, "@%%f:%%l");
167 }
168 offset += snprintf(fmt + offset, FMT_MAX - offset, ")");
169
170
171 offset += snprintf(fmt + offset, FMT_MAX - offset, " %%g\t%%p: %%b");
172
173 CRM_LOG_ASSERT(offset > 0);
174 qb_log_format_set(method, fmt);
175 }
176 }
177
178 #define DEFAULT_LOG_FILE CRM_LOG_DIR "/pacemaker.log"
179
180 static bool
181 logfile_disabled(const char *filename)
182 {
183 return pcmk__str_eq(filename, "none", pcmk__str_casei)
184 || pcmk__str_eq(filename, "/dev/null", pcmk__str_none);
185 }
186
187
188
189
190
191
192
193
194
195
196 static int
197 chown_logfile(const char *filename, int logfd)
198 {
199 uid_t pcmk_uid = 0;
200 gid_t pcmk_gid = 0;
201 struct stat st;
202 int rc;
203
204
205 if (fstat(logfd, &st) < 0) {
206 return errno;
207 }
208
209
210
211 rc = pcmk_daemon_user(&pcmk_uid, &pcmk_gid);
212 if (rc != pcmk_ok) {
213 rc = pcmk_legacy2rc(rc);
214 crm_warn("Not changing '%s' ownership because user information "
215 "unavailable: %s", filename, pcmk_rc_str(rc));
216 return pcmk_rc_ok;
217 }
218 if ((st.st_gid == pcmk_gid)
219 && ((st.st_mode & S_IRWXG) == (S_IRGRP|S_IWGRP))) {
220 return pcmk_rc_ok;
221 }
222 if (fchown(logfd, pcmk_uid, pcmk_gid) < 0) {
223 crm_warn("Couldn't change '%s' ownership to user %s gid %d: %s",
224 filename, CRM_DAEMON_USER, pcmk_gid, strerror(errno));
225 }
226 return pcmk_rc_ok;
227 }
228
229
230 static void
231 chmod_logfile(const char *filename, int logfd)
232 {
233 const char *modestr = getenv("PCMK_logfile_mode");
234 mode_t filemode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP;
235
236 if (modestr != NULL) {
237 long filemode_l = strtol(modestr, NULL, 8);
238
239 if ((filemode_l != LONG_MIN) && (filemode_l != LONG_MAX)) {
240 filemode = (mode_t) filemode_l;
241 }
242 }
243 if ((filemode != 0) && (fchmod(logfd, filemode) < 0)) {
244 crm_warn("Couldn't change '%s' mode to %04o: %s",
245 filename, filemode, strerror(errno));
246 }
247 }
248
249
250 static int
251 set_logfile_permissions(const char *filename, FILE *logfile)
252 {
253 if (geteuid() == 0) {
254 int logfd = fileno(logfile);
255 int rc = chown_logfile(filename, logfd);
256
257 if (rc != pcmk_rc_ok) {
258 return rc;
259 }
260 chmod_logfile(filename, logfd);
261 }
262 return pcmk_rc_ok;
263 }
264
265
266 static void
267 enable_logfile(int fd)
268 {
269 qb_log_ctl(fd, QB_LOG_CONF_ENABLED, QB_TRUE);
270 #if 0
271 qb_log_ctl(fd, QB_LOG_CONF_FILE_SYNC, 1);
272 #endif
273
274 #ifdef HAVE_qb_log_conf_QB_LOG_CONF_MAX_LINE_LEN
275
276 qb_log_ctl(fd, QB_LOG_CONF_MAX_LINE_LEN, 800);
277 #endif
278
279 crm_update_callsites();
280 }
281
282 static inline void
283 disable_logfile(int fd)
284 {
285 qb_log_ctl(fd, QB_LOG_CONF_ENABLED, QB_FALSE);
286 }
287
288 static void
289 setenv_logfile(const char *filename)
290 {
291
292 if (pcmk__env_option("logfile") == NULL) {
293 pcmk__set_env_option("logfile", filename);
294 }
295 }
296
297
298
299
300
301
302
303
304 int
305 pcmk__add_logfile(const char *filename)
306 {
307
308
309
310
311
312 int fd = 0;
313 int rc = pcmk_rc_ok;
314 FILE *logfile = NULL;
315 bool is_default = false;
316
317 static int default_fd = -1;
318 static bool have_logfile = false;
319
320
321 if (filename == NULL) {
322 if (have_logfile) {
323 return pcmk_rc_ok;
324 }
325 filename = DEFAULT_LOG_FILE;
326 }
327
328
329 if (logfile_disabled(filename)) {
330 return pcmk_rc_ok;
331 }
332
333
334 is_default = pcmk__str_eq(filename, DEFAULT_LOG_FILE, pcmk__str_none);
335 if (is_default && (default_fd >= 0)) {
336 return pcmk_rc_ok;
337 }
338
339
340 logfile = fopen(filename, "a");
341 if (logfile == NULL) {
342 rc = errno;
343 crm_warn("Logging to '%s' is disabled: %s " CRM_XS " uid=%u gid=%u",
344 filename, strerror(rc), geteuid(), getegid());
345 return rc;
346 }
347
348 rc = set_logfile_permissions(filename, logfile);
349 if (rc != pcmk_rc_ok) {
350 crm_warn("Logging to '%s' is disabled: %s " CRM_XS " permissions",
351 filename, strerror(rc));
352 fclose(logfile);
353 return rc;
354 }
355
356
357 fclose(logfile);
358 fd = qb_log_file_open(filename);
359 if (fd < 0) {
360 crm_warn("Logging to '%s' is disabled: %s " CRM_XS " qb_log_file_open",
361 filename, strerror(-fd));
362 return -fd;
363 }
364
365 if (is_default) {
366 default_fd = fd;
367 setenv_logfile(filename);
368
369 } else if (default_fd >= 0) {
370 crm_notice("Switching logging to %s", filename);
371 disable_logfile(default_fd);
372 }
373
374 crm_notice("Additional logging available in %s", filename);
375 enable_logfile(fd);
376 have_logfile = true;
377 return pcmk_rc_ok;
378 }
379
380 static int blackbox_trigger = 0;
381 static volatile char *blackbox_file_prefix = NULL;
382
383 static void
384 blackbox_logger(int32_t t, struct qb_log_callsite *cs, log_time_t timestamp,
385 const char *msg)
386 {
387 if(cs && cs->priority < LOG_ERR) {
388 crm_write_blackbox(SIGTRAP, cs);
389 } else {
390 crm_write_blackbox(0, cs);
391 }
392 }
393
394 static void
395 crm_control_blackbox(int nsig, bool enable)
396 {
397 int lpc = 0;
398
399 if (blackbox_file_prefix == NULL) {
400 pid_t pid = getpid();
401
402 blackbox_file_prefix = crm_strdup_printf("%s/%s-%lu",
403 CRM_BLACKBOX_DIR,
404 crm_system_name,
405 (unsigned long) pid);
406 }
407
408 if (enable && qb_log_ctl(QB_LOG_BLACKBOX, QB_LOG_CONF_STATE_GET, 0) != QB_LOG_STATE_ENABLED) {
409 qb_log_ctl(QB_LOG_BLACKBOX, QB_LOG_CONF_SIZE, 5 * 1024 * 1024);
410 qb_log_ctl(QB_LOG_BLACKBOX, QB_LOG_CONF_ENABLED, QB_TRUE);
411
412
413 for (lpc = QB_LOG_BLACKBOX; lpc < QB_LOG_TARGET_MAX; lpc++) {
414 qb_log_ctl(lpc, QB_LOG_CONF_FILE_SYNC, QB_TRUE);
415 }
416
417 crm_notice("Initiated blackbox recorder: %s", blackbox_file_prefix);
418
419
420 crm_signal_handler(SIGSEGV, crm_trigger_blackbox);
421 crm_signal_handler(SIGABRT, crm_trigger_blackbox);
422 crm_signal_handler(SIGILL, crm_trigger_blackbox);
423 crm_signal_handler(SIGBUS, crm_trigger_blackbox);
424 crm_signal_handler(SIGFPE, crm_trigger_blackbox);
425
426 crm_update_callsites();
427
428 blackbox_trigger = qb_log_custom_open(blackbox_logger, NULL, NULL, NULL);
429 qb_log_ctl(blackbox_trigger, QB_LOG_CONF_ENABLED, QB_TRUE);
430 crm_trace("Trigger: %d is %d %d", blackbox_trigger,
431 qb_log_ctl(blackbox_trigger, QB_LOG_CONF_STATE_GET, 0), QB_LOG_STATE_ENABLED);
432
433 crm_update_callsites();
434
435 } else if (!enable && qb_log_ctl(QB_LOG_BLACKBOX, QB_LOG_CONF_STATE_GET, 0) == QB_LOG_STATE_ENABLED) {
436 qb_log_ctl(QB_LOG_BLACKBOX, QB_LOG_CONF_ENABLED, QB_FALSE);
437
438
439 for (lpc = QB_LOG_BLACKBOX; lpc < QB_LOG_TARGET_MAX; lpc++) {
440 qb_log_ctl(lpc, QB_LOG_CONF_FILE_SYNC, QB_FALSE);
441 }
442 }
443 }
444
445 void
446 crm_enable_blackbox(int nsig)
447 {
448 crm_control_blackbox(nsig, TRUE);
449 }
450
451 void
452 crm_disable_blackbox(int nsig)
453 {
454 crm_control_blackbox(nsig, FALSE);
455 }
456
457
458
459
460
461
462
463
464
465
466
467 void
468 crm_write_blackbox(int nsig, struct qb_log_callsite *cs)
469 {
470 static volatile int counter = 1;
471 static volatile time_t last = 0;
472
473 char buffer[NAME_MAX];
474 time_t now = time(NULL);
475
476 if (blackbox_file_prefix == NULL) {
477 return;
478 }
479
480 switch (nsig) {
481 case 0:
482 case SIGTRAP:
483
484
485 if (nsig == 0 && now == last) {
486
487 return;
488 }
489
490 snprintf(buffer, NAME_MAX, "%s.%d", blackbox_file_prefix, counter++);
491 if (nsig == SIGTRAP) {
492 crm_notice("Blackbox dump requested, please see %s for contents", buffer);
493
494 } else if (cs) {
495 syslog(LOG_NOTICE,
496 "Problem detected at %s:%d (%s), please see %s for additional details",
497 cs->function, cs->lineno, cs->filename, buffer);
498 } else {
499 crm_notice("Problem detected, please see %s for additional details", buffer);
500 }
501
502 last = now;
503 qb_log_blackbox_write_to_file(buffer);
504
505
506
507
508 qb_log_ctl(QB_LOG_BLACKBOX, QB_LOG_CONF_ENABLED, QB_FALSE);
509 qb_log_ctl(QB_LOG_BLACKBOX, QB_LOG_CONF_ENABLED, QB_TRUE);
510 break;
511
512 default:
513
514
515
516 crm_signal_handler(nsig, SIG_DFL);
517 qb_log_blackbox_write_to_file((const char *)blackbox_file_prefix);
518 qb_log_ctl(QB_LOG_BLACKBOX, QB_LOG_CONF_ENABLED, QB_FALSE);
519 raise(nsig);
520 break;
521 }
522 }
523
524 static const char *
525 crm_quark_to_string(uint32_t tag)
526 {
527 const char *text = g_quark_to_string(tag);
528
529 if (text) {
530 return text;
531 }
532 return "";
533 }
534
535 static void
536 crm_log_filter_source(int source, const char *trace_files, const char *trace_fns,
537 const char *trace_fmts, const char *trace_tags, const char *trace_blackbox,
538 struct qb_log_callsite *cs)
539 {
540 if (qb_log_ctl(source, QB_LOG_CONF_STATE_GET, 0) != QB_LOG_STATE_ENABLED) {
541 return;
542 } else if (cs->tags != crm_trace_nonlog && source == QB_LOG_BLACKBOX) {
543
544 qb_bit_set(cs->targets, source);
545
546 } else if (source == blackbox_trigger && blackbox_trigger > 0) {
547
548 if (cs->priority <= LOG_ERR) {
549 qb_bit_set(cs->targets, source);
550
551 } else if (trace_blackbox) {
552 char *key = crm_strdup_printf("%s:%d", cs->function, cs->lineno);
553
554 if (strstr(trace_blackbox, key) != NULL) {
555 qb_bit_set(cs->targets, source);
556 }
557 free(key);
558 }
559
560 } else if (source == QB_LOG_SYSLOG) {
561 if (cs->priority <= crm_log_priority && cs->priority <= crm_log_level) {
562 qb_bit_set(cs->targets, source);
563 }
564
565 } else if (cs->priority <= crm_log_level) {
566 qb_bit_set(cs->targets, source);
567 } else if (trace_files && strstr(trace_files, cs->filename) != NULL) {
568 qb_bit_set(cs->targets, source);
569 } else if (trace_fns && strstr(trace_fns, cs->function) != NULL) {
570 qb_bit_set(cs->targets, source);
571 } else if (trace_fmts && strstr(trace_fmts, cs->format) != NULL) {
572 qb_bit_set(cs->targets, source);
573 } else if (trace_tags
574 && cs->tags != 0
575 && cs->tags != crm_trace_nonlog && g_quark_to_string(cs->tags) != NULL) {
576 qb_bit_set(cs->targets, source);
577 }
578 }
579
580 static void
581 crm_log_filter(struct qb_log_callsite *cs)
582 {
583 int lpc = 0;
584 static int need_init = 1;
585 static const char *trace_fns = NULL;
586 static const char *trace_tags = NULL;
587 static const char *trace_fmts = NULL;
588 static const char *trace_files = NULL;
589 static const char *trace_blackbox = NULL;
590
591 if (need_init) {
592 need_init = 0;
593 trace_fns = getenv("PCMK_trace_functions");
594 trace_fmts = getenv("PCMK_trace_formats");
595 trace_tags = getenv("PCMK_trace_tags");
596 trace_files = getenv("PCMK_trace_files");
597 trace_blackbox = getenv("PCMK_trace_blackbox");
598
599 if (trace_tags != NULL) {
600 uint32_t tag;
601 char token[500];
602 const char *offset = NULL;
603 const char *next = trace_tags;
604
605 do {
606 offset = next;
607 next = strchrnul(offset, ',');
608 snprintf(token, sizeof(token), "%.*s", (int)(next - offset), offset);
609
610 tag = g_quark_from_string(token);
611 crm_info("Created GQuark %u from token '%s' in '%s'", tag, token, trace_tags);
612
613 if (next[0] != 0) {
614 next++;
615 }
616
617 } while (next != NULL && next[0] != 0);
618 }
619 }
620
621 cs->targets = 0;
622 for (lpc = QB_LOG_SYSLOG; lpc < QB_LOG_TARGET_MAX; lpc++) {
623 crm_log_filter_source(lpc, trace_files, trace_fns, trace_fmts, trace_tags, trace_blackbox,
624 cs);
625 }
626 }
627
628 gboolean
629 crm_is_callsite_active(struct qb_log_callsite *cs, uint8_t level, uint32_t tags)
630 {
631 gboolean refilter = FALSE;
632
633 if (cs == NULL) {
634 return FALSE;
635 }
636
637 if (cs->priority != level) {
638 cs->priority = level;
639 refilter = TRUE;
640 }
641
642 if (cs->tags != tags) {
643 cs->tags = tags;
644 refilter = TRUE;
645 }
646
647 if (refilter) {
648 crm_log_filter(cs);
649 }
650
651 if (cs->targets == 0) {
652 return FALSE;
653 }
654 return TRUE;
655 }
656
657 void
658 crm_update_callsites(void)
659 {
660 static gboolean log = TRUE;
661
662 if (log) {
663 log = FALSE;
664 crm_debug
665 ("Enabling callsites based on priority=%d, files=%s, functions=%s, formats=%s, tags=%s",
666 crm_log_level, getenv("PCMK_trace_files"), getenv("PCMK_trace_functions"),
667 getenv("PCMK_trace_formats"), getenv("PCMK_trace_tags"));
668 }
669 qb_log_filter_fn_set(crm_log_filter);
670 }
671
672 static gboolean
673 crm_tracing_enabled(void)
674 {
675 if (crm_log_level == LOG_TRACE) {
676 return TRUE;
677 } else if (getenv("PCMK_trace_files") || getenv("PCMK_trace_functions")
678 || getenv("PCMK_trace_formats") || getenv("PCMK_trace_tags")) {
679 return TRUE;
680 }
681 return FALSE;
682 }
683
684 static int
685 crm_priority2int(const char *name)
686 {
687 struct syslog_names {
688 const char *name;
689 int priority;
690 };
691 static struct syslog_names p_names[] = {
692 {"emerg", LOG_EMERG},
693 {"alert", LOG_ALERT},
694 {"crit", LOG_CRIT},
695 {"error", LOG_ERR},
696 {"warning", LOG_WARNING},
697 {"notice", LOG_NOTICE},
698 {"info", LOG_INFO},
699 {"debug", LOG_DEBUG},
700 {NULL, -1}
701 };
702 int lpc;
703
704 for (lpc = 0; name != NULL && p_names[lpc].name != NULL; lpc++) {
705 if (pcmk__str_eq(p_names[lpc].name, name, pcmk__str_none)) {
706 return p_names[lpc].priority;
707 }
708 }
709 return crm_log_priority;
710 }
711
712
713 static void
714 set_identity(const char *entity, int argc, char **argv)
715 {
716 if (crm_system_name != NULL) {
717 return;
718 }
719
720 if (entity != NULL) {
721 crm_system_name = strdup(entity);
722
723 } else if ((argc > 0) && (argv != NULL)) {
724 char *mutable = strdup(argv[0]);
725 char *modified = basename(mutable);
726
727 if (strstr(modified, "lt-") == modified) {
728 modified += 3;
729 }
730 crm_system_name = strdup(modified);
731 free(mutable);
732
733 } else {
734 crm_system_name = strdup("Unknown");
735 }
736
737 CRM_ASSERT(crm_system_name != NULL);
738
739 setenv("PCMK_service", crm_system_name, 1);
740 }
741
742 void
743 crm_log_preinit(const char *entity, int argc, char **argv)
744 {
745
746
747 int lpc = 0;
748 int32_t qb_facility = 0;
749
750 static bool have_logging = FALSE;
751
752 if(have_logging == FALSE) {
753 have_logging = TRUE;
754
755 crm_xml_init();
756
757 if (crm_trace_nonlog == 0) {
758 crm_trace_nonlog = g_quark_from_static_string("Pacemaker non-logging tracepoint");
759 }
760
761 umask(S_IWGRP | S_IWOTH | S_IROTH);
762
763
764 glib_log_default = g_log_set_default_handler(crm_glib_handler, NULL);
765
766
767 g_log_set_always_fatal((GLogLevelFlags) 0);
768
769
770
771
772 set_identity(entity, argc, argv);
773
774 qb_facility = qb_log_facility2int("local0");
775 qb_log_init(crm_system_name, qb_facility, LOG_ERR);
776 crm_log_level = LOG_CRIT;
777
778
779 qb_log_ctl(QB_LOG_SYSLOG, QB_LOG_CONF_ENABLED, QB_FALSE);
780 #ifdef HAVE_qb_log_conf_QB_LOG_CONF_MAX_LINE_LEN
781
782 qb_log_ctl(QB_LOG_SYSLOG, QB_LOG_CONF_MAX_LINE_LEN, 256);
783 #endif
784
785
786
787
788 qb_log_tags_stringify_fn_set(crm_quark_to_string);
789 for (lpc = QB_LOG_SYSLOG; lpc < QB_LOG_TARGET_MAX; lpc++) {
790 qb_log_ctl(lpc, QB_LOG_CONF_THREADED, QB_FALSE);
791 #ifdef HAVE_qb_log_conf_QB_LOG_CONF_ELLIPSIS
792
793 qb_log_ctl(lpc, QB_LOG_CONF_ELLIPSIS, QB_TRUE);
794 #endif
795 set_format_string(lpc, crm_system_name);
796 }
797 }
798 }
799
800 gboolean
801 crm_log_init(const char *entity, uint8_t level, gboolean daemon, gboolean to_stderr,
802 int argc, char **argv, gboolean quiet)
803 {
804 const char *syslog_priority = NULL;
805 const char *facility = pcmk__env_option("logfacility");
806 const char *f_copy = facility;
807
808 pcmk__is_daemon = daemon;
809 crm_log_preinit(entity, argc, argv);
810
811 if (level > LOG_TRACE) {
812 level = LOG_TRACE;
813 }
814 if(level > crm_log_level) {
815 crm_log_level = level;
816 }
817
818
819 if (facility == NULL) {
820 if (pcmk__is_daemon) {
821 facility = "daemon";
822 } else {
823 facility = "none";
824 }
825 pcmk__set_env_option("logfacility", facility);
826 }
827
828 if (pcmk__str_eq(facility, "none", pcmk__str_casei)) {
829 quiet = TRUE;
830
831
832 } else {
833 qb_log_ctl(QB_LOG_SYSLOG, QB_LOG_CONF_FACILITY, qb_log_facility2int(facility));
834 }
835
836 if (pcmk__env_option_enabled(crm_system_name, "debug")) {
837
838 crm_log_level = LOG_DEBUG;
839 }
840
841
842 syslog_priority = pcmk__env_option("logpriority");
843 if (syslog_priority) {
844 crm_log_priority = crm_priority2int(syslog_priority);
845 }
846 qb_log_filter_ctl(QB_LOG_SYSLOG, QB_LOG_FILTER_ADD, QB_LOG_FILTER_FILE, "*",
847 crm_log_priority);
848
849
850 if (!quiet) {
851 qb_log_ctl(QB_LOG_SYSLOG, QB_LOG_CONF_ENABLED, QB_TRUE);
852 }
853
854
855 if (pcmk__env_option_enabled(crm_system_name, "stderr")) {
856
857 to_stderr = TRUE;
858 }
859 crm_enable_stderr(to_stderr);
860
861
862 {
863 const char *logfile = pcmk__env_option("logfile");
864
865 if (!pcmk__str_eq("none", logfile, pcmk__str_casei)
866 && (pcmk__is_daemon || (logfile != NULL))) {
867
868 pcmk__add_logfile(logfile);
869 }
870 }
871
872 if (pcmk__is_daemon
873 && pcmk__env_option_enabled(crm_system_name, "blackbox")) {
874 crm_enable_blackbox(0);
875 }
876
877
878 crm_trace("Quiet: %d, facility %s", quiet, f_copy);
879 pcmk__env_option("logfile");
880 pcmk__env_option("logfacility");
881
882 crm_update_callsites();
883
884
885
886
887 if (pcmk__is_daemon) {
888 const char *user = getenv("USER");
889
890 if (user != NULL && !pcmk__strcase_any_of(user, "root", CRM_DAEMON_USER, NULL)) {
891 crm_trace("Not switching to corefile directory for %s", user);
892 pcmk__is_daemon = false;
893 }
894 }
895
896 if (pcmk__is_daemon) {
897 int user = getuid();
898 const char *base = CRM_CORE_DIR;
899 struct passwd *pwent = getpwuid(user);
900
901 if (pwent == NULL) {
902 crm_perror(LOG_ERR, "Cannot get name for uid: %d", user);
903
904 } else if (!pcmk__strcase_any_of(pwent->pw_name, "root", CRM_DAEMON_USER, NULL)) {
905 crm_trace("Don't change active directory for regular user: %s", pwent->pw_name);
906
907 } else if (chdir(base) < 0) {
908 crm_perror(LOG_INFO, "Cannot change active directory to %s", base);
909
910 } else {
911 crm_info("Changed active directory to %s", base);
912 #if 0
913 {
914 char path[512];
915
916 snprintf(path, 512, "%s-%lu", crm_system_name, (unsigned long) getpid());
917 mkdir(path, 0750);
918 chdir(path);
919 crm_info("Changed active directory to %s/%s/%s", base, pwent->pw_name, path);
920 }
921 #endif
922 }
923
924
925
926
927
928
929
930
931
932
933 mainloop_add_signal(SIGUSR1, crm_enable_blackbox);
934 mainloop_add_signal(SIGUSR2, crm_disable_blackbox);
935 mainloop_add_signal(SIGTRAP, crm_trigger_blackbox);
936
937 } else if (!quiet) {
938 crm_log_args(argc, argv);
939 }
940
941 return TRUE;
942 }
943
944
945 unsigned int
946 set_crm_log_level(unsigned int level)
947 {
948 unsigned int old = crm_log_level;
949
950 if (level > LOG_TRACE) {
951 level = LOG_TRACE;
952 }
953 crm_log_level = level;
954 crm_update_callsites();
955 crm_trace("New log level: %d", level);
956 return old;
957 }
958
959 void
960 crm_enable_stderr(int enable)
961 {
962 if (enable && qb_log_ctl(QB_LOG_STDERR, QB_LOG_CONF_STATE_GET, 0) != QB_LOG_STATE_ENABLED) {
963 qb_log_ctl(QB_LOG_STDERR, QB_LOG_CONF_ENABLED, QB_TRUE);
964 crm_update_callsites();
965
966 } else if (enable == FALSE) {
967 qb_log_ctl(QB_LOG_STDERR, QB_LOG_CONF_ENABLED, QB_FALSE);
968 }
969 }
970
971
972
973
974
975
976
977
978
979
980 void
981 crm_bump_log_level(int argc, char **argv)
982 {
983 if (qb_log_ctl(QB_LOG_STDERR, QB_LOG_CONF_STATE_GET, 0)
984 != QB_LOG_STATE_ENABLED) {
985 crm_enable_stderr(TRUE);
986 } else {
987 set_crm_log_level(crm_log_level + 1);
988 }
989 }
990
991 unsigned int
992 get_crm_log_level(void)
993 {
994 return crm_log_level;
995 }
996
997
998
999
1000
1001
1002
1003
1004
1005
1006 void
1007 crm_log_args(int argc, char **argv)
1008 {
1009 static bool logged = false;
1010 gchar *arg_string = NULL;
1011
1012 if ((argc == 0) || (argv == NULL) || logged) {
1013 return;
1014 }
1015 logged = true;
1016 arg_string = g_strjoinv(" ", argv);
1017 crm_notice("Invoked: %s", arg_string);
1018 g_free(arg_string);
1019 }
1020
1021 void
1022 crm_log_output_fn(const char *file, const char *function, int line, int level, const char *prefix,
1023 const char *output)
1024 {
1025 const char *next = NULL;
1026 const char *offset = NULL;
1027
1028 if (level == LOG_NEVER) {
1029 return;
1030 }
1031
1032 if (output == NULL) {
1033 if (level != LOG_STDOUT) {
1034 level = LOG_TRACE;
1035 }
1036 output = "-- empty --";
1037 }
1038
1039 next = output;
1040 do {
1041 offset = next;
1042 next = strchrnul(offset, '\n');
1043 do_crm_log_alias(level, file, function, line, "%s [ %.*s ]", prefix,
1044 (int)(next - offset), offset);
1045 if (next[0] != 0) {
1046 next++;
1047 }
1048
1049 } while (next != NULL && next[0] != 0);
1050 }
1051
1052 void
1053 pcmk__cli_init_logging(const char *name, unsigned int verbosity)
1054 {
1055 crm_log_init(name, LOG_ERR, FALSE, FALSE, 0, NULL, TRUE);
1056
1057 for (int i = 0; i < verbosity; i++) {
1058
1059 crm_bump_log_level(0, NULL);
1060 }
1061 }
1062
1063
1064
1065 #include <crm/common/logging_compat.h>
1066
1067 gboolean
1068 crm_log_cli_init(const char *entity)
1069 {
1070 pcmk__cli_init_logging(entity, 0);
1071 return TRUE;
1072 }
1073
1074 gboolean
1075 crm_add_logfile(const char *filename)
1076 {
1077 return pcmk__add_logfile(filename) == pcmk_rc_ok;
1078 }
1079
1080