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 *
nsc_open(path,flag,mode)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 *
nsc_fdopen(id,path,mode)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
_nsc_open_path(fd)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
_nsc_open_check(fd)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
nsc_close(fd)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
nsc_reserve(fd)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
nsc_release(fd)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
nsc_partsize(nsc_fd_t * fd,nsc_size_t * rvp)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
nsc_fileno(fd)287 nsc_fileno(fd)
288 nsc_fd_t *fd;
289 {
290 return ((fd) ? fd->sf_fd : -1);
291 }
292
293
294 void
_nsc_nocheck()295 _nsc_nocheck()
296 {
297 ckdchk = 0;
298 }
299
300
301 static int
_nsc_do_ioctl(cmd,arg)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
nsc_freeze(path)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
nsc_unfreeze(path)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
nsc_isfrozen(path)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
nsc_gmem_sizes(int * size)401 nsc_gmem_sizes(int *size)
402 {
403 return (_nsc_do_ioctl(NSCIOC_GLOBAL_SIZES, size));
404 }
405
406 int
nsc_gmem_data(char * addr)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
nsc_nvclean(int force)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 }
426