OpenSolaris_b135/lib/libnsctl/common/cache.c

Compare this file to the similar file:
Show the results in this format:

/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License (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 2008 Sun Microsystems, Inc.  All rights reserved.
 * Use is subject to license terms.
 */

#include <sys/types.h>
#include <sys/fcntl.h>
#include <errno.h>
#include <fcntl.h>
#include <stdlib.h>
#include <signal.h>
#include <strings.h>
#include <unistd.h>
#include <stdio.h>

#include "libnsctl.h"
#include <nsctl.h>


static int _nsc_open_path(nsc_fd_t *);
static int _nsc_open_check(nsc_fd_t *);


/*
 * Turn off ckdchk checking of nsc_open()'d volumes since we have no CKD
 * formatted volumes right now.  If/when we come back with CKD volumes,
 * we could do this more sanely by completing the implementation of the
 * CKD module, and having nsc_open() prevent any non-NSC_CKD_DISK open
 * of a CKD volume.
 * -- Simon, Thu Feb 18 10:49:46 GMT 1999
 */
static int ckdchk = 0;


nsc_fd_t *
nsc_open(path, flag, mode)
char *path;
int flag, mode;
{
	nsc_fd_t *fd;

	if (strlen(path) >= NSC_MAXPATH) {
		errno = ENAMETOOLONG;
		return (0);
	}

	if (!(fd = (nsc_fd_t *)calloc(1, sizeof (nsc_fd_t))))
		return (0);

	if ((mode & O_ACCMODE) == O_WRONLY) {
		mode &= ~O_ACCMODE;
		mode |= O_RDWR;
	}

	fd->sf_flag = flag;
	fd->sf_fmode = mode;

	strcpy(fd->sf_path, path);

	if (!_nsc_open_path(fd)) {
		free(fd);
		return (0);
	}

	if (ckdchk && !_nsc_open_check(fd)) {
		(void) nsc_close(fd);
		return (0);
	}

	return (fd);
}


nsc_fd_t *
nsc_fdopen(id, path, mode)
int id, mode;
char *path;
{
	struct flock lk;
	nsc_fd_t *fd;
	int i;

	if (strlen(path) >= NSC_MAXPATH) {
		errno = ENAMETOOLONG;
		return (0);
	}

	if (!(fd = (nsc_fd_t *)calloc(1, sizeof (nsc_fd_t))))
		return (0);

	lk.l_type = F_WRLCK;
	lk.l_whence = SEEK_SET;
	lk.l_start = 0;
	lk.l_len = 0;

	if (fcntl(id, F_SETLKW, &lk) < 0)
		return (0);

	i = fcntl(id, F_GETFL);

	if ((mode & O_ACCMODE) != O_RDONLY) {
		if ((i & O_ACCMODE) == O_RDONLY) {
			errno = EBADF;
			return (0);
		}
	}

	if ((mode & O_ACCMODE) != O_WRONLY) {
		if ((i & O_ACCMODE) == O_WRONLY) {
			errno = EBADF;
			return (0);
		}
	}

	mode = (i & O_ACCMODE) | (mode & ~O_ACCMODE);

	if (fcntl(id, F_SETFL, mode) < 0)
		return (0);

	if (lseek(id, 0, SEEK_SET) < 0)
		return (0);

	fd->sf_fd = id;
	fd->sf_fmode = mode;

	strcpy(fd->sf_path, path);

	return (fd);
}


static int
_nsc_open_path(fd)
nsc_fd_t *fd;
{
	struct nscioc_open op;

	memset(&op, 0, sizeof (op));

	op.flag = fd->sf_flag;
	op.mode = fd->sf_fmode;
	strcpy(op.path, fd->sf_path);

	if ((fd->sf_fd = open(_NSC_DEV_PATH, fd->sf_fmode)) < 0)
		return (0);

	if (ioctl(fd->sf_fd, NSCIOC_OPEN, &op) == 0)
		return (1);

	close(fd->sf_fd);
	return (0);
}


static int
_nsc_open_check(fd)
nsc_fd_t *fd;
{
	struct flock lk;
	char s[30];
	pid_t pid;
	int i;

	if ((fd->sf_fmode & O_ACCMODE) == O_RDONLY)
		return (1);

	if (access(_NSC_CKDCHK_PATH, X_OK) != 0)
		return (0);

	lk.l_type = F_WRLCK;
	lk.l_whence = SEEK_SET;
	lk.l_start = 0;
	lk.l_len = 0;

	if (fcntl(fd->sf_fd, F_SETLKW, &lk) < 0)
		return (0);

	if ((pid = fork()) == 0) {
		for (i = 1; i <= NSIG; i++)
			signal(i, SIG_IGN);

		for (i = fd->sf_fd; i <= 2 && (i = dup(i)) != -1; )
			fd->sf_fd = i;

		for (i = sysconf(_SC_OPEN_MAX); i >= 0; i--)
			if (i != fd->sf_fd)
				close(i);

		fcntl(fd->sf_fd, F_SETFD, 0);

		(void) open("/dev/null", 0);
		(void) open(_NSC_CKDCHK_LOG, O_WRONLY|O_CREAT|O_APPEND, 0666);
		(void) open(_NSC_CKDCHK_LOG, O_WRONLY|O_CREAT|O_APPEND, 0666);

		(void) sprintf(s, "%d", fd->sf_fd);

		(void) execl(_NSC_CKDCHK_PATH, "ckdchk", "-u", "-F",
			s, fd->sf_path, 0);

		exit(1);
	}

	return (pid != -1);
}


int
nsc_close(fd)
nsc_fd_t *fd;
{
	int rc;

	if (!fd)
		return (0);

	rc = close(fd->sf_fd);
	free(fd);

	return (rc);
}


int
nsc_reserve(fd)
nsc_fd_t *fd;
{
	return ((fd) ? ioctl(fd->sf_fd, NSCIOC_RESERVE, 0) : 0);
}


int
nsc_release(fd)
nsc_fd_t *fd;
{
	if (!fd)
		return (0);

	if (ckdchk && (fd->sf_fmode & O_ACCMODE) != O_RDONLY) {
		errno = EINVAL;
		return (-1);
	}

	return (ioctl(fd->sf_fd, NSCIOC_RELEASE, 0));
}


int
nsc_partsize(nsc_fd_t *fd, nsc_size_t *rvp)
{
	struct nscioc_partsize partsize;
	int rc;

	if (!fd)
		return (0);

	rc = ioctl(fd->sf_fd, NSCIOC_PARTSIZE, &partsize);
	if (rc != 0) {
		return (rc);
	}

	*rvp = (nsc_size_t)partsize.partsize;
	return (0);
}


int
nsc_fileno(fd)
nsc_fd_t *fd;
{
	return ((fd) ? fd->sf_fd : -1);
}


void
_nsc_nocheck()
{
	ckdchk = 0;
}


static int
_nsc_do_ioctl(cmd, arg)
int cmd;
void *arg;
{
	int fd, rc, save_errno;

	fd = open(_NSC_DEV_PATH, O_RDONLY);
	if (fd < 0)
		return (-1);

	rc = save_errno = 0;
	rc = ioctl(fd, cmd, arg);
	if (rc < 0)
		save_errno = errno;

	close(fd);

	errno = save_errno;
	return (rc);
}


/*
 * int
 * nsc_freeze(char *path)
 *	Freeze a pathname
 *
 * Calling/Exit State:
 *	Returns 0 for success, or -1 and sets errno.
 *
 * Description:
 *	This is the user level interface to the nsctl freeze operation.
 *	See uts/common/ns/nsctl/nsc_freeze.c for more information.
 */
int
nsc_freeze(path)
char *path;
{
	if (strlen(path) >= NSC_MAXPATH) {
		errno = ENAMETOOLONG;
		return (-1);
	}

	return (_nsc_do_ioctl(NSCIOC_FREEZE, path));
}

/*
 * int
 * nsc_unfreeze(char *path)
 *	Unfreeze a pathname
 *
 * Calling/Exit State:
 *	Returns 0 for success, or -1 and sets errno.
 *
 * Description:
 *	This is the user level interface to the nsctl unfreeze operation.
 *	See uts/common/ns/nsctl/nsc_freeze.c for more information.
 */
int
nsc_unfreeze(path)
char *path;
{
	if (strlen(path) >= NSC_MAXPATH) {
		errno = ENAMETOOLONG;
		return (-1);
	}

	return (_nsc_do_ioctl(NSCIOC_UNFREEZE, path));
}


/*
 * int
 * nsc_isfrozen(char *path)
 *	Test if a pathname is frozen
 *
 * Calling/Exit State:
 *	Returns:
 *		0	path is frozen
 *		1	path is not frozen
 *		-1	error (errno will be set)
 *
 * Description
 *	This is the user level interface to to the nsctl isfrozen operation.
 *	See uts/common/ns/nsctl/nsc_freeze.c for more information.
 */
int
nsc_isfrozen(path)
char *path;
{
	if (strlen(path) >= NSC_MAXPATH) {
		errno = ENAMETOOLONG;
		return (-1);
	}

	return (_nsc_do_ioctl(NSCIOC_ISFROZEN, path));
}

int
nsc_gmem_sizes(int *size)
{
	return (_nsc_do_ioctl(NSCIOC_GLOBAL_SIZES, size));
}

int
nsc_gmem_data(char *addr)
{
	return (_nsc_do_ioctl(NSCIOC_GLOBAL_DATA, addr));
}

/*
 * int
 * nsc_nvclean()
 *	mark nvmem clean, to prevent a warmstart of the cache on reboot
 */
int
nsc_nvclean(int force)
{
	int cmd;

	cmd = force ? NSCIOC_NVMEM_CLEANF : NSCIOC_NVMEM_CLEAN;

	return (_nsc_do_ioctl(cmd, (void *)0));
}