// SPDX-License-Identifier: GPL-2.0-or-later /* * * BlueZ - Bluetooth protocol stack for Linux * * Copyright (C) 2014 Intel Corporation. All rights reserved. * * */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include #include #include #include #include #include #include #include #include #include "src/log.h" #define LOG_TAG "bluetoothd" #define LOG_DEBUG 3 #define LOG_INFO 4 #define LOG_WARN 5 #define LOG_ERR 6 #define LOG_ID_SYSTEM 3 struct logd_header { uint8_t id; uint16_t pid; /* Android logd expects only 2 bytes for PID */ uint32_t sec; uint32_t nsec; } __attribute__ ((packed)); static int log_fd = -1; static bool legacy_log = false; static void android_log(unsigned char level, const char *fmt, va_list ap) { struct logd_header header; struct iovec vec[4]; int cnt = 0; char *msg; static pid_t pid = 0; if (log_fd < 0) return; /* no need to call getpid all the time since we don't fork */ if (!pid) pid = getpid(); if (vasprintf(&msg, fmt, ap) < 0) return; if (!legacy_log) { struct timespec ts; clock_gettime(CLOCK_REALTIME, &ts); header.id = LOG_ID_SYSTEM; header.pid = pid; header.sec = ts.tv_sec; header.nsec = ts.tv_nsec; vec[0].iov_base = &header; vec[0].iov_len = sizeof(header); cnt += 1; } vec[cnt + 0].iov_base = &level; vec[cnt + 0].iov_len = sizeof(level); vec[cnt + 1].iov_base = LOG_TAG; vec[cnt + 1].iov_len = sizeof(LOG_TAG); vec[cnt + 2].iov_base = msg; vec[cnt + 2].iov_len = strlen(msg) + 1; cnt += 3; writev(log_fd, vec, cnt); free(msg); } void info(const char *format, ...) { va_list ap; va_start(ap, format); android_log(LOG_INFO, format, ap); va_end(ap); } void warn(const char *format, ...) { va_list ap; va_start(ap, format); android_log(LOG_WARN, format, ap); va_end(ap); } void error(const char *format, ...) { va_list ap; va_start(ap, format); android_log(LOG_ERR, format, ap); va_end(ap); } void btd_debug(uint16_t index, const char *format, ...) { va_list ap; va_start(ap, format); android_log(LOG_DEBUG, format, ap); va_end(ap); } static bool init_legacy_log(void) { log_fd = open("/dev/log/system", O_WRONLY); if (log_fd < 0) return false; legacy_log = true; return true; } static bool init_logd(void) { struct sockaddr_un addr; log_fd = socket(PF_UNIX, SOCK_DGRAM | SOCK_CLOEXEC, 0); if (log_fd < 0) return false; if (fcntl(log_fd, F_SETFL, O_NONBLOCK) < 0) goto failed; memset(&addr, 0, sizeof(addr)); addr.sun_family = AF_UNIX; strcpy(addr.sun_path, "/dev/socket/logdw"); if (connect(log_fd, (struct sockaddr *)&addr, sizeof(addr)) < 0) goto failed; return true; failed: close(log_fd); log_fd = -1; return false; } extern struct btd_debug_desc __start___debug[]; extern struct btd_debug_desc __stop___debug[]; void __btd_log_init(const char *debug, int detach) { if (!init_logd() && !init_legacy_log()) return; if (debug) { struct btd_debug_desc *desc; for (desc = __start___debug; desc < __stop___debug; desc++) desc->flags |= BTD_DEBUG_FLAG_PRINT; } info("Bluetooth daemon %s", VERSION); } void __btd_log_cleanup(void) { if (log_fd < 0) return; close(log_fd); log_fd = -1; }