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