Change wiki ref to wiki.openafs.org from stanford.edu
[openafs.git] / src / afs / afs_pioctl.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"    /* Standard vendor system headers */
15 #ifdef AFS_OBSD_ENV
16 #include "h/syscallargs.h"
17 #endif
18 #ifdef AFS_FBSD_ENV
19 #include "h/sysproto.h"
20 #endif
21 #ifdef AFS_NBSD40_ENV
22 #include <sys/ioctl.h>
23 #include <sys/ioccom.h>
24 #endif
25 #include "afsincludes.h"        /* Afs-based standard headers */
26 #include "afs/afs_stats.h"      /* afs statistics */
27 #include "afs/vice.h"
28 #include "afs/afs_bypasscache.h"
29 #include "rx/rx_globals.h"
30 #include "token.h"
31
32 struct VenusFid afs_rootFid;
33 afs_int32 afs_waitForever = 0;
34 short afs_waitForeverCount = 0;
35 afs_int32 afs_showflags = GAGUSER | GAGCONSOLE; /* show all messages */
36
37 afs_int32 afs_is_disconnected;
38 afs_int32 afs_is_discon_rw;
39 /* On reconnection, turn this knob on until it finishes,
40  * then turn it off.
41  */
42 afs_int32 afs_in_sync = 0;
43
44 struct afs_pdata {
45     char *ptr;
46     size_t remaining;
47 };
48
49 /*
50  * A set of handy little functions for encoding and decoding
51  * pioctls without losing your marbles, or memory integrity
52  */
53
54 static_inline int
55 afs_pd_alloc(struct afs_pdata *apd, size_t size)
56 {
57
58     if (size > AFS_LRALLOCSIZ)
59         apd->ptr = osi_Alloc(size + 1);
60     else
61         apd->ptr = osi_AllocLargeSpace(AFS_LRALLOCSIZ);
62
63     if (apd->ptr == NULL)
64         return ENOMEM;
65
66     apd->remaining = size;
67
68     return 0;
69 }
70
71 static_inline void
72 afs_pd_free(struct afs_pdata *apd)
73 {
74     if (apd->ptr == NULL)
75         return;
76
77     if (apd->remaining > AFS_LRALLOCSIZ)
78         osi_Free(apd->ptr, apd->remaining + 1);
79     else
80         osi_FreeLargeSpace(apd->ptr);
81
82     apd->ptr = NULL;
83     apd->remaining = 0;
84 }
85
86 static_inline char *
87 afs_pd_where(struct afs_pdata *apd)
88 {
89     return apd ? apd->ptr : NULL;
90 }
91
92 static_inline size_t
93 afs_pd_remaining(struct afs_pdata *apd)
94 {
95     return apd ? apd->remaining : 0;
96 }
97
98 static_inline int
99 afs_pd_skip(struct afs_pdata *apd, size_t skip)
100 {
101     if (apd == NULL || apd->remaining < skip)
102         return EINVAL;
103     apd->remaining -= skip;
104     apd->ptr += skip;
105
106     return 0;
107 }
108
109 static_inline int
110 afs_pd_getBytes(struct afs_pdata *apd, void *dest, size_t bytes)
111 {
112     if (apd == NULL || apd->remaining < bytes)
113         return EINVAL;
114     apd->remaining -= bytes;
115     memcpy(dest, apd->ptr, bytes);
116     apd->ptr += bytes;
117     return 0;
118 }
119
120 static_inline int
121 afs_pd_getInt(struct afs_pdata *apd, afs_int32 *val)
122 {
123     return afs_pd_getBytes(apd, val, sizeof(*val));
124 }
125
126 static_inline int
127 afs_pd_getUint(struct afs_pdata *apd, afs_uint32 *val)
128 {
129     return afs_pd_getBytes(apd, val, sizeof(*val));
130 }
131
132 static_inline void *
133 afs_pd_inline(struct afs_pdata *apd, size_t bytes)
134 {
135     void *ret;
136
137     if (apd == NULL || apd->remaining < bytes)
138         return NULL;
139
140     ret = apd->ptr;
141
142     apd->remaining -= bytes;
143     apd->ptr += bytes;
144
145     return ret;
146 }
147
148 static_inline void
149 afs_pd_xdrStart(struct afs_pdata *apd, XDR *xdrs, enum xdr_op op) {
150     xdrmem_create(xdrs, apd->ptr, apd->remaining, op);
151 }
152
153 static_inline void
154 afs_pd_xdrEnd(struct afs_pdata *apd, XDR *xdrs) {
155     size_t pos;
156
157     pos = xdr_getpos(xdrs);
158     apd->ptr += pos;
159     apd->remaining -= pos;
160     xdr_destroy(xdrs);
161 }
162
163
164
165 static_inline int
166 afs_pd_getString(struct afs_pdata *apd, char *str, size_t maxLen)
167 {
168     size_t len;
169
170     if (apd == NULL || apd->remaining <= 0)
171         return EINVAL;
172     len = strlen(apd->ptr) + 1;
173     if (len > maxLen)
174         return E2BIG;
175     memcpy(str, apd->ptr, len);
176     apd->ptr += len;
177     apd->remaining -= len;
178     return 0;
179 }
180
181 static_inline int
182 afs_pd_getStringPtr(struct afs_pdata *apd, char **str)
183 {
184     size_t len;
185
186     if (apd == NULL || apd->remaining <= 0)
187         return EINVAL;
188     len = strlen(apd->ptr) + 1;
189     *str = apd->ptr;
190     apd->ptr += len;
191     apd->remaining -= len;
192     return 0;
193 }
194
195 static_inline int
196 afs_pd_putBytes(struct afs_pdata *apd, const void *bytes, size_t len)
197 {
198     if (apd == NULL || apd->remaining < len)
199         return E2BIG;
200     memcpy(apd->ptr, bytes, len);
201     apd->ptr += len;
202     apd->remaining -= len;
203     return 0;
204 }
205
206 static_inline int
207 afs_pd_putInt(struct afs_pdata *apd, afs_int32 val)
208 {
209     return afs_pd_putBytes(apd, &val, sizeof(val));
210 }
211
212 static_inline int
213 afs_pd_putString(struct afs_pdata *apd, char *str) {
214
215     /* Add 1 so we copy the NULL too */
216     return afs_pd_putBytes(apd, str, strlen(str) +1);
217 }
218
219 /*!
220  * \defgroup pioctl Path IOCTL functions
221  *
222  * DECL_PIOCTL is a macro defined to contain the following parameters for functions:
223  *
224  * \param[in] avc
225  *      the AFS vcache structure in use by pioctl
226  * \param[in] afun
227  *      not in use
228  * \param[in] areq
229  *      the AFS vrequest structure
230  * \param[in] ain
231  *      an afs_pdata block describing the data received from the caller
232  * \param[in] aout
233  *      an afs_pdata block describing a pre-allocated block for output
234  * \param[in] acred
235  *      UNIX credentials structure underlying the operation
236  */
237
238 #define DECL_PIOCTL(x) \
239         static int x(struct vcache *avc, int afun, struct vrequest *areq, \
240                      struct afs_pdata *ain, struct afs_pdata *aout, \
241                      afs_ucred_t **acred)
242
243 /* Prototypes for pioctl routines */
244 DECL_PIOCTL(PGetFID);
245 DECL_PIOCTL(PSetAcl);
246 DECL_PIOCTL(PStoreBehind);
247 DECL_PIOCTL(PGCPAGs);
248 DECL_PIOCTL(PGetAcl);
249 DECL_PIOCTL(PNoop);
250 DECL_PIOCTL(PBogus);
251 DECL_PIOCTL(PGetFileCell);
252 DECL_PIOCTL(PGetWSCell);
253 DECL_PIOCTL(PGetUserCell);
254 DECL_PIOCTL(PSetTokens);
255 DECL_PIOCTL(PSetTokens2);
256 DECL_PIOCTL(PGetVolumeStatus);
257 DECL_PIOCTL(PSetVolumeStatus);
258 DECL_PIOCTL(PFlush);
259 DECL_PIOCTL(PNewStatMount);
260 DECL_PIOCTL(PGetTokens);
261 DECL_PIOCTL(PGetTokens2);
262 DECL_PIOCTL(PUnlog);
263 DECL_PIOCTL(PMariner);
264 DECL_PIOCTL(PCheckServers);
265 DECL_PIOCTL(PCheckVolNames);
266 DECL_PIOCTL(PCheckAuth);
267 DECL_PIOCTL(PFindVolume);
268 DECL_PIOCTL(PViceAccess);
269 DECL_PIOCTL(PSetCacheSize);
270 DECL_PIOCTL(PGetCacheSize);
271 DECL_PIOCTL(PRemoveCallBack);
272 DECL_PIOCTL(PNewCell);
273 DECL_PIOCTL(PNewAlias);
274 DECL_PIOCTL(PListCells);
275 DECL_PIOCTL(PListAliases);
276 DECL_PIOCTL(PRemoveMount);
277 DECL_PIOCTL(PGetCellStatus);
278 DECL_PIOCTL(PSetCellStatus);
279 DECL_PIOCTL(PFlushVolumeData);
280 DECL_PIOCTL(PGetVnodeXStatus);
281 DECL_PIOCTL(PGetVnodeXStatus2);
282 DECL_PIOCTL(PSetSysName);
283 DECL_PIOCTL(PSetSPrefs);
284 DECL_PIOCTL(PSetSPrefs33);
285 DECL_PIOCTL(PGetSPrefs);
286 DECL_PIOCTL(PExportAfs);
287 DECL_PIOCTL(PGag);
288 DECL_PIOCTL(PTwiddleRx);
289 DECL_PIOCTL(PGetInitParams);
290 DECL_PIOCTL(PGetRxkcrypt);
291 DECL_PIOCTL(PSetRxkcrypt);
292 DECL_PIOCTL(PGetCPrefs);
293 DECL_PIOCTL(PSetCPrefs);
294 DECL_PIOCTL(PFlushMount);
295 DECL_PIOCTL(PRxStatProc);
296 DECL_PIOCTL(PRxStatPeer);
297 DECL_PIOCTL(PPrefetchFromTape);
298 DECL_PIOCTL(PFsCmd);
299 DECL_PIOCTL(PCallBackAddr);
300 DECL_PIOCTL(PDiscon);
301 DECL_PIOCTL(PNFSNukeCreds);
302 DECL_PIOCTL(PNewUuid);
303 DECL_PIOCTL(PPrecache);
304 DECL_PIOCTL(PGetPAG);
305 #if defined(AFS_CACHE_BYPASS) && defined(AFS_LINUX24_ENV)
306 DECL_PIOCTL(PSetCachingThreshold);
307 #endif
308
309 /*
310  * A macro that says whether we're going to need HandleClientContext().
311  * This is currently used only by the nfs translator.
312  */
313 #if !defined(AFS_NONFSTRANS) || defined(AFS_AIX_IAUTH_ENV)
314 #define AFS_NEED_CLIENTCONTEXT
315 #endif
316
317 /* Prototypes for private routines */
318 #ifdef AFS_NEED_CLIENTCONTEXT
319 static int HandleClientContext(struct afs_ioctl *ablob, int *com,
320                                afs_ucred_t **acred,
321                                afs_ucred_t *credp);
322 #endif
323 int HandleIoctl(struct vcache *avc, afs_int32 acom,
324                 struct afs_ioctl *adata);
325 int afs_HandlePioctl(struct vnode *avp, afs_int32 acom,
326                      struct afs_ioctl *ablob, int afollow,
327                      afs_ucred_t **acred);
328 static int Prefetch(uparmtype apath, struct afs_ioctl *adata, int afollow,
329                     afs_ucred_t *acred);
330
331 typedef int (*pioctlFunction) (struct vcache *, int, struct vrequest *,
332                                struct afs_pdata *, struct afs_pdata *,
333                                afs_ucred_t **);
334
335 static pioctlFunction VpioctlSw[] = {
336     PBogus,                     /* 0 */
337     PSetAcl,                    /* 1 */
338     PGetAcl,                    /* 2 */
339     PSetTokens,                 /* 3 */
340     PGetVolumeStatus,           /* 4 */
341     PSetVolumeStatus,           /* 5 */
342     PFlush,                     /* 6 */
343     PBogus,                     /* 7 */
344     PGetTokens,                 /* 8 */
345     PUnlog,                     /* 9 */
346     PCheckServers,              /* 10 */
347     PCheckVolNames,             /* 11 */
348     PCheckAuth,                 /* 12 */
349     PBogus,                     /* 13 -- used to be quick check time */
350     PFindVolume,                /* 14 */
351     PBogus,                     /* 15 -- prefetch is now special-cased; see pioctl code! */
352     PBogus,                     /* 16 -- used to be testing code */
353     PNoop,                      /* 17 -- used to be enable group */
354     PNoop,                      /* 18 -- used to be disable group */
355     PBogus,                     /* 19 -- used to be list group */
356     PViceAccess,                /* 20 */
357     PUnlog,                     /* 21 -- unlog *is* unpag in this system */
358     PGetFID,                    /* 22 -- get file ID */
359     PBogus,                     /* 23 -- used to be waitforever */
360     PSetCacheSize,              /* 24 */
361     PRemoveCallBack,            /* 25 -- flush only the callback */
362     PNewCell,                   /* 26 */
363     PListCells,                 /* 27 */
364     PRemoveMount,               /* 28 -- delete mount point */
365     PNewStatMount,              /* 29 -- new style mount point stat */
366     PGetFileCell,               /* 30 -- get cell name for input file */
367     PGetWSCell,                 /* 31 -- get cell name for workstation */
368     PMariner,                   /* 32 - set/get mariner host */
369     PGetUserCell,               /* 33 -- get cell name for user */
370     PBogus,                     /* 34 -- Enable/Disable logging */
371     PGetCellStatus,             /* 35 */
372     PSetCellStatus,             /* 36 */
373     PFlushVolumeData,           /* 37 -- flush all data from a volume */
374     PSetSysName,                /* 38 - Set system name */
375     PExportAfs,                 /* 39 - Export Afs to remote nfs clients */
376     PGetCacheSize,              /* 40 - get cache size and usage */
377     PGetVnodeXStatus,           /* 41 - get vcache's special status */
378     PSetSPrefs33,               /* 42 - Set CM Server preferences... */
379     PGetSPrefs,                 /* 43 - Get CM Server preferences... */
380     PGag,                       /* 44 - turn off/on all CM messages */
381     PTwiddleRx,                 /* 45 - adjust some RX params       */
382     PSetSPrefs,                 /* 46 - Set CM Server preferences... */
383     PStoreBehind,               /* 47 - set degree of store behind to be done */
384     PGCPAGs,                    /* 48 - disable automatic pag gc-ing */
385     PGetInitParams,             /* 49 - get initial cm params */
386     PGetCPrefs,                 /* 50 - get client interface addresses */
387     PSetCPrefs,                 /* 51 - set client interface addresses */
388     PFlushMount,                /* 52 - flush mount symlink data */
389     PRxStatProc,                /* 53 - control process RX statistics */
390     PRxStatPeer,                /* 54 - control peer RX statistics */
391     PGetRxkcrypt,               /* 55 -- Get rxkad encryption flag */
392     PSetRxkcrypt,               /* 56 -- Set rxkad encryption flag */
393     PBogus,                     /* 57 -- arla: set file prio */
394     PBogus,                     /* 58 -- arla: fallback getfh */
395     PBogus,                     /* 59 -- arla: fallback fhopen */
396     PBogus,                     /* 60 -- arla: controls xfsdebug */
397     PBogus,                     /* 61 -- arla: controls arla debug */
398     PBogus,                     /* 62 -- arla: debug interface */
399     PBogus,                     /* 63 -- arla: print xfs status */
400     PBogus,                     /* 64 -- arla: force cache check */
401     PBogus,                     /* 65 -- arla: break callback */
402     PPrefetchFromTape,          /* 66 -- MR-AFS: prefetch file from tape */
403     PFsCmd,                     /* 67 -- RXOSD: generic commnd interface */
404     PBogus,                     /* 68 -- arla: fetch stats */
405     PGetVnodeXStatus2,          /* 69 - get caller access and some vcache status */
406 };
407
408 static pioctlFunction CpioctlSw[] = {
409     PBogus,                     /* 0 */
410     PNewAlias,                  /* 1 -- create new cell alias */
411     PListAliases,               /* 2 -- list cell aliases */
412     PCallBackAddr,              /* 3 -- request addr for callback rxcon */
413     PBogus,                     /* 4 */
414     PDiscon,                    /* 5 -- get/set discon mode */
415     PBogus,                     /* 6 */
416     PGetTokens2,                /* 7 */
417     PSetTokens2,                /* 8 */
418     PNewUuid,                   /* 9 */
419     PBogus,                     /* 10 */
420     PBogus,                     /* 11 */
421     PPrecache,                  /* 12 */
422     PGetPAG,                    /* 13 */
423 };
424
425 static pioctlFunction OpioctlSw[]  = {
426     PBogus,                     /* 0 */
427     PNFSNukeCreds,              /* 1 -- nuke all creds for NFS client */
428 #if defined(AFS_CACHE_BYPASS) && defined(AFS_LINUX24_ENV)
429     PSetCachingThreshold        /* 2 -- get/set cache-bypass size threshold */
430 #else
431     PNoop                       /* 2 -- get/set cache-bypass size threshold */
432 #endif
433 };
434
435 #define PSetClientContext 99    /*  Special pioctl to setup caller's creds  */
436 int afs_nobody = NFS_NOBODY;
437
438 int
439 HandleIoctl(struct vcache *avc, afs_int32 acom,
440             struct afs_ioctl *adata)
441 {
442     afs_int32 code;
443
444     code = 0;
445     AFS_STATCNT(HandleIoctl);
446
447     switch (acom & 0xff) {
448     case 1:
449         avc->f.states |= CSafeStore;
450         avc->asynchrony = 0;
451         /* SXW - Should we force a MetaData flush for this flag setting */
452         break;
453
454         /* case 2 used to be abort store, but this is no longer provided,
455          * since it is impossible to implement under normal Unix.
456          */
457
458     case 3:{
459             /* return the name of the cell this file is open on */
460             struct cell *tcell;
461             afs_int32 i;
462
463             tcell = afs_GetCell(avc->f.fid.Cell, READ_LOCK);
464             if (tcell) {
465                 i = strlen(tcell->cellName) + 1;        /* bytes to copy out */
466
467                 if (i > adata->out_size) {
468                     /* 0 means we're not interested in the output */
469                     if (adata->out_size != 0)
470                         code = EFAULT;
471                 } else {
472                     /* do the copy */
473                     AFS_COPYOUT(tcell->cellName, adata->out, i, code);
474                 }
475                 afs_PutCell(tcell, READ_LOCK);
476             } else
477                 code = ENOTTY;
478         }
479         break;
480
481     case 49:                    /* VIOC_GETINITPARAMS */
482         if (adata->out_size < sizeof(struct cm_initparams)) {
483             code = EFAULT;
484         } else {
485             AFS_COPYOUT(&cm_initParams, adata->out,
486                         sizeof(struct cm_initparams), code);
487         }
488         break;
489
490     default:
491
492         code = EINVAL;
493 #ifdef AFS_AIX51_ENV
494         code = ENOSYS;
495 #endif
496         break;
497     }
498     return code;                /* so far, none implemented */
499 }
500
501 #ifdef AFS_AIX_ENV
502 /* For aix we don't temporarily bypass ioctl(2) but rather do our
503  * thing directly in the vnode layer call, VNOP_IOCTL; thus afs_ioctl
504  * is now called from afs_gn_ioctl.
505  */
506 int
507 afs_ioctl(struct vcache *tvc, int cmd, int arg)
508 {
509     struct afs_ioctl data;
510     int error = 0;
511
512     AFS_STATCNT(afs_ioctl);
513     if (((cmd >> 8) & 0xff) == 'V') {
514         /* This is a VICEIOCTL call */
515         AFS_COPYIN(arg, (caddr_t) & data, sizeof(data), error);
516         if (error)
517             return (error);
518         error = HandleIoctl(tvc, cmd, &data);
519         return (error);
520     } else {
521         /* No-op call; just return. */
522         return (ENOTTY);
523     }
524 }
525 # if defined(AFS_AIX32_ENV)
526 #  if defined(AFS_AIX51_ENV)
527 #   ifdef __64BIT__
528 int
529 kioctl(int fdes, int com, caddr_t arg, caddr_t ext, caddr_t arg2,
530            caddr_t arg3)
531 #   else /* __64BIT__ */
532 int
533 kioctl32(int fdes, int com, caddr_t arg, caddr_t ext, caddr_t arg2,
534              caddr_t arg3)
535 #   endif /* __64BIT__ */
536 #  else
537 int
538 kioctl(int fdes, int com, caddr_t arg, caddr_t ext)
539 #  endif /* AFS_AIX51_ENV */
540 {
541     struct a {
542         int fd, com;
543         caddr_t arg, ext;
544 #  ifdef AFS_AIX51_ENV
545         caddr_t arg2, arg3;
546 #  endif
547     } u_uap, *uap = &u_uap;
548     struct file *fd;
549     struct vcache *tvc;
550     int ioctlDone = 0, code = 0;
551
552     AFS_STATCNT(afs_xioctl);
553     uap->fd = fdes;
554     uap->com = com;
555     uap->arg = arg;
556 #  ifdef AFS_AIX51_ENV
557     uap->arg2 = arg2;
558     uap->arg3 = arg3;
559 #  endif
560     if (setuerror(getf(uap->fd, &fd))) {
561         return -1;
562     }
563     if (fd->f_type == DTYPE_VNODE) {
564         /* good, this is a vnode; next see if it is an AFS vnode */
565         tvc = VTOAFS(fd->f_vnode);      /* valid, given a vnode */
566         if (tvc && IsAfsVnode(AFSTOV(tvc))) {
567             /* This is an AFS vnode */
568             if (((uap->com >> 8) & 0xff) == 'V') {
569                 struct afs_ioctl *datap;
570                 AFS_GLOCK();
571                 datap =
572                     (struct afs_ioctl *)osi_AllocSmallSpace(AFS_SMALLOCSIZ);
573                 code=copyin_afs_ioctl((char *)uap->arg, datap);
574                 if (code) {
575                     osi_FreeSmallSpace(datap);
576                     AFS_GUNLOCK();
577 #  if defined(AFS_AIX41_ENV)
578                     ufdrele(uap->fd);
579 #  endif
580                     return (setuerror(code), code);
581                 }
582                 code = HandleIoctl(tvc, uap->com, datap);
583                 osi_FreeSmallSpace(datap);
584                 AFS_GUNLOCK();
585                 ioctlDone = 1;
586 #  if defined(AFS_AIX41_ENV)
587                 ufdrele(uap->fd);
588 #  endif
589              }
590         }
591     }
592     if (!ioctlDone) {
593 #  if defined(AFS_AIX41_ENV)
594         ufdrele(uap->fd);
595 #   if defined(AFS_AIX51_ENV)
596 #    ifdef __64BIT__
597         code = okioctl(fdes, com, arg, ext, arg2, arg3);
598 #    else /* __64BIT__ */
599         code = okioctl32(fdes, com, arg, ext, arg2, arg3);
600 #    endif /* __64BIT__ */
601 #   else /* !AFS_AIX51_ENV */
602         code = okioctl(fdes, com, arg, ext);
603 #   endif /* AFS_AIX51_ENV */
604         return code;
605 #  elif defined(AFS_AIX32_ENV)
606         okioctl(fdes, com, arg, ext);
607 #  endif
608     }
609 #  if defined(KERNEL_HAVE_UERROR)
610     if (!getuerror())
611         setuerror(code);
612 #   if !defined(AFS_AIX41_ENV)
613     return (getuerror()? -1 : u.u_ioctlrv);
614 #   else
615     return getuerror()? -1 : 0;
616 #   endif
617 #  endif
618     return 0;
619 }
620 # endif
621
622 #elif defined(AFS_SGI_ENV)
623 # if defined(AFS_SGI65_ENV)
624 afs_ioctl(OSI_VN_DECL(tvc), int cmd, void *arg, int flag, cred_t * cr,
625           rval_t * rvalp, struct vopbd * vbds)
626 # else
627 afs_ioctl(OSI_VN_DECL(tvc), int cmd, void *arg, int flag, cred_t * cr,
628           rval_t * rvalp, struct vopbd * vbds)
629 # endif
630 {
631     struct afs_ioctl data;
632     int error = 0;
633     int locked;
634
635     OSI_VN_CONVERT(tvc);
636
637     AFS_STATCNT(afs_ioctl);
638     if (((cmd >> 8) & 0xff) == 'V') {
639         /* This is a VICEIOCTL call */
640         error = copyin_afs_ioctl(arg, &data);
641         if (error)
642             return (error);
643         locked = ISAFS_GLOCK();
644         if (!locked)
645             AFS_GLOCK();
646         error = HandleIoctl(tvc, cmd, &data);
647         if (!locked)
648             AFS_GUNLOCK();
649         return (error);
650     } else {
651         /* No-op call; just return. */
652         return (ENOTTY);
653     }
654 }
655 #elif defined(AFS_SUN5_ENV)
656 struct afs_ioctl_sys {
657     int fd;
658     int com;
659     int arg;
660 };
661
662 int
663 afs_xioctl(struct afs_ioctl_sys *uap, rval_t *rvp)
664 {
665     struct file *fd;
666     struct vcache *tvc;
667     int ioctlDone = 0, code = 0;
668
669     AFS_STATCNT(afs_xioctl);
670 # if defined(AFS_SUN57_ENV)
671     fd = getf(uap->fd);
672     if (!fd)
673         return (EBADF);
674 # elif defined(AFS_SUN54_ENV)
675     fd = GETF(uap->fd);
676     if (!fd)
677         return (EBADF);
678 # else
679     if (code = getf(uap->fd, &fd)) {
680         return (code);
681     }
682 # endif
683     if (fd->f_vnode->v_type == VREG || fd->f_vnode->v_type == VDIR) {
684         tvc = VTOAFS(fd->f_vnode);      /* valid, given a vnode */
685         if (tvc && IsAfsVnode(AFSTOV(tvc))) {
686             /* This is an AFS vnode */
687             if (((uap->com >> 8) & 0xff) == 'V') {
688                 struct afs_ioctl *datap;
689                 AFS_GLOCK();
690                 datap =
691                     (struct afs_ioctl *)osi_AllocSmallSpace(AFS_SMALLOCSIZ);
692                 code=copyin_afs_ioctl((char *)uap->arg, datap);
693                 if (code) {
694                     osi_FreeSmallSpace(datap);
695                     AFS_GUNLOCK();
696 # if defined(AFS_SUN54_ENV)
697                     releasef(uap->fd);
698 # else
699                     releasef(fd);
700 # endif
701                     return (EFAULT);
702                 }
703                 code = HandleIoctl(tvc, uap->com, datap);
704                 osi_FreeSmallSpace(datap);
705                 AFS_GUNLOCK();
706                 ioctlDone = 1;
707             }
708         }
709     }
710 # if defined(AFS_SUN57_ENV)
711     releasef(uap->fd);
712 # elif defined(AFS_SUN54_ENV)
713     RELEASEF(uap->fd);
714 # else
715     releasef(fd);
716 # endif
717     if (!ioctlDone)
718         code = ioctl(uap, rvp);
719
720     return (code);
721 }
722 #elif defined(AFS_LINUX22_ENV)
723 struct afs_ioctl_sys {
724     unsigned int com;
725     unsigned long arg;
726 };
727 int
728 afs_xioctl(struct inode *ip, struct file *fp, unsigned int com,
729            unsigned long arg)
730 {
731     struct afs_ioctl_sys ua, *uap = &ua;
732     struct vcache *tvc;
733     int code = 0;
734
735     AFS_STATCNT(afs_xioctl);
736     ua.com = com;
737     ua.arg = arg;
738
739     tvc = VTOAFS(ip);
740     if (tvc && IsAfsVnode(AFSTOV(tvc))) {
741         /* This is an AFS vnode */
742         if (((uap->com >> 8) & 0xff) == 'V') {
743             struct afs_ioctl *datap;
744             AFS_GLOCK();
745             datap = osi_AllocSmallSpace(AFS_SMALLOCSIZ);
746             code = copyin_afs_ioctl((char *)uap->arg, datap);
747             if (code) {
748                 osi_FreeSmallSpace(datap);
749                 AFS_GUNLOCK();
750                 return -code;
751             }
752             code = HandleIoctl(tvc, uap->com, datap);
753             osi_FreeSmallSpace(datap);
754             AFS_GUNLOCK();
755         }
756         else
757             code = EINVAL;
758     }
759     return -code;
760 }
761 #elif defined(AFS_DARWIN_ENV) && !defined(AFS_DARWIN80_ENV)
762 struct ioctl_args {
763     int fd;
764     u_long com;
765     caddr_t arg;
766 };
767
768 int
769 afs_xioctl(afs_proc_t *p, struct ioctl_args *uap, register_t *retval)
770 {
771     struct file *fd;
772     struct vcache *tvc;
773     int ioctlDone = 0, code = 0;
774
775     AFS_STATCNT(afs_xioctl);
776     if ((code = fdgetf(p, uap->fd, &fd)))
777         return code;
778     if (fd->f_type == DTYPE_VNODE) {
779         tvc = VTOAFS((struct vnode *)fd->f_data);       /* valid, given a vnode */
780         if (tvc && IsAfsVnode(AFSTOV(tvc))) {
781             /* This is an AFS vnode */
782             if (((uap->com >> 8) & 0xff) == 'V') {
783                 struct afs_ioctl *datap;
784                 AFS_GLOCK();
785                 datap = osi_AllocSmallSpace(AFS_SMALLOCSIZ);
786                 code = copyin_afs_ioctl((char *)uap->arg, datap);
787                 if (code) {
788                     osi_FreeSmallSpace(datap);
789                     AFS_GUNLOCK();
790                     return code;
791                 }
792                 code = HandleIoctl(tvc, uap->com, datap);
793                 osi_FreeSmallSpace(datap);
794                 AFS_GUNLOCK();
795                 ioctlDone = 1;
796             }
797         }
798     }
799
800     if (!ioctlDone)
801         return ioctl(p, uap, retval);
802
803     return (code);
804 }
805 #elif defined(AFS_XBSD_ENV)
806 # if defined(AFS_FBSD_ENV)
807 #  define arg data
808 int
809 afs_xioctl(struct thread *td, struct ioctl_args *uap,
810            register_t *retval)
811 {
812     afs_proc_t *p = td->td_proc;
813 # elif defined(AFS_NBSD_ENV)
814 int
815 afs_xioctl(afs_proc_t *p, const struct sys_ioctl_args *uap, register_t *retval)
816 {
817 # else
818 struct ioctl_args {
819     int fd;
820     u_long com;
821     caddr_t arg;
822 };
823
824 int
825 afs_xioctl(afs_proc_t *p, const struct ioctl_args *uap, register_t *retval)
826 {
827 # endif
828     struct filedesc *fdp;
829     struct vcache *tvc;
830     int ioctlDone = 0, code = 0;
831     struct file *fd;
832
833     AFS_STATCNT(afs_xioctl);
834 #if defined(AFS_NBSD40_ENV)
835     fdp = p->l_proc->p_fd;
836 #else
837     fdp = p->p_fd;
838 #endif
839 #if defined(AFS_NBSD50_ENV)
840     if ((fd = fd_getfile(SCARG(uap, fd))) == NULL)
841         return (EBADF);
842 #else
843     if ((uap->fd >= fdp->fd_nfiles)
844         || ((fd = fdp->fd_ofiles[uap->fd]) == NULL))
845         return EBADF;
846 #endif
847     if ((fd->f_flag & (FREAD | FWRITE)) == 0)
848         return EBADF;
849     /* first determine whether this is any sort of vnode */
850     if (fd->f_type == DTYPE_VNODE) {
851         /* good, this is a vnode; next see if it is an AFS vnode */
852 # if defined(AFS_OBSD_ENV)
853         tvc =
854             IsAfsVnode((struct vnode *)fd->
855                        f_data) ? VTOAFS((struct vnode *)fd->f_data) : NULL;
856 # else
857         tvc = VTOAFS((struct vnode *)fd->f_data);       /* valid, given a vnode */
858 # endif
859         if (tvc && IsAfsVnode((struct vnode *)fd->f_data)) {
860             /* This is an AFS vnode */
861 #if defined(AFS_NBSD50_ENV)
862             if (((SCARG(uap, com) >> 8) & 0xff) == 'V') {
863 #else
864             if (((uap->com >> 8) & 0xff) == 'V') {
865 #endif
866                 struct afs_ioctl *datap;
867                 AFS_GLOCK();
868                 datap = osi_AllocSmallSpace(AFS_SMALLOCSIZ);
869 #if defined(AFS_NBSD50_ENV)
870                 code = copyin_afs_ioctl(SCARG(uap, data), datap);
871 #else
872                 code = copyin_afs_ioctl((char *)uap->arg, datap);
873 #endif
874                 if (code) {
875                     osi_FreeSmallSpace(datap);
876                     AFS_GUNLOCK();
877                     return code;
878                 }
879 #if defined(AFS_NBSD50_ENV)
880                 code = HandleIoctl(tvc, SCARG(uap, com), datap);
881 #else
882                 code = HandleIoctl(tvc, uap->com, datap);
883 #endif
884                 osi_FreeSmallSpace(datap);
885                 AFS_GUNLOCK();
886                 ioctlDone = 1;
887             }
888         }
889     }
890
891 #if defined(AFS_NBSD50_ENV)
892     fd_putfile(SCARG(uap, fd));
893 #endif
894
895     if (!ioctlDone) {
896 # if defined(AFS_FBSD_ENV)
897         return ioctl(td, uap);
898 # elif defined(AFS_OBSD_ENV)
899         code = sys_ioctl(p, uap, retval);
900 # elif defined(AFS_NBSD_ENV)
901         code = sys_ioctl(p, uap, retval);
902 # endif
903     }
904
905     return (code);
906 }
907 #elif defined(UKERNEL)
908 int
909 afs_xioctl(void)
910 {
911     struct a {
912         int fd;
913         int com;
914         caddr_t arg;
915     } *uap = (struct a *)get_user_struct()->u_ap;
916     struct file *fd;
917     struct vcache *tvc;
918     int ioctlDone = 0, code = 0;
919
920     AFS_STATCNT(afs_xioctl);
921
922     fd = getf(uap->fd);
923     if (!fd)
924         return (EBADF);
925     /* first determine whether this is any sort of vnode */
926     if (fd->f_type == DTYPE_VNODE) {
927         /* good, this is a vnode; next see if it is an AFS vnode */
928         tvc = VTOAFS((struct vnode *)fd->f_data);       /* valid, given a vnode */
929         if (tvc && IsAfsVnode(AFSTOV(tvc))) {
930             /* This is an AFS vnode */
931             if (((uap->com >> 8) & 0xff) == 'V') {
932                 struct afs_ioctl *datap;
933                 AFS_GLOCK();
934                 datap = osi_AllocSmallSpace(AFS_SMALLOCSIZ);
935                 code=copyin_afs_ioctl((char *)uap->arg, datap);
936                 if (code) {
937                     osi_FreeSmallSpace(datap);
938                     AFS_GUNLOCK();
939
940                     return (setuerror(code), code);
941                 }
942                 code = HandleIoctl(tvc, uap->com, datap);
943                 osi_FreeSmallSpace(datap);
944                 AFS_GUNLOCK();
945                 ioctlDone = 1;
946             }
947         }
948     }
949
950     if (!ioctlDone) {
951         ioctl();
952     }
953
954     return 0;
955 }
956 #endif /* AFS_HPUX102_ENV */
957
958 #if defined(AFS_SGI_ENV)
959   /* "pioctl" system call entry point; just pass argument to the parameterized
960    * call below */
961 struct pioctlargs {
962     char *path;
963     sysarg_t cmd;
964     caddr_t cmarg;
965     sysarg_t follow;
966 };
967 int
968 afs_pioctl(struct pioctlargs *uap, rval_t * rvp)
969 {
970     int code;
971
972     AFS_STATCNT(afs_pioctl);
973     AFS_GLOCK();
974     code = afs_syscall_pioctl(uap->path, uap->cmd, uap->cmarg, uap->follow);
975     AFS_GUNLOCK();
976 # ifdef AFS_SGI64_ENV
977     return code;
978 # else
979     return u.u_error;
980 # endif
981 }
982
983 #elif defined(AFS_FBSD_ENV)
984 int
985 afs_pioctl(struct thread *td, void *args, int *retval)
986 {
987     struct a {
988         char *path;
989         int cmd;
990         caddr_t cmarg;
991         int follow;
992     } *uap = (struct a *)args;
993
994     AFS_STATCNT(afs_pioctl);
995     return (afs_syscall_pioctl
996             (uap->path, uap->cmd, uap->cmarg, uap->follow, td->td_ucred));
997 }
998
999 #elif defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
1000 int
1001 afs_pioctl(afs_proc_t *p, void *args, int *retval)
1002 {
1003     struct a {
1004         char *path;
1005         int cmd;
1006         caddr_t cmarg;
1007         int follow;
1008     } *uap = (struct a *)args;
1009
1010     AFS_STATCNT(afs_pioctl);
1011 # if defined(AFS_DARWIN80_ENV) || defined(AFS_NBSD40_ENV)
1012     return (afs_syscall_pioctl
1013             (uap->path, uap->cmd, uap->cmarg, uap->follow,
1014              kauth_cred_get()));
1015 # else
1016     return (afs_syscall_pioctl
1017             (uap->path, uap->cmd, uap->cmarg, uap->follow,
1018 #  if defined(AFS_FBSD_ENV)
1019              td->td_ucred));
1020 #  else
1021              p->p_cred->pc_ucred));
1022 #  endif
1023 # endif
1024 }
1025
1026 #endif
1027
1028 /* macro to avoid adding any more #ifdef's to pioctl code. */
1029 #if defined(AFS_LINUX22_ENV) || defined(AFS_AIX41_ENV)
1030 #define PIOCTL_FREE_CRED() crfree(credp)
1031 #else
1032 #define PIOCTL_FREE_CRED()
1033 #endif
1034
1035 int
1036 #ifdef  AFS_SUN5_ENV
1037 afs_syscall_pioctl(char *path, unsigned int com, caddr_t cmarg, int follow,
1038                    rval_t *vvp, afs_ucred_t *credp)
1039 #else
1040 #ifdef AFS_DARWIN100_ENV
1041 afs_syscall64_pioctl(user_addr_t path, unsigned int com, user_addr_t cmarg,
1042                    int follow, afs_ucred_t *credp)
1043 #elif defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
1044 afs_syscall_pioctl(char *path, unsigned int com, caddr_t cmarg, int follow,
1045                    afs_ucred_t *credp)
1046 #else
1047 afs_syscall_pioctl(char *path, unsigned int com, caddr_t cmarg, int follow)
1048 #endif
1049 #endif
1050 {
1051     struct afs_ioctl data;
1052 #ifdef AFS_NEED_CLIENTCONTEXT
1053     afs_ucred_t *tmpcred = NULL;
1054 #endif
1055 #if defined(AFS_NEED_CLIENTCONTEXT) || defined(AFS_SUN5_ENV) || defined(AFS_AIX41_ENV) || defined(AFS_LINUX22_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
1056     afs_ucred_t *foreigncreds = NULL;
1057 #endif
1058     afs_int32 code = 0;
1059     struct vnode *vp = NULL;
1060 #ifdef  AFS_AIX41_ENV
1061     struct ucred *credp = crref();      /* don't free until done! */
1062 #endif
1063 #ifdef AFS_LINUX22_ENV
1064     cred_t *credp = crref();    /* don't free until done! */
1065     struct dentry *dp;
1066 #endif
1067
1068     AFS_STATCNT(afs_syscall_pioctl);
1069     if (follow)
1070         follow = 1;             /* compat. with old venus */
1071     code = copyin_afs_ioctl(cmarg, &data);
1072     if (code) {
1073         PIOCTL_FREE_CRED();
1074 #if defined(KERNEL_HAVE_UERROR)
1075         setuerror(code);
1076 #endif
1077         return (code);
1078     }
1079     if ((com & 0xff) == PSetClientContext) {
1080 #ifdef AFS_NEED_CLIENTCONTEXT
1081 #if defined(AFS_SUN5_ENV) || defined(AFS_AIX41_ENV) || defined(AFS_LINUX22_ENV)
1082         code = HandleClientContext(&data, &com, &foreigncreds, credp);
1083 #else
1084         code = HandleClientContext(&data, &com, &foreigncreds, osi_curcred());
1085 #endif
1086         if (code) {
1087             if (foreigncreds) {
1088                 crfree(foreigncreds);
1089             }
1090             PIOCTL_FREE_CRED();
1091 #if defined(KERNEL_HAVE_UERROR)
1092             return (setuerror(code), code);
1093 #else
1094             return (code);
1095 #endif
1096         }
1097 #else /* AFS_NEED_CLIENTCONTEXT */
1098         return EINVAL;
1099 #endif /* AFS_NEED_CLIENTCONTEXT */
1100     }
1101 #ifdef AFS_NEED_CLIENTCONTEXT
1102     if (foreigncreds) {
1103         /*
1104          * We could have done without temporary setting the u.u_cred below
1105          * (foreigncreds could be passed as param the pioctl modules)
1106          * but calls such as afs_osi_suser() doesn't allow that since it
1107          * references u.u_cred directly.  We could, of course, do something
1108          * like afs_osi_suser(cred) which, I think, is better since it
1109          * generalizes and supports multi cred environments...
1110          */
1111 #if defined(AFS_SUN5_ENV) || defined(AFS_LINUX22_ENV)
1112         tmpcred = credp;
1113         credp = foreigncreds;
1114 #elif defined(AFS_AIX41_ENV)
1115         tmpcred = crref();      /* XXX */
1116         crset(foreigncreds);
1117 #elif defined(AFS_HPUX101_ENV)
1118         tmpcred = p_cred(u.u_procp);
1119         set_p_cred(u.u_procp, foreigncreds);
1120 #elif defined(AFS_SGI_ENV)
1121         tmpcred = OSI_GET_CURRENT_CRED();
1122         OSI_SET_CURRENT_CRED(foreigncreds);
1123 #else
1124         tmpcred = u.u_cred;
1125         u.u_cred = foreigncreds;
1126 #endif
1127     }
1128 #endif /* AFS_NEED_CLIENTCONTEXT */
1129     if ((com & 0xff) == 15) {
1130         /* special case prefetch so entire pathname eval occurs in helper process.
1131          * otherwise, the pioctl call is essentially useless */
1132 #if     defined(AFS_SUN5_ENV) || defined(AFS_AIX41_ENV) || defined(AFS_LINUX22_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
1133         code =
1134             Prefetch(path, &data, follow,
1135                      foreigncreds ? foreigncreds : credp);
1136 #else
1137         code = Prefetch(path, &data, follow, osi_curcred());
1138 #endif
1139         vp = NULL;
1140 #if defined(KERNEL_HAVE_UERROR)
1141         setuerror(code);
1142 #endif
1143         goto rescred;
1144     }
1145     if (path) {
1146         AFS_GUNLOCK();
1147 #ifdef  AFS_AIX41_ENV
1148         code =
1149             lookupname(path, USR, follow, NULL, &vp,
1150                        foreigncreds ? foreigncreds : credp);
1151 #else
1152 #ifdef AFS_LINUX22_ENV
1153         code = gop_lookupname_user(path, AFS_UIOUSER, follow, &dp);
1154         if (!code)
1155             vp = (struct vnode *)dp->d_inode;
1156 #else
1157         code = gop_lookupname_user(path, AFS_UIOUSER, follow, &vp);
1158 #if defined(AFS_FBSD80_ENV) /* XXX check on 7x */
1159         if (vp != NULL)
1160                 VN_HOLD(vp);
1161 #endif /* AFS_FBSD80_ENV */
1162 #endif /* AFS_LINUX22_ENV */
1163 #endif /* AFS_AIX41_ENV */
1164         AFS_GLOCK();
1165         if (code) {
1166             vp = NULL;
1167 #if defined(KERNEL_HAVE_UERROR)
1168             setuerror(code);
1169 #endif
1170             goto rescred;
1171         }
1172     } else
1173         vp = NULL;
1174
1175 #if defined(AFS_SUN510_ENV)
1176     if (vp && !IsAfsVnode(vp)) {
1177         struct vnode *realvp;
1178         if
1179 #ifdef AFS_SUN511_ENV
1180           (VOP_REALVP(vp, &realvp, NULL) == 0)
1181 #else
1182           (VOP_REALVP(vp, &realvp) == 0)
1183 #endif
1184 {
1185             struct vnode *oldvp = vp;
1186
1187             VN_HOLD(realvp);
1188             vp = realvp;
1189             AFS_RELE(oldvp);
1190         }
1191     }
1192 #endif
1193     /* now make the call if we were passed no file, or were passed an AFS file */
1194     if (!vp || IsAfsVnode(vp)) {
1195 #if defined(AFS_SUN5_ENV)
1196         code = afs_HandlePioctl(vp, com, &data, follow, &credp);
1197 #elif defined(AFS_AIX41_ENV)
1198         {
1199             struct ucred *cred1, *cred2;
1200
1201             if (foreigncreds) {
1202                 cred1 = cred2 = foreigncreds;
1203             } else {
1204                 cred1 = cred2 = credp;
1205             }
1206             code = afs_HandlePioctl(vp, com, &data, follow, &cred1);
1207             if (cred1 != cred2) {
1208                 /* something changed the creds */
1209                 crset(cred1);
1210             }
1211         }
1212 #elif defined(AFS_HPUX101_ENV)
1213         {
1214             struct ucred *cred = p_cred(u.u_procp);
1215             code = afs_HandlePioctl(vp, com, &data, follow, &cred);
1216         }
1217 #elif defined(AFS_SGI_ENV)
1218         {
1219             struct cred *credp;
1220             credp = OSI_GET_CURRENT_CRED();
1221             code = afs_HandlePioctl(vp, com, &data, follow, &credp);
1222         }
1223 #elif defined(AFS_LINUX22_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
1224         code = afs_HandlePioctl(vp, com, &data, follow, &credp);
1225 #elif defined(UKERNEL)
1226         code = afs_HandlePioctl(vp, com, &data, follow,
1227                                 &(get_user_struct()->u_cred));
1228 #else
1229         code = afs_HandlePioctl(vp, com, &data, follow, &u.u_cred);
1230 #endif
1231     } else {
1232 #if defined(KERNEL_HAVE_UERROR)
1233         setuerror(EINVAL);
1234 #else
1235         code = EINVAL;          /* not in /afs */
1236 #endif
1237     }
1238
1239   rescred:
1240 #if defined(AFS_NEED_CLIENTCONTEXT)
1241     if (foreigncreds) {
1242 #ifdef  AFS_AIX41_ENV
1243         crset(tmpcred);         /* restore original credentials */
1244 #else
1245 #if     defined(AFS_HPUX101_ENV)
1246         set_p_cred(u.u_procp, tmpcred); /* restore original credentials */
1247 #elif   defined(AFS_SGI_ENV)
1248         OSI_SET_CURRENT_CRED(tmpcred);  /* restore original credentials */
1249 #elif   defined(AFS_SUN5_ENV) || defined(AFS_LINUX22_ENV)
1250         credp = tmpcred;                /* restore original credentials */
1251 #else
1252         osi_curcred() = tmpcred;        /* restore original credentials */
1253 #endif /* AFS_HPUX101_ENV */
1254         crfree(foreigncreds);
1255 #endif /* AIX41 */
1256     }
1257 #endif /* AFS_NEED_CLIENTCONTEXT */
1258     if (vp) {
1259 #ifdef AFS_LINUX22_ENV
1260         dput(dp);
1261 #else
1262 #if defined(AFS_FBSD80_ENV)
1263     if (VOP_ISLOCKED(vp))
1264         VOP_UNLOCK(vp, 0);
1265 #endif /* AFS_FBSD80_ENV */
1266         AFS_RELE(vp);           /* put vnode back */
1267 #endif
1268     }
1269     PIOCTL_FREE_CRED();
1270 #if defined(KERNEL_HAVE_UERROR)
1271     if (!getuerror())
1272         setuerror(code);
1273     return (getuerror());
1274 #else
1275     return (code);
1276 #endif
1277 }
1278
1279 #ifdef AFS_DARWIN100_ENV
1280 int
1281 afs_syscall_pioctl(char * path, unsigned int com, caddr_t cmarg,
1282                    int follow, afs_ucred_t *credp)
1283 {
1284     return afs_syscall64_pioctl(CAST_USER_ADDR_T(path), com,
1285                                 CAST_USER_ADDR_T((unsigned int)cmarg), follow,
1286                                 credp);
1287 }
1288 #endif
1289
1290 #define MAXPIOCTLTOKENLEN \
1291 (3*sizeof(afs_int32)+MAXKTCTICKETLEN+sizeof(struct ClearToken)+MAXKTCREALMLEN)
1292
1293 int
1294 afs_HandlePioctl(struct vnode *avp, afs_int32 acom,
1295                  struct afs_ioctl *ablob, int afollow,
1296                  afs_ucred_t **acred)
1297 {
1298     struct vcache *avc;
1299     struct vrequest treq;
1300     afs_int32 code;
1301     afs_int32 function, device;
1302     struct afs_pdata input, output;
1303     struct afs_pdata copyInput, copyOutput;
1304     size_t outSize;
1305     pioctlFunction *pioctlSw;
1306     int pioctlSwSize;
1307     struct afs_fakestat_state fakestate;
1308
1309     memset(&input, 0, sizeof(input));
1310     memset(&output, 0, sizeof(output));
1311
1312     avc = avp ? VTOAFS(avp) : NULL;
1313     afs_Trace3(afs_iclSetp, CM_TRACE_PIOCTL, ICL_TYPE_INT32, acom & 0xff,
1314                ICL_TYPE_POINTER, avc, ICL_TYPE_INT32, afollow);
1315     AFS_STATCNT(HandlePioctl);
1316
1317     code = afs_InitReq(&treq, *acred);
1318     if (code)
1319         return code;
1320
1321     afs_InitFakeStat(&fakestate);
1322     if (avc) {
1323         code = afs_EvalFakeStat(&avc, &fakestate, &treq);
1324         if (code)
1325             goto out;
1326     }
1327     device = (acom & 0xff00) >> 8;
1328     switch (device) {
1329     case 'V':                   /* Original pioctls */
1330         pioctlSw = VpioctlSw;
1331         pioctlSwSize = sizeof(VpioctlSw);
1332         break;
1333     case 'C':                   /* Coordinated/common pioctls */
1334         pioctlSw = CpioctlSw;
1335         pioctlSwSize = sizeof(CpioctlSw);
1336         break;
1337     case 'O':                   /* Coordinated/common pioctls */
1338         pioctlSw = OpioctlSw;
1339         pioctlSwSize = sizeof(OpioctlSw);
1340         break;
1341     default:
1342         code = EINVAL;
1343         goto out;
1344     }
1345     function = acom & 0xff;
1346     if (function >= (pioctlSwSize / sizeof(char *))) {
1347         code = EINVAL;
1348         goto out;
1349     }
1350
1351     /* Do all range checking before continuing */
1352     if (ablob->in_size > MAXPIOCTLTOKENLEN ||
1353         ablob->in_size < 0 || ablob->out_size < 0) {
1354         code = EINVAL;
1355         goto out;
1356     }
1357
1358     code = afs_pd_alloc(&input, ablob->in_size);
1359     if (code)
1360         goto out;
1361
1362     if (ablob->in_size > 0) {
1363         AFS_COPYIN(ablob->in, input.ptr, ablob->in_size, code);
1364         input.ptr[input.remaining] = '\0';
1365     }
1366     if (code)
1367         goto out;
1368
1369     if ((function == 8 && device == 'V') ||
1370        (function == 7 && device == 'C')) {      /* PGetTokens */
1371         code = afs_pd_alloc(&output, MAXPIOCTLTOKENLEN);
1372     } else {
1373         code = afs_pd_alloc(&output, AFS_LRALLOCSIZ);
1374     }
1375     if (code)
1376         goto out;
1377
1378     copyInput = input;
1379     copyOutput = output;
1380
1381     code =
1382         (*pioctlSw[function]) (avc, function, &treq, &copyInput,
1383                                &copyOutput, acred);
1384
1385     outSize = copyOutput.ptr - output.ptr;
1386
1387     if (code == 0 && ablob->out_size > 0) {
1388         if (outSize > ablob->out_size) {
1389             code = E2BIG;       /* data wont fit in user buffer */
1390         } else if (outSize) {
1391             AFS_COPYOUT(output.ptr, ablob->out, outSize, code);
1392         }
1393     }
1394
1395 out:
1396     afs_pd_free(&input);
1397     afs_pd_free(&output);
1398
1399     afs_PutFakeStat(&fakestate);
1400     return afs_CheckCode(code, &treq, 41);
1401 }
1402
1403 /*!
1404  * VIOCGETFID (22) - Get file ID quickly
1405  *
1406  * \ingroup pioctl
1407  *
1408  * \param[in] ain       not in use
1409  * \param[out] aout     fid of requested file
1410  *
1411  * \retval EINVAL       Error if some of the initial arguments aren't set
1412  *
1413  * \post get the file id of some file
1414  */
1415 DECL_PIOCTL(PGetFID)
1416 {
1417     AFS_STATCNT(PGetFID);
1418     if (!avc)
1419         return EINVAL;
1420     if (afs_pd_putBytes(aout, &avc->f.fid, sizeof(struct VenusFid)) != 0)
1421         return EINVAL;
1422     return 0;
1423 }
1424
1425 /*!
1426  * VIOCSETAL (1) - Set access control list
1427  *
1428  * \ingroup pioctl
1429  *
1430  * \param[in] ain       the ACL being set
1431  * \param[out] aout     the ACL being set returned
1432  *
1433  * \retval EINVAL       Error if some of the standard args aren't set
1434  *
1435  * \post Changed ACL, via direct writing to the wire
1436  */
1437 int
1438 dummy_PSetAcl(char *ain, char *aout)
1439 {
1440     return 0;
1441 }
1442
1443 DECL_PIOCTL(PSetAcl)
1444 {
1445     afs_int32 code;
1446     struct afs_conn *tconn;
1447     struct AFSOpaque acl;
1448     struct AFSVolSync tsync;
1449     struct AFSFetchStatus OutStatus;
1450     struct rx_connection *rxconn;
1451     XSTATS_DECLS;
1452
1453     AFS_STATCNT(PSetAcl);
1454     if (!avc)
1455         return EINVAL;
1456
1457     if (afs_pd_getStringPtr(ain, &acl.AFSOpaque_val) != 0)
1458         return EINVAL;
1459     acl.AFSOpaque_len = strlen(acl.AFSOpaque_val) + 1;
1460     if (acl.AFSOpaque_len > 1024)
1461         return EINVAL;
1462
1463     do {
1464         tconn = afs_Conn(&avc->f.fid, areq, SHARED_LOCK, &rxconn);
1465         if (tconn) {
1466             XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_STOREACL);
1467             RX_AFS_GUNLOCK();
1468             code =
1469                 RXAFS_StoreACL(rxconn, (struct AFSFid *)&avc->f.fid.Fid,
1470                                &acl, &OutStatus, &tsync);
1471             RX_AFS_GLOCK();
1472             XSTATS_END_TIME;
1473         } else
1474             code = -1;
1475     } while (afs_Analyze
1476              (tconn, rxconn, code, &avc->f.fid, areq, AFS_STATS_FS_RPCIDX_STOREACL,
1477               SHARED_LOCK, NULL));
1478
1479     /* now we've forgotten all of the access info */
1480     ObtainWriteLock(&afs_xcbhash, 455);
1481     avc->callback = 0;
1482     afs_DequeueCallback(avc);
1483     avc->f.states &= ~(CStatd | CUnique);
1484     ReleaseWriteLock(&afs_xcbhash);
1485     if (avc->f.fid.Fid.Vnode & 1 || (vType(avc) == VDIR))
1486         osi_dnlc_purgedp(avc);
1487
1488     /* SXW - Should we flush metadata here? */
1489     return code;
1490 }
1491
1492 int afs_defaultAsynchrony = 0;
1493
1494 /*!
1495  * VIOC_STOREBEHIND (47) Adjust store asynchrony
1496  *
1497  * \ingroup pioctl
1498  *
1499  * \param[in] ain       sbstruct (store behind structure) input
1500  * \param[out] aout     resulting sbstruct
1501  *
1502  * \retval EPERM
1503  *      Error if the user doesn't have super-user credentials
1504  * \retval EACCES
1505  *      Error if there isn't enough access to not check the mode bits
1506  *
1507  * \post
1508  *      Changes either the default asynchrony (the amount of data that
1509  *      can remain to be written when the cache manager returns control
1510  *      to the user), or the asyncrony for the specified file.
1511  */
1512 DECL_PIOCTL(PStoreBehind)
1513 {
1514     struct sbstruct sbr;
1515
1516     if (afs_pd_getBytes(ain, &sbr, sizeof(struct sbstruct)) != 0)
1517         return EINVAL;
1518
1519     if (sbr.sb_default != -1) {
1520         if (afs_osi_suser(*acred))
1521             afs_defaultAsynchrony = sbr.sb_default;
1522         else
1523             return EPERM;
1524     }
1525
1526     if (avc && (sbr.sb_thisfile != -1)) {
1527         if (afs_AccessOK
1528             (avc, PRSFS_WRITE | PRSFS_ADMINISTER, areq, DONT_CHECK_MODE_BITS))
1529             avc->asynchrony = sbr.sb_thisfile;
1530         else
1531             return EACCES;
1532     }
1533
1534     memset(&sbr, 0, sizeof(sbr));
1535     sbr.sb_default = afs_defaultAsynchrony;
1536     if (avc) {
1537         sbr.sb_thisfile = avc->asynchrony;
1538     }
1539
1540     return afs_pd_putBytes(aout, &sbr, sizeof(sbr));
1541 }
1542
1543 /*!
1544  * VIOC_GCPAGS (48) - Disable automatic PAG gc'ing
1545  *
1546  * \ingroup pioctl
1547  *
1548  * \param[in] ain       not in use
1549  * \param[out] aout     not in use
1550  *
1551  * \retval EACCES       Error if the user doesn't have super-user credentials
1552  *
1553  * \post set the gcpags to GCPAGS_USERDISABLED
1554  */
1555 DECL_PIOCTL(PGCPAGs)
1556 {
1557     if (!afs_osi_suser(*acred)) {
1558         return EACCES;
1559     }
1560     afs_gcpags = AFS_GCPAGS_USERDISABLED;
1561     return 0;
1562 }
1563
1564 /*!
1565  * VIOCGETAL (2) - Get access control list
1566  *
1567  * \ingroup pioctl
1568  *
1569  * \param[in] ain       not in use
1570  * \param[out] aout     the ACL
1571  *
1572  * \retval EINVAL       Error if some of the standard args aren't set
1573  * \retval ERANGE       Error if the vnode of the file id is too large
1574  * \retval -1           Error if getting the ACL failed
1575  *
1576  * \post Obtain the ACL, based on file ID
1577  *
1578  * \notes
1579  *      There is a hack to tell which type of ACL is being returned, checks
1580  *      the top 2-bytes of the input size to judge what type of ACL it is,
1581  *      only for dfs xlator ACLs
1582  */
1583 DECL_PIOCTL(PGetAcl)
1584 {
1585     struct AFSOpaque acl;
1586     struct AFSVolSync tsync;
1587     struct AFSFetchStatus OutStatus;
1588     afs_int32 code;
1589     struct afs_conn *tconn;
1590     struct AFSFid Fid;
1591     struct rx_connection *rxconn;
1592     XSTATS_DECLS;
1593
1594     AFS_STATCNT(PGetAcl);
1595     if (!avc)
1596         return EINVAL;
1597     Fid.Volume = avc->f.fid.Fid.Volume;
1598     Fid.Vnode = avc->f.fid.Fid.Vnode;
1599     Fid.Unique = avc->f.fid.Fid.Unique;
1600     if (avc->f.states & CForeign) {
1601         /*
1602          * For a dfs xlator acl we have a special hack so that the
1603          * xlator will distinguish which type of acl will return. So
1604          * we currently use the top 2-bytes (vals 0-4) to tell which
1605          * type of acl to bring back. Horrible hack but this will
1606          * cause the least number of changes to code size and interfaces.
1607          */
1608         if (Fid.Vnode & 0xc0000000)
1609             return ERANGE;
1610         Fid.Vnode |= (ain->remaining << 30);
1611     }
1612     acl.AFSOpaque_val = aout->ptr;
1613     do {
1614         tconn = afs_Conn(&avc->f.fid, areq, SHARED_LOCK, &rxconn);
1615         if (tconn) {
1616             acl.AFSOpaque_val[0] = '\0';
1617             XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_FETCHACL);
1618             RX_AFS_GUNLOCK();
1619             code = RXAFS_FetchACL(rxconn, &Fid, &acl, &OutStatus, &tsync);
1620             RX_AFS_GLOCK();
1621             XSTATS_END_TIME;
1622         } else
1623             code = -1;
1624     } while (afs_Analyze
1625              (tconn, rxconn, code, &avc->f.fid, areq, AFS_STATS_FS_RPCIDX_FETCHACL,
1626               SHARED_LOCK, NULL));
1627
1628     if (code == 0) {
1629         if (acl.AFSOpaque_len == 0)
1630             afs_pd_skip(aout, 1); /* leave the NULL */
1631         else
1632             afs_pd_skip(aout, acl.AFSOpaque_len); /* Length of the ACL */
1633     }
1634     return code;
1635 }
1636
1637 /*!
1638  * PNoop returns success.  Used for functions which are not implemented
1639  * or are no longer in use.
1640  *
1641  * \ingroup pioctl
1642  *
1643  * \retval Always returns success
1644  *
1645  * \notes
1646  *      Functions involved in this:
1647  *      17 (VIOCENGROUP) -- used to be enable group;
1648  *      18 (VIOCDISGROUP) -- used to be disable group;
1649  *      2 (?) -- get/set cache-bypass size threshold
1650  */
1651 DECL_PIOCTL(PNoop)
1652 {
1653     AFS_STATCNT(PNoop);
1654     return 0;
1655 }
1656
1657 /*!
1658  * PBogus returns fail.  Used for functions which are not implemented or
1659  * are no longer in use.
1660  *
1661  * \ingroup pioctl
1662  *
1663  * \retval EINVAL       Always returns this value
1664  *
1665  * \notes
1666  *      Functions involved in this:
1667  *      0 (?);
1668  *      4 (?);
1669  *      6 (?);
1670  *      7 (VIOCSTAT);
1671  *      8 (?);
1672  *      13 (VIOCGETTIME) -- used to be quick check time;
1673  *      15 (VIOCPREFETCH) -- prefetch is now special-cased; see pioctl code!;
1674  *      16 (VIOCNOP) -- used to be testing code;
1675  *      19 (VIOCLISTGROUPS) -- used to be list group;
1676  *      23 (VIOCWAITFOREVER) -- used to be waitforever;
1677  *      57 (VIOC_FPRIOSTATUS) -- arla: set file prio;
1678  *      58 (VIOC_FHGET) -- arla: fallback getfh;
1679  *      59 (VIOC_FHOPEN) -- arla: fallback fhopen;
1680  *      60 (VIOC_XFSDEBUG) -- arla: controls xfsdebug;
1681  *      61 (VIOC_ARLADEBUG) -- arla: controls arla debug;
1682  *      62 (VIOC_AVIATOR) -- arla: debug interface;
1683  *      63 (VIOC_XFSDEBUG_PRINT) -- arla: print xfs status;
1684  *      64 (VIOC_CALCULATE_CACHE) -- arla: force cache check;
1685  *      65 (VIOC_BREAKCELLBACK) -- arla: break callback;
1686  *      68 (?) -- arla: fetch stats;
1687  */
1688 DECL_PIOCTL(PBogus)
1689 {
1690     AFS_STATCNT(PBogus);
1691     return EINVAL;
1692 }
1693
1694 /*!
1695  * VIOC_FILE_CELL_NAME (30) - Get cell in which file lives
1696  *
1697  * \ingroup pioctl
1698  *
1699  * \param[in] ain       not in use (avc used to pass in file id)
1700  * \param[out] aout     cell name
1701  *
1702  * \retval EINVAL       Error if some of the standard args aren't set
1703  * \retval ESRCH        Error if the file isn't part of a cell
1704  *
1705  * \post Get a cell based on a passed in file id
1706  */
1707 DECL_PIOCTL(PGetFileCell)
1708 {
1709     struct cell *tcell;
1710
1711     AFS_STATCNT(PGetFileCell);
1712     if (!avc)
1713         return EINVAL;
1714     tcell = afs_GetCell(avc->f.fid.Cell, READ_LOCK);
1715     if (!tcell)
1716         return ESRCH;
1717
1718     if (afs_pd_putString(aout, tcell->cellName) != 0)
1719         return EINVAL;
1720
1721     afs_PutCell(tcell, READ_LOCK);
1722     return 0;
1723 }
1724
1725 /*!
1726  * VIOC_GET_WS_CELL (31) - Get cell in which workstation lives
1727  *
1728  * \ingroup pioctl
1729  *
1730  * \param[in] ain       not in use
1731  * \param[out] aout     cell name
1732  *
1733  * \retval EIO
1734  *      Error if the afs daemon hasn't started yet
1735  * \retval ESRCH
1736  *      Error if the machine isn't part of a cell, for whatever reason
1737  *
1738  * \post Get the primary cell that the machine is a part of.
1739  */
1740 DECL_PIOCTL(PGetWSCell)
1741 {
1742     struct cell *tcell = NULL;
1743
1744     AFS_STATCNT(PGetWSCell);
1745     if (!afs_resourceinit_flag) /* afs daemons haven't started yet */
1746         return EIO;             /* Inappropriate ioctl for device */
1747
1748     tcell = afs_GetPrimaryCell(READ_LOCK);
1749     if (!tcell)                 /* no primary cell? */
1750         return ESRCH;
1751
1752     if (afs_pd_putString(aout, tcell->cellName) != 0)
1753         return EINVAL;
1754     afs_PutCell(tcell, READ_LOCK);
1755     return 0;
1756 }
1757
1758 /*!
1759  * VIOC_GET_PRIMARY_CELL (33) - Get primary cell for caller
1760  *
1761  * \ingroup pioctl
1762  *
1763  * \param[in] ain       not in use (user id found via areq)
1764  * \param[out] aout     cell name
1765  *
1766  * \retval ESRCH
1767  *      Error if the user id doesn't have a primary cell specified
1768  *
1769  * \post Get the primary cell for a certain user, based on the user's uid
1770  */
1771 DECL_PIOCTL(PGetUserCell)
1772 {
1773     afs_int32 i;
1774     struct unixuser *tu;
1775     struct cell *tcell;
1776
1777     AFS_STATCNT(PGetUserCell);
1778     if (!afs_resourceinit_flag) /* afs daemons haven't started yet */
1779         return EIO;             /* Inappropriate ioctl for device */
1780
1781     /* return the cell name of the primary cell for this user */
1782     i = UHash(areq->uid);
1783     ObtainWriteLock(&afs_xuser, 224);
1784     for (tu = afs_users[i]; tu; tu = tu->next) {
1785         if (tu->uid == areq->uid && (tu->states & UPrimary)) {
1786             tu->refCount++;
1787             ReleaseWriteLock(&afs_xuser);
1788             afs_LockUser(tu, READ_LOCK, 0);
1789             break;
1790         }
1791     }
1792     if (tu) {
1793         tcell = afs_GetCell(tu->cell, READ_LOCK);
1794         afs_PutUser(tu, READ_LOCK);
1795         if (!tcell)
1796             return ESRCH;
1797         else {
1798             if (afs_pd_putString(aout, tcell->cellName) != 0)
1799                 return E2BIG;
1800             afs_PutCell(tcell, READ_LOCK);
1801         }
1802     } else {
1803         ReleaseWriteLock(&afs_xuser);
1804     }
1805     return 0;
1806 }
1807
1808 /* Work out which cell we're changing tokens for */
1809 static_inline int
1810 _settok_tokenCell(char *cellName, int *cellNum, int *primary) {
1811     int t1;
1812     struct cell *cell;
1813
1814     if (primary) {
1815         *primary = 0;
1816     }
1817
1818     if (cellName && strlen(cellName) > 0) {
1819         cell = afs_GetCellByName(cellName, READ_LOCK);
1820     } else {
1821         cell = afs_GetPrimaryCell(READ_LOCK);
1822         if (primary)
1823             *primary = 1;
1824     }
1825     if (!cell) {
1826         t1 = afs_initState;
1827         if (t1 < 101)
1828             return EIO;
1829         else
1830             return ESRCH;
1831     }
1832     *cellNum = cell->cellNum;
1833     afs_PutCell(cell, READ_LOCK);
1834
1835     return 0;
1836 }
1837
1838
1839 static_inline int
1840 _settok_setParentPag(afs_ucred_t **cred) {
1841     afs_uint32 pag;
1842 #if defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
1843     char procname[256];
1844     osi_procname(procname, 256);
1845     afs_warnuser("Process %d (%s) tried to change pags in PSetTokens\n",
1846                  MyPidxx2Pid(MyPidxx), procname);
1847     return setpag(osi_curproc(), cred, -1, &pag, 1);
1848 #else
1849     return setpag(cred, -1, &pag, 1);
1850 #endif
1851 }
1852
1853 /*!
1854  * VIOCSETTOK (3) - Set authentication tokens
1855  *
1856  * \ingroup pioctl
1857  *
1858  * \param[in] ain       the krb tickets from which to set the afs tokens
1859  * \param[out] aout     not in use
1860  *
1861  * \retval EINVAL
1862  *      Error if the ticket is either too long or too short
1863  * \retval EIO
1864  *      Error if the AFS initState is below 101
1865  * \retval ESRCH
1866  *      Error if the cell for which the Token is being set can't be found
1867  *
1868  * \post
1869  *      Set the Tokens for a specific cell name, unless there is none set,
1870  *      then default to primary
1871  *
1872  */
1873 DECL_PIOCTL(PSetTokens)
1874 {
1875     afs_int32 cellNum;
1876     afs_int32 size;
1877     afs_int32 code;
1878     struct unixuser *tu;
1879     struct ClearToken clear;
1880     char *stp;
1881     char *cellName;
1882     int stLen;
1883     struct vrequest treq;
1884     afs_int32 flag, set_parent_pag = 0;
1885
1886     AFS_STATCNT(PSetTokens);
1887     if (!afs_resourceinit_flag) {
1888         return EIO;
1889     }
1890
1891     if (afs_pd_getInt(ain, &stLen) != 0)
1892         return EINVAL;
1893
1894     stp = afs_pd_where(ain);    /* remember where the ticket is */
1895     if (stLen < 0 || stLen > MAXKTCTICKETLEN)
1896         return EINVAL;          /* malloc may fail */
1897     if (afs_pd_skip(ain, stLen) != 0)
1898         return EINVAL;
1899
1900     if (afs_pd_getInt(ain, &size) != 0)
1901         return EINVAL;
1902     if (size != sizeof(struct ClearToken))
1903         return EINVAL;
1904
1905     if (afs_pd_getBytes(ain, &clear, sizeof(struct ClearToken)) !=0)
1906         return EINVAL;
1907
1908     if (clear.AuthHandle == -1)
1909         clear.AuthHandle = 999; /* more rxvab compat stuff */
1910
1911     if (afs_pd_remaining(ain) != 0) {
1912         /* still stuff left?  we've got primary flag and cell name.
1913          * Set these */
1914
1915         if (afs_pd_getInt(ain, &flag) != 0)
1916             return EINVAL;
1917
1918         /* some versions of gcc appear to need != 0 in order to get this
1919          * right */
1920         if ((flag & 0x8000) != 0) {     /* XXX Use Constant XXX */
1921             flag &= ~0x8000;
1922             set_parent_pag = 1;
1923         }
1924
1925         if (afs_pd_getStringPtr(ain, &cellName) != 0)
1926             return EINVAL;
1927
1928         code = _settok_tokenCell(cellName, &cellNum, NULL);
1929         if (code)
1930             return code;
1931     } else {
1932         /* default to primary cell, primary id */
1933         code = _settok_tokenCell(NULL, &cellNum, &flag);
1934         if (code)
1935             return code;
1936     }
1937
1938     if (set_parent_pag) {
1939         if (_settok_setParentPag(acred) == 0) {
1940             afs_InitReq(&treq, *acred);
1941             areq = &treq;
1942         }
1943     }
1944
1945     /* now we just set the tokens */
1946     tu = afs_GetUser(areq->uid, cellNum, WRITE_LOCK);
1947     /* Set tokens destroys any that are already there */
1948     afs_FreeTokens(&tu->tokens);
1949     afs_AddRxkadToken(&tu->tokens, stp, stLen, &clear);
1950 #ifndef AFS_NOSTATS
1951     afs_stats_cmfullperf.authent.TicketUpdates++;
1952     afs_ComputePAGStats();
1953 #endif /* AFS_NOSTATS */
1954     tu->states |= UHasTokens;
1955     tu->states &= ~UTokensBad;
1956     afs_SetPrimary(tu, flag);
1957     tu->tokenTime = osi_Time();
1958     afs_ResetUserConns(tu);
1959     afs_NotifyUser(tu, UTokensObtained);
1960     afs_PutUser(tu, WRITE_LOCK);
1961
1962     return 0;
1963 }
1964
1965 /*!
1966  * VIOCGETVOLSTAT (4) - Get volume status
1967  *
1968  * \ingroup pioctl
1969  *
1970  * \param[in] ain       not in use
1971  * \param[out] aout     status of the volume
1972  *
1973  * \retval EINVAL       Error if some of the standard args aren't set
1974  *
1975  * \post
1976  *      The status of a volume (based on the FID of the volume), or an
1977  *      offline message /motd
1978  */
1979 DECL_PIOCTL(PGetVolumeStatus)
1980 {
1981     char volName[32];
1982     char *offLineMsg = afs_osi_Alloc(256);
1983     char *motd = afs_osi_Alloc(256);
1984     struct afs_conn *tc;
1985     afs_int32 code = 0;
1986     struct AFSFetchVolumeStatus volstat;
1987     char *Name;
1988     struct rx_connection *rxconn;
1989     XSTATS_DECLS;
1990
1991     osi_Assert(offLineMsg != NULL);
1992     osi_Assert(motd != NULL);
1993     AFS_STATCNT(PGetVolumeStatus);
1994     if (!avc) {
1995         code = EINVAL;
1996         goto out;
1997     }
1998     Name = volName;
1999     do {
2000         tc = afs_Conn(&avc->f.fid, areq, SHARED_LOCK, &rxconn);
2001         if (tc) {
2002             XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_GETVOLUMESTATUS);
2003             RX_AFS_GUNLOCK();
2004             code =
2005                 RXAFS_GetVolumeStatus(rxconn, avc->f.fid.Fid.Volume, &volstat,
2006                                       &Name, &offLineMsg, &motd);
2007             RX_AFS_GLOCK();
2008             XSTATS_END_TIME;
2009         } else
2010             code = -1;
2011     } while (afs_Analyze
2012              (tc, rxconn, code, &avc->f.fid, areq, AFS_STATS_FS_RPCIDX_GETVOLUMESTATUS,
2013               SHARED_LOCK, NULL));
2014
2015     if (code)
2016         goto out;
2017     /* Copy all this junk into msg->im_data, keeping track of the lengths. */
2018     if (afs_pd_putBytes(aout, &volstat, sizeof(VolumeStatus)) != 0)
2019         return E2BIG;
2020     if (afs_pd_putString(aout, volName) != 0)
2021         return E2BIG;
2022     if (afs_pd_putString(aout, offLineMsg) != 0)
2023         return E2BIG;
2024     if (afs_pd_putString(aout, motd) != 0)
2025         return E2BIG;
2026   out:
2027     afs_osi_Free(offLineMsg, 256);
2028     afs_osi_Free(motd, 256);
2029     return code;
2030 }
2031
2032 /*!
2033  * VIOCSETVOLSTAT (5) - Set volume status
2034  *
2035  * \ingroup pioctl
2036  *
2037  * \param[in] ain
2038  *      values to set the status at, offline message, message of the day,
2039  *      volume name, minimum quota, maximum quota
2040  * \param[out] aout
2041  *      status of a volume, offlines messages, minimum quota, maximumm quota
2042  *
2043  * \retval EINVAL
2044  *      Error if some of the standard args aren't set
2045  * \retval EROFS
2046  *      Error if the volume is read only, or a backup volume
2047  * \retval ENODEV
2048  *      Error if the volume can't be accessed
2049  * \retval E2BIG
2050  *      Error if the volume name, offline message, and motd are too big
2051  *
2052  * \post
2053  *      Set the status of a volume, including any offline messages,
2054  *      a minimum quota, and a maximum quota
2055  */
2056 DECL_PIOCTL(PSetVolumeStatus)
2057 {
2058     char *volName;
2059     char *offLineMsg;
2060     char *motd;
2061     struct afs_conn *tc;
2062     afs_int32 code = 0;
2063     struct AFSFetchVolumeStatus volstat;
2064     struct AFSStoreVolumeStatus storeStat;
2065     struct volume *tvp;
2066     struct rx_connection *rxconn;
2067     XSTATS_DECLS;
2068
2069     AFS_STATCNT(PSetVolumeStatus);
2070     if (!avc)
2071         return EINVAL;
2072
2073     tvp = afs_GetVolume(&avc->f.fid, areq, READ_LOCK);
2074     if (tvp) {
2075         if (tvp->states & (VRO | VBackup)) {
2076             afs_PutVolume(tvp, READ_LOCK);
2077             return EROFS;
2078         }
2079         afs_PutVolume(tvp, READ_LOCK);
2080     } else
2081         return ENODEV;
2082
2083
2084     if (afs_pd_getBytes(ain, &volstat, sizeof(AFSFetchVolumeStatus)) != 0)
2085         return EINVAL;
2086
2087     if (afs_pd_getStringPtr(ain, &volName) != 0)
2088         return EINVAL;
2089     if (strlen(volName) > 32)
2090         return E2BIG;
2091
2092     if (afs_pd_getStringPtr(ain, &offLineMsg) != 0)
2093         return EINVAL;
2094     if (strlen(offLineMsg) > 256)
2095         return E2BIG;
2096
2097     if (afs_pd_getStringPtr(ain, &motd) != 0)
2098         return EINVAL;
2099     if (strlen(motd) > 256)
2100         return E2BIG;
2101
2102     /* Done reading ... */
2103
2104     storeStat.Mask = 0;
2105     if (volstat.MinQuota != -1) {
2106         storeStat.MinQuota = volstat.MinQuota;
2107         storeStat.Mask |= AFS_SETMINQUOTA;
2108     }
2109     if (volstat.MaxQuota != -1) {
2110         storeStat.MaxQuota = volstat.MaxQuota;
2111         storeStat.Mask |= AFS_SETMAXQUOTA;
2112     }
2113     do {
2114         tc = afs_Conn(&avc->f.fid, areq, SHARED_LOCK, &rxconn);
2115         if (tc) {
2116             XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_SETVOLUMESTATUS);
2117             RX_AFS_GUNLOCK();
2118             code =
2119                 RXAFS_SetVolumeStatus(rxconn, avc->f.fid.Fid.Volume, &storeStat,
2120                                       volName, offLineMsg, motd);
2121             RX_AFS_GLOCK();
2122             XSTATS_END_TIME;
2123         } else
2124             code = -1;
2125     } while (afs_Analyze
2126              (tc, rxconn, code, &avc->f.fid, areq, AFS_STATS_FS_RPCIDX_SETVOLUMESTATUS,
2127               SHARED_LOCK, NULL));
2128
2129     if (code)
2130         return code;
2131     /* we are sending parms back to make compat. with prev system.  should
2132      * change interface later to not ask for current status, just set new
2133      * status */
2134
2135     if (afs_pd_putBytes(aout, &volstat, sizeof(VolumeStatus)) != 0)
2136         return EINVAL;
2137     if (afs_pd_putString(aout, volName) != 0)
2138         return EINVAL;
2139     if (afs_pd_putString(aout, offLineMsg) != 0)
2140         return EINVAL;
2141     if (afs_pd_putString(aout, motd) != 0)
2142         return EINVAL;
2143
2144     return code;
2145 }
2146
2147 /*!
2148  * VIOCFLUSH (6) - Invalidate cache entry
2149  *
2150  * \ingroup pioctl
2151  *
2152  * \param[in] ain       not in use
2153  * \param[out] aout     not in use
2154  *
2155  * \retval EINVAL       Error if some of the standard args aren't set
2156  *
2157  * \post Flush any information the cache manager has on an entry
2158  */
2159 DECL_PIOCTL(PFlush)
2160 {
2161     AFS_STATCNT(PFlush);
2162     if (!avc)
2163         return EINVAL;
2164 #ifdef AFS_BOZONLOCK_ENV
2165     afs_BozonLock(&avc->pvnLock, avc);  /* Since afs_TryToSmush will do a pvn_vptrunc */
2166 #endif
2167     ObtainWriteLock(&avc->lock, 225);
2168     afs_ResetVCache(avc, *acred);
2169     ReleaseWriteLock(&avc->lock);
2170 #ifdef AFS_BOZONLOCK_ENV
2171     afs_BozonUnlock(&avc->pvnLock, avc);
2172 #endif
2173     return 0;
2174 }
2175
2176 /*!
2177  * VIOC_AFS_STAT_MT_PT (29) - Stat mount point
2178  *
2179  * \ingroup pioctl
2180  *
2181  * \param[in] ain
2182  *      the last component in a path, related to mountpoint that we're
2183  *      looking for information about
2184  * \param[out] aout
2185  *      volume, cell, link data
2186  *
2187  * \retval EINVAL       Error if some of the standard args aren't set
2188  * \retval ENOTDIR      Error if the 'mount point' argument isn't a directory
2189  * \retval EIO          Error if the link data can't be accessed
2190  *
2191  * \post Get the volume, and cell, as well as the link data for a mount point
2192  */
2193 DECL_PIOCTL(PNewStatMount)
2194 {
2195     afs_int32 code;
2196     struct vcache *tvc;
2197     struct dcache *tdc;
2198     struct VenusFid tfid;
2199     char *bufp;
2200     char *name;
2201     struct sysname_info sysState;
2202     afs_size_t offset, len;
2203
2204     AFS_STATCNT(PNewStatMount);
2205     if (!avc)
2206         return EINVAL;
2207
2208     if (afs_pd_getStringPtr(ain, &name) != 0)
2209         return EINVAL;
2210
2211     code = afs_VerifyVCache(avc, areq);
2212     if (code)
2213         return code;
2214     if (vType(avc) != VDIR) {
2215         return ENOTDIR;
2216     }
2217     tdc = afs_GetDCache(avc, (afs_size_t) 0, areq, &offset, &len, 1);
2218     if (!tdc)
2219         return ENOENT;
2220     Check_AtSys(avc, name, &sysState, areq);
2221     ObtainReadLock(&tdc->lock);
2222     do {
2223         code = afs_dir_Lookup(tdc, sysState.name, &tfid.Fid);
2224     } while (code == ENOENT && Next_AtSys(avc, areq, &sysState));
2225     ReleaseReadLock(&tdc->lock);
2226     afs_PutDCache(tdc);         /* we're done with the data */
2227     bufp = sysState.name;
2228     if (code) {
2229         goto out;
2230     }
2231     tfid.Cell = avc->f.fid.Cell;
2232     tfid.Fid.Volume = avc->f.fid.Fid.Volume;
2233     if (!tfid.Fid.Unique && (avc->f.states & CForeign)) {
2234         tvc = afs_LookupVCache(&tfid, areq, NULL, avc, bufp);
2235     } else {
2236         tvc = afs_GetVCache(&tfid, areq, NULL, NULL);
2237     }
2238     if (!tvc) {
2239         code = ENOENT;
2240         goto out;
2241     }
2242     if (tvc->mvstat != 1) {
2243         afs_PutVCache(tvc);
2244         code = EINVAL;
2245         goto out;
2246     }
2247     ObtainWriteLock(&tvc->lock, 226);
2248     code = afs_HandleLink(tvc, areq);
2249     if (code == 0) {
2250         if (tvc->linkData) {
2251             if ((tvc->linkData[0] != '#') && (tvc->linkData[0] != '%'))
2252                 code = EINVAL;
2253             else {
2254                 /* we have the data */
2255                 if (afs_pd_putString(aout, tvc->linkData) != 0)
2256                     code = EINVAL;
2257             }
2258         } else
2259             code = EIO;
2260     }
2261     ReleaseWriteLock(&tvc->lock);
2262     afs_PutVCache(tvc);
2263   out:
2264     if (sysState.allocked)
2265         osi_FreeLargeSpace(bufp);
2266     return code;
2267 }
2268
2269 /*!
2270  * A helper function to get the n'th cell which a particular user has tokens
2271  * for. This is racy. If new tokens are added whilst we're iterating, then
2272  * we may return some cells twice. If tokens expire mid run, then we'll
2273  * miss some cells from our output. So, could be better, but that would
2274  * require an interface change.
2275  */
2276
2277 static struct unixuser *
2278 getNthCell(afs_int32 uid, afs_int32 iterator) {
2279     int i;
2280     struct unixuser *tu = NULL;
2281
2282     i = UHash(uid);
2283     ObtainReadLock(&afs_xuser);
2284     for (tu = afs_users[i]; tu; tu = tu->next) {
2285         if (tu->uid == uid && (tu->states & UHasTokens)) {
2286             if (iterator-- == 0)
2287             break;      /* are we done yet? */
2288         }
2289     }
2290     if (tu) {
2291         tu->refCount++;
2292     }
2293     ReleaseReadLock(&afs_xuser);
2294     if (tu) {
2295         afs_LockUser(tu, READ_LOCK, 0);
2296     }
2297
2298
2299     return tu;
2300 }
2301 /*!
2302  * VIOCGETTOK (8) - Get authentication tokens
2303  *
2304  * \ingroup pioctl
2305  *
2306  * \param[in] ain       cellid to return tokens for
2307  * \param[out] aout     token
2308  *
2309  * \retval EIO
2310  *      Error if the afs daemon hasn't started yet
2311  * \retval EDOM
2312  *      Error if the input parameter is out of the bounds of the available
2313  *      tokens
2314  * \retval ENOTCONN
2315  *      Error if there aren't tokens for this cell
2316  *
2317  * \post
2318  *      If the input paramater exists, get the token that corresponds to
2319  *      the parameter value, if there is no token at this value, get the
2320  *      token for the first cell
2321  *
2322  * \notes "it's a weird interface (from comments in the code)"
2323  */
2324
2325 DECL_PIOCTL(PGetTokens)
2326 {
2327     struct cell *tcell;
2328     struct unixuser *tu = NULL;
2329     union tokenUnion *token;
2330     afs_int32 iterator = 0;
2331     int newStyle;
2332     int cellNum;
2333     int code = E2BIG;
2334
2335     AFS_STATCNT(PGetTokens);
2336     if (!afs_resourceinit_flag) /* afs daemons haven't started yet */
2337         return EIO;             /* Inappropriate ioctl for device */
2338
2339     /* weird interface.  If input parameter is present, it is an integer and
2340      * we're supposed to return the parm'th tokens for this unix uid.
2341      * If not present, we just return tokens for cell 1.
2342      * If counter out of bounds, return EDOM.
2343      * If no tokens for the particular cell, return ENOTCONN.
2344      * Also, if this mysterious parm is present, we return, along with the
2345      * tokens, the primary cell indicator (an afs_int32 0) and the cell name
2346      * at the end, in that order.
2347      */
2348     newStyle = (afs_pd_remaining(ain) > 0);
2349     if (newStyle) {
2350         if (afs_pd_getInt(ain, &iterator) != 0)
2351             return EINVAL;
2352     }
2353     if (newStyle) {
2354         tu = getNthCell(areq->uid, iterator);
2355     } else {
2356         cellNum = afs_GetPrimaryCellNum();
2357         if (cellNum)
2358             tu = afs_FindUser(areq->uid, cellNum, READ_LOCK);
2359     }
2360     if (!tu) {
2361         return EDOM;
2362     }
2363     if (!(tu->states & UHasTokens)
2364         || !afs_HasUsableTokens(tu->tokens, osi_Time())) {
2365         tu->states |= (UTokensBad | UNeedsReset);
2366         afs_NotifyUser(tu, UTokensDropped);
2367         afs_PutUser(tu, READ_LOCK);
2368         return ENOTCONN;
2369     }
2370     token = afs_FindToken(tu->tokens, RX_SECIDX_KAD);
2371
2372     /* If they don't have an RXKAD token, but do have other tokens,
2373      * then sadly there's nothing this interface can do to help them. */
2374     if (token == NULL)
2375         return ENOTCONN;
2376
2377     /* for compat, we try to return 56 byte tix if they fit */
2378     iterator = token->rxkad.ticketLen;
2379     if (iterator < 56)
2380         iterator = 56;          /* # of bytes we're returning */
2381
2382     if (afs_pd_putInt(aout, iterator) != 0)
2383         goto out;
2384     if (afs_pd_putBytes(aout, token->rxkad.ticket, token->rxkad.ticketLen) != 0)
2385         goto out;
2386     if (token->rxkad.ticketLen < 56) {
2387         /* Tokens are always 56 bytes or larger */
2388         if (afs_pd_skip(aout, iterator - token->rxkad.ticketLen) != 0) {
2389             goto out;
2390         }
2391     }
2392
2393     if (afs_pd_putInt(aout, sizeof(struct ClearToken)) != 0)
2394         goto out;
2395     if (afs_pd_putBytes(aout, &token->rxkad.clearToken,
2396                         sizeof(struct ClearToken)) != 0)
2397         goto out;
2398
2399     if (newStyle) {
2400         /* put out primary id and cell name, too */
2401         iterator = (tu->states & UPrimary ? 1 : 0);
2402         if (afs_pd_putInt(aout, iterator) != 0)
2403             goto out;
2404         tcell = afs_GetCell(tu->cell, READ_LOCK);
2405         if (tcell) {
2406             if (afs_pd_putString(aout, tcell->cellName) != 0)
2407                 goto out;
2408             afs_PutCell(tcell, READ_LOCK);
2409         } else
2410             if (afs_pd_putString(aout, "") != 0)
2411                 goto out;
2412     }
2413     /* Got here, all is good */
2414     code = 0;
2415 out:
2416     afs_PutUser(tu, READ_LOCK);
2417     return code;
2418 }
2419
2420 /*!
2421  * VIOCUNLOG (9) - Invalidate tokens
2422  *
2423  * \ingroup pioctl
2424  *
2425  * \param[in] ain       not in use
2426  * \param[out] aout     not in use
2427  *
2428  * \retval EIO  Error if the afs daemon hasn't been started yet
2429  *
2430  * \post remove tokens from a user, specified by the user id
2431  *
2432  * \notes sets the token's time to 0, which then causes it to be removed
2433  * \notes Unlog is the same as un-pag in OpenAFS
2434  */
2435 DECL_PIOCTL(PUnlog)
2436 {
2437     afs_int32 i;
2438     struct unixuser *tu;
2439
2440     AFS_STATCNT(PUnlog);
2441     if (!afs_resourceinit_flag) /* afs daemons haven't started yet */
2442         return EIO;             /* Inappropriate ioctl for device */
2443
2444     i = UHash(areq->uid);
2445     ObtainWriteLock(&afs_xuser, 227);
2446     for (tu = afs_users[i]; tu; tu = tu->next) {
2447         if (tu->uid == areq->uid) {
2448             tu->refCount++;
2449             ReleaseWriteLock(&afs_xuser);
2450
2451             afs_LockUser(tu, WRITE_LOCK, 366);
2452
2453             tu->states &= ~UHasTokens;
2454             afs_FreeTokens(&tu->tokens);
2455             afs_NotifyUser(tu, UTokensDropped);
2456             /* We have to drop the lock over the call to afs_ResetUserConns,
2457              * since it obtains the afs_xvcache lock.  We could also keep
2458              * the lock, and modify ResetUserConns to take parm saying we
2459              * obtained the lock already, but that is overkill.  By keeping
2460              * the "tu" pointer held over the released lock, we guarantee
2461              * that we won't lose our place, and that we'll pass over
2462              * every user conn that existed when we began this call.
2463              */
2464             afs_ResetUserConns(tu);
2465             afs_PutUser(tu, WRITE_LOCK);
2466             ObtainWriteLock(&afs_xuser, 228);
2467 #ifdef UKERNEL
2468             /* set the expire times to 0, causes
2469              * afs_GCUserData to remove this entry
2470              */
2471             tu->tokenTime = 0;
2472 #endif /* UKERNEL */
2473         }
2474     }
2475     ReleaseWriteLock(&afs_xuser);
2476     return 0;
2477 }
2478
2479 /*!
2480  * VIOC_AFS_MARINER_HOST (32) - Get/set mariner (cache manager monitor) host
2481  *
2482  * \ingroup pioctl
2483  *
2484  * \param[in] ain       host address to be set
2485  * \param[out] aout     old host address
2486  *
2487  * \post
2488  *      depending on whether or not a variable is set, either get the host
2489  *      for the cache manager monitor, or set the old address and give it
2490  *      a new address
2491  *
2492  * \notes Errors turn off mariner
2493  */
2494 DECL_PIOCTL(PMariner)
2495 {
2496     afs_int32 newHostAddr;
2497     afs_int32 oldHostAddr;
2498
2499     AFS_STATCNT(PMariner);
2500     if (afs_mariner)
2501         memcpy((char *)&oldHostAddr, (char *)&afs_marinerHost,
2502                sizeof(afs_int32));
2503     else
2504         oldHostAddr = 0xffffffff;       /* disabled */
2505
2506     if (afs_pd_getInt(ain, &newHostAddr) != 0)
2507         return EINVAL;
2508
2509     if (newHostAddr == 0xffffffff) {
2510         /* disable mariner operations */
2511         afs_mariner = 0;
2512     } else if (newHostAddr) {
2513         afs_mariner = 1;
2514         afs_marinerHost = newHostAddr;
2515     }
2516
2517     if (afs_pd_putInt(aout, oldHostAddr) != 0)
2518         return E2BIG;
2519
2520     return 0;
2521 }
2522
2523 /*!
2524  * VIOCCKSERV (10) - Check that servers are up
2525  *
2526  * \ingroup pioctl
2527  *
2528  * \param[in] ain       name of the cell
2529  * \param[out] aout     current down server list
2530  *
2531  * \retval EIO          Error if the afs daemon hasn't started yet
2532  * \retval EACCES       Error if the user doesn't have super-user credentials
2533  * \retval ENOENT       Error if we are unable to obtain the cell
2534  *
2535  * \post
2536  *      Either a fast check (where it doesn't contact servers) or a
2537  *      local check (checks local cell only)
2538  */
2539 DECL_PIOCTL(PCheckServers)
2540 {
2541     int i;
2542     struct server *ts;
2543     afs_int32 temp;
2544     char *cellName = NULL;
2545     struct cell *cellp;
2546     struct chservinfo *pcheck;
2547
2548     AFS_STATCNT(PCheckServers);
2549
2550     if (!afs_resourceinit_flag) /* afs daemons haven't started yet */
2551         return EIO;             /* Inappropriate ioctl for device */
2552
2553     /* This is tricky, because we need to peak at the datastream to see
2554      * what we're getting. For now, let's cheat. */
2555
2556     /* ain contains either an int32 or a string */
2557     if (ain->remaining == 0)
2558         return EINVAL;
2559
2560     if (*(afs_int32 *)ain->ptr == 0x12345678) { /* For afs3.3 version */
2561         pcheck = afs_pd_inline(ain, sizeof(*pcheck));
2562         if (pcheck == NULL)
2563             return EINVAL;
2564
2565         if (pcheck->tinterval >= 0) {
2566             if (afs_pd_putInt(aout, afs_probe_interval) != 0)
2567                 return E2BIG;
2568             if (pcheck->tinterval > 0) {
2569                 if (!afs_osi_suser(*acred))
2570                     return EACCES;
2571                 afs_probe_interval = pcheck->tinterval;
2572             }
2573             return 0;
2574         }
2575         temp = pcheck->tflags;
2576         if (pcheck->tsize)
2577             cellName = pcheck->tbuffer;
2578     } else {                    /* For pre afs3.3 versions */
2579         if (afs_pd_getInt(ain, &temp) != 0)
2580             return EINVAL;
2581         if (afs_pd_remaining(ain) > 0) {
2582             if (afs_pd_getStringPtr(ain, &cellName) != 0)
2583                 return EINVAL;
2584         }
2585     }
2586
2587     /*
2588      * 1: fast check, don't contact servers.
2589      * 2: local cell only.
2590      */
2591     if (cellName) {
2592         /* have cell name, too */
2593         cellp = afs_GetCellByName(cellName, READ_LOCK);
2594         if (!cellp)
2595             return ENOENT;
2596     } else
2597         cellp = NULL;
2598     if (!cellp && (temp & 2)) {
2599         /* use local cell */
2600         cellp = afs_GetPrimaryCell(READ_LOCK);
2601     }
2602     if (!(temp & 1)) {          /* if not fast, call server checker routine */
2603         afs_CheckServers(1, cellp);     /* check down servers */
2604         afs_CheckServers(0, cellp);     /* check up servers */
2605     }
2606     /* now return the current down server list */
2607     ObtainReadLock(&afs_xserver);
2608     for (i = 0; i < NSERVERS; i++) {
2609         for (ts = afs_servers[i]; ts; ts = ts->next) {
2610             if (cellp && ts->cell != cellp)
2611                 continue;       /* cell spec'd and wrong */
2612             if ((ts->flags & SRVR_ISDOWN)
2613                 && ts->addr->sa_portal != ts->cell->vlport) {
2614                 afs_pd_putInt(aout, ts->addr->sa_ip);
2615             }
2616         }
2617     }
2618     ReleaseReadLock(&afs_xserver);
2619     if (cellp)
2620         afs_PutCell(cellp, READ_LOCK);
2621     return 0;
2622 }
2623
2624 /*!
2625  * VIOCCKBACK (11) - Check backup volume mappings
2626  *
2627  * \ingroup pioctl
2628  *
2629  * \param[in] ain       not in use
2630  * \param[out] aout     not in use
2631  *
2632  * \retval EIO          Error if the afs daemon hasn't started yet
2633  *
2634  * \post
2635  *      Check the root volume, and then check the names if the volume
2636  *      check variable is set to force, has expired, is busy, or if
2637  *      the mount points variable is set
2638  */
2639 DECL_PIOCTL(PCheckVolNames)
2640 {
2641     AFS_STATCNT(PCheckVolNames);
2642     if (!afs_resourceinit_flag) /* afs daemons haven't started yet */
2643         return EIO;             /* Inappropriate ioctl for device */
2644
2645     afs_CheckRootVolume();
2646     afs_CheckVolumeNames(AFS_VOLCHECK_FORCE | AFS_VOLCHECK_EXPIRED |
2647                          AFS_VOLCHECK_BUSY | AFS_VOLCHECK_MTPTS);
2648     return 0;
2649 }
2650
2651 /*!
2652  * VIOCCKCONN (12) - Check connections for a user
2653  *
2654  * \ingroup pioctl
2655  *
2656  * \param[in] ain       not in use
2657  * \param[out] aout     not in use
2658  *
2659  * \retval EACCESS
2660  *      Error if no user is specififed, the user has no tokens set,
2661  *      or if the user's tokens are bad
2662  *
2663  * \post
2664  *      check to see if a user has the correct authentication.
2665  *      If so, allow access.
2666  *
2667  * \notes Check the connections to all the servers specified
2668  */
2669 DECL_PIOCTL(PCheckAuth)
2670 {
2671     int i;
2672     struct srvAddr *sa;
2673     struct sa_conn_vector *tcv;
2674     struct unixuser *tu;
2675     afs_int32 retValue;
2676
2677     AFS_STATCNT(PCheckAuth);
2678     if (!afs_resourceinit_flag) /* afs daemons haven't started yet */
2679         return EIO;             /* Inappropriate ioctl for device */
2680
2681     retValue = 0;
2682     tu = afs_GetUser(areq->uid, 1, READ_LOCK);  /* check local cell authentication */
2683     if (!tu)
2684         retValue = EACCES;
2685     else {
2686         /* we have a user */
2687         ObtainReadLock(&afs_xsrvAddr);
2688         ObtainReadLock(&afs_xconn);
2689
2690         /* any tokens set? */
2691         if ((tu->states & UHasTokens) == 0)
2692             retValue = EACCES;
2693         /* all connections in cell 1 working? */
2694         for (i = 0; i < NSERVERS; i++) {
2695             for (sa = afs_srvAddrs[i]; sa; sa = sa->next_bkt) {
2696                 for (tcv = sa->conns; tcv; tcv = tcv->next) {
2697                     if (tcv->user == tu && (tu->states & UTokensBad))
2698                         retValue = EACCES;
2699                 }
2700             }
2701         }
2702         ReleaseReadLock(&afs_xsrvAddr);
2703         ReleaseReadLock(&afs_xconn);
2704         afs_PutUser(tu, READ_LOCK);
2705     }
2706     if (afs_pd_putInt(aout, retValue) != 0)
2707         return E2BIG;
2708     return 0;
2709 }
2710
2711 static int
2712 Prefetch(uparmtype apath, struct afs_ioctl *adata, int afollow,
2713          afs_ucred_t *acred)
2714 {
2715     char *tp;
2716     afs_int32 code;
2717 #if defined(AFS_SGI61_ENV) || defined(AFS_SUN57_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
2718     size_t bufferSize;
2719 #else
2720     u_int bufferSize;
2721 #endif
2722
2723     AFS_STATCNT(Prefetch);
2724     if (!apath)
2725         return EINVAL;
2726     tp = osi_AllocLargeSpace(1024);
2727     AFS_COPYINSTR(apath, tp, 1024, &bufferSize, code);
2728     if (code) {
2729         osi_FreeLargeSpace(tp);
2730         return code;
2731     }
2732     if (afs_BBusy()) {          /* do this as late as possible */
2733         osi_FreeLargeSpace(tp);
2734         return EWOULDBLOCK;     /* pretty close */
2735     }
2736     afs_BQueue(BOP_PATH, (struct vcache *)0, 0, 0, acred, (afs_size_t) 0,
2737                (afs_size_t) 0, tp, (void *)0, (void *)0);
2738     return 0;
2739 }
2740
2741 /*!
2742  * VIOCWHEREIS (14) - Find out where a volume is located
2743  *
2744  * \ingroup pioctl
2745  *
2746  * \param[in] ain       not in use
2747  * \param[out] aout     volume location
2748  *
2749  * \retval EINVAL       Error if some of the default arguments don't exist
2750  * \retval ENODEV       Error if there is no such volume
2751  *
2752  * \post fine a volume, based on a volume file id
2753  *
2754  * \notes check each of the servers specified
2755  */
2756 DECL_PIOCTL(PFindVolume)
2757 {
2758     struct volume *tvp;
2759     struct server *ts;
2760     afs_int32 i;
2761     int code = 0;
2762
2763     AFS_STATCNT(PFindVolume);
2764     if (!avc)
2765         return EINVAL;
2766     tvp = afs_GetVolume(&avc->f.fid, areq, READ_LOCK);
2767     if (!tvp)
2768         return ENODEV;
2769
2770     for (i = 0; i < AFS_MAXHOSTS; i++) {
2771         ts = tvp->serverHost[i];
2772         if (!ts)
2773             break;
2774         if (afs_pd_putInt(aout, ts->addr->sa_ip) != 0) {
2775             code = E2BIG;
2776             goto out;
2777         }
2778     }
2779     if (i < AFS_MAXHOSTS) {
2780         /* still room for terminating NULL, add it on */
2781         if (afs_pd_putInt(aout, 0) != 0) {
2782             code = E2BIG;
2783             goto out;
2784         }
2785     }
2786 out:
2787     afs_PutVolume(tvp, READ_LOCK);
2788     return code;
2789 }
2790
2791 /*!
2792  * VIOCACCESS (20) - Access using PRS_FS bits
2793  *
2794  * \ingroup pioctl
2795  *
2796  * \param[in] ain       PRS_FS bits
2797  * \param[out] aout     not in use
2798  *
2799  * \retval EINVAL       Error if some of the initial arguments aren't set
2800  * \retval EACCES       Error if access is denied
2801  *
2802  * \post check to make sure access is allowed
2803  */
2804 DECL_PIOCTL(PViceAccess)
2805 {
2806     afs_int32 code;
2807     afs_int32 temp;
2808
2809     AFS_STATCNT(PViceAccess);
2810     if (!avc)
2811         return EINVAL;
2812
2813     code = afs_VerifyVCache(avc, areq);
2814     if (code)
2815         return code;
2816
2817     if (afs_pd_getInt(ain, &temp) != 0)
2818         return EINVAL;
2819
2820     code = afs_AccessOK(avc, temp, areq, CHECK_MODE_BITS);
2821     if (code)
2822         return 0;
2823     else
2824         return EACCES;
2825 }
2826
2827 /*!
2828  * VIOC_GETPAG (13) - Get PAG value
2829  *
2830  * \ingroup pioctl
2831  *
2832  * \param[in] ain       not in use
2833  * \param[out] aout     PAG value or NOPAG
2834  *
2835  * \post get PAG value for the caller's cred
2836  */
2837 DECL_PIOCTL(PGetPAG)
2838 {
2839     afs_int32 pag;
2840
2841     pag = PagInCred(*acred);
2842
2843     return afs_pd_putInt(aout, pag);
2844 }
2845
2846 DECL_PIOCTL(PPrecache)
2847 {
2848     afs_int32 newValue;
2849
2850     /*AFS_STATCNT(PPrecache);*/
2851     if (!afs_osi_suser(*acred))
2852         return EACCES;
2853
2854     if (afs_pd_getInt(ain, &newValue) != 0)
2855         return EINVAL;
2856
2857     afs_preCache = newValue*1024;
2858     return 0;
2859 }
2860
2861 /*!
2862  * VIOCSETCACHESIZE (24) - Set venus cache size in 1000 units
2863  *
2864  * \ingroup pioctl
2865  *
2866  * \param[in] ain       the size the venus cache should be set to
2867  * \param[out] aout     not in use
2868  *
2869  * \retval EACCES       Error if the user doesn't have super-user credentials
2870  * \retval EROFS        Error if the cache is set to be in memory
2871  *
2872  * \post
2873  *      Set the cache size based on user input.  If no size is given,
2874  *      set it to the default OpenAFS cache size.
2875  *
2876  * \notes
2877  *      recompute the general cache parameters for every single block allocated
2878  */
2879 DECL_PIOCTL(PSetCacheSize)
2880 {
2881     afs_int32 newValue;
2882     int waitcnt = 0;
2883
2884     AFS_STATCNT(PSetCacheSize);
2885
2886     if (!afs_osi_suser(*acred))
2887         return EACCES;
2888     /* too many things are setup initially in mem cache version */
2889     if (cacheDiskType == AFS_FCACHE_TYPE_MEM)
2890         return EROFS;
2891     if (afs_pd_getInt(ain, &newValue) != 0)
2892         return EINVAL;
2893     if (newValue == 0)
2894         afs_cacheBlocks = afs_stats_cmperf.cacheBlocksOrig;
2895     else {
2896         if (newValue < afs_min_cache)
2897             afs_cacheBlocks = afs_min_cache;
2898         else
2899             afs_cacheBlocks = newValue;
2900     }
2901     afs_stats_cmperf.cacheBlocksTotal = afs_cacheBlocks;
2902     afs_ComputeCacheParms();    /* recompute basic cache parameters */
2903     afs_MaybeWakeupTruncateDaemon();
2904     while (waitcnt++ < 100 && afs_cacheBlocks < afs_blocksUsed) {
2905         afs_osi_Wait(1000, 0, 0);
2906         afs_MaybeWakeupTruncateDaemon();
2907     }
2908     return 0;
2909 }
2910
2911 #define MAXGCSTATS      16
2912 /*!
2913  * VIOCGETCACHEPARMS (40) - Get cache stats
2914  *
2915  * \ingroup pioctl
2916  *
2917  * \param[in] ain       afs index flags
2918  * \param[out] aout     cache blocks, blocks used, blocks files (in an array)
2919  *
2920  * \post Get the cache blocks, and how many of the cache blocks there are
2921  */
2922 DECL_PIOCTL(PGetCacheSize)
2923 {
2924     afs_int32 results[MAXGCSTATS];
2925     afs_int32 flags;
2926     struct dcache * tdc;
2927     int i, size;
2928
2929     AFS_STATCNT(PGetCacheSize);
2930
2931     if (afs_pd_remaining(ain) == sizeof(afs_int32)) {
2932         afs_pd_getInt(ain, &flags); /* can't error, we just checked size */
2933     } else if (afs_pd_remaining(ain) == 0) {
2934         flags = 0;
2935     } else {
2936         return EINVAL;
2937     }
2938
2939     memset(results, 0, sizeof(results));
2940     results[0] = afs_cacheBlocks;
2941     results[1] = afs_blocksUsed;
2942     results[2] = afs_cacheFiles;
2943
2944     if (1 == flags){
2945         for (i = 0; i < afs_cacheFiles; i++) {
2946             if (afs_indexFlags[i] & IFFree) results[3]++;
2947         }
2948     } else if (2 == flags){
2949         for (i = 0; i < afs_cacheFiles; i++) {
2950             if (afs_indexFlags[i] & IFFree) results[3]++;
2951             if (afs_indexFlags[i] & IFEverUsed) results[4]++;
2952             if (afs_indexFlags[i] & IFDataMod) results[5]++;
2953             if (afs_indexFlags[i] & IFDirtyPages) results[6]++;
2954             if (afs_indexFlags[i] & IFAnyPages) results[7]++;
2955             if (afs_indexFlags[i] & IFDiscarded) results[8]++;
2956
2957             tdc = afs_indexTable[i];
2958             if (tdc){
2959                 results[9]++;
2960                 size = tdc->validPos;
2961                 if ( 0 < size && size < (1<<12) ) results[10]++;
2962                 else if (size < (1<<14) ) results[11]++;
2963                 else if (size < (1<<16) ) results[12]++;
2964                 else if (size < (1<<18) ) results[13]++;
2965                 else if (size < (1<<20) ) results[14]++;
2966                 else if (size >= (1<<20) ) results[15]++;
2967             }
2968         }
2969     }
2970     return afs_pd_putBytes(aout, results, sizeof(results));
2971 }
2972
2973 /*!
2974  * VIOCFLUSHCB (25) - Flush callback only
2975  *
2976  * \ingroup pioctl
2977  *
2978  * \param[in] ain       not in use
2979  * \param[out] aout     not in use
2980  *
2981  * \retval EINVAL       Error if some of the standard args aren't set
2982  * \retval 0            0 returned if the volume is set to read-only
2983  *
2984  * \post
2985  *      Flushes callbacks, by setting the length of callbacks to one,
2986  *      setting the next callback to be sent to the CB_DROPPED value,
2987  *      and then dequeues everything else.
2988  */
2989 DECL_PIOCTL(PRemoveCallBack)
2990 {
2991     struct afs_conn *tc;
2992     afs_int32 code = 0;
2993     struct AFSCallBack CallBacks_Array[1];
2994     struct AFSCBFids theFids;
2995     struct AFSCBs theCBs;
2996     struct rx_connection *rxconn;
2997     XSTATS_DECLS;
2998
2999     AFS_STATCNT(PRemoveCallBack);
3000     if (!avc)
3001         return EINVAL;
3002     if (avc->f.states & CRO)
3003         return 0;               /* read-only-ness can't change */
3004     ObtainWriteLock(&avc->lock, 229);
3005     theFids.AFSCBFids_len = 1;
3006     theCBs.AFSCBs_len = 1;
3007     theFids.AFSCBFids_val = (struct AFSFid *)&avc->f.fid.Fid;
3008     theCBs.AFSCBs_val = CallBacks_Array;
3009     CallBacks_Array[0].CallBackType = CB_DROPPED;
3010     if (avc->callback) {
3011         do {
3012             tc = afs_Conn(&avc->f.fid, areq, SHARED_LOCK, &rxconn);
3013             if (tc) {
3014                 XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_GIVEUPCALLBACKS);
3015                 RX_AFS_GUNLOCK();
3016                 code = RXAFS_GiveUpCallBacks(rxconn, &theFids, &theCBs);
3017                 RX_AFS_GLOCK();
3018                 XSTATS_END_TIME;
3019             }
3020             /* don't set code on failure since we wouldn't use it */
3021         } while (afs_Analyze
3022                  (tc, rxconn, code, &avc->f.fid, areq,
3023                   AFS_STATS_FS_RPCIDX_GIVEUPCALLBACKS, SHARED_LOCK, NULL));
3024
3025         ObtainWriteLock(&afs_xcbhash, 457);
3026         afs_DequeueCallback(avc);
3027         avc->callback = 0;
3028         avc->f.states &= ~(CStatd | CUnique);
3029         ReleaseWriteLock(&afs_xcbhash);
3030         if (avc->f.fid.Fid.Vnode & 1 || (vType(avc) == VDIR))
3031             osi_dnlc_purgedp(avc);
3032     }
3033     ReleaseWriteLock(&avc->lock);
3034     return 0;
3035 }
3036
3037 /*!
3038  * VIOCNEWCELL (26) - Configure new cell
3039  *
3040  * \ingroup pioctl
3041  *
3042  * \param[in] ain
3043  *      the name of the cell, the hosts that will be a part of the cell,
3044  *      whether or not it's linked with another cell, the other cell it's
3045  *      linked with, the file server port, and the volume server port
3046  * \param[out] aout
3047  *      not in use
3048  *
3049  * \retval EIO          Error if the afs daemon hasn't started yet
3050  * \retval EACCES       Error if the user doesn't have super-user cedentials
3051  * \retval EINVAL       Error if some 'magic' var doesn't have a certain bit set
3052  *
3053  * \post creates a new cell
3054  */
3055 DECL_PIOCTL(PNewCell)
3056 {
3057     afs_int32 cellHosts[AFS_MAXCELLHOSTS], magic = 0;
3058     char *newcell = NULL;
3059     char *linkedcell = NULL;
3060     afs_int32 code, ls;
3061     afs_int32 linkedstate = 0;
3062     afs_int32 fsport = 0, vlport = 0;
3063     int skip;
3064
3065     AFS_STATCNT(PNewCell);
3066     if (!afs_resourceinit_flag) /* afs daemons haven't started yet */
3067         return EIO;             /* Inappropriate ioctl for device */
3068
3069     if (!afs_osi_suser(*acred))
3070         return EACCES;
3071
3072     if (afs_pd_getInt(ain, &magic) != 0)
3073         return EINVAL;
3074     if (magic != 0x12345678)
3075         return EINVAL;
3076
3077     /* A 3.4 fs newcell command will pass an array of AFS_MAXCELLHOSTS
3078      * server addresses while the 3.5 fs newcell command passes
3079      * AFS_MAXHOSTS. To figure out which is which, check if the cellname
3080      * is good.
3081      *
3082      * This whole logic is bogus, because it relies on the newer command
3083      * sending its 12th address as 0.
3084      */
3085     if ((afs_pd_remaining(ain) < AFS_MAXCELLHOSTS +3) * sizeof(afs_int32))
3086         return EINVAL;
3087
3088     newcell = afs_pd_where(ain) + (AFS_MAXCELLHOSTS + 3) * sizeof(afs_int32);
3089     if (newcell[0] != '\0') {
3090         skip = 0;
3091     } else {
3092         skip = AFS_MAXHOSTS - AFS_MAXCELLHOSTS;
3093     }
3094
3095     /* AFS_MAXCELLHOSTS (=8) is less than AFS_MAXHOSTS (=13) */
3096     if (afs_pd_getBytes(ain, &cellHosts,
3097                         AFS_MAXCELLHOSTS * sizeof(afs_int32)) != 0)
3098         return EINVAL;
3099     if (afs_pd_skip(ain, skip * sizeof(afs_int32)) !=0)
3100         return EINVAL;
3101
3102     if (afs_pd_getInt(ain, &fsport) != 0)
3103         return EINVAL;
3104     if (fsport < 1024)
3105         fsport = 0;             /* Privileged ports not allowed */
3106
3107     if (afs_pd_getInt(ain, &vlport) != 0)
3108         return EINVAL;
3109     if (vlport < 1024)
3110         vlport = 0;             /* Privileged ports not allowed */
3111
3112     if (afs_pd_getInt(ain, &ls) != 0)
3113         return EINVAL;
3114
3115     if (afs_pd_getStringPtr(ain, &newcell) != 0)
3116         return EINVAL;
3117
3118     if (ls & 1) {
3119         if (afs_pd_getStringPtr(ain, &linkedcell) != 0)
3120             return EINVAL;
3121         linkedstate |= CLinkedCell;
3122     }
3123
3124     linkedstate |= CNoSUID;     /* setuid is disabled by default for fs newcell */
3125     code =
3126         afs_NewCell(newcell, cellHosts, linkedstate, linkedcell, fsport,
3127                     vlport, (int)0);
3128     return code;
3129 }
3130
3131 DECL_PIOCTL(PNewAlias)
3132 {
3133     /* create a new cell alias */
3134     char *realName, *aliasName;
3135
3136     if (!afs_resourceinit_flag) /* afs daemons haven't started yet */
3137         return EIO;             /* Inappropriate ioctl for device */
3138
3139     if (!afs_osi_suser(*acred))
3140         return EACCES;
3141
3142     if (afs_pd_getStringPtr(ain, &aliasName) != 0)
3143         return EINVAL;
3144     if (afs_pd_getStringPtr(ain, &realName) != 0)
3145         return EINVAL;
3146
3147     return afs_NewCellAlias(aliasName, realName);
3148 }
3149
3150 /*!
3151  * VIOCGETCELL (27) - Get cell info
3152  *
3153  * \ingroup pioctl
3154  *
3155  * \param[in] ain       The cell index of a specific cell
3156  * \param[out] aout     list of servers in the cell
3157  *
3158  * \retval EIO          Error if the afs daemon hasn't started yet
3159  * \retval EDOM         Error if there is no cell asked about
3160  *
3161  * \post Lists the cell's server names and and addresses
3162  */
3163 DECL_PIOCTL(PListCells)
3164 {
3165     afs_int32 whichCell;
3166     struct cell *tcell = 0;
3167     afs_int32 i;
3168     int code;
3169
3170     AFS_STATCNT(PListCells);
3171     if (!afs_resourceinit_flag) /* afs daemons haven't started yet */
3172         return EIO;             /* Inappropriate ioctl for device */
3173
3174     if (afs_pd_getInt(ain, &whichCell) != 0)
3175         return EINVAL;
3176
3177     tcell = afs_GetCellByIndex(whichCell, READ_LOCK);
3178     if (!tcell)
3179         return EDOM;
3180
3181     code = E2BIG;
3182
3183     for (i = 0; i < AFS_MAXCELLHOSTS; i++) {
3184         if (tcell->cellHosts[i] == 0)
3185             break;
3186         if (afs_pd_putInt(aout, tcell->cellHosts[i]->addr->sa_ip) != 0)
3187             goto out;
3188     }
3189     for (;i < AFS_MAXCELLHOSTS; i++) {
3190         if (afs_pd_putInt(aout, 0) != 0)
3191             goto out;
3192     }
3193     if (afs_pd_putString(aout, tcell->cellName) != 0)
3194         goto out;
3195     code = 0;
3196
3197 out:
3198     afs_PutCell(tcell, READ_LOCK);
3199     return code;
3200 }
3201
3202 DECL_PIOCTL(PListAliases)
3203 {
3204     afs_int32 whichAlias;
3205     struct cell_alias *tcalias = 0;
3206     int code;
3207
3208     if (!afs_resourceinit_flag) /* afs daemons haven't started yet */
3209         return EIO;             /* Inappropriate ioctl for device */
3210
3211     if (afs_pd_getInt(ain, &whichAlias) != 0)
3212         return EINVAL;
3213
3214     tcalias = afs_GetCellAlias(whichAlias);
3215     if (tcalias == NULL)
3216         return EDOM;
3217
3218     code = E2BIG;
3219     if (afs_pd_putString(aout, tcalias->alias) != 0)
3220         goto out;
3221     if (afs_pd_putString(aout, tcalias->cell) != 0)
3222         goto out;
3223
3224     code = 0;
3225 out:
3226     afs_PutCellAlias(tcalias);
3227     return code;
3228 }
3229
3230 /*!
3231  * VIOC_AFS_DELETE_MT_PT (28) - Delete mount point
3232  *
3233  * \ingroup pioctl
3234  *
3235  * \param[in] ain       the name of the file in this dir to remove
3236  * \param[out] aout     not in use
3237  *
3238  * \retval EINVAL
3239  *      Error if some of the standard args aren't set
3240  * \retval ENOTDIR
3241  *      Error if the argument to remove is not a directory
3242  * \retval ENOENT
3243  *      Error if there is no cache to remove the mount point from or
3244  *      if a vcache doesn't exist
3245  *
3246  * \post
3247  *      Ensure that everything is OK before deleting the mountpoint.
3248  *      If not, don't delete.  Delete a mount point based on a file id.
3249  */
3250 DECL_PIOCTL(PRemoveMount)
3251 {
3252     afs_int32 code;
3253     char *bufp;
3254     char *name;
3255     struct sysname_info sysState;
3256     afs_size_t offset, len;
3257     struct afs_conn *tc;
3258     struct dcache *tdc;
3259     struct vcache *tvc;
3260     struct AFSFetchStatus OutDirStatus;
3261     struct VenusFid tfid;
3262     struct AFSVolSync tsync;
3263     struct rx_connection *rxconn;
3264     XSTATS_DECLS;
3265
3266     /* "ain" is the name of the file in this dir to remove */
3267
3268     AFS_STATCNT(PRemoveMount);
3269     if (!avc)
3270         return EINVAL;
3271     if (afs_pd_getStringPtr(ain, &name) != 0)
3272         return EINVAL;
3273
3274     code = afs_VerifyVCache(avc, areq);
3275     if (code)
3276         return code;
3277     if (vType(avc) != VDIR)
3278         return ENOTDIR;
3279
3280     tdc = afs_GetDCache(avc, (afs_size_t) 0, areq, &offset, &len, 1);   /* test for error below */
3281     if (!tdc)
3282         return ENOENT;
3283     Check_AtSys(avc, name, &sysState, areq);
3284     ObtainReadLock(&tdc->lock);
3285     do {
3286         code = afs_dir_Lookup(tdc, sysState.name, &tfid.Fid);
3287     } while (code == ENOENT && Next_AtSys(avc, areq, &sysState));
3288     ReleaseReadLock(&tdc->lock);
3289     bufp = sysState.name;
3290     if (code) {
3291         afs_PutDCache(tdc);
3292         goto out;
3293     }
3294     tfid.Cell = avc->f.fid.Cell;
3295     tfid.Fid.Volume = avc->f.fid.Fid.Volume;
3296     if (!tfid.Fid.Unique && (avc->f.states & CForeign)) {
3297         tvc = afs_LookupVCache(&tfid, areq, NULL, avc, bufp);
3298     } else {
3299         tvc = afs_GetVCache(&tfid, areq, NULL, NULL);
3300     }
3301     if (!tvc) {
3302         code = ENOENT;
3303         afs_PutDCache(tdc);
3304         goto out;
3305     }
3306     if (tvc->mvstat != 1) {
3307         afs_PutDCache(tdc);
3308         afs_PutVCache(tvc);
3309         code = EINVAL;
3310         goto out;
3311     }
3312     ObtainWriteLock(&tvc->lock, 230);
3313     code = afs_HandleLink(tvc, areq);
3314     if (!code) {
3315         if (tvc->linkData) {
3316             if ((tvc->linkData[0] != '#') && (tvc->linkData[0] != '%'))
3317                 code = EINVAL;
3318         } else
3319             code = EIO;
3320     }
3321     ReleaseWriteLock(&tvc->lock);
3322     osi_dnlc_purgedp(tvc);
3323     afs_PutVCache(tvc);
3324     if (code) {
3325         afs_PutDCache(tdc);
3326         goto out;
3327     }
3328     ObtainWriteLock(&avc->lock, 231);
3329     osi_dnlc_remove(avc, bufp, tvc);
3330     do {
3331         tc = afs_Conn(&avc->f.fid, areq, SHARED_LOCK, &rxconn);
3332         if (tc) {
3333             XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_REMOVEFILE);
3334             RX_AFS_GUNLOCK();
3335             code =
3336                 RXAFS_RemoveFile(rxconn, (struct AFSFid *)&avc->f.fid.Fid, bufp,
3337                                  &OutDirStatus, &tsync);
3338             RX_AFS_GLOCK();
3339             XSTATS_END_TIME;
3340         } else
3341             code = -1;
3342     } while (afs_Analyze
3343              (tc, rxconn, code, &avc->f.fid, areq, AFS_STATS_FS_RPCIDX_REMOVEFILE,
3344               SHARED_LOCK, NULL));
3345
3346     if (code) {
3347         if (tdc)
3348             afs_PutDCache(tdc);
3349         ReleaseWriteLock(&avc->lock);
3350         goto out;
3351     }
3352     if (tdc) {
3353         /* we have the thing in the cache */
3354         ObtainWriteLock(&tdc->lock, 661);
3355         if (afs_LocalHero(avc, tdc, &OutDirStatus, 1)) {
3356             /* we can do it locally */
3357             code = afs_dir_Delete(tdc, bufp);
3358             if (code) {
3359                 ZapDCE(tdc);    /* surprise error -- invalid value */
3360                 DZap(tdc);
3361             }
3362         }
3363         ReleaseWriteLock(&tdc->lock);
3364         afs_PutDCache(tdc);     /* drop ref count */
3365     }
3366     avc->f.states &= ~CUnique;  /* For the dfs xlator */
3367     ReleaseWriteLock(&avc->lock);
3368     code = 0;
3369   out:
3370     if (sysState.allocked)
3371         osi_FreeLargeSpace(bufp);
3372     return code;
3373 }
3374
3375 /*!
3376  * VIOC_GETCELLSTATUS (35) - Get cell status info
3377  *
3378  * \ingroup pioctl
3379  *
3380  * \param[in] ain       The cell you want status information on
3381  * \param[out] aout     cell state (as a struct)
3382  *
3383  * \retval EIO          Error if the afs daemon hasn't started yet
3384  * \retval ENOENT       Error if the cell doesn't exist
3385  *
3386  * \post Returns the state of the cell as defined in a struct cell
3387  */
3388 DECL_PIOCTL(PGetCellStatus)
3389 {
3390     struct cell *tcell;
3391     char *cellName;
3392     afs_int32 temp;
3393
3394     AFS_STATCNT(PGetCellStatus);
3395     if (!afs_resourceinit_flag) /* afs daemons haven't started yet */
3396         return EIO;             /* Inappropriate ioctl for device */
3397
3398     if (afs_pd_getStringPtr(ain, &cellName) != 0)
3399         return EINVAL;
3400
3401     tcell = afs_GetCellByName(cellName, READ_LOCK);
3402     if (!tcell)
3403         return ENOENT;
3404     temp = tcell->states;
3405     afs_PutCell(tcell, READ_LOCK);
3406
3407     return afs_pd_putInt(aout, temp);
3408 }
3409
3410 /*!
3411  * VIOC_SETCELLSTATUS (36) - Set corresponding info
3412  *
3413  * \ingroup pioctl
3414  *
3415  * \param[in] ain
3416  *      The cell you want to set information about, and the values you
3417  *      want to set
3418  * \param[out] aout
3419  *      not in use
3420  *
3421  * \retval EIO          Error if the afs daemon hasn't started yet
3422  * \retval EACCES       Error if the user doesn't have super-user credentials
3423  *
3424  * \post
3425  *      Set the state of the cell in a defined struct cell, based on
3426  *      whether or not SetUID is allowed
3427  */
3428 DECL_PIOCTL(PSetCellStatus)
3429 {
3430     struct cell *tcell;
3431     char *cellName;
3432     afs_int32 flags0, flags1;
3433
3434     if (!afs_osi_suser(*acred))
3435         return EACCES;
3436     if (!afs_resourceinit_flag) /* afs daemons haven't started yet */
3437         return EIO;             /* Inappropriate ioctl for device */
3438
3439     if (afs_pd_getInt(ain, &flags0) != 0)
3440         return EINVAL;
3441     if (afs_pd_getInt(ain, &flags1) != 0)
3442         return EINVAL;
3443     if (afs_pd_getStringPtr(ain, &cellName) != 0)
3444         return EINVAL;
3445
3446     tcell = afs_GetCellByName(cellName, WRITE_LOCK);
3447     if (!tcell)
3448         return ENOENT;
3449     if (flags0 & CNoSUID)
3450         tcell->states |= CNoSUID;
3451     else
3452         tcell->states &= ~CNoSUID;
3453     afs_PutCell(tcell, WRITE_LOCK);
3454     return 0;
3455 }
3456
3457 /*!
3458  * VIOC_FLUSHVOLUME (37) - Flush whole volume's data
3459  *
3460  * \ingroup pioctl
3461  *
3462  * \param[in] ain       not in use (args in avc)
3463  * \param[out] aout     not in use
3464  *
3465  * \retval EINVAL       Error if some of the standard args aren't set
3466  * \retval EIO          Error if the afs daemon hasn't started yet
3467  *
3468  * \post
3469  *      Flush all cached contents of a volume.  Exactly what stays and what
3470  *      goes depends on the platform.
3471  *
3472  * \notes
3473  *      Does not flush a file that a user has open and is using, because
3474  *      it will be re-created on next write.  Also purges the dnlc,
3475  *      because things are screwed up.
3476  */
3477 DECL_PIOCTL(PFlushVolumeData)
3478 {
3479     afs_int32 i;
3480     struct dcache *tdc;
3481     struct vcache *tvc;
3482     struct volume *tv;
3483     afs_int32 cell, volume;
3484     struct afs_q *tq, *uq;
3485 #ifdef AFS_DARWIN80_ENV
3486     vnode_t vp;
3487 #endif
3488
3489     AFS_STATCNT(PFlushVolumeData);
3490     if (!avc)
3491         return EINVAL;
3492     if (!afs_resourceinit_flag) /* afs daemons haven't started yet */
3493         return EIO;             /* Inappropriate ioctl for device */
3494
3495     volume = avc->f.fid.Fid.Volume;     /* who to zap */
3496     cell = avc->f.fid.Cell;
3497
3498     /*
3499      * Clear stat'd flag from all vnodes from this volume; this will
3500      * invalidate all the vcaches associated with the volume.
3501      */
3502  loop:
3503     ObtainReadLock(&afs_xvcache);
3504     i = VCHashV(&avc->f.fid);
3505     for (tq = afs_vhashTV[i].prev; tq != &afs_vhashTV[i]; tq = uq) {
3506             uq = QPrev(tq);
3507             tvc = QTOVH(tq);
3508             if (tvc->f.fid.Fid.Volume == volume && tvc->f.fid.Cell == cell) {
3509                 if (tvc->f.states & CVInit) {
3510                     ReleaseReadLock(&afs_xvcache);
3511                     afs_osi_Sleep(&tvc->f.states);
3512                     goto loop;
3513                 }
3514 #ifdef AFS_DARWIN80_ENV
3515                 if (tvc->f.states & CDeadVnode) {
3516                     ReleaseReadLock(&afs_xvcache);
3517                     afs_osi_Sleep(&tvc->f.states);
3518                     goto loop;
3519                 }
3520                 vp = AFSTOV(tvc);
3521                 if (vnode_get(vp))
3522                     continue;
3523                 if (vnode_ref(vp)) {
3524                     AFS_GUNLOCK();
3525                     vnode_put(vp);
3526                     AFS_GLOCK();
3527                     continue;
3528                 }
3529 #else
3530                 AFS_FAST_HOLD(tvc);
3531 #endif
3532                 ReleaseReadLock(&afs_xvcache);
3533 #ifdef AFS_BOZONLOCK_ENV
3534                 afs_BozonLock(&tvc->pvnLock, tvc);      /* Since afs_TryToSmush will do a pvn_vptrunc */
3535 #endif
3536                 ObtainWriteLock(&tvc->lock, 232);
3537
3538                 ObtainWriteLock(&afs_xcbhash, 458);
3539                 afs_DequeueCallback(tvc);
3540                 tvc->f.states &= ~(CStatd | CDirty);
3541                 ReleaseWriteLock(&afs_xcbhash);
3542                 if (tvc->f.fid.Fid.Vnode & 1 || (vType(tvc) == VDIR))
3543                     osi_dnlc_purgedp(tvc);
3544                 afs_TryToSmush(tvc, *acred, 1);
3545                 ReleaseWriteLock(&tvc->lock);
3546 #ifdef AFS_BOZONLOCK_ENV
3547                 afs_BozonUnlock(&tvc->pvnLock, tvc);
3548 #endif
3549 #ifdef AFS_DARWIN80_ENV
3550                 vnode_put(AFSTOV(tvc));
3551 #endif
3552                 ObtainReadLock(&afs_xvcache);
3553                 uq = QPrev(tq);
3554                 /* our tvc ptr is still good until now */
3555                 AFS_FAST_RELE(tvc);
3556             }
3557         }
3558     ReleaseReadLock(&afs_xvcache);
3559
3560
3561     ObtainWriteLock(&afs_xdcache, 328); /* needed to flush any stuff */
3562     for (i = 0; i < afs_cacheFiles; i++) {
3563         if (!(afs_indexFlags[i] & IFEverUsed))
3564             continue;           /* never had any data */
3565         tdc = afs_GetDSlot(i, NULL);
3566         if (tdc->refCount <= 1) {    /* too high, in use by running sys call */
3567             ReleaseReadLock(&tdc->tlock);
3568             if (tdc->f.fid.Fid.Volume == volume && tdc->f.fid.Cell == cell) {
3569                 if (!(afs_indexFlags[i] & IFDataMod)) {
3570                     /* if the file is modified, but has a ref cnt of only 1,
3571                      * then someone probably has the file open and is writing
3572                      * into it. Better to skip flushing such a file, it will be
3573                      * brought back immediately on the next write anyway.
3574                      *
3575                      * If we *must* flush, then this code has to be rearranged
3576                      * to call afs_storeAllSegments() first */
3577                     afs_FlushDCache(tdc);
3578                 }
3579             }
3580         } else {
3581             ReleaseReadLock(&tdc->tlock);
3582         }
3583         afs_PutDCache(tdc);     /* bumped by getdslot */
3584     }
3585     ReleaseWriteLock(&afs_xdcache);
3586
3587     ObtainReadLock(&afs_xvolume);
3588     for (i = 0; i < NVOLS; i++) {
3589         for (tv = afs_volumes[i]; tv; tv = tv->next) {
3590             if (tv->volume == volume) {
3591                 afs_ResetVolumeInfo(tv);
3592                 break;
3593             }
3594         }
3595     }
3596     ReleaseReadLock(&afs_xvolume);
3597
3598     /* probably, a user is doing this, probably, because things are screwed up.
3599      * maybe it's the dnlc's fault? */
3600     osi_dnlc_purge();
3601     return 0;
3602 }
3603
3604
3605 /*!
3606  * VIOCGETVCXSTATUS (41) - gets vnode x status
3607  *
3608  * \ingroup pioctl
3609  *
3610  * \param[in] ain
3611  *      not in use (avc used)
3612  * \param[out] aout
3613  *      vcxstat: the file id, the data version, any lock, the parent vnode,
3614  *      the parent unique id, the trunc position, the callback, cbExpires,
3615  *      what access is being made, what files are open,
3616  *      any users executing/writing, the flock count, the states,
3617  *      the move stat
3618  *
3619  * \retval EINVAL
3620  *      Error if some of the initial default arguments aren't set
3621  * \retval EACCES
3622  *      Error if access to check the mode bits is denied
3623  *
3624  * \post
3625  *      gets stats for the vnode, a struct listed in vcxstat
3626  */
3627 DECL_PIOCTL(PGetVnodeXStatus)
3628 {
3629     afs_int32 code;
3630     struct vcxstat stat;
3631     afs_int32 mode, i;
3632
3633 /*  AFS_STATCNT(PGetVnodeXStatus); */
3634     if (!avc)
3635         return EINVAL;
3636     code = afs_VerifyVCache(avc, areq);
3637     if (code)
3638         return code;
3639     if (vType(avc) == VDIR)
3640         mode = PRSFS_LOOKUP;
3641     else
3642         mode = PRSFS_READ;
3643     if (!afs_AccessOK(avc, mode, areq, CHECK_MODE_BITS))
3644         return EACCES;
3645
3646     memset(&stat, 0, sizeof(struct vcxstat));
3647     stat.fid = avc->f.fid;
3648     hset32(stat.DataVersion, hgetlo(avc->f.m.DataVersion));
3649     stat.lock = avc->lock;
3650     stat.parentVnode = avc->f.parent.vnode;
3651     stat.parentUnique = avc->f.parent.unique;
3652     hset(stat.flushDV, avc->flushDV);
3653     hset(stat.mapDV, avc->mapDV);
3654     stat.truncPos = avc->f.truncPos;
3655     {                   /* just grab the first two - won't break anything... */
3656         struct axscache *ac;
3657
3658         for (i = 0, ac = avc->Access; ac && i < CPSIZE; i++, ac = ac->next) {
3659             stat.randomUid[i] = ac->uid;
3660             stat.randomAccess[i] = ac->axess;
3661         }
3662     }
3663     stat.callback = afs_data_pointer_to_int32(avc->callback);
3664     stat.cbExpires = avc->cbExpires;
3665     stat.anyAccess = avc->f.anyAccess;
3666     stat.opens = avc->opens;
3667     stat.execsOrWriters = avc->execsOrWriters;
3668     stat.flockCount = avc->flockCount;
3669     stat.mvstat = avc->mvstat;
3670     stat.states = avc->f.states;
3671     return afs_pd_putBytes(aout, &stat, sizeof(struct vcxstat));
3672 }
3673
3674
3675 DECL_PIOCTL(PGetVnodeXStatus2)
3676 {
3677     afs_int32 code;
3678     struct vcxstat2 stat;
3679     afs_int32 mode;
3680
3681     if (!avc)
3682         return EINVAL;
3683     code = afs_VerifyVCache(avc, areq);
3684     if (code)
3685         return code;
3686     if (vType(avc) == VDIR)
3687         mode = PRSFS_LOOKUP;
3688     else
3689         mode = PRSFS_READ;
3690     if (!afs_AccessOK(avc, mode, areq, CHECK_MODE_BITS))
3691         return EACCES;
3692
3693     memset(&stat, 0, sizeof(struct vcxstat2));
3694
3695     stat.cbExpires = avc->cbExpires;
3696     stat.anyAccess = avc->f.anyAccess;
3697     stat.mvstat = avc->mvstat;
3698     stat.callerAccess = afs_GetAccessBits(avc, ~0, areq);
3699
3700     return afs_pd_putBytes(aout, &stat, sizeof(struct vcxstat2));
3701 }
3702
3703
3704 /*!
3705  * VIOC_AFS_SYSNAME (38) - Change @sys value
3706  *
3707  * \ingroup pioctl
3708  *
3709  * \param[in] ain       new value for @sys
3710  * \param[out] aout     count, entry, list (debug values?)
3711  *
3712  * \retval EINVAL
3713  *      Error if afsd isn't running, the new sysname is too large,
3714  *      the new sysname causes issues (starts with a . or ..),
3715  *      there is no PAG set in the credentials, or the user of a PAG
3716  *      can't be found
3717  * \retval EACCES
3718  *      Error if the user doesn't have super-user credentials
3719  *
3720  * \post
3721  *      Set the value of @sys if these things work: if the input isn't
3722  *      too long or if input doesn't start with . or ..
3723  *
3724  * \notes
3725  *      We require root for local sysname changes, but not for remote
3726  *      (since we don't really believe remote uids anyway)
3727  *      outname[] shouldn't really be needed- this is left as an
3728  *      exercise for the reader.
3729  */
3730 DECL_PIOCTL(PSetSysName)
3731 {
3732     char *inname = NULL;
3733     char outname[MAXSYSNAME];
3734     afs_int32 setsysname;
3735     int foundname = 0;
3736     struct afs_exporter *exporter;
3737     struct unixuser *au;
3738     afs_int32 pag, error;
3739     int t, count, num = 0, allpags = 0;
3740     char **sysnamelist;
3741     struct afs_pdata validate;
3742
3743     AFS_STATCNT(PSetSysName);
3744     if (!afs_globalVFS) {
3745         /* Afsd is NOT running; disable it */
3746 #if defined(KERNEL_HAVE_UERROR)
3747         return (setuerror(EINVAL), EINVAL);
3748 #else
3749         return (EINVAL);
3750 #endif
3751     }
3752     if (afs_pd_getInt(ain, &setsysname) != 0)
3753         return EINVAL;
3754     if (setsysname & 0x8000) {
3755         allpags = 1;
3756         setsysname &= ~0x8000;
3757     }
3758     if (setsysname) {
3759
3760         /* Check my args */
3761         if (setsysname < 0 || setsysname > MAXNUMSYSNAMES)
3762             return EINVAL;
3763         validate = *ain;
3764         for (count = 0; count < setsysname; count++) {
3765             if (afs_pd_getStringPtr(&validate, &inname) != 0)
3766                 return EINVAL;
3767             t = strlen(inname);
3768             if (t >= MAXSYSNAME || t <= 0)
3769                 return EINVAL;
3770             /* check for names that can shoot us in the foot */
3771             if (inname[0] == '.' && (inname[1] == 0
3772                 || (inname[1] == '.' && inname[2] == 0)))
3773                 return EINVAL;
3774         }
3775         /* args ok, so go back to the beginning of that section */
3776
3777         if (afs_pd_getStringPtr(ain, &inname) != 0)
3778             return EINVAL;
3779         num = count;
3780     }
3781     if (afs_cr_gid(*acred) == RMTUSER_REQ ||
3782         afs_cr_gid(*acred) == RMTUSER_REQ_PRIV) {   /* Handles all exporters */
3783         if (allpags && afs_cr_gid(*acred) != RMTUSER_REQ_PRIV) {
3784             return EPERM;
3785         }
3786         pag = PagInCred(*acred);
3787         if (pag == NOPAG) {
3788             return EINVAL;      /* Better than panicing */
3789         }
3790         if (!(au = afs_FindUser(pag, -1, READ_LOCK))) {
3791             return EINVAL;      /* Better than panicing */
3792         }
3793         if (!(exporter = au->exporter)) {
3794             afs_PutUser(au, READ_LOCK);
3795             return EINVAL;      /* Better than panicing */
3796         }
3797         error = EXP_SYSNAME(exporter, inname, &sysnamelist,
3798                             &num, allpags);
3799         if (error) {
3800             if (error == ENODEV)
3801                 foundname = 0;  /* sysname not set yet! */
3802             else {
3803                 afs_PutUser(au, READ_LOCK);
3804                 return error;
3805             }
3806         } else {
3807             foundname = num;
3808             strcpy(outname, sysnamelist[0]);
3809         }
3810         afs_PutUser(au, READ_LOCK);
3811         if (setsysname)
3812             afs_sysnamegen++;
3813     } else {
3814         /* Not xlating, so local case */
3815         if (!afs_sysname)
3816             osi_Panic("PSetSysName: !afs_sysname\n");
3817         if (!setsysname) {      /* user just wants the info */
3818             strcpy(outname, afs_sysname);
3819             foundname = afs_sysnamecount;
3820             sysnamelist = afs_sysnamelist;
3821         } else {                /* Local guy; only root can change sysname */
3822             if (!afs_osi_suser(*acred))
3823                 return EACCES;
3824
3825             /* allpags makes no sense for local use */
3826             if (allpags)
3827                 return EINVAL;
3828
3829             /* clear @sys entries from the dnlc, once afs_lookup can
3830              * do lookups of @sys entries and thinks it can trust them */
3831             /* privs ok, store the entry, ... */
3832
3833             if (strlen(inname) >= MAXSYSNAME-1)
3834                 return EINVAL;
3835             strcpy(afs_sysname, inname);
3836
3837             if (setsysname > 1) {       /* ... or list */
3838                 for (count = 1; count < setsysname; ++count) {
3839                     if (!afs_sysnamelist[count])
3840                         osi_Panic
3841                            ("PSetSysName: no afs_sysnamelist entry to write\n");
3842                     if (afs_pd_getString(ain, afs_sysnamelist[count],
3843                                          MAXSYSNAME) != 0)
3844                         return EINVAL;
3845                 }
3846             }
3847             afs_sysnamecount = setsysname;
3848             afs_sysnamegen++;
3849         }
3850     }
3851     if (!setsysname) {
3852         if (afs_pd_putInt(aout, foundname) != 0)
3853             return E2BIG;
3854         if (foundname) {
3855             if (afs_pd_putString(aout, outname) != 0)
3856                 return E2BIG;
3857             for (count = 1; count < foundname; ++count) {    /* ... or list. */
3858                 if (!sysnamelist[count])
3859                     osi_Panic
3860                         ("PSetSysName: no afs_sysnamelist entry to read\n");
3861                 t = strlen(sysnamelist[count]);
3862                 if (t >= MAXSYSNAME)
3863                     osi_Panic("PSetSysName: sysname entry garbled\n");
3864                 if (afs_pd_putString(aout, sysnamelist[count]) != 0)
3865                     return E2BIG;
3866             }
3867         }
3868     }
3869     return 0;
3870 }
3871
3872 /* sequential search through the list of touched cells is not a good
3873  * long-term solution here. For small n, though, it should be just
3874  * fine.  Should consider special-casing the local cell for large n.
3875  * Likewise for PSetSPrefs.
3876  *
3877  * s - number of ids in array l[] -- NOT index of last id
3878  * l - array of cell ids which have volumes that need to be sorted
3879  * vlonly - sort vl servers or file servers?
3880  */
3881 static void *
3882 ReSortCells_cb(struct cell *cell, void *arg)
3883 {
3884     afs_int32 *p = (afs_int32 *) arg;
3885     afs_int32 *l = p + 1;
3886     int i, s = p[0];
3887
3888     for (i = 0; i < s; i++) {
3889         if (l[i] == cell->cellNum) {
3890             ObtainWriteLock(&cell->lock, 690);
3891             afs_SortServers(cell->cellHosts, AFS_MAXCELLHOSTS);
3892             ReleaseWriteLock(&cell->lock);
3893         }
3894     }
3895
3896     return NULL;
3897 }
3898
3899 static void
3900 ReSortCells(int s, afs_int32 * l, int vlonly)
3901 {
3902     int i;
3903     struct volume *j;
3904     int k;
3905
3906     if (vlonly) {
3907         afs_int32 *p;
3908         p = afs_osi_Alloc(sizeof(afs_int32) * (s + 1));
3909         osi_Assert(p != NULL);
3910         p[0] = s;
3911         memcpy(p + 1, l, s * sizeof(afs_int32));
3912         afs_TraverseCells(&ReSortCells_cb, p);
3913         afs_osi_Free(p, sizeof(afs_int32) * (s + 1));
3914         return;
3915     }
3916
3917     ObtainReadLock(&afs_xvolume);
3918     for (i = 0; i < NVOLS; i++) {
3919         for (j = afs_volumes[i]; j; j = j->next) {
3920             for (k = 0; k < s; k++)
3921                 if (j->cell == l[k]) {
3922                     ObtainWriteLock(&j->lock, 233);
3923                     afs_SortServers(j->serverHost, AFS_MAXHOSTS);
3924                     ReleaseWriteLock(&j->lock);
3925                     break;
3926                 }
3927         }
3928     }
3929     ReleaseReadLock(&afs_xvolume);
3930 }
3931
3932
3933 static int debugsetsp = 0;
3934 static int
3935 afs_setsprefs(struct spref *sp, unsigned int num, unsigned int vlonly)
3936 {
3937     struct srvAddr *sa;
3938     int i, j, k, matches, touchedSize;
3939     struct server *srvr = NULL;
3940     afs_int32 touched[34];
3941     int isfs;
3942
3943     touchedSize = 0;
3944     for (k = 0; k < num; sp++, k++) {
3945         if (debugsetsp) {
3946             afs_warn("sp host=%x, rank=%d\n", sp->host.s_addr, sp->rank);
3947         }
3948         matches = 0;
3949         ObtainReadLock(&afs_xserver);
3950
3951         i = SHash(sp->host.s_addr);
3952         for (sa = afs_srvAddrs[i]; sa; sa = sa->next_bkt) {
3953             if (sa->sa_ip == sp->host.s_addr) {
3954                 srvr = sa->server;
3955                 isfs = (srvr->cell && (sa->sa_portal == srvr->cell->fsport))
3956                     || (sa->sa_portal == AFS_FSPORT);
3957                 if ((!vlonly && isfs) || (vlonly && !isfs)) {
3958                     matches++;
3959                     break;
3960                 }
3961             }
3962         }
3963
3964         if (sa && matches) {    /* found one! */
3965             if (debugsetsp) {
3966                 afs_warn("sa ip=%x, ip_rank=%d\n", sa->sa_ip, sa->sa_iprank);
3967             }
3968             sa->sa_iprank = sp->rank + afs_randomMod15();
3969             afs_SortOneServer(sa->server);
3970
3971             if (srvr->cell) {
3972                 /* if we don't know yet what cell it's in, this is moot */
3973                 for (j = touchedSize - 1;
3974                      j >= 0 && touched[j] != srvr->cell->cellNum; j--)
3975                     /* is it in our list of touched cells ?  */ ;
3976                 if (j < 0) {    /* no, it's not */
3977                     touched[touchedSize++] = srvr->cell->cellNum;
3978                     if (touchedSize >= 32) {    /* watch for ovrflow */
3979                         ReleaseReadLock(&afs_xserver);
3980                         ReSortCells(touchedSize, touched, vlonly);
3981                         touchedSize = 0;
3982                         ObtainReadLock(&afs_xserver);
3983                     }
3984                 }
3985             }
3986         }
3987
3988         ReleaseReadLock(&afs_xserver);
3989         /* if we didn't find one, start to create one. */
3990         /* Note that it doesn't have a cell yet...     */
3991         if (!matches) {
3992             afs_uint32 temp = sp->host.s_addr;
3993             srvr =
3994                 afs_GetServer(&temp, 1, 0, (vlonly ? AFS_VLPORT : AFS_FSPORT),
3995                               WRITE_LOCK, (afsUUID *) 0, 0);
3996             srvr->addr->sa_iprank = sp->rank + afs_randomMod15();
3997             afs_PutServer(srvr, WRITE_LOCK);
3998         }
3999     }                           /* for all cited preferences */
4000
4001     ReSortCells(touchedSize, touched, vlonly);
4002     return 0;
4003 }
4004
4005 /*!
4006  * VIOC_SETPREFS (46) - Set server ranks
4007  *
4008  * \param[in] ain       the sprefs value you want the sprefs to be set to
4009  * \param[out] aout     not in use
4010  *
4011  * \retval EIO
4012  *      Error if the afs daemon hasn't started yet
4013  * \retval EACCES
4014  *      Error if the user doesn't have super-user credentials
4015  * \retval EINVAL
4016  *      Error if the struct setsprefs is too large or if it multiplied
4017  *      by the number of servers is too large
4018  *
4019  * \post set the sprefs using the afs_setsprefs() function
4020  */
4021 DECL_PIOCTL(PSetSPrefs)
4022 {
4023     struct setspref *ssp;
4024     char *ainPtr;
4025     size_t ainSize;
4026
4027     AFS_STATCNT(PSetSPrefs);
4028
4029     if (!afs_resourceinit_flag) /* afs daemons haven't started yet */
4030         return EIO;             /* Inappropriate ioctl for device */
4031
4032     if (!afs_osi_suser(*acred))
4033         return EACCES;
4034
4035     /* The I/O handling here is ghastly, as it relies on overrunning the ends
4036      * of arrays. But, i'm not quite brave enough to change it yet. */
4037     ainPtr = ain->ptr;
4038     ainSize = ain->remaining;
4039
4040     if (ainSize < sizeof(struct setspref))
4041         return EINVAL;
4042
4043     ssp = (struct setspref *)ainPtr;
4044     if (ainSize < (sizeof(struct setspref)
4045                    + sizeof(struct spref) * ssp->num_servers-1))
4046         return EINVAL;
4047
4048     afs_setsprefs(&(ssp->servers[0]), ssp->num_servers,
4049                   (ssp->flags & DBservers));
4050     return 0;
4051 }
4052
4053 /*
4054  * VIOC_SETPREFS33 (42) - Set server ranks (deprecated)
4055  *
4056  * \param[in] ain       the server preferences to be set
4057  * \param[out] aout     not in use
4058  *
4059  * \retval EIO          Error if the afs daemon hasn't started yet
4060  * \retval EACCES       Error if the user doesn't have super-user credentials
4061  *
4062  * \post set the server preferences, calling a function
4063  *
4064  * \notes this may only be performed by the local root user.
4065  */
4066 DECL_PIOCTL(PSetSPrefs33)
4067 {
4068     AFS_STATCNT(PSetSPrefs);
4069     if (!afs_resourceinit_flag) /* afs daemons haven't started yet */
4070         return EIO;             /* Inappropriate ioctl for device */
4071
4072
4073     if (!afs_osi_suser(*acred))
4074         return EACCES;
4075
4076     afs_setsprefs((struct spref *)afs_pd_where(ain),
4077                   afs_pd_remaining(ain) / sizeof(struct spref),
4078                   0 /*!vlonly */ );
4079     return 0;
4080 }
4081
4082 /*
4083  * VIOC_GETSPREFS (43) - Get server ranks
4084  *
4085  * \ingroup pioctl
4086  *
4087  * \param[in] ain       the server preferences to get
4088  * \param[out] aout     the server preferences information
4089  *
4090  * \retval EIO          Error if the afs daemon hasn't started yet
4091  * \retval ENOENT       Error if the sprefrequest is too large
4092  *
4093  * \post Get the sprefs
4094  *
4095  * \notes
4096  *      in the hash table of server structs, all servers with the same
4097  *      IP address; will be on the same overflow chain; This could be
4098  *      sped slightly in some circumstances by having it cache the
4099  *      immediately previous slot in the hash table and some
4100  *      supporting information; Only reports file servers now.
4101  */
4102 DECL_PIOCTL(PGetSPrefs)
4103 {
4104     struct sprefrequest spin;   /* input */
4105     struct sprefinfo *spout;    /* output */
4106     struct spref *srvout;       /* one output component */
4107     int i, j;                   /* counters for hash table traversal */
4108     struct server *srvr;        /* one of CM's server structs */
4109     struct srvAddr *sa;
4110     int vlonly;                 /* just return vlservers ? */
4111     int isfs;
4112
4113     AFS_STATCNT(PGetSPrefs);
4114     if (!afs_resourceinit_flag) /* afs daemons haven't started yet */
4115         return EIO;             /* Inappropriate ioctl for device */
4116
4117     /* Work out from the size whether we've got a new, or old, style pioctl */
4118     if (afs_pd_remaining(ain) < sizeof(struct sprefrequest)) {
4119         if (afs_pd_getBytes(ain, &spin, sizeof(struct sprefrequest_33)) != 0)
4120            return ENOENT;
4121         vlonly = 0;
4122         spin.flags = 0;
4123     } else {
4124         if (afs_pd_getBytes(ain, &spin, sizeof(struct sprefrequest)) != 0)
4125            return EINVAL;
4126         vlonly = (spin.flags & DBservers);
4127     }
4128
4129     /* This code relies on overflowing arrays. It's ghastly, but I'm not
4130      * quite brave enough to tackle it yet ...
4131      */
4132
4133     /* struct sprefinfo includes 1 server struct...  that size gets added
4134      * in during the loop that follows.
4135      */
4136     spout = afs_pd_inline(aout,
4137                           sizeof(struct sprefinfo) - sizeof(struct spref));
4138     spout->next_offset = spin.offset;
4139     spout->num_servers = 0;
4140     srvout = spout->servers;
4141
4142     ObtainReadLock(&afs_xserver);
4143     for (i = 0, j = 0; j < NSERVERS; j++) {     /* sift through hash table */
4144         for (sa = afs_srvAddrs[j]; sa; sa = sa->next_bkt, i++) {
4145             if (spin.offset > (unsigned short)i) {
4146                 continue;       /* catch up to where we left off */
4147             }
4148             spout->next_offset++;
4149
4150             srvr = sa->server;
4151             isfs = (srvr->cell && (sa->sa_portal == srvr->cell->fsport))
4152                 || (sa->sa_portal == AFS_FSPORT);
4153
4154             if ((vlonly && isfs) || (!vlonly && !isfs)) {
4155                 /* only report ranks for vl servers */
4156                 continue;
4157             }
4158
4159             /* Check we've actually got the space we're about to use */
4160             if (afs_pd_inline(aout, sizeof(struct spref)) == NULL) {
4161                 ReleaseReadLock(&afs_xserver);  /* no more room! */
4162                 return 0;
4163             }
4164
4165             srvout->host.s_addr = sa->sa_ip;
4166             srvout->rank = sa->sa_iprank;
4167             spout->num_servers++;
4168             srvout++;
4169         }
4170     }
4171     ReleaseReadLock(&afs_xserver);
4172
4173     spout->next_offset = 0;     /* start over from the beginning next time */
4174
4175     return 0;
4176 }
4177
4178 /* Enable/Disable the specified exporter. Must be root to disable an exporter */
4179 int afs_NFSRootOnly = 1;
4180 /*!
4181  * VIOC_EXPORTAFS (39) - Export afs to nfs clients
4182  *
4183  * \ingroup pioctl
4184  *
4185  * \param[in] ain
4186  *      an integer containing the desired exportee flags
4187  * \param[out] aout
4188  *      an integer containing the current exporter flags
4189  *
4190  * \retval ENODEV       Error if the exporter doesn't exist
4191  * \retval EACCES       Error if the user doesn't have super-user credentials
4192  *
4193  * \post
4194  *      Changes the state of various values to reflect the change
4195  *      of the export values between nfs and afs.
4196  *
4197  * \notes Legacy code obtained from IBM.
4198  */
4199 DECL_PIOCTL(PExportAfs)
4200 {
4201     afs_int32 export, newint = 0;
4202     afs_int32 type, changestate, handleValue, convmode, pwsync, smounts;
4203     afs_int32 rempags = 0, pagcb = 0;
4204     struct afs_exporter *exporter;
4205
4206     AFS_STATCNT(PExportAfs);
4207     if (afs_pd_getInt(ain, &handleValue) != 0)
4208         return EINVAL;
4209     type = handleValue >> 24;
4210     if (type == 0x71) {
4211         newint = 1;
4212         type = 1;               /* nfs */
4213     }
4214     exporter = exporter_find(type);
4215     if (newint) {
4216         export = handleValue & 3;
4217         changestate = handleValue & 0xfff;
4218         smounts = (handleValue >> 2) & 3;
4219         pwsync = (handleValue >> 4) & 3;
4220         convmode = (handleValue >> 6) & 3;
4221         rempags = (handleValue >> 8) & 3;
4222         pagcb = (handleValue >> 10) & 3;
4223     } else {
4224         changestate = (handleValue >> 16) & 0x1;
4225         convmode = (handleValue >> 16) & 0x2;
4226         pwsync = (handleValue >> 16) & 0x4;
4227         smounts = (handleValue >> 16) & 0x8;
4228         export = handleValue & 0xff;
4229     }
4230     if (!exporter) {
4231         /*  Failed finding desired exporter; */
4232         return ENODEV;
4233     }
4234     if (!changestate) {
4235         handleValue = exporter->exp_states;
4236         if (afs_pd_putInt(aout, handleValue) != 0)
4237             return E2BIG;
4238     } else {
4239         if (!afs_osi_suser(*acred))
4240             return EACCES;      /* Only superuser can do this */
4241         if (newint) {
4242             if (export & 2) {
4243                 if (export & 1)
4244                     exporter->exp_states |= EXP_EXPORTED;
4245                 else
4246                     exporter->exp_states &= ~EXP_EXPORTED;
4247             }
4248             if (convmode & 2) {
4249                 if (convmode & 1)
4250                     exporter->exp_states |= EXP_UNIXMODE;
4251                 else
4252                     exporter->exp_states &= ~EXP_UNIXMODE;
4253             }
4254             if (pwsync & 2) {
4255                 if (pwsync & 1)
4256                     exporter->exp_states |= EXP_PWSYNC;
4257                 else
4258                     exporter->exp_states &= ~EXP_PWSYNC;
4259             }
4260             if (smounts & 2) {
4261                 if (smounts & 1) {
4262                     afs_NFSRootOnly = 0;
4263                     exporter->exp_states |= EXP_SUBMOUNTS;
4264                 } else {
4265                     afs_NFSRootOnly = 1;
4266                     exporter->exp_states &= ~EXP_SUBMOUNTS;
4267                 }
4268             }
4269             if (rempags & 2) {
4270                 if (rempags & 1)
4271                     exporter->exp_states |= EXP_CLIPAGS;
4272                 else
4273                     exporter->exp_states &= ~EXP_CLIPAGS;
4274             }
4275             if (pagcb & 2) {
4276                 if (pagcb & 1)
4277                     exporter->exp_states |= EXP_CALLBACK;
4278                 else
4279                     exporter->exp_states &= ~EXP_CALLBACK;
4280             }
4281             handleValue = exporter->exp_states;
4282             if (afs_pd_putInt(aout, handleValue) != 0)
4283                 return E2BIG;
4284         } else {
4285             if (export)
4286                 exporter->exp_states |= EXP_EXPORTED;
4287             else
4288                 exporter->exp_states &= ~EXP_EXPORTED;
4289             if (convmode)
4290                 exporter->exp_states |= EXP_UNIXMODE;
4291             else
4292                 exporter->exp_states &= ~EXP_UNIXMODE;
4293             if (pwsync)
4294                 exporter->exp_states |= EXP_PWSYNC;
4295             else
4296                 exporter->exp_states &= ~EXP_PWSYNC;
4297             if (smounts) {
4298                 afs_NFSRootOnly = 0;
4299                 exporter->exp_states |= EXP_SUBMOUNTS;
4300             } else {
4301                 afs_NFSRootOnly = 1;
4302                 exporter->exp_states &= ~EXP_SUBMOUNTS;
4303             }
4304         }
4305     }
4306
4307     return 0;
4308 }
4309
4310 /*!
4311  * VIOC_GAG (44) - Silence Cache Manager
4312  *
4313  * \ingroup pioctl
4314  *
4315  * \param[in] ain       the flags to either gag or de-gag the cache manager
4316  * \param[out] aout     not in use
4317  *
4318  * \retval EACCES       Error if the user doesn't have super-user credentials
4319  *
4320  * \post set the gag flags, then show these flags
4321  */
4322 DECL_PIOCTL(PGag)
4323 {
4324     struct gaginfo *gagflags;
4325
4326     if (!afs_osi_suser(*acred))
4327         return EACCES;
4328
4329     gagflags = afs_pd_inline(ain, sizeof(*gagflags));
4330     if (gagflags == NULL)
4331         return EINVAL;
4332     afs_showflags = gagflags->showflags;
4333
4334     return 0;
4335 }
4336
4337 /*!
4338  * VIOC_TWIDDLE (45) - Adjust RX knobs
4339  *
4340  * \ingroup pioctl
4341  *
4342  * \param[in] ain       the previous settings of the 'knobs'
4343  * \param[out] aout     not in use
4344  *
4345  * \retval EACCES       Error if the user doesn't have super-user credentials
4346  *
4347  * \post build out the struct rxp, from a struct rx
4348  */
4349 DECL_PIOCTL(PTwiddleRx)
4350 {
4351     struct rxparams *rxp;
4352
4353     if (!afs_osi_suser(*acred))
4354         return EACCES;
4355
4356     rxp = afs_pd_inline(ain, sizeof(*rxp));
4357     if (rxp == NULL)
4358         return EINVAL;
4359
4360     if (rxp->rx_initReceiveWindow)
4361         rx_initReceiveWindow = rxp->rx_initReceiveWindow;
4362     if (rxp->rx_maxReceiveWindow)
4363         rx_maxReceiveWindow = rxp->rx_maxReceiveWindow;
4364     if (rxp->rx_initSendWindow)
4365         rx_initSendWindow = rxp->rx_initSendWindow;
4366     if (rxp->rx_maxSendWindow)
4367         rx_maxSendWindow = rxp->rx_maxSendWindow;
4368     if (rxp->rxi_nSendFrags)
4369         rxi_nSendFrags = rxp->rxi_nSendFrags;
4370     if (rxp->rxi_nRecvFrags)
4371         rxi_nRecvFrags = rxp->rxi_nRecvFrags;
4372     if (rxp->rxi_OrphanFragSize)
4373         rxi_OrphanFragSize = rxp->rxi_OrphanFragSize;
4374     if (rxp->rx_maxReceiveSize) {
4375         rx_maxReceiveSize = rxp->rx_maxReceiveSize;
4376         rx_maxReceiveSizeUser = rxp->rx_maxReceiveSize;
4377     }
4378     if (rxp->rx_MyMaxSendSize)
4379         rx_MyMaxSendSize = rxp->rx_MyMaxSendSize;
4380
4381     return 0;
4382 }
4383
4384 /*!
4385  * VIOC_GETINITPARAMS (49) - Get initial cache manager parameters
4386  *
4387  * \ingroup pioctl
4388  *
4389  * \param[in] ain       not in use
4390  * \param[out] aout     initial cache manager params
4391  *
4392  * \retval E2BIG
4393  *      Error if the initial parameters are bigger than some PIGGYSIZE
4394  *
4395  * \post return the initial cache manager parameters
4396  */
4397 DECL_PIOCTL(PGetInitParams)
4398 {
4399     if (sizeof(struct cm_initparams) > PIGGYSIZE)
4400         return E2BIG;
4401
4402     return afs_pd_putBytes(aout, &cm_initParams,
4403                            sizeof(struct cm_initparams));
4404 }
4405
4406 #ifdef AFS_SGI65_ENV
4407 /* They took crget() from us, so fake it. */
4408 static cred_t *
4409 crget(void)
4410 {
4411     cred_t *cr;
4412     cr = crdup(get_current_cred());
4413     memset(cr, 0, sizeof(cred_t));
4414 #if CELL || CELL_PREPARE
4415     cr->cr_id = -1;
4416 #endif
4417     return cr;
4418 }
4419 #endif
4420
4421 /*!
4422  * VIOC_GETRXKCRYPT (55) - Get rxkad encryption flag
4423  *
4424  * \ingroup pioctl
4425  *
4426  * \param[in] ain       not in use
4427  * \param[out] aout     value of cryptall
4428  *
4429  * \post Turns on, or disables, rxkad encryption by setting the cryptall global
4430  */
4431 DECL_PIOCTL(PGetRxkcrypt)
4432 {
4433     return afs_pd_putInt(aout, cryptall);
4434 }
4435
4436 /*!
4437  * VIOC_SETRXKCRYPT (56) - Set rxkad encryption flag
4438  *
4439  * \ingroup pioctl
4440  *
4441  * \param[in] ain       the argument whether or not things should be encrypted
4442  * \param[out] aout     not in use
4443  *
4444  * \retval EPERM
4445  *      Error if the user doesn't have super-user credentials
4446  * \retval EINVAL
4447  *      Error if the input is too big, or if the input is outside the
4448  *      bounds of what it can be set to
4449  *
4450  * \post set whether or not things should be encrypted
4451  *
4452  * \notes
4453  *      may need to be modified at a later date to take into account
4454  *      other values for cryptall (beyond true or false)
4455  */
4456 DECL_PIOCTL(PSetRxkcrypt)
4457 {
4458     afs_int32 tmpval;
4459
4460     if (!afs_osi_suser(*acred))
4461         return EPERM;
4462     if (afs_pd_getInt(ain, &tmpval) != 0)
4463         return EINVAL;
4464     /* if new mappings added later this will need to be changed */
4465     if (tmpval != 0 && tmpval != 1)
4466         return EINVAL;
4467     cryptall = tmpval;
4468     return 0;
4469 }
4470
4471 #ifdef AFS_NEED_CLIENTCONTEXT
4472 /*
4473  * Create new credentials to correspond to a remote user with given
4474  * <hostaddr, uid, g0, g1>.  This allows a server running as root to
4475  * provide pioctl (and other) services to foreign clients (i.e. nfs
4476  * clients) by using this call to `become' the client.
4477  */
4478 #define PSETPAG         110
4479 #define PIOCTL_HEADER   6
4480 static int
4481 HandleClientContext(struct afs_ioctl *ablob, int *com,
4482                     afs_ucred_t **acred, afs_ucred_t *credp)
4483 {
4484     char *ain, *inData;
4485     afs_uint32 hostaddr;
4486     afs_int32 uid, g0, g1, i, code, pag, exporter_type, isroot = 0;
4487     struct afs_exporter *exporter, *outexporter;
4488     afs_ucred_t *newcred;
4489     struct unixuser *au;
4490     afs_uint32 comp = *com & 0xff00;
4491     afs_uint32 h, l;
4492 #if defined(AFS_SUN510_ENV)
4493     gid_t gids[2];
4494 #endif
4495
4496 #if defined(AFS_SGIMP_ENV)
4497     osi_Assert(ISAFS_GLOCK());
4498 #endif
4499     AFS_STATCNT(HandleClientContext);
4500     if (ablob->in_size < PIOCTL_HEADER * sizeof(afs_int32)) {
4501         /* Must at least include the PIOCTL_HEADER header words
4502          * required by the protocol */
4503         return EINVAL;          /* Too small to be good  */
4504     }
4505     ain = inData = osi_AllocLargeSpace(AFS_LRALLOCSIZ);
4506     AFS_COPYIN(ablob->in, ain, PIOCTL_HEADER * sizeof(afs_int32), code);
4507     if (code) {
4508         osi_FreeLargeSpace(inData);
4509         return code;
4510     }
4511
4512     /* Extract information for remote user */
4513     hostaddr = *((afs_uint32 *) ain);
4514     ain += sizeof(hostaddr);
4515     uid = *((afs_uint32 *) ain);
4516     ain += sizeof(uid);
4517     g0 = *((afs_uint32 *) ain);
4518     ain += sizeof(g0);
4519     g1 = *((afs_uint32 *) ain);
4520     ain += sizeof(g1);
4521     *com = *((afs_uint32 *) ain);
4522     ain += sizeof(afs_int32);
4523     exporter_type = *((afs_uint32 *) ain);/* In case we support more than NFS */
4524
4525     /*
4526      * Of course, one must be root for most of these functions, but
4527      * we'll allow (for knfs) you to set things if the pag is 0 and
4528      * you're setting tokens or unlogging.
4529      */
4530     i = (*com) & 0xff;
4531     if (!afs_osi_suser(credp)) {
4532 #if defined(AFS_SGI_ENV) && !defined(AFS_SGI64_ENV)
4533         /* Since SGI's suser() returns explicit failure after the call.. */
4534         u.u_error = 0;
4535 #endif
4536         /* check for acceptable opcodes for normal folks, which are, so far,
4537          * get/set tokens, sysname, and unlog.
4538          */
4539         if (i != 9 && i != 3 && i != 38 && i != 8) {
4540             osi_FreeLargeSpace(inData);
4541             return EACCES;
4542         }
4543     }
4544
4545     ablob->in_size -= PIOCTL_HEADER * sizeof(afs_int32);
4546     ablob->in += PIOCTL_HEADER * sizeof(afs_int32);
4547     osi_FreeLargeSpace(inData);
4548     if (uid == 0) {
4549         /*
4550          * We map uid 0 to nobody to match the mapping that the nfs
4551          * server does and to ensure that the suser() calls in the afs
4552          * code fails for remote client roots.
4553          */
4554         uid = afs_nobody;       /* NFS_NOBODY == -2 */
4555         isroot = 1;
4556     }
4557     newcred = crget();
4558 #ifdef  AFS_AIX41_ENV
4559     setuerror(0);
4560 #endif
4561     afs_set_cr_gid(newcred, isroot ? RMTUSER_REQ_PRIV : RMTUSER_REQ);
4562 #ifdef AFS_AIX51_ENV
4563     newcred->cr_groupset.gs_union.un_groups[0] = g0;
4564     newcred->cr_groupset.gs_union.un_groups[1] = g1;
4565 #elif defined(AFS_LINUX26_ENV)
4566 # ifdef AFS_LINUX26_ONEGROUP_ENV
4567     afs_set_cr_group_info(newcred, groups_alloc(1)); /* nothing sets this */
4568     l = (((g0-0x3f00) & 0x3fff) << 14) | ((g1-0x3f00) & 0x3fff);
4569     h = ((g0-0x3f00) >> 14);
4570     h = ((g1-0x3f00) >> 14) + h + h + h;
4571     GROUP_AT(afs_cr_group_info(newcred), 0) = ((h << 28) | l);
4572 # else
4573     afs_set_cr_group_info(newcred, groups_alloc(2));
4574     GROUP_AT(afs_cr_group_info(newcred), 0) = g0;
4575     GROUP_AT(afs_cr_group_info(newcred), 1) = g1;
4576 # endif
4577 #elif defined(AFS_SUN510_ENV)
4578     gids[0] = g0;
4579     gids[1] = g1;
4580     crsetgroups(newcred, 2, gids);
4581 #else
4582     newcred->cr_groups[0] = g0;
4583     newcred->cr_groups[1] = g1;
4584 #endif
4585 #ifdef AFS_AIX_ENV
4586     newcred->cr_ngrps = 2;
4587 #elif !defined(AFS_LINUX26_ENV) && !defined(AFS_SUN510_ENV)
4588 # if defined(AFS_SGI_ENV) || defined(AFS_SUN5_ENV) || defined(AFS_LINUX22_ENV) || defined(AFS_FBSD80_ENV)
4589     newcred->cr_ngroups = 2;
4590 # else
4591     for (i = 2; i < NGROUPS; i++)
4592         newcred->cr_groups[i] = NOGROUP;
4593 # endif
4594 #endif
4595     if (!(exporter = exporter_find(exporter_type))) {
4596         /* Exporter wasn't initialized or an invalid exporter type */
4597         crfree(newcred);
4598         return EINVAL;
4599     }
4600     if (exporter->exp_states & EXP_PWSYNC) {
4601         if (uid != afs_cr_uid(credp)) {
4602             crfree(newcred);
4603             return ENOEXEC;     /* XXX Find a better errno XXX */
4604         }
4605     }
4606     afs_set_cr_uid(newcred, uid);       /* Only temporary  */
4607     code = EXP_REQHANDLER(exporter, &newcred, hostaddr, &pag, &outexporter);
4608     /* The client's pag is the only unique identifier for it */
4609     afs_set_cr_uid(newcred, pag);
4610     *acred = newcred;
4611     if (!code && *com == PSETPAG) {
4612         /* Special case for 'setpag' */
4613         afs_uint32 pagvalue = genpag();
4614
4615         au = afs_GetUser(pagvalue, -1, WRITE_LOCK); /* a new unixuser struct */
4616         /*
4617          * Note that we leave the 'outexporter' struct held so it won't
4618          * dissappear on us
4619          */
4620         au->exporter = outexporter;
4621         if (ablob->out_size >= 4) {
4622             AFS_COPYOUT((char *)&pagvalue, ablob->out, sizeof(afs_int32),
4623                         code);
4624         }
4625         afs_PutUser(au, WRITE_LOCK);
4626         if (code)
4627             return code;
4628         return PSETPAG;         /*  Special return for setpag  */
4629     } else if (!code) {
4630         EXP_RELE(outexporter);
4631     }
4632     if (!code)
4633         *com = (*com) | comp;
4634     return code;
4635 }
4636 #endif /* AFS_NEED_CLIENTCONTEXT */
4637
4638
4639 /*!
4640  * VIOC_GETCPREFS (50) - Get client interface
4641  *
4642  * \ingroup pioctl
4643  *
4644  * \param[in] ain       sprefrequest input
4645  * \param[out] aout     spref information
4646  *
4647  * \retval EIO          Error if the afs daemon hasn't started yet
4648  * \retval EINVAL       Error if some of the standard args aren't set
4649  *
4650  * \post
4651  *      get all interface addresses and other information of the client
4652  *      interface
4653  */
4654 DECL_PIOCTL(PGetCPrefs)
4655 {
4656     struct sprefrequest *spin;  /* input */
4657     struct sprefinfo *spout;    /* output */
4658     struct spref *srvout;       /* one output component */
4659     int maxNumber;
4660     int i, j;
4661
4662     AFS_STATCNT(PGetCPrefs);
4663     if (!afs_resourceinit_flag) /* afs daemons haven't started yet */
4664         return EIO;             /* Inappropriate ioctl for device */
4665
4666     spin = afs_pd_inline(ain, sizeof(*spin));
4667     if (spin == NULL)
4668         return EINVAL;
4669
4670     /* Output spout relies on writing past the end of arrays. It's horrible,
4671      * but I'm not quite brave enough to tackle it yet */
4672     spout = (struct sprefinfo *)aout->ptr;
4673
4674     maxNumber = spin->num_servers;      /* max addrs this time */
4675     srvout = spout->servers;
4676
4677     ObtainReadLock(&afs_xinterface);
4678
4679     /* copy out the client interface information from the
4680      * kernel data structure "interface" to the output buffer
4681      */
4682     for (i = spin->offset, j = 0; (i < afs_cb_interface.numberOfInterfaces)
4683          && (j < maxNumber); i++, j++, srvout++)
4684         srvout->host.s_addr = afs_cb_interface.addr_in[i];
4685
4686     spout->num_servers = j;
4687     aout->ptr += sizeof(struct sprefinfo) + (j - 1) * sizeof(struct spref);
4688
4689     if (i >= afs_cb_interface.numberOfInterfaces)
4690         spout->next_offset = 0; /* start from beginning again */
4691     else
4692         spout->next_offset = spin->offset + j;
4693
4694     ReleaseReadLock(&afs_xinterface);
4695     return 0;
4696 }
4697
4698 /*!
4699  * VIOC_SETCPREFS (51) - Set client interface
4700  *
4701  * \ingroup pioctl
4702  *
4703  * \param[in] ain       the interfaces you want set
4704  * \param[out] aout     not in use
4705  *
4706  * \retval EIO          Error if the afs daemon hasn't started yet
4707  * \retval EINVAL       Error if the input is too large for the struct
4708  * \retval ENOMEM       Error if there are too many servers
4709  *
4710  * \post set the callbak interfaces addresses to those of the hosts
4711  */
4712 DECL_PIOCTL(PSetCPrefs)
4713 {
4714     char *ainPtr;
4715     size_t ainSize;
4716     struct setspref *sin;
4717     int i;
4718
4719     AFS_STATCNT(PSetCPrefs);
4720     if (!afs_resourceinit_flag) /* afs daemons haven't started yet */
4721         return EIO;             /* Inappropriate ioctl for device */
4722
4723     /* Yuck. Input to this function relies on reading past the end of
4724      * structures. Bodge it for now.
4725      */
4726     ainPtr = ain->ptr;
4727     ainSize = ain->remaining;
4728
4729     sin = (struct setspref *)ainPtr;
4730
4731     if (ainSize < sizeof(struct setspref))
4732         return EINVAL;
4733 #if 0                           /* num_servers is unsigned */
4734     if (sin->num_servers < 0)
4735         return EINVAL;
4736 #endif
4737     if (sin->num_servers > AFS_MAX_INTERFACE_ADDR)
4738         return ENOMEM;
4739
4740     ObtainWriteLock(&afs_xinterface, 412);
4741     afs_cb_interface.numberOfInterfaces = sin->num_servers;
4742     for (i = 0; (unsigned short)i < sin->num_servers; i++)
4743         afs_cb_interface.addr_in[i] = sin->servers[i].host.s_addr;
4744
4745     ReleaseWriteLock(&afs_xinterface);
4746     return 0;
4747 }
4748
4749 /*!
4750  * VIOC_AFS_FLUSHMOUNT (52) - Flush mount symlink data
4751  *
4752  * \ingroup pioctl
4753  *
4754  * \param[in] ain
4755  *      the last part of a path to a mount point, which tells us what to flush
4756  * \param[out] aout
4757  *      not in use
4758  *
4759  * \retval EINVAL
4760  *      Error if some of the initial arguments aren't set
4761  * \retval ENOTDIR
4762  *      Error if the initial argument for the mount point isn't a directory
4763  * \retval ENOENT
4764  *      Error if the dcache entry isn't set
4765  *
4766  * \post
4767  *      remove all of the mount data from the dcache regarding a
4768  *      certain mount point
4769  */
4770 DECL_PIOCTL(PFlushMount)
4771 {
4772     afs_int32 code;
4773     struct vcache *tvc;
4774     struct dcache *tdc;
4775     struct VenusFid tfid;
4776     char *bufp;
4777     char *mount;
4778     struct sysname_info sysState;
4779     afs_size_t offset, len;
4780
4781     AFS_STATCNT(PFlushMount);
4782     if (!avc)
4783         return EINVAL;
4784
4785     if (afs_pd_getStringPtr(ain, &mount) != 0)
4786         return EINVAL;
4787
4788     code = afs_VerifyVCache(avc, areq);
4789     if (code)
4790         return code;
4791     if (vType(avc) != VDIR) {
4792         return ENOTDIR;
4793     }
4794     tdc = afs_GetDCache(avc, (afs_size_t) 0, areq, &offset, &len, 1);
4795     if (!tdc)
4796         return ENOENT;
4797     Check_AtSys(avc, mount, &sysState, areq);
4798     ObtainReadLock(&tdc->lock);
4799     do {
4800         code = afs_dir_Lookup(tdc, sysState.name, &tfid.Fid);
4801     } while (code == ENOENT && Next_AtSys(avc, areq, &sysState));
4802     ReleaseReadLock(&tdc->lock);
4803     afs_PutDCache(tdc);         /* we're done with the data */
4804     bufp = sysState.name;
4805     if (code) {
4806         goto out;
4807     }
4808     tfid.Cell = avc->f.fid.Cell;
4809     tfid.Fid.Volume = avc->f.fid.Fid.Volume;
4810     if (!tfid.Fid.Unique && (avc->f.states & CForeign)) {
4811         tvc = afs_LookupVCache(&tfid, areq, NULL, avc, bufp);
4812     } else {
4813         tvc = afs_GetVCache(&tfid, areq, NULL, NULL);
4814     }
4815     if (!tvc) {
4816         code = ENOENT;
4817         goto out;
4818     }
4819     if (tvc->mvstat != 1) {
4820         afs_PutVCache(tvc);
4821         code = EINVAL;
4822         goto out;
4823     }
4824 #ifdef AFS_BOZONLOCK_ENV
4825     afs_BozonLock(&tvc->pvnLock, tvc);  /* Since afs_TryToSmush will do a pvn_vptrunc */
4826 #endif
4827     ObtainWriteLock(&tvc->lock, 649);
4828     ObtainWriteLock(&afs_xcbhash, 650);
4829     afs_DequeueCallback(tvc);
4830     tvc->f.states &= ~(CStatd | CDirty); /* next reference will re-stat cache entry */
4831     ReleaseWriteLock(&afs_xcbhash);
4832     /* now find the disk cache entries */
4833     afs_TryToSmush(tvc, *acred, 1);
4834     osi_dnlc_purgedp(tvc);
4835     if (tvc->linkData && !(tvc->f.states & CCore)) {
4836         afs_osi_Free(tvc->linkData, strlen(tvc->linkData) + 1);
4837         tvc->linkData = NULL;
4838     }
4839     ReleaseWriteLock(&tvc->lock);
4840 #ifdef AFS_BOZONLOCK_ENV
4841     afs_BozonUnlock(&tvc->pvnLock, tvc);
4842 #endif
4843     afs_PutVCache(tvc);
4844   out:
4845     if (sysState.allocked)
4846         osi_FreeLargeSpace(bufp);
4847     return code;
4848 }
4849
4850 /*!
4851  * VIOC_RXSTAT_PROC (53) - Control process RX statistics
4852  *
4853  * \ingroup pioctl
4854  *
4855  * \param[in] ain       the flags that control which stats to use
4856  * \param[out] aout     not in use
4857  *
4858  * \retval EACCES       Error if the user doesn't have super-user credentials
4859  * \retval EINVAL       Error if the flag input is too long
4860  *
4861  * \post
4862  *      either enable process RPCStats, disable process RPCStats,
4863  *      or clear the process RPCStats
4864  */
4865 DECL_PIOCTL(PRxStatProc)
4866 {
4867     afs_int32 flags;
4868
4869     if (!afs_osi_suser(*acred))
4870         return EACCES;
4871
4872     if (afs_pd_getInt(ain, &flags) != 0)
4873         return EINVAL;
4874
4875     if (!(flags & AFSCALL_RXSTATS_MASK) || (flags & ~AFSCALL_RXSTATS_MASK))
4876         return EINVAL;
4877
4878     if (flags & AFSCALL_RXSTATS_ENABLE) {
4879         rx_enableProcessRPCStats();
4880     }
4881     if (flags & AFSCALL_RXSTATS_DISABLE) {
4882         rx_disableProcessRPCStats();
4883     }
4884     if (flags & AFSCALL_RXSTATS_CLEAR) {
4885         rx_clearProcessRPCStats(AFS_RX_STATS_CLEAR_ALL);
4886     }
4887     return 0;
4888 }
4889
4890
4891 /*!
4892  * VIOC_RXSTAT_PEER (54) - Control peer RX statistics
4893  *
4894  * \ingroup pioctl
4895  *
4896  * \param[in] ain       the flags that control which statistics to use
4897  * \param[out] aout     not in use
4898  *
4899  * \retval EACCES       Error if the user doesn't have super-user credentials
4900  * \retval EINVAL       Error if the flag input is too long
4901  *
4902  * \post
4903  *      either enable peer RPCStatws, disable peer RPCStats,
4904  *      or clear the peer RPCStats
4905  */
4906 DECL_PIOCTL(PRxStatPeer)
4907 {
4908     afs_int32 flags;
4909
4910     if (!afs_osi_suser(*acred))
4911         return EACCES;
4912
4913     if (afs_pd_getInt(ain, &flags) != 0)
4914         return EINVAL;
4915
4916     if (!(flags & AFSCALL_RXSTATS_MASK) || (flags & ~AFSCALL_RXSTATS_MASK))
4917         return EINVAL;
4918
4919     if (flags & AFSCALL_RXSTATS_ENABLE) {
4920         rx_enablePeerRPCStats();
4921     }
4922     if (flags & AFSCALL_RXSTATS_DISABLE) {
4923         rx_disablePeerRPCStats();
4924     }
4925     if (flags & AFSCALL_RXSTATS_CLEAR) {
4926         rx_clearPeerRPCStats(AFS_RX_STATS_CLEAR_ALL);
4927     }
4928     return 0;
4929 }
4930
4931 DECL_PIOCTL(PPrefetchFromTape)
4932 {
4933     afs_int32 code, code1;
4934     afs_int32 bytes, outval;
4935     struct afs_conn *tc;
4936     struct rx_call *tcall;
4937     struct AFSVolSync tsync;
4938     struct AFSFetchStatus OutStatus;
4939     struct AFSCallBack CallBack;
4940     struct VenusFid tfid;
4941     struct AFSFid *Fid;
4942     struct vcache *tvc;
4943     struct rx_connection *rxconn;
4944
4945     AFS_STATCNT(PSetAcl);
4946     if (!avc)
4947         return EINVAL;
4948
4949     Fid = afs_pd_inline(ain, sizeof(struct AFSFid));
4950     if (Fid == NULL)
4951         Fid = &avc->f.fid.Fid;
4952
4953     tfid.Cell = avc->f.fid.Cell;
4954     tfid.Fid.Volume = Fid->Volume;
4955     tfid.Fid.Vnode = Fid->Vnode;
4956     tfid.Fid.Unique = Fid->Unique;
4957
4958     tvc = afs_GetVCache(&tfid, areq, NULL, NULL);
4959     if (!tvc) {
4960         afs_Trace3(afs_iclSetp, CM_TRACE_PREFETCHCMD, ICL_TYPE_POINTER, tvc,
4961                    ICL_TYPE_FID, &tfid, ICL_TYPE_FID, &avc->f.fid);
4962         return ENOENT;
4963     }
4964     afs_Trace3(afs_iclSetp, CM_TRACE_PREFETCHCMD, ICL_TYPE_POINTER, tvc,
4965                ICL_TYPE_FID, &tfid, ICL_TYPE_FID, &tvc->f.fid);
4966
4967     do {
4968         tc = afs_Conn(&tvc->f.fid, areq, SHARED_LOCK, &rxconn);
4969         if (tc) {
4970
4971             RX_AFS_GUNLOCK();
4972             tcall = rx_NewCall(rxconn);
4973             code =
4974                 StartRXAFS_FetchData(tcall, (struct AFSFid *)&tvc->f.fid.Fid, 0,
4975                                      0);
4976             if (!code) {
4977                 bytes = rx_Read(tcall, (char *)&outval, sizeof(afs_int32));
4978                 code =
4979                     EndRXAFS_FetchData(tcall, &OutStatus, &CallBack, &tsync);
4980             }
4981             code1 = rx_EndCall(tcall, code);
4982             RX_AFS_GLOCK();
4983         } else
4984             code = -1;
4985     } while (afs_Analyze
4986              (tc, rxconn, code, &tvc->f.fid, areq, AFS_STATS_FS_RPCIDX_RESIDENCYRPCS,
4987               SHARED_LOCK, NULL));
4988     /* This call is done only to have the callback things handled correctly */
4989     afs_FetchStatus(tvc, &tfid, areq, &OutStatus);
4990     afs_PutVCache(tvc);
4991
4992     if (code)
4993         return code;
4994
4995     return afs_pd_putInt(aout, outval);
4996 }
4997
4998 DECL_PIOCTL(PFsCmd)
4999 {
5000     afs_int32 code;
5001     struct afs_conn *tc;
5002     struct vcache *tvc;
5003     struct FsCmdInputs *Inputs;
5004     struct FsCmdOutputs *Outputs;
5005     struct VenusFid tfid;
5006     struct AFSFid *Fid;
5007     struct rx_connection *rxconn;
5008
5009     if (!avc)
5010         return EINVAL;
5011
5012     Inputs = afs_pd_inline(ain, sizeof(*Inputs));
5013     if (Inputs == NULL)
5014         return EINVAL;
5015
5016     Outputs = afs_pd_inline(aout, sizeof(*Outputs));
5017     if (Outputs == NULL)
5018         return E2BIG;
5019
5020     Fid = &Inputs->fid;
5021     if (!Fid->Volume)
5022         Fid = &avc->f.fid.Fid;
5023
5024     tfid.Cell = avc->f.fid.Cell;
5025     tfid.Fid.Volume = Fid->Volume;
5026     tfid.Fid.Vnode = Fid->Vnode;
5027     tfid.Fid.Unique = Fid->Unique;
5028
5029     tvc = afs_GetVCache(&tfid, areq, NULL, NULL);
5030     afs_Trace3(afs_iclSetp, CM_TRACE_RESIDCMD, ICL_TYPE_POINTER, tvc,
5031                ICL_TYPE_INT32, Inputs->command, ICL_TYPE_FID, &tfid);
5032     if (!tvc)
5033         return ENOENT;
5034
5035     if (Inputs->command) {
5036         do {
5037             tc = afs_Conn(&tvc->f.fid, areq, SHARED_LOCK, &rxconn);
5038             if (tc) {
5039                 RX_AFS_GUNLOCK();
5040                 code =
5041                     RXAFS_FsCmd(rxconn, Fid, Inputs,
5042                                         (struct FsCmdOutputs *)aout);
5043                 RX_AFS_GLOCK();
5044             } else
5045                 code = -1;
5046         } while (afs_Analyze
5047                  (tc, rxconn, code, &tvc->f.fid, areq,
5048                   AFS_STATS_FS_RPCIDX_RESIDENCYRPCS, SHARED_LOCK, NULL));
5049         /* This call is done to have the callback things handled correctly */
5050         afs_FetchStatus(tvc, &tfid, areq, &Outputs->status);
5051     } else {            /* just a status request, return also link data */
5052         code = 0;
5053         Outputs->code = afs_FetchStatus(tvc, &tfid, areq, &Outputs->status);
5054         Outputs->chars[0] = 0;
5055         if (vType(tvc) == VLNK) {
5056             ObtainWriteLock(&tvc->lock, 555);
5057             if (afs_HandleLink(tvc, areq) == 0)
5058                 strncpy((char *)&Outputs->chars, tvc->linkData, MAXCMDCHARS);
5059             ReleaseWriteLock(&tvc->lock);
5060         }
5061     }
5062
5063     afs_PutVCache(tvc);
5064
5065     return code;
5066 }
5067
5068 DECL_PIOCTL(PNewUuid)
5069 {
5070     /*AFS_STATCNT(PNewUuid); */
5071     if (!afs_resourceinit_flag) /* afs deamons havn't started yet */
5072         return EIO;             /* Inappropriate ioctl for device */
5073
5074     if (!afs_osi_suser(*acred))
5075         return EACCES;
5076
5077     ObtainWriteLock(&afs_xinterface, 555);
5078     afs_uuid_create(&afs_cb_interface.uuid);
5079     ReleaseWriteLock(&afs_xinterface);
5080     ForceAllNewConnections();
5081     return 0;
5082 }
5083
5084 #if defined(AFS_CACHE_BYPASS) && defined(AFS_LINUX24_ENV)
5085
5086 DECL_PIOCTL(PSetCachingThreshold)
5087 {
5088     afs_int32 getting = 1;
5089     afs_int32 setting = 1;
5090     afs_int32 threshold = AFS_CACHE_BYPASS_DISABLED;
5091
5092     if (afs_pd_getInt(ain, &threshold) != 0)
5093         setting = 0;
5094
5095     if (aout == NULL)
5096         getting = 0;
5097
5098     if (setting == 0 && getting == 0)
5099         return EINVAL;
5100
5101     /*
5102      * If setting, set first, and return the value now in effect
5103      */
5104     if (setting) {
5105         if (!afs_osi_suser(*acred))
5106             return EPERM;
5107         cache_bypass_threshold = threshold;
5108         afs_warn("Cache Bypass Threshold set to: %d\n", threshold);
5109         /* TODO:  move to separate pioctl, or enhance pioctl */
5110         cache_bypass_strategy = LARGE_FILES_BYPASS_CACHE;
5111     }
5112
5113     /* Return the current size threshold */
5114     if (getting)
5115         return afs_pd_putInt(aout, cache_bypass_threshold);
5116
5117     return(0);
5118 }
5119
5120 #endif /* defined(AFS_CACHE_BYPASS) */
5121
5122 DECL_PIOCTL(PCallBackAddr)
5123 {
5124 #ifndef UKERNEL
5125     afs_uint32 addr, code;
5126     int srvAddrCount;
5127     struct server *ts;
5128     struct srvAddr *sa;
5129     struct afs_conn *tc;
5130     afs_int32 i, j;
5131     struct unixuser *tu;
5132     struct srvAddr **addrs;
5133     struct rx_connection *rxconn;
5134
5135     /*AFS_STATCNT(PCallBackAddr); */
5136     if (!afs_resourceinit_flag) /* afs deamons havn't started yet */
5137         return EIO;             /* Inappropriate ioctl for device */
5138
5139     if (!afs_osi_suser(acred))
5140         return EACCES;
5141
5142     if (afs_pd_getInt(ain, &addr) != 0)
5143         return EINVAL;
5144
5145     ObtainReadLock(&afs_xinterface);
5146     for (i = 0; (unsigned short)i < afs_cb_interface.numberOfInterfaces; i++) {
5147         if (afs_cb_interface.addr_in[i] == addr)
5148             break;
5149     }
5150
5151     ReleaseWriteLock(&afs_xinterface);
5152
5153     if (afs_cb_interface.addr_in[i] != addr)
5154         return EINVAL;
5155
5156     ObtainReadLock(&afs_xserver);       /* Necessary? */
5157     ObtainReadLock(&afs_xsrvAddr);
5158
5159     srvAddrCount = 0;
5160     for (i = 0; i < NSERVERS; i++) {
5161         for (sa = afs_srvAddrs[i]; sa; sa = sa->next_bkt) {
5162             srvAddrCount++;
5163         }
5164     }
5165
5166     addrs = afs_osi_Alloc(srvAddrCount * sizeof(*addrs));
5167     osi_Assert(addrs != NULL);
5168     j = 0;
5169     for (i = 0; i < NSERVERS; i++) {
5170         for (sa = afs_srvAddrs[i]; sa; sa = sa->next_bkt) {
5171             if (j >= srvAddrCount)
5172                 break;
5173             addrs[j++] = sa;
5174         }
5175     }
5176
5177     ReleaseReadLock(&afs_xsrvAddr);
5178     ReleaseReadLock(&afs_xserver);
5179
5180     for (i = 0; i < j; i++) {
5181         sa = addrs[i];
5182         ts = sa->server;
5183         if (!ts)
5184             continue;
5185
5186         /* vlserver has no callback conn */
5187         if (sa->sa_portal == AFS_VLPORT) {
5188             continue;
5189         }
5190
5191         if (!ts->cell)          /* not really an active server, anyway, it must */
5192             continue;           /* have just been added by setsprefs */
5193
5194         /* get a connection, even if host is down; bumps conn ref count */
5195         tu = afs_GetUser(areq->uid, ts->cell->cellNum, SHARED_LOCK);
5196         tc = afs_ConnBySA(sa, ts->cell->fsport, ts->cell->cellNum, tu,
5197                           1 /*force */ , 1 /*create */ , SHARED_LOCK, &rxconn);
5198         afs_PutUser(tu, SHARED_LOCK);
5199         if (!tc)
5200             continue;
5201
5202         if ((sa->sa_flags & SRVADDR_ISDOWN) || afs_HaveCallBacksFrom(ts)) {
5203             if (sa->sa_flags & SRVADDR_ISDOWN) {
5204                 rx_SetConnDeadTime(rxconn, 3);
5205             }
5206 #ifdef RX_ENABLE_LOCKS
5207             AFS_GUNLOCK();
5208 #endif /* RX_ENABLE_LOCKS */
5209             code = RXAFS_CallBackRxConnAddr(rxconn, &addr);
5210 #ifdef RX_ENABLE_LOCKS
5211             AFS_GLOCK();
5212 #endif /* RX_ENABLE_LOCKS */
5213         }
5214         afs_PutConn(tc, rxconn, SHARED_LOCK);   /* done with it now */
5215     }                           /* Outer loop over addrs */
5216 #endif /* UKERNEL */
5217     return 0;
5218 }
5219
5220 DECL_PIOCTL(PDiscon)
5221 {
5222     static afs_int32 mode = 1; /* Start up in 'off' */
5223     afs_int32 force = 0;
5224     int code = 0;
5225     char flags[4];
5226     struct vrequest lreq;
5227
5228     if (afs_pd_getBytes(ain, &flags, 4) == 0) {
5229         if (!afs_osi_suser(*acred))
5230             return EPERM;
5231
5232         if (flags[0])
5233             mode = flags[0] - 1;
5234         if (flags[1])
5235             afs_ConflictPolicy = flags[1] - 1;
5236         if (flags[2])
5237             force = 1;
5238         if (flags[3]) {
5239             /* Fake InitReq support for UID override */
5240             memset(&lreq, 0, sizeof(lreq));
5241             lreq.uid = flags[3];
5242             areq = &lreq; /* override areq we got */
5243         }
5244
5245         /*
5246          * All of these numbers are hard coded in fs.c. If they
5247          * change here, they should change there and vice versa
5248          */
5249         switch (mode) {
5250         case 0: /* Disconnect ("offline" mode), breaking all callbacks */
5251             if (!AFS_IS_DISCONNECTED) {
5252                 ObtainWriteLock(&afs_discon_lock, 999);
5253                 afs_DisconGiveUpCallbacks();
5254                 afs_RemoveAllConns();
5255                 afs_is_disconnected = 1;
5256                 afs_is_discon_rw = 1;
5257                 ReleaseWriteLock(&afs_discon_lock);
5258             }
5259             break;
5260         case 1: /* Fully connected, ("online" mode). */
5261             ObtainWriteLock(&afs_discon_lock, 998);
5262
5263             afs_in_sync = 1;
5264             afs_MarkAllServersUp();
5265             code = afs_ResyncDisconFiles(areq, *acred);
5266             afs_in_sync = 0;
5267
5268             if (code && !force) {
5269                 afs_warnuser("Files not synchronized properly, still in discon state. \n"
5270                        "Please retry or use \"force\".\n");
5271                 mode = 0;
5272             } else {
5273                 if (force) {
5274                     afs_DisconDiscardAll(*acred);
5275                 }
5276                 afs_ClearAllStatdFlag();
5277                 afs_is_disconnected = 0;
5278                 afs_is_discon_rw = 0;
5279                 afs_warnuser("\nSync succeeded. You are back online.\n");
5280             }
5281
5282             ReleaseWriteLock(&afs_discon_lock);
5283             break;
5284         default:
5285             return EINVAL;
5286         }
5287     } else {
5288         return EINVAL;
5289     }
5290
5291     if (code)
5292         return code;
5293
5294     return afs_pd_putInt(aout, mode);
5295 }
5296
5297 #define MAX_PIOCTL_TOKENS 10
5298
5299 DECL_PIOCTL(PSetTokens2)
5300 {
5301     int code =0;
5302     int i, cellNum, primaryFlag;
5303     XDR xdrs;
5304     struct unixuser *tu;
5305     struct vrequest treq;
5306     struct ktc_setTokenData tokenSet;
5307     struct ktc_tokenUnion decodedToken;
5308
5309     memset(&tokenSet, 0, sizeof(tokenSet));
5310
5311     AFS_STATCNT(PSetTokens2);
5312     if (!afs_resourceinit_flag)
5313         return EIO;
5314
5315     afs_pd_xdrStart(ain, &xdrs, XDR_DECODE);
5316
5317     if (!xdr_ktc_setTokenData(&xdrs, &tokenSet)) {
5318         afs_pd_xdrEnd(ain, &xdrs);
5319         return EINVAL;
5320     }
5321
5322     afs_pd_xdrEnd(ain, &xdrs);
5323
5324     /* We limit each PAG to 10 tokens to prevent a malicous (or runaway)
5325      * process from using up the whole of the kernel memory by allocating
5326      * tokens.
5327      */
5328     if (tokenSet.tokens.tokens_len > MAX_PIOCTL_TOKENS) {
5329         xdr_free((xdrproc_t) xdr_ktc_setTokenData, &tokenSet);
5330         return E2BIG;
5331     }
5332
5333     code = _settok_tokenCell(tokenSet.cell, &cellNum, &primaryFlag);
5334     if (code) {
5335         xdr_free((xdrproc_t) xdr_ktc_setTokenData, &tokenSet);
5336         return code;
5337     }
5338
5339     if (tokenSet.flags & AFSTOKEN_EX_SETPAG) {
5340         if (_settok_setParentPag(acred) == 0) {
5341             afs_InitReq(&treq, *acred);
5342             areq = &treq;
5343         }
5344     }
5345
5346     tu = afs_GetUser(areq->uid, cellNum, WRITE_LOCK);
5347     /* Free any tokens that we've already got */
5348     afs_FreeTokens(&tu->tokens);
5349
5350     /* Iterate across the set of tokens we've received, and stuff them
5351      * into this user's tokenJar
5352      */
5353     for (i=0; i < tokenSet.tokens.tokens_len; i++) {
5354         xdrmem_create(&xdrs,
5355                       tokenSet.tokens.tokens_val[i].token_opaque_val,
5356                       tokenSet.tokens.tokens_val[i].token_opaque_len,
5357                       XDR_DECODE);
5358
5359         memset(&decodedToken, 0, sizeof(decodedToken));
5360         if (!xdr_ktc_tokenUnion(&xdrs, &decodedToken)) {
5361             xdr_destroy(&xdrs);
5362             code = EINVAL;
5363             goto out;
5364         }
5365
5366         xdr_destroy(&xdrs);
5367
5368         afs_AddTokenFromPioctl(&tu->tokens, &decodedToken);
5369         /* This is untidy - the old token interface supported passing
5370          * the primaryFlag as part of the token interface. Current
5371          * OpenAFS userland never sets this, but it's specified as being
5372          * part of the XG interface, so we should probably still support
5373          * it. Rather than add it to our AddToken interface, just handle
5374          * it here.
5375          */
5376         if (decodedToken.at_type == AFSTOKEN_UNION_KAD) {
5377             if (decodedToken.ktc_tokenUnion_u.at_kad.rk_primary_flag)
5378                 primaryFlag = 1;
5379         }
5380
5381         /* XXX - We should think more about destruction here. It's likely that
5382          * there is key material in what we're about to throw away, which
5383          * we really should zero out before giving back to the allocator */
5384         xdr_free((xdrproc_t) xdr_ktc_tokenUnion, &decodedToken);
5385     }
5386
5387     tu->states |= UHasTokens;
5388     tu->states &= ~UTokensBad;
5389     afs_SetPrimary(tu, primaryFlag);
5390     tu->tokenTime = osi_Time();
5391
5392     xdr_free((xdrproc_t) xdr_ktc_setTokenData, &tokenSet);
5393
5394 out:
5395     afs_ResetUserConns(tu);
5396     afs_PutUser(tu, WRITE_LOCK);
5397
5398     return code;
5399 }
5400
5401 DECL_PIOCTL(PGetTokens2)
5402 {
5403     struct cell *cell;
5404     struct unixuser *tu = NULL;
5405     afs_int32 iterator;
5406     char *cellName = NULL;
5407     afs_int32 cellNum;
5408     int code = 0;
5409     time_t now;
5410     XDR xdrs;
5411     struct ktc_setTokenData tokenSet;
5412
5413     AFS_STATCNT(PGetTokens);
5414     if (!afs_resourceinit_flag)
5415         return EIO;
5416
5417     memset(&tokenSet, 0, sizeof(tokenSet));
5418
5419     /* No input data - return tokens for primary cell */
5420     /* 4 octets of data is an iterator count */
5421     /* Otherwise, treat as string & return tokens for that cell name */
5422
5423     if (afs_pd_remaining(ain) == sizeof(afs_int32)) {
5424         /* Integer iterator - return tokens for the n'th cell found for user */
5425         if (afs_pd_getInt(ain, &iterator) != 0)
5426             return EINVAL;
5427         tu = getNthCell(areq->uid, iterator);
5428     } else {
5429         if (afs_pd_remaining(ain) > 0) {
5430             if (afs_pd_getStringPtr(ain, &cellName) != 0)
5431                 return EINVAL;
5432         } else {
5433             cellName = NULL;
5434         }
5435         code = _settok_tokenCell(cellName, &cellNum, NULL);
5436         if (code)
5437             return code;
5438         tu = afs_FindUser(areq->uid, cellNum, READ_LOCK);
5439     }
5440     if (tu == NULL)
5441         return EDOM;
5442
5443     now = osi_Time();
5444
5445     if (!(tu->states & UHasTokens)
5446         || !afs_HasValidTokens(tu->tokens, now)) {
5447         tu->states |= (UTokensBad | UNeedsReset);
5448         afs_PutUser(tu, READ_LOCK);
5449         return ENOTCONN;
5450     }
5451
5452     code = afs_ExtractTokensForPioctl(tu->tokens, now, &tokenSet);
5453     if (code)
5454         goto out;
5455
5456     cell = afs_GetCell(tu->cell, READ_LOCK);
5457     tokenSet.cell = cell->cellName;
5458     afs_pd_xdrStart(aout, &xdrs, XDR_ENCODE);
5459     if (!xdr_ktc_setTokenData(&xdrs, &tokenSet)) {
5460         code = E2BIG;
5461         goto out;
5462     }
5463     afs_pd_xdrEnd(aout, &xdrs);
5464
5465 out:
5466     tokenSet.cell = NULL;
5467
5468     if (tu)
5469         afs_PutUser(tu, READ_LOCK);
5470     if (cell)
5471         afs_PutCell(cell, READ_LOCK);
5472     xdr_free((xdrproc_t)xdr_ktc_setTokenData, &tokenSet);
5473
5474     return code;
5475 };
5476
5477 DECL_PIOCTL(PNFSNukeCreds)
5478 {
5479     afs_uint32 addr;
5480     afs_int32 i;
5481     struct unixuser *tu;
5482
5483     AFS_STATCNT(PUnlog);
5484     if (!afs_resourceinit_flag) /* afs daemons haven't started yet */
5485         return EIO;             /* Inappropriate ioctl for device */
5486
5487     if (afs_pd_getUint(ain, &addr) != 0)
5488         return EINVAL;
5489
5490     if (afs_cr_gid(*acred) == RMTUSER_REQ_PRIV && !addr) {
5491         tu = afs_GetUser(areq->uid, -1, SHARED_LOCK);
5492         if (!tu->exporter || !(addr = EXP_GETHOST(tu->exporter))) {
5493             afs_PutUser(tu, SHARED_LOCK);
5494             return EACCES;
5495         }
5496         afs_PutUser(tu, SHARED_LOCK);
5497     } else if (!afs_osi_suser(acred)) {
5498         return EACCES;
5499     }
5500
5501     ObtainWriteLock(&afs_xuser, 227);
5502     for (i = 0; i < NUSERS; i++) {
5503         for (tu = afs_users[i]; tu; tu = tu->next) {
5504             if (tu->exporter && EXP_CHECKHOST(tu->exporter, addr)) {
5505                 tu->refCount++;
5506                 ReleaseWriteLock(&afs_xuser);
5507
5508                 afs_LockUser(tu, WRITE_LOCK, 367);
5509
5510                 tu->states &= ~UHasTokens;
5511                 afs_FreeTokens(&tu->tokens);
5512                 afs_ResetUserConns(tu);
5513                 afs_PutUser(tu, WRITE_LOCK);
5514                 ObtainWriteLock(&afs_xuser, 228);
5515 #ifdef UKERNEL
5516                 /* set the expire times to 0, causes
5517                  * afs_GCUserData to remove this entry
5518                  */
5519                 tu->tokenTime = 0;
5520 #endif /* UKERNEL */
5521             }
5522         }
5523     }
5524     ReleaseWriteLock(&afs_xuser);
5525     return 0;
5526 }