/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License, Version 1.0 only
* (the "License"). You may not use this file except in compliance
* with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright (c) 1999-2000 by Sun Microsystems, Inc.
* All rights reserved.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
/*
* Postprocessor for NFS server logging.
*/
#include <assert.h>
#include <deflt.h>
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include <signal.h>
#include <syslog.h>
#include <limits.h>
#include <libintl.h>
#include <locale.h>
#include <unistd.h>
#include <sys/resource.h>
#include <rpc/clnt_stat.h>
#include "fhtab.h"
#include "nfslogd.h"
#include "buffer_list.h"
#include "../lib/nfslog_config.h"
#include "../lib/nfslogtab.h"
enum pidfile_operation {
};
static int nfslogtab_deactivate_after_boot(void);
static int
static int cycle_logs(nfsl_config_t *, int);
static void enable_logcycling(void);
static int process_pidfile(enum pidfile_operation);
static void short_cleanup(void);
static void full_cleanup(void);
static void transactions_timeout(nfsl_config_t *);
static void close_all_translogs(nfsl_config_t *);
int cycle_log(char *, int);
/*
* Configuration information.
*/
int debug = 0;
/* prune_timeout measures how old a database entry must be to be pruned */
/* prune_frequency measures how often should prune_dbs be called */
/*ARGSUSED*/
int
{
int error = 0;
char *defp;
/*
* Check to make sure user is root.
*/
if (geteuid() != 0) {
argv[0]);
exit(1);
}
/*
* Read defaults file.
*/
if (defopen(NFSLOG_OPTIONS_FILE) == 0) {
if (debug > 0)
}
if (debug > 0) {
if (test)
(void) printf("test=TRUE\n");
else
(void) printf("test=FALSE\n");
}
}
/*
* Set Umask for log and fhtable creation.
*/
}
/*
* Minimum size buffer should reach before processing.
*/
if (debug > 0)
}
/*
* Number of seconds the daemon should
* sleep waiting for more work.
*/
if (debug > 0)
}
/*
* Maximum number of logs to preserve.
*/
if (debug > 0) {
(void) printf("max_logs_preserve=%d\n",
}
}
/*
* Frequency of atime updates.
*/
if (debug > 0) {
(void) printf("mapping_update_interval=%ld\n",
}
}
/*
* Time to remove entries
*/
/*
* Prune timeout is in hours but we want
* deal with the time in seconds internally.
*/
if (prune_timeout < prune_frequency)
if (debug > 0) {
(void) printf("prune_timeout=%ld\n",
}
}
/*
*/
/*
* Specify full pathname of fhtable to prune before
* any processing is to be done
*/
if (debug > 0) {
(void) printf("fhtable to prune=%s\n",
}
} else {
"malloc fhtable_to_prune error %s\n"),
}
}
/*
* Log cycle frequency.
*/
if (debug > 0) {
(void) printf("cycle_frequency=%ld\n",
}
}
/*
* defopen of NULL closes the open defaults file.
*/
}
"getrlimit failed error is %d - %s\n"),
exit(1);
}
"MIN_PROCESSING_SIZE out of range, should be >= 0 and "
exit(1);
}
"IDLE_TIME out of range, should be >= 0 and "
exit(1);
}
"MAX_LOGS_PRESERVE out of range, should be >= 0 and "
exit(1);
}
"MAPPING_UPDATE_INTERVAL out of range, "
"should be >= 0 and "
exit(1);
}
"CYCLE_FREQUENCY out of range, should be >= 0 and "
exit(1);
}
/* get value in seconds */
/*
* If we dump core, it will be /core
*/
if (chdir("/") < 0)
/*
* Config errors to stderr
*/
#ifndef DEBUG
if (pid == -1) {
argv[0]);
exit(1);
}
if (pid != 0)
exit(0);
/*
* Config errors to syslog
*/
#endif /* DEBUG */
#if !defined(TEXT_DOMAIN)
#endif
(void) textdomain(TEXT_DOMAIN);
/*
* Check to see if nfslogd is already running.
*/
if (process_pidfile(PID_STARTUP) != 0) {
exit(1);
}
#ifndef DEBUG
/*
* standard input, output, and error, and detach from
* controlling terminal.
*/
closefrom(0);
(void) dup(1);
}
(void) setsid();
#endif /* DEBUG */
/*
* Call once at startup to handle the nfslogtab
*/
if (nfslogtab_deactivate_after_boot() == -1)
exit(1);
/*
* Get a list of buffers that need to be processed.
*/
goto done;
}
/*
* Get the configuration list.
*/
"Could not obtain configuration list: %s"),
goto done;
}
/*
* loop to process the work being generated by the NFS server
*/
while (keep_running) {
buffers_processed = 0;
while (buffer_list == NULL) {
/*
* Nothing to do
*/
if (!keep_running) {
/*
* We have been interrupted and asked to
* flush our transactions and exit.
*/
goto done;
}
}
process_start = time(0);
"Could not update configuration list: %s"),
goto done;
}
need2cycle = TRUE;
if (need2cycle) {
if (error) {
"One or more logfiles couldn't be cycled, "
"continuing regular processing"));
}
need2cycle = FALSE;
last_cycle = time(0);
}
need2prune = TRUE;
if (need2prune || fhtable_to_prune) {
if (error) {
"Error in cleaning database files"));
}
need2prune = FALSE;
last_prune = time(0);
/* After the first time, use the normal procedure */
}
processed = 0;
"Buffer file '%s' "
"processed successfully."),
}
error =
"\t\"%s\t%s\t%d\" from %s"),
error =
/*
* An error different from what we've reported
* before occured.
*/
"Cannot process buffer file '%s' - "
"will retry on every iteration."),
}
}
if (keep_running) {
/*
* Sleep idle_time minus however long it took us
* to process the buffers.
*/
if (process_time < idle_time)
}
}
done:
/*
* Make sure to clean house before we exit
*/
(void) process_pidfile(PID_SHUTDOWN);
return (error);
}
static void
short_cleanup(void)
{
if (debug) {
"SIGTERM received, setting state to terminate...\n");
}
}
static void
full_cleanup(void)
{
if (debug) {
"SIGHUP received, setting state to shutdown...\n");
}
}
/*
* Removes nfslogtab entries matching the specified buffer_ent,
* if 'inactive_only' is set, then only inactive entries are removed.
* The buffer_list and sharepoint list entries are removed appropriately.
* Returns 0 on success, error otherwise.
*/
static int
struct buffer_ent **buffer_list,
struct buffer_ent **bep,
{
int error = 0;
return (error);
}
return (error);
}
continue;
goto errout;
}
}
/*
* All sharepoints were removed from NFSLOGTAB.
* Remove this buffer from our list.
*/
}
return (error);
}
/*
* Deactivates entries if nfslogtab is older than the boot time.
*/
static int
{
int error = 0;
return (-1);
}
return (0);
}
return (-1);
}
"Cannot deactivate all entries in %s\n"), NFSLOGTAB);
return (-1);
}
return (0);
}
/*
* Enables the log file cycling flag.
*/
static void
enable_logcycling(void)
{
need2cycle = TRUE;
}
/*
* Cycle all log files that have been active since the last cycling.
* This means it's not simply listed in the configuration file, but
* there's information associated with it.
*/
static int
{
error = 0;
/*
* Process transpath log.
*/
if (clp->nc_logpath) {
&clp->nc_transcookie);
}
} else if (error)
goto errout;
}
total_errors += error;
/*
* Process elfpath log.
*/
if (clp->nc_rpclogpath) {
} else if (error)
goto errout;
}
total_errors += error;
}
/*
* Free the list of processed entries.
*/
return (total_errors);
}
/*
* Returns TRUE if this log has not yet been cycled, FALSE otherwise.
* '*head' points to the list of entries that have been processed.
* If this is a new entry, it gets inserted at the beginning of the
* list, and returns TRUE.
*
* The list is freed if 'need2free' is set, and returns FALSE.
* Sets 'error' on failure, and returns FALSE.
*/
static boolean_t
{
struct list {
char *log;
if (need2free) {
/*
* Free the list and return
*/
free(p);
}
return (B_FALSE);
}
*error = 0;
/*
* Have we seen this before?
*/
return (B_FALSE);
}
/*
* Add it to the list
*/
return (B_FALSE);
}
head = p;
return (B_TRUE);
}
/*
* cycle given log file.
*/
int
{
int i;
char *file_1;
char *file_2;
int error = 0;
if (max_logs_preserve == 0)
return (0);
/*
* Nothing to cycle.
*/
return (0);
}
return (errno);
}
for (i = max_logs_preserve - 2; i >= 0; i--) {
"cycle_log: can not rename %s to %s: %s"),
goto out;
}
}
}
"cycle_log: can not rename %s to %s: %s"),
goto out;
}
}
error = 0;
return (error);
}
/*
* If operation = PID_STARTUP then checks the nfslogd.pid file, it is opened
* if it exists, read and the pid is checked for an active process. If no
* active process is found, the pid of this process is written to the file,
* and 0 is returned, otherwise non-zero error is returned.
*
* If operation = PID_SHUTDOWN then removes the nfslogd.pid file and 0 is
* returned.
*/
static int
{
int error = 0;
int open_flags;
if (op == PID_STARTUP)
else {
open_flags = O_RDWR;
}
/*
* We were going to remove it anyway
*/
error = 0;
goto out;
}
"cannot open or create pid file %s\n"), PidFile);
goto out;
}
"Cannot lock %s - %s\n"), PidFile,
goto out;
}
"Can not read from file %s - %s\n"), PidFile,
}
if (op == PID_STARTUP) {
if (read_count > 0) {
"Terminated - nfslogd(%ld) already "
"running.\n"), pid);
goto out;
"Unexpected error returned %s\n"),
goto out;
}
}
/*
* rewind the file to overwrite old pid
*/
"Cannot update %s: %s\n"),
}
} else {
}
}
out:
if (fd >= 0)
return (error);
}
/*
* Forces a timeout on all open transactions.
*/
static void
{
FALSE);
}
}
}
/*
* Closes all transaction logs causing outstanding transactions
* to be flushed to their respective log.
*/
static void
{
}
}
}