view usr/src/cmd/acctadm/aconf.c @ 0:c9caec207d52 b86

Initial porting based on b86
author Koji Uno <koji.uno@sun.com>
date Tue, 02 Jun 2009 18:56:50 +0900
parents
children 1a15d5aaf794
line wrap: on
line source

/*
 * 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
 * or http://www.opensolaris.org/os/licensing.
 * 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 2004 Sun Microsystems, Inc.  All rights reserved.
 * Use is subject to license terms.
 */

#pragma ident	"@(#)aconf.c	1.7	05/06/08 SMI"

#include <sys/types.h>
#include <sys/stat.h>
#include <sys/acctctl.h>

#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <fcntl.h>
#include <errno.h>
#include <limits.h>

#include "aconf.h"
#include "utils.h"
#include "res.h"

#define	BUFSZ	(PATH_MAX + 80)

typedef struct ac_token {
	char *tok_name;
	int tok_type;
	int (*tok_parse)(acctconf_t *, char *, int);
	int (*tok_print)(acctconf_t *, FILE *, int);
} ac_token_t;

static int print_enable(acctconf_t *, FILE *, int);
static int print_file(acctconf_t *, FILE *, int);
static int print_tracked(acctconf_t *, FILE *, int);
static int print_untracked(acctconf_t *, FILE *, int);

static ac_token_t tokens[] = {
	{ "ACCTADM_PROC_ENABLE",
		AC_PROC, aconf_str2enable, print_enable },
	{ "ACCTADM_PROC_FILE",
		AC_PROC, aconf_str2file, print_file },
	{ "ACCTADM_PROC_TRACKED",
		AC_PROC, aconf_str2tracked, print_tracked },
	{ "ACCTADM_PROC_UNTRACKED",
		AC_PROC, aconf_str2untracked, print_untracked },
	{ "ACCTADM_TASK_ENABLE",
		AC_TASK, aconf_str2enable, print_enable },
	{ "ACCTADM_TASK_FILE",
		AC_TASK, aconf_str2file, print_file },
	{ "ACCTADM_TASK_TRACKED",
		AC_TASK, aconf_str2tracked, print_tracked },
	{ "ACCTADM_TASK_UNTRACKED",
		AC_TASK, aconf_str2untracked, print_untracked },
	{ "ACCTADM_FLOW_ENABLE",
		AC_FLOW, aconf_str2enable, print_enable },
	{ "ACCTADM_FLOW_FILE",
		AC_FLOW, aconf_str2file, print_file },
	{ "ACCTADM_FLOW_TRACKED",
		AC_FLOW, aconf_str2tracked, print_tracked },
	{ "ACCTADM_FLOW_UNTRACKED",
		AC_FLOW, aconf_str2untracked, print_untracked },
	{ NULL,
		AC_NONE, NULL, NULL }
};

