#include <strings.h>
#include <string.h>
#include <syslog.h>
#include <locale.h>
#include <nfs/nfs.h>
#include <nfs/export.h>
#include <nfs/nfssys.h>
#include <nfs/nfs_log.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
#include <errno.h>
#include <assert.h>
#include <stdlib.h>
#include <unistd.h>
#include <nfs/nfs_log.h>
#include "../lib/nfslog_config.h"
#include "buffer_list.h"
#include "nfslogd.h"
extern int _nfssys(int, void *);
struct nfs_log_list {
char *l_name;
struct nfs_log_list *l_next;
};
static void badtag_notify(char *tag);
static struct nfs_log_list *badtag_list = NULL;
static void cleanup_elf_state(nfsl_config_t *);
static void cleanup_trans_state(nfsl_config_t *);
int
process_buffer(
struct buffer_ent *bep,
nfsl_config_t **config_list,
int min_size,
int idle_time,
int *buffer_processed)
{
struct stat st;
struct nfsl_flush_args nfa;
struct nfslog_buf *lbp = NULL;
struct nfslog_lr *lrp;
char *path1 = NULL;
char *path2 = NULL;
char *buffer_inprog = NULL;
int buffer_inprog_len;
int error = 0;
nfsl_config_t *ncp = NULL, *last_good_ncp;
char *bufferpath = bep->be_name;
char *tag;
boolean_t elf_checked = B_FALSE;
boolean_t trans_checked = B_FALSE;
assert(buffer_processed != NULL);
assert(bufferpath != NULL);
if (stat(bufferpath, &st) == -1) {
error = errno;
if (error == ENOENT) {
error = 0;
buffer_inprog_len = strlen(bufferpath) +
strlen(LOG_INPROG_STRING) + 1;
buffer_inprog = (char *)malloc(buffer_inprog_len);
if (buffer_inprog == NULL) {
syslog(LOG_ERR, gettext(
"process_buffer: malloc failed"));
return (ENOMEM);
}
(void) sprintf(buffer_inprog, "%s%s", bufferpath,
LOG_INPROG_STRING);
if (stat(buffer_inprog, &st) == -1) {
error = errno;
if (bep->be_error != error) {
syslog(LOG_ERR, gettext(
"Can not stat %s: %s"),
buffer_inprog, strerror(error));
}
free(buffer_inprog);
return (error);
}
free(buffer_inprog);
if ((st.st_size < min_size) &&
((time(0) - bep->be_lastprocessed) < idle_time)) {
return (0);
}
(void) memset((void *)&nfa, 0, sizeof (nfa));
nfa.version = NFSL_FLUSH_ARGS_VERS;
nfa.directive = NFSL_RENAME | NFSL_SYNC;
nfa.buff = bufferpath;
nfa.buff_len = strlen(bufferpath) + 1;
if (_nfssys(LOG_FLUSH, &nfa) < 0) {
error = errno;
if (bep->be_error != error) {
syslog(LOG_ERR, gettext(
"_nfssys(%s) failed: %s"),
nfa.buff, strerror(error));
}
return (error);
}
} else {
if (bep->be_error != error) {
syslog(LOG_ERR, gettext("Can not stat %s: %s"),
bufferpath, strerror(error));
}
return (error);
}
}
error = bep->be_error;
if ((lbp = nfslog_open_buf(bufferpath, &error)) == NULL)
goto done;
if ((ncp = last_good_ncp =
nfsl_findconfig(*config_list, "global", &error)) == NULL) {
assert(error != 0);
nfsl_freeconfig_list(config_list);
if (error != bep->be_error) {
syslog(LOG_ERR, gettext(
"Could not search config list: %s"),
strerror(error));
}
goto done;
}
assert(error == 0);
while ((lrp = nfslog_get_logrecord(lbp)) != NULL && keep_running) {
if (*buffer_processed == 0)
(*buffer_processed)++;
tag = lrp->log_record.re_tag;
if (strcmp(tag, last_good_ncp->nc_name) != 0) {
ncp = nfsl_findconfig(*config_list, tag, &error);
if (error) {
if (error != bep->be_error) {
syslog(LOG_ERR, gettext(
"Could not search config list: %s"),
strerror(error));
}
nfsl_freeconfig_list(config_list);
goto done;
}
if (ncp == NULL) {
badtag_notify(tag);
ncp = last_good_ncp;
goto skip;
}
last_good_ncp = ncp;
}
if (ncp->nc_flags & NC_UPDATED) {
cleanup_elf_state(ncp);
cleanup_trans_state(ncp);
ncp->nc_flags &= ~NC_UPDATED;
elf_checked = trans_checked = B_FALSE;
}
if (ncp->nc_rpclogpath != NULL) {
if (!elf_checked && ncp->nc_elfcookie != NULL) {
if (stat(ncp->nc_rpclogpath, &st) == -1 &&
errno == ENOENT) {
cleanup_elf_state(ncp);
}
elf_checked = B_TRUE;
}
if (ncp->nc_elfcookie == NULL) {
error = bep->be_error;
ncp->nc_elfcookie = nfslog_open_elf_file(
ncp->nc_rpclogpath, &lbp->bh, &error);
if (ncp->nc_elfcookie == NULL) {
bep->be_error = error;
goto done;
}
}
}
if (ncp->nc_logpath != NULL) {
if (!trans_checked && ncp->nc_transcookie != NULL) {
if (stat(ncp->nc_logpath, &st) == -1 &&
errno == ENOENT) {
cleanup_trans_state(ncp);
}
trans_checked = B_TRUE;
}
if (ncp->nc_transcookie == NULL) {
int transtolog;
transtolog =
(ncp->nc_logformat == TRANSLOG_BASIC) ?
TRANSTOLOG_OPER_READWRITE : TRANSTOLOG_ALL;
error = bep->be_error;
ncp->nc_transcookie = nfslog_open_trans_file(
ncp->nc_logpath, ncp->nc_logformat,
transtolog, &error);
if (ncp->nc_transcookie == NULL) {
bep->be_error = error;
goto done;
}
}
}
assert(ncp->nc_fhpath != NULL);
if (nfslog_process_fh_rec(lrp, ncp->nc_fhpath, &path1, &path2,
ncp->nc_elfcookie != NULL)) {
if (ncp->nc_elfcookie != NULL) {
(void) nfslog_process_elf_rec(ncp->nc_elfcookie,
&lrp->log_record, path1, path2);
}
if (ncp->nc_transcookie != NULL) {
(void) nfslog_process_trans_rec(
ncp->nc_transcookie,
&lrp->log_record, ncp->nc_fhpath,
path1, path2);
}
}
skip: if (path1 != NULL)
free(path1);
if (path2 != NULL)
free(path2);
path1 = path2 = NULL;
nfslog_free_logrecord(lrp, TRUE);
}
if (!error && keep_running) {
bep->be_lastprocessed = time(0);
if (test && *buffer_processed != 0) {
if (cycle_log(bufferpath, max_logs_preserve)) {
syslog(LOG_ERR, gettext(
"could not save copy of buffer \"%s\""),
bufferpath);
}
} else {
if (unlink(bufferpath)) {
error = errno;
syslog(LOG_ERR, gettext(
"could not unlink %s: %s"),
bufferpath, strerror(error));
error = 0;
}
}
}
done:
if (lbp != NULL)
nfslog_close_buf(lbp, quick_cleaning);
if (ncp && !quick_cleaning)
cleanup_elf_state(ncp);
return (error);
}
static void
cleanup_elf_state(nfsl_config_t *ncp)
{
if (ncp->nc_elfcookie != NULL) {
nfslog_close_elf_file(&ncp->nc_elfcookie);
assert(ncp->nc_elfcookie == NULL);
}
}
static void
cleanup_trans_state(nfsl_config_t *ncp)
{
if (ncp->nc_transcookie != NULL) {
nfslog_close_transactions(&ncp->nc_transcookie);
assert(ncp->nc_transcookie == NULL);
}
}
static void
badtag_notify(char *tag)
{
struct nfs_log_list *lp, *p;
int error;
for (p = badtag_list; p != NULL; p = p->l_next) {
if (strcmp(tag, p->l_name) == 0) {
return;
}
}
syslog(LOG_ERR, gettext("tag \"%s\" not found in %s - "
"ignoring records referencing such tag."),
tag, NFSL_CONFIG_FILE_PATH);
if ((lp = (struct nfs_log_list *)malloc(sizeof (*lp))) != NULL) {
if ((lp->l_name = strdup(tag)) != NULL) {
lp->l_next = badtag_list;
badtag_list = lp;
return;
}
}
if (lp->l_name != NULL)
free(lp->l_name);
if (lp)
free(lp);
error = errno;
syslog(LOG_ERR, gettext(
"Cannot add \"%s\" to bad tag list: %s"), tag, strerror(error));
}