blob: 35917c6018f32409c1e2aa3c8f670b577f50ffd8 [file] [log] [blame]
/*
*
* BlueZ - Bluetooth protocol stack for Linux
*
* Copyright (C) 2014 Intel Corporation. All rights reserved.
*
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <fcntl.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdbool.h>
#include <time.h>
#include <sys/uio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
#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;
}