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 }