fsipd/logfile.c

198 lines
4.4 KiB
C

/*-
* Copyright (c) 2016, Babak Farrokhi
* 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.
*
* 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 "logfile.h"
#ifdef __linux__
#define _PROGNAME program_invocation_short_name
#else
#define _PROGNAME getprogname()
#endif /* __linux__ */
/*
* create/open given logfile and initialize appropriate struct
*/
log_t *
log_open(const char *path, mode_t mode)
{
log_t *lh;
struct stat sb;
char *filename;
int fd;
if (path == NULL) {
asprintf(&filename, "%s/%s.log", LOGPATH, _PROGNAME);
} else {
filename = (char *)path;
}
/*
* try to create / append the file and make sure it is correctly
* created
*/
if ((fd = open(filename, O_WRONLY | O_APPEND | O_CREAT | O_SYNC, mode)) == -1)
return (NULL);
if (flock(fd, LOCK_EX) == -1) {
close(fd);
return (NULL);
}
if (stat(filename, &sb) == -1) {
close(fd);
return (NULL);
}
/* initialize data structure */
lh = calloc(1, sizeof(log_t));
lh->fd = fd;
lh->dev = sb.st_dev;
lh->ino = sb.st_ino;
lh->mode = sb.st_mode;
strncpy(lh->path, filename, strnlen(filename, MAXPATHLEN + 1));
return (lh);
}
/*
* close logfile handle and free up allocated struct
*/
void
log_close(const log_t *log)
{
if (!log_isopen(log))
return;
close(log->fd);
free((void *)log);
}
/*
* check whether or not the logfile is opened
*/
inline bool
log_isopen(const log_t *log)
{
if (log == NULL)
return (false);
return (log->fd != -1);
}
/*
* close and open logfile, used when a HUP signal is received (mosly in case of log roration)
*/
void
log_reopen(log_t **log)
{
log_t *newlog;
if (!log_isopen(*log))
return;
newlog = malloc(sizeof(log_t));
memcpy(newlog, *log, sizeof(log_t));
log_close(*log);
*log = log_open(newlog->path, newlog->mode);
free(newlog);
}
/*
* printf given text into logfile
*/
void
log_printf(const log_t *log, const char *format,...)
{
if (!log_isopen(log))
return;
va_list args;
char *message;
char *newline = "\n";
va_start(args, format);
vasprintf(&message, format, args);
va_end(args);
write(log->fd, message, strnlen(message, MAX_MSG_SIZE));
write(log->fd, newline, sizeof(*newline));
free(message);
}
/*
* printf into a logfile with timestamp prefix
*/
void
log_tsprintf(const log_t *log, const char *format,...)
{
if (!log_isopen(log))
return;
va_list args;
char *message;
char s_time[30];
time_t now;
struct tm *ltime;
size_t tsize;
char *newline = "\n";
va_start(args, format);
vasprintf(&message, format, args);
va_end(args);
now = time(NULL);
ltime = localtime(&now);
tsize = strftime(s_time, sizeof(s_time), "%Y-%m-%d %T %Z - ", ltime);
write(log->fd, s_time, tsize);
write(log->fd, message, strnlen(message, MAX_MSG_SIZE));
write(log->fd, newline, sizeof(*newline));
free(message);
}
/*
* check integrity of logfile with comparing filesystem stat with our use-specified settings
*/
bool
log_verify(const log_t *log)
{
struct stat sb;
if (log == NULL || log->fd == -1) {
errno = EINVAL;
return (false);
}
if (fstat(log->fd, &sb) == -1)
return (false);
if (log->ino != sb.st_ino || log->dev != sb.st_dev || log->mode != sb.st_mode) {
errno = EINVAL;
return (false);
}
return true;
}