Annotation of sys/xfs/xfs_syscalls-common.c, Revision 1.1.1.1
1.1 nbrk 1: /*
2: * Copyright (c) 1995 - 2002 Kungliga Tekniska Högskolan
3: * (Royal Institute of Technology, Stockholm, Sweden).
4: * All rights reserved.
5: *
6: * Redistribution and use in source and binary forms, with or without
7: * modification, are permitted provided that the following conditions
8: * are met:
9: *
10: * 1. Redistributions of source code must retain the above copyright
11: * notice, this list of conditions and the following disclaimer.
12: *
13: * 2. Redistributions in binary form must reproduce the above copyright
14: * notice, this list of conditions and the following disclaimer in the
15: * documentation and/or other materials provided with the distribution.
16: *
17: * 3. Neither the name of the Institute nor the names of its contributors
18: * may be used to endorse or promote products derived from this software
19: * without specific prior written permission.
20: *
21: * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
22: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24: * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
25: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31: * SUCH DAMAGE.
32: */
33:
34: #include <xfs/xfs_locl.h>
35:
36: RCSID("$arla: xfs_syscalls-common.c,v 1.72 2003/01/19 20:53:49 lha Exp $");
37:
38: /*
39: * NNPFS system calls.
40: */
41:
42: #include <xfs/xfs_syscalls.h>
43: #include <xfs/xfs_message.h>
44: #include <xfs/xfs_fs.h>
45: #include <xfs/xfs_dev.h>
46: #include <xfs/xfs_node.h>
47: #include <xfs/xfs_vfsops.h>
48: #include <xfs/xfs_deb.h>
49:
50: /* Misc syscalls */
51: #ifdef HAVE_SYS_IOCCOM_H
52: #include <sys/ioccom.h>
53: #elif defined(HAVE_SYS_IOCTL_H)
54: #include <sys/ioctl.h>
55: #endif
56: /*
57: * XXX - horrible kludge. If we are openbsd and not building an lkm,
58: * then use their headerfile.
59: */
60: #if (defined(__OpenBSD__) || defined(__NetBSD__)) && !defined(_LKM)
61: #define NNPFS_NOT_LKM 1
62: #elif defined(__FreeBSD__) && !defined(KLD_MODULE)
63: #define NNPFS_NOT_LKM 1
64: #endif
65:
66: #ifdef NNPFS_NOT_LKM
67: #include <xfs/xfs_pioctl.h>
68: #else
69: #include <kafs.h>
70: #endif
71:
72: int (*old_setgroups_func)(syscall_d_thread_t *p, void *v, register_t *retval);
73:
74: #if defined(__FreeBSD__) && __FreeBSD_version >= 500026
75: /*
76: * XXX This is wrong
77: */
78: static struct ucred *
79: xfs_crcopy(struct ucred *cr)
80: {
81: struct ucred *ncr;
82:
83: if (crshared(cr)) {
84: ncr = crdup(cr);
85: crfree(cr);
86: return ncr;
87: }
88: return cr;
89: }
90: #else
91: #define xfs_crcopy crcopy
92: #endif
93:
94:
95: /*
96: * the syscall entry point
97: */
98:
99: #ifdef NNPFS_NOT_LKM
100: int
101: sys_xfspioctl(syscall_d_thread_t *proc, void *varg, register_t *return_value)
102: #else
103: int
104: xfspioctl(syscall_d_thread_t *proc, void *varg, register_t *return_value)
105: #endif
106: {
107: #ifdef NNPFS_NOT_LKM
108: struct sys_xfspioctl_args *arg = (struct sys_xfspioctl_args *) varg;
109: #else
110: struct sys_pioctl_args *arg = (struct sys_pioctl_args *) varg;
111: #endif
112: int error = EINVAL;
113:
114: switch (SCARG(arg, operation)) {
115: case AFSCALL_PIOCTL:
116: error = xfs_pioctl_call(syscall_thread_to_thread(proc),
117: varg, return_value);
118: break;
119: case AFSCALL_SETPAG:
120: #ifdef HAVE_FREEBSD_THREAD
121: error = xfs_setpag_call(&xfs_thread_to_cred(proc));
122: #else
123: error = xfs_setpag_call(&xfs_proc_to_cred(syscall_thread_to_thread(proc)));
124: #endif
125: break;
126: default:
127: NNPFSDEB(XDEBSYS, ("Unimplemeted xfspioctl: %d\n",
128: SCARG(arg, operation)));
129: error = EINVAL;
130: break;
131: }
132:
133: return error;
134: }
135:
136: /*
137: * Def pag:
138: * 33536 <= g0 <= 34560
139: * 32512 <= g1 <= 48896
140: */
141:
142: #define NNPFS_PAG1_LLIM 33536
143: #define NNPFS_PAG1_ULIM 34560
144: #define NNPFS_PAG2_LLIM 32512
145: #define NNPFS_PAG2_ULIM 48896
146:
147: static gid_t pag_part_one = NNPFS_PAG1_LLIM;
148: static gid_t pag_part_two = NNPFS_PAG2_LLIM;
149:
150: /*
151: * Is `cred' member of a PAG?
152: */
153:
154: static int
155: xfs_is_pag(struct ucred *cred)
156: {
157: /* The first group is the gid of the user ? */
158:
159: if (cred->cr_ngroups >= 3 &&
160: cred->cr_groups[1] >= NNPFS_PAG1_LLIM &&
161: cred->cr_groups[1] <= NNPFS_PAG1_ULIM &&
162: cred->cr_groups[2] >= NNPFS_PAG2_LLIM &&
163: cred->cr_groups[2] <= NNPFS_PAG2_ULIM)
164: return 1;
165: else
166: return 0;
167: }
168:
169: /*
170: * Return the pag used by `cred'
171: */
172:
173: xfs_pag_t
174: xfs_get_pag(struct ucred *cred)
175: {
176: if (xfs_is_pag(cred)) {
177:
178: return (((cred->cr_groups[1] << 16) & 0xFFFF0000) |
179: ((cred->cr_groups[2] & 0x0000FFFF)));
180:
181: } else
182: return cred->cr_uid; /* XXX */
183: }
184:
185: /*
186: * Set the pag in `ret_cred' and return a new cred.
187: */
188:
189: static int
190: store_pag (struct ucred **ret_cred, gid_t part1, gid_t part2)
191: {
192: struct ucred *cred = *ret_cred;
193:
194: if (!xfs_is_pag (cred)) {
195: int i;
196:
197: if (cred->cr_ngroups + 2 >= NGROUPS)
198: return E2BIG;
199:
200: cred = xfs_crcopy (cred);
201:
202: for (i = cred->cr_ngroups - 1; i > 0; i--) {
203: cred->cr_groups[i + 2] = cred->cr_groups[i];
204: }
205: cred->cr_ngroups += 2;
206: } else {
207: cred = xfs_crcopy (cred);
208: }
209: cred->cr_groups[1] = part1;
210: cred->cr_groups[2] = part2;
211: *ret_cred = cred;
212:
213: return 0;
214: }
215:
216: /*
217: * Acquire a new pag in `ret_cred'
218: */
219:
220: int
221: xfs_setpag_call(struct ucred **ret_cred)
222: {
223: int ret;
224:
225: ret = store_pag (ret_cred, pag_part_one, pag_part_two++);
226: if (ret)
227: return ret;
228:
229: if (pag_part_two > NNPFS_PAG2_ULIM) {
230: pag_part_one++;
231: pag_part_two = NNPFS_PAG2_LLIM;
232: }
233: return 0;
234: }
235:
236: #ifndef NNPFS_NOT_LKM
237: /*
238: * remove a pag
239: */
240:
241: static int
242: xfs_unpag (struct ucred *cred)
243: {
244: while (xfs_is_pag (cred)) {
245: int i;
246:
247: for (i = 0; i < cred->cr_ngroups - 2; ++i)
248: cred->cr_groups[i] = cred->cr_groups[i+2];
249: cred->cr_ngroups -= 2;
250: }
251: return 0;
252: }
253:
254: /*
255: * A wrapper around setgroups that preserves the pag.
256: */
257:
258: int
259: xfs_setgroups (syscall_d_thread_t *p,
260: void *varg,
261: register_t *retval)
262: {
263: struct xfs_setgroups_args *uap = (struct xfs_setgroups_args *)varg;
264: #ifdef HAVE_FREEBSD_THREAD
265: struct ucred **cred = &xfs_thread_to_cred(p);
266: #else
267: struct ucred **cred = &xfs_proc_to_cred(syscall_thread_to_thread(p));
268: #endif
269:
270: if (xfs_is_pag (*cred)) {
271: gid_t part1, part2;
272: int ret;
273:
274: if (SCARG(uap,gidsetsize) + 2 > NGROUPS)
275: return EINVAL;
276:
277: part1 = (*cred)->cr_groups[1];
278: part2 = (*cred)->cr_groups[2];
279: ret = (*old_setgroups_func) (p, uap, retval);
280: if (ret)
281: return ret;
282: return store_pag (cred, part1, part2);
283: } else {
284: int ret;
285:
286: ret = (*old_setgroups_func) (p, uap, retval);
287: /* don't support setting a PAG */
288: if (xfs_is_pag (*cred)) {
289: xfs_unpag (*cred);
290: return EINVAL;
291: }
292: return ret;
293: }
294: }
295: #endif /* !NNPFS_NOT_LKM */
296:
297: /*
298: * Return the vnode corresponding to `pathptr'
299: */
300:
301: static int
302: lookup_node (const char *pathptr,
303: int follow_links_p,
304: struct vnode **res,
305: d_thread_t *proc)
306: {
307: int error;
308: char path[MAXPATHLEN];
309: #ifdef __osf__
310: struct nameidata *ndp = &u.u_nd;
311: #else
312: struct nameidata nd, *ndp = &nd;
313: #endif
314: struct vnode *vp;
315: size_t count;
316:
317: NNPFSDEB(XDEBSYS, ("xfs_syscall: looking up: %lx\n",
318: (unsigned long)pathptr));
319:
320: error = copyinstr((char *) pathptr, path, MAXPATHLEN, &count);
321:
322: NNPFSDEB(XDEBSYS, ("xfs_syscall: looking up: %s, error: %d\n", path, error));
323:
324: if (error)
325: return error;
326:
327: NDINIT(ndp, LOOKUP,
328: follow_links_p ? FOLLOW : 0,
329: UIO_SYSSPACE, path, proc);
330:
331: error = namei(ndp);
332:
333: if (error != 0) {
334: NNPFSDEB(XDEBSYS, ("xfs_syscall: error during namei: %d\n", error));
335: return EINVAL;
336: }
337:
338: vp = ndp->ni_vp;
339:
340: *res = vp;
341: return 0;
342: }
343:
344: /*
345: * implement xfs fhget in a way that should be compatible with the native
346: * getfh
347: */
348:
349: static int
350: getfh_compat (d_thread_t *p,
351: struct ViceIoctl *vice_ioctl,
352: struct vnode *vp)
353: {
354: /* This is to be same as getfh */
355: fhandle_t fh;
356: int error;
357:
358: bzero((caddr_t)&fh, sizeof(fh));
359: fh.fh_fsid = vp->v_mount->mnt_stat.f_fsid;
360: #if __osf__
361: VFS_VPTOFH(vp, &fh.fh_fid, error);
362: #else
363: error = VFS_VPTOFH(vp, &fh.fh_fid);
364: #endif
365: if (error)
366: return error;
367:
368: if (vice_ioctl->out_size < sizeof(fh))
369: return EINVAL;
370:
371: return copyout((caddr_t)&fh, vice_ioctl->out, sizeof (fh));
372: }
373:
374: /*
375: * implement xfs fhget by combining (dev, ino, generation)
376: */
377:
378: #ifndef __OpenBSD__
379: static int
380: trad_fhget (d_thread_t *p,
381: struct ViceIoctl *vice_ioctl,
382: struct vnode *vp)
383: {
384: int error;
385: struct mount *mnt;
386: struct vattr vattr;
387: size_t len;
388: struct xfs_fhandle_t xfs_handle;
389: struct xfs_fh_args fh_args;
390:
391: #ifdef HAVE_FREEBSD_THREAD
392: xfs_vop_getattr(vp, &vattr, xfs_thread_to_cred(p), p, error);
393: #else
394: xfs_vop_getattr(vp, &vattr, xfs_proc_to_cred(p), p, error);
395: #endif
396: if (error)
397: return error;
398:
399: mnt = vp->v_mount;
400:
401: SCARG(&fh_args, fsid) = mnt->mnt_stat.f_fsid;
402: SCARG(&fh_args, fileid) = vattr.va_fileid;
403: SCARG(&fh_args, gen) = vattr.va_gen;
404:
405: xfs_handle.len = sizeof(fh_args);
406: memcpy (xfs_handle.fhdata, &fh_args, sizeof(fh_args));
407: len = sizeof(xfs_handle);
408:
409: if (vice_ioctl->out_size < len)
410: return EINVAL;
411:
412: error = copyout (&xfs_handle, vice_ioctl->out, len);
413: if (error) {
414: NNPFSDEB(XDEBSYS, ("fhget_call: copyout failed: %d\n", error));
415: }
416: return error;
417: }
418: #endif /* ! __OpenBSD__ */
419:
420: /*
421: * return file handle of `vp' in vice_ioctl->out
422: * vp is vrele:d
423: */
424:
425: static int
426: fhget_call (d_thread_t *p,
427: struct ViceIoctl *vice_ioctl,
428: struct vnode *vp)
429: {
430: int error;
431:
432: NNPFSDEB(XDEBSYS, ("fhget_call\n"));
433:
434: if (vp == NULL)
435: return EBADF;
436:
437: #if defined(__APPLE__) || defined(__osf__)
438: error = EINVAL; /* XXX: Leaks vnodes if fhget/fhopen is used */
439: goto out;
440: #endif
441:
442: error = xfs_suser (p);
443: if (error)
444: goto out;
445:
446: #if (defined(HAVE_GETFH) && defined(HAVE_FHOPEN)) || defined(__osf__)
447: error = getfh_compat (p, vice_ioctl, vp);
448: #else
449: error = trad_fhget (p, vice_ioctl, vp);
450: #endif /* HAVE_GETFH && HAVE_FHOPEN */
451: out:
452: vrele(vp);
453: return error;
454: }
455:
456: /*
457: * open the file specified in `vice_ioctl->in'
458: */
459:
460: static int
461: fhopen_call (d_thread_t *p,
462: struct ViceIoctl *vice_ioctl,
463: struct vnode *vp,
464: int flags,
465: register_t *retval)
466: {
467:
468: NNPFSDEB(XDEBSYS, ("fhopen_call: flags = %d\n", flags));
469:
470: if (vp != NULL) {
471: vrele (vp);
472: return EINVAL;
473: }
474:
475: #if defined(__APPLE__) || defined(__osf__)
476: return EINVAL; /* XXX: Leaks vnodes if fhget/fhopen is used */
477: #endif
478:
479: return xfs_fhopen (p,
480: (struct xfs_fhandle_t *)vice_ioctl->in,
481: flags,
482: retval);
483: }
484:
485: /*
486: * Send the pioctl to arlad
487: */
488:
489: static int
490: remote_pioctl (d_thread_t *p,
491: struct sys_pioctl_args *arg,
492: struct ViceIoctl *vice_ioctl,
493: struct vnode *vp)
494: {
495: int error = 0;
496: struct xfs_message_pioctl *msg = NULL;
497: struct xfs_message_wakeup_data *msg2;
498:
499: msg = malloc(sizeof(struct xfs_message_symlink), M_TEMP, M_WAITOK);
500: if (msg == NULL) {
501: error = ENOMEM;
502: goto done;
503: }
504: memset(msg, 0, sizeof(*msg));
505:
506: if (vp != NULL) {
507: struct xfs_node *xn;
508:
509: if (vp->v_tag != VT_XFS) {
510: NNPFSDEB(XDEBSYS, ("xfs_syscall: file is not in afs\n"));
511: vrele(vp);
512: error = EINVAL;
513: goto done;
514: }
515:
516: xn = VNODE_TO_XNODE(vp);
517:
518: msg->handle = xn->handle;
519: vrele(vp);
520: }
521:
522: if (vice_ioctl->in_size < 0) {
523: printf("xfs: remote pioctl: got a negative data size: opcode: %d",
524: SCARG(arg, a_opcode));
525: error = EINVAL;
526: goto done;
527: }
528:
529: if (vice_ioctl->in_size > NNPFS_MSG_MAX_DATASIZE) {
530: printf("xfs_pioctl_call: got a humongous in packet: opcode: %d",
531: SCARG(arg, a_opcode));
532: error = EINVAL;
533: goto done;
534: }
535: if (vice_ioctl->in_size != 0) {
536: error = copyin(vice_ioctl->in, msg->msg, vice_ioctl->in_size);
537: if (error)
538: goto done;
539: }
540:
541: msg->header.opcode = NNPFS_MSG_PIOCTL;
542: msg->header.size = sizeof(*msg);
543: msg->opcode = SCARG(arg, a_opcode);
544:
545: msg->insize = vice_ioctl->in_size;
546: msg->outsize = vice_ioctl->out_size;
547: #ifdef HAVE_FREEBSD_THREAD
548: msg->cred.uid = xfs_thread_to_euid(p);
549: msg->cred.pag = xfs_get_pag(xfs_thread_to_cred(p));
550: #else
551: msg->cred.uid = xfs_proc_to_euid(p);
552: msg->cred.pag = xfs_get_pag(xfs_proc_to_cred(p));
553: #endif
554:
555: error = xfs_message_rpc(0, &(msg->header), sizeof(*msg), p); /* XXX */
556: msg2 = (struct xfs_message_wakeup_data *) msg;
557:
558: if (error == 0)
559: error = msg2->error;
560: if (error == ENODEV)
561: error = EINVAL;
562:
563: if (error == 0 && msg2->header.opcode == NNPFS_MSG_WAKEUP_DATA) {
564: int len;
565:
566: len = msg2->len;
567: if (len > vice_ioctl->out_size)
568: len = vice_ioctl->out_size;
569: if (len > NNPFS_MSG_MAX_DATASIZE)
570: len = NNPFS_MSG_MAX_DATASIZE;
571: if (len < 0)
572: len = 0;
573:
574: error = copyout(msg2->msg, vice_ioctl->out, len);
575: }
576: done:
577: free(msg, M_TEMP);
578: return error;
579: }
580:
581: static int
582: xfs_debug (d_thread_t *p,
583: struct ViceIoctl *vice_ioctl)
584: {
585: int32_t flags;
586: int error;
587:
588: if (vice_ioctl->in_size != 0) {
589: if (vice_ioctl->in_size < sizeof(int32_t))
590: return EINVAL;
591:
592: error = xfs_suser (p);
593: if (error)
594: return error;
595:
596: error = copyin (vice_ioctl->in,
597: &flags,
598: sizeof(flags));
599: if (error)
600: return error;
601:
602: xfsdeb = flags;
603: }
604:
605: if (vice_ioctl->out_size != 0) {
606: if (vice_ioctl->out_size < sizeof(int32_t))
607: return EINVAL;
608:
609: error = copyout (&xfsdeb,
610: vice_ioctl->out,
611: sizeof(int32_t));
612: if (error)
613: return error;
614: }
615:
616: return 0;
617: }
618:
619:
620: /*
621: * Handle `pioctl'
622: */
623:
624: int
625: xfs_pioctl_call(d_thread_t *proc,
626: struct sys_pioctl_args *arg,
627: register_t *return_value)
628: {
629: int error;
630: struct ViceIoctl vice_ioctl;
631: char *pathptr;
632: struct vnode *vp = NULL;
633:
634: NNPFSDEB(XDEBSYS, ("xfs_syscall(%d, %lx, %d, %lx, %d)\n",
635: SCARG(arg, operation),
636: (unsigned long)SCARG(arg, a_pathP),
637: SCARG(arg, a_opcode),
638: (unsigned long)SCARG(arg, a_paramsP),
639: SCARG(arg, a_followSymlinks)));
640:
641: /* Copy in the data structure for us */
642:
643: error = copyin(SCARG(arg, a_paramsP),
644: &vice_ioctl,
645: sizeof(vice_ioctl));
646:
647: if (error)
648: return error;
649:
650: pathptr = SCARG(arg, a_pathP);
651:
652: if (pathptr != NULL) {
653: error = lookup_node (pathptr, SCARG(arg, a_followSymlinks), &vp,
654: proc);
655: if(error)
656: return error;
657: }
658:
659: switch (SCARG(arg, a_opcode)) {
660: case VIOC_FHGET :
661: return fhget_call (proc, &vice_ioctl, vp);
662: case VIOC_FHOPEN :
663: return fhopen_call (proc, &vice_ioctl, vp,
664: SCARG(arg, a_followSymlinks), return_value);
665: case VIOC_XFSDEBUG :
666: if (vp != NULL)
667: vrele (vp);
668: return xfs_debug (proc, &vice_ioctl);
669: default :
670: NNPFSDEB(XDEBSYS, ("a_opcode = %x\n", SCARG(arg, a_opcode)));
671: return remote_pioctl (proc, arg, &vice_ioctl, vp);
672: }
673: }
CVSweb