1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright (c) 1999 by Sun Microsystems, Inc.
24  * All rights reserved.
25  */
26 
27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
28 
29 #include <sys/types.h>
30 #include <sys/stat.h>
31 #include <errno.h>
32 #include <syslog.h>
33 #include <libintl.h>
34 #include <unistd.h>
35 #include <strings.h>
36 #include <string.h>
37 #include <assert.h>
38 #include <stdlib.h>
39 #include "nfslogd.h"
40 #include "../lib/nfslogtab.h"
41 #include "buffer_list.h"
42 
43 static int buildbuffer_list(struct buffer_ent **, timestruc_t *);
44 static void free_buffer_ent(struct buffer_ent *);
45 static struct buffer_ent *findbuffer(struct buffer_ent *, char *);
46 static void free_sharepnt_list(struct sharepnt_ent *);
47 static void free_sharepnt_ent(struct sharepnt_ent *);
48 #ifdef	DEBUG
49 static void print_sharepnt_list(struct sharepnt_ent *);
50 #endif
51 static struct sharepnt_ent *findsharepnt(struct sharepnt_ent *, char *,
52 	struct sharepnt_ent **);
53 
54 /*
55  * Builds the buffer list from NFSLOGTAB and returns it in *listpp.
56  * Returns 0 on success, non-zero error code otherwise.
57  */
58 int
getbuffer_list(struct buffer_ent ** listpp,timestruc_t * lu)59 getbuffer_list(struct buffer_ent **listpp, timestruc_t *lu)
60 {
61 	*listpp = NULL;
62 	return (buildbuffer_list(listpp, lu));
63 }
64 
65 /*
66  * If NFSLOGTAB has not been modified since the last time we read it,
67  * it simply returns the same buffer list, otherwise it re-reads NFSLOGTAB
68  * and rebuilds the list.
69  * No NFSLOGTAB is not treated as an error.
70  * Returns 0 on success, non-zero error code otherwise
71  */
72 int
checkbuffer_list(struct buffer_ent ** listpp,timestruc_t * lu)73 checkbuffer_list(struct buffer_ent **listpp, timestruc_t *lu)
74 {
75 	struct stat st;
76 	int error = 0;
77 
78 	if (stat(NFSLOGTAB, &st) == -1) {
79 		error = errno;
80 		if (error != ENOENT) {
81 			syslog(LOG_ERR, gettext("Can't stat %s - %s"),
82 				NFSLOGTAB, strerror(error));
83 			error = 0;
84 		}
85 		return (error);
86 	}
87 
88 	if (lu->tv_sec == st.st_mtim.tv_sec &&
89 	    lu->tv_nsec == st.st_mtim.tv_nsec)
90 		return (0);
91 
92 	free_buffer_list(listpp);	/* free existing list first */
93 	return (buildbuffer_list(listpp, lu));
94 }
95 
96 /*
97  * Does the actual work of reading NFSLOGTAB, and building the
98  * buffer list. If *be_head already contains entries, it will
99  * update the list with new information.
100  * Returns 0 on success, non-zero error code otherwise.
101  */
102 static int
buildbuffer_list(struct buffer_ent ** be_head,timestruc_t * lu)103 buildbuffer_list(struct buffer_ent **be_head, timestruc_t *lu)
104 {
105 	FILE *fd;
106 	struct buffer_ent *be_tail = NULL, *bep;
107 	struct sharepnt_ent *se_tail = NULL, *sep;
108 	struct logtab_ent *lep;
109 	struct stat st;
110 	int error = 0, res;
111 
112 	if ((fd = fopen(NFSLOGTAB, "r+")) == NULL) {
113 		error = errno;
114 		if (error != ENOENT) {
115 			syslog(LOG_ERR, gettext("%s - %s\n"), NFSLOGTAB,
116 				strerror(error));
117 			error = 0;
118 		}
119 		return (error);
120 	}
121 
122 	if (lockf(fileno(fd), F_LOCK, 0L) < 0) {
123 		error = errno;
124 		syslog(LOG_ERR, gettext("cannot lock %s - %s\n"), NFSLOGTAB,
125 			strerror(error));
126 		(void) fclose(fd);
127 		return (error);
128 	}
129 
130 	assert(*be_head == NULL);
131 	while ((res = logtab_getent(fd, &lep)) > 0) {
132 		if (bep = findbuffer(*be_head, lep->le_buffer)) {
133 			/*
134 			 * Add sharepnt to buffer list
135 			 */
136 			if (sep = findsharepnt(bep->be_sharepnt,
137 			    lep->le_path, &se_tail)) {
138 				/*
139 				 * Sharepoint already in list,
140 				 * update its state.
141 				 */
142 				sep->se_state = lep->le_state;
143 			} else {
144 				/*
145 				 * Need to add to sharepoint list
146 				 */
147 				sep = (struct sharepnt_ent *)
148 					malloc(sizeof (*sep));
149 				if (sep == NULL) {
150 					error = ENOMEM;
151 					goto errout;
152 				}
153 				(void) memset(sep, 0, sizeof (*sep));
154 
155 				sep->se_name = strdup(lep->le_path);
156 				if (sep->se_name == NULL) {
157 					error = ENOMEM;
158 					goto errout;
159 				}
160 				sep->se_state = lep->le_state;
161 
162 				assert(se_tail != NULL);
163 				assert(se_tail->se_next == NULL);
164 				se_tail->se_next = sep;
165 			}
166 		} else {
167 			/*
168 			 * Add new buffer to list
169 			 */
170 			bep = (struct buffer_ent *)malloc(sizeof (*bep));
171 			if (bep == NULL) {
172 				error = ENOMEM;
173 				goto errout;
174 			}
175 			(void) memset(bep, 0, sizeof (*bep));
176 
177 			bep->be_name = strdup(lep->le_buffer);
178 			if (bep->be_name == NULL) {
179 				error = ENOMEM;
180 				goto errout;
181 			}
182 
183 			if (*be_head == NULL)
184 				*be_head = bep;
185 			else
186 				be_tail->be_next = bep;
187 			be_tail = bep;
188 
189 			bep->be_sharepnt = (struct sharepnt_ent *)
190 				malloc(sizeof (*(bep->be_sharepnt)));
191 			(void) memset(bep->be_sharepnt, 0,
192 				sizeof (*(bep->be_sharepnt)));
193 
194 			if (bep->be_sharepnt == NULL) {
195 				error = ENOMEM;
196 				goto errout;
197 			}
198 			bep->be_sharepnt->se_name = strdup(lep->le_path);
199 			if (bep->be_sharepnt->se_name == NULL) {
200 				error = ENOMEM;
201 				goto errout;
202 			}
203 			bep->be_sharepnt->se_state = lep->le_state;
204 		}
205 	}
206 
207 	if (res < 0) {
208 		error = EIO;
209 		goto errout;
210 	}
211 
212 	/*
213 	 * Get modification time while we have the file locked.
214 	 */
215 	if (lu) {
216 		if ((error = fstat(fileno(fd), &st)) == -1) {
217 			syslog(LOG_ERR, gettext("Can't stat %s"), NFSLOGTAB);
218 			goto errout;
219 		}
220 		*lu = st.st_mtim;
221 	}
222 
223 	(void) fclose(fd);
224 	return (error);
225 
226 errout:
227 	(void) fclose(fd);
228 	if (lep)
229 		logtab_ent_free(lep);
230 	free_buffer_list(be_head);
231 	assert(*be_head == NULL);
232 	syslog(LOG_ERR, gettext("cannot read %s: %s\n"), NFSLOGTAB,
233 		strerror(error));
234 
235 	return (error);
236 }
237 
238 /*
239  * Removes the entry from the buffer list and frees it.
240  */
241 void
remove_buffer_ent(struct buffer_ent ** be_listpp,struct buffer_ent * bep)242 remove_buffer_ent(struct buffer_ent **be_listpp, struct buffer_ent *bep)
243 {
244 	struct buffer_ent *p, *prev;
245 
246 	for (p = prev = *be_listpp; p != NULL; p = p->be_next) {
247 		if (p == bep) {
248 			if (p == *be_listpp)
249 				*be_listpp = (*be_listpp)->be_next;
250 			else
251 				prev->be_next = bep->be_next;
252 			free_buffer_ent(bep);
253 			break;
254 		}
255 		prev = p;
256 	}
257 }
258 
259 /*
260  * Frees the buffer list.
261  */
262 void
free_buffer_list(struct buffer_ent ** be_listpp)263 free_buffer_list(struct buffer_ent **be_listpp)
264 {
265 	struct buffer_ent *bep, *nextp;
266 
267 	for (bep = *be_listpp; bep != NULL; bep = nextp) {
268 		nextp = bep->be_next;
269 		free_buffer_ent(bep);
270 	}
271 	*be_listpp = NULL;
272 }
273 
274 static void
free_buffer_ent(struct buffer_ent * bep)275 free_buffer_ent(struct buffer_ent *bep)
276 {
277 	assert(bep != NULL);
278 	if (debug)
279 		(void) printf("freeing %s\n", bep->be_name);
280 	if (bep->be_name != NULL)
281 		free(bep->be_name);
282 	if (bep->be_sharepnt != NULL)
283 		free_sharepnt_list(bep->be_sharepnt);
284 	free(bep);
285 }
286 
287 static void
free_sharepnt_list(struct sharepnt_ent * sep_listp)288 free_sharepnt_list(struct sharepnt_ent *sep_listp)
289 {
290 	struct sharepnt_ent *nextp;
291 
292 	for (; sep_listp != NULL; sep_listp = nextp) {
293 		nextp = sep_listp->se_next;
294 		free_sharepnt_ent(sep_listp);
295 	}
296 	free(sep_listp);
297 }
298 
299 /*
300  * Removes the entry from the sharepnt list and frees it.
301  */
302 void
remove_sharepnt_ent(struct sharepnt_ent ** se_listpp,struct sharepnt_ent * sep)303 remove_sharepnt_ent(struct sharepnt_ent **se_listpp, struct sharepnt_ent *sep)
304 {
305 	struct sharepnt_ent *p, *prev;
306 
307 	for (p = prev = *se_listpp; p != NULL; p = p->se_next) {
308 		if (p == sep) {
309 			if (p == *se_listpp)
310 				*se_listpp = (*se_listpp)->se_next;
311 			else
312 				prev->se_next = sep->se_next;
313 			free_sharepnt_ent(sep);
314 			break;
315 		}
316 		prev = p;
317 	}
318 }
319 
320 static void
free_sharepnt_ent(struct sharepnt_ent * sep)321 free_sharepnt_ent(struct sharepnt_ent *sep)
322 {
323 	assert(sep != NULL);
324 	if (debug)
325 		(void) printf("freeing %s\n", sep->se_name);
326 	if (sep->se_name != NULL)
327 		free(sep->se_name);
328 	free(sep);
329 }
330 
331 #ifdef DEBUG
332 void
printbuffer_list(struct buffer_ent * bep)333 printbuffer_list(struct buffer_ent *bep)
334 {
335 	for (; bep != NULL; bep = bep->be_next) {
336 		(void) printf("%s\n", bep->be_name);
337 		if (bep->be_sharepnt != NULL)
338 			print_sharepnt_list(bep->be_sharepnt);
339 	}
340 }
341 
342 static void
print_sharepnt_list(struct sharepnt_ent * sep)343 print_sharepnt_list(struct sharepnt_ent *sep)
344 {
345 	for (; sep != NULL; sep = sep->se_next)
346 		(void) printf("\t(%d) %s\n", sep->se_state, sep->se_name);
347 }
348 #endif
349 
350 /*
351  * Returns a pointer to the buffer matching 'name', NULL otherwise.
352  */
353 static struct buffer_ent *
findbuffer(struct buffer_ent * bep,char * name)354 findbuffer(struct buffer_ent *bep, char *name)
355 {
356 	for (; bep != NULL; bep = bep->be_next) {
357 		if (strcmp(bep->be_name, name) == 0)
358 			return (bep);
359 	}
360 	return (NULL);
361 }
362 
363 /*
364  * Returns a pointer the sharepoint entry matching 'name'.
365  * Otherwise, it sets '*se_tail' to the last element of the list
366  * to make insertion of new element easier, and returns NULL.
367  */
368 static struct sharepnt_ent *
findsharepnt(struct sharepnt_ent * sep,char * name,struct sharepnt_ent ** se_tail)369 findsharepnt(
370 	struct sharepnt_ent *sep,
371 	char *name,
372 	struct sharepnt_ent **se_tail)
373 {
374 	struct sharepnt_ent *tail;
375 
376 	for (; sep != NULL; sep = sep->se_next) {
377 		if (strcmp(sep->se_name, name) == 0)
378 			return (sep);
379 		tail = sep;
380 	}
381 	*se_tail = tail;
382 	return (NULL);
383 }
384