/* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (the "License"). You may not use this file except in compliance * with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright (c) 1999 by Sun Microsystems, Inc. * All rights reserved. */ #include #include #include #include #include #include #include #include #include #include #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 **); /* * Builds the buffer list from NFSLOGTAB and returns it in *listpp. * Returns 0 on success, non-zero error code otherwise. */ int getbuffer_list(struct buffer_ent **listpp, timestruc_t *lu) { *listpp = NULL; return (buildbuffer_list(listpp, lu)); } /* * If NFSLOGTAB has not been modified since the last time we read it, * it simply returns the same buffer list, otherwise it re-reads NFSLOGTAB * and rebuilds the list. * No NFSLOGTAB is not treated as an error. * Returns 0 on success, non-zero error code otherwise */ 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); /* free existing list first */ return (buildbuffer_list(listpp, lu)); } /* * Does the actual work of reading NFSLOGTAB, and building the * buffer list. If *be_head already contains entries, it will * update the list with new information. * Returns 0 on success, non-zero error code otherwise. */ 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)) { /* * Add sharepnt to buffer list */ if (sep = findsharepnt(bep->be_sharepnt, lep->le_path, &se_tail)) { /* * Sharepoint already in list, * update its state. */ sep->se_state = lep->le_state; } else { /* * Need to add to sharepoint list */ 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 { /* * Add new buffer to list */ 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; } /* * Get modification time while we have the file locked. */ 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); } /* * Removes the entry from the buffer list and frees it. */ 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; } } /* * Frees the buffer list. */ 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); } /* * Removes the entry from the sharepnt list and frees it. */ 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 /* * Returns a pointer to the buffer matching 'name', NULL otherwise. */ 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); } /* * Returns a pointer the sharepoint entry matching 'name'. * Otherwise, it sets '*se_tail' to the last element of the list * to make insertion of new element easier, and returns 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); }