void
aconf_init(acctconf_t *acp)
{
	void *buf;
	void *pathname;
	char *tracked, *untracked;
	int state;

	if ((buf = malloc(AC_BUFSIZE)) == NULL ||
	    (pathname = malloc(MAXPATHLEN)) == NULL)
		die(gettext("not enough memory\n"));

	/*
	 * Initialize process accounting settings
	 */
	(void) memset(pathname, 0, MAXPATHLEN);
	if (acctctl(AC_PROC | AC_STATE_GET, &state, sizeof (int)) == -1)
		die(gettext("cannot get process accounting state\n"));
	acp->ac_proc_state = state;
	if (acctctl(AC_PROC | AC_FILE_GET, pathname, MAXPATHLEN) == -1) {
		if (errno == ENOTACTIVE)
			(void) strlcpy(acp->ac_proc_file,
			    AC_STR_NONE, MAXPATHLEN);
		else
			die(gettext("cannot get process accounting file name"));
	} else {
		(void) strlcpy(acp->ac_proc_file, pathname, MAXPATHLEN);
	}
	(void) memset(buf, 0, AC_BUFSIZE);
	if (acctctl(AC_PROC | AC_RES_GET, buf, AC_BUFSIZE) == -1)
		die(gettext("cannot obtain the list of enabled resources\n"));
	tracked = buf2str(buf, AC_BUFSIZE, AC_ON, AC_PROC);
	untracked = buf2str(buf, AC_BUFSIZE, AC_OFF, AC_PROC);
	(void) strlcpy(acp->ac_proc_tracked, tracked, MAXRESLEN);
	(void) strlcpy(acp->ac_proc_untracked, untracked, MAXRESLEN);
	free(tracked);
	free(untracked);

	/*
	 * Initialize flow accounting settings
	 */
	(void) memset(pathname, 0, MAXPATHLEN);
	if (acctctl(AC_FLOW | AC_STATE_GET, &state, sizeof (int)) == -1)
		die(gettext("cannot get flow accounting state\n"));
	acp->ac_flow_state = state;
	if (acctctl(AC_FLOW | AC_FILE_GET, pathname, MAXPATHLEN) == -1) {
		if (errno == ENOTACTIVE)
			(void) strlcpy(acp->ac_flow_file,
			    AC_STR_NONE, MAXPATHLEN);
		else
			die(gettext("cannot get flow accounting file name"));
	} else {
		(void) strlcpy(acp->ac_flow_file, pathname, MAXPATHLEN);
	}
	(void) memset(buf, 0, AC_BUFSIZE);
	if (acctctl(AC_FLOW | AC_RES_GET, buf, AC_BUFSIZE) == -1)
		die(gettext("cannot obtain the list of enabled resources\n"));
	tracked = buf2str(buf, AC_BUFSIZE, AC_ON, AC_FLOW);
	untracked = buf2str(buf, AC_BUFSIZE, AC_OFF, AC_FLOW);
	(void) strlcpy(acp->ac_flow_tracked, tracked, MAXRESLEN);
	(void) strlcpy(acp->ac_flow_untracked, untracked, MAXRESLEN);
	free(tracked);
	free(untracked);

	/*
	 * Initialize task accounting settings
	 */
	(void) memset(pathname, 0, MAXPATHLEN);
	if (acctctl(AC_TASK | AC_STATE_GET, &state, sizeof (int)) == -1)
		die(gettext("cannot get task accounting state\n"));
	acp->ac_task_state = state;
	if (acctctl(AC_TASK | AC_FILE_GET, pathname, MAXPATHLEN) == -1) {
		if (errno == ENOTACTIVE)
			(void) strlcpy(acp->ac_task_file,
			    AC_STR_NONE, MAXPATHLEN);
		else
			die(gettext("cannot get task accounting file name"));
	} else {
		(void) strlcpy(acp->ac_task_file, pathname, MAXPATHLEN);
	}
	(void) memset(buf, 0, AC_BUFSIZE);
	if (acctctl(AC_TASK | AC_RES_GET, buf, AC_BUFSIZE) == -1)
		die(gettext("cannot obtain the list of enabled resources\n"));
	tracked = buf2str(buf, AC_BUFSIZE, AC_ON, AC_TASK);
	untracked = buf2str(buf, AC_BUFSIZE, AC_OFF, AC_TASK);
	(void) strlcpy(acp->ac_task_tracked, tracked, MAXRESLEN);
	(void) strlcpy(acp->ac_task_untracked, untracked, MAXRESLEN);
	free(pathname);
	free(buf);
	free(tracked);
	free(untracked);
}

int
aconf_create(acctconf_t *acp, const char *fpath)
{
	if ((acp->ac_conf_fd = open(fpath, O_RDWR | O_CREAT, AC_PERM)) == -1) {
		warn(gettext("failed to open %s"), fpath);
		return (-1);
	}
	if ((acp->ac_conf_fp = fdopen(acp->ac_conf_fd, "r+")) == NULL) {
		warn(gettext("failed to open stream for %s"), fpath);
		return (-1);
	}
	return (0);
}

