blob: 73140822bcad11efdbec580d37ba3784ae56dd68 [file] [log] [blame]
/*
* logging.c -- Logging functions
*
* (c) Copyright IBM Corporation 2014.
*
* Author: Stefan Berger <stefanb@us.ibm.com>
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* Neither the names of the IBM Corporation nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "config.h"
#include "sys_dependencies.h"
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <unistd.h>
#include <stdbool.h>
#include "logging.h"
#include "utils.h"
#include <libtpms/tpm_library.h>
#define CONSOLE_LOGGING 2 /* stderr */
#define SUPPRESS_LOGGING -1
static int logfd = CONSOLE_LOGGING;
static unsigned int log_level = 1;
static char *log_prefix;
static void log_prefix_clear(void)
{
free(log_prefix);
log_prefix = NULL;
}
/*
* log_init:
* Initialize the logging to log into a file with the given name.
* @filename: the log filename; use '-' to suppress logging
*
* Returns 0 on success, -1 on failure with errno set.
*/
int log_init(const char *filename, bool truncate)
{
int flags;
if (!strcmp(filename, "-")) {
logfd = SUPPRESS_LOGGING;
return 0;
}
if (!truncate) {
flags = O_WRONLY|O_CREAT|O_APPEND|O_NOFOLLOW;
} else {
flags = O_WRONLY|O_CREAT|O_TRUNC|O_NOFOLLOW;
}
logfd = open(filename, flags, S_IRUSR|S_IWUSR);
if (logfd < 0) {
logfd = CONSOLE_LOGGING;
return -1;
}
log_prefix_clear();
return 0;
}
/*
* log_init_fd:
* Initialize the logging and have the logs written to the given file
* descriptor.
* @fd: file descriptor to log to
*
* Returns 0 on success, -1 on failure with errno set.
*/
int log_init_fd(int fd)
{
int flags;
close(logfd);
logfd = fd;
if (logfd >= 0) {
flags = fcntl(logfd, F_GETFL);
if (flags == -1)
return -1;
if ((flags & (O_RDWR|O_WRONLY)) == 0) {
errno = EPERM;
return -1;
}
}
log_prefix_clear();
return 0;
}
/*
* log_set_level
* Set the log level; the higher the level, the more is printed
* @level: the log level
*/
int log_set_level(unsigned int level)
{
log_level = level;
char *prefixbuf = NULL;
int ret = 0;
if (level >= 5) {
TPMLIB_SetDebugLevel(level - 4);
if (asprintf(&prefixbuf, "%s%s",
log_prefix ? log_prefix : "",
" ") < 0) {
ret = -1;
goto err_exit;
}
TPMLIB_SetDebugPrefix(prefixbuf);
free(prefixbuf);
}
if (logfd != SUPPRESS_LOGGING)
TPMLIB_SetDebugFD(logfd);
err_exit:
return ret;
}
/*
* log_set_prefix
* Set the logging prefix; this function should be
* call before log_set_level.
*
* @prefix: string to print before every line
*/
int log_set_prefix(const char *prefix)
{
free(log_prefix);
if (prefix) {
log_prefix = strdup(prefix);
if (!log_prefix)
return -1;
} else {
log_prefix = NULL;
}
return 0;
}
/*
* Check whether to write the string to the log following
* the log level
* @string: the string to print
*
* Returns -1 in case the string must not be printed following
* the log level, the number of bytes used for indentation otherwise.
*/
int log_check_string(const char *string)
{
unsigned int level, i;
if (log_level == 0)
return -1;
level = log_level - 1;
i = 0;
while (1) {
if (string[i] == 0)
return -1;
if (string[i] != ' ')
return i;
if (i == level)
return -1;
i++;
}
}
/*
* log_global_free: free memory allocated for global variables
*/
void log_global_free(void)
{
free(log_prefix);
log_prefix = NULL;
TPMLIB_SetDebugPrefix(NULL);
}
/*
* _logprintf:
* Format a log line and output it to the given file descriptor.
* @fd: file descriptor to log to
* @format: printf type of format for the string
* @ap: list of var args to format
* @check_indent: whether to check the level or force printing
*
* Returns the number of bytes written on success, a value < 0 on error.
*/
static int _logprintf(int fd, const char *format, va_list ap, bool check_indent)
{
char *buf = NULL;
int ret = 0, len = 0;
if (logfd == SUPPRESS_LOGGING)
return 0;
if (logfd > 0)
fd = logfd;
ret = vasprintf(&buf, format, ap);
if (ret < 0)
goto cleanup;
if (!check_indent || log_check_string(buf) >= 0) {
if (log_prefix) {
ret = write_full(fd, log_prefix, strlen(log_prefix));
if (ret < 0)
goto err_exit;
len = ret;
}
ret = write_full(fd, buf, strlen(buf));
if (ret < 0)
goto err_exit;
ret += len;
} else
ret = 0;
err_exit:
free(buf);
cleanup:
return ret;
}
/*
* logprintf:
* log to stderr or logfile
* @fd : the foile descriptor to log to
* @format: the printf style format to format the var args into
* @... : var args list of parameters to format
*
* Returns the number of bytes written on success, a value < 0 on error.
*/
int logprintf(int fd, const char *format, ...)
{
int ret;
va_list ap;
va_start(ap, format);
ret = _logprintf(fd, format, ap, true);
va_end(ap);
return ret;
}
/*
* logprintfA:
* log to stderr or logfile without checking the log level; indent each
* line by a number of spaces
*
* @fd : the foile descriptor to log to
* @indent: number of bytes to indent the string
* @format: the printf style format to format the var args into
* @... : var args list of parameters to format
*
* Returns the number of bytes written on success, a value < 0 on error.
*/
int logprintfA(int fd, unsigned int indent, const char *format, ...)
{
int ret;
va_list ap;
char spaces[20];
if (indent) {
if (indent > sizeof(spaces) - 1)
indent = sizeof(spaces) - 1;
memset(spaces, ' ', indent);
spaces[indent] = 0;
logprintfA(fd, 0, spaces, "");
}
va_start(ap, format);
ret = _logprintf(fd, format, ap, false);
va_end(ap);
return ret;
}