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