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