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 #include <sys/types.h> 28 #include <sys/stat.h> 29 #include <errno.h> 30 #include <syslog.h> 31 #include <libintl.h> 32 #include <unistd.h> 33 #include <strings.h> 34 #include <string.h> 35 #include <assert.h> 36 #include <stdlib.h> 37 #include "nfslogd.h" 38 #include "../lib/nfslogtab.h" 39 #include "buffer_list.h" 40 41 static int buildbuffer_list(struct buffer_ent **, timestruc_t *); 42 static void free_buffer_ent(struct buffer_ent *); 43 static struct buffer_ent *findbuffer(struct buffer_ent *, char *); 44 static void free_sharepnt_list(struct sharepnt_ent *); 45 static void free_sharepnt_ent(struct sharepnt_ent *); 46 #ifdef DEBUG 47 static void print_sharepnt_list(struct sharepnt_ent *); 48 #endif 49 static struct sharepnt_ent *findsharepnt(struct sharepnt_ent *, char *, 50 struct sharepnt_ent **); 51 52 /* 53 * Builds the buffer list from NFSLOGTAB and returns it in *listpp. 54 * Returns 0 on success, non-zero error code otherwise. 55 */ 56 int 57 getbuffer_list(struct buffer_ent **listpp, timestruc_t *lu) 58 { 59 *listpp = NULL; 60 return (buildbuffer_list(listpp, lu)); 61 } 62 63 /* 64 * If NFSLOGTAB has not been modified since the last time we read it, 65 * it simply returns the same buffer list, otherwise it re-reads NFSLOGTAB 66 * and rebuilds the list. 67 * No NFSLOGTAB is not treated as an error. 68 * Returns 0 on success, non-zero error code otherwise 69 */ 70 int 71 checkbuffer_list(struct buffer_ent **listpp, timestruc_t *lu) 72 { 73 struct stat st; 74 int error = 0; 75 76 if (stat(NFSLOGTAB, &st) == -1) { 77 error = errno; 78 if (error != ENOENT) { 79 syslog(LOG_ERR, gettext("Can't stat %s - %s"), 80 NFSLOGTAB, strerror(error)); 81 error = 0; 82 } 83 return (error); 84 } 85 86 if (lu->tv_sec == st.st_mtim.tv_sec && 87 lu->tv_nsec == st.st_mtim.tv_nsec) 88 return (0); 89 90 free_buffer_list(listpp); /* free existing list first */ 91 return (buildbuffer_list(listpp, lu)); 92 } 93 94 /* 95 * Does the actual work of reading NFSLOGTAB, and building the 96 * buffer list. If *be_head already contains entries, it will 97 * update the list with new information. 98 * Returns 0 on success, non-zero error code otherwise. 99 */ 100 static int 101 buildbuffer_list(struct buffer_ent **be_head, timestruc_t *lu) 102 { 103 FILE *fd; 104 struct buffer_ent *be_tail = NULL, *bep; 105 struct sharepnt_ent *se_tail = NULL, *sep; 106 struct logtab_ent *lep; 107 struct stat st; 108 int error = 0, res; 109 110 if ((fd = fopen(NFSLOGTAB, "r+")) == NULL) { 111 error = errno; 112 if (error != ENOENT) { 113 syslog(LOG_ERR, gettext("%s - %s\n"), NFSLOGTAB, 114 strerror(error)); 115 error = 0; 116 } 117 return (error); 118 } 119 120 if (lockf(fileno(fd), F_LOCK, 0L) < 0) { 121 error = errno; 122 syslog(LOG_ERR, gettext("cannot lock %s - %s\n"), NFSLOGTAB, 123 strerror(error)); 124 (void) fclose(fd); 125 return (error); 126 } 127 128 assert(*be_head == NULL); 129 while ((res = logtab_getent(fd, &lep)) > 0) { 130 if (bep = findbuffer(*be_head, lep->le_buffer)) { 131 /* 132 * Add sharepnt to buffer list 133 */ 134 if (sep = findsharepnt(bep->be_sharepnt, 135 lep->le_path, &se_tail)) { 136 /* 137 * Sharepoint already in list, 138 * update its state. 139 */ 140 sep->se_state = lep->le_state; 141 } else { 142 /* 143 * Need to add to sharepoint list 144 */ 145 sep = (struct sharepnt_ent *) 146 malloc(sizeof (*sep)); 147 if (sep == NULL) { 148 error = ENOMEM; 149 goto errout; 150 } 151 (void) memset(sep, 0, sizeof (*sep)); 152 153 sep->se_name = strdup(lep->le_path); 154 if (sep->se_name == NULL) { 155 error = ENOMEM; 156 goto errout; 157 } 158 sep->se_state = lep->le_state; 159 160 assert(se_tail != NULL); 161 assert(se_tail->se_next == NULL); 162 se_tail->se_next = sep; 163 } 164 } else { 165 /* 166 * Add new buffer to list 167 */ 168 bep = (struct buffer_ent *)malloc(sizeof (*bep)); 169 if (bep == NULL) { 170 error = ENOMEM; 171 goto errout; 172 } 173 (void) memset(bep, 0, sizeof (*bep)); 174 175 bep->be_name = strdup(lep->le_buffer); 176 if (bep->be_name == NULL) { 177 error = ENOMEM; 178 goto errout; 179 } 180 181 if (*be_head == NULL) 182 *be_head = bep; 183 else 184 be_tail->be_next = bep; 185 be_tail = bep; 186 187 bep->be_sharepnt = (struct sharepnt_ent *) 188 malloc(sizeof (*(bep->be_sharepnt))); 189 (void) memset(bep->be_sharepnt, 0, 190 sizeof (*(bep->be_sharepnt))); 191 192 if (bep->be_sharepnt == NULL) { 193 error = ENOMEM; 194 goto errout; 195 } 196 bep->be_sharepnt->se_name = strdup(lep->le_path); 197 if (bep->be_sharepnt->se_name == NULL) { 198 error = ENOMEM; 199 goto errout; 200 } 201 bep->be_sharepnt->se_state = lep->le_state; 202 } 203 } 204 205 if (res < 0) { 206 error = EIO; 207 goto errout; 208 } 209 210 /* 211 * Get modification time while we have the file locked. 212 */ 213 if (lu) { 214 if ((error = fstat(fileno(fd), &st)) == -1) { 215 syslog(LOG_ERR, gettext("Can't stat %s"), NFSLOGTAB); 216 goto errout; 217 } 218 *lu = st.st_mtim; 219 } 220 221 (void) fclose(fd); 222 return (error); 223 224 errout: 225 (void) fclose(fd); 226 if (lep) 227 logtab_ent_free(lep); 228 free_buffer_list(be_head); 229 assert(*be_head == NULL); 230 syslog(LOG_ERR, gettext("cannot read %s: %s\n"), NFSLOGTAB, 231 strerror(error)); 232 233 return (error); 234 } 235 236 /* 237 * Removes the entry from the buffer list and frees it. 238 */ 239 void 240 remove_buffer_ent(struct buffer_ent **be_listpp, struct buffer_ent *bep) 241 { 242 struct buffer_ent *p, *prev; 243 244 for (p = prev = *be_listpp; p != NULL; p = p->be_next) { 245 if (p == bep) { 246 if (p == *be_listpp) 247 *be_listpp = (*be_listpp)->be_next; 248 else 249 prev->be_next = bep->be_next; 250 free_buffer_ent(bep); 251 break; 252 } 253 prev = p; 254 } 255 } 256 257 /* 258 * Frees the buffer list. 259 */ 260 void 261 free_buffer_list(struct buffer_ent **be_listpp) 262 { 263 struct buffer_ent *bep, *nextp; 264 265 for (bep = *be_listpp; bep != NULL; bep = nextp) { 266 nextp = bep->be_next; 267 free_buffer_ent(bep); 268 } 269 *be_listpp = NULL; 270 } 271 272 static void 273 free_buffer_ent(struct buffer_ent *bep) 274 { 275 assert(bep != NULL); 276 if (debug) 277 (void) printf("freeing %s\n", bep->be_name); 278 if (bep->be_name != NULL) 279 free(bep->be_name); 280 if (bep->be_sharepnt != NULL) 281 free_sharepnt_list(bep->be_sharepnt); 282 free(bep); 283 } 284 285 static void 286 free_sharepnt_list(struct sharepnt_ent *sep_listp) 287 { 288 struct sharepnt_ent *nextp; 289 290 for (; sep_listp != NULL; sep_listp = nextp) { 291 nextp = sep_listp->se_next; 292 free_sharepnt_ent(sep_listp); 293 } 294 free(sep_listp); 295 } 296 297 /* 298 * Removes the entry from the sharepnt list and frees it. 299 */ 300 void 301 remove_sharepnt_ent(struct sharepnt_ent **se_listpp, struct sharepnt_ent *sep) 302 { 303 struct sharepnt_ent *p, *prev; 304 305 for (p = prev = *se_listpp; p != NULL; p = p->se_next) { 306 if (p == sep) { 307 if (p == *se_listpp) 308 *se_listpp = (*se_listpp)->se_next; 309 else 310 prev->se_next = sep->se_next; 311 free_sharepnt_ent(sep); 312 break; 313 } 314 prev = p; 315 } 316 } 317 318 static void 319 free_sharepnt_ent(struct sharepnt_ent *sep) 320 { 321 assert(sep != NULL); 322 if (debug) 323 (void) printf("freeing %s\n", sep->se_name); 324 if (sep->se_name != NULL) 325 free(sep->se_name); 326 free(sep); 327 } 328 329 #ifdef DEBUG 330 void 331 printbuffer_list(struct buffer_ent *bep) 332 { 333 for (; bep != NULL; bep = bep->be_next) { 334 (void) printf("%s\n", bep->be_name); 335 if (bep->be_sharepnt != NULL) 336 print_sharepnt_list(bep->be_sharepnt); 337 } 338 } 339 340 static void 341 print_sharepnt_list(struct sharepnt_ent *sep) 342 { 343 for (; sep != NULL; sep = sep->se_next) 344 (void) printf("\t(%d) %s\n", sep->se_state, sep->se_name); 345 } 346 #endif 347 348 /* 349 * Returns a pointer to the buffer matching 'name', NULL otherwise. 350 */ 351 static struct buffer_ent * 352 findbuffer(struct buffer_ent *bep, char *name) 353 { 354 for (; bep != NULL; bep = bep->be_next) { 355 if (strcmp(bep->be_name, name) == 0) 356 return (bep); 357 } 358 return (NULL); 359 } 360 361 /* 362 * Returns a pointer the sharepoint entry matching 'name'. 363 * Otherwise, it sets '*se_tail' to the last element of the list 364 * to make insertion of new element easier, and returns NULL. 365 */ 366 static struct sharepnt_ent * 367 findsharepnt( 368 struct sharepnt_ent *sep, 369 char *name, 370 struct sharepnt_ent **se_tail) 371 { 372 struct sharepnt_ent *tail; 373 374 for (; sep != NULL; sep = sep->se_next) { 375 if (strcmp(sep->se_name, name) == 0) 376 return (sep); 377 tail = sep; 378 } 379 *se_tail = tail; 380 return (NULL); 381 } 382