2 * Copyright 2000, International Business Machines Corporation and others.
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
10 #include <afsconfig.h>
11 #include "afs/param.h"
14 #include "afs/sysincludes.h" /* Standard vendor system headers */
16 #include "h/syscallargs.h"
19 #include "h/sysproto.h"
21 #include "afsincludes.h" /* Afs-based standard headers */
22 #include "afs/afs_stats.h" /* afs statistics */
24 #include "afs/afs_bypasscache.h"
25 #include "rx/rx_globals.h"
27 struct VenusFid afs_rootFid;
28 afs_int32 afs_waitForever = 0;
29 short afs_waitForeverCount = 0;
30 afs_int32 afs_showflags = GAGUSER | GAGCONSOLE; /* show all messages */
33 afs_int32 afs_is_disconnected;
34 afs_int32 afs_is_discon_rw;
35 /* On reconnection, turn this knob on until it finishes,
38 afs_int32 afs_in_sync = 0;
47 * A set of handy little functions for encoding and decoding
48 * pioctls without losing your marbles, or memory integrity
52 afs_pd_alloc(struct afs_pdata *apd, size_t size) {
54 if (size > AFS_LRALLOCSIZ)
55 apd->ptr = osi_Alloc(size + 1);
57 apd->ptr = osi_AllocLargeSpace(AFS_LRALLOCSIZ);
62 apd->remaining = size;
68 afs_pd_free(struct afs_pdata *apd) {
72 if (apd->remaining > AFS_LRALLOCSIZ)
73 osi_Free(apd->ptr, apd->remaining + 1);
75 osi_FreeLargeSpace(apd->ptr);
82 afs_pd_where(struct afs_pdata *apd) {
83 return apd ? apd->ptr : NULL;
87 afs_pd_remaining(struct afs_pdata *apd) {
88 return apd ? apd->remaining : 0;
92 afs_pd_skip(struct afs_pdata *apd, size_t skip) {
93 if (apd == NULL || apd->remaining < skip)
95 apd->remaining -= skip;
102 afs_pd_getInt(struct afs_pdata *apd, afs_int32 *val) {
103 if (apd == NULL || apd->remaining < sizeof(afs_int32))
105 apd->remaining -= sizeof(afs_int32);
106 *val = *(afs_int32 *)apd->ptr;
107 apd->ptr += sizeof(afs_int32);
112 afs_pd_getUint(struct afs_pdata *apd, afs_uint32 *val) {
113 return afs_pd_getInt(apd, (afs_int32 *)val);
117 afs_pd_getBytes(struct afs_pdata *apd, void *dest, size_t bytes) {
118 if (apd == NULL || apd->remaining < bytes)
120 apd->remaining -= bytes;
121 memcpy(dest, apd->ptr, bytes);
127 afs_pd_inline(struct afs_pdata *apd, size_t bytes) {
130 if (apd == NULL || apd->remaining < bytes)
135 apd->remaining -= bytes;
142 afs_pd_getString(struct afs_pdata *apd, char *str, size_t maxLen) {
145 if (apd == NULL || apd->remaining <= 0)
147 len = strlen(apd->ptr) + 1;
150 memcpy(str, apd->ptr, len);
152 apd->remaining -= len;
157 afs_pd_getStringPtr(struct afs_pdata *apd, char **str) {
160 if (apd == NULL || apd->remaining <= 0)
162 len = strlen(apd->ptr) + 1;
165 apd->remaining -= len;
170 afs_pd_putInt(struct afs_pdata *apd, afs_int32 val) {
171 if (apd == NULL || apd->remaining < sizeof(afs_int32))
173 *(afs_int32 *)apd->ptr = val;
174 apd->ptr += sizeof(afs_int32);
175 apd->remaining -= sizeof(afs_int32);
181 afs_pd_putBytes(struct afs_pdata *apd, const void *bytes, size_t len) {
182 if (apd == NULL || apd->remaining < len)
184 memcpy(apd->ptr, bytes, len);
186 apd->remaining -= len;
191 afs_pd_putString(struct afs_pdata *apd, char *str) {
193 /* Add 1 so we copy the NULL too */
194 return afs_pd_putBytes(apd, str, strlen(str) +1);
198 * \defgroup pioctl Path IOCTL functions
200 * DECL_PIOCTL is a macro defined to contain the following parameters for functions:
203 * the AFS vcache structure in use by pioctl
207 * the AFS vrequest structure
209 * an afs_pdata block describing the data received from the caller
211 * an afs_pdata block describing a pre-allocated block for output
213 * UNIX credentials structure underlying the operation
216 #define DECL_PIOCTL(x) \
217 static int x(struct vcache *avc, int afun, struct vrequest *areq, \
218 struct afs_pdata *ain, struct afs_pdata *aout, \
221 /* Prototypes for pioctl routines */
222 DECL_PIOCTL(PGetFID);
223 DECL_PIOCTL(PSetAcl);
224 DECL_PIOCTL(PStoreBehind);
225 DECL_PIOCTL(PGCPAGs);
226 DECL_PIOCTL(PGetAcl);
229 DECL_PIOCTL(PGetFileCell);
230 DECL_PIOCTL(PGetWSCell);
231 DECL_PIOCTL(PGetUserCell);
232 DECL_PIOCTL(PSetTokens);
233 DECL_PIOCTL(PGetVolumeStatus);
234 DECL_PIOCTL(PSetVolumeStatus);
236 DECL_PIOCTL(PNewStatMount);
237 DECL_PIOCTL(PGetTokens);
239 DECL_PIOCTL(PMariner);
240 DECL_PIOCTL(PCheckServers);
241 DECL_PIOCTL(PCheckVolNames);
242 DECL_PIOCTL(PCheckAuth);
243 DECL_PIOCTL(PFindVolume);
244 DECL_PIOCTL(PViceAccess);
245 DECL_PIOCTL(PSetCacheSize);
246 DECL_PIOCTL(PGetCacheSize);
247 DECL_PIOCTL(PRemoveCallBack);
248 DECL_PIOCTL(PNewCell);
249 DECL_PIOCTL(PNewAlias);
250 DECL_PIOCTL(PListCells);
251 DECL_PIOCTL(PListAliases);
252 DECL_PIOCTL(PRemoveMount);
253 DECL_PIOCTL(PVenusLogging);
254 DECL_PIOCTL(PGetCellStatus);
255 DECL_PIOCTL(PSetCellStatus);
256 DECL_PIOCTL(PFlushVolumeData);
257 DECL_PIOCTL(PGetVnodeXStatus);
258 DECL_PIOCTL(PGetVnodeXStatus2);
259 DECL_PIOCTL(PSetSysName);
260 DECL_PIOCTL(PSetSPrefs);
261 DECL_PIOCTL(PSetSPrefs33);
262 DECL_PIOCTL(PGetSPrefs);
263 DECL_PIOCTL(PExportAfs);
265 DECL_PIOCTL(PTwiddleRx);
266 DECL_PIOCTL(PGetInitParams);
267 DECL_PIOCTL(PGetRxkcrypt);
268 DECL_PIOCTL(PSetRxkcrypt);
269 DECL_PIOCTL(PGetCPrefs);
270 DECL_PIOCTL(PSetCPrefs);
271 DECL_PIOCTL(PFlushMount);
272 DECL_PIOCTL(PRxStatProc);
273 DECL_PIOCTL(PRxStatPeer);
274 DECL_PIOCTL(PPrefetchFromTape);
276 DECL_PIOCTL(PCallBackAddr);
277 DECL_PIOCTL(PDiscon);
278 DECL_PIOCTL(PNFSNukeCreds);
279 DECL_PIOCTL(PNewUuid);
280 DECL_PIOCTL(PPrecache);
281 DECL_PIOCTL(PGetPAG);
282 #if defined(AFS_CACHE_BYPASS)
283 DECL_PIOCTL(PSetCachingThreshold);
284 DECL_PIOCTL(PSetCachingBlkSize);
288 * A macro that says whether we're going to need HandleClientContext().
289 * This is currently used only by the nfs translator.
291 #if !defined(AFS_NONFSTRANS) || defined(AFS_AIX_IAUTH_ENV)
292 #define AFS_NEED_CLIENTCONTEXT
295 /* Prototypes for private routines */
296 #ifdef AFS_NEED_CLIENTCONTEXT
297 static int HandleClientContext(struct afs_ioctl *ablob, int *com,
301 int HandleIoctl(register struct vcache *avc, register afs_int32 acom,
302 struct afs_ioctl *adata);
303 int afs_HandlePioctl(struct vnode *avp, afs_int32 acom,
304 register struct afs_ioctl *ablob, int afollow,
305 afs_ucred_t **acred);
306 static int Prefetch(uparmtype apath, struct afs_ioctl *adata, int afollow,
309 typedef int (*pioctlFunction) (struct vcache *, int, struct vrequest *,
310 struct afs_pdata *, struct afs_pdata *,
313 static pioctlFunction VpioctlSw[] = {
318 PGetVolumeStatus, /* 4 */
319 PSetVolumeStatus, /* 5 */
324 PCheckServers, /* 10 */
325 PCheckVolNames, /* 11 */
327 PBogus, /* 13 -- used to be quick check time */
328 PFindVolume, /* 14 */
329 PBogus, /* 15 -- prefetch is now special-cased; see pioctl code! */
330 PBogus, /* 16 -- used to be testing code */
331 PNoop, /* 17 -- used to be enable group */
332 PNoop, /* 18 -- used to be disable group */
333 PBogus, /* 19 -- used to be list group */
334 PViceAccess, /* 20 */
335 PUnlog, /* 21 -- unlog *is* unpag in this system */
336 PGetFID, /* 22 -- get file ID */
337 PBogus, /* 23 -- used to be waitforever */
338 PSetCacheSize, /* 24 */
339 PRemoveCallBack, /* 25 -- flush only the callback */
342 PRemoveMount, /* 28 -- delete mount point */
343 PNewStatMount, /* 29 -- new style mount point stat */
344 PGetFileCell, /* 30 -- get cell name for input file */
345 PGetWSCell, /* 31 -- get cell name for workstation */
346 PMariner, /* 32 - set/get mariner host */
347 PGetUserCell, /* 33 -- get cell name for user */
348 PVenusLogging, /* 34 -- Enable/Disable logging */
349 PGetCellStatus, /* 35 */
350 PSetCellStatus, /* 36 */
351 PFlushVolumeData, /* 37 -- flush all data from a volume */
352 PSetSysName, /* 38 - Set system name */
353 PExportAfs, /* 39 - Export Afs to remote nfs clients */
354 PGetCacheSize, /* 40 - get cache size and usage */
355 PGetVnodeXStatus, /* 41 - get vcache's special status */
356 PSetSPrefs33, /* 42 - Set CM Server preferences... */
357 PGetSPrefs, /* 43 - Get CM Server preferences... */
358 PGag, /* 44 - turn off/on all CM messages */
359 PTwiddleRx, /* 45 - adjust some RX params */
360 PSetSPrefs, /* 46 - Set CM Server preferences... */
361 PStoreBehind, /* 47 - set degree of store behind to be done */
362 PGCPAGs, /* 48 - disable automatic pag gc-ing */
363 PGetInitParams, /* 49 - get initial cm params */
364 PGetCPrefs, /* 50 - get client interface addresses */
365 PSetCPrefs, /* 51 - set client interface addresses */
366 PFlushMount, /* 52 - flush mount symlink data */
367 PRxStatProc, /* 53 - control process RX statistics */
368 PRxStatPeer, /* 54 - control peer RX statistics */
369 PGetRxkcrypt, /* 55 -- Get rxkad encryption flag */
370 PSetRxkcrypt, /* 56 -- Set rxkad encryption flag */
371 PBogus, /* 57 -- arla: set file prio */
372 PBogus, /* 58 -- arla: fallback getfh */
373 PBogus, /* 59 -- arla: fallback fhopen */
374 PBogus, /* 60 -- arla: controls xfsdebug */
375 PBogus, /* 61 -- arla: controls arla debug */
376 PBogus, /* 62 -- arla: debug interface */
377 PBogus, /* 63 -- arla: print xfs status */
378 PBogus, /* 64 -- arla: force cache check */
379 PBogus, /* 65 -- arla: break callback */
380 PPrefetchFromTape, /* 66 -- MR-AFS: prefetch file from tape */
381 PFsCmd, /* 67 -- RXOSD: generic commnd interface */
382 PBogus, /* 68 -- arla: fetch stats */
383 PGetVnodeXStatus2, /* 69 - get caller access and some vcache status */
386 static pioctlFunction CpioctlSw[] = {
388 PNewAlias, /* 1 -- create new cell alias */
389 PListAliases, /* 2 -- list cell aliases */
390 PCallBackAddr, /* 3 -- request addr for callback rxcon */
392 PDiscon, /* 5 -- get/set discon mode */
403 static pioctlFunction OpioctlSw[] = {
405 PNFSNukeCreds, /* 1 -- nuke all creds for NFS client */
406 #if defined(AFS_CACHE_BYPASS)
407 PSetCachingThreshold /* 2 -- get/set cache-bypass size threshold */
409 PNoop /* 2 -- get/set cache-bypass size threshold */
413 #define PSetClientContext 99 /* Special pioctl to setup caller's creds */
414 int afs_nobody = NFS_NOBODY;
417 HandleIoctl(register struct vcache *avc, register afs_int32 acom,
418 struct afs_ioctl *adata)
420 register afs_int32 code;
423 AFS_STATCNT(HandleIoctl);
425 switch (acom & 0xff) {
427 avc->f.states |= CSafeStore;
429 /* SXW - Should we force a MetaData flush for this flag setting */
432 /* case 2 used to be abort store, but this is no longer provided,
433 * since it is impossible to implement under normal Unix.
437 /* return the name of the cell this file is open on */
438 register struct cell *tcell;
439 register afs_int32 i;
441 tcell = afs_GetCell(avc->f.fid.Cell, READ_LOCK);
443 i = strlen(tcell->cellName) + 1; /* bytes to copy out */
445 if (i > adata->out_size) {
446 /* 0 means we're not interested in the output */
447 if (adata->out_size != 0)
451 AFS_COPYOUT(tcell->cellName, adata->out, i, code);
453 afs_PutCell(tcell, READ_LOCK);
459 case 49: /* VIOC_GETINITPARAMS */
460 if (adata->out_size < sizeof(struct cm_initparams)) {
463 AFS_COPYOUT(&cm_initParams, adata->out,
464 sizeof(struct cm_initparams), code);
476 return code; /* so far, none implemented */
480 /* For aix we don't temporarily bypass ioctl(2) but rather do our
481 * thing directly in the vnode layer call, VNOP_IOCTL; thus afs_ioctl
482 * is now called from afs_gn_ioctl.
485 afs_ioctl(struct vcache *tvc, int cmd, int arg)
487 struct afs_ioctl data;
490 AFS_STATCNT(afs_ioctl);
491 if (((cmd >> 8) & 0xff) == 'V') {
492 /* This is a VICEIOCTL call */
493 AFS_COPYIN(arg, (caddr_t) & data, sizeof(data), error);
496 error = HandleIoctl(tvc, cmd, &data);
499 /* No-op call; just return. */
503 #endif /* AFS_AIX_ENV */
505 #if defined(AFS_SGI_ENV)
506 afs_ioctl(OSI_VN_DECL(tvc), int cmd, void *arg, int flag, cred_t * cr,
509 , struct vopbd * vbds
513 struct afs_ioctl data;
519 AFS_STATCNT(afs_ioctl);
520 if (((cmd >> 8) & 0xff) == 'V') {
521 /* This is a VICEIOCTL call */
522 error = copyin_afs_ioctl(arg, &data);
525 locked = ISAFS_GLOCK();
528 error = HandleIoctl(tvc, cmd, &data);
533 /* No-op call; just return. */
537 #endif /* AFS_SGI_ENV */
539 /* unlike most calls here, this one uses u.u_error to return error conditions,
540 since this is really an intercepted chapter 2 call, rather than a vnode
543 /* AFS_HPUX102 and up uses VNODE ioctl instead */
544 #if !defined(AFS_HPUX102_ENV) && !defined(AFS_DARWIN80_ENV)
545 # if !defined(AFS_SGI_ENV)
546 # ifdef AFS_AIX32_ENV
547 # ifdef AFS_AIX51_ENV
550 kioctl(int fdes, int com, caddr_t arg, caddr_t ext, caddr_t arg2,
552 # else /* __64BIT__ */
554 kioctl32(int fdes, int com, caddr_t arg, caddr_t ext, caddr_t arg2,
556 # endif /* __64BIT__ */
559 kioctl(int fdes, int com, caddr_t arg, caddr_t ext)
565 # ifdef AFS_AIX51_ENV
568 } u_uap, *uap = &u_uap;
570 # if defined(AFS_SUN5_ENV)
572 struct afs_ioctl_sys {
579 afs_xioctl(struct afs_ioctl_sys *uap, rval_t *rvp)
581 # elif defined(AFS_FBSD50_ENV)
584 afs_xioctl(struct thread *td, register struct ioctl_args *uap,
587 afs_proc_t *p = td->td_proc;
588 # elif defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
596 afs_xioctl(afs_proc_t *p, register struct ioctl_args *uap, register_t *retval)
598 # elif defined(AFS_LINUX22_ENV)
599 struct afs_ioctl_sys {
604 afs_xioctl(struct inode *ip, struct file *fp, unsigned int com,
607 struct afs_ioctl_sys ua, *uap = &ua;
616 } *uap = (struct a *)u.u_ap;
617 # endif /* AFS_SUN5_ENV */
619 # if defined(AFS_AIX32_ENV) || defined(AFS_SUN5_ENV) || defined(AFS_DARWIN_ENV)
621 # elif !defined(AFS_LINUX22_ENV)
622 register struct file *fd;
624 # if defined(AFS_XBSD_ENV)
625 register struct filedesc *fdp;
627 register struct vcache *tvc;
628 register int ioctlDone = 0, code = 0;
630 AFS_STATCNT(afs_xioctl);
631 # if defined(AFS_DARWIN_ENV)
632 if ((code = fdgetf(p, uap->fd, &fd)))
634 # elif defined(AFS_XBSD_ENV)
636 if ((u_int) uap->fd >= fdp->fd_nfiles
637 || (fd = fdp->fd_ofiles[uap->fd]) == NULL)
639 if ((fd->f_flag & (FREAD | FWRITE)) == 0)
641 # elif defined(AFS_LINUX22_ENV)
644 # elif defined(AFS_AIX32_ENV)
648 # ifdef AFS_AIX51_ENV
652 if (setuerror(getf(uap->fd, &fd))) {
655 # elif defined(AFS_SUN5_ENV)
656 # if defined(AFS_SUN57_ENV)
660 # elif defined(AFS_SUN54_ENV)
665 if (code = getf(uap->fd, &fd)) {
668 # endif /* AFS_SUN57_ENV */
674 /* first determine whether this is any sort of vnode */
675 # if defined(AFS_LINUX22_ENV)
680 if (fd->f_vnode->v_type == VREG || fd->f_vnode->v_type == VDIR) {
682 if (fd->f_type == DTYPE_VNODE) {
684 /* good, this is a vnode; next see if it is an AFS vnode */
685 # if defined(AFS_AIX32_ENV) || defined(AFS_SUN5_ENV)
686 tvc = VTOAFS(fd->f_vnode); /* valid, given a vnode */
687 # elif defined(AFS_OBSD_ENV)
689 IsAfsVnode((struct vnode *)fd->
690 f_data) ? VTOAFS((struct vnode *)fd->f_data) : NULL;
692 tvc = VTOAFS((struct vnode *)fd->f_data); /* valid, given a vnode */
694 # endif /* AFS_LINUX22_ENV */
695 if (tvc && IsAfsVnode(AFSTOV(tvc))) {
696 /* This is an AFS vnode */
697 if (((uap->com >> 8) & 0xff) == 'V') {
698 register struct afs_ioctl *datap;
701 (struct afs_ioctl *)osi_AllocSmallSpace(AFS_SMALLOCSIZ);
702 code=copyin_afs_ioctl((char *)uap->arg, datap);
704 osi_FreeSmallSpace(datap);
706 # if defined(AFS_AIX41_ENV)
708 # elif defined(AFS_SUN54_ENV)
710 # elif defined(AFS_SUN5_ENV)
714 # if defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
716 # elif defined(AFS_SUN5_ENV)
718 # elif defined(AFS_LINUX22_ENV)
721 return (setuerror(code), code);
724 code = HandleIoctl(tvc, uap->com, datap);
725 osi_FreeSmallSpace(datap);
728 # if defined(AFS_AIX41_ENV)
732 # if defined(AFS_LINUX22_ENV)
740 # if defined(AFS_AIX41_ENV)
742 # ifdef AFS_AIX51_ENV
744 code = okioctl(fdes, com, arg, ext, arg2, arg3);
745 # else /* __64BIT__ */
746 code = okioctl32(fdes, com, arg, ext, arg2, arg3);
747 # endif /* __64BIT__ */
748 # else /* !AFS_AIX51_ENV */
749 code = okioctl(fdes, com, arg, ext);
750 # endif /* AFS_AIX51_ENV */
752 # elif defined(AFS_AIX32_ENV)
753 okioctl(fdes, com, arg, ext);
754 # elif defined(AFS_SUN5_ENV)
755 # if defined(AFS_SUN57_ENV)
757 # elif defined(AFS_SUN54_ENV)
762 code = ioctl(uap, rvp);
763 # elif defined(AFS_FBSD50_ENV)
764 return ioctl(td, uap);
765 # elif defined(AFS_FBSD_ENV)
766 return ioctl(p, uap);
767 # elif defined(AFS_OBSD_ENV)
768 code = sys_ioctl(p, uap, retval);
769 # elif defined(AFS_DARWIN_ENV)
770 return ioctl(p, uap, retval);
771 # elif !defined(AFS_LINUX22_ENV)
777 # ifdef AFS_SUN54_ENV
783 # elif defined(AFS_LINUX22_ENV)
785 # elif defined(KERNEL_HAVE_UERROR)
788 # if defined(AFS_AIX32_ENV) && !defined(AFS_AIX41_ENV)
789 return (getuerror()? -1 : u.u_ioctlrv);
791 return getuerror()? -1 : 0;
795 # if defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
801 # endif /* AFS_SGI_ENV */
802 #endif /* AFS_HPUX102_ENV */
804 #if defined(AFS_SGI_ENV)
805 /* "pioctl" system call entry point; just pass argument to the parameterized
814 afs_pioctl(struct pioctlargs *uap, rval_t * rvp)
818 AFS_STATCNT(afs_pioctl);
820 code = afs_syscall_pioctl(uap->path, uap->cmd, uap->cmarg, uap->follow);
822 # ifdef AFS_SGI64_ENV
829 #elif defined(AFS_FBSD50_ENV)
831 afs_pioctl(struct thread *td, void *args, int *retval)
838 } *uap = (struct a *)args;
840 AFS_STATCNT(afs_pioctl);
841 return (afs_syscall_pioctl
842 (uap->path, uap->cmd, uap->cmarg, uap->follow, td->td_ucred));
845 #elif defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
847 afs_pioctl(afs_proc_t *p, void *args, int *retval)
854 } *uap = (struct a *)args;
856 AFS_STATCNT(afs_pioctl);
857 # ifdef AFS_DARWIN80_ENV
858 return (afs_syscall_pioctl
859 (uap->path, uap->cmd, uap->cmarg, uap->follow,
862 return (afs_syscall_pioctl
863 (uap->path, uap->cmd, uap->cmarg, uap->follow,
864 p->p_cred->pc_ucred));
870 /* macro to avoid adding any more #ifdef's to pioctl code. */
871 #if defined(AFS_LINUX22_ENV) || defined(AFS_AIX41_ENV)
872 #define PIOCTL_FREE_CRED() crfree(credp)
874 #define PIOCTL_FREE_CRED()
879 afs_syscall_pioctl(char *path, unsigned int com, caddr_t cmarg, int follow,
880 rval_t *vvp, afs_ucred_t *credp)
882 #ifdef AFS_DARWIN100_ENV
883 afs_syscall64_pioctl(user_addr_t path, unsigned int com, user_addr_t cmarg,
884 int follow, afs_ucred_t *credp)
885 #elif defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
886 afs_syscall_pioctl(char *path, unsigned int com, caddr_t cmarg, int follow,
889 afs_syscall_pioctl(char *path, unsigned int com, caddr_t cmarg, int follow)
893 struct afs_ioctl data;
894 #ifdef AFS_NEED_CLIENTCONTEXT
895 afs_ucred_t *tmpcred = NULL;
897 #if defined(AFS_NEED_CLIENTCONTEXT) || defined(AFS_SUN5_ENV) || defined(AFS_AIX41_ENV) || defined(AFS_LINUX22_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
898 afs_ucred_t *foreigncreds = NULL;
900 register afs_int32 code = 0;
901 struct vnode *vp = NULL;
903 struct ucred *credp = crref(); /* don't free until done! */
905 #ifdef AFS_LINUX22_ENV
906 cred_t *credp = crref(); /* don't free until done! */
910 AFS_STATCNT(afs_syscall_pioctl);
912 follow = 1; /* compat. with old venus */
913 code = copyin_afs_ioctl(cmarg, &data);
916 #if defined(KERNEL_HAVE_UERROR)
921 if ((com & 0xff) == PSetClientContext) {
922 #ifdef AFS_NEED_CLIENTCONTEXT
923 #if defined(AFS_SUN5_ENV) || defined(AFS_AIX41_ENV) || defined(AFS_LINUX22_ENV)
924 code = HandleClientContext(&data, &com, &foreigncreds, credp);
926 code = HandleClientContext(&data, &com, &foreigncreds, osi_curcred());
930 crfree(foreigncreds);
933 #if defined(KERNEL_HAVE_UERROR)
934 return (setuerror(code), code);
939 #else /* AFS_NEED_CLIENTCONTEXT */
941 #endif /* AFS_NEED_CLIENTCONTEXT */
943 #ifdef AFS_NEED_CLIENTCONTEXT
946 * We could have done without temporary setting the u.u_cred below
947 * (foreigncreds could be passed as param the pioctl modules)
948 * but calls such as afs_osi_suser() doesn't allow that since it
949 * references u.u_cred directly. We could, of course, do something
950 * like afs_osi_suser(cred) which, I think, is better since it
951 * generalizes and supports multi cred environments...
953 #if defined(AFS_SUN5_ENV) || defined(AFS_LINUX22_ENV)
955 credp = foreigncreds;
956 #elif defined(AFS_AIX41_ENV)
957 tmpcred = crref(); /* XXX */
959 #elif defined(AFS_HPUX101_ENV)
960 tmpcred = p_cred(u.u_procp);
961 set_p_cred(u.u_procp, foreigncreds);
962 #elif defined(AFS_SGI_ENV)
963 tmpcred = OSI_GET_CURRENT_CRED();
964 OSI_SET_CURRENT_CRED(foreigncreds);
967 u.u_cred = foreigncreds;
970 #endif /* AFS_NEED_CLIENTCONTEXT */
971 if ((com & 0xff) == 15) {
972 /* special case prefetch so entire pathname eval occurs in helper process.
973 * otherwise, the pioctl call is essentially useless */
974 #if defined(AFS_SUN5_ENV) || defined(AFS_AIX41_ENV) || defined(AFS_LINUX22_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
976 Prefetch(path, &data, follow,
977 foreigncreds ? foreigncreds : credp);
979 code = Prefetch(path, &data, follow, osi_curcred());
982 #if defined(KERNEL_HAVE_UERROR)
991 lookupname(path, USR, follow, NULL, &vp,
992 foreigncreds ? foreigncreds : credp);
994 #ifdef AFS_LINUX22_ENV
995 code = gop_lookupname_user(path, AFS_UIOUSER, follow, &dp);
997 vp = (struct vnode *)dp->d_inode;
999 code = gop_lookupname_user(path, AFS_UIOUSER, follow, &vp);
1000 #if defined(AFS_FBSD80_ENV) /* XXX check on 7x */
1002 #endif /* AFS_FBSD80_ENV */
1003 #endif /* AFS_LINUX22_ENV */
1004 #endif /* AFS_AIX41_ENV */
1008 #if defined(KERNEL_HAVE_UERROR)
1016 #if defined(AFS_SUN510_ENV)
1017 if (vp && !IsAfsVnode(vp)) {
1018 struct vnode *realvp;
1020 #ifdef AFS_SUN511_ENV
1021 (VOP_REALVP(vp, &realvp, NULL) == 0)
1023 (VOP_REALVP(vp, &realvp) == 0)
1026 struct vnode *oldvp = vp;
1034 /* now make the call if we were passed no file, or were passed an AFS file */
1035 if (!vp || IsAfsVnode(vp)) {
1036 #if defined(AFS_SUN5_ENV)
1037 code = afs_HandlePioctl(vp, com, &data, follow, &credp);
1038 #elif defined(AFS_AIX41_ENV)
1040 struct ucred *cred1, *cred2;
1043 cred1 = cred2 = foreigncreds;
1045 cred1 = cred2 = credp;
1047 code = afs_HandlePioctl(vp, com, &data, follow, &cred1);
1048 if (cred1 != cred2) {
1049 /* something changed the creds */
1053 #elif defined(AFS_HPUX101_ENV)
1055 struct ucred *cred = p_cred(u.u_procp);
1056 code = afs_HandlePioctl(vp, com, &data, follow, &cred);
1058 #elif defined(AFS_SGI_ENV)
1061 credp = OSI_GET_CURRENT_CRED();
1062 code = afs_HandlePioctl(vp, com, &data, follow, &credp);
1064 #elif defined(AFS_LINUX22_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
1065 code = afs_HandlePioctl(vp, com, &data, follow, &credp);
1067 code = afs_HandlePioctl(vp, com, &data, follow, &u.u_cred);
1070 #if defined(KERNEL_HAVE_UERROR)
1073 code = EINVAL; /* not in /afs */
1078 #if defined(AFS_NEED_CLIENTCONTEXT)
1080 #ifdef AFS_AIX41_ENV
1081 crset(tmpcred); /* restore original credentials */
1083 #if defined(AFS_HPUX101_ENV)
1084 set_p_cred(u.u_procp, tmpcred); /* restore original credentials */
1085 #elif defined(AFS_SGI_ENV)
1086 OSI_SET_CURRENT_CRED(tmpcred); /* restore original credentials */
1087 #elif defined(AFS_SUN5_ENV) || defined(AFS_LINUX22_ENV)
1088 credp = tmpcred; /* restore original credentials */
1090 osi_curcred() = tmpcred; /* restore original credentials */
1091 #endif /* AFS_HPUX101_ENV */
1092 crfree(foreigncreds);
1095 #endif /* AFS_NEED_CLIENTCONTEXT */
1097 #ifdef AFS_LINUX22_ENV
1100 #if defined(AFS_FBSD80_ENV)
1101 if (VOP_ISLOCKED(vp))
1103 #endif /* AFS_FBSD80_ENV */
1104 AFS_RELE(vp); /* put vnode back */
1108 #if defined(KERNEL_HAVE_UERROR)
1111 return (getuerror());
1117 #ifdef AFS_DARWIN100_ENV
1119 afs_syscall_pioctl(char * path, unsigned int com, caddr_t cmarg,
1120 int follow, afs_ucred_t *credp)
1122 return afs_syscall64_pioctl(CAST_USER_ADDR_T(path), com,
1123 CAST_USER_ADDR_T((unsigned int)cmarg), follow,
1128 #define MAXPIOCTLTOKENLEN \
1129 (3*sizeof(afs_int32)+MAXKTCTICKETLEN+sizeof(struct ClearToken)+MAXKTCREALMLEN)
1132 afs_HandlePioctl(struct vnode *avp, afs_int32 acom,
1133 register struct afs_ioctl *ablob, int afollow,
1134 afs_ucred_t **acred)
1137 struct vrequest treq;
1138 register afs_int32 code;
1139 register afs_int32 function, device;
1140 struct afs_pdata input, output;
1141 struct afs_pdata copyInput, copyOutput;
1143 pioctlFunction *pioctlSw;
1145 struct afs_fakestat_state fakestate;
1147 memset(&input, 0, sizeof(input));
1148 memset(&output, 0, sizeof(output));
1150 avc = avp ? VTOAFS(avp) : NULL;
1151 afs_Trace3(afs_iclSetp, CM_TRACE_PIOCTL, ICL_TYPE_INT32, acom & 0xff,
1152 ICL_TYPE_POINTER, avc, ICL_TYPE_INT32, afollow);
1153 AFS_STATCNT(HandlePioctl);
1155 code = afs_InitReq(&treq, *acred);
1159 afs_InitFakeStat(&fakestate);
1161 code = afs_EvalFakeStat(&avc, &fakestate, &treq);
1165 device = (acom & 0xff00) >> 8;
1167 case 'V': /* Original pioctls */
1168 pioctlSw = VpioctlSw;
1169 pioctlSwSize = sizeof(VpioctlSw);
1171 case 'C': /* Coordinated/common pioctls */
1172 pioctlSw = CpioctlSw;
1173 pioctlSwSize = sizeof(CpioctlSw);
1175 case 'O': /* Coordinated/common pioctls */
1176 pioctlSw = OpioctlSw;
1177 pioctlSwSize = sizeof(OpioctlSw);
1183 function = acom & 0xff;
1184 if (function >= (pioctlSwSize / sizeof(char *))) {
1189 /* Do all range checking before continuing */
1190 if (ablob->in_size > MAXPIOCTLTOKENLEN ||
1191 ablob->in_size < 0 || ablob->out_size < 0) {
1196 code = afs_pd_alloc(&input, ablob->in_size);
1200 if (ablob->in_size > 0) {
1201 AFS_COPYIN(ablob->in, input.ptr, ablob->in_size, code);
1202 input.ptr[input.remaining] = '\0';
1207 if (function == 8 && device == 'V') { /* PGetTokens */
1208 code = afs_pd_alloc(&output, MAXPIOCTLTOKENLEN);
1210 code = afs_pd_alloc(&output, AFS_LRALLOCSIZ);
1216 copyOutput = output;
1219 (*pioctlSw[function]) (avc, function, &treq, ©Input,
1220 ©Output, acred);
1222 outSize = copyOutput.ptr - output.ptr;
1224 if (code == 0 && ablob->out_size > 0) {
1225 if (outSize > ablob->out_size) {
1226 code = E2BIG; /* data wont fit in user buffer */
1227 } else if (outSize) {
1228 AFS_COPYOUT(output.ptr, ablob->out, outSize, code);
1233 afs_pd_free(&input);
1234 afs_pd_free(&output);
1236 afs_PutFakeStat(&fakestate);
1237 return afs_CheckCode(code, &treq, 41);
1241 * VIOCGETFID (22) - Get file ID quickly
1245 * \param[in] ain not in use
1246 * \param[out] aout fid of requested file
1248 * \retval EINVAL Error if some of the initial arguments aren't set
1250 * \post get the file id of some file
1252 DECL_PIOCTL(PGetFID)
1254 AFS_STATCNT(PGetFID);
1257 if (afs_pd_putBytes(aout, &avc->f.fid, sizeof(struct VenusFid)) != 0)
1263 * VIOCSETAL (1) - Set access control list
1267 * \param[in] ain the ACL being set
1268 * \param[out] aout the ACL being set returned
1270 * \retval EINVAL Error if some of the standard args aren't set
1272 * \post Changed ACL, via direct writing to the wire
1274 int dummy_PSetAcl(char *ain, char *aout)
1279 DECL_PIOCTL(PSetAcl)
1281 register afs_int32 code;
1282 struct afs_conn *tconn;
1283 struct AFSOpaque acl;
1284 struct AFSVolSync tsync;
1285 struct AFSFetchStatus OutStatus;
1288 AFS_STATCNT(PSetAcl);
1292 if (afs_pd_getStringPtr(ain, &acl.AFSOpaque_val) != 0)
1294 acl.AFSOpaque_len = strlen(acl.AFSOpaque_val) + 1;
1295 if (acl.AFSOpaque_len > 1024)
1299 tconn = afs_Conn(&avc->f.fid, areq, SHARED_LOCK);
1301 XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_STOREACL);
1304 RXAFS_StoreACL(tconn->id, (struct AFSFid *)&avc->f.fid.Fid,
1305 &acl, &OutStatus, &tsync);
1310 } while (afs_Analyze
1311 (tconn, code, &avc->f.fid, areq, AFS_STATS_FS_RPCIDX_STOREACL,
1312 SHARED_LOCK, NULL));
1314 /* now we've forgotten all of the access info */
1315 ObtainWriteLock(&afs_xcbhash, 455);
1317 afs_DequeueCallback(avc);
1318 avc->f.states &= ~(CStatd | CUnique);
1319 ReleaseWriteLock(&afs_xcbhash);
1320 if (avc->f.fid.Fid.Vnode & 1 || (vType(avc) == VDIR))
1321 osi_dnlc_purgedp(avc);
1323 /* SXW - Should we flush metadata here? */
1327 int afs_defaultAsynchrony = 0;
1330 * VIOC_STOREBEHIND (47) Adjust store asynchrony
1334 * \param[in] ain sbstruct (store behind structure) input
1335 * \param[out] aout resulting sbstruct
1337 * \retval EPERM Error if the user doesn't have super-user credentials
1338 * \retval EACCES Error if there isn't enough access to not check the mode bits
1340 * \post sets asynchrony based on a file, from a struct sbstruct "I THINK"
1342 DECL_PIOCTL(PStoreBehind)
1344 struct sbstruct sbr;
1346 if (afs_pd_getBytes(ain, &sbr, sizeof(struct sbstruct)) != 0)
1349 if (sbr.sb_default != -1) {
1350 if (afs_osi_suser(*acred))
1351 afs_defaultAsynchrony = sbr.sb_default;
1356 if (avc && (sbr.sb_thisfile != -1)) {
1358 (avc, PRSFS_WRITE | PRSFS_ADMINISTER, areq, DONT_CHECK_MODE_BITS))
1359 avc->asynchrony = sbr.sb_thisfile;
1364 memset(&sbr, 0, sizeof(sbr));
1365 sbr.sb_default = afs_defaultAsynchrony;
1367 sbr.sb_thisfile = avc->asynchrony;
1370 return afs_pd_putBytes(aout, &sbr, sizeof(sbr));
1374 * VIOC_GCPAGS (48) - Disable automatic PAG gc'ing
1378 * \param[in] ain not in use
1379 * \param[out] aout not in use
1381 * \retval EACCES Error if the user doesn't have super-user credentials
1383 * \post set the gcpags to GCPAGS_USERDISABLED
1385 DECL_PIOCTL(PGCPAGs)
1387 if (!afs_osi_suser(*acred)) {
1390 afs_gcpags = AFS_GCPAGS_USERDISABLED;
1395 * VIOCGETAL (2) - Get access control list
1399 * \param[in] ain not in use
1400 * \param[out] aout the ACL
1402 * \retval EINVAL Error if some of the standard args aren't set
1403 * \retval ERANGE Error if the vnode of the file id is too large
1404 * \retval -1 Error if getting the ACL failed
1406 * \post Obtain the ACL, based on file ID
1408 * \notes there is a hack to tell which type of ACL is being returned, checks the top 2-bytes to judge what type of ACL it is, only for dfs xlat or ACLs
1410 DECL_PIOCTL(PGetAcl)
1412 struct AFSOpaque acl;
1413 struct AFSVolSync tsync;
1414 struct AFSFetchStatus OutStatus;
1416 struct afs_conn *tconn;
1420 AFS_STATCNT(PGetAcl);
1423 Fid.Volume = avc->f.fid.Fid.Volume;
1424 Fid.Vnode = avc->f.fid.Fid.Vnode;
1425 Fid.Unique = avc->f.fid.Fid.Unique;
1426 if (avc->f.states & CForeign) {
1428 * For a dfs xlator acl we have a special hack so that the
1429 * xlator will distinguish which type of acl will return. So
1430 * we currently use the top 2-bytes (vals 0-4) to tell which
1431 * type of acl to bring back. Horrible hack but this will
1432 * cause the least number of changes to code size and interfaces.
1434 if (Fid.Vnode & 0xc0000000)
1436 Fid.Vnode |= (ain->remaining << 30);
1438 acl.AFSOpaque_val = aout->ptr;
1440 tconn = afs_Conn(&avc->f.fid, areq, SHARED_LOCK);
1442 acl.AFSOpaque_val[0] = '\0';
1443 XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_FETCHACL);
1445 code = RXAFS_FetchACL(tconn->id, &Fid, &acl, &OutStatus, &tsync);
1450 } while (afs_Analyze
1451 (tconn, code, &avc->f.fid, areq, AFS_STATS_FS_RPCIDX_FETCHACL,
1452 SHARED_LOCK, NULL));
1455 if (acl.AFSOpaque_len == 0)
1456 afs_pd_skip(aout, 1); /* leave the NULL */
1458 afs_pd_skip(aout, acl.AFSOpaque_len); /* Length of the ACL */
1464 * PNoop returns success. Used for functions which are not implemented or are no longer in use.
1468 * \notes Functions involved in this: 17 (VIOCENGROUP) -- used to be enable group; 18 (VIOCDISGROUP) -- used to be disable group; 2 (?) -- get/set cache-bypass size threshold
1477 * PBogus returns fail. Used for functions which are not implemented or are no longer in use.
1481 * \retval EINVAL Error if some of the standard args aren't set
1483 * \notes Functions involved in this: 0 (?); 4 (?); 6 (?); 7 (VIOCSTAT); 8 (?); 13 (VIOCGETTIME) -- used to be quick check time; 15 (VIOCPREFETCH) -- prefetch is now special-cased; see pioctl code!; 16 (VIOCNOP) -- used to be testing code; 19 (VIOCLISTGROUPS) -- used to be list group; 23 (VIOCWAITFOREVER) -- used to be waitforever; 57 (VIOC_FPRIOSTATUS) -- arla: set file prio; 58 (VIOC_FHGET) -- arla: fallback getfh; 59 (VIOC_FHOPEN) -- arla: fallback fhopen; 60 (VIOC_XFSDEBUG) -- arla: controls xfsdebug; 61 (VIOC_ARLADEBUG) -- arla: controls arla debug; 62 (VIOC_AVIATOR) -- arla: debug interface; 63 (VIOC_XFSDEBUG_PRINT) -- arla: print xfs status; 64 (VIOC_CALCULATE_CACHE) -- arla: force cache check; 65 (VIOC_BREAKCELLBACK) -- arla: break callback; 68 (?) -- arla: fetch stats;
1487 AFS_STATCNT(PBogus);
1492 * VIOC_FILE_CELL_NAME (30) - Get cell in which file lives
1496 * \param[in] ain not in use (avc used to pass in file id)
1497 * \param[out] aout cell name
1499 * \retval EINVAL Error if some of the standard args aren't set
1500 * \retval ESRCH Error if the file isn't part of a cell
1502 * \post Get a cell based on a passed in file id
1504 DECL_PIOCTL(PGetFileCell)
1506 register struct cell *tcell;
1508 AFS_STATCNT(PGetFileCell);
1511 tcell = afs_GetCell(avc->f.fid.Cell, READ_LOCK);
1515 if (afs_pd_putString(aout, tcell->cellName) != 0)
1518 afs_PutCell(tcell, READ_LOCK);
1523 * VIOC_GET_WS_CELL (31) - Get cell in which workstation lives
1527 * \param[in] ain not in use
1528 * \param[out] aout cell name
1530 * \retval EIO Error if the afs daemon hasn't started yet
1531 * \retval ESRCH Error if the machine isn't part of a cell, for whatever reason
1533 * \post Get the primary cell that the machine is a part of.
1535 DECL_PIOCTL(PGetWSCell)
1537 struct cell *tcell = NULL;
1539 AFS_STATCNT(PGetWSCell);
1540 if (!afs_resourceinit_flag) /* afs daemons haven't started yet */
1541 return EIO; /* Inappropriate ioctl for device */
1543 tcell = afs_GetPrimaryCell(READ_LOCK);
1544 if (!tcell) /* no primary cell? */
1547 if (afs_pd_putString(aout, tcell->cellName) != 0)
1549 afs_PutCell(tcell, READ_LOCK);
1554 * VIOC_GET_PRIMARY_CELL (33) - Get primary cell for caller
1558 * \param[in] ain not in use (user id found via areq)
1559 * \param[out] aout cell name
1561 * \retval ESRCH Error if the user id doesn't have a primary cell specified
1563 * \post Get the primary cell for a certain user, based on the user's uid
1565 DECL_PIOCTL(PGetUserCell)
1567 register afs_int32 i;
1568 register struct unixuser *tu;
1569 register struct cell *tcell;
1571 AFS_STATCNT(PGetUserCell);
1572 if (!afs_resourceinit_flag) /* afs daemons haven't started yet */
1573 return EIO; /* Inappropriate ioctl for device */
1575 /* return the cell name of the primary cell for this user */
1576 i = UHash(areq->uid);
1577 ObtainWriteLock(&afs_xuser, 224);
1578 for (tu = afs_users[i]; tu; tu = tu->next) {
1579 if (tu->uid == areq->uid && (tu->states & UPrimary)) {
1581 ReleaseWriteLock(&afs_xuser);
1586 tcell = afs_GetCell(tu->cell, READ_LOCK);
1587 afs_PutUser(tu, WRITE_LOCK);
1591 if (afs_pd_putString(aout, tcell->cellName) != 0)
1593 afs_PutCell(tcell, READ_LOCK);
1596 ReleaseWriteLock(&afs_xuser);
1602 * VIOCSETTOK (3) - Set authentication tokens
1606 * \param[in] ain the krb tickets from which to set the afs tokens
1607 * \param[out] aout not in use
1609 * \retval EINVAL Error if the ticket is either too long or too short
1610 * \retval EIO Error if the AFS initState is below 101
1611 * \retval ESRCH Error if the cell for which the Token is being set can't be found
1613 * \post Set the Tokens for a specific cell name, unless there is none set, then default to primary
1616 DECL_PIOCTL(PSetTokens)
1619 register struct unixuser *tu;
1620 struct ClearToken clear;
1621 register struct cell *tcell;
1625 struct vrequest treq;
1626 afs_int32 flag, set_parent_pag = 0;
1628 AFS_STATCNT(PSetTokens);
1629 if (!afs_resourceinit_flag) {
1633 if (afs_pd_getInt(ain, &stLen) != 0)
1636 stp = afs_pd_where(ain); /* remember where the ticket is */
1637 if (stLen < 0 || stLen > MAXKTCTICKETLEN)
1638 return EINVAL; /* malloc may fail */
1639 if (afs_pd_skip(ain, stLen) != 0)
1642 if (afs_pd_getInt(ain, &i) != 0)
1644 if (i != sizeof(struct ClearToken))
1647 if (afs_pd_getBytes(ain, &clear, sizeof(struct ClearToken)) !=0)
1650 if (clear.AuthHandle == -1)
1651 clear.AuthHandle = 999; /* more rxvab compat stuff */
1653 if (afs_pd_remaining(ain) != 0) {
1654 /* still stuff left? we've got primary flag and cell name. Set these */
1656 if (afs_pd_getInt(ain, &flag) != 0)
1659 /* some versions of gcc appear to need != 0 in order to get this right */
1660 if ((flag & 0x8000) != 0) { /* XXX Use Constant XXX */
1665 if (afs_pd_getStringPtr(ain, &cellName) != 0)
1668 /* rest is cell name, look it up */
1669 tcell = afs_GetCellByName(cellName, READ_LOCK);
1673 /* default to primary cell, primary id */
1674 flag = 1; /* primary id */
1675 tcell = afs_GetPrimaryCell(READ_LOCK);
1680 afs_PutCell(tcell, READ_LOCK);
1681 if (set_parent_pag) {
1683 #if defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
1684 # if defined(AFS_DARWIN_ENV)
1685 afs_proc_t *p = current_proc(); /* XXX */
1687 afs_proc_t *p = curproc; /* XXX */
1689 # ifndef AFS_DARWIN80_ENV
1690 uprintf("Process %d (%s) tried to change pags in PSetTokens\n",
1691 p->p_pid, p->p_comm);
1693 if (!setpag(p, acred, -1, &pag, 1)) {
1695 if (!setpag(acred, -1, &pag, 1)) {
1697 afs_InitReq(&treq, *acred);
1701 /* now we just set the tokens */
1702 tu = afs_GetUser(areq->uid, i, WRITE_LOCK); /* i has the cell # */
1703 tu->vid = clear.ViceId;
1704 if (tu->stp != NULL) {
1705 afs_osi_Free(tu->stp, tu->stLen);
1707 tu->stp = (char *)afs_osi_Alloc(stLen);
1708 if (tu->stp == NULL) {
1712 memcpy(tu->stp, stp, stLen);
1715 afs_stats_cmfullperf.authent.TicketUpdates++;
1716 afs_ComputePAGStats();
1717 #endif /* AFS_NOSTATS */
1718 tu->states |= UHasTokens;
1719 tu->states &= ~UTokensBad;
1720 afs_SetPrimary(tu, flag);
1721 tu->tokenTime = osi_Time();
1722 afs_ResetUserConns(tu);
1723 afs_PutUser(tu, WRITE_LOCK);
1739 * VIOCGETVOLSTAT (4) - Get volume status
1743 * \param[in] ain not in use
1744 * \param[out] aout status of the volume
1746 * \retval EINVAL Error if some of the standard args aren't set
1748 * \post The status of a volume (based on the FID of the volume), or an offline message /motd
1750 DECL_PIOCTL(PGetVolumeStatus)
1753 char *offLineMsg = afs_osi_Alloc(256);
1754 char *motd = afs_osi_Alloc(256);
1755 register struct afs_conn *tc;
1756 register afs_int32 code = 0;
1757 struct AFSFetchVolumeStatus volstat;
1761 AFS_STATCNT(PGetVolumeStatus);
1768 tc = afs_Conn(&avc->f.fid, areq, SHARED_LOCK);
1770 XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_GETVOLUMESTATUS);
1773 RXAFS_GetVolumeStatus(tc->id, avc->f.fid.Fid.Volume, &volstat,
1774 &Name, &offLineMsg, &motd);
1779 } while (afs_Analyze
1780 (tc, code, &avc->f.fid, areq, AFS_STATS_FS_RPCIDX_GETVOLUMESTATUS,
1781 SHARED_LOCK, NULL));
1785 /* Copy all this junk into msg->im_data, keeping track of the lengths. */
1786 if (afs_pd_putBytes(aout, &volstat, sizeof(VolumeStatus)) != 0)
1788 if (afs_pd_putString(aout, volName) != 0)
1790 if (afs_pd_putString(aout, offLineMsg) != 0)
1792 if (afs_pd_putString(aout, motd) != 0)
1795 afs_osi_Free(offLineMsg, 256);
1796 afs_osi_Free(motd, 256);
1801 * VIOCSETVOLSTAT (5) - Set volume status
1805 * \param[in] ain values to set the status at, offline message, message of the day, volume name, minimum quota, maximum quota
1806 * \param[out] aout status of a volume, offlines messages, minimum quota, maximumm quota
1808 * \retval EINVAL Error if some of the standard args aren't set
1809 * \retval EROFS Error if the volume is read only, or a backup volume
1810 * \retval ENODEV Error if the volume can't be accessed
1811 * \retval E2BIG Error if the volume name, offline message, and motd are too big
1813 * \post Set the status of a volume, including any offline messages, a minimum quota, and a maximum quota
1815 DECL_PIOCTL(PSetVolumeStatus)
1820 register struct afs_conn *tc;
1821 register afs_int32 code = 0;
1822 struct AFSFetchVolumeStatus volstat;
1823 struct AFSStoreVolumeStatus storeStat;
1824 register struct volume *tvp;
1827 AFS_STATCNT(PSetVolumeStatus);
1831 tvp = afs_GetVolume(&avc->f.fid, areq, READ_LOCK);
1833 if (tvp->states & (VRO | VBackup)) {
1834 afs_PutVolume(tvp, READ_LOCK);
1837 afs_PutVolume(tvp, READ_LOCK);
1842 if (afs_pd_getBytes(ain, &volstat, sizeof(AFSFetchVolumeStatus)) != 0)
1845 if (afs_pd_getStringPtr(ain, &volName) != 0)
1847 if (strlen(volName) > 32)
1850 if (afs_pd_getStringPtr(ain, &offLineMsg) != 0)
1852 if (strlen(offLineMsg) > 256)
1855 if (afs_pd_getStringPtr(ain, &motd) != 0)
1857 if (strlen(motd) > 256)
1860 /* Done reading ... */
1863 if (volstat.MinQuota != -1) {
1864 storeStat.MinQuota = volstat.MinQuota;
1865 storeStat.Mask |= AFS_SETMINQUOTA;
1867 if (volstat.MaxQuota != -1) {
1868 storeStat.MaxQuota = volstat.MaxQuota;
1869 storeStat.Mask |= AFS_SETMAXQUOTA;
1872 tc = afs_Conn(&avc->f.fid, areq, SHARED_LOCK);
1874 XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_SETVOLUMESTATUS);
1877 RXAFS_SetVolumeStatus(tc->id, avc->f.fid.Fid.Volume, &storeStat,
1878 volName, offLineMsg, motd);
1883 } while (afs_Analyze
1884 (tc, code, &avc->f.fid, areq, AFS_STATS_FS_RPCIDX_SETVOLUMESTATUS,
1885 SHARED_LOCK, NULL));
1889 /* we are sending parms back to make compat. with prev system. should
1890 * change interface later to not ask for current status, just set new status */
1892 /* XXX - We really need to check that this doesn't overflow, too, otherwise
1893 * bad fileserver status could be _really_ bad */
1894 if (afs_pd_putBytes(aout, &volstat, sizeof(VolumeStatus)) != 0)
1896 if (afs_pd_putString(aout, volName) != 0)
1898 if (afs_pd_putString(aout, offLineMsg) != 0)
1900 if (afs_pd_putString(aout, motd) != 0)
1907 * VIOCFLUSH (6) - Invalidate cache entry
1911 * \param[in] ain not in use
1912 * \param[out] aout not in use
1914 * \retval EINVAL Error if some of the standard args aren't set
1916 * \post Flush any information the cache manager has on an entry
1920 AFS_STATCNT(PFlush);
1923 #ifdef AFS_BOZONLOCK_ENV
1924 afs_BozonLock(&avc->pvnLock, avc); /* Since afs_TryToSmush will do a pvn_vptrunc */
1926 ObtainWriteLock(&avc->lock, 225);
1927 afs_ResetVCache(avc, *acred);
1928 ReleaseWriteLock(&avc->lock);
1929 #ifdef AFS_BOZONLOCK_ENV
1930 afs_BozonUnlock(&avc->pvnLock, avc);
1936 * VIOC_AFS_STAT_MT_PT (29) - Stat mount point
1940 * \param[in] ain the last component in a path, related to mountpoint that we're looking for information about
1941 * \param[out] aout volume, cell, link data
1943 * \retval EINVAL Error if some of the standard args aren't set
1944 * \retval ENOTDIR Error if the 'mount point' argument isn't a directory
1945 * \retval EIO Error if the link data can't be accessed
1947 * \post Get the volume, and cell, as well as the link data for a mount point
1949 DECL_PIOCTL(PNewStatMount)
1951 register afs_int32 code;
1952 register struct vcache *tvc;
1953 register struct dcache *tdc;
1954 struct VenusFid tfid;
1957 struct sysname_info sysState;
1958 afs_size_t offset, len;
1960 AFS_STATCNT(PNewStatMount);
1964 if (afs_pd_getStringPtr(ain, &name) != 0)
1967 code = afs_VerifyVCache(avc, areq);
1970 if (vType(avc) != VDIR) {
1973 tdc = afs_GetDCache(avc, (afs_size_t) 0, areq, &offset, &len, 1);
1976 Check_AtSys(avc, name, &sysState, areq);
1977 ObtainReadLock(&tdc->lock);
1979 code = afs_dir_Lookup(tdc, sysState.name, &tfid.Fid);
1980 } while (code == ENOENT && Next_AtSys(avc, areq, &sysState));
1981 ReleaseReadLock(&tdc->lock);
1982 afs_PutDCache(tdc); /* we're done with the data */
1983 bufp = sysState.name;
1987 tfid.Cell = avc->f.fid.Cell;
1988 tfid.Fid.Volume = avc->f.fid.Fid.Volume;
1989 if (!tfid.Fid.Unique && (avc->f.states & CForeign)) {
1990 tvc = afs_LookupVCache(&tfid, areq, NULL, avc, bufp);
1992 tvc = afs_GetVCache(&tfid, areq, NULL, NULL);
1998 if (tvc->mvstat != 1) {
2003 ObtainWriteLock(&tvc->lock, 226);
2004 code = afs_HandleLink(tvc, areq);
2006 if (tvc->linkData) {
2007 if ((tvc->linkData[0] != '#') && (tvc->linkData[0] != '%'))
2010 /* we have the data */
2011 if (afs_pd_putString(aout, tvc->linkData) != 0)
2017 ReleaseWriteLock(&tvc->lock);
2020 if (sysState.allocked)
2021 osi_FreeLargeSpace(bufp);
2026 * VIOCGETTOK (8) - Get authentication tokens
2030 * \param[in] ain userid
2031 * \param[out] aout token
2033 * \retval EIO Error if the afs daemon hasn't started yet
2034 * \retval EDOM Error if the input parameter is out of the bounds of the available tokens
2035 * \retval ENOTCONN Error if there aren't tokens for this cell
2037 * \post If the input paramater exists, get the token that corresponds to the parameter value, if there is no token at this value, get the token for the first cell
2039 * \notes "it's a weird interface (from comments in the code)"
2042 DECL_PIOCTL(PGetTokens)
2044 register struct cell *tcell;
2045 register afs_int32 i;
2046 register struct unixuser *tu;
2047 afs_int32 iterator = 0;
2051 AFS_STATCNT(PGetTokens);
2052 if (!afs_resourceinit_flag) /* afs daemons haven't started yet */
2053 return EIO; /* Inappropriate ioctl for device */
2055 /* weird interface. If input parameter is present, it is an integer and
2056 * we're supposed to return the parm'th tokens for this unix uid.
2057 * If not present, we just return tokens for cell 1.
2058 * If counter out of bounds, return EDOM.
2059 * If no tokens for the particular cell, return ENOTCONN.
2060 * Also, if this mysterious parm is present, we return, along with the
2061 * tokens, the primary cell indicator (an afs_int32 0) and the cell name
2062 * at the end, in that order.
2064 newStyle = (afs_pd_remaining(ain) > 0);
2066 if (afs_pd_getInt(ain, &iterator) != 0)
2069 i = UHash(areq->uid);
2070 ObtainReadLock(&afs_xuser);
2071 for (tu = afs_users[i]; tu; tu = tu->next) {
2073 if (tu->uid == areq->uid && (tu->states & UHasTokens)) {
2074 if (iterator-- == 0)
2075 break; /* are we done yet? */
2078 if (tu->uid == areq->uid && afs_IsPrimaryCellNum(tu->cell))
2084 * No need to hold a read lock on each user entry
2088 ReleaseReadLock(&afs_xuser);
2093 if (((tu->states & UHasTokens) == 0)
2094 || (tu->ct.EndTimestamp < osi_Time())) {
2095 tu->states |= (UTokensBad | UNeedsReset);
2096 afs_PutUser(tu, READ_LOCK);
2099 iterator = tu->stLen; /* for compat, we try to return 56 byte tix if they fit */
2101 iterator = 56; /* # of bytes we're returning */
2103 if (afs_pd_putInt(aout, iterator) != 0)
2105 if (afs_pd_putBytes(aout, tu->stp, tu->stLen) != 0)
2107 if (tu->stLen < 56) {
2108 /* Tokens are always 56 bytes or larger */
2109 if (afs_pd_skip(aout, iterator - tu->stLen) != 0) {
2114 if (afs_pd_putInt(aout, sizeof(struct ClearToken)) != 0)
2116 if (afs_pd_putBytes(aout, &tu->ct, sizeof(struct ClearToken)) != 0)
2120 /* put out primary id and cell name, too */
2121 iterator = (tu->states & UPrimary ? 1 : 0);
2122 if (afs_pd_putInt(aout, iterator) != 0)
2124 tcell = afs_GetCell(tu->cell, READ_LOCK);
2126 if (afs_pd_putString(aout, tcell->cellName) != 0)
2128 afs_PutCell(tcell, READ_LOCK);
2130 if (afs_pd_putString(aout, "") != 0)
2133 /* Got here, all is good */
2136 afs_PutUser(tu, READ_LOCK);
2141 * VIOCUNLOG (9) - Invalidate tokens
2145 * \param[in] ain not in use
2146 * \param[out] aout not in use
2148 * \retval EIO Error if the afs daemon hasn't been started yet
2150 * \post remove tokens from a user, specified by the user id
2152 * \notes sets the token's time to 0, which then causes it to be removed
2153 * \notes Unlog is the same as un-pag in OpenAFS
2157 register afs_int32 i;
2158 register struct unixuser *tu;
2160 AFS_STATCNT(PUnlog);
2161 if (!afs_resourceinit_flag) /* afs daemons haven't started yet */
2162 return EIO; /* Inappropriate ioctl for device */
2164 i = UHash(areq->uid);
2165 ObtainWriteLock(&afs_xuser, 227);
2166 for (tu = afs_users[i]; tu; tu = tu->next) {
2167 if (tu->uid == areq->uid) {
2169 tu->states &= ~UHasTokens;
2170 /* security is not having to say you're sorry */
2171 memset(&tu->ct, 0, sizeof(struct ClearToken));
2173 ReleaseWriteLock(&afs_xuser);
2174 /* We have to drop the lock over the call to afs_ResetUserConns, since
2175 * it obtains the afs_xvcache lock. We could also keep the lock, and
2176 * modify ResetUserConns to take parm saying we obtained the lock
2177 * already, but that is overkill. By keeping the "tu" pointer
2178 * held over the released lock, we guarantee that we won't lose our
2179 * place, and that we'll pass over every user conn that existed when
2180 * we began this call.
2182 afs_ResetUserConns(tu);
2184 ObtainWriteLock(&afs_xuser, 228);
2186 /* set the expire times to 0, causes
2187 * afs_GCUserData to remove this entry
2189 tu->ct.EndTimestamp = 0;
2191 #endif /* UKERNEL */
2194 ReleaseWriteLock(&afs_xuser);
2199 * VIOC_AFS_MARINER_HOST (32) - Get/set mariner (cache manager monitor) host
2203 * \param[in] ain host address to be set
2204 * \param[out] aout old host address
2206 * \post depending on whether or not a variable is set, either get the host for the cache manager monitor, or set the old address and give it a new address
2208 * \notes Errors turn off mariner
2210 DECL_PIOCTL(PMariner)
2212 afs_int32 newHostAddr;
2213 afs_int32 oldHostAddr;
2215 AFS_STATCNT(PMariner);
2217 memcpy((char *)&oldHostAddr, (char *)&afs_marinerHost,
2220 oldHostAddr = 0xffffffff; /* disabled */
2222 if (afs_pd_getInt(ain, &newHostAddr) != 0)
2225 if (newHostAddr == 0xffffffff) {
2226 /* disable mariner operations */
2228 } else if (newHostAddr) {
2230 afs_marinerHost = newHostAddr;
2233 if (afs_pd_putInt(aout, oldHostAddr) != 0)
2240 * VIOCCKSERV (10) - Check that servers are up
2244 * \param[in] ain name of the cell
2245 * \param[out] aout current down server list
2247 * \retval EIO Error if the afs daemon hasn't started yet
2248 * \retval EACCES Error if the user doesn't have super-user credentials
2249 * \retval ENOENT Error if we are unable to obtain the cell
2251 * \post Either a fast check (where it doesn't contact servers) or a local check (checks local cell only)
2253 DECL_PIOCTL(PCheckServers)
2256 register struct server *ts;
2258 char *cellName = NULL;
2260 struct chservinfo *pcheck;
2262 AFS_STATCNT(PCheckServers);
2264 if (!afs_resourceinit_flag) /* afs daemons haven't started yet */
2265 return EIO; /* Inappropriate ioctl for device */
2267 /* This is tricky, because we need to peak at the datastream to see
2268 * what we're getting. For now, let's cheat. */
2270 /* ain contains either an int32 or a string */
2271 if (ain->remaining == 0)
2274 if (*(afs_int32 *)ain->ptr == 0x12345678) { /* For afs3.3 version */
2275 pcheck = afs_pd_inline(ain, sizeof(*pcheck));
2279 if (pcheck->tinterval >= 0) {
2280 if (afs_pd_putInt(aout, afs_probe_interval) != 0)
2282 if (pcheck->tinterval > 0) {
2283 if (!afs_osi_suser(*acred))
2285 afs_probe_interval = pcheck->tinterval;
2289 temp = pcheck->tflags;
2291 cellName = pcheck->tbuffer;
2292 } else { /* For pre afs3.3 versions */
2293 if (afs_pd_getInt(ain, &temp) != 0)
2295 if (afs_pd_remaining(ain) > 0) {
2296 if (afs_pd_getStringPtr(ain, &cellName) != 0)
2302 * 1: fast check, don't contact servers.
2303 * 2: local cell only.
2306 /* have cell name, too */
2307 cellp = afs_GetCellByName(cellName, READ_LOCK);
2312 if (!cellp && (temp & 2)) {
2313 /* use local cell */
2314 cellp = afs_GetPrimaryCell(READ_LOCK);
2316 if (!(temp & 1)) { /* if not fast, call server checker routine */
2317 afs_CheckServers(1, cellp); /* check down servers */
2318 afs_CheckServers(0, cellp); /* check up servers */
2320 /* now return the current down server list */
2321 ObtainReadLock(&afs_xserver);
2322 for (i = 0; i < NSERVERS; i++) {
2323 for (ts = afs_servers[i]; ts; ts = ts->next) {
2324 if (cellp && ts->cell != cellp)
2325 continue; /* cell spec'd and wrong */
2326 if ((ts->flags & SRVR_ISDOWN)
2327 && ts->addr->sa_portal != ts->cell->vlport) {
2328 afs_pd_putInt(aout, ts->addr->sa_ip);
2332 ReleaseReadLock(&afs_xserver);
2334 afs_PutCell(cellp, READ_LOCK);
2339 * VIOCCKBACK (11) - Check backup volume mappings
2343 * \param[in] ain not in use
2344 * \param[out] aout not in use
2346 * \retval EIO Error if the afs daemon hasn't started yet
2348 * \post Check the root volume, and then check the names if the volume check variable is set to force, has expired, is busy, or if the mount points variable is set
2350 DECL_PIOCTL(PCheckVolNames)
2352 AFS_STATCNT(PCheckVolNames);
2353 if (!afs_resourceinit_flag) /* afs daemons haven't started yet */
2354 return EIO; /* Inappropriate ioctl for device */
2356 afs_CheckRootVolume();
2357 afs_CheckVolumeNames(AFS_VOLCHECK_FORCE | AFS_VOLCHECK_EXPIRED |
2358 AFS_VOLCHECK_BUSY | AFS_VOLCHECK_MTPTS);
2363 * VIOCCKCONN (12) - Check connections for a user
2367 * \param[in] ain not in use
2368 * \param[out] aout not in use
2370 * \retval EACCESS Error if no user is specififed, the user has no tokens set, or if the user's tokens are bad
2372 * \post check to see if a user has the correct authentication. If so, allow access.
2374 * \notes Check the connections to all the servers specified
2376 DECL_PIOCTL(PCheckAuth)
2380 struct afs_conn *tc;
2381 struct unixuser *tu;
2384 AFS_STATCNT(PCheckAuth);
2385 if (!afs_resourceinit_flag) /* afs daemons haven't started yet */
2386 return EIO; /* Inappropriate ioctl for device */
2389 tu = afs_GetUser(areq->uid, 1, READ_LOCK); /* check local cell authentication */
2393 /* we have a user */
2394 ObtainReadLock(&afs_xsrvAddr);
2395 ObtainReadLock(&afs_xconn);
2397 /* any tokens set? */
2398 if ((tu->states & UHasTokens) == 0)
2400 /* all connections in cell 1 working? */
2401 for (i = 0; i < NSERVERS; i++) {
2402 for (sa = afs_srvAddrs[i]; sa; sa = sa->next_bkt) {
2403 for (tc = sa->conns; tc; tc = tc->next) {
2404 if (tc->user == tu && (tu->states & UTokensBad))
2409 ReleaseReadLock(&afs_xsrvAddr);
2410 ReleaseReadLock(&afs_xconn);
2411 afs_PutUser(tu, READ_LOCK);
2413 if (afs_pd_putInt(aout, retValue) != 0)
2419 Prefetch(uparmtype apath, struct afs_ioctl *adata, int afollow,
2423 register afs_int32 code;
2424 #if defined(AFS_SGI61_ENV) || defined(AFS_SUN57_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
2430 AFS_STATCNT(Prefetch);
2433 tp = osi_AllocLargeSpace(1024);
2434 AFS_COPYINSTR(apath, tp, 1024, &bufferSize, code);
2436 osi_FreeLargeSpace(tp);
2439 if (afs_BBusy()) { /* do this as late as possible */
2440 osi_FreeLargeSpace(tp);
2441 return EWOULDBLOCK; /* pretty close */
2443 afs_BQueue(BOP_PATH, (struct vcache *)0, 0, 0, acred, (afs_size_t) 0,
2444 (afs_size_t) 0, tp);
2449 * VIOCWHEREIS (14) - Find out where a volume is located
2453 * \param[in] ain not in use
2454 * \param[out] aout volume location
2456 * \retval EINVAL Error if some of the default arguments don't exist
2457 * \retval ENODEV Error if there is no such volume
2459 * \post fine a volume, based on a volume file id
2461 * \notes check each of the servers specified
2463 DECL_PIOCTL(PFindVolume)
2465 register struct volume *tvp;
2466 register struct server *ts;
2467 register afs_int32 i;
2470 AFS_STATCNT(PFindVolume);
2473 tvp = afs_GetVolume(&avc->f.fid, areq, READ_LOCK);
2477 for (i = 0; i < AFS_MAXHOSTS; i++) {
2478 ts = tvp->serverHost[i];
2481 if (afs_pd_putInt(aout, ts->addr->sa_ip) != 0) {
2486 if (i < AFS_MAXHOSTS) {
2487 /* still room for terminating NULL, add it on */
2488 if (afs_pd_putInt(aout, 0) != 0) {
2494 afs_PutVolume(tvp, READ_LOCK);
2499 * VIOCACCESS (20) - Access using PRS_FS bits
2503 * \param[in] ain PRS_FS bits
2504 * \param[out] aout not in use
2506 * \retval EINVAL Error if some of the initial arguments aren't set
2507 * \retval EACCES Error if access is denied
2509 * \post check to make sure access is allowed
2511 DECL_PIOCTL(PViceAccess)
2513 register afs_int32 code;
2516 AFS_STATCNT(PViceAccess);
2520 code = afs_VerifyVCache(avc, areq);
2524 if (afs_pd_getInt(ain, &temp) != 0)
2527 code = afs_AccessOK(avc, temp, areq, CHECK_MODE_BITS);
2535 * VIOC_GETPAG (13) - Get PAG value
2539 * \param[in] ain not in use
2540 * \param[out] aout PAG value or NOPAG
2542 * \post get PAG value for the caller's cred
2544 DECL_PIOCTL(PGetPAG)
2548 pag = PagInCred(*acred);
2550 return afs_pd_putInt(aout, pag);
2553 DECL_PIOCTL(PPrecache)
2557 /*AFS_STATCNT(PPrecache);*/
2558 if (!afs_osi_suser(*acred))
2561 if (afs_pd_getInt(ain, &newValue) != 0)
2564 afs_preCache = newValue*1024;
2569 * VIOCSETCACHESIZE (24) - Set venus cache size in 1000 units
2573 * \param[in] ain the size the venus cache should be set to
2574 * \param[out] aout not in use
2576 * \retval EACCES Error if the user doesn't have super-user credentials
2577 * \retval EROFS Error if the cache is set to be in memory
2579 * \post Set the cache size based on user input. If no size is given, set it to the default OpenAFS cache size.
2581 * \notes recompute the general cache parameters for every single block allocated
2583 DECL_PIOCTL(PSetCacheSize)
2588 AFS_STATCNT(PSetCacheSize);
2590 if (!afs_osi_suser(*acred))
2592 /* too many things are setup initially in mem cache version */
2593 if (cacheDiskType == AFS_FCACHE_TYPE_MEM)
2595 if (afs_pd_getInt(ain, &newValue) != 0)
2598 afs_cacheBlocks = afs_stats_cmperf.cacheBlocksOrig;
2600 if (newValue < afs_min_cache)
2601 afs_cacheBlocks = afs_min_cache;
2603 afs_cacheBlocks = newValue;
2605 afs_stats_cmperf.cacheBlocksTotal = afs_cacheBlocks;
2606 afs_ComputeCacheParms(); /* recompute basic cache parameters */
2607 afs_MaybeWakeupTruncateDaemon();
2608 while (waitcnt++ < 100 && afs_cacheBlocks < afs_blocksUsed) {
2609 afs_osi_Wait(1000, 0, 0);
2610 afs_MaybeWakeupTruncateDaemon();
2615 #define MAXGCSTATS 16
2617 * VIOCGETCACHEPARMS (40) - Get cache stats
2621 * \param[in] ain afs index flags
2622 * \param[out] aout cache blocks, blocks used, blocks files (in an array)
2624 * \post Get the cache blocks, and how many of the cache blocks there are
2626 DECL_PIOCTL(PGetCacheSize)
2628 afs_int32 results[MAXGCSTATS];
2630 register struct dcache * tdc;
2633 AFS_STATCNT(PGetCacheSize);
2635 if (afs_pd_remaining(ain) == sizeof(afs_int32)) {
2636 afs_pd_getInt(ain, &flags); /* can't error, we just checked size */
2637 } else if (afs_pd_remaining(ain) == 0) {
2643 memset(results, 0, sizeof(results));
2644 results[0] = afs_cacheBlocks;
2645 results[1] = afs_blocksUsed;
2646 results[2] = afs_cacheFiles;
2649 for (i = 0; i < afs_cacheFiles; i++) {
2650 if (afs_indexFlags[i] & IFFree) results[3]++;
2652 } else if (2 == flags){
2653 for (i = 0; i < afs_cacheFiles; i++) {
2654 if (afs_indexFlags[i] & IFFree) results[3]++;
2655 if (afs_indexFlags[i] & IFEverUsed) results[4]++;
2656 if (afs_indexFlags[i] & IFDataMod) results[5]++;
2657 if (afs_indexFlags[i] & IFDirtyPages) results[6]++;
2658 if (afs_indexFlags[i] & IFAnyPages) results[7]++;
2659 if (afs_indexFlags[i] & IFDiscarded) results[8]++;
2661 tdc = afs_indexTable[i];
2664 size = tdc->validPos;
2665 if ( 0 < size && size < (1<<12) ) results[10]++;
2666 else if (size < (1<<14) ) results[11]++;
2667 else if (size < (1<<16) ) results[12]++;
2668 else if (size < (1<<18) ) results[13]++;
2669 else if (size < (1<<20) ) results[14]++;
2670 else if (size >= (1<<20) ) results[15]++;
2674 return afs_pd_putBytes(aout, results, sizeof(results));
2678 * VIOCFLUSHCB (25) - Flush callback only
2682 * \param[in] ain not in use
2683 * \param[out] aout not in use
2685 * \retval EINVAL Error if some of the standard args aren't set
2686 * \retval 0 0 returned if the volume is set to read-only
2688 * \post Flushes callbacks, by setting the length of callbacks to one, setting the next callback to be sent to the CB_DROPPED value, and then dequeues everything else.
2690 DECL_PIOCTL(PRemoveCallBack)
2692 register struct afs_conn *tc;
2693 register afs_int32 code = 0;
2694 struct AFSCallBack CallBacks_Array[1];
2695 struct AFSCBFids theFids;
2696 struct AFSCBs theCBs;
2699 AFS_STATCNT(PRemoveCallBack);
2702 if (avc->f.states & CRO)
2703 return 0; /* read-only-ness can't change */
2704 ObtainWriteLock(&avc->lock, 229);
2705 theFids.AFSCBFids_len = 1;
2706 theCBs.AFSCBs_len = 1;
2707 theFids.AFSCBFids_val = (struct AFSFid *)&avc->f.fid.Fid;
2708 theCBs.AFSCBs_val = CallBacks_Array;
2709 CallBacks_Array[0].CallBackType = CB_DROPPED;
2710 if (avc->callback) {
2712 tc = afs_Conn(&avc->f.fid, areq, SHARED_LOCK);
2714 XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_GIVEUPCALLBACKS);
2716 code = RXAFS_GiveUpCallBacks(tc->id, &theFids, &theCBs);
2720 /* don't set code on failure since we wouldn't use it */
2721 } while (afs_Analyze
2722 (tc, code, &avc->f.fid, areq,
2723 AFS_STATS_FS_RPCIDX_GIVEUPCALLBACKS, SHARED_LOCK, NULL));
2725 ObtainWriteLock(&afs_xcbhash, 457);
2726 afs_DequeueCallback(avc);
2728 avc->f.states &= ~(CStatd | CUnique);
2729 ReleaseWriteLock(&afs_xcbhash);
2730 if (avc->f.fid.Fid.Vnode & 1 || (vType(avc) == VDIR))
2731 osi_dnlc_purgedp(avc);
2733 ReleaseWriteLock(&avc->lock);
2738 * VIOCNEWCELL (26) - Configure new cell
2742 * \param[in] ain the name of the cell, the hosts that will be a part of the cell, whether or not it's linked with another cell, the other cell it's linked with, the file server port, and the volume server port
2743 * \param[out] aout not in use
2745 * \retval EIO Error if the afs daemon hasn't started yet
2746 * \retval EACCES Error if the user doesn't have super-user cedentials
2747 * \retval EINVAL Error if some 'magic' var doesn't have a certain bit set
2749 * \post creates a new cell
2751 DECL_PIOCTL(PNewCell)
2753 afs_int32 cellHosts[AFS_MAXCELLHOSTS], magic = 0;
2754 char *newcell = NULL;
2755 char *linkedcell = NULL;
2757 afs_int32 linkedstate = 0;
2758 afs_int32 fsport = 0, vlport = 0;
2761 AFS_STATCNT(PNewCell);
2762 if (!afs_resourceinit_flag) /* afs daemons haven't started yet */
2763 return EIO; /* Inappropriate ioctl for device */
2765 if (!afs_osi_suser(*acred))
2768 if (afs_pd_getInt(ain, &magic) != 0)
2770 if (magic != 0x12345678)
2773 /* A 3.4 fs newcell command will pass an array of AFS_MAXCELLHOSTS
2774 * server addresses while the 3.5 fs newcell command passes
2775 * AFS_MAXHOSTS. To figure out which is which, check if the cellname
2778 * This whole logic is bogus, because it relies on the newer command
2779 * sending its 12th address as 0.
2781 if ((afs_pd_remaining(ain) < AFS_MAXCELLHOSTS +3) * sizeof(afs_int32))
2784 newcell = afs_pd_where(ain) + (AFS_MAXCELLHOSTS + 3) * sizeof(afs_int32);
2785 if (newcell[0] != '\0') {
2788 skip = AFS_MAXHOSTS - AFS_MAXCELLHOSTS;
2791 /* AFS_MAXCELLHOSTS (=8) is less than AFS_MAXHOSTS (=13) */
2792 if (afs_pd_getBytes(ain, &cellHosts,
2793 AFS_MAXCELLHOSTS * sizeof(afs_int32)) != 0)
2795 if (afs_pd_skip(ain, skip * sizeof(afs_int32)) !=0)
2798 if (afs_pd_getInt(ain, &fsport) != 0)
2801 fsport = 0; /* Privileged ports not allowed */
2803 if (afs_pd_getInt(ain, &vlport) != 0)
2806 vlport = 0; /* Privileged ports not allowed */
2808 if (afs_pd_getInt(ain, &ls) != 0)
2811 if (afs_pd_getStringPtr(ain, &newcell) != 0)
2815 if (afs_pd_getStringPtr(ain, &linkedcell) != 0)
2817 linkedstate |= CLinkedCell;
2820 linkedstate |= CNoSUID; /* setuid is disabled by default for fs newcell */
2822 afs_NewCell(newcell, cellHosts, linkedstate, linkedcell, fsport,
2827 DECL_PIOCTL(PNewAlias)
2829 /* create a new cell alias */
2830 char *realName, *aliasName;
2832 if (!afs_resourceinit_flag) /* afs daemons haven't started yet */
2833 return EIO; /* Inappropriate ioctl for device */
2835 if (!afs_osi_suser(*acred))
2838 if (afs_pd_getStringPtr(ain, &aliasName) != 0)
2840 if (afs_pd_getStringPtr(ain, &realName) != 0)
2843 return afs_NewCellAlias(aliasName, realName);
2847 * VIOCGETCELL (27) - Get cell info
2851 * \param[in] ain The cell index of a specific cell
2852 * \param[out] aout list of servers in the cell
2854 * \retval EIO Error if the afs daemon hasn't started yet
2855 * \retval EDOM Error if there is no cell asked about
2857 * \post Lists the cell's server names and and addresses
2859 DECL_PIOCTL(PListCells)
2861 afs_int32 whichCell;
2862 register struct cell *tcell = 0;
2863 register afs_int32 i;
2866 AFS_STATCNT(PListCells);
2867 if (!afs_resourceinit_flag) /* afs daemons haven't started yet */
2868 return EIO; /* Inappropriate ioctl for device */
2870 if (afs_pd_getInt(ain, &whichCell) != 0)
2873 tcell = afs_GetCellByIndex(whichCell, READ_LOCK);
2879 for (i = 0; i < AFS_MAXCELLHOSTS; i++) {
2880 if (tcell->cellHosts[i] == 0)
2882 if (afs_pd_putInt(aout, tcell->cellHosts[i]->addr->sa_ip) != 0)
2885 for (;i < AFS_MAXCELLHOSTS; i++) {
2886 if (afs_pd_putInt(aout, 0) != 0)
2889 if (afs_pd_putString(aout, tcell->cellName) != 0)
2894 afs_PutCell(tcell, READ_LOCK);
2898 DECL_PIOCTL(PListAliases)
2900 afs_int32 whichAlias;
2901 register struct cell_alias *tcalias = 0;
2904 if (!afs_resourceinit_flag) /* afs daemons haven't started yet */
2905 return EIO; /* Inappropriate ioctl for device */
2907 if (afs_pd_getInt(ain, &whichAlias) != 0)
2910 tcalias = afs_GetCellAlias(whichAlias);
2911 if (tcalias == NULL)
2915 if (afs_pd_putString(aout, tcalias->alias) != 0)
2917 if (afs_pd_putString(aout, tcalias->cell) != 0)
2922 afs_PutCellAlias(tcalias);
2927 * VIOC_AFS_DELETE_MT_PT (28) - Delete mount point
2931 * \param[in] ain the name of the file in this dir to remove
2932 * \param[out] aout not in use
2934 * \retval EINVAL Error if some of the standard args aren't set
2935 * \retval ENOTDIR Error if the argument to remove is not a directory
2936 * \retval ENOENT Error if there is no cache to remove the mount point from or if a vcache doesn't exist
2938 * \post Ensure that everything is OK before deleting the mountpoint. If not, don't delete. Delete a mount point based on a file id.
2940 DECL_PIOCTL(PRemoveMount)
2942 register afs_int32 code;
2945 struct sysname_info sysState;
2946 afs_size_t offset, len;
2947 register struct afs_conn *tc;
2948 register struct dcache *tdc;
2949 register struct vcache *tvc;
2950 struct AFSFetchStatus OutDirStatus;
2951 struct VenusFid tfid;
2952 struct AFSVolSync tsync;
2955 /* "ain" is the name of the file in this dir to remove */
2957 AFS_STATCNT(PRemoveMount);
2960 if (afs_pd_getStringPtr(ain, &name) != 0)
2963 code = afs_VerifyVCache(avc, areq);
2966 if (vType(avc) != VDIR)
2969 tdc = afs_GetDCache(avc, (afs_size_t) 0, areq, &offset, &len, 1); /* test for error below */
2972 Check_AtSys(avc, name, &sysState, areq);
2973 ObtainReadLock(&tdc->lock);
2975 code = afs_dir_Lookup(tdc, sysState.name, &tfid.Fid);
2976 } while (code == ENOENT && Next_AtSys(avc, areq, &sysState));
2977 ReleaseReadLock(&tdc->lock);
2978 bufp = sysState.name;
2983 tfid.Cell = avc->f.fid.Cell;
2984 tfid.Fid.Volume = avc->f.fid.Fid.Volume;
2985 if (!tfid.Fid.Unique && (avc->f.states & CForeign)) {
2986 tvc = afs_LookupVCache(&tfid, areq, NULL, avc, bufp);
2988 tvc = afs_GetVCache(&tfid, areq, NULL, NULL);
2995 if (tvc->mvstat != 1) {
3001 ObtainWriteLock(&tvc->lock, 230);
3002 code = afs_HandleLink(tvc, areq);
3004 if (tvc->linkData) {
3005 if ((tvc->linkData[0] != '#') && (tvc->linkData[0] != '%'))
3010 ReleaseWriteLock(&tvc->lock);
3011 osi_dnlc_purgedp(tvc);
3017 ObtainWriteLock(&avc->lock, 231);
3018 osi_dnlc_remove(avc, bufp, tvc);
3020 tc = afs_Conn(&avc->f.fid, areq, SHARED_LOCK);
3022 XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_REMOVEFILE);
3025 RXAFS_RemoveFile(tc->id, (struct AFSFid *)&avc->f.fid.Fid, bufp,
3026 &OutDirStatus, &tsync);
3031 } while (afs_Analyze
3032 (tc, code, &avc->f.fid, areq, AFS_STATS_FS_RPCIDX_REMOVEFILE,
3033 SHARED_LOCK, NULL));
3038 ReleaseWriteLock(&avc->lock);
3042 /* we have the thing in the cache */
3043 ObtainWriteLock(&tdc->lock, 661);
3044 if (afs_LocalHero(avc, tdc, &OutDirStatus, 1)) {
3045 /* we can do it locally */
3046 code = afs_dir_Delete(tdc, bufp);
3048 ZapDCE(tdc); /* surprise error -- invalid value */
3052 ReleaseWriteLock(&tdc->lock);
3053 afs_PutDCache(tdc); /* drop ref count */
3055 avc->f.states &= ~CUnique; /* For the dfs xlator */
3056 ReleaseWriteLock(&avc->lock);
3059 if (sysState.allocked)
3060 osi_FreeLargeSpace(bufp);
3065 * VIOC_VENUSLOG (34) - Enable/Disable venus logging
3069 * \retval EINVAL Error if some of the standard args aren't set
3071 * \notes Obsoleted, perhaps should be PBogus
3073 DECL_PIOCTL(PVenusLogging)
3075 return EINVAL; /* OBSOLETE */
3079 * VIOC_GETCELLSTATUS (35) - Get cell status info
3083 * \param[in] ain The cell you want status information on
3084 * \param[out] aout cell state (as a struct)
3086 * \retval EIO Error if the afs daemon hasn't started yet
3087 * \retval ENOENT Error if the cell doesn't exist
3089 * \post Returns the state of the cell as defined in a struct cell
3091 DECL_PIOCTL(PGetCellStatus)
3093 register struct cell *tcell;
3097 AFS_STATCNT(PGetCellStatus);
3098 if (!afs_resourceinit_flag) /* afs daemons haven't started yet */
3099 return EIO; /* Inappropriate ioctl for device */
3101 if (afs_pd_getStringPtr(ain, &cellName) != 0)
3104 tcell = afs_GetCellByName(cellName, READ_LOCK);
3107 temp = tcell->states;
3108 afs_PutCell(tcell, READ_LOCK);
3110 return afs_pd_putInt(aout, temp);
3114 * VIOC_SETCELLSTATUS (36) - Set corresponding info
3118 * \param[in] ain The cell you want to set information about, and the values you want to set
3119 * \param[out] aout not in use
3121 * \retval EIO Error if the afs daemon hasn't started yet
3122 * \retval EACCES Error if the user doesn't have super-user credentials
3124 * \post Set the state of the cell in a defined struct cell, based on whether or not SetUID is allowed
3126 DECL_PIOCTL(PSetCellStatus)
3128 register struct cell *tcell;
3130 afs_int32 flags0, flags1;
3132 if (!afs_osi_suser(*acred))
3134 if (!afs_resourceinit_flag) /* afs daemons haven't started yet */
3135 return EIO; /* Inappropriate ioctl for device */
3137 if (afs_pd_getInt(ain, &flags0) != 0)
3139 if (afs_pd_getInt(ain, &flags1) != 0)
3141 if (afs_pd_getStringPtr(ain, &cellName) != 0)
3144 tcell = afs_GetCellByName(cellName, WRITE_LOCK);
3147 if (flags0 & CNoSUID)
3148 tcell->states |= CNoSUID;
3150 tcell->states &= ~CNoSUID;
3151 afs_PutCell(tcell, WRITE_LOCK);
3156 * VIOC_FLUSHVOLUME (37) - Flush whole volume's data
3160 * \param[in] ain not in use (args in avc)
3161 * \param[out] aout not in use
3163 * \retval EINVAL Error if some of the standard args aren't set
3164 * \retval EIO Error if the afs daemon hasn't started yet
3166 * \post Wipe everything on the volume. This is done dependent on which platform this is for.
3168 * \notes Does not flush a file that a user has open and is using, because it will be re-created on next write. Also purges the dnlc, because things are screwed up.
3170 DECL_PIOCTL(PFlushVolumeData)
3172 register afs_int32 i;
3173 register struct dcache *tdc;
3174 register struct vcache *tvc;
3175 register struct volume *tv;
3176 afs_int32 cell, volume;
3177 struct afs_q *tq, *uq;
3178 #ifdef AFS_DARWIN80_ENV
3182 AFS_STATCNT(PFlushVolumeData);
3185 if (!afs_resourceinit_flag) /* afs daemons haven't started yet */
3186 return EIO; /* Inappropriate ioctl for device */
3188 volume = avc->f.fid.Fid.Volume; /* who to zap */
3189 cell = avc->f.fid.Cell;
3192 * Clear stat'd flag from all vnodes from this volume; this will invalidate all
3193 * the vcaches associated with the volume.
3196 ObtainReadLock(&afs_xvcache);
3197 i = VCHashV(&avc->f.fid);
3198 for (tq = afs_vhashTV[i].prev; tq != &afs_vhashTV[i]; tq = uq) {
3201 if (tvc->f.fid.Fid.Volume == volume && tvc->f.fid.Cell == cell) {
3202 if (tvc->f.states & CVInit) {
3203 ReleaseReadLock(&afs_xvcache);
3204 afs_osi_Sleep(&tvc->f.states);
3207 #ifdef AFS_DARWIN80_ENV
3208 if (tvc->f.states & CDeadVnode) {
3209 ReleaseReadLock(&afs_xvcache);
3210 afs_osi_Sleep(&tvc->f.states);
3214 #if defined(AFS_SGI_ENV) || defined(AFS_SUN5_ENV) || defined(AFS_HPUX_ENV) || defined(AFS_LINUX20_ENV)
3215 VN_HOLD(AFSTOV(tvc));
3216 #elif defined(AFS_DARWIN80_ENV)
3220 if (vnode_ref(vp)) {
3226 #elif defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
3229 VREFCOUNT_INC(tvc); /* AIX, apparently */
3231 ReleaseReadLock(&afs_xvcache);
3232 #ifdef AFS_BOZONLOCK_ENV
3233 afs_BozonLock(&tvc->pvnLock, tvc); /* Since afs_TryToSmush will do a pvn_vptrunc */
3235 ObtainWriteLock(&tvc->lock, 232);
3237 ObtainWriteLock(&afs_xcbhash, 458);
3238 afs_DequeueCallback(tvc);
3239 tvc->f.states &= ~(CStatd | CDirty);
3240 ReleaseWriteLock(&afs_xcbhash);
3241 if (tvc->f.fid.Fid.Vnode & 1 || (vType(tvc) == VDIR))
3242 osi_dnlc_purgedp(tvc);
3243 afs_TryToSmush(tvc, *acred, 1);
3244 ReleaseWriteLock(&tvc->lock);
3245 #ifdef AFS_BOZONLOCK_ENV
3246 afs_BozonUnlock(&tvc->pvnLock, tvc);
3248 #ifdef AFS_DARWIN80_ENV
3249 vnode_put(AFSTOV(tvc));
3251 ObtainReadLock(&afs_xvcache);
3253 /* our tvc ptr is still good until now */
3257 ReleaseReadLock(&afs_xvcache);
3260 ObtainWriteLock(&afs_xdcache, 328); /* needed if you're going to flush any stuff */
3261 for (i = 0; i < afs_cacheFiles; i++) {
3262 if (!(afs_indexFlags[i] & IFEverUsed))
3263 continue; /* never had any data */
3264 tdc = afs_GetDSlot(i, NULL);
3265 if (tdc->refCount <= 1) { /* too high, in use by running sys call */
3266 ReleaseReadLock(&tdc->tlock);
3267 if (tdc->f.fid.Fid.Volume == volume && tdc->f.fid.Cell == cell) {
3268 if (!(afs_indexFlags[i] & IFDataMod)) {
3269 /* if the file is modified, but has a ref cnt of only 1, then
3270 * someone probably has the file open and is writing into it.
3271 * Better to skip flushing such a file, it will be brought back
3272 * immediately on the next write anyway.
3274 * If we *must* flush, then this code has to be rearranged to call
3275 * afs_storeAllSegments() first */
3276 afs_FlushDCache(tdc);
3280 ReleaseReadLock(&tdc->tlock);
3282 afs_PutDCache(tdc); /* bumped by getdslot */
3284 ReleaseWriteLock(&afs_xdcache);
3286 ObtainReadLock(&afs_xvolume);
3287 for (i = 0; i < NVOLS; i++) {
3288 for (tv = afs_volumes[i]; tv; tv = tv->next) {
3289 if (tv->volume == volume) {
3290 afs_ResetVolumeInfo(tv);
3295 ReleaseReadLock(&afs_xvolume);
3297 /* probably, a user is doing this, probably, because things are screwed up.
3298 * maybe it's the dnlc's fault? */
3305 * VIOCGETVCXSTATUS (41) - gets vnode x status
3309 * \param[in] ain not in use (avc used)
3310 * \param[out] aout vcxstat: the file id, the data version, any lock, the parent vnode, the parent unique id, the trunc position, the callback, cbExpires, what access is being made, what files are open, any users executing/writing, the flock ount, the states, the move stat
3312 * \retval EINVAL Error if some of the initial default arguments aren't set
3313 * \retval EACCES Error if access to check the mode bits is denied
3315 * \post gets stats for the vnode, a struct listed in vcxstat
3317 DECL_PIOCTL(PGetVnodeXStatus)
3319 register afs_int32 code;
3320 struct vcxstat stat;
3323 /* AFS_STATCNT(PGetVnodeXStatus); */
3326 code = afs_VerifyVCache(avc, areq);
3329 if (vType(avc) == VDIR)
3330 mode = PRSFS_LOOKUP;
3333 if (!afs_AccessOK(avc, mode, areq, CHECK_MODE_BITS))
3336 memset(&stat, 0, sizeof(struct vcxstat));
3337 stat.fid = avc->f.fid;
3338 hset32(stat.DataVersion, hgetlo(avc->f.m.DataVersion));
3339 stat.lock = avc->lock;
3340 stat.parentVnode = avc->f.parent.vnode;
3341 stat.parentUnique = avc->f.parent.unique;
3342 hset(stat.flushDV, avc->flushDV);
3343 hset(stat.mapDV, avc->mapDV);
3344 stat.truncPos = avc->f.truncPos;
3345 { /* just grab the first two - won't break anything... */
3346 struct axscache *ac;
3348 for (i = 0, ac = avc->Access; ac && i < CPSIZE; i++, ac = ac->next) {
3349 stat.randomUid[i] = ac->uid;
3350 stat.randomAccess[i] = ac->axess;
3353 stat.callback = afs_data_pointer_to_int32(avc->callback);
3354 stat.cbExpires = avc->cbExpires;
3355 stat.anyAccess = avc->f.anyAccess;
3356 stat.opens = avc->opens;
3357 stat.execsOrWriters = avc->execsOrWriters;
3358 stat.flockCount = avc->flockCount;
3359 stat.mvstat = avc->mvstat;
3360 stat.states = avc->f.states;
3361 return afs_pd_putBytes(aout, &stat, sizeof(struct vcxstat));
3365 DECL_PIOCTL(PGetVnodeXStatus2)
3367 register afs_int32 code;
3368 struct vcxstat2 stat;
3373 code = afs_VerifyVCache(avc, areq);
3376 if (vType(avc) == VDIR)
3377 mode = PRSFS_LOOKUP;
3380 if (!afs_AccessOK(avc, mode, areq, CHECK_MODE_BITS))
3383 memset(&stat, 0, sizeof(struct vcxstat2));
3385 stat.cbExpires = avc->cbExpires;
3386 stat.anyAccess = avc->f.anyAccess;
3387 stat.mvstat = avc->mvstat;
3388 stat.callerAccess = afs_GetAccessBits(avc, ~0, areq);
3390 return afs_pd_putBytes(aout, &stat, sizeof(struct vcxstat2));
3395 * VIOC_AFS_SYSNAME (38) - Change @sys value
3399 * \param[in] ain new value for @sys
3400 * \param[out] aout count, entry, list (debug values?)
3402 * \retval EINVAL Error if afsd isn't running, the new sysname is too large, the new sysname causes issues (starts with a .0 or ..0), there is no PAG set in the credentials, the user of a PAG can't be found, (!(exporter = au->exporter)) "NOT SURE ON THIS"
3403 * \retval ENODEV Error if there isn't already a system named that ("I THINK")
3404 * \retval EACCES Error if the user doesn't have super-user credentials
3406 * \post Set the value of @sys if these things work: if the input isn't too long or if input doesn't start with .0 or ..0
3408 * \notes We require root for local sysname changes, but not for remote (since we don't really believe remote uids anyway) outname[] shouldn't really be needed- this is left as an exercise for the reader.
3410 DECL_PIOCTL(PSetSysName)
3412 char *inname = NULL;
3413 char outname[MAXSYSNAME];
3414 afs_int32 setsysname;
3416 register struct afs_exporter *exporter;
3417 register struct unixuser *au;
3418 register afs_int32 pag, error;
3419 int t, count, num = 0, allpags = 0;
3421 struct afs_pdata validate;
3423 AFS_STATCNT(PSetSysName);
3424 if (!afs_globalVFS) {
3425 /* Afsd is NOT running; disable it */
3426 #if defined(KERNEL_HAVE_UERROR)
3427 return (setuerror(EINVAL), EINVAL);
3432 if (afs_pd_getInt(ain, &setsysname) != 0)
3434 if (setsysname & 0x8000) {
3436 setsysname &= ~0x8000;
3441 if (setsysname < 0 || setsysname > MAXNUMSYSNAMES)
3444 for (count = 0; count < setsysname; count++) {
3445 if (afs_pd_getStringPtr(&validate, &inname) != 0)
3448 if (t >= MAXSYSNAME || t <= 0)
3450 /* check for names that can shoot us in the foot */
3451 if (inname[0] == '.' && (inname[1] == 0
3452 || (inname[1] == '.' && inname[2] == 0)))
3455 /* args ok, so go back to the beginning of that section */
3457 if (afs_pd_getStringPtr(ain, &inname) != 0)
3461 if (afs_cr_gid(*acred) == RMTUSER_REQ ||
3462 afs_cr_gid(*acred) == RMTUSER_REQ_PRIV) { /* Handles all exporters */
3463 if (allpags && afs_cr_gid(*acred) != RMTUSER_REQ_PRIV) {
3466 pag = PagInCred(*acred);
3468 return EINVAL; /* Better than panicing */
3470 if (!(au = afs_FindUser(pag, -1, READ_LOCK))) {
3471 return EINVAL; /* Better than panicing */
3473 if (!(exporter = au->exporter)) {
3474 afs_PutUser(au, READ_LOCK);
3475 return EINVAL; /* Better than panicing */
3477 error = EXP_SYSNAME(exporter, inname, &sysnamelist,
3480 if (error == ENODEV)
3481 foundname = 0; /* sysname not set yet! */
3483 afs_PutUser(au, READ_LOCK);
3488 strcpy(outname, sysnamelist[0]);
3490 afs_PutUser(au, READ_LOCK);
3494 /* Not xlating, so local case */
3496 osi_Panic("PSetSysName: !afs_sysname\n");
3497 if (!setsysname) { /* user just wants the info */
3498 strcpy(outname, afs_sysname);
3499 foundname = afs_sysnamecount;
3500 sysnamelist = afs_sysnamelist;
3501 } else { /* Local guy; only root can change sysname */
3502 if (!afs_osi_suser(*acred))
3505 /* allpags makes no sense for local use */
3509 /* clear @sys entries from the dnlc, once afs_lookup can
3510 * do lookups of @sys entries and thinks it can trust them */
3511 /* privs ok, store the entry, ... */
3513 if (strlen(inname) >= MAXSYSNAME-1)
3515 strcpy(afs_sysname, inname);
3517 if (setsysname > 1) { /* ... or list */
3518 for (count = 1; count < setsysname; ++count) {
3519 if (!afs_sysnamelist[count])
3521 ("PSetSysName: no afs_sysnamelist entry to write\n");
3522 if (afs_pd_getString(ain, afs_sysnamelist[count],
3527 afs_sysnamecount = setsysname;
3532 if (afs_pd_putInt(aout, foundname) != 0)
3535 if (afs_pd_putString(aout, outname) != 0)
3537 for (count = 1; count < foundname; ++count) { /* ... or list. */
3538 if (!sysnamelist[count])
3540 ("PSetSysName: no afs_sysnamelist entry to read\n");
3541 t = strlen(sysnamelist[count]);
3542 if (t >= MAXSYSNAME)
3543 osi_Panic("PSetSysName: sysname entry garbled\n");
3544 if (afs_pd_putString(aout, sysnamelist[count]) != 0)
3552 /* sequential search through the list of touched cells is not a good
3553 * long-term solution here. For small n, though, it should be just
3554 * fine. Should consider special-casing the local cell for large n.
3555 * Likewise for PSetSPrefs.
3557 * s - number of ids in array l[] -- NOT index of last id
3558 * l - array of cell ids which have volumes that need to be sorted
3559 * vlonly - sort vl servers or file servers?
3562 ReSortCells_cb(struct cell *cell, void *arg)
3564 afs_int32 *p = (afs_int32 *) arg;
3565 afs_int32 *l = p + 1;
3568 for (i = 0; i < s; i++) {
3569 if (l[i] == cell->cellNum) {
3570 ObtainWriteLock(&cell->lock, 690);
3571 afs_SortServers(cell->cellHosts, AFS_MAXCELLHOSTS);
3572 ReleaseWriteLock(&cell->lock);
3580 ReSortCells(int s, afs_int32 * l, int vlonly)
3588 p = (afs_int32 *) afs_osi_Alloc(sizeof(afs_int32) * (s + 1));
3590 memcpy(p + 1, l, s * sizeof(afs_int32));
3591 afs_TraverseCells(&ReSortCells_cb, p);
3592 afs_osi_Free(p, sizeof(afs_int32) * (s + 1));
3596 ObtainReadLock(&afs_xvolume);
3597 for (i = 0; i < NVOLS; i++) {
3598 for (j = afs_volumes[i]; j; j = j->next) {
3599 for (k = 0; k < s; k++)
3600 if (j->cell == l[k]) {
3601 ObtainWriteLock(&j->lock, 233);
3602 afs_SortServers(j->serverHost, AFS_MAXHOSTS);
3603 ReleaseWriteLock(&j->lock);
3608 ReleaseReadLock(&afs_xvolume);
3612 static int debugsetsp = 0;
3614 afs_setsprefs(struct spref *sp, unsigned int num, unsigned int vlonly)
3617 int i, j, k, matches, touchedSize;
3618 struct server *srvr = NULL;
3619 afs_int32 touched[34];
3623 for (k = 0; k < num; sp++, k++) {
3625 printf("sp host=%x, rank=%d\n", sp->host.s_addr, sp->rank);
3628 ObtainReadLock(&afs_xserver);
3630 i = SHash(sp->host.s_addr);
3631 for (sa = afs_srvAddrs[i]; sa; sa = sa->next_bkt) {
3632 if (sa->sa_ip == sp->host.s_addr) {
3634 isfs = (srvr->cell && (sa->sa_portal == srvr->cell->fsport))
3635 || (sa->sa_portal == AFS_FSPORT);
3636 if ((!vlonly && isfs) || (vlonly && !isfs)) {
3643 if (sa && matches) { /* found one! */
3645 printf("sa ip=%x, ip_rank=%d\n", sa->sa_ip, sa->sa_iprank);
3647 sa->sa_iprank = sp->rank + afs_randomMod15();
3648 afs_SortOneServer(sa->server);
3651 /* if we don't know yet what cell it's in, this is moot */
3652 for (j = touchedSize - 1;
3653 j >= 0 && touched[j] != srvr->cell->cellNum; j--)
3654 /* is it in our list of touched cells ? */ ;
3655 if (j < 0) { /* no, it's not */
3656 touched[touchedSize++] = srvr->cell->cellNum;
3657 if (touchedSize >= 32) { /* watch for ovrflow */
3658 ReleaseReadLock(&afs_xserver);
3659 ReSortCells(touchedSize, touched, vlonly);
3661 ObtainReadLock(&afs_xserver);
3667 ReleaseReadLock(&afs_xserver);
3668 /* if we didn't find one, start to create one. */
3669 /* Note that it doesn't have a cell yet... */
3671 afs_uint32 temp = sp->host.s_addr;
3673 afs_GetServer(&temp, 1, 0, (vlonly ? AFS_VLPORT : AFS_FSPORT),
3674 WRITE_LOCK, (afsUUID *) 0, 0);
3675 srvr->addr->sa_iprank = sp->rank + afs_randomMod15();
3676 afs_PutServer(srvr, WRITE_LOCK);
3678 } /* for all cited preferences */
3680 ReSortCells(touchedSize, touched, vlonly);
3685 * VIOC_SETPREFS (46) - Set server ranks
3687 * \param[in] ain the sprefs value you want the sprefs to be set to
3688 * \param[out] aout not in use
3690 * \retval EIO Error if the afs daemon hasn't started yet
3691 * \retval EACCES Error if the user doesn't have super-user credentials
3692 * \retval EINVAL Error if the struct setsprefs is too large or if it multiplied by the number of servers is too large
3694 * \post set the sprefs using the afs_setsprefs() function
3696 DECL_PIOCTL(PSetSPrefs)
3698 struct setspref *ssp;
3702 AFS_STATCNT(PSetSPrefs);
3704 if (!afs_resourceinit_flag) /* afs daemons haven't started yet */
3705 return EIO; /* Inappropriate ioctl for device */
3707 if (!afs_osi_suser(*acred))
3710 /* The I/O handling here is ghastly, as it relies on overrunning the ends
3711 * of arrays. But, i'm not quite brave enough to change it yet. */
3713 ainSize = ain->remaining;
3715 if (ainSize < sizeof(struct setspref))
3718 ssp = (struct setspref *)ainPtr;
3719 if (ainSize < (sizeof(struct setspref)
3720 + sizeof(struct spref) * ssp->num_servers-1))
3723 afs_setsprefs(&(ssp->servers[0]), ssp->num_servers,
3724 (ssp->flags & DBservers));
3729 * VIOC_SETPREFS33 (42) - Set server ranks (deprecated)
3731 * \param[in] ain the server preferences to be set
3732 * \param[out] aout not in use
3734 * \retval EIO Error if the afs daemon hasn't started yet
3735 * \retval EACCES Error if the user doesn't have super-user credentials
3737 * \post set the server preferences, calling a function
3739 * \notes this may only be performed by the local root user.
3741 DECL_PIOCTL(PSetSPrefs33)
3743 AFS_STATCNT(PSetSPrefs);
3744 if (!afs_resourceinit_flag) /* afs daemons haven't started yet */
3745 return EIO; /* Inappropriate ioctl for device */
3748 if (!afs_osi_suser(*acred))
3751 afs_setsprefs((struct spref *)afs_pd_where(ain),
3752 afs_pd_remaining(ain) / sizeof(struct spref),
3758 * VIOC_GETSPREFS (43) - Get server ranks
3762 * \param[in] ain the server preferences to get
3763 * \param[out] aout the server preferences information
3765 * \retval EIO Error if the afs daemon hasn't started yet
3766 * \retval ENOENT Error if the sprefrequest is too large
3768 * \post Get the sprefs
3770 * \notes in the hash table of server structs, all servers with the same IP address; will be on the same overflow chain; This could be sped slightly in some circumstances by having it cache the immediately previous slot in the hash table and some supporting information; Only reports file servers now.
3772 DECL_PIOCTL(PGetSPrefs)
3774 struct sprefrequest spin; /* input */
3775 struct sprefinfo *spout; /* output */
3776 struct spref *srvout; /* one output component */
3777 int i, j; /* counters for hash table traversal */
3778 struct server *srvr; /* one of CM's server structs */
3780 int vlonly; /* just return vlservers ? */
3783 AFS_STATCNT(PGetSPrefs);
3784 if (!afs_resourceinit_flag) /* afs daemons haven't started yet */
3785 return EIO; /* Inappropriate ioctl for device */
3787 /* Work out from the size whether we've got a new, or old, style pioctl */
3788 if (afs_pd_remaining(ain) < sizeof(struct sprefrequest)) {
3789 if (afs_pd_getBytes(ain, &spin, sizeof(struct sprefrequest_33)) != 0)
3794 if (afs_pd_getBytes(ain, &spin, sizeof(struct sprefrequest)) != 0)
3796 vlonly = (spin.flags & DBservers);
3799 /* This code relies on overflowing arrays. It's ghastly, but I'm not
3800 * quite brave enough to tackle it yet ...
3803 /* struct sprefinfo includes 1 server struct... that size gets added
3804 * in during the loop that follows.
3806 spout = afs_pd_inline(aout,
3807 sizeof(struct sprefinfo) - sizeof(struct spref));
3808 spout->next_offset = spin.offset;
3809 spout->num_servers = 0;
3810 srvout = spout->servers;
3812 ObtainReadLock(&afs_xserver);
3813 for (i = 0, j = 0; j < NSERVERS; j++) { /* sift through hash table */
3814 for (sa = afs_srvAddrs[j]; sa; sa = sa->next_bkt, i++) {
3815 if (spin.offset > (unsigned short)i) {
3816 continue; /* catch up to where we left off */
3818 spout->next_offset++;
3821 isfs = (srvr->cell && (sa->sa_portal == srvr->cell->fsport))
3822 || (sa->sa_portal == AFS_FSPORT);
3824 if ((vlonly && isfs) || (!vlonly && !isfs)) {
3825 /* only report ranks for vl servers */
3829 /* Check we've actually got the space we're about to use */
3830 if (afs_pd_inline(aout, sizeof(struct spref)) == NULL) {
3831 ReleaseReadLock(&afs_xserver); /* no more room! */
3835 srvout->host.s_addr = sa->sa_ip;
3836 srvout->rank = sa->sa_iprank;
3837 spout->num_servers++;
3841 ReleaseReadLock(&afs_xserver);
3843 spout->next_offset = 0; /* start over from the beginning next time */
3848 /* Enable/Disable the specified exporter. Must be root to disable an exporter */
3849 int afs_NFSRootOnly = 1;
3851 * VIOC_EXPORTAFS (39) - Export afs to nfs clients
3855 * \param[in] ain a struct Vic * EIOctl containing export values needed to change between nfs and afs
3856 * \param[out] aout a struct of the exporter states (exporter->exp_states)
3858 * \retval ENODEV Error if the exporter doesn't exist
3859 * \retval EACCES Error if the user doesn't have super-user credentials
3861 * \post Changes the state of various values to reflect the change of the export values between nfs and afs.
3863 * \notes Legacy code obtained from IBM.
3865 DECL_PIOCTL(PExportAfs)
3867 afs_int32 export, newint =
3868 0, type, changestate, handleValue, convmode, pwsync, smounts;
3869 afs_int32 rempags = 0, pagcb = 0;
3870 register struct afs_exporter *exporter;
3872 AFS_STATCNT(PExportAfs);
3873 if (afs_pd_getInt(ain, &handleValue) != 0)
3875 type = handleValue >> 24;
3880 exporter = exporter_find(type);
3882 export = handleValue & 3;
3883 changestate = handleValue & 0xfff;
3884 smounts = (handleValue >> 2) & 3;
3885 pwsync = (handleValue >> 4) & 3;
3886 convmode = (handleValue >> 6) & 3;
3887 rempags = (handleValue >> 8) & 3;
3888 pagcb = (handleValue >> 10) & 3;
3890 changestate = (handleValue >> 16) & 0x1;
3891 convmode = (handleValue >> 16) & 0x2;
3892 pwsync = (handleValue >> 16) & 0x4;
3893 smounts = (handleValue >> 16) & 0x8;
3894 export = handleValue & 0xff;
3897 /* Failed finding desired exporter; */
3901 handleValue = exporter->exp_states;
3902 if (afs_pd_putInt(aout, handleValue) != 0)
3905 if (!afs_osi_suser(*acred))
3906 return EACCES; /* Only superuser can do this */
3910 exporter->exp_states |= EXP_EXPORTED;
3912 exporter->exp_states &= ~EXP_EXPORTED;
3916 exporter->exp_states |= EXP_UNIXMODE;
3918 exporter->exp_states &= ~EXP_UNIXMODE;
3922 exporter->exp_states |= EXP_PWSYNC;
3924 exporter->exp_states &= ~EXP_PWSYNC;
3928 afs_NFSRootOnly = 0;
3929 exporter->exp_states |= EXP_SUBMOUNTS;
3931 afs_NFSRootOnly = 1;
3932 exporter->exp_states &= ~EXP_SUBMOUNTS;
3937 exporter->exp_states |= EXP_CLIPAGS;
3939 exporter->exp_states &= ~EXP_CLIPAGS;
3943 exporter->exp_states |= EXP_CALLBACK;
3945 exporter->exp_states &= ~EXP_CALLBACK;
3947 handleValue = exporter->exp_states;
3948 if (afs_pd_putInt(aout, handleValue) != 0)
3952 exporter->exp_states |= EXP_EXPORTED;
3954 exporter->exp_states &= ~EXP_EXPORTED;
3956 exporter->exp_states |= EXP_UNIXMODE;
3958 exporter->exp_states &= ~EXP_UNIXMODE;
3960 exporter->exp_states |= EXP_PWSYNC;
3962 exporter->exp_states &= ~EXP_PWSYNC;
3964 afs_NFSRootOnly = 0;
3965 exporter->exp_states |= EXP_SUBMOUNTS;
3967 afs_NFSRootOnly = 1;
3968 exporter->exp_states &= ~EXP_SUBMOUNTS;
3977 * VIOC_GAG (44) - Silence Cache Manager
3981 * \param[in] ain the flags to either gag or de-gag the cache manager
3982 * \param[out] aout not in use
3984 * \retval EACCES Error if the user doesn't have super-user credentials
3986 * \post set the gag flags, then show these flags
3990 struct gaginfo *gagflags;
3992 if (!afs_osi_suser(*acred))
3995 gagflags = afs_pd_inline(ain, sizeof(*gagflags));
3996 if (gagflags == NULL)
3998 afs_showflags = gagflags->showflags;
4004 * VIOC_TWIDDLE (45) - Adjust RX knobs
4008 * \param[in] ain the previous settings of the 'knobs'
4009 * \param[out] aout not in use
4011 * \retval EACCES Error if the user doesn't have super-user credentials
4013 * \post build out the struct rxp, from a struct rx
4015 DECL_PIOCTL(PTwiddleRx)
4017 struct rxparams *rxp;
4019 if (!afs_osi_suser(*acred))
4022 rxp = afs_pd_inline(ain, sizeof(*rxp));
4026 if (rxp->rx_initReceiveWindow)
4027 rx_initReceiveWindow = rxp->rx_initReceiveWindow;
4028 if (rxp->rx_maxReceiveWindow)
4029 rx_maxReceiveWindow = rxp->rx_maxReceiveWindow;
4030 if (rxp->rx_initSendWindow)
4031 rx_initSendWindow = rxp->rx_initSendWindow;
4032 if (rxp->rx_maxSendWindow)
4033 rx_maxSendWindow = rxp->rx_maxSendWindow;
4034 if (rxp->rxi_nSendFrags)
4035 rxi_nSendFrags = rxp->rxi_nSendFrags;
4036 if (rxp->rxi_nRecvFrags)
4037 rxi_nRecvFrags = rxp->rxi_nRecvFrags;
4038 if (rxp->rxi_OrphanFragSize)
4039 rxi_OrphanFragSize = rxp->rxi_OrphanFragSize;
4040 if (rxp->rx_maxReceiveSize) {
4041 rx_maxReceiveSize = rxp->rx_maxReceiveSize;
4042 rx_maxReceiveSizeUser = rxp->rx_maxReceiveSize;
4044 if (rxp->rx_MyMaxSendSize)
4045 rx_MyMaxSendSize = rxp->rx_MyMaxSendSize;
4051 * VIOC_GETINITPARAMS (49) - Get initial cache manager parameters
4055 * \param[in] ain not in use
4056 * \param[out] aout initial cache manager params
4058 * \retval E2BIG Error if the initial parameters are bigger than some PIGGYSIZE
4060 * \post return the initial cache manager parameters
4062 DECL_PIOCTL(PGetInitParams)
4064 if (sizeof(struct cm_initparams) > PIGGYSIZE)
4067 return afs_pd_putBytes(aout, &cm_initParams,
4068 sizeof(struct cm_initparams));
4072 #ifdef AFS_SGI65_ENV
4073 /* They took crget() from us, so fake it. */
4078 cr = crdup(get_current_cred());
4079 memset(cr, 0, sizeof(cred_t));
4080 #if CELL || CELL_PREPARE
4088 * VIOC_GETRXKCRYPT (55) - Get rxkad encryption flag
4092 * \param[in] ain not in use
4093 * \param[out] aout value of cryptall
4095 * \post get the value of cryptall (presumably whether or not things should be encrypted)
4097 DECL_PIOCTL(PGetRxkcrypt)
4099 return afs_pd_putInt(aout, cryptall);
4103 * VIOC_SETRXKCRYPT (56) - Set rxkad encryption flag
4107 * \param[in] ain the argument whether or not things should be encrypted
4108 * \param[out] aout not in use
4110 * \retval EPERM Error if the user doesn't have super-user credentials
4111 * \retval EINVAL Error if the input is too big, or if the input is outside the bounds of what it can be set to
4113 * \post set whether or not things should be encrypted
4115 * \notes may need to be modified at a later date to take into account other values for cryptall (beyond true or false)
4117 DECL_PIOCTL(PSetRxkcrypt)
4121 if (!afs_osi_suser(*acred))
4123 if (afs_pd_getInt(ain, &tmpval) != 0)
4125 /* if new mappings added later this will need to be changed */
4126 if (tmpval != 0 && tmpval != 1)
4132 #ifdef AFS_NEED_CLIENTCONTEXT
4134 * Create new credentials to correspond to a remote user with given
4135 * <hostaddr, uid, g0, g1>. This allows a server running as root to
4136 * provide pioctl (and other) services to foreign clients (i.e. nfs
4137 * clients) by using this call to `become' the client.
4140 #define PIOCTL_HEADER 6
4142 HandleClientContext(struct afs_ioctl *ablob, int *com,
4143 afs_ucred_t **acred, afs_ucred_t *credp)
4146 afs_uint32 hostaddr;
4147 afs_int32 uid, g0, g1, i, code, pag, exporter_type, isroot = 0;
4148 struct afs_exporter *exporter, *outexporter;
4149 afs_ucred_t *newcred;
4150 struct unixuser *au;
4151 afs_uint32 comp = *com & 0xff00;
4153 #if defined(AFS_SUN510_ENV)
4157 #if defined(AFS_SGIMP_ENV)
4158 osi_Assert(ISAFS_GLOCK());
4160 AFS_STATCNT(HandleClientContext);
4161 if (ablob->in_size < PIOCTL_HEADER * sizeof(afs_int32)) {
4162 /* Must at least include the PIOCTL_HEADER header words required by the protocol */
4163 return EINVAL; /* Too small to be good */
4165 ain = inData = osi_AllocLargeSpace(AFS_LRALLOCSIZ);
4166 AFS_COPYIN(ablob->in, ain, PIOCTL_HEADER * sizeof(afs_int32), code);
4168 osi_FreeLargeSpace(inData);
4172 /* Extract information for remote user */
4173 hostaddr = *((afs_uint32 *) ain);
4174 ain += sizeof(hostaddr);
4175 uid = *((afs_uint32 *) ain);
4177 g0 = *((afs_uint32 *) ain);
4179 g1 = *((afs_uint32 *) ain);
4181 *com = *((afs_uint32 *) ain);
4182 ain += sizeof(afs_int32);
4183 exporter_type = *((afs_uint32 *) ain); /* In case we support more than NFS */
4186 * Of course, one must be root for most of these functions, but
4187 * we'll allow (for knfs) you to set things if the pag is 0 and
4188 * you're setting tokens or unlogging.
4191 if (!afs_osi_suser(credp)) {
4192 #if defined(AFS_SGI_ENV) && !defined(AFS_SGI64_ENV)
4193 /* Since SGI's suser() returns explicit failure after the call.. */
4196 /* check for acceptable opcodes for normal folks, which are, so far,