dmake: do not set MAKEFLAGS=k
[unleashed/tickless.git] / usr / src / cmd / fs.d / nfs / nfslog / process_buffer.c
blob257b499bb59042248c6dd7ec46ac7f3cf29c7738
1 /*
2 * CDDL HEADER START
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]
19 * CDDL HEADER END
22 * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
26 #include <strings.h>
27 #include <string.h>
28 #include <syslog.h>
29 #include <locale.h>
30 #include <nfs/nfs.h>
31 #include <nfs/export.h>
32 #include <nfs/nfssys.h>
33 #include <nfs/nfs_log.h>
34 #include <sys/types.h>
35 #include <sys/stat.h>
36 #include <stdio.h>
37 #include <errno.h>
38 #include <assert.h>
39 #include <stdlib.h>
40 #include <unistd.h>
41 #include <nfs/nfs_log.h>
42 #include "../lib/nfslog_config.h"
43 #include "buffer_list.h"
44 #include "nfslogd.h"
46 extern int _nfssys(int, void *);
49 * simple list used to keep track of bad tag messages syslogged.
51 struct nfs_log_list {
52 char *l_name;
53 struct nfs_log_list *l_next;
56 static void badtag_notify(char *tag);
57 static struct nfs_log_list *badtag_list = NULL;
59 static void cleanup_elf_state(nfsl_config_t *);
60 static void cleanup_trans_state(nfsl_config_t *);
63 * Read the contents of the 'bufferpath', process them and store the
64 * user-readable log in 'elfpath', updating the 'fhpath' filehandle
65 * table.
66 * The contents of the configuration list (*config_list) may be
67 * modified if the configuration file has been updated and we can not
68 * find the configuration entry in the currently loaded list.
70 * Returns 0 on success and sets *buffer_processed to 1.
71 * non zero error on failure and *buffer_processed set to 0.
73 int
74 process_buffer(
75 struct buffer_ent *bep,
76 nfsl_config_t **config_list,
77 int min_size,
78 int idle_time,
79 int *buffer_processed)
81 struct stat st;
82 struct nfsl_flush_args nfa;
83 struct nfslog_buf *lbp = NULL;
84 struct nfslog_lr *lrp;
85 char *path1 = NULL;
86 char *path2 = NULL;
87 char *buffer_inprog = NULL;
88 int buffer_inprog_len;
89 int error = 0;
90 nfsl_config_t *ncp = NULL, *last_good_ncp;
91 char *bufferpath = bep->be_name;
92 char *tag;
93 boolean_t elf_checked = B_FALSE;
94 boolean_t trans_checked = B_FALSE;
96 assert(buffer_processed != NULL);
97 assert(bufferpath != NULL);
99 if (stat(bufferpath, &st) == -1) {
100 error = errno;
101 if (error == ENOENT) {
102 error = 0;
103 buffer_inprog_len = strlen(bufferpath) +
104 strlen(LOG_INPROG_STRING) + 1;
105 buffer_inprog = (char *)malloc(buffer_inprog_len);
106 if (buffer_inprog == NULL) {
107 syslog(LOG_ERR, gettext(
108 "process_buffer: malloc failed"));
109 return (ENOMEM);
111 (void) sprintf(buffer_inprog, "%s%s", bufferpath,
112 LOG_INPROG_STRING);
114 if (stat(buffer_inprog, &st) == -1) {
115 error = errno;
116 if (bep->be_error != error) {
117 syslog(LOG_ERR, gettext(
118 "Can not stat %s: %s"),
119 buffer_inprog, strerror(error));
121 free(buffer_inprog);
122 return (error);
125 free(buffer_inprog);
128 * Does the buffer in progress meet our minimum
129 * processing requirements? or has it been around
130 * longer than we're willing to wait for more
131 * data to be logged?
133 if ((st.st_size < min_size) &&
134 ((time(0) - bep->be_lastprocessed) < idle_time)) {
136 * The buffer does not meet the minimum
137 * size processing requirements, and it has not
138 * been around longer than we're willing to
139 * wait for more data collection.
140 * We return now without processing it.
142 return (0);
146 * Issue the LOG_FLUSH system call to flush the
147 * buffer and process it.
149 (void) memset(&nfa, 0, sizeof (nfa));
150 nfa.version = NFSL_FLUSH_ARGS_VERS;
151 nfa.directive = NFSL_RENAME | NFSL_SYNC;
152 nfa.buff = bufferpath;
153 nfa.buff_len = strlen(bufferpath) + 1;
155 if (_nfssys(LOG_FLUSH, &nfa) < 0) {
156 error = errno;
157 if (bep->be_error != error) {
158 syslog(LOG_ERR, gettext(
159 "_nfssys(%s) failed: %s"),
160 nfa.buff, strerror(error));
162 return (error);
164 } else {
165 if (bep->be_error != error) {
166 syslog(LOG_ERR, gettext("Can not stat %s: %s"),
167 bufferpath, strerror(error));
169 return (error);
174 * Open and lock input buffer.
175 * Passes in the value of the last error so that it will not
176 * print it again if it is still hitting the same error condition.
178 error = bep->be_error;
179 if ((lbp = nfslog_open_buf(bufferpath, &error)) == NULL)
180 goto done;
182 if ((ncp = last_good_ncp =
183 nfsl_findconfig(*config_list, "global", &error)) == NULL) {
184 assert(error != 0);
185 nfsl_freeconfig_list(config_list);
186 if (error != bep->be_error) {
187 syslog(LOG_ERR, gettext(
188 "Could not search config list: %s"),
189 strerror(error));
191 goto done;
194 assert(error == 0);
195 while ((lrp = nfslog_get_logrecord(lbp)) != NULL && keep_running) {
197 if (*buffer_processed == 0)
198 (*buffer_processed)++;
201 * Get the matching config entry.
203 tag = lrp->log_record.re_tag;
204 if (strcmp(tag, last_good_ncp->nc_name) != 0) {
205 ncp = nfsl_findconfig(*config_list, tag, &error);
206 if (error) {
207 if (error != bep->be_error) {
208 syslog(LOG_ERR, gettext(
209 "Could not search config list: %s"),
210 strerror(error));
212 nfsl_freeconfig_list(config_list);
213 goto done;
215 if (ncp == NULL) {
216 badtag_notify(tag);
217 ncp = last_good_ncp;
218 goto skip;
220 last_good_ncp = ncp;
223 if (ncp->nc_flags & NC_UPDATED) {
225 * The location of the log files may have changed,
226 * we need to close transactions and invalidate
227 * cookies so that the log files can be reopened
228 * further down.
230 cleanup_elf_state(ncp);
231 cleanup_trans_state(ncp);
233 ncp->nc_flags &= ~NC_UPDATED;
236 * Force cookies to be recreated if necessary.
238 elf_checked = trans_checked = B_FALSE;
242 * Open output files.
244 if (ncp->nc_rpclogpath != NULL) {
246 * Log rpc requests in W3C-ELF format.
248 if (!elf_checked && ncp->nc_elfcookie != NULL) {
250 * Make sure file still exists.
251 * Do this once per buffer.
253 if (stat(ncp->nc_rpclogpath, &st) == -1 &&
254 errno == ENOENT) {
256 * The open rpclogfile has been
257 * deleted. Get new one below.
259 cleanup_elf_state(ncp);
261 elf_checked = B_TRUE;
263 if (ncp->nc_elfcookie == NULL) {
264 error = bep->be_error;
265 ncp->nc_elfcookie = nfslog_open_elf_file(
266 ncp->nc_rpclogpath, &lbp->bh, &error);
267 if (ncp->nc_elfcookie == NULL) {
268 bep->be_error = error;
269 goto done;
274 if (ncp->nc_logpath != NULL) {
276 * Log rpc reqs in trans/ftp format.
278 if (!trans_checked && ncp->nc_transcookie != NULL) {
280 * Do this once per buffer.
282 if (stat(ncp->nc_logpath, &st) == -1 &&
283 errno == ENOENT) {
285 * The open transaction file has been
286 * deleted. Close pending transaction
287 * work. A new transaction log will be
288 * opened by nfslog_open_trans_file()
289 * below.
291 cleanup_trans_state(ncp);
293 trans_checked = B_TRUE;
295 if (ncp->nc_transcookie == NULL) {
296 int transtolog;
298 transtolog =
299 (ncp->nc_logformat == TRANSLOG_BASIC) ?
300 TRANSTOLOG_OPER_READWRITE : TRANSTOLOG_ALL;
301 error = bep->be_error;
302 ncp->nc_transcookie = nfslog_open_trans_file(
303 ncp->nc_logpath, ncp->nc_logformat,
304 transtolog, &error);
305 if (ncp->nc_transcookie == NULL) {
306 bep->be_error = error;
307 goto done;
312 assert(ncp->nc_fhpath != NULL);
314 if (nfslog_process_fh_rec(lrp, ncp->nc_fhpath, &path1, &path2,
315 ncp->nc_elfcookie != NULL)) {
317 * Make sure there is room.
319 if (ncp->nc_elfcookie != NULL) {
320 (void) nfslog_process_elf_rec(ncp->nc_elfcookie,
321 &lrp->log_record, path1, path2);
324 if (ncp->nc_transcookie != NULL) {
325 (void) nfslog_process_trans_rec(
326 ncp->nc_transcookie,
327 &lrp->log_record, ncp->nc_fhpath,
328 path1, path2);
332 skip: free(path1);
333 free(path2);
335 path1 = path2 = NULL;
336 nfslog_free_logrecord(lrp, TRUE);
337 } /* while */
339 if (!error && keep_running) {
341 * Keep track of when this buffer was last processed.
343 bep->be_lastprocessed = time(0);
345 if (test && *buffer_processed != 0) {
347 * Save the buffer for future debugging. We do this
348 * by following the log cycling policy, with a maximum
349 * of 'max_logs_preserve' to save.
351 if (cycle_log(bufferpath, max_logs_preserve)) {
352 syslog(LOG_ERR, gettext(
353 "could not save copy of buffer \"%s\""),
354 bufferpath);
356 } else {
358 * Remove buffer since it has been processed.
360 if (unlink(bufferpath)) {
361 error = errno;
362 syslog(LOG_ERR, gettext(
363 "could not unlink %s: %s"),
364 bufferpath, strerror(error));
366 * Buffer was processed correctly.
368 error = 0;
373 done:
374 if (lbp != NULL)
375 nfslog_close_buf(lbp, quick_cleaning);
376 if (ncp && !quick_cleaning)
377 cleanup_elf_state(ncp);
379 return (error);
382 static void
383 cleanup_elf_state(nfsl_config_t *ncp)
385 if (ncp->nc_elfcookie != NULL) {
386 nfslog_close_elf_file(&ncp->nc_elfcookie);
387 assert(ncp->nc_elfcookie == NULL);
391 static void
392 cleanup_trans_state(nfsl_config_t *ncp)
394 if (ncp->nc_transcookie != NULL) {
395 nfslog_close_transactions(&ncp->nc_transcookie);
396 assert(ncp->nc_transcookie == NULL);
401 * Searches the list of previously seen bad tags. Note that this
402 * list is never pruned. This should not be a problem since the
403 * list of bad tags should be fairl small. New entries are inserted
404 * at the beginning of the list assuming it will be accessed more
405 * frequently since we have just seen it.
407 static void
408 badtag_notify(char *tag)
410 struct nfs_log_list *lp, *p;
411 int error;
413 for (p = badtag_list; p != NULL; p = p->l_next) {
414 if (strcmp(tag, p->l_name) == 0) {
416 * We've seen this before, nothing to do.
418 return;
423 * Not on the list, add it.
425 syslog(LOG_ERR, gettext("tag \"%s\" not found in %s - "
426 "ignoring records referencing such tag."),
427 tag, NFSL_CONFIG_FILE_PATH);
429 if ((lp = (struct nfs_log_list *)malloc(sizeof (*lp))) != NULL) {
430 if ((lp->l_name = strdup(tag)) != NULL) {
431 lp->l_next = badtag_list;
432 badtag_list = lp;
433 return; /* done */
437 free(lp->l_name);
438 free(lp);
439 error = errno;
440 syslog(LOG_ERR, gettext(
441 "Cannot add \"%s\" to bad tag list: %s"), tag, strerror(error));