#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>
#include <syslog.h>
#include <libintl.h>
#include <unistd.h>
#include <strings.h>
#include <string.h>
#include <assert.h>
#include <stdlib.h>
#include "nfslogd.h"
#include "../lib/nfslogtab.h"
#include "buffer_list.h"
static int buildbuffer_list(struct buffer_ent **, timestruc_t *);
static void free_buffer_ent(struct buffer_ent *);
static struct buffer_ent *findbuffer(struct buffer_ent *, char *);
static void free_sharepnt_list(struct sharepnt_ent *);
static void free_sharepnt_ent(struct sharepnt_ent *);
#ifdef DEBUG
static void print_sharepnt_list(struct sharepnt_ent *);
#endif
static struct sharepnt_ent *findsharepnt(struct sharepnt_ent *, char *,
struct sharepnt_ent **);
int
getbuffer_list(struct buffer_ent **listpp, timestruc_t *lu)
{
*listpp = NULL;
return (buildbuffer_list(listpp, lu));
}
int
checkbuffer_list(struct buffer_ent **listpp, timestruc_t *lu)
{
struct stat st;
int error = 0;
if (stat(NFSLOGTAB, &st) == -1) {
error = errno;
if (error != ENOENT) {
syslog(LOG_ERR, gettext("Can't stat %s - %s"),
NFSLOGTAB, strerror(error));
error = 0;
}
return (error);
}
if (lu->tv_sec == st.st_mtim.tv_sec &&
lu->tv_nsec == st.st_mtim.tv_nsec)
return (0);
free_buffer_list(listpp);
return (buildbuffer_list(listpp, lu));
}
static int
buildbuffer_list(struct buffer_ent **be_head, timestruc_t *lu)
{
FILE *fd;
struct buffer_ent *be_tail = NULL, *bep;
struct sharepnt_ent *se_tail = NULL, *sep;
struct logtab_ent *lep;
struct stat st;
int error = 0, res;
if ((fd = fopen(NFSLOGTAB, "r+")) == NULL) {
error = errno;
if (error != ENOENT) {
syslog(LOG_ERR, gettext("%s - %s\n"), NFSLOGTAB,
strerror(error));
error = 0;
}
return (error);
}
if (lockf(fileno(fd), F_LOCK, 0L) < 0) {
error = errno;
syslog(LOG_ERR, gettext("cannot lock %s - %s\n"), NFSLOGTAB,
strerror(error));
(void) fclose(fd);
return (error);
}
assert(*be_head == NULL);
while ((res = logtab_getent(fd, &lep)) > 0) {
if (bep = findbuffer(*be_head, lep->le_buffer)) {
if (sep = findsharepnt(bep->be_sharepnt,
lep->le_path, &se_tail)) {
sep->se_state = lep->le_state;
} else {
sep = (struct sharepnt_ent *)
malloc(sizeof (*sep));
if (sep == NULL) {
error = ENOMEM;
goto errout;
}
(void) memset(sep, 0, sizeof (*sep));
sep->se_name = strdup(lep->le_path);
if (sep->se_name == NULL) {
error = ENOMEM;
goto errout;
}
sep->se_state = lep->le_state;
assert(se_tail != NULL);
assert(se_tail->se_next == NULL);
se_tail->se_next = sep;
}
} else {
bep = (struct buffer_ent *)malloc(sizeof (*bep));
if (bep == NULL) {
error = ENOMEM;
goto errout;
}
(void) memset(bep, 0, sizeof (*bep));
bep->be_name = strdup(lep->le_buffer);
if (bep->be_name == NULL) {
error = ENOMEM;
goto errout;
}
if (*be_head == NULL)
*be_head = bep;
else
be_tail->be_next = bep;
be_tail = bep;
bep->be_sharepnt = (struct sharepnt_ent *)
malloc(sizeof (*(bep->be_sharepnt)));
(void) memset(bep->be_sharepnt, 0,
sizeof (*(bep->be_sharepnt)));
if (bep->be_sharepnt == NULL) {
error = ENOMEM;
goto errout;
}
bep->be_sharepnt->se_name = strdup(lep->le_path);
if (bep->be_sharepnt->se_name == NULL) {
error = ENOMEM;
goto errout;
}
bep->be_sharepnt->se_state = lep->le_state;
}
}
if (res < 0) {
error = EIO;
goto errout;
}
if (lu) {
if ((error = fstat(fileno(fd), &st)) == -1) {
syslog(LOG_ERR, gettext("Can't stat %s"), NFSLOGTAB);
goto errout;
}
*lu = st.st_mtim;
}
(void) fclose(fd);
return (error);
errout:
(void) fclose(fd);
if (lep)
logtab_ent_free(lep);
free_buffer_list(be_head);
assert(*be_head == NULL);
syslog(LOG_ERR, gettext("cannot read %s: %s\n"), NFSLOGTAB,
strerror(error));
return (error);
}
void
remove_buffer_ent(struct buffer_ent **be_listpp, struct buffer_ent *bep)
{
struct buffer_ent *p, *prev;
for (p = prev = *be_listpp; p != NULL; p = p->be_next) {
if (p == bep) {
if (p == *be_listpp)
*be_listpp = (*be_listpp)->be_next;
else
prev->be_next = bep->be_next;
free_buffer_ent(bep);
break;
}
prev = p;
}
}
void
free_buffer_list(struct buffer_ent **be_listpp)
{
struct buffer_ent *bep, *nextp;
for (bep = *be_listpp; bep != NULL; bep = nextp) {
nextp = bep->be_next;
free_buffer_ent(bep);
}
*be_listpp = NULL;
}
static void
free_buffer_ent(struct buffer_ent *bep)
{
assert(bep != NULL);
if (debug)
(void) printf("freeing %s\n", bep->be_name);
if (bep->be_name != NULL)
free(bep->be_name);
if (bep->be_sharepnt != NULL)
free_sharepnt_list(bep->be_sharepnt);
free(bep);
}
static void
free_sharepnt_list(struct sharepnt_ent *sep_listp)
{
struct sharepnt_ent *nextp;
for (; sep_listp != NULL; sep_listp = nextp) {
nextp = sep_listp->se_next;
free_sharepnt_ent(sep_listp);
}
free(sep_listp);
}
void
remove_sharepnt_ent(struct sharepnt_ent **se_listpp, struct sharepnt_ent *sep)
{
struct sharepnt_ent *p, *prev;
for (p = prev = *se_listpp; p != NULL; p = p->se_next) {
if (p == sep) {
if (p == *se_listpp)
*se_listpp = (*se_listpp)->se_next;
else
prev->se_next = sep->se_next;
free_sharepnt_ent(sep);
break;
}
prev = p;
}
}
static void
free_sharepnt_ent(struct sharepnt_ent *sep)
{
assert(sep != NULL);
if (debug)
(void) printf("freeing %s\n", sep->se_name);
if (sep->se_name != NULL)
free(sep->se_name);
free(sep);
}
#ifdef DEBUG
void
printbuffer_list(struct buffer_ent *bep)
{
for (; bep != NULL; bep = bep->be_next) {
(void) printf("%s\n", bep->be_name);
if (bep->be_sharepnt != NULL)
print_sharepnt_list(bep->be_sharepnt);
}
}
static void
print_sharepnt_list(struct sharepnt_ent *sep)
{
for (; sep != NULL; sep = sep->se_next)
(void) printf("\t(%d) %s\n", sep->se_state, sep->se_name);
}
#endif
static struct buffer_ent *
findbuffer(struct buffer_ent *bep, char *name)
{
for (; bep != NULL; bep = bep->be_next) {
if (strcmp(bep->be_name, name) == 0)
return (bep);
}
return (NULL);
}
static struct sharepnt_ent *
findsharepnt(
struct sharepnt_ent *sep,
char *name,
struct sharepnt_ent **se_tail)
{
struct sharepnt_ent *tail;
for (; sep != NULL; sep = sep->se_next) {
if (strcmp(sep->se_name, name) == 0)
return (sep);
tail = sep;
}
*se_tail = tail;
return (NULL);
}