1 /*
   2  * CDDL HEADER START
   3  *
   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.
   7  *
   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.
  12  *
  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]
  18  *
  19  * CDDL HEADER END
  20  */
  21 /*
  22  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
  23  * Use is subject to license terms.
  24  */
  25 
  26 #include <sys/types.h>
  27 #include <sys/fcntl.h>
  28 #include <errno.h>
  29 #include <fcntl.h>
  30 #include <stdlib.h>
  31 #include <signal.h>
  32 #include <strings.h>
  33 #include <unistd.h>
  34 #include <stdio.h>
  35 
  36 #include "libnsctl.h"
  37 #include <nsctl.h>
  38 
  39 
  40 static int _nsc_open_path(nsc_fd_t *);
  41 static int _nsc_open_check(nsc_fd_t *);
  42 
  43 
  44 /*
  45  * Turn off ckdchk checking of nsc_open()'d volumes since we have no CKD
  46  * formatted volumes right now.  If/when we come back with CKD volumes,
  47  * we could do this more sanely by completing the implementation of the
  48  * CKD module, and having nsc_open() prevent any non-NSC_CKD_DISK open
  49  * of a CKD volume.
  50  * -- Simon, Thu Feb 18 10:49:46 GMT 1999
  51  */
  52 static int ckdchk = 0;
  53 
  54 
  55 nsc_fd_t *
  56 nsc_open(path, flag, mode)
  57 char *path;
  58 int flag, mode;
  59 {
  60         nsc_fd_t *fd;
  61 
  62         if (strlen(path) >= NSC_MAXPATH) {
  63                 errno = ENAMETOOLONG;
  64                 return (0);
  65         }
  66 
  67         if (!(fd = (nsc_fd_t *)calloc(1, sizeof (nsc_fd_t))))
  68                 return (0);
  69 
  70         if ((mode & O_ACCMODE) == O_WRONLY) {
  71                 mode &= ~O_ACCMODE;
  72                 mode |= O_RDWR;
  73         }
  74 
  75         fd->sf_flag = flag;
  76         fd->sf_fmode = mode;
  77 
  78         strcpy(fd->sf_path, path);
  79 
  80         if (!_nsc_open_path(fd)) {
  81                 free(fd);
  82                 return (0);
  83         }
  84 
  85         if (ckdchk && !_nsc_open_check(fd)) {
  86                 (void) nsc_close(fd);
  87                 return (0);
  88         }
  89 
  90         return (fd);
  91 }
  92 
  93 
  94 nsc_fd_t *
  95 nsc_fdopen(id, path, mode)
  96 int id, mode;
  97 char *path;
  98 {
  99         struct flock lk;
 100         nsc_fd_t *fd;
 101         int i;
 102 
 103         if (strlen(path) >= NSC_MAXPATH) {
 104                 errno = ENAMETOOLONG;
 105                 return (0);
 106         }
 107 
 108         if (!(fd = (nsc_fd_t *)calloc(1, sizeof (nsc_fd_t))))
 109                 return (0);
 110 
 111         lk.l_type = F_WRLCK;
 112         lk.l_whence = SEEK_SET;
 113         lk.l_start = 0;
 114         lk.l_len = 0;
 115 
 116         if (fcntl(id, F_SETLKW, &lk) < 0)
 117                 return (0);
 118 
 119         i = fcntl(id, F_GETFL);
 120 
 121         if ((mode & O_ACCMODE) != O_RDONLY) {
 122                 if ((i & O_ACCMODE) == O_RDONLY) {
 123                         errno = EBADF;
 124                         return (0);
 125                 }
 126         }
 127 
 128         if ((mode & O_ACCMODE) != O_WRONLY) {
 129                 if ((i & O_ACCMODE) == O_WRONLY) {
 130                         errno = EBADF;
 131                         return (0);
 132                 }
 133         }
 134 
 135         mode = (i & O_ACCMODE) | (mode & ~O_ACCMODE);
 136 
 137         if (fcntl(id, F_SETFL, mode) < 0)
 138                 return (0);
 139 
 140         if (lseek(id, 0, SEEK_SET) < 0)
 141                 return (0);
 142 
 143         fd->sf_fd = id;
 144         fd->sf_fmode = mode;
 145 
 146         strcpy(fd->sf_path, path);
 147 
 148         return (fd);
 149 }
 150 
 151 
 152 static int
 153 _nsc_open_path(fd)
 154 nsc_fd_t *fd;
 155 {
 156         struct nscioc_open op;
 157 
 158         memset(&op, 0, sizeof (op));
 159 
 160         op.flag = fd->sf_flag;
 161         op.mode = fd->sf_fmode;
 162         strcpy(op.path, fd->sf_path);
 163 
 164         if ((fd->sf_fd = open(_NSC_DEV_PATH, fd->sf_fmode)) < 0)
 165                 return (0);
 166 
 167         if (ioctl(fd->sf_fd, NSCIOC_OPEN, &op) == 0)
 168                 return (1);
 169 
 170         close(fd->sf_fd);
 171         return (0);
 172 }
 173 
 174 
 175 static int
 176 _nsc_open_check(fd)
 177 nsc_fd_t *fd;
 178 {
 179         struct flock lk;
 180         char s[30];
 181         pid_t pid;
 182         int i;
 183 
 184         if ((fd->sf_fmode & O_ACCMODE) == O_RDONLY)
 185                 return (1);
 186 
 187         if (access(_NSC_CKDCHK_PATH, X_OK) != 0)
 188                 return (0);
 189 
 190         lk.l_type = F_WRLCK;
 191         lk.l_whence = SEEK_SET;
 192         lk.l_start = 0;
 193         lk.l_len = 0;
 194 
 195         if (fcntl(fd->sf_fd, F_SETLKW, &lk) < 0)
 196                 return (0);
 197 
 198         if ((pid = fork()) == 0) {
 199                 for (i = 1; i <= NSIG; i++)
 200                         signal(i, SIG_IGN);
 201 
 202                 for (i = fd->sf_fd; i <= 2 && (i = dup(i)) != -1; )
 203                         fd->sf_fd = i;
 204 
 205                 for (i = sysconf(_SC_OPEN_MAX); i >= 0; i--)
 206                         if (i != fd->sf_fd)
 207                                 close(i);
 208 
 209                 fcntl(fd->sf_fd, F_SETFD, 0);
 210 
 211                 (void) open("/dev/null", 0);
 212                 (void) open(_NSC_CKDCHK_LOG, O_WRONLY|O_CREAT|O_APPEND, 0666);
 213                 (void) open(_NSC_CKDCHK_LOG, O_WRONLY|O_CREAT|O_APPEND, 0666);
 214 
 215                 (void) sprintf(s, "%d", fd->sf_fd);
 216 
 217                 (void) execl(_NSC_CKDCHK_PATH, "ckdchk", "-u", "-F",
 218                         s, fd->sf_path, 0);
 219 
 220                 exit(1);
 221         }
 222 
 223         return (pid != -1);
 224 }
 225 
 226 
 227 int
 228 nsc_close(fd)
 229 nsc_fd_t *fd;
 230 {
 231         int rc;
 232 
 233         if (!fd)
 234                 return (0);
 235 
 236         rc = close(fd->sf_fd);
 237         free(fd);
 238 
 239         return (rc);
 240 }
 241 
 242 
 243 int
 244 nsc_reserve(fd)
 245 nsc_fd_t *fd;
 246 {
 247         return ((fd) ? ioctl(fd->sf_fd, NSCIOC_RESERVE, 0) : 0);
 248 }
 249 
 250 
 251 int
 252 nsc_release(fd)
 253 nsc_fd_t *fd;
 254 {
 255         if (!fd)
 256                 return (0);
 257 
 258         if (ckdchk && (fd->sf_fmode & O_ACCMODE) != O_RDONLY) {
 259                 errno = EINVAL;
 260                 return (-1);
 261         }
 262 
 263         return (ioctl(fd->sf_fd, NSCIOC_RELEASE, 0));
 264 }
 265 
 266 
 267 int
 268 nsc_partsize(nsc_fd_t *fd, nsc_size_t *rvp)
 269 {
 270         struct nscioc_partsize partsize;
 271         int rc;
 272 
 273         if (!fd)
 274                 return (0);
 275 
 276         rc = ioctl(fd->sf_fd, NSCIOC_PARTSIZE, &partsize);
 277         if (rc != 0) {
 278                 return (rc);
 279         }
 280 
 281         *rvp = (nsc_size_t)partsize.partsize;
 282         return (0);
 283 }
 284 
 285 
 286 int
 287 nsc_fileno(fd)
 288 nsc_fd_t *fd;
 289 {
 290         return ((fd) ? fd->sf_fd : -1);
 291 }
 292 
 293 
 294 void
 295 _nsc_nocheck()
 296 {
 297         ckdchk = 0;
 298 }
 299 
 300 
 301 static int
 302 _nsc_do_ioctl(cmd, arg)
 303 int cmd;
 304 void *arg;
 305 {
 306         int fd, rc, save_errno;
 307 
 308         fd = open(_NSC_DEV_PATH, O_RDONLY);
 309         if (fd < 0)
 310                 return (-1);
 311 
 312         rc = save_errno = 0;
 313         rc = ioctl(fd, cmd, arg);
 314         if (rc < 0)
 315                 save_errno = errno;
 316 
 317         close(fd);
 318 
 319         errno = save_errno;
 320         return (rc);
 321 }
 322 
 323 
 324 /*
 325  * int
 326  * nsc_freeze(char *path)
 327  *      Freeze a pathname
 328  *
 329  * Calling/Exit State:
 330  *      Returns 0 for success, or -1 and sets errno.
 331  *
 332  * Description:
 333  *      This is the user level interface to the nsctl freeze operation.
 334  *      See uts/common/ns/nsctl/nsc_freeze.c for more information.
 335  */
 336 int
 337 nsc_freeze(path)
 338 char *path;
 339 {
 340         if (strlen(path) >= NSC_MAXPATH) {
 341                 errno = ENAMETOOLONG;
 342                 return (-1);
 343         }
 344 
 345         return (_nsc_do_ioctl(NSCIOC_FREEZE, path));
 346 }
 347 
 348 /*
 349  * int
 350  * nsc_unfreeze(char *path)
 351  *      Unfreeze a pathname
 352  *
 353  * Calling/Exit State:
 354  *      Returns 0 for success, or -1 and sets errno.
 355  *
 356  * Description:
 357  *      This is the user level interface to the nsctl unfreeze operation.
 358  *      See uts/common/ns/nsctl/nsc_freeze.c for more information.
 359  */
 360 int
 361 nsc_unfreeze(path)
 362 char *path;
 363 {
 364         if (strlen(path) >= NSC_MAXPATH) {
 365                 errno = ENAMETOOLONG;
 366                 return (-1);
 367         }
 368 
 369         return (_nsc_do_ioctl(NSCIOC_UNFREEZE, path));
 370 }
 371 
 372 
 373 /*
 374  * int
 375  * nsc_isfrozen(char *path)
 376  *      Test if a pathname is frozen
 377  *
 378  * Calling/Exit State:
 379  *      Returns:
 380  *              0       path is frozen
 381  *              1       path is not frozen
 382  *              -1      error (errno will be set)
 383  *
 384  * Description
 385  *      This is the user level interface to to the nsctl isfrozen operation.
 386  *      See uts/common/ns/nsctl/nsc_freeze.c for more information.
 387  */
 388 int
 389 nsc_isfrozen(path)
 390 char *path;
 391 {
 392         if (strlen(path) >= NSC_MAXPATH) {
 393                 errno = ENAMETOOLONG;
 394                 return (-1);
 395         }
 396 
 397         return (_nsc_do_ioctl(NSCIOC_ISFROZEN, path));
 398 }
 399 
 400 int
 401 nsc_gmem_sizes(int *size)
 402 {
 403         return (_nsc_do_ioctl(NSCIOC_GLOBAL_SIZES, size));
 404 }
 405 
 406 int
 407 nsc_gmem_data(char *addr)
 408 {
 409         return (_nsc_do_ioctl(NSCIOC_GLOBAL_DATA, addr));
 410 }
 411 
 412 /*
 413  * int
 414  * nsc_nvclean()
 415  *      mark nvmem clean, to prevent a warmstart of the cache on reboot
 416  */
 417 int
 418 nsc_nvclean(int force)
 419 {
 420         int cmd;
 421 
 422         cmd = force ? NSCIOC_NVMEM_CLEANF : NSCIOC_NVMEM_CLEAN;
 423 
 424         return (_nsc_do_ioctl(cmd, (void *)0));
 425 }