/* * 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. */ #pragma ident "%Z%%M% %I% %E% SMI" /* * Manipulates the nfslogtab */ #ifndef _REENTRANT #define _REENTRANT #endif #include #include #include #include #include #include #include #include #include #include #include "nfslogtab.h" #ifndef LINTHAPPY #define LINTHAPPY #endif static void logtab_ent_list_free(struct logtab_ent_list *); /* * Retrieves the next entry from nfslogtab. * Assumes the file is locked. * '*lepp' points to the new entry if successful. * Returns: * > 0 valid entry * = 0 end of file * < 0 error */ int logtab_getent(FILE *fd, struct logtab_ent **lepp) { char line[MAXBUFSIZE + 1]; char *p; char *lasts, *tmp; char *w = " \t"; struct logtab_ent *lep = NULL; int error = 0; if ((lep = (struct logtab_ent *)malloc(sizeof (*lep))) == NULL) { return (-1); } (void) memset((char *)lep, 0, sizeof (*lep)); if ((p = fgets(line, MAXBUFSIZE, fd)) == NULL) { error = 0; goto errout; } line[strlen(line) - 1] = '\0'; tmp = (char *)strtok_r(p, w, &lasts); if (tmp == NULL) { error = -1; goto errout; } if ((lep->le_buffer = strdup(tmp)) == NULL) { error = -1; goto errout; } tmp = (char *)strtok_r(NULL, w, &lasts); if (tmp == NULL) { error = -1; goto errout; } if ((lep->le_path = strdup(tmp)) == NULL) { error = -1; goto errout; } tmp = (char *)strtok_r(NULL, w, &lasts); if (tmp == NULL) { error = -1; goto errout; } if ((lep->le_tag = strdup(tmp)) == NULL) { error = -1; goto errout; } tmp = (char *)strtok_r(NULL, w, &lasts); if (tmp == NULL) { error = -1; goto errout; } lep->le_state = atoi(tmp); *lepp = lep; return (1); errout: logtab_ent_free(lep); return (error); } /* * Append an entry to the logtab file. */ int logtab_putent(FILE *fd, struct logtab_ent *lep) { int r; if (fseek(fd, 0L, SEEK_END) < 0) return (errno); r = fprintf(fd, "%s\t%s\t%s\t%d\n", lep->le_buffer, lep->le_path, lep->le_tag, lep->le_state); return (r); } #ifndef LINTHAPPY /* * Searches the nfslogtab file looking for the next entry which matches * the search criteria. The search is continued at the current position * in the nfslogtab file. * If 'buffer' != NULL, then buffer is matched. * If 'path' != NULL, then path is matched. * If 'tag' != NULL, then tag is matched. * If 'state' != -1, then state is matched. * 'buffer', 'path' and 'tag' can all be non-NULL, which means the entry must * satisfy all requirements. * * Returns 0 on success, ENOENT otherwise. * If found, '*lepp' points to the matching entry, otherwise '*lepp' is * undefined. */ static int logtab_findent(FILE *fd, char *buffer, char *path, char *tag, int state, struct logtab_ent **lepp) { boolean_t found = B_FALSE; while (!found && (logtab_getent(fd, lepp) > 0)) { found = B_TRUE; if (buffer != NULL) found = strcmp(buffer, (*lepp)->le_buffer) == 0; if (path != NULL) found = found && (strcmp(path, (*lepp)->le_path) == 0); if (tag != NULL) found = found && (strcmp(tag, (*lepp)->le_tag) == 0); if (state != -1) found = found && (state == (*lepp)->le_state); if (!found) logtab_ent_free(*lepp); } return (found ? 0 : ENOENT); } #endif /* * Remove all entries which match the search criteria. * If 'buffer' != NULL, then buffer is matched. * If 'path' != NULL, then path is matched. * If 'tag' != NULL, then tag is matched. * If 'state' != -1, then state is matched. * 'buffer', 'path' and 'tag' can all be non-NULL, which means the entry must * satisfy all requirements. * The file is assumed to be locked. * Read the entries into a linked list of logtab_ent structures * minus the entries to be removed, then truncate the nfslogtab * file and write it back to the file from the linked list. * * On success returns 0, -1 otherwise. * Entry not found is treated as success since it was going to be removed * anyway. */ int logtab_rement(FILE *fd, char *buffer, char *path, char *tag, int state) { struct logtab_ent_list *head = NULL, *tail = NULL, *tmpl; struct logtab_ent *lep; int remcnt = 0; /* remove count */ int error = 0; boolean_t found; rewind(fd); while ((error = logtab_getent(fd, &lep)) > 0) { found = B_TRUE; if (buffer != NULL) found = strcmp(buffer, lep->le_buffer) == 0; if (path != NULL) found = found && (strcmp(path, lep->le_path) == 0); if (tag != NULL) found = found && (strcmp(tag, lep->le_tag) == 0); if (state != -1) found = found && (state == lep->le_state); if (found) { remcnt++; logtab_ent_free(lep); } else { tmpl = (struct logtab_ent_list *) malloc(sizeof (struct logtab_ent)); if (tmpl == NULL) { error = ENOENT; break; } tmpl->lel_le = lep; tmpl->lel_next = NULL; if (head == NULL) { /* * empty list */ head = tail = tmpl; } else { /* * Add to the end of the list and remember * the new last element. */ tail->lel_next = tmpl; tail = tmpl; /* remember the last element */ } } } if (error) goto deallocate; if (remcnt == 0) { /* * Entry not found, nothing to do */ goto deallocate; } if (ftruncate(fileno(fd), 0) < 0) { error = -1; goto deallocate; } for (tmpl = head; tmpl != NULL; tmpl = tmpl->lel_next) (void) logtab_putent(fd, tmpl->lel_le); deallocate: logtab_ent_list_free(head); return (error); } /* * Deactivate all entries matching search criteria. * If 'buffer' != NULL then match buffer. * If 'path' != NULL then match path. * If 'tag' != NULL then match tag. * Note that 'buffer', 'path' and 'tag' can al be non-null at the same time. * * Rewrites the nfslogtab file with the updated state for each entry. * Assumes the nfslogtab file has been locked for writing. * Returns 0 on success, -1 on failure. */ int logtab_deactivate(FILE *fd, char *buffer, char *path, char *tag) { struct logtab_ent_list *lelp, *head = NULL, *tail = NULL; struct logtab_ent *lep; boolean_t found; int error = 0; int count = 0; rewind(fd); while ((error = logtab_getent(fd, &lep)) > 0) { found = B_TRUE; if (buffer != NULL) found = strcmp(buffer, lep->le_buffer) == 0; if (path != NULL) found = found && (strcmp(path, lep->le_path) == 0); if (tag != NULL) found = found && (strcmp(tag, lep->le_tag) == 0); if (found && (lep->le_state == LES_ACTIVE)) { count++; lep->le_state = LES_INACTIVE; } lelp = (struct logtab_ent_list *) malloc(sizeof (struct logtab_ent)); if (lelp == NULL) { error = ENOENT; break; } lelp->lel_le = lep; lelp->lel_next = NULL; if (head == NULL) { /* * empty list */ head = tail = lelp; } else { /* * Add to the end of the list and remember * the new last element. */ tail->lel_next = lelp; tail = lelp; /* remember the last element */ } } if (error) goto deallocate; if (count == 0) { /* * done */ error = 0; goto deallocate; } if (ftruncate(fileno(fd), 0) < 0) { error = -1; goto deallocate; } for (lelp = head; lelp != NULL; lelp = lelp->lel_next) (void) logtab_putent(fd, lelp->lel_le); deallocate: logtab_ent_list_free(head); return (error); } /* * Deactivates all entries if nfslogtab exists and is older than boot time * This will only happen the first time it is called. * Assumes 'fd' has been locked by the caller. * Returns 0 on success, otherwise -1. */ int logtab_deactivate_after_boot(FILE *fd) { struct stat st; struct utmpx *utmpxp; int error = 0; if ((fstat(fileno(fd), &st) == 0) && ((utmpxp = getutxent()) != NULL) && (utmpxp->ut_xtime > st.st_mtime)) { if (logtab_deactivate(fd, NULL, NULL, NULL)) error = -1; } return (error); } void logtab_ent_free(struct logtab_ent *lep) { if (lep->le_buffer) free(lep->le_buffer); if (lep->le_path) free(lep->le_path); if (lep->le_tag) free(lep->le_tag); free(lep); } static void logtab_ent_list_free(struct logtab_ent_list *head) { struct logtab_ent_list *lelp, *next; if (head == NULL) return; for (lelp = head; lelp != NULL; lelp = next) { if (lelp->lel_le != NULL) logtab_ent_free(lelp->lel_le); next = lelp->lel_next; free(lelp); } }