22dcfb047ac35752396b387449f10e99226f88dd
[openafs.git] / src / afs / DARWIN / osi_misc.c
1 /*
2  * Copyright 2000, International Business Machines Corporation and others.
3  * All Rights Reserved.
4  * 
5  * This software has been released under the terms of the IBM Public
6  * License.  For details, see the LICENSE file in the top-level source
7  * directory or online at http://www.openafs.org/dl/license10.html
8  */
9
10 #include <afsconfig.h>
11 #include "afs/param.h"
12
13
14 #include "afs/sysincludes.h"
15 #include "afsincludes.h"
16 #include <sys/namei.h>
17
18 #ifndef PATHBUFLEN
19 #define PATHBUFLEN 256
20 #endif
21
22 #ifdef AFS_DARWIN80_ENV
23 static thread_t vfs_context_owner;
24
25 /* works like PFlushVolumeData */
26 void
27 darwin_notify_perms(struct unixuser *auser, int event)
28 {
29     int i;
30     struct afs_q *tq, *uq = NULL;
31     struct vcache *tvc, *hnext;
32     int isglock = ISAFS_GLOCK();
33     struct vnode *vp;
34     struct vnode_attr va;
35     int isctxtowner = 0;
36
37     if (!afs_darwin_fsevents)
38         return;
39
40     VATTR_INIT(&va);
41     VATTR_SET(&va, va_mode, 0777);
42     if (event & UTokensObtained)
43         VATTR_SET(&va, va_uid, auser->uid);
44     else
45         VATTR_SET(&va, va_uid, -2); /* nobody */
46
47     if (!isglock)
48         AFS_GLOCK();
49     if (!(vfs_context_owner == current_thread())) {
50         get_vfs_context();
51         isctxtowner = 1;
52     }
53 loop:
54     ObtainReadLock(&afs_xvcache);
55     for (i = 0; i < VCSIZE; i++) {
56         for (tq = afs_vhashTV[i].prev; tq != &afs_vhashTV[i]; tq = uq) {
57             uq = QPrev(tq);
58             tvc = QTOVH(tq);
59             if (tvc->f.states & CDeadVnode) {
60                 /* we can afford to be best-effort */
61                 continue;
62             }
63             /* no per-file acls, so only notify on directories */
64             if (!(vp = AFSTOV(tvc)) || !vnode_isdir(AFSTOV(tvc)))
65                 continue;
66             /* dynroot object. no callbacks. anonymous ACL. just no. */
67             if (afs_IsDynrootFid(&tvc->f.fid))
68                 continue;
69             /* no fake fsevents on mount point sources. leaks refs */
70             if (tvc->mvstat == AFS_MVSTAT_MTPT)
71                 continue;
72             /* if it's being reclaimed, just pass */
73             if (vnode_get(vp))
74                 continue;
75             if (vnode_ref(vp)) {
76                 AFS_GUNLOCK();
77                 vnode_put(vp);
78                 AFS_GLOCK();
79                 continue;
80             }
81             ReleaseReadLock(&afs_xvcache);
82             /* Avoid potentially re-entering on this lock */
83             if (0 == NBObtainWriteLock(&tvc->lock, 234)) {
84                 tvc->f.states |= CEvent;
85                 AFS_GUNLOCK();
86                 vnode_setattr(vp, &va, afs_osi_ctxtp);
87                 tvc->f.states &= ~CEvent;
88                 vnode_put(vp);
89                 AFS_GLOCK();
90                 ReleaseWriteLock(&tvc->lock);
91             } else {
92                 AFS_GUNLOCK();
93                 vnode_put(vp);
94                 AFS_GLOCK();
95             }
96             ObtainReadLock(&afs_xvcache);
97             uq = QPrev(tq);
98             /* our tvc ptr is still good until now */
99             AFS_FAST_RELE(tvc);
100         }
101     }
102     ReleaseReadLock(&afs_xvcache);
103     if (isctxtowner)
104         put_vfs_context();
105     if (!isglock)
106         AFS_GUNLOCK();
107 }
108
109 int
110 osi_lookupname_user(user_addr_t aname, enum uio_seg seg, int followlink,
111                     struct vnode **vpp) {
112     char tname[PATHBUFLEN];
113     size_t len;
114     int code;
115
116     if (seg == AFS_UIOUSER) { /* XXX 64bit */
117         AFS_COPYINSTR(aname, tname, sizeof(tname), &len, code);
118         if (code)
119             return code;
120         return osi_lookupname(tname, seg, followlink, vpp);
121     } else
122         return osi_lookupname(CAST_DOWN(char *, aname), seg, followlink, vpp);
123
124 }
125
126 int
127 osi_lookupname(char *aname, enum uio_seg seg, int followlink,
128                struct vnode **vpp) {
129     vfs_context_t ctx;
130     int code, flags;
131
132     flags = 0;
133     if (!followlink)
134         flags |= VNODE_LOOKUP_NOFOLLOW;
135     ctx=vfs_context_create(NULL);
136     code = vnode_lookup(aname, flags, vpp, ctx);
137     if (!code) { /* get a usecount */
138         vnode_ref(*vpp);
139         vnode_put(*vpp);
140     }
141     vfs_context_rele(ctx);
142     return code;
143 }
144 #else
145 int
146 osi_lookupname(char *aname, enum uio_seg seg, int followlink,
147                struct vnode **vpp)
148 {
149     struct nameidata n;
150     int flags, error;
151     flags = 0;
152     flags = LOCKLEAF;
153     if (followlink)
154         flags |= FOLLOW;
155     else
156         flags |= NOFOLLOW;
157     NDINIT(&n, LOOKUP, flags, seg, aname, current_proc());
158     if (error = namei(&n))
159         return error;
160     *vpp = n.ni_vp;
161    /* should we do this? */
162     VOP_UNLOCK(n.ni_vp, 0, current_proc());
163     return 0;
164 }
165 #endif
166
167 /*
168  * afs_suser() returns true if the caller is superuser, false otherwise.
169  *
170  * Note that it must NOT set errno.
171  */
172 int
173 afs_suser(void *credp)
174 {
175     int error;
176     struct proc *p = current_proc();
177
178 #ifdef AFS_DARWIN80_ENV
179     if ((error = proc_suser(p)) == 0) {
180         return (1);
181     }
182     return (0);
183 #else
184     if ((error = suser(p->p_ucred, &p->p_acflag)) == 0) {
185         return (1);
186     }
187     return (0);
188 #endif
189 }
190
191 #ifdef AFS_DARWIN80_ENV
192 struct uio *
193 afsio_partialcopy(struct uio *auio, size_t size)
194 {
195     struct uio *res;
196     int i;
197     user_addr_t iovaddr;
198     user_size_t iovsize;
199
200     if (proc_is64bit(current_proc())) {
201         res = uio_create(uio_iovcnt(auio), uio_offset(auio),
202                          uio_isuserspace(auio) ? UIO_USERSPACE64 : UIO_SYSSPACE32,
203                          uio_rw(auio));
204     } else {
205         res = uio_create(uio_iovcnt(auio), uio_offset(auio),
206                          uio_isuserspace(auio) ? UIO_USERSPACE32 : UIO_SYSSPACE32,
207                          uio_rw(auio));
208     }
209
210     for (i = 0;i < uio_iovcnt(auio) && size > 0;i++) {
211         if (uio_getiov(auio, i, &iovaddr, &iovsize))
212             break;
213         if (iovsize > size)
214             iovsize = size;
215         if (uio_addiov(res, iovaddr, iovsize))
216             break;
217         size -= iovsize;
218     }
219     return res;
220 }
221
222 vfs_context_t afs_osi_ctxtp;
223 int afs_osi_ctxtp_initialized;
224 static proc_t vfs_context_curproc;
225 int vfs_context_ref;
226
227 void
228 get_vfs_context(void)
229 {
230     int isglock = ISAFS_GLOCK();
231
232     if (!isglock)
233         AFS_GLOCK();
234     if (afs_osi_ctxtp_initialized) {
235         if (!isglock)
236             AFS_GUNLOCK();
237         return;
238     }
239     osi_Assert(vfs_context_owner != current_thread());
240     if (afs_osi_ctxtp && current_proc() == vfs_context_curproc) {
241         vfs_context_ref++;
242         vfs_context_owner = current_thread();
243         if (!isglock)
244             AFS_GUNLOCK();
245         return;
246     }
247     while (afs_osi_ctxtp && vfs_context_ref) {
248         afs_osi_Sleep(&afs_osi_ctxtp);
249         if (afs_osi_ctxtp_initialized) {
250             if (!isglock)
251                 AFS_GUNLOCK();
252             return;
253         }
254     }
255     vfs_context_rele(afs_osi_ctxtp);
256     vfs_context_ref=1;
257     afs_osi_ctxtp = vfs_context_create(NULL);
258     vfs_context_owner = current_thread();
259     vfs_context_curproc = current_proc();
260     if (!isglock)
261         AFS_GUNLOCK();
262 }
263
264 void
265 put_vfs_context(void)
266 {
267     int isglock = ISAFS_GLOCK();
268
269     if (!isglock)
270         AFS_GLOCK();
271     if (afs_osi_ctxtp_initialized) {
272         if (!isglock)
273             AFS_GUNLOCK();
274         return;
275     }
276     if (vfs_context_owner == current_thread())
277         vfs_context_owner = (thread_t)0;
278     vfs_context_ref--;
279     afs_osi_Wakeup(&afs_osi_ctxtp);
280     if (!isglock)
281         AFS_GUNLOCK();
282 }
283
284 int
285 afs_cdev_nop_openclose(dev_t dev, int flags, int devtype,struct proc *p)
286 {
287     return 0;
288 }
289
290 int
291 afs_cdev_ioctl(dev_t dev, u_long cmd, caddr_t data, int fflag, struct proc *p) {
292     unsigned int retval=0;
293     int code, is64 = proc_is64bit(p);
294     struct afssysargs *a = (struct afssysargs *)data;
295     struct afssysargs64 *a64 = (struct afssysargs64 *)data;
296
297     if (((unsigned int)cmd != VIOC_SYSCALL) &&
298         ((unsigned int)cmd != VIOC_SYSCALL64))
299         return EINVAL;
300
301     if (((unsigned int)cmd == VIOC_SYSCALL64) && (is64 == 0))
302         return EINVAL;
303
304     if (((unsigned int)cmd == VIOC_SYSCALL) && (is64 != 0))
305         return EINVAL;
306     
307     code=afs3_syscall(p, data, &retval);
308     if (code)
309         return code;
310
311     if ((!is64) && retval && a->syscall != AFSCALL_CALL
312         && a->param1 != AFSOP_CACHEINODE)
313     {
314         printf("SSCall(%d,%d) is returning non-error value %d\n", a->syscall, a->param1, retval);
315     }
316     if ((is64) && retval && a64->syscall != AFSCALL_CALL
317         && a64->param1 != AFSOP_CACHEINODE)
318     {
319         printf("SSCall(%d,%llx) is returning non-error value %d\n", a64->syscall, a64->param1, retval);
320     }
321
322     if (!is64)
323         a->retval = retval;
324     else
325         a64->retval = retval;
326     return 0; 
327 }
328
329 #endif