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