int
aconf_open(acctconf_t *acp, const char *fpath)
{
	char buf[BUFSZ];
	int line;
	int ret = 0;

	if ((acp->ac_conf_fd = open(fpath, O_RDONLY, AC_PERM)) == -1) {
		warn(gettext("failed to open %s"), fpath);
		return (-1);
	}
	if ((acp->ac_conf_fp = fdopen(acp->ac_conf_fd, "r")) == NULL) {
		warn(gettext("failed to open stream for %s"), fpath);
		return (-1);
	}
	for (line = 1; fgets(buf, BUFSZ, acp->ac_conf_fp) != NULL; line++) {
		char name[BUFSZ], value[BUFSZ];
		ac_token_t *tokp;
		int len;

		if (buf[0] == '#' || buf[0] == '\n')
			continue;
		/*
		 * Look for "name=value", with optional whitespace on either
		 * side, terminated by a newline, and consuming the whole line.
		 */
		/* LINTED - unbounded string specifier */
		if (sscanf(buf, " %[^=]=%s \n%n", name, value, &len) == 2 &&
		    name[0] != '\0' && value[0] != '\0' && len == strlen(buf)) {
			/*
			 * Locate a matching token in the tokens[] table,
			 * and invoke its parsing function.
			 */
			for (tokp = tokens; tokp->tok_name != NULL; tokp++) {
				if (strcmp(name, tokp->tok_name) == 0) {
					if (tokp->tok_parse(acp, value,
					    tokp->tok_type) == -1) {
						warn(gettext("\"%s\", line %d: "
						    "warning: invalid %s\n"),
						    fpath, line, name);
						ret = -1;
					}
					break;
				}
			}
			/*
			 * If we hit the end of the tokens[] table,
			 * no matching token was found.
			 */
			if (tokp->tok_name == NULL) {
				warn(gettext("\"%s\", line %d: warning: "
				    "invalid token: %s\n"), fpath, line, name);
				ret = -1;
			}
		} else {
			warn(gettext("\"%s\", line %d: syntax error\n"),
			    fpath, line);
			ret = -1;
		}
	}
	if (line == 1) {
		warn(gettext("cannot read settings from %s\n"), fpath);
		ret = -1;
	}
	return (ret);
}

int
aconf_setup(acctconf_t *acp)
{
	void *buf;

	if ((buf = malloc(AC_BUFSIZE)) == NULL)
		die(gettext("not enough memory\n"));

	/*
	 * Setup process accounting
	 */
	(void) memset(buf, 0, AC_BUFSIZE);
	str2buf(buf, acp->ac_proc_untracked, AC_OFF, AC_PROC);
	str2buf(buf, acp->ac_proc_tracked, AC_ON, AC_PROC);
	if (acctctl(AC_PROC | AC_RES_SET, buf, AC_BUFSIZE) == -1) {
		warn(gettext("cannot enable or disable resources\n"));
		return (-1);
	}
	if (strcmp(acp->ac_proc_file, AC_STR_NONE) != 0) {
		if (acctctl(AC_PROC | AC_FILE_SET,
		    acp->ac_proc_file, strlen(acp->ac_proc_file) + 1) == -1) {
			warn(gettext("cannot open accounting file"));
			return (-1);
		}
	} else {
		if (acctctl(AC_PROC | AC_FILE_SET, NULL, 0) == -1) {
			warn(gettext("cannot close accounting file\n"));
			return (-1);
		}
	}
	if (acctctl(AC_PROC | AC_STATE_SET, &acp->ac_proc_state,
	    sizeof (int)) == -1) {
		warn(gettext("cannot enable/disable process accounting"));
		return (-1);
	}

	/*
	 * Setup flow accounting
	 */
	(void) memset(buf, 0, AC_BUFSIZE);
	str2buf(buf, acp->ac_flow_untracked, AC_OFF, AC_FLOW);
	str2buf(buf, acp->ac_flow_tracked, AC_ON, AC_FLOW);
	if (acctctl(AC_FLOW | AC_RES_SET, buf, AC_BUFSIZE) == -1) {
		warn(gettext("cannot enable or disable resources\n"));
		return (-1);
	}
	if (strcmp(acp->ac_flow_file, AC_STR_NONE) != 0) {
		if (acctctl(AC_FLOW | AC_FILE_SET,
		    acp->ac_flow_file, strlen(acp->ac_flow_file) + 1) == -1) {
			warn(gettext("cannot open accounting file"));
			return (-1);
		}
	} else {
		if (acctctl(AC_FLOW | AC_FILE_SET, NULL, 0) == -1) {
			warn(gettext("cannot close accounting file\n"));
			return (-1);
		}
	}
	if (acctctl(AC_FLOW | AC_STATE_SET, &acp->ac_flow_state,
	    sizeof (int)) == -1) {
		warn(gettext("cannot enable/disable flow accounting"));
		return (-1);
	}


	/*
	 * Setup task accounting
	 */
	(void) memset(buf, 0, AC_BUFSIZE);
	str2buf(buf, acp->ac_task_untracked, AC_OFF, AC_TASK);
	str2buf(buf, acp->ac_task_tracked, AC_ON, AC_TASK);
	if (acctctl(AC_TASK | AC_RES_SET, buf, AC_BUFSIZE) == -1) {
		warn(gettext("cannot enable or disable resources\n"));
		return (-1);
	}
	if (strcmp(acp->ac_task_file, AC_STR_NONE) != 0) {
		if (acctctl(AC_TASK | AC_FILE_SET,
		    acp->ac_task_file, strlen(acp->ac_task_file) + 1) == -1) {
			warn(gettext("cannot set accounting file"));
			return (-1);
		}
	} else {
		if (acctctl(AC_TASK | AC_FILE_SET, NULL, 0) == -1) {
			warn(gettext("cannot close accounting file\n"));
			return (-1);
		}
	}
	if (acctctl(AC_TASK | AC_STATE_SET, &acp->ac_task_state,
	    sizeof (int)) == -1) {
		warn(gettext("cannot enable/disable task accounting"));
		return (-1);
	}

	free(buf);
	return (0);
}

