/* * 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 #include #include #include #include #include #include #include #include #include "libnsctl.h" #include 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)); }