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