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