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 #include <strings.h> 30 #include <string.h> 31 #include <syslog.h> 32 #include <locale.h> 33 #include <nfs/nfs.h> 34 #include <nfs/export.h> 35 #include <nfs/nfssys.h> 36 #include <nfs/nfs_log.h> 37 #include <sys/types.h> 38 #include <sys/stat.h> 39 #include <stdio.h> 40 #include <errno.h> 41 #include <assert.h> 42 #include <stdlib.h> 43 #include <unistd.h> 44 #include <nfs/nfs_log.h> 45 #include "../lib/nfslog_config.h" 46 #include "buffer_list.h" 47 #include "nfslogd.h" 48 49 extern int _nfssys(int, void *); 50 51 /* 52 * simple list used to keep track of bad tag messages syslogged. 53 */ 54 struct list { 55 char *l_name; 56 struct list *l_next; 57 }; 58 59 static void badtag_notify(char *tag); 60 static struct list *badtag_list = NULL; 61 62 static void cleanup_elf_state(nfsl_config_t *); 63 static void cleanup_trans_state(nfsl_config_t *); 64 65 /* 66 * Read the contents of the 'bufferpath', process them and store the 67 * user-readable log in 'elfpath', updating the 'fhpath' filehandle 68 * table. 69 * The contents of the configuration list (*config_list) may be 70 * modified if the configuration file has been updated and we can not 71 * find the configuration entry in the currently loaded list. 72 * 73 * Returns 0 on success and sets *buffer_processed to 1. 74 * non zero error on failure and *buffer_processed set to 0. 75 */ 76 int 77 process_buffer( 78 struct buffer_ent *bep, 79 nfsl_config_t **config_list, 80 int min_size, 81 int idle_time, 82 int *buffer_processed) 83 { 84 struct stat st; 85 struct nfsl_flush_args nfa; 86 struct nfslog_buf *lbp = NULL; 87 struct nfslog_lr *lrp; 88 char *path1 = NULL; 89 char *path2 = NULL; 90 char *buffer_inprog = NULL; 91 int buffer_inprog_len; 92 int error = 0; 93 nfsl_config_t *ncp = NULL, *last_good_ncp; 94 char *bufferpath = bep->be_name; 95 char *tag; 96 boolean_t elf_checked = B_FALSE; 97 boolean_t trans_checked = B_FALSE; 98 99 assert(buffer_processed != NULL); 100 assert(bufferpath != NULL); 101 102 if (stat(bufferpath, &st) == -1) { 103 error = errno; 104 if (error == ENOENT) { 105 error = 0; 106 buffer_inprog_len = strlen(bufferpath) + 107 strlen(LOG_INPROG_STRING) + 1; 108 buffer_inprog = (char *)malloc(buffer_inprog_len); 109 if (buffer_inprog == NULL) { 110 syslog(LOG_ERR, gettext( 111 "process_buffer: malloc failed")); 112 return (ENOMEM); 113 } 114 (void) sprintf(buffer_inprog, "%s%s", bufferpath, 115 LOG_INPROG_STRING); 116 117 if (stat(buffer_inprog, &st) == -1) { 118 error = errno; 119 if (bep->be_error != error) { 120 syslog(LOG_ERR, gettext( 121 "Can not stat %s: %s"), 122 buffer_inprog, strerror(error)); 123 } 124 free(buffer_inprog); 125 return (error); 126 } 127 128 free(buffer_inprog); 129 130 /* 131 * Does the buffer in progress meet our minimum 132 * processing requirements? or has it been around 133 * longer than we're willing to wait for more 134 * data to be logged? 135 */ 136 if ((st.st_size < min_size) && 137 ((time(0) - bep->be_lastprocessed) < idle_time)) { 138 /* 139 * The buffer does not meet the minimum 140 * size processing requirements, and it has not 141 * been around longer than we're willing to 142 * wait for more data collection. 143 * We return now without processing it. 144 */ 145 return (0); 146 } 147 148 /* 149 * Issue the LOG_FLUSH system call to flush the 150 * buffer and process it. 151 */ 152 (void) memset((void *)&nfa, 0, sizeof (nfa)); 153 nfa.version = NFSL_FLUSH_ARGS_VERS; 154 nfa.directive = NFSL_RENAME | NFSL_SYNC; 155 nfa.buff = bufferpath; 156 nfa.buff_len = strlen(bufferpath) + 1; 157 158 if (_nfssys(LOG_FLUSH, &nfa) < 0) { 159 error = errno; 160 if (bep->be_error != error) { 161 syslog(LOG_ERR, gettext( 162 "_nfssys(%s) failed: %s"), 163 nfa.buff, strerror(error)); 164 } 165 return (error); 166 } 167 } else { 168 if (bep->be_error != error) { 169 syslog(LOG_ERR, gettext("Can not stat %s: %s"), 170 bufferpath, strerror(error)); 171 } 172 return (error); 173 } 174 } 175 176 /* 177 * Open and lock input buffer. 178 * Passes in the value of the last error so that it will not 179 * print it again if it is still hitting the same error condition. 180 */ 181 error = bep->be_error; 182 if ((lbp = nfslog_open_buf(bufferpath, &error)) == NULL) 183 goto done; 184 185 if ((ncp = last_good_ncp = 186 nfsl_findconfig(*config_list, "global", &error)) == NULL) { 187 assert(error != 0); 188 nfsl_freeconfig_list(config_list); 189 if (error != bep->be_error) { 190 syslog(LOG_ERR, gettext( 191 "Could not search config list: %s"), 192 strerror(error)); 193 } 194 goto done; 195 } 196 197 assert(error == 0); 198 while ((lrp = nfslog_get_logrecord(lbp)) != NULL && keep_running) { 199 200 if (*buffer_processed == 0) 201 (*buffer_processed)++; 202 203 /* 204 * Get the matching config entry. 205 */ 206 tag = lrp->log_record.re_tag; 207 if (strcmp(tag, last_good_ncp->nc_name) != 0) { 208 ncp = nfsl_findconfig(*config_list, tag, &error); 209 if (error) { 210 if (error != bep->be_error) { 211 syslog(LOG_ERR, gettext( 212 "Could not search config list: %s"), 213 strerror(error)); 214 } 215 nfsl_freeconfig_list(config_list); 216 goto done; 217 } 218 if (ncp == NULL) { 219 badtag_notify(tag); 220 ncp = last_good_ncp; 221 goto skip; 222 } 223 last_good_ncp = ncp; 224 } 225 226 if (ncp->nc_flags & NC_UPDATED) { 227 /* 228 * The location of the log files may have changed, 229 * we need to close transactions and invalidate 230 * cookies so that the log files can be reopened 231 * further down. 232 */ 233 cleanup_elf_state(ncp); 234 cleanup_trans_state(ncp); 235 236 ncp->nc_flags &= ~NC_UPDATED; 237 238 /* 239 * Force cookies to be recreated if necessary. 240 */ 241 elf_checked = trans_checked = B_FALSE; 242 } 243 244 /* 245 * Open output files. 246 */ 247 if (ncp->nc_rpclogpath != NULL) { 248 /* 249 * Log rpc requests in W3C-ELF format. 250 */ 251 if (!elf_checked && ncp->nc_elfcookie != NULL) { 252 /* 253 * Make sure file still exists. 254 * Do this once per buffer. 255 */ 256 if (stat(ncp->nc_rpclogpath, &st) == -1 && 257 errno == ENOENT) { 258 /* 259 * The open rpclogfile has been 260 * deleted. Get new one below. 261 */ 262 cleanup_elf_state(ncp); 263 } 264 elf_checked = B_TRUE; 265 } 266 if (ncp->nc_elfcookie == NULL) { 267 error = bep->be_error; 268 ncp->nc_elfcookie = nfslog_open_elf_file( 269 ncp->nc_rpclogpath, 270 &lbp->bh, &error); 271 if (ncp->nc_elfcookie == NULL) { 272 bep->be_error = error; 273 goto done; 274 } 275 } 276 } 277 278 if (ncp->nc_logpath != NULL) { 279 /* 280 * Log rpc reqs in trans/ftp format. 281 */ 282 if (!trans_checked && ncp->nc_transcookie != NULL) { 283 /* 284 * Do this once per buffer. 285 */ 286 if (stat(ncp->nc_logpath, &st) == -1 && 287 errno == ENOENT) { 288 /* 289 * The open transaction file has been 290 * deleted. Close pending transaction 291 * work. A new transaction log will be 292 * opened by nfslog_open_trans_file() 293 * below. 294 */ 295 cleanup_trans_state(ncp); 296 } 297 trans_checked = B_TRUE; 298 } 299 if (ncp->nc_transcookie == NULL) { 300 int transtolog; 301 302 transtolog = 303 (ncp->nc_logformat == TRANSLOG_BASIC) ? 304 TRANSTOLOG_OPER_READWRITE : 305 TRANSTOLOG_ALL; 306 error = bep->be_error; 307 ncp->nc_transcookie = nfslog_open_trans_file( 308 ncp->nc_logpath, 309 ncp->nc_logformat, 310 transtolog, &error); 311 if (ncp->nc_transcookie == NULL) { 312 bep->be_error = error; 313 goto done; 314 } 315 } 316 } 317 318 assert(ncp->nc_fhpath != NULL); 319 320 if (nfslog_process_fh_rec(lrp, ncp->nc_fhpath, &path1, &path2, 321 ncp->nc_elfcookie != NULL)) { 322 /* 323 * Make sure there is room. 324 */ 325 if (ncp->nc_elfcookie != NULL) { 326 (void) nfslog_process_elf_rec(ncp->nc_elfcookie, 327 &lrp->log_record, path1, path2); 328 } 329 330 if (ncp->nc_transcookie != NULL) { 331 (void) nfslog_process_trans_rec( 332 ncp->nc_transcookie, 333 &lrp->log_record, ncp->nc_fhpath, 334 path1, path2); 335 } 336 } 337 338 skip: if (path1 != NULL) 339 free(path1); 340 if (path2 != NULL) 341 free(path2); 342 343 path1 = path2 = NULL; 344 nfslog_free_logrecord(lrp, TRUE); 345 } /* while */ 346 347 if (!error && keep_running) { 348 /* 349 * Keep track of when this buffer was last processed. 350 */ 351 bep->be_lastprocessed = time(0); 352 353 if (test && *buffer_processed != 0) { 354 /* 355 * Save the buffer for future debugging. We do this 356 * by following the log cycling policy, with a maximum 357 * of 'max_logs_preserve' to save. 358 */ 359 if (cycle_log(bufferpath, max_logs_preserve)) { 360 syslog(LOG_ERR, gettext( 361 "could not save copy of buffer \"%s\""), 362 bufferpath); 363 } 364 } else { 365 /* 366 * Remove buffer since it has been processed. 367 */ 368 if (unlink(bufferpath)) { 369 error = errno; 370 syslog(LOG_ERR, gettext( 371 "could not unlink %s: %s"), 372 bufferpath, strerror(error)); 373 /* 374 * Buffer was processed correctly. 375 */ 376 error = 0; 377 } 378 } 379 } 380 381 done: 382 if (lbp != NULL) 383 nfslog_close_buf(lbp, quick_cleaning); 384 if (ncp && !quick_cleaning) 385 cleanup_elf_state(ncp); 386 387 return (error); 388 } 389 390 static void 391 cleanup_elf_state(nfsl_config_t *ncp) 392 { 393 if (ncp->nc_elfcookie != NULL) { 394 nfslog_close_elf_file(&ncp->nc_elfcookie); 395 assert(ncp->nc_elfcookie == NULL); 396 } 397 } 398 399 static void 400 cleanup_trans_state(nfsl_config_t *ncp) 401 { 402 if (ncp->nc_transcookie != NULL) { 403 nfslog_close_transactions(&ncp->nc_transcookie); 404 assert(ncp->nc_transcookie == NULL); 405 } 406 } 407 408 /* 409 * Searches the list of previously seen bad tags. Note that this 410 * list is never pruned. This should not be a problem since the 411 * list of bad tags should be fairl small. New entries are inserted 412 * at the beginning of the list assuming it will be accessed more 413 * frequently since we have just seen it. 414 */ 415 static void 416 badtag_notify(char *tag) 417 { 418 struct list *lp, *p; 419 int error; 420 421 for (p = badtag_list; p != NULL; p = p->l_next) { 422 if (strcmp(tag, p->l_name) == 0) { 423 /* 424 * We've seen this before, nothing to do. 425 */ 426 return; 427 } 428 } 429 430 /* 431 * Not on the list, add it. 432 */ 433 syslog(LOG_ERR, gettext( 434 "tag \"%s\" not found in %s - " 435 "ignoring records referencing such tag."), 436 tag, NFSL_CONFIG_FILE_PATH); 437 438 if ((lp = (struct list *)malloc(sizeof (*lp))) != NULL) { 439 if ((lp->l_name = strdup(tag)) != NULL) { 440 lp->l_next = badtag_list; 441 badtag_list = lp; 442 return; /* done */ 443 } 444 } 445 446 if (lp->l_name != NULL) 447 free(lp->l_name); 448 if (lp) 449 free(lp); 450 error = errno; 451 syslog(LOG_ERR, gettext( 452 "Cannot add \"%s\" to bad tag list: %s"), tag, strerror(error)); 453 } 454