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
logtab_getent(FILE * fd,struct logtab_ent ** lepp)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
logtab_putent(FILE * fd,struct logtab_ent * lep)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
logtab_findent(FILE * fd,char * buffer,char * path,char * tag,int state,struct logtab_ent ** lepp)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
logtab_rement(FILE * fd,char * buffer,char * path,char * tag,int state)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
logtab_deactivate(FILE * fd,char * buffer,char * path,char * tag)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
logtab_deactivate_after_boot(FILE * fd)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
logtab_ent_free(struct logtab_ent * lep)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
logtab_ent_list_free(struct logtab_ent_list * head)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