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