int
aconf_close(acctconf_t *acp)
{
	if (acp->ac_conf_fp != NULL && fclose(acp->ac_conf_fp) != 0)
		return (-1);
	else
		return (0);
}

int
aconf_write(acctconf_t *acp)
{
	ac_token_t *tokp;

	if (fseeko(acp->ac_conf_fp, (off_t)0, SEEK_SET) == -1) {
		warn(gettext("failed to seek config file"));
		return (-1);
	}
	if (ftruncate(acp->ac_conf_fd, (off_t)0) == -1) {
		warn(gettext("failed to truncate config file"));
		return (-1);
	}
	(void) fputs("#\n# acctadm.conf\n#\n"
	    "# Configuration parameters for extended accounting.\n"
	    "# Do NOT edit this file by hand -- use acctadm(1m) instead.\n"
	    "#\n", acp->ac_conf_fp);
	for (tokp = tokens; tokp->tok_name != NULL; tokp++) {
		if (fprintf(acp->ac_conf_fp, "%s=", tokp->tok_name) == -1 ||
		    tokp->tok_print(acp, acp->ac_conf_fp,
		    tokp->tok_type) == -1) {
			warn(gettext("failed to write token"));
			return (-1);
		}
	}
	if (fflush(acp->ac_conf_fp) != 0)
		warn(gettext("warning: failed to flush config file"));
	if (fsync(acp->ac_conf_fd) == -1)
		warn(gettext("warning: failed to sync config file to disk"));
	if (fchmod(acp->ac_conf_fd, AC_PERM) == -1)
		warn(gettext("warning: failed to reset mode on config file"));
	if (fchown(acp->ac_conf_fd, AC_OWNER, AC_GROUP) == -1)
		warn(gettext("warning: failed to reset owner on config file"));
	return (0);
}

void
aconf_print(acctconf_t *acp, FILE *fp, int type)
{
	if (type & AC_TASK) {
		(void) fprintf(fp,
		    gettext("            Task accounting: %s\n"),
		    acp->ac_task_state ?
		    gettext("active") : gettext("inactive"));
		(void) fprintf(fp,
		    gettext("       Task accounting file: %s\n"),
		    acp->ac_task_file);
		(void) fprintf(fp,
		    gettext("     Tracked task resources: %s\n"),
		    acp->ac_task_tracked);
		(void) fprintf(fp,
		    gettext("   Untracked task resources: %s\n"),
		    acp->ac_task_untracked);
	}
	if (type & AC_PROC) {
		(void) fprintf(fp,
		    gettext("         Process accounting: %s\n"),
		    acp->ac_proc_state ?
		    gettext("active") : gettext("inactive"));
		(void) fprintf(fp,
		    gettext("    Process accounting file: %s\n"),
		    acp->ac_proc_file);
		(void) fprintf(fp,
		    gettext("  Tracked process resources: %s\n"),
		    acp->ac_proc_tracked);
		(void) fprintf(fp,
		    gettext("Untracked process resources: %s\n"),
		    acp->ac_proc_untracked);
	}
	if (type & AC_FLOW) {
		(void) fprintf(fp,
		    gettext("            Flow accounting: %s\n"),
		    acp->ac_flow_state ?
		    gettext("active") : gettext("inactive"));
		(void) fprintf(fp,
		    gettext("       Flow accounting file: %s\n"),
		    acp->ac_flow_file);
		(void) fprintf(fp,
		    gettext("     Tracked flow resources: %s\n"),
		    acp->ac_flow_tracked);
		(void) fprintf(fp,
		    gettext("   Untracked flow resources: %s\n"),
		    acp->ac_flow_untracked);
	}
}

int
aconf_str2enable(acctconf_t *acp, char *buf, int type)
{
	int state;

	if (strcasecmp(buf, AC_STR_YES) == 0)
		state = AC_ON;
	else if (strcasecmp(buf, AC_STR_NO) == 0)
		state = AC_OFF;
	else
		return (-1);
	if (type == AC_PROC)
		acp->ac_proc_state = state;
	else if (type == AC_TASK)
		acp->ac_task_state = state;
	else if (type == AC_FLOW)
		acp->ac_flow_state = state;
	else
		return (-1);
	return (0);
}

int
aconf_str2file(acctconf_t *acp, char *buf, int type)
{
	if (strcmp(buf, AC_STR_NONE) != 0 && !valid_abspath(buf))
		return (-1);
	if (type == AC_PROC)
		(void) strlcpy(acp->ac_proc_file, buf, MAXPATHLEN);
	else if (type == AC_TASK)
		(void) strlcpy(acp->ac_task_file, buf, MAXPATHLEN);
	else if (type == AC_FLOW)
		(void) strlcpy(acp->ac_flow_file, buf, MAXPATHLEN);
	return (0);
}

int
aconf_str2tracked(acctconf_t *acp, char *buf, int type)
{
	if (type == AC_PROC)
		(void) strlcpy(acp->ac_proc_tracked, buf, MAXRESLEN);
	else if (type == AC_TASK)
		(void) strlcpy(acp->ac_task_tracked, buf, MAXRESLEN);
	else if (type == AC_FLOW)
		(void) strlcpy(acp->ac_flow_tracked, buf, MAXRESLEN);
	else
		return (-1);
	return (0);
}

int
aconf_str2untracked(acctconf_t *acp, char *buf, int type)
{
	if (type == AC_PROC)
		(void) strlcpy(acp->ac_proc_untracked, buf, MAXRESLEN);
	else if (type == AC_TASK)
		(void) strlcpy(acp->ac_task_untracked, buf, MAXRESLEN);
	else if (type == AC_FLOW)
		(void) strlcpy(acp->ac_flow_untracked, buf, MAXRESLEN);
	else
		return (-1);
	return (0);
}

static int
print_enable(acctconf_t *acp, FILE *fp, int type)
{
	if (type == AC_PROC)
		return (fprintf(fp, "%s\n", (acp->ac_proc_state == AC_OFF) ?
		    AC_STR_NO : AC_STR_YES));
	else if (type == AC_TASK)
		return (fprintf(fp, "%s\n", (acp->ac_task_state == AC_OFF) ?
		    AC_STR_NO : AC_STR_YES));
	else if (type == AC_FLOW)
		return (fprintf(fp, "%s\n", (acp->ac_flow_state == AC_OFF) ?
		    AC_STR_NO : AC_STR_YES));
	else
		return (-1);
}

static int
print_file(acctconf_t *acp, FILE *fp, int type)
{
	if (type == AC_PROC)
		return (fprintf(fp, "%s\n", acp->ac_proc_file));
	else if (type == AC_TASK)
		return (fprintf(fp, "%s\n", acp->ac_task_file));
	else if (type == AC_FLOW)
		return (fprintf(fp, "%s\n", acp->ac_flow_file));
	else
		return (-1);
}

static int
print_tracked(acctconf_t *acp, FILE *fp, int type)
{
	if (type == AC_PROC)
		return (fprintf(fp, "%s\n", acp->ac_proc_tracked));
	else if (type == AC_TASK)
		return (fprintf(fp, "%s\n", acp->ac_task_tracked));
	else if (type == AC_FLOW)
		return (fprintf(fp, "%s\n", acp->ac_flow_tracked));
	else
		return (-1);
}

static int
print_untracked(acctconf_t *acp, FILE *fp, int type)
{
	if (type == AC_PROC)
		return (fprintf(fp, "%s\n", acp->ac_proc_untracked));
	else if (type == AC_TASK)
		return (fprintf(fp, "%s\n", acp->ac_task_untracked));
	else if (type == AC_FLOW)
		return (fprintf(fp, "%s\n", acp->ac_flow_untracked));
	else
		return (-1);
}