xref: /illumos-gate/usr/src/cmd/fs.d/nfs/lib/nfslogtab.c (revision 942c5e3c2dd127463517e5cc1694ee94ca45e021)
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 /*
30  * Manipulates the nfslogtab
31  */
32 
33 #ifndef _REENTRANT
34 #define	_REENTRANT
35 #endif
36 
37 #include <sys/types.h>
38 #include <sys/stat.h>
39 #include <errno.h>
40 #include <utmpx.h>
41 #include <assert.h>
42 #include <stdio.h>
43 #include <stdlib.h>
44 #include <unistd.h>
45 #include <strings.h>
46 #include <string.h>
47 #include "nfslogtab.h"
48 
49 #ifndef	LINTHAPPY
50 #define	LINTHAPPY
51 #endif
52 
53 static void logtab_ent_list_free(struct logtab_ent_list *);
54 
55 /*
56  * Retrieves the next entry from nfslogtab.
57  * Assumes the file is locked.
58  * '*lepp' points to the new entry if successful.
59  * Returns:
60  *      > 0  valid entry
61  *      = 0  end of file
62  *      < 0  error
63  */
64 int
65 logtab_getent(FILE *fd, struct logtab_ent **lepp)
66 {
67 	char line[MAXBUFSIZE + 1];
68 	char *p;
69 	char *lasts, *tmp;
70 	char *w = " \t";
71 	struct logtab_ent *lep = NULL;
72 	int error = 0;
73 
74 	if ((lep = (struct logtab_ent *)malloc(sizeof (*lep))) == NULL) {
75 		return (-1);
76 	}
77 	(void) memset((char *)lep, 0, sizeof (*lep));
78 
79 	if ((p = fgets(line, MAXBUFSIZE, fd)) == NULL)  {
80 		error = 0;
81 		goto errout;
82 	}
83 
84 	line[strlen(line) - 1] = '\0';
85 
86 	tmp = (char *)strtok_r(p, w, &lasts);
87 	if (tmp == NULL) {
88 		error = -1;
89 		goto errout;
90 	}
91 	if ((lep->le_buffer = strdup(tmp)) == NULL) {
92 		error = -1;
93 		goto errout;
94 	}
95 
96 	tmp = (char *)strtok_r(NULL, w, &lasts);
97 	if (tmp == NULL) {
98 		error = -1;
99 		goto errout;
100 	}
101 	if ((lep->le_path = strdup(tmp)) == NULL) {
102 		error = -1;
103 		goto errout;
104 	}
105 
106 	tmp = (char *)strtok_r(NULL, w, &lasts);
107 	if (tmp == NULL) {
108 		error = -1;
109 		goto errout;
110 	}
111 	if ((lep->le_tag = strdup(tmp)) == NULL) {
112 		error = -1;
113 		goto errout;
114 	}
115 
116 	tmp = (char *)strtok_r(NULL, w, &lasts);
117 	if (tmp == NULL) {
118 		error = -1;
119 		goto errout;
120 	}
121 	lep->le_state = atoi(tmp);
122 
123 	*lepp = lep;
124 	return (1);
125 
126 errout:
127 	logtab_ent_free(lep);
128 
129 	return (error);
130 }
131 
132 /*
133  * Append an entry to the logtab file.
134  */
135 int
136 logtab_putent(FILE *fd, struct logtab_ent *lep)
137 {
138 	int r;
139 
140 	if (fseek(fd, 0L, SEEK_END) < 0)
141 		return (errno);
142 
143 	r = fprintf(fd, "%s\t%s\t%s\t%d\n",
144 		lep->le_buffer,
145 		lep->le_path,
146 		lep->le_tag,
147 		lep->le_state);
148 
149 	return (r);
150 }
151 
152 #ifndef	LINTHAPPY
153 /*
154  * Searches the nfslogtab file looking for the next entry which matches
155  * the search criteria. The search is continued at the current position
156  * in the nfslogtab file.
157  * If 'buffer' != NULL, then buffer is matched.
158  * If 'path' != NULL, then path is matched.
159  * If 'tag' != NULL, then tag is matched.
160  * If 'state' != -1, then state is matched.
161  * 'buffer', 'path' and 'tag' can all be non-NULL, which means the entry must
162  * satisfy all requirements.
163  *
164  * Returns 0 on success, ENOENT otherwise.
165  * If found, '*lepp' points to the matching entry, otherwise '*lepp' is
166  * undefined.
167  */
168 static int
169 logtab_findent(FILE *fd, char *buffer, char *path, char *tag, int state,
170 		struct logtab_ent **lepp)
171 {
172 	boolean_t found = B_FALSE;
173 
174 	while (!found && (logtab_getent(fd, lepp) > 0)) {
175 		found = B_TRUE;
176 		if (buffer != NULL)
177 			found = strcmp(buffer, (*lepp)->le_buffer) == 0;
178 		if (path != NULL)
179 			found = found && (strcmp(path, (*lepp)->le_path) == 0);
180 		if (tag != NULL)
181 			found = found && (strcmp(tag, (*lepp)->le_tag) == 0);
182 		if (state != -1)
183 			found = found && (state == (*lepp)->le_state);
184 		if (!found)
185 			logtab_ent_free(*lepp);
186 	}
187 
188 	return (found ? 0 : ENOENT);
189 }
190 #endif
191 
192 /*
193  * Remove all entries which match the search criteria.
194  * If 'buffer' != NULL, then buffer is matched.
195  * If 'path' != NULL, then path is matched.
196  * If 'tag' != NULL, then tag is matched.
197  * If 'state' != -1, then state is matched.
198  * 'buffer', 'path' and 'tag' can all be non-NULL, which means the entry must
199  * satisfy all requirements.
200  * The file is assumed to be locked.
201  * Read the entries into a linked list of logtab_ent structures
202  * minus the entries to be removed, then truncate the nfslogtab
203  * file and write it back to the file from the linked list.
204  *
205  * On success returns 0, -1 otherwise.
206  * Entry not found is treated as success since it was going to be removed
207  * anyway.
208  */
209 int
210 logtab_rement(FILE *fd, char *buffer, char *path, char *tag, int state)
211 {
212 	struct logtab_ent_list *head = NULL, *tail = NULL, *tmpl;
213 	struct logtab_ent *lep;
214 	int remcnt = 0;		/* remove count */
215 	int error = 0;
216 	boolean_t found;
217 
218 	rewind(fd);
219 	while ((error = logtab_getent(fd, &lep)) > 0) {
220 		found = B_TRUE;
221 		if (buffer != NULL)
222 			found = strcmp(buffer, lep->le_buffer) == 0;
223 		if (path != NULL)
224 			found = found && (strcmp(path, lep->le_path) == 0);
225 		if (tag != NULL)
226 			found = found && (strcmp(tag, lep->le_tag) == 0);
227 		if (state != -1)
228 			found = found && (state == lep->le_state);
229 		if (found) {
230 			remcnt++;
231 			logtab_ent_free(lep);
232 		} else {
233 			tmpl = (struct logtab_ent_list *)
234 				malloc(sizeof (struct logtab_ent));
235 			if (tmpl == NULL) {
236 				error = ENOENT;
237 				break;
238 			}
239 
240 			tmpl->lel_le = lep;
241 			tmpl->lel_next = NULL;
242 			if (head == NULL) {
243 				/*
244 				 * empty list
245 				 */
246 				head = tail = tmpl;
247 			} else {
248 				/*
249 				 * Add to the end of the list and remember
250 				 * the new last element.
251 				 */
252 				tail->lel_next = tmpl;
253 				tail = tmpl;	/* remember the last element */
254 			}
255 		}
256 	}
257 
258 	if (error)
259 		goto deallocate;
260 
261 	if (remcnt == 0) {
262 		/*
263 		 * Entry not found, nothing to do
264 		 */
265 		goto deallocate;
266 	}
267 
268 	if (ftruncate(fileno(fd), 0) < 0) {
269 		error = -1;
270 		goto deallocate;
271 	}
272 
273 	for (tmpl = head; tmpl != NULL; tmpl = tmpl->lel_next)
274 		(void) logtab_putent(fd, tmpl->lel_le);
275 
276 deallocate:
277 	logtab_ent_list_free(head);
278 
279 	return (error);
280 }
281 
282 /*
283  * Deactivate all entries matching search criteria.
284  * If 'buffer' != NULL then match buffer.
285  * If 'path' != NULL then match path.
286  * If 'tag' != NULL then match tag.
287  * Note that 'buffer', 'path' and 'tag' can al be non-null at the same time.
288  *
289  * Rewrites the nfslogtab file with the updated state for each entry.
290  * Assumes the nfslogtab file has been locked for writing.
291  * Returns 0 on success, -1 on failure.
292  */
293 int
294 logtab_deactivate(FILE *fd, char *buffer, char *path, char *tag)
295 {
296 	struct logtab_ent_list *lelp, *head = NULL, *tail = NULL;
297 	struct logtab_ent *lep;
298 	boolean_t found;
299 	int error = 0;
300 	int count = 0;
301 
302 	rewind(fd);
303 	while ((error = logtab_getent(fd, &lep)) > 0) {
304 		found = B_TRUE;
305 		if (buffer != NULL)
306 			found = strcmp(buffer, lep->le_buffer) == 0;
307 		if (path != NULL)
308 			found = found && (strcmp(path, lep->le_path) == 0);
309 		if (tag != NULL)
310 			found = found && (strcmp(tag, lep->le_tag) == 0);
311 		if (found && (lep->le_state == LES_ACTIVE)) {
312 			count++;
313 			lep->le_state = LES_INACTIVE;
314 		}
315 
316 		lelp = (struct logtab_ent_list *)
317 			malloc(sizeof (struct logtab_ent));
318 		if (lelp == NULL) {
319 			error = ENOENT;
320 			break;
321 		}
322 
323 		lelp->lel_le = lep;
324 		lelp->lel_next = NULL;
325 		if (head == NULL) {
326 			/*
327 			 * empty list
328 			 */
329 			head = tail = lelp;
330 		} else {
331 			/*
332 			 * Add to the end of the list and remember
333 			 * the new last element.
334 			 */
335 			tail->lel_next = lelp;
336 			tail = lelp;	/* remember the last element */
337 		}
338 	}
339 
340 	if (error)
341 		goto deallocate;
342 
343 	if (count == 0) {
344 		/*
345 		 * done
346 		 */
347 		error = 0;
348 		goto deallocate;
349 	}
350 
351 	if (ftruncate(fileno(fd), 0) < 0) {
352 		error = -1;
353 		goto deallocate;
354 	}
355 
356 	for (lelp = head; lelp != NULL; lelp = lelp->lel_next)
357 		(void) logtab_putent(fd, lelp->lel_le);
358 
359 deallocate:
360 	logtab_ent_list_free(head);
361 
362 	return (error);
363 }
364 
365 /*
366  * Deactivates all entries if nfslogtab exists and is older than boot time
367  * This will only happen the first time it is called.
368  * Assumes 'fd' has been locked by the caller.
369  * Returns 0 on success, otherwise -1.
370  */
371 int
372 logtab_deactivate_after_boot(FILE *fd)
373 {
374 	struct stat st;
375 	struct utmpx *utmpxp;
376 	int error = 0;
377 
378 	if ((fstat(fileno(fd), &st) == 0) &&
379 	    ((utmpxp = getutxent()) != NULL) &&
380 	    (utmpxp->ut_xtime > st.st_mtime)) {
381 		if (logtab_deactivate(fd, NULL, NULL, NULL))
382 			error = -1;
383 	}
384 
385 	return (error);
386 }
387 
388 void
389 logtab_ent_free(struct logtab_ent *lep)
390 {
391 	if (lep->le_buffer)
392 		free(lep->le_buffer);
393 	if (lep->le_path)
394 		free(lep->le_path);
395 	if (lep->le_tag)
396 		free(lep->le_tag);
397 	free(lep);
398 }
399 
400 static void
401 logtab_ent_list_free(struct logtab_ent_list *head)
402 {
403 	struct logtab_ent_list *lelp, *next;
404 
405 	if (head == NULL)
406 		return;
407 
408 	for (lelp = head; lelp != NULL; lelp = next) {
409 		if (lelp->lel_le != NULL)
410 			logtab_ent_free(lelp->lel_le);
411 		next = lelp->lel_next;
412 		free(lelp);
413 	}
414 }
415