4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
22 * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
26 #pragma ident "%Z%%M% %I% %E% SMI"
33 #include <nfs/export.h>
34 #include <nfs/nfssys.h>
35 #include <nfs/nfs_log.h>
36 #include <sys/types.h>
43 #include <nfs/nfs_log.h>
44 #include "../lib/nfslog_config.h"
45 #include "buffer_list.h"
48 extern int _nfssys(int, void *);
51 * simple list used to keep track of bad tag messages syslogged.
55 struct nfs_log_list
*l_next
;
58 static void badtag_notify(char *tag
);
59 static struct nfs_log_list
*badtag_list
= NULL
;
61 static void cleanup_elf_state(nfsl_config_t
*);
62 static void cleanup_trans_state(nfsl_config_t
*);
65 * Read the contents of the 'bufferpath', process them and store the
66 * user-readable log in 'elfpath', updating the 'fhpath' filehandle
68 * The contents of the configuration list (*config_list) may be
69 * modified if the configuration file has been updated and we can not
70 * find the configuration entry in the currently loaded list.
72 * Returns 0 on success and sets *buffer_processed to 1.
73 * non zero error on failure and *buffer_processed set to 0.
77 struct buffer_ent
*bep
,
78 nfsl_config_t
**config_list
,
81 int *buffer_processed
)
84 struct nfsl_flush_args nfa
;
85 struct nfslog_buf
*lbp
= NULL
;
86 struct nfslog_lr
*lrp
;
89 char *buffer_inprog
= NULL
;
90 int buffer_inprog_len
;
92 nfsl_config_t
*ncp
= NULL
, *last_good_ncp
;
93 char *bufferpath
= bep
->be_name
;
95 boolean_t elf_checked
= B_FALSE
;
96 boolean_t trans_checked
= B_FALSE
;
98 assert(buffer_processed
!= NULL
);
99 assert(bufferpath
!= NULL
);
101 if (stat(bufferpath
, &st
) == -1) {
103 if (error
== ENOENT
) {
105 buffer_inprog_len
= strlen(bufferpath
) +
106 strlen(LOG_INPROG_STRING
) + 1;
107 buffer_inprog
= (char *)malloc(buffer_inprog_len
);
108 if (buffer_inprog
== NULL
) {
109 syslog(LOG_ERR
, gettext(
110 "process_buffer: malloc failed"));
113 (void) sprintf(buffer_inprog
, "%s%s", bufferpath
,
116 if (stat(buffer_inprog
, &st
) == -1) {
118 if (bep
->be_error
!= error
) {
119 syslog(LOG_ERR
, gettext(
120 "Can not stat %s: %s"),
121 buffer_inprog
, strerror(error
));
130 * Does the buffer in progress meet our minimum
131 * processing requirements? or has it been around
132 * longer than we're willing to wait for more
135 if ((st
.st_size
< min_size
) &&
136 ((time(0) - bep
->be_lastprocessed
) < idle_time
)) {
138 * The buffer does not meet the minimum
139 * size processing requirements, and it has not
140 * been around longer than we're willing to
141 * wait for more data collection.
142 * We return now without processing it.
148 * Issue the LOG_FLUSH system call to flush the
149 * buffer and process it.
151 (void) memset((void *)&nfa
, 0, sizeof (nfa
));
152 nfa
.version
= NFSL_FLUSH_ARGS_VERS
;
153 nfa
.directive
= NFSL_RENAME
| NFSL_SYNC
;
154 nfa
.buff
= bufferpath
;
155 nfa
.buff_len
= strlen(bufferpath
) + 1;
157 if (_nfssys(LOG_FLUSH
, &nfa
) < 0) {
159 if (bep
->be_error
!= error
) {
160 syslog(LOG_ERR
, gettext(
161 "_nfssys(%s) failed: %s"),
162 nfa
.buff
, strerror(error
));
167 if (bep
->be_error
!= error
) {
168 syslog(LOG_ERR
, gettext("Can not stat %s: %s"),
169 bufferpath
, strerror(error
));
176 * Open and lock input buffer.
177 * Passes in the value of the last error so that it will not
178 * print it again if it is still hitting the same error condition.
180 error
= bep
->be_error
;
181 if ((lbp
= nfslog_open_buf(bufferpath
, &error
)) == NULL
)
184 if ((ncp
= last_good_ncp
=
185 nfsl_findconfig(*config_list
, "global", &error
)) == NULL
) {
187 nfsl_freeconfig_list(config_list
);
188 if (error
!= bep
->be_error
) {
189 syslog(LOG_ERR
, gettext(
190 "Could not search config list: %s"),
197 while ((lrp
= nfslog_get_logrecord(lbp
)) != NULL
&& keep_running
) {
199 if (*buffer_processed
== 0)
200 (*buffer_processed
)++;
203 * Get the matching config entry.
205 tag
= lrp
->log_record
.re_tag
;
206 if (strcmp(tag
, last_good_ncp
->nc_name
) != 0) {
207 ncp
= nfsl_findconfig(*config_list
, tag
, &error
);
209 if (error
!= bep
->be_error
) {
210 syslog(LOG_ERR
, gettext(
211 "Could not search config list: %s"),
214 nfsl_freeconfig_list(config_list
);
225 if (ncp
->nc_flags
& NC_UPDATED
) {
227 * The location of the log files may have changed,
228 * we need to close transactions and invalidate
229 * cookies so that the log files can be reopened
232 cleanup_elf_state(ncp
);
233 cleanup_trans_state(ncp
);
235 ncp
->nc_flags
&= ~NC_UPDATED
;
238 * Force cookies to be recreated if necessary.
240 elf_checked
= trans_checked
= B_FALSE
;
246 if (ncp
->nc_rpclogpath
!= NULL
) {
248 * Log rpc requests in W3C-ELF format.
250 if (!elf_checked
&& ncp
->nc_elfcookie
!= NULL
) {
252 * Make sure file still exists.
253 * Do this once per buffer.
255 if (stat(ncp
->nc_rpclogpath
, &st
) == -1 &&
258 * The open rpclogfile has been
259 * deleted. Get new one below.
261 cleanup_elf_state(ncp
);
263 elf_checked
= B_TRUE
;
265 if (ncp
->nc_elfcookie
== NULL
) {
266 error
= bep
->be_error
;
267 ncp
->nc_elfcookie
= nfslog_open_elf_file(
268 ncp
->nc_rpclogpath
, &lbp
->bh
, &error
);
269 if (ncp
->nc_elfcookie
== NULL
) {
270 bep
->be_error
= error
;
276 if (ncp
->nc_logpath
!= NULL
) {
278 * Log rpc reqs in trans/ftp format.
280 if (!trans_checked
&& ncp
->nc_transcookie
!= NULL
) {
282 * Do this once per buffer.
284 if (stat(ncp
->nc_logpath
, &st
) == -1 &&
287 * The open transaction file has been
288 * deleted. Close pending transaction
289 * work. A new transaction log will be
290 * opened by nfslog_open_trans_file()
293 cleanup_trans_state(ncp
);
295 trans_checked
= B_TRUE
;
297 if (ncp
->nc_transcookie
== NULL
) {
301 (ncp
->nc_logformat
== TRANSLOG_BASIC
) ?
302 TRANSTOLOG_OPER_READWRITE
: TRANSTOLOG_ALL
;
303 error
= bep
->be_error
;
304 ncp
->nc_transcookie
= nfslog_open_trans_file(
305 ncp
->nc_logpath
, ncp
->nc_logformat
,
307 if (ncp
->nc_transcookie
== NULL
) {
308 bep
->be_error
= error
;
314 assert(ncp
->nc_fhpath
!= NULL
);
316 if (nfslog_process_fh_rec(lrp
, ncp
->nc_fhpath
, &path1
, &path2
,
317 ncp
->nc_elfcookie
!= NULL
)) {
319 * Make sure there is room.
321 if (ncp
->nc_elfcookie
!= NULL
) {
322 (void) nfslog_process_elf_rec(ncp
->nc_elfcookie
,
323 &lrp
->log_record
, path1
, path2
);
326 if (ncp
->nc_transcookie
!= NULL
) {
327 (void) nfslog_process_trans_rec(
329 &lrp
->log_record
, ncp
->nc_fhpath
,
334 skip
: if (path1
!= NULL
)
339 path1
= path2
= NULL
;
340 nfslog_free_logrecord(lrp
, TRUE
);
343 if (!error
&& keep_running
) {
345 * Keep track of when this buffer was last processed.
347 bep
->be_lastprocessed
= time(0);
349 if (test
&& *buffer_processed
!= 0) {
351 * Save the buffer for future debugging. We do this
352 * by following the log cycling policy, with a maximum
353 * of 'max_logs_preserve' to save.
355 if (cycle_log(bufferpath
, max_logs_preserve
)) {
356 syslog(LOG_ERR
, gettext(
357 "could not save copy of buffer \"%s\""),
362 * Remove buffer since it has been processed.
364 if (unlink(bufferpath
)) {
366 syslog(LOG_ERR
, gettext(
367 "could not unlink %s: %s"),
368 bufferpath
, strerror(error
));
370 * Buffer was processed correctly.
379 nfslog_close_buf(lbp
, quick_cleaning
);
380 if (ncp
&& !quick_cleaning
)
381 cleanup_elf_state(ncp
);
387 cleanup_elf_state(nfsl_config_t
*ncp
)
389 if (ncp
->nc_elfcookie
!= NULL
) {
390 nfslog_close_elf_file(&ncp
->nc_elfcookie
);
391 assert(ncp
->nc_elfcookie
== NULL
);
396 cleanup_trans_state(nfsl_config_t
*ncp
)
398 if (ncp
->nc_transcookie
!= NULL
) {
399 nfslog_close_transactions(&ncp
->nc_transcookie
);
400 assert(ncp
->nc_transcookie
== NULL
);
405 * Searches the list of previously seen bad tags. Note that this
406 * list is never pruned. This should not be a problem since the
407 * list of bad tags should be fairl small. New entries are inserted
408 * at the beginning of the list assuming it will be accessed more
409 * frequently since we have just seen it.
412 badtag_notify(char *tag
)
414 struct nfs_log_list
*lp
, *p
;
417 for (p
= badtag_list
; p
!= NULL
; p
= p
->l_next
) {
418 if (strcmp(tag
, p
->l_name
) == 0) {
420 * We've seen this before, nothing to do.
427 * Not on the list, add it.
429 syslog(LOG_ERR
, gettext("tag \"%s\" not found in %s - "
430 "ignoring records referencing such tag."),
431 tag
, NFSL_CONFIG_FILE_PATH
);
433 if ((lp
= (struct nfs_log_list
*)malloc(sizeof (*lp
))) != NULL
) {
434 if ((lp
->l_name
= strdup(tag
)) != NULL
) {
435 lp
->l_next
= badtag_list
;
441 if (lp
->l_name
!= NULL
)
446 syslog(LOG_ERR
, gettext(
447 "Cannot add \"%s\" to bad tag list: %s"), tag
, strerror(error
));