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;
42 * \defgroup pioctl Path IOCTL functions
44 * DECL_PIOCTL is a macro defined to contain the following parameters for functions:
46 * \param[in] avc the AFS vcache structure in use by pioctl
47 * \param[in] afun not in use
48 * \param[in] areq the AFS vrequest structure
49 * \param[in] ain as defined by the function
50 * \param[in] aout as defined by the function
51 * \param[in] ainSize size of ain
52 * \param[in] aoutSize size of aout
53 * \param[in] acred UNIX credentials structure underlying the operation
56 #define DECL_PIOCTL(x) static int x(struct vcache *avc, int afun, struct vrequest *areq, \
57 char *ain, char *aout, afs_int32 ainSize, afs_int32 *aoutSize, \
58 struct AFS_UCRED **acred)
60 /* Prototypes for pioctl routines */
63 DECL_PIOCTL(PStoreBehind);
68 DECL_PIOCTL(PGetFileCell);
69 DECL_PIOCTL(PGetWSCell);
70 DECL_PIOCTL(PGetUserCell);
71 DECL_PIOCTL(PSetTokens);
72 DECL_PIOCTL(PGetVolumeStatus);
73 DECL_PIOCTL(PSetVolumeStatus);
75 DECL_PIOCTL(PNewStatMount);
76 DECL_PIOCTL(PGetTokens);
78 DECL_PIOCTL(PMariner);
79 DECL_PIOCTL(PCheckServers);
80 DECL_PIOCTL(PCheckVolNames);
81 DECL_PIOCTL(PCheckAuth);
82 DECL_PIOCTL(PFindVolume);
83 DECL_PIOCTL(PViceAccess);
84 DECL_PIOCTL(PSetCacheSize);
85 DECL_PIOCTL(PGetCacheSize);
86 DECL_PIOCTL(PRemoveCallBack);
87 DECL_PIOCTL(PNewCell);
88 DECL_PIOCTL(PNewAlias);
89 DECL_PIOCTL(PListCells);
90 DECL_PIOCTL(PListAliases);
91 DECL_PIOCTL(PRemoveMount);
92 DECL_PIOCTL(PVenusLogging);
93 DECL_PIOCTL(PGetCellStatus);
94 DECL_PIOCTL(PSetCellStatus);
95 DECL_PIOCTL(PFlushVolumeData);
96 DECL_PIOCTL(PGetVnodeXStatus);
97 DECL_PIOCTL(PGetVnodeXStatus2);
98 DECL_PIOCTL(PSetSysName);
99 DECL_PIOCTL(PSetSPrefs);
100 DECL_PIOCTL(PSetSPrefs33);
101 DECL_PIOCTL(PGetSPrefs);
102 DECL_PIOCTL(PExportAfs);
104 DECL_PIOCTL(PTwiddleRx);
105 DECL_PIOCTL(PGetInitParams);
106 DECL_PIOCTL(PGetRxkcrypt);
107 DECL_PIOCTL(PSetRxkcrypt);
108 DECL_PIOCTL(PGetCPrefs);
109 DECL_PIOCTL(PSetCPrefs);
110 DECL_PIOCTL(PFlushMount);
111 DECL_PIOCTL(PRxStatProc);
112 DECL_PIOCTL(PRxStatPeer);
113 DECL_PIOCTL(PPrefetchFromTape);
115 DECL_PIOCTL(PCallBackAddr);
116 DECL_PIOCTL(PDiscon);
117 DECL_PIOCTL(PNFSNukeCreds);
118 DECL_PIOCTL(PNewUuid);
119 DECL_PIOCTL(PPrecache);
120 DECL_PIOCTL(PGetPAG);
121 #if defined(AFS_CACHE_BYPASS)
122 DECL_PIOCTL(PSetCachingThreshold);
123 DECL_PIOCTL(PSetCachingBlkSize);
127 * A macro that says whether we're going to need HandleClientContext().
128 * This is currently used only by the nfs translator.
130 #if !defined(AFS_NONFSTRANS) || defined(AFS_AIX_IAUTH_ENV)
131 #define AFS_NEED_CLIENTCONTEXT
134 /* Prototypes for private routines */
135 #ifdef AFS_NEED_CLIENTCONTEXT
136 static int HandleClientContext(struct afs_ioctl *ablob, int *com,
137 struct AFS_UCRED **acred,
138 struct AFS_UCRED *credp);
140 int HandleIoctl(register struct vcache *avc, register afs_int32 acom,
141 struct afs_ioctl *adata);
142 int afs_HandlePioctl(struct vnode *avp, afs_int32 acom,
143 register struct afs_ioctl *ablob, int afollow,
144 struct AFS_UCRED **acred);
145 static int Prefetch(char *apath, struct afs_ioctl *adata, int afollow,
146 struct AFS_UCRED *acred);
148 typedef int (*pioctlFunction) (struct vcache *, int, struct vrequest *,
149 char *, char *, afs_int32, afs_int32 *,
150 struct AFS_UCRED **);
152 static pioctlFunction VpioctlSw[] = {
157 PGetVolumeStatus, /* 4 */
158 PSetVolumeStatus, /* 5 */
163 PCheckServers, /* 10 */
164 PCheckVolNames, /* 11 */
166 PBogus, /* 13 -- used to be quick check time */
167 PFindVolume, /* 14 */
168 PBogus, /* 15 -- prefetch is now special-cased; see pioctl code! */
169 PBogus, /* 16 -- used to be testing code */
170 PNoop, /* 17 -- used to be enable group */
171 PNoop, /* 18 -- used to be disable group */
172 PBogus, /* 19 -- used to be list group */
173 PViceAccess, /* 20 */
174 PUnlog, /* 21 -- unlog *is* unpag in this system */
175 PGetFID, /* 22 -- get file ID */
176 PBogus, /* 23 -- used to be waitforever */
177 PSetCacheSize, /* 24 */
178 PRemoveCallBack, /* 25 -- flush only the callback */
181 PRemoveMount, /* 28 -- delete mount point */
182 PNewStatMount, /* 29 -- new style mount point stat */
183 PGetFileCell, /* 30 -- get cell name for input file */
184 PGetWSCell, /* 31 -- get cell name for workstation */
185 PMariner, /* 32 - set/get mariner host */
186 PGetUserCell, /* 33 -- get cell name for user */
187 PVenusLogging, /* 34 -- Enable/Disable logging */
188 PGetCellStatus, /* 35 */
189 PSetCellStatus, /* 36 */
190 PFlushVolumeData, /* 37 -- flush all data from a volume */
191 PSetSysName, /* 38 - Set system name */
192 PExportAfs, /* 39 - Export Afs to remote nfs clients */
193 PGetCacheSize, /* 40 - get cache size and usage */
194 PGetVnodeXStatus, /* 41 - get vcache's special status */
195 PSetSPrefs33, /* 42 - Set CM Server preferences... */
196 PGetSPrefs, /* 43 - Get CM Server preferences... */
197 PGag, /* 44 - turn off/on all CM messages */
198 PTwiddleRx, /* 45 - adjust some RX params */
199 PSetSPrefs, /* 46 - Set CM Server preferences... */
200 PStoreBehind, /* 47 - set degree of store behind to be done */
201 PGCPAGs, /* 48 - disable automatic pag gc-ing */
202 PGetInitParams, /* 49 - get initial cm params */
203 PGetCPrefs, /* 50 - get client interface addresses */
204 PSetCPrefs, /* 51 - set client interface addresses */
205 PFlushMount, /* 52 - flush mount symlink data */
206 PRxStatProc, /* 53 - control process RX statistics */
207 PRxStatPeer, /* 54 - control peer RX statistics */
208 PGetRxkcrypt, /* 55 -- Get rxkad encryption flag */
209 PSetRxkcrypt, /* 56 -- Set rxkad encryption flag */
210 PBogus, /* 57 -- arla: set file prio */
211 PBogus, /* 58 -- arla: fallback getfh */
212 PBogus, /* 59 -- arla: fallback fhopen */
213 PBogus, /* 60 -- arla: controls xfsdebug */
214 PBogus, /* 61 -- arla: controls arla debug */
215 PBogus, /* 62 -- arla: debug interface */
216 PBogus, /* 63 -- arla: print xfs status */
217 PBogus, /* 64 -- arla: force cache check */
218 PBogus, /* 65 -- arla: break callback */
219 PPrefetchFromTape, /* 66 -- MR-AFS: prefetch file from tape */
220 PFsCmd, /* 67 -- RXOSD: generic commnd interface */
221 PBogus, /* 68 -- arla: fetch stats */
222 PGetVnodeXStatus2, /* 69 - get caller access and some vcache status */
225 static pioctlFunction CpioctlSw[] = {
227 PNewAlias, /* 1 -- create new cell alias */
228 PListAliases, /* 2 -- list cell aliases */
229 PCallBackAddr, /* 3 -- request addr for callback rxcon */
231 PDiscon, /* 5 -- get/set discon mode */
242 static pioctlFunction OpioctlSw[] = {
244 PNFSNukeCreds, /* 1 -- nuke all creds for NFS client */
245 #if defined(AFS_CACHE_BYPASS)
246 PSetCachingThreshold /* 2 -- get/set cache-bypass size threshold */
248 PNoop /* 2 -- get/set cache-bypass size threshold */
252 #define PSetClientContext 99 /* Special pioctl to setup caller's creds */
253 int afs_nobody = NFS_NOBODY;
256 HandleIoctl(register struct vcache *avc, register afs_int32 acom,
257 struct afs_ioctl *adata)
259 register afs_int32 code;
262 AFS_STATCNT(HandleIoctl);
264 switch (acom & 0xff) {
266 avc->f.states |= CSafeStore;
268 /* SXW - Should we force a MetaData flush for this flag setting */
271 /* case 2 used to be abort store, but this is no longer provided,
272 * since it is impossible to implement under normal Unix.
276 /* return the name of the cell this file is open on */
277 register struct cell *tcell;
278 register afs_int32 i;
280 tcell = afs_GetCell(avc->f.fid.Cell, READ_LOCK);
282 i = strlen(tcell->cellName) + 1; /* bytes to copy out */
284 if (i > adata->out_size) {
285 /* 0 means we're not interested in the output */
286 if (adata->out_size != 0)
290 AFS_COPYOUT(tcell->cellName, adata->out, i, code);
292 afs_PutCell(tcell, READ_LOCK);
298 case 49: /* VIOC_GETINITPARAMS */
299 if (adata->out_size < sizeof(struct cm_initparams)) {
302 AFS_COPYOUT(&cm_initParams, adata->out,
303 sizeof(struct cm_initparams), code);
315 return code; /* so far, none implemented */
320 /* For aix we don't temporarily bypass ioctl(2) but rather do our
321 * thing directly in the vnode layer call, VNOP_IOCTL; thus afs_ioctl
322 * is now called from afs_gn_ioctl.
325 afs_ioctl(struct vcache *tvc, int cmd, int arg)
327 struct afs_ioctl data;
330 AFS_STATCNT(afs_ioctl);
331 if (((cmd >> 8) & 0xff) == 'V') {
332 /* This is a VICEIOCTL call */
333 AFS_COPYIN(arg, (caddr_t) & data, sizeof(data), error);
336 error = HandleIoctl(tvc, cmd, &data);
339 /* No-op call; just return. */
343 #endif /* AFS_AIX_ENV */
345 #if defined(AFS_SGI_ENV)
346 afs_ioctl(OSI_VN_DECL(tvc), int cmd, void *arg, int flag, cred_t * cr,
349 , struct vopbd * vbds
353 struct afs_ioctl data;
359 AFS_STATCNT(afs_ioctl);
360 if (((cmd >> 8) & 0xff) == 'V') {
361 /* This is a VICEIOCTL call */
362 error = copyin_afs_ioctl(arg, &data);
365 locked = ISAFS_GLOCK();
368 error = HandleIoctl(tvc, cmd, &data);
373 /* No-op call; just return. */
377 #endif /* AFS_SGI_ENV */
379 /* unlike most calls here, this one uses u.u_error to return error conditions,
380 since this is really an intercepted chapter 2 call, rather than a vnode
383 /* AFS_HPUX102 and up uses VNODE ioctl instead */
384 #if !defined(AFS_HPUX102_ENV) && !defined(AFS_DARWIN80_ENV)
385 #if !defined(AFS_SGI_ENV)
390 kioctl(int fdes, int com, caddr_t arg, caddr_t ext, caddr_t arg2,
392 #else /* __64BIT__ */
394 kioctl32(int fdes, int com, caddr_t arg, caddr_t ext, caddr_t arg2,
396 #endif /* __64BIT__ */
399 kioctl(int fdes, int com, caddr_t arg, caddr_t ext)
408 } u_uap, *uap = &u_uap;
410 #if defined(AFS_SUN5_ENV)
412 struct afs_ioctl_sys {
419 afs_xioctl(struct afs_ioctl_sys *uap, rval_t *rvp)
421 #elif defined(AFS_OSF_ENV)
423 afs_xioctl(struct proc *p, void *args, long *retval)
429 } *uap = (struct a *)args;
430 #elif defined(AFS_FBSD50_ENV)
433 afs_xioctl(struct thread *td, register struct ioctl_args *uap,
436 struct proc *p = td->td_proc;
437 #elif defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
445 afs_xioctl(struct proc *p, register struct ioctl_args *uap, register_t *retval)
447 #elif defined(AFS_LINUX22_ENV)
448 struct afs_ioctl_sys {
453 afs_xioctl(struct inode *ip, struct file *fp, unsigned int com,
456 struct afs_ioctl_sys ua, *uap = &ua;
465 } *uap = (struct a *)u.u_ap;
466 #endif /* AFS_SUN5_ENV */
468 #if defined(AFS_AIX32_ENV) || defined(AFS_SUN5_ENV) || defined(AFS_OSF_ENV) || defined(AFS_DARWIN_ENV)
470 #elif !defined(AFS_LINUX22_ENV)
471 register struct file *fd;
473 #if defined(AFS_XBSD_ENV)
474 register struct filedesc *fdp;
476 register struct vcache *tvc;
477 register int ioctlDone = 0, code = 0;
479 AFS_STATCNT(afs_xioctl);
480 #if defined(AFS_DARWIN_ENV)
481 if ((code = fdgetf(p, uap->fd, &fd)))
483 #elif defined(AFS_XBSD_ENV)
485 if ((u_int) uap->fd >= fdp->fd_nfiles
486 || (fd = fdp->fd_ofiles[uap->fd]) == NULL)
488 if ((fd->f_flag & (FREAD | FWRITE)) == 0)
490 #elif defined(AFS_LINUX22_ENV)
493 #elif defined(AFS_AIX32_ENV)
501 if (setuerror(getf(uap->fd, &fd))) {
504 #elif defined(AFS_OSF_ENV)
506 if (code = getf(&fd, uap->fd, FILE_FLAGS_NULL, &u.u_file_state))
508 #elif defined(AFS_SUN5_ENV)
509 # if defined(AFS_SUN57_ENV)
513 # elif defined(AFS_SUN54_ENV)
518 if (code = getf(uap->fd, &fd)) {
521 # endif /* AFS_SUN57_ENV */
527 /* first determine whether this is any sort of vnode */
528 #if defined(AFS_LINUX22_ENV)
533 if (fd->f_vnode->v_type == VREG || fd->f_vnode->v_type == VDIR) {
535 if (fd->f_type == DTYPE_VNODE) {
537 /* good, this is a vnode; next see if it is an AFS vnode */
538 #if defined(AFS_AIX32_ENV) || defined(AFS_SUN5_ENV)
539 tvc = VTOAFS(fd->f_vnode); /* valid, given a vnode */
540 #elif defined(AFS_OBSD_ENV)
542 IsAfsVnode((struct vnode *)fd->
543 f_data) ? VTOAFS((struct vnode *)fd->f_data) : NULL;
545 tvc = VTOAFS((struct vnode *)fd->f_data); /* valid, given a vnode */
547 #endif /* AFS_LINUX22_ENV */
548 if (tvc && IsAfsVnode(AFSTOV(tvc))) {
549 /* This is an AFS vnode */
550 if (((uap->com >> 8) & 0xff) == 'V') {
551 register struct afs_ioctl *datap;
554 (struct afs_ioctl *)osi_AllocSmallSpace(AFS_SMALLOCSIZ);
555 code=copyin_afs_ioctl((char *)uap->arg, datap);
557 osi_FreeSmallSpace(datap);
559 #if defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
562 #if defined(AFS_SUN5_ENV)
577 #else /* AFS_OSF_ENV */
581 #ifdef AFS_LINUX22_ENV
584 return (setuerror(code), code);
590 code = HandleIoctl(tvc, uap->com, datap);
591 osi_FreeSmallSpace(datap);
605 #if defined(AFS_LINUX22_ENV)
617 code = okioctl(fdes, com, arg, ext, arg2, arg3);
618 #else /* __64BIT__ */
619 code = okioctl32(fdes, com, arg, ext, arg2, arg3);
620 #endif /* __64BIT__ */
621 #else /* !AFS_AIX51_ENV */
622 code = okioctl(fdes, com, arg, ext);
623 #endif /* AFS_AIX51_ENV */
625 #else /* !AFS_AIX41_ENV */
627 okioctl(fdes, com, arg, ext);
628 #elif defined(AFS_SUN5_ENV)
629 #if defined(AFS_SUN57_ENV)
631 #elif defined(AFS_SUN54_ENV)
636 code = ioctl(uap, rvp);
637 #elif defined(AFS_FBSD50_ENV)
638 return ioctl(td, uap);
639 #elif defined(AFS_FBSD_ENV)
640 return ioctl(p, uap);
641 #elif defined(AFS_OBSD_ENV)
642 code = sys_ioctl(p, uap, retval);
643 #elif defined(AFS_DARWIN_ENV)
644 return ioctl(p, uap, retval);
645 #elif defined(AFS_OSF_ENV)
646 code = ioctl(p, args, retval);
653 #elif !defined(AFS_LINUX22_ENV)
667 #ifdef AFS_LINUX22_ENV
670 #if defined(KERNEL_HAVE_UERROR)
673 #if defined(AFS_AIX32_ENV) && !defined(AFS_AIX41_ENV)
674 return (getuerror()? -1 : u.u_ioctlrv);
676 return getuerror()? -1 : 0;
679 #endif /* AFS_LINUX22_ENV */
680 #endif /* AFS_SUN5_ENV */
681 #if defined(AFS_OSF_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
687 #endif /* AFS_SGI_ENV */
688 #endif /* AFS_HPUX102_ENV */
690 #if defined(AFS_SGI_ENV)
691 /* "pioctl" system call entry point; just pass argument to the parameterized
700 afs_pioctl(struct pioctlargs *uap, rval_t * rvp)
704 AFS_STATCNT(afs_pioctl);
706 code = afs_syscall_pioctl(uap->path, uap->cmd, uap->cmarg, uap->follow);
715 #elif defined(AFS_OSF_ENV)
716 afs_pioctl(struct proc *p, void *args, int *retval)
723 } *uap = (struct a *)args;
725 AFS_STATCNT(afs_pioctl);
726 return (afs_syscall_pioctl(uap->path, uap->cmd, uap->cmarg, uap->follow));
729 #elif defined(AFS_FBSD50_ENV)
731 afs_pioctl(struct thread *td, void *args, int *retval)
738 } *uap = (struct a *)args;
740 AFS_STATCNT(afs_pioctl);
741 return (afs_syscall_pioctl
742 (uap->path, uap->cmd, uap->cmarg, uap->follow, td->td_ucred));
745 #elif defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
747 afs_pioctl(struct proc *p, void *args, int *retval)
754 } *uap = (struct a *)args;
756 AFS_STATCNT(afs_pioctl);
757 #ifdef AFS_DARWIN80_ENV
758 return (afs_syscall_pioctl
759 (uap->path, uap->cmd, uap->cmarg, uap->follow,
762 return (afs_syscall_pioctl
763 (uap->path, uap->cmd, uap->cmarg, uap->follow,
764 p->p_cred->pc_ucred));
770 /* macro to avoid adding any more #ifdef's to pioctl code. */
771 #if defined(AFS_LINUX22_ENV) || defined(AFS_AIX41_ENV)
772 #define PIOCTL_FREE_CRED() crfree(credp)
774 #define PIOCTL_FREE_CRED()
779 afs_syscall_pioctl(char *path, unsigned int com, caddr_t cmarg, int follow,
780 rval_t *vvp, struct AFS_UCRED *credp)
782 #if defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
783 afs_syscall_pioctl(char *path, unsigned int com, caddr_t cmarg, int follow,
784 struct AFS_UCRED *credp)
786 afs_syscall_pioctl(char *path, unsigned int com, caddr_t cmarg, int follow)
790 struct afs_ioctl data;
791 #ifdef AFS_NEED_CLIENTCONTEXT
792 struct AFS_UCRED *tmpcred = NULL;
794 #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)
795 struct AFS_UCRED *foreigncreds = NULL;
797 register afs_int32 code = 0;
798 struct vnode *vp = NULL;
800 struct ucred *credp = crref(); /* don't free until done! */
802 #ifdef AFS_LINUX22_ENV
803 cred_t *credp = crref(); /* don't free until done! */
807 AFS_STATCNT(afs_syscall_pioctl);
809 follow = 1; /* compat. with old venus */
810 code = copyin_afs_ioctl(cmarg, &data);
813 #if defined(KERNEL_HAVE_UERROR)
818 if ((com & 0xff) == PSetClientContext) {
819 #ifdef AFS_NEED_CLIENTCONTEXT
820 #if defined(AFS_SUN5_ENV) || defined(AFS_AIX41_ENV) || defined(AFS_LINUX22_ENV)
821 code = HandleClientContext(&data, &com, &foreigncreds, credp);
823 code = HandleClientContext(&data, &com, &foreigncreds, osi_curcred());
827 crfree(foreigncreds);
830 #if defined(KERNEL_HAVE_UERROR)
831 return (setuerror(code), code);
836 #else /* AFS_NEED_CLIENTCONTEXT */
838 #endif /* AFS_NEED_CLIENTCONTEXT */
840 #ifdef AFS_NEED_CLIENTCONTEXT
843 * We could have done without temporary setting the u.u_cred below
844 * (foreigncreds could be passed as param the pioctl modules)
845 * but calls such as afs_osi_suser() doesn't allow that since it
846 * references u.u_cred directly. We could, of course, do something
847 * like afs_osi_suser(cred) which, I think, is better since it
848 * generalizes and supports multi cred environments...
850 #if defined(AFS_SUN5_ENV) || defined(AFS_LINUX22_ENV)
852 credp = foreigncreds;
853 #elif defined(AFS_AIX41_ENV)
854 tmpcred = crref(); /* XXX */
856 #elif defined(AFS_HPUX101_ENV)
857 tmpcred = p_cred(u.u_procp);
858 set_p_cred(u.u_procp, foreigncreds);
859 #elif defined(AFS_SGI_ENV)
860 tmpcred = OSI_GET_CURRENT_CRED();
861 OSI_SET_CURRENT_CRED(foreigncreds);
864 u.u_cred = foreigncreds;
867 #endif /* AFS_NEED_CLIENTCONTEXT */
868 if ((com & 0xff) == 15) {
869 /* special case prefetch so entire pathname eval occurs in helper process.
870 * otherwise, the pioctl call is essentially useless */
871 #if defined(AFS_SUN5_ENV) || defined(AFS_AIX41_ENV) || defined(AFS_LINUX22_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
873 Prefetch(path, &data, follow,
874 foreigncreds ? foreigncreds : credp);
876 code = Prefetch(path, &data, follow, osi_curcred());
879 #if defined(KERNEL_HAVE_UERROR)
888 lookupname(path, USR, follow, NULL, &vp,
889 foreigncreds ? foreigncreds : credp);
891 #ifdef AFS_LINUX22_ENV
892 code = gop_lookupname(path, AFS_UIOUSER, follow, &dp);
894 vp = (struct vnode *)dp->d_inode;
896 code = gop_lookupname(path, AFS_UIOUSER, follow, &vp);
897 #endif /* AFS_LINUX22_ENV */
898 #endif /* AFS_AIX41_ENV */
902 #if defined(KERNEL_HAVE_UERROR)
910 #if defined(AFS_SUN510_ENV)
911 if (vp && !IsAfsVnode(vp)) {
912 struct vnode *realvp;
914 #ifdef AFS_SUN511_ENV
915 (VOP_REALVP(vp, &realvp, NULL) == 0)
917 (VOP_REALVP(vp, &realvp) == 0)
920 struct vnode *oldvp = vp;
928 /* now make the call if we were passed no file, or were passed an AFS file */
929 if (!vp || IsAfsVnode(vp)) {
930 #if defined(AFS_SUN5_ENV)
931 code = afs_HandlePioctl(vp, com, &data, follow, &credp);
932 #elif defined(AFS_AIX41_ENV)
934 struct ucred *cred1, *cred2;
937 cred1 = cred2 = foreigncreds;
939 cred1 = cred2 = credp;
941 code = afs_HandlePioctl(vp, com, &data, follow, &cred1);
942 if (cred1 != cred2) {
943 /* something changed the creds */
947 #elif defined(AFS_HPUX101_ENV)
949 struct ucred *cred = p_cred(u.u_procp);
950 code = afs_HandlePioctl(vp, com, &data, follow, &cred);
952 #elif defined(AFS_SGI_ENV)
955 credp = OSI_GET_CURRENT_CRED();
956 code = afs_HandlePioctl(vp, com, &data, follow, &credp);
958 #elif defined(AFS_LINUX22_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
959 code = afs_HandlePioctl(vp, com, &data, follow, &credp);
961 code = afs_HandlePioctl(vp, com, &data, follow, &u.u_cred);
964 #if defined(KERNEL_HAVE_UERROR)
967 code = EINVAL; /* not in /afs */
972 #if defined(AFS_NEED_CLIENTCONTEXT)
975 crset(tmpcred); /* restore original credentials */
977 #if defined(AFS_HPUX101_ENV)
978 set_p_cred(u.u_procp, tmpcred); /* restore original credentials */
979 #elif defined(AFS_SGI_ENV)
980 OSI_SET_CURRENT_CRED(tmpcred); /* restore original credentials */
981 #elif defined(AFS_SUN5_ENV) || defined(AFS_LINUX22_ENV)
982 credp = tmpcred; /* restore original credentials */
984 osi_curcred() = tmpcred; /* restore original credentials */
985 #endif /* AFS_HPUX101_ENV */
986 crfree(foreigncreds);
989 #endif /* AFS_NEED_CLIENTCONTEXT */
991 #ifdef AFS_LINUX22_ENV
994 AFS_RELE(vp); /* put vnode back */
998 #if defined(KERNEL_HAVE_UERROR)
1001 return (getuerror());
1007 #define MAXPIOCTLTOKENLEN \
1008 (3*sizeof(afs_int32)+MAXKTCTICKETLEN+sizeof(struct ClearToken)+MAXKTCREALMLEN)
1011 afs_HandlePioctl(struct vnode *avp, afs_int32 acom,
1012 register struct afs_ioctl *ablob, int afollow,
1013 struct AFS_UCRED **acred)
1016 struct vrequest treq;
1017 register afs_int32 code;
1018 register afs_int32 function, device;
1019 afs_int32 inSize, outSize, outSizeMax;
1020 char *inData, *outData;
1021 pioctlFunction *pioctlSw;
1023 struct afs_fakestat_state fakestate;
1025 avc = avp ? VTOAFS(avp) : NULL;
1026 afs_Trace3(afs_iclSetp, CM_TRACE_PIOCTL, ICL_TYPE_INT32, acom & 0xff,
1027 ICL_TYPE_POINTER, avc, ICL_TYPE_INT32, afollow);
1028 AFS_STATCNT(HandlePioctl);
1029 if ((code = afs_InitReq(&treq, *acred)))
1031 afs_InitFakeStat(&fakestate);
1033 code = afs_EvalFakeStat(&avc, &fakestate, &treq);
1035 afs_PutFakeStat(&fakestate);
1039 device = (acom & 0xff00) >> 8;
1041 case 'V': /* Original pioctls */
1042 pioctlSw = VpioctlSw;
1043 pioctlSwSize = sizeof(VpioctlSw);
1045 case 'C': /* Coordinated/common pioctls */
1046 pioctlSw = CpioctlSw;
1047 pioctlSwSize = sizeof(CpioctlSw);
1049 case 'O': /* Coordinated/common pioctls */
1050 pioctlSw = OpioctlSw;
1051 pioctlSwSize = sizeof(OpioctlSw);
1054 afs_PutFakeStat(&fakestate);
1057 function = acom & 0xff;
1058 if (function >= (pioctlSwSize / sizeof(char *))) {
1059 afs_PutFakeStat(&fakestate);
1060 return EINVAL; /* out of range */
1062 inSize = ablob->in_size;
1064 /* Do all range checking before continuing */
1065 if (inSize > MAXPIOCTLTOKENLEN || inSize < 0 || ablob->out_size < 0)
1068 /* Note that we use osi_Alloc for large allocs and osi_AllocLargeSpace for small ones */
1069 if (inSize > AFS_LRALLOCSIZ) {
1070 inData = osi_Alloc(inSize + 1);
1072 inData = osi_AllocLargeSpace(AFS_LRALLOCSIZ);
1077 AFS_COPYIN(ablob->in, inData, inSize, code);
1078 inData[inSize] = '\0';
1082 if (inSize > AFS_LRALLOCSIZ) {
1083 osi_Free(inData, inSize + 1);
1085 osi_FreeLargeSpace(inData);
1087 afs_PutFakeStat(&fakestate);
1090 if (function == 8 && device == 'V') { /* PGetTokens */
1091 outSizeMax = MAXPIOCTLTOKENLEN;
1092 outData = osi_Alloc(outSizeMax);
1094 outSizeMax = AFS_LRALLOCSIZ;
1095 outData = osi_AllocLargeSpace(AFS_LRALLOCSIZ);
1098 if (inSize > AFS_LRALLOCSIZ) {
1099 osi_Free(inData, inSize + 1);
1101 osi_FreeLargeSpace(inData);
1103 afs_PutFakeStat(&fakestate);
1108 (*pioctlSw[function]) (avc, function, &treq, inData, outData, inSize,
1110 if (inSize > AFS_LRALLOCSIZ) {
1111 osi_Free(inData, inSize + 1);
1113 osi_FreeLargeSpace(inData);
1115 if (code == 0 && ablob->out_size > 0) {
1116 if (outSize > ablob->out_size) {
1117 code = E2BIG; /* data wont fit in user buffer */
1118 } else if (outSize) {
1119 AFS_COPYOUT(outData, ablob->out, outSize, code);
1122 if (outSizeMax > AFS_LRALLOCSIZ) {
1123 osi_Free(outData, outSizeMax);
1125 osi_FreeLargeSpace(outData);
1127 afs_PutFakeStat(&fakestate);
1128 return afs_CheckCode(code, &treq, 41);
1132 * VIOCGETFID (22) - Get file ID quickly
1136 * \param[in] ain not in use
1137 * \param[out] aout fid of requested file
1139 * \retval EINVAL Error if some of the initial arguments aren't set
1141 * \post get the file id of some file
1143 DECL_PIOCTL(PGetFID)
1145 AFS_STATCNT(PGetFID);
1148 memcpy(aout, (char *)&avc->f.fid, sizeof(struct VenusFid));
1149 *aoutSize = sizeof(struct VenusFid);
1154 * VIOCSETAL (1) - Set access control list
1158 * \param[in] ain the ACL being set
1159 * \param[out] aout the ACL being set returned
1161 * \retval EINVAL Error if some of the standard args aren't set
1163 * \post Changed ACL, via direct writing to the wire
1165 int dummy_PSetAcl(char *ain, char *aout)
1170 DECL_PIOCTL(PSetAcl)
1172 register afs_int32 code;
1173 struct afs_conn *tconn;
1174 struct AFSOpaque acl;
1175 struct AFSVolSync tsync;
1176 struct AFSFetchStatus OutStatus;
1179 AFS_STATCNT(PSetAcl);
1182 if ((acl.AFSOpaque_len = strlen(ain) + 1) > 1024 /* AFSOPAQUEMAX */)
1185 acl.AFSOpaque_val = ain;
1187 tconn = afs_Conn(&avc->f.fid, areq, SHARED_LOCK);
1189 XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_STOREACL);
1192 RXAFS_StoreACL(tconn->id, (struct AFSFid *)&avc->f.fid.Fid,
1193 &acl, &OutStatus, &tsync);
1198 } while (afs_Analyze
1199 (tconn, code, &avc->f.fid, areq, AFS_STATS_FS_RPCIDX_STOREACL,
1200 SHARED_LOCK, NULL));
1202 /* now we've forgotten all of the access info */
1203 ObtainWriteLock(&afs_xcbhash, 455);
1205 afs_DequeueCallback(avc);
1206 avc->f.states &= ~(CStatd | CUnique);
1207 ReleaseWriteLock(&afs_xcbhash);
1208 if (avc->f.fid.Fid.Vnode & 1 || (vType(avc) == VDIR))
1209 osi_dnlc_purgedp(avc);
1211 /* SXW - Should we flush metadata here? */
1215 int afs_defaultAsynchrony = 0;
1218 * VIOC_STOREBEHIND (47) Adjust store asynchrony
1222 * \param[in] ain sbstruct (store behind structure) input
1223 * \param[out] aout resulting sbstruct
1225 * \retval EPERM Error if the user doesn't have super-user credentials
1226 * \retval EACCES Error if there isn't enough access to not check the mode bits
1228 * \post sets asynchrony based on a file, from a struct sbstruct "I THINK"
1230 DECL_PIOCTL(PStoreBehind)
1233 struct sbstruct *sbr;
1235 sbr = (struct sbstruct *)ain;
1236 if (sbr->sb_default != -1) {
1237 if (afs_osi_suser(*acred))
1238 afs_defaultAsynchrony = sbr->sb_default;
1243 if (avc && (sbr->sb_thisfile != -1)) {
1245 (avc, PRSFS_WRITE | PRSFS_ADMINISTER, areq, DONT_CHECK_MODE_BITS))
1246 avc->asynchrony = sbr->sb_thisfile;
1251 *aoutSize = sizeof(struct sbstruct);
1252 sbr = (struct sbstruct *)aout;
1253 sbr->sb_default = afs_defaultAsynchrony;
1255 sbr->sb_thisfile = avc->asynchrony;
1262 * VIOC_GCPAGS (48) - Disable automatic PAG gc'ing
1266 * \param[in] ain not in use
1267 * \param[out] aout not in use
1269 * \retval EACCES Error if the user doesn't have super-user credentials
1271 * \post set the gcpags to GCPAGS_USERDISABLED
1273 DECL_PIOCTL(PGCPAGs)
1275 if (!afs_osi_suser(*acred)) {
1278 afs_gcpags = AFS_GCPAGS_USERDISABLED;
1283 * VIOCGETAL (2) - Get access control list
1287 * \param[in] ain not in use
1288 * \param[out] aout the ACL
1290 * \retval EINVAL Error if some of the standard args aren't set
1291 * \retval ERANGE Error if the vnode of the file id is too large
1292 * \retval -1 Error if getting the ACL failed
1294 * \post Obtain the ACL, based on file ID
1296 * \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
1298 DECL_PIOCTL(PGetAcl)
1300 struct AFSOpaque acl;
1301 struct AFSVolSync tsync;
1302 struct AFSFetchStatus OutStatus;
1304 struct afs_conn *tconn;
1308 AFS_STATCNT(PGetAcl);
1311 Fid.Volume = avc->f.fid.Fid.Volume;
1312 Fid.Vnode = avc->f.fid.Fid.Vnode;
1313 Fid.Unique = avc->f.fid.Fid.Unique;
1314 if (avc->f.states & CForeign) {
1316 * For a dfs xlator acl we have a special hack so that the
1317 * xlator will distinguish which type of acl will return. So
1318 * we currently use the top 2-bytes (vals 0-4) to tell which
1319 * type of acl to bring back. Horrible hack but this will
1320 * cause the least number of changes to code size and interfaces.
1322 if (Fid.Vnode & 0xc0000000)
1324 Fid.Vnode |= (ainSize << 30);
1326 acl.AFSOpaque_val = aout;
1328 tconn = afs_Conn(&avc->f.fid, areq, SHARED_LOCK);
1331 XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_FETCHACL);
1333 code = RXAFS_FetchACL(tconn->id, &Fid, &acl, &OutStatus, &tsync);
1338 } while (afs_Analyze
1339 (tconn, code, &avc->f.fid, areq, AFS_STATS_FS_RPCIDX_FETCHACL,
1340 SHARED_LOCK, NULL));
1343 *aoutSize = (acl.AFSOpaque_len == 0 ? 1 : acl.AFSOpaque_len);
1349 * PNoop returns success. Used for functions which are not implemented or are no longer in use.
1353 * \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
1362 * PBogus returns fail. Used for functions which are not implemented or are no longer in use.
1366 * \retval EINVAL Error if some of the standard args aren't set
1368 * \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;
1372 AFS_STATCNT(PBogus);
1377 * VIOC_FILE_CELL_NAME (30) - Get cell in which file lives
1381 * \param[in] ain not in use (avc used to pass in file id)
1382 * \param[out] aout cell name
1384 * \retval EINVAL Error if some of the standard args aren't set
1385 * \retval ESRCH Error if the file isn't part of a cell
1387 * \post Get a cell based on a passed in file id
1389 DECL_PIOCTL(PGetFileCell)
1391 register struct cell *tcell;
1393 AFS_STATCNT(PGetFileCell);
1396 tcell = afs_GetCell(avc->f.fid.Cell, READ_LOCK);
1399 strcpy(aout, tcell->cellName);
1400 afs_PutCell(tcell, READ_LOCK);
1401 *aoutSize = strlen(aout) + 1;
1406 * VIOC_GET_WS_CELL (31) - Get cell in which workstation lives
1410 * \param[in] ain not in use
1411 * \param[out] aout cell name
1413 * \retval EIO Error if the afs daemon hasn't started yet
1414 * \retval ESRCH Error if the machine isn't part of a cell, for whatever reason
1416 * \post Get the primary cell that the machine is a part of.
1418 DECL_PIOCTL(PGetWSCell)
1420 struct cell *tcell = NULL;
1422 AFS_STATCNT(PGetWSCell);
1423 if (!afs_resourceinit_flag) /* afs daemons haven't started yet */
1424 return EIO; /* Inappropriate ioctl for device */
1426 tcell = afs_GetPrimaryCell(READ_LOCK);
1427 if (!tcell) /* no primary cell? */
1429 strcpy(aout, tcell->cellName);
1430 *aoutSize = strlen(aout) + 1;
1431 afs_PutCell(tcell, READ_LOCK);
1436 * VIOC_GET_PRIMARY_CELL (33) - Get primary cell for caller
1440 * \param[in] ain not in use (user id found via areq)
1441 * \param[out] aout cell name
1443 * \retval ESRCH Error if the user id doesn't have a primary cell specified
1445 * \post Get the primary cell for a certain user, based on the user's uid
1447 DECL_PIOCTL(PGetUserCell)
1449 register afs_int32 i;
1450 register struct unixuser *tu;
1451 register struct cell *tcell;
1453 AFS_STATCNT(PGetUserCell);
1454 if (!afs_resourceinit_flag) /* afs daemons haven't started yet */
1455 return EIO; /* Inappropriate ioctl for device */
1457 /* return the cell name of the primary cell for this user */
1458 i = UHash(areq->uid);
1459 ObtainWriteLock(&afs_xuser, 224);
1460 for (tu = afs_users[i]; tu; tu = tu->next) {
1461 if (tu->uid == areq->uid && (tu->states & UPrimary)) {
1463 ReleaseWriteLock(&afs_xuser);
1468 tcell = afs_GetCell(tu->cell, READ_LOCK);
1469 afs_PutUser(tu, WRITE_LOCK);
1473 strcpy(aout, tcell->cellName);
1474 afs_PutCell(tcell, READ_LOCK);
1475 *aoutSize = strlen(aout) + 1; /* 1 for the null */
1478 ReleaseWriteLock(&afs_xuser);
1486 * VIOCSETTOK (3) - Set authentication tokens
1490 * \param[in] ain the krb tickets from which to set the afs tokens
1491 * \param[out] aout not in use
1493 * \retval EINVAL Error if the ticket is either too long or too short
1494 * \retval EIO Error if the AFS initState is below 101
1495 * \retval ESRCH Error if the cell for which the Token is being set can't be found
1497 * \post Set the Tokens for a specific cell name, unless there is none set, then default to primary
1500 DECL_PIOCTL(PSetTokens)
1503 register struct unixuser *tu;
1504 struct ClearToken clear;
1505 register struct cell *tcell;
1508 struct vrequest treq;
1509 afs_int32 flag, set_parent_pag = 0;
1511 AFS_STATCNT(PSetTokens);
1512 if (!afs_resourceinit_flag) {
1515 memcpy((char *)&i, ain, sizeof(afs_int32));
1516 ain += sizeof(afs_int32);
1517 stp = ain; /* remember where the ticket is */
1518 if (i < 0 || i > MAXKTCTICKETLEN)
1519 return EINVAL; /* malloc may fail */
1521 ain += i; /* skip over ticket */
1522 memcpy((char *)&i, ain, sizeof(afs_int32));
1523 ain += sizeof(afs_int32);
1524 if (i != sizeof(struct ClearToken)) {
1527 memcpy((char *)&clear, ain, sizeof(struct ClearToken));
1528 if (clear.AuthHandle == -1)
1529 clear.AuthHandle = 999; /* more rxvab compat stuff */
1530 ain += sizeof(struct ClearToken);
1531 if (ainSize != 2 * sizeof(afs_int32) + stLen + sizeof(struct ClearToken)) {
1532 /* still stuff left? we've got primary flag and cell name. Set these */
1533 memcpy((char *)&flag, ain, sizeof(afs_int32)); /* primary id flag */
1534 ain += sizeof(afs_int32); /* skip id field */
1535 /* rest is cell name, look it up */
1536 /* some versions of gcc appear to need != 0 in order to get this right */
1537 if ((flag & 0x8000) != 0) { /* XXX Use Constant XXX */
1541 tcell = afs_GetCellByName(ain, READ_LOCK);
1545 /* default to primary cell, primary id */
1546 flag = 1; /* primary id */
1547 tcell = afs_GetPrimaryCell(READ_LOCK);
1552 afs_PutCell(tcell, READ_LOCK);
1553 if (set_parent_pag) {
1555 #if defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
1556 #if defined(AFS_DARWIN_ENV)
1557 struct proc *p = current_proc(); /* XXX */
1559 struct proc *p = curproc; /* XXX */
1561 #ifndef AFS_DARWIN80_ENV
1562 uprintf("Process %d (%s) tried to change pags in PSetTokens\n",
1563 p->p_pid, p->p_comm);
1565 if (!setpag(p, acred, -1, &pag, 1)) {
1568 if (!setpag(u.u_procp, acred, -1, &pag, 1)) { /* XXX u.u_procp is a no-op XXX */
1570 if (!setpag(acred, -1, &pag, 1)) {
1573 afs_InitReq(&treq, *acred);
1577 /* now we just set the tokens */
1578 tu = afs_GetUser(areq->uid, i, WRITE_LOCK); /* i has the cell # */
1579 tu->vid = clear.ViceId;
1580 if (tu->stp != NULL) {
1581 afs_osi_Free(tu->stp, tu->stLen);
1583 tu->stp = (char *)afs_osi_Alloc(stLen);
1584 if (tu->stp == NULL) {
1588 memcpy(tu->stp, stp, stLen);
1591 afs_stats_cmfullperf.authent.TicketUpdates++;
1592 afs_ComputePAGStats();
1593 #endif /* AFS_NOSTATS */
1594 tu->states |= UHasTokens;
1595 tu->states &= ~UTokensBad;
1596 afs_SetPrimary(tu, flag);
1597 tu->tokenTime = osi_Time();
1598 afs_ResetUserConns(tu);
1599 afs_PutUser(tu, WRITE_LOCK);
1615 * VIOCGETVOLSTAT (4) - Get volume status
1619 * \param[in] ain not in use
1620 * \param[out] aout status of the volume
1622 * \retval EINVAL Error if some of the standard args aren't set
1624 * \post The status of a volume (based on the FID of the volume), or an offline message /motd
1626 DECL_PIOCTL(PGetVolumeStatus)
1629 char *offLineMsg = afs_osi_Alloc(256);
1630 char *motd = afs_osi_Alloc(256);
1631 register struct afs_conn *tc;
1632 register afs_int32 code = 0;
1633 struct AFSFetchVolumeStatus volstat;
1635 char *Name, *OfflineMsg, *MOTD;
1638 AFS_STATCNT(PGetVolumeStatus);
1644 OfflineMsg = offLineMsg;
1647 tc = afs_Conn(&avc->f.fid, areq, SHARED_LOCK);
1649 XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_GETVOLUMESTATUS);
1652 RXAFS_GetVolumeStatus(tc->id, avc->f.fid.Fid.Volume, &volstat,
1653 &Name, &OfflineMsg, &MOTD);
1658 } while (afs_Analyze
1659 (tc, code, &avc->f.fid, areq, AFS_STATS_FS_RPCIDX_GETVOLUMESTATUS,
1660 SHARED_LOCK, NULL));
1664 /* Copy all this junk into msg->im_data, keeping track of the lengths. */
1666 memcpy(cp, (char *)&volstat, sizeof(VolumeStatus));
1667 cp += sizeof(VolumeStatus);
1668 strcpy(cp, volName);
1669 cp += strlen(volName) + 1;
1670 strcpy(cp, offLineMsg);
1671 cp += strlen(offLineMsg) + 1;
1673 cp += strlen(motd) + 1;
1674 *aoutSize = (cp - aout);
1676 afs_osi_Free(offLineMsg, 256);
1677 afs_osi_Free(motd, 256);
1682 * VIOCSETVOLSTAT (5) - Set volume status
1686 * \param[in] ain values to set the status at, offline message, message of the day, volume name, minimum quota, maximum quota
1687 * \param[out] aout status of a volume, offlines messages, minimum quota, maximumm quota
1689 * \retval EINVAL Error if some of the standard args aren't set
1690 * \retval EROFS Error if the volume is read only, or a backup volume
1691 * \retval ENODEV Error if the volume can't be accessed
1692 * \retval E2BIG Error if the volume name, offline message, and motd are too big
1694 * \post Set the status of a volume, including any offline messages, a minimum quota, and a maximum quota
1696 DECL_PIOCTL(PSetVolumeStatus)
1699 char *offLineMsg = afs_osi_Alloc(256);
1700 char *motd = afs_osi_Alloc(256);
1701 register struct afs_conn *tc;
1702 register afs_int32 code = 0;
1703 struct AFSFetchVolumeStatus volstat;
1704 struct AFSStoreVolumeStatus storeStat;
1705 register struct volume *tvp;
1709 AFS_STATCNT(PSetVolumeStatus);
1715 tvp = afs_GetVolume(&avc->f.fid, areq, READ_LOCK);
1717 if (tvp->states & (VRO | VBackup)) {
1718 afs_PutVolume(tvp, READ_LOCK);
1722 afs_PutVolume(tvp, READ_LOCK);
1727 /* Copy the junk out, using cp as a roving pointer. */
1729 memcpy((char *)&volstat, cp, sizeof(AFSFetchVolumeStatus));
1730 cp += sizeof(AFSFetchVolumeStatus);
1731 if (strlen(cp) >= sizeof(volName)) {
1735 strcpy(volName, cp);
1736 cp += strlen(volName) + 1;
1737 if (strlen(cp) >= sizeof(offLineMsg)) {
1741 strcpy(offLineMsg, cp);
1742 cp += strlen(offLineMsg) + 1;
1743 if (strlen(cp) >= sizeof(motd)) {
1749 if (volstat.MinQuota != -1) {
1750 storeStat.MinQuota = volstat.MinQuota;
1751 storeStat.Mask |= AFS_SETMINQUOTA;
1753 if (volstat.MaxQuota != -1) {
1754 storeStat.MaxQuota = volstat.MaxQuota;
1755 storeStat.Mask |= AFS_SETMAXQUOTA;
1758 tc = afs_Conn(&avc->f.fid, areq, SHARED_LOCK);
1760 XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_SETVOLUMESTATUS);
1763 RXAFS_SetVolumeStatus(tc->id, avc->f.fid.Fid.Volume, &storeStat,
1764 volName, offLineMsg, motd);
1769 } while (afs_Analyze
1770 (tc, code, &avc->f.fid, areq, AFS_STATS_FS_RPCIDX_SETVOLUMESTATUS,
1771 SHARED_LOCK, NULL));
1775 /* we are sending parms back to make compat. with prev system. should
1776 * change interface later to not ask for current status, just set new status */
1778 memcpy(cp, (char *)&volstat, sizeof(VolumeStatus));
1779 cp += sizeof(VolumeStatus);
1780 strcpy(cp, volName);
1781 cp += strlen(volName) + 1;
1782 strcpy(cp, offLineMsg);
1783 cp += strlen(offLineMsg) + 1;
1785 cp += strlen(motd) + 1;
1786 *aoutSize = cp - aout;
1788 afs_osi_Free(offLineMsg, 256);
1789 afs_osi_Free(motd, 256);
1794 * VIOCFLUSH (6) - Invalidate cache entry
1798 * \param[in] ain not in use
1799 * \param[out] aout not in use
1801 * \retval EINVAL Error if some of the standard args aren't set
1803 * \post Flush any information the cache manager has on an entry
1807 AFS_STATCNT(PFlush);
1810 #ifdef AFS_BOZONLOCK_ENV
1811 afs_BozonLock(&avc->pvnLock, avc); /* Since afs_TryToSmush will do a pvn_vptrunc */
1813 ObtainWriteLock(&avc->lock, 225);
1814 afs_ResetVCache(avc, *acred);
1815 ReleaseWriteLock(&avc->lock);
1816 #ifdef AFS_BOZONLOCK_ENV
1817 afs_BozonUnlock(&avc->pvnLock, avc);
1823 * VIOC_AFS_STAT_MT_PT (29) - Stat mount point
1827 * \param[in] ain the last component in a path, related to mountpoint that we're looking for information about
1828 * \param[out] aout volume, cell, link data
1830 * \retval EINVAL Error if some of the standard args aren't set
1831 * \retval ENOTDIR Error if the 'mount point' argument isn't a directory
1832 * \retval EIO Error if the link data can't be accessed
1834 * \post Get the volume, and cell, as well as the link data for a mount point
1836 DECL_PIOCTL(PNewStatMount)
1838 register afs_int32 code;
1839 register struct vcache *tvc;
1840 register struct dcache *tdc;
1841 struct VenusFid tfid;
1843 struct sysname_info sysState;
1844 afs_size_t offset, len;
1846 AFS_STATCNT(PNewStatMount);
1849 code = afs_VerifyVCache(avc, areq);
1852 if (vType(avc) != VDIR) {
1855 tdc = afs_GetDCache(avc, (afs_size_t) 0, areq, &offset, &len, 1);
1858 Check_AtSys(avc, ain, &sysState, areq);
1859 ObtainReadLock(&tdc->lock);
1861 code = afs_dir_Lookup(tdc, sysState.name, &tfid.Fid);
1862 } while (code == ENOENT && Next_AtSys(avc, areq, &sysState));
1863 ReleaseReadLock(&tdc->lock);
1864 afs_PutDCache(tdc); /* we're done with the data */
1865 bufp = sysState.name;
1869 tfid.Cell = avc->f.fid.Cell;
1870 tfid.Fid.Volume = avc->f.fid.Fid.Volume;
1871 if (!tfid.Fid.Unique && (avc->f.states & CForeign)) {
1872 tvc = afs_LookupVCache(&tfid, areq, NULL, avc, bufp);
1874 tvc = afs_GetVCache(&tfid, areq, NULL, NULL);
1880 if (tvc->mvstat != 1) {
1885 ObtainWriteLock(&tvc->lock, 226);
1886 code = afs_HandleLink(tvc, areq);
1888 if (tvc->linkData) {
1889 if ((tvc->linkData[0] != '#') && (tvc->linkData[0] != '%'))
1892 /* we have the data */
1893 strcpy(aout, tvc->linkData);
1894 *aoutSize = strlen(tvc->linkData) + 1;
1899 ReleaseWriteLock(&tvc->lock);
1902 if (sysState.allocked)
1903 osi_FreeLargeSpace(bufp);
1908 * VIOCGETTOK (8) - Get authentication tokens
1912 * \param[in] ain userid
1913 * \param[out] aout token
1915 * \retval EIO Error if the afs daemon hasn't started yet
1916 * \retval EDOM Error if the input parameter is out of the bounds of the available tokens
1917 * \retval ENOTCONN Error if there aren't tokens for this cell
1919 * \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
1921 * \notes "it's a weird interface (from comments in the code)"
1924 DECL_PIOCTL(PGetTokens)
1926 register struct cell *tcell;
1927 register afs_int32 i;
1928 register struct unixuser *tu;
1930 afs_int32 iterator = 0;
1933 AFS_STATCNT(PGetTokens);
1934 if (!afs_resourceinit_flag) /* afs daemons haven't started yet */
1935 return EIO; /* Inappropriate ioctl for device */
1937 /* weird interface. If input parameter is present, it is an integer and
1938 * we're supposed to return the parm'th tokens for this unix uid.
1939 * If not present, we just return tokens for cell 1.
1940 * If counter out of bounds, return EDOM.
1941 * If no tokens for the particular cell, return ENOTCONN.
1942 * Also, if this mysterious parm is present, we return, along with the
1943 * tokens, the primary cell indicator (an afs_int32 0) and the cell name
1944 * at the end, in that order.
1946 if ((newStyle = (ainSize > 0))) {
1947 memcpy((char *)&iterator, ain, sizeof(afs_int32));
1949 i = UHash(areq->uid);
1950 ObtainReadLock(&afs_xuser);
1951 for (tu = afs_users[i]; tu; tu = tu->next) {
1953 if (tu->uid == areq->uid && (tu->states & UHasTokens)) {
1954 if (iterator-- == 0)
1955 break; /* are we done yet? */
1958 if (tu->uid == areq->uid && afs_IsPrimaryCellNum(tu->cell))
1964 * No need to hold a read lock on each user entry
1968 ReleaseReadLock(&afs_xuser);
1973 if (((tu->states & UHasTokens) == 0)
1974 || (tu->ct.EndTimestamp < osi_Time())) {
1975 tu->states |= (UTokensBad | UNeedsReset);
1976 afs_PutUser(tu, READ_LOCK);
1979 /* use iterator for temp */
1981 iterator = tu->stLen; /* for compat, we try to return 56 byte tix if they fit */
1983 iterator = 56; /* # of bytes we're returning */
1984 memcpy(cp, (char *)&iterator, sizeof(afs_int32));
1985 cp += sizeof(afs_int32);
1986 memcpy(cp, tu->stp, tu->stLen); /* copy out st */
1988 iterator = sizeof(struct ClearToken);
1989 memcpy(cp, (char *)&iterator, sizeof(afs_int32));
1990 cp += sizeof(afs_int32);
1991 memcpy(cp, (char *)&tu->ct, sizeof(struct ClearToken));
1992 cp += sizeof(struct ClearToken);
1994 /* put out primary id and cell name, too */
1995 iterator = (tu->states & UPrimary ? 1 : 0);
1996 memcpy(cp, (char *)&iterator, sizeof(afs_int32));
1997 cp += sizeof(afs_int32);
1998 tcell = afs_GetCell(tu->cell, READ_LOCK);
2000 strcpy(cp, tcell->cellName);
2001 cp += strlen(tcell->cellName) + 1;
2002 afs_PutCell(tcell, READ_LOCK);
2006 *aoutSize = cp - aout;
2007 afs_PutUser(tu, READ_LOCK);
2012 * VIOCUNLOG (9) - Invalidate tokens
2016 * \param[in] ain not in use
2017 * \param[out] aout not in use
2019 * \retval EIO Error if the afs daemon hasn't been started yet
2021 * \post remove tokens from a user, specified by the user id
2023 * \notes sets the token's time to 0, which then causes it to be removed
2024 * \notes Unlog is the same as un-pag in OpenAFS
2028 register afs_int32 i;
2029 register struct unixuser *tu;
2031 AFS_STATCNT(PUnlog);
2032 if (!afs_resourceinit_flag) /* afs daemons haven't started yet */
2033 return EIO; /* Inappropriate ioctl for device */
2035 i = UHash(areq->uid);
2036 ObtainWriteLock(&afs_xuser, 227);
2037 for (tu = afs_users[i]; tu; tu = tu->next) {
2038 if (tu->uid == areq->uid) {
2040 tu->states &= ~UHasTokens;
2041 /* security is not having to say you're sorry */
2042 memset((char *)&tu->ct, 0, sizeof(struct ClearToken));
2044 ReleaseWriteLock(&afs_xuser);
2045 /* We have to drop the lock over the call to afs_ResetUserConns, since
2046 * it obtains the afs_xvcache lock. We could also keep the lock, and
2047 * modify ResetUserConns to take parm saying we obtained the lock
2048 * already, but that is overkill. By keeping the "tu" pointer
2049 * held over the released lock, we guarantee that we won't lose our
2050 * place, and that we'll pass over every user conn that existed when
2051 * we began this call.
2053 afs_ResetUserConns(tu);
2055 ObtainWriteLock(&afs_xuser, 228);
2057 /* set the expire times to 0, causes
2058 * afs_GCUserData to remove this entry
2060 tu->ct.EndTimestamp = 0;
2062 #endif /* UKERNEL */
2065 ReleaseWriteLock(&afs_xuser);
2070 * VIOC_AFS_MARINER_HOST (32) - Get/set mariner (cache manager monitor) host
2074 * \param[in] ain host address to be set
2075 * \param[out] aout old host address
2077 * \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
2079 * \notes Errors turn off mariner
2081 DECL_PIOCTL(PMariner)
2083 afs_int32 newHostAddr;
2084 afs_int32 oldHostAddr;
2086 AFS_STATCNT(PMariner);
2088 memcpy((char *)&oldHostAddr, (char *)&afs_marinerHost,
2091 oldHostAddr = 0xffffffff; /* disabled */
2093 memcpy((char *)&newHostAddr, ain, sizeof(afs_int32));
2094 if (newHostAddr == 0xffffffff) {
2095 /* disable mariner operations */
2097 } else if (newHostAddr) {
2099 afs_marinerHost = newHostAddr;
2101 memcpy(aout, (char *)&oldHostAddr, sizeof(afs_int32));
2102 *aoutSize = sizeof(afs_int32);
2107 * VIOCCKSERV (10) - Check that servers are up
2111 * \param[in] ain name of the cell
2112 * \param[out] aout current down server list
2114 * \retval EIO Error if the afs daemon hasn't started yet
2115 * \retval EACCES Error if the user doesn't have super-user credentials
2116 * \retval ENOENT Error if we are unable to obtain the cell
2118 * \post Either a fast check (where it doesn't contact servers) or a local check (checks local cell only)
2120 DECL_PIOCTL(PCheckServers)
2122 register char *cp = 0;
2124 register struct server *ts;
2125 afs_int32 temp, *lp = (afs_int32 *) ain, havecell = 0;
2127 struct chservinfo *pcheck;
2129 AFS_STATCNT(PCheckServers);
2131 if (!afs_resourceinit_flag) /* afs daemons haven't started yet */
2132 return EIO; /* Inappropriate ioctl for device */
2134 if (*lp == 0x12345678) { /* For afs3.3 version */
2135 pcheck = (struct chservinfo *)ain;
2136 if (pcheck->tinterval >= 0) {
2138 memcpy(cp, (char *)&afs_probe_interval, sizeof(afs_int32));
2139 *aoutSize = sizeof(afs_int32);
2140 if (pcheck->tinterval > 0) {
2141 if (!afs_osi_suser(*acred))
2143 afs_probe_interval = pcheck->tinterval;
2149 temp = pcheck->tflags;
2150 cp = pcheck->tbuffer;
2151 } else { /* For pre afs3.3 versions */
2152 memcpy((char *)&temp, ain, sizeof(afs_int32));
2153 cp = ain + sizeof(afs_int32);
2154 if (ainSize > sizeof(afs_int32))
2159 * 1: fast check, don't contact servers.
2160 * 2: local cell only.
2163 /* have cell name, too */
2164 cellp = afs_GetCellByName(cp, READ_LOCK);
2169 if (!cellp && (temp & 2)) {
2170 /* use local cell */
2171 cellp = afs_GetPrimaryCell(READ_LOCK);
2173 if (!(temp & 1)) { /* if not fast, call server checker routine */
2174 afs_CheckServers(1, cellp); /* check down servers */
2175 afs_CheckServers(0, cellp); /* check up servers */
2177 /* now return the current down server list */
2179 ObtainReadLock(&afs_xserver);
2180 for (i = 0; i < NSERVERS; i++) {
2181 for (ts = afs_servers[i]; ts; ts = ts->next) {
2182 if (cellp && ts->cell != cellp)
2183 continue; /* cell spec'd and wrong */
2184 if ((ts->flags & SRVR_ISDOWN)
2185 && ts->addr->sa_portal != ts->cell->vlport) {
2186 memcpy(cp, (char *)&ts->addr->sa_ip, sizeof(afs_int32));
2187 cp += sizeof(afs_int32);
2191 ReleaseReadLock(&afs_xserver);
2193 afs_PutCell(cellp, READ_LOCK);
2194 *aoutSize = cp - aout;
2199 * VIOCCKBACK (11) - Check backup volume mappings
2203 * \param[in] ain not in use
2204 * \param[out] aout not in use
2206 * \retval EIO Error if the afs daemon hasn't started yet
2208 * \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
2210 DECL_PIOCTL(PCheckVolNames)
2212 AFS_STATCNT(PCheckVolNames);
2213 if (!afs_resourceinit_flag) /* afs daemons haven't started yet */
2214 return EIO; /* Inappropriate ioctl for device */
2216 afs_CheckRootVolume();
2217 afs_CheckVolumeNames(AFS_VOLCHECK_FORCE | AFS_VOLCHECK_EXPIRED |
2218 AFS_VOLCHECK_BUSY | AFS_VOLCHECK_MTPTS);
2223 * VIOCCKCONN (12) - Check connections for a user
2227 * \param[in] ain not in use
2228 * \param[out] aout not in use
2230 * \retval EACCESS Error if no user is specififed, the user has no tokens set, or if the user's tokens are bad
2232 * \post check to see if a user has the correct authentication. If so, allow access.
2234 * \notes Check the connections to all the servers specified
2236 DECL_PIOCTL(PCheckAuth)
2240 struct afs_conn *tc;
2241 struct unixuser *tu;
2244 AFS_STATCNT(PCheckAuth);
2245 if (!afs_resourceinit_flag) /* afs daemons haven't started yet */
2246 return EIO; /* Inappropriate ioctl for device */
2249 tu = afs_GetUser(areq->uid, 1, READ_LOCK); /* check local cell authentication */
2253 /* we have a user */
2254 ObtainReadLock(&afs_xsrvAddr);
2255 ObtainReadLock(&afs_xconn);
2257 /* any tokens set? */
2258 if ((tu->states & UHasTokens) == 0)
2260 /* all connections in cell 1 working? */
2261 for (i = 0; i < NSERVERS; i++) {
2262 for (sa = afs_srvAddrs[i]; sa; sa = sa->next_bkt) {
2263 for (tc = sa->conns; tc; tc = tc->next) {
2264 if (tc->user == tu && (tu->states & UTokensBad))
2269 ReleaseReadLock(&afs_xsrvAddr);
2270 ReleaseReadLock(&afs_xconn);
2271 afs_PutUser(tu, READ_LOCK);
2273 memcpy(aout, (char *)&retValue, sizeof(afs_int32));
2274 *aoutSize = sizeof(afs_int32);
2279 Prefetch(char *apath, struct afs_ioctl *adata, int afollow,
2280 struct AFS_UCRED *acred)
2283 register afs_int32 code;
2284 #if defined(AFS_SGI61_ENV) || defined(AFS_SUN57_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
2290 AFS_STATCNT(Prefetch);
2293 tp = osi_AllocLargeSpace(1024);
2294 AFS_COPYINSTR(apath, tp, 1024, &bufferSize, code);
2296 osi_FreeLargeSpace(tp);
2299 if (afs_BBusy()) { /* do this as late as possible */
2300 osi_FreeLargeSpace(tp);
2301 return EWOULDBLOCK; /* pretty close */
2303 afs_BQueue(BOP_PATH, (struct vcache *)0, 0, 0, acred, (afs_size_t) 0,
2304 (afs_size_t) 0, tp);
2309 * VIOCWHEREIS (14) - Find out where a volume is located
2313 * \param[in] ain not in use
2314 * \param[out] aout volume location
2316 * \retval EINVAL Error if some of the default arguments don't exist
2317 * \retval ENODEV Error if there is no such volume
2319 * \post fine a volume, based on a volume file id
2321 * \notes check each of the servers specified
2323 DECL_PIOCTL(PFindVolume)
2325 register struct volume *tvp;
2326 register struct server *ts;
2327 register afs_int32 i;
2330 AFS_STATCNT(PFindVolume);
2333 tvp = afs_GetVolume(&avc->f.fid, areq, READ_LOCK);
2336 for (i = 0; i < MAXHOSTS; i++) {
2337 ts = tvp->serverHost[i];
2340 memcpy(cp, (char *)&ts->addr->sa_ip, sizeof(afs_int32));
2341 cp += sizeof(afs_int32);
2344 /* still room for terminating NULL, add it on */
2345 ainSize = 0; /* reuse vbl */
2346 memcpy(cp, (char *)&ainSize, sizeof(afs_int32));
2347 cp += sizeof(afs_int32);
2349 *aoutSize = cp - aout;
2350 afs_PutVolume(tvp, READ_LOCK);
2357 * VIOCACCESS (20) - Access using PRS_FS bits
2361 * \param[in] ain PRS_FS bits
2362 * \param[out] aout not in use
2364 * \retval EINVAL Error if some of the initial arguments aren't set
2365 * \retval EACCES Error if access is denied
2367 * \post check to make sure access is allowed
2369 DECL_PIOCTL(PViceAccess)
2371 register afs_int32 code;
2374 AFS_STATCNT(PViceAccess);
2377 code = afs_VerifyVCache(avc, areq);
2380 memcpy((char *)&temp, ain, sizeof(afs_int32));
2381 code = afs_AccessOK(avc, temp, areq, CHECK_MODE_BITS);
2389 * VIOC_GETPAG (13) - Get PAG value
2393 * \param[in] ain not in use
2394 * \param[out] aout PAG value or NOPAG
2396 * \retval E2BIG Error not enough space to copy out value
2398 * \post get PAG value for the caller's cred
2400 DECL_PIOCTL(PGetPAG)
2404 if (*aoutSize < sizeof(afs_int32)) {
2408 pag = PagInCred(*acred);
2410 memcpy(aout, (char *)&pag, sizeof(afs_int32));
2411 *aoutSize = sizeof(afs_int32);
2415 DECL_PIOCTL(PPrecache)
2419 /*AFS_STATCNT(PPrecache);*/
2420 if (!afs_osi_suser(*acred))
2422 memcpy((char *)&newValue, ain, sizeof(afs_int32));
2423 afs_preCache = newValue*1024;
2428 * VIOCSETCACHESIZE (24) - Set venus cache size in 1000 units
2432 * \param[in] ain the size the venus cache should be set to
2433 * \param[out] aout not in use
2435 * \retval EACCES Error if the user doesn't have super-user credentials
2436 * \retval EROFS Error if the cache is set to be in memory
2438 * \post Set the cache size based on user input. If no size is given, set it to the default OpenAFS cache size.
2440 * \notes recompute the general cache parameters for every single block allocated
2442 DECL_PIOCTL(PSetCacheSize)
2447 AFS_STATCNT(PSetCacheSize);
2448 if (!afs_osi_suser(*acred))
2450 /* too many things are setup initially in mem cache version */
2451 if (cacheDiskType == AFS_FCACHE_TYPE_MEM)
2453 memcpy((char *)&newValue, ain, sizeof(afs_int32));
2455 afs_cacheBlocks = afs_stats_cmperf.cacheBlocksOrig;
2457 if (newValue < afs_min_cache)
2458 afs_cacheBlocks = afs_min_cache;
2460 afs_cacheBlocks = newValue;
2462 afs_stats_cmperf.cacheBlocksTotal = afs_cacheBlocks;
2463 afs_ComputeCacheParms(); /* recompute basic cache parameters */
2464 afs_MaybeWakeupTruncateDaemon();
2465 while (waitcnt++ < 100 && afs_cacheBlocks < afs_blocksUsed) {
2466 afs_osi_Wait(1000, 0, 0);
2467 afs_MaybeWakeupTruncateDaemon();
2472 #define MAXGCSTATS 16
2474 * VIOCGETCACHEPARMS (40) - Get cache stats
2478 * \param[in] ain afs index flags
2479 * \param[out] aout cache blocks, blocks used, blocks files (in an array)
2481 * \post Get the cache blocks, and how many of the cache blocks there are
2483 DECL_PIOCTL(PGetCacheSize)
2485 afs_int32 results[MAXGCSTATS];
2487 register struct dcache * tdc;
2490 AFS_STATCNT(PGetCacheSize);
2492 if (sizeof(afs_int32) == ainSize){
2493 memcpy((char *)&flags, ain, sizeof(afs_int32));
2494 } else if (0 == ainSize){
2500 memset((char *)results, 0, sizeof(results));
2501 results[0] = afs_cacheBlocks;
2502 results[1] = afs_blocksUsed;
2503 results[2] = afs_cacheFiles;
2506 for (i = 0; i < afs_cacheFiles; i++) {
2507 if (afs_indexFlags[i] & IFFree) results[3]++;
2509 } else if (2 == flags){
2510 for (i = 0; i < afs_cacheFiles; i++) {
2511 if (afs_indexFlags[i] & IFFree) results[3]++;
2512 if (afs_indexFlags[i] & IFEverUsed) results[4]++;
2513 if (afs_indexFlags[i] & IFDataMod) results[5]++;
2514 if (afs_indexFlags[i] & IFDirtyPages) results[6]++;
2515 if (afs_indexFlags[i] & IFAnyPages) results[7]++;
2516 if (afs_indexFlags[i] & IFDiscarded) results[8]++;
2518 tdc = afs_indexTable[i];
2521 size = tdc->validPos;
2522 if ( 0 < size && size < (1<<12) ) results[10]++;
2523 else if (size < (1<<14) ) results[11]++;
2524 else if (size < (1<<16) ) results[12]++;
2525 else if (size < (1<<18) ) results[13]++;
2526 else if (size < (1<<20) ) results[14]++;
2527 else if (size >= (1<<20) ) results[15]++;
2531 memcpy(aout, (char *)results, sizeof(results));
2532 *aoutSize = sizeof(results);
2537 * VIOCFLUSHCB (25) - Flush callback only
2541 * \param[in] ain not in use
2542 * \param[out] aout not in use
2544 * \retval EINVAL Error if some of the standard args aren't set
2545 * \retval 0 0 returned if the volume is set to read-only
2547 * \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.
2549 DECL_PIOCTL(PRemoveCallBack)
2551 register struct afs_conn *tc;
2552 register afs_int32 code = 0;
2553 struct AFSCallBack CallBacks_Array[1];
2554 struct AFSCBFids theFids;
2555 struct AFSCBs theCBs;
2558 AFS_STATCNT(PRemoveCallBack);
2561 if (avc->f.states & CRO)
2562 return 0; /* read-only-ness can't change */
2563 ObtainWriteLock(&avc->lock, 229);
2564 theFids.AFSCBFids_len = 1;
2565 theCBs.AFSCBs_len = 1;
2566 theFids.AFSCBFids_val = (struct AFSFid *)&avc->f.fid.Fid;
2567 theCBs.AFSCBs_val = CallBacks_Array;
2568 CallBacks_Array[0].CallBackType = CB_DROPPED;
2569 if (avc->callback) {
2571 tc = afs_Conn(&avc->f.fid, areq, SHARED_LOCK);
2573 XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_GIVEUPCALLBACKS);
2575 code = RXAFS_GiveUpCallBacks(tc->id, &theFids, &theCBs);
2579 /* don't set code on failure since we wouldn't use it */
2580 } while (afs_Analyze
2581 (tc, code, &avc->f.fid, areq,
2582 AFS_STATS_FS_RPCIDX_GIVEUPCALLBACKS, SHARED_LOCK, NULL));
2584 ObtainWriteLock(&afs_xcbhash, 457);
2585 afs_DequeueCallback(avc);
2587 avc->f.states &= ~(CStatd | CUnique);
2588 ReleaseWriteLock(&afs_xcbhash);
2589 if (avc->f.fid.Fid.Vnode & 1 || (vType(avc) == VDIR))
2590 osi_dnlc_purgedp(avc);
2592 ReleaseWriteLock(&avc->lock);
2597 * VIOCNEWCELL (26) - Configure new cell
2601 * \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
2602 * \param[out] aout not in use
2604 * \retval EIO Error if the afs daemon hasn't started yet
2605 * \retval EACCES Error if the user doesn't have super-user cedentials
2606 * \retval EINVAL Error if some 'magic' var doesn't have a certain bit set
2608 * \post creates a new cell
2610 DECL_PIOCTL(PNewCell)
2612 /* create a new cell */
2613 afs_int32 cellHosts[MAXCELLHOSTS], *lp, magic = 0;
2614 char *newcell = 0, *linkedcell = 0, *tp = ain;
2615 register afs_int32 code, linkedstate = 0, ls;
2616 u_short fsport = 0, vlport = 0;
2619 AFS_STATCNT(PNewCell);
2620 if (!afs_resourceinit_flag) /* afs daemons haven't started yet */
2621 return EIO; /* Inappropriate ioctl for device */
2623 if (!afs_osi_suser(*acred))
2626 memcpy((char *)&magic, tp, sizeof(afs_int32));
2627 tp += sizeof(afs_int32);
2628 if (magic != 0x12345678)
2631 /* A 3.4 fs newcell command will pass an array of MAXCELLHOSTS
2632 * server addresses while the 3.5 fs newcell command passes
2633 * MAXHOSTS. To figure out which is which, check if the cellname
2636 newcell = tp + (MAXCELLHOSTS + 3) * sizeof(afs_int32);
2637 scount = ((newcell[0] != '\0') ? MAXCELLHOSTS : MAXHOSTS);
2639 /* MAXCELLHOSTS (=8) is less than MAXHOSTS (=13) */
2640 memcpy((char *)cellHosts, tp, MAXCELLHOSTS * sizeof(afs_int32));
2641 tp += (scount * sizeof(afs_int32));
2643 lp = (afs_int32 *) tp;
2647 fsport = 0; /* Privileged ports not allowed */
2649 vlport = 0; /* Privileged ports not allowed */
2650 tp += (3 * sizeof(afs_int32));
2652 if ((ls = *lp) & 1) {
2653 linkedcell = tp + strlen(newcell) + 1;
2654 linkedstate |= CLinkedCell;
2657 linkedstate |= CNoSUID; /* setuid is disabled by default for fs newcell */
2659 afs_NewCell(newcell, cellHosts, linkedstate, linkedcell, fsport,
2664 DECL_PIOCTL(PNewAlias)
2666 /* create a new cell alias */
2668 register afs_int32 code;
2669 char *realName, *aliasName;
2671 if (!afs_resourceinit_flag) /* afs daemons haven't started yet */
2672 return EIO; /* Inappropriate ioctl for device */
2674 if (!afs_osi_suser(*acred))
2678 tp += strlen(aliasName) + 1;
2681 code = afs_NewCellAlias(aliasName, realName);
2687 * VIOCGETCELL (27) - Get cell info
2691 * \param[in] ain The cell index of a specific cell
2692 * \param[out] aout list of servers in the cell
2694 * \retval EIO Error if the afs daemon hasn't started yet
2695 * \retval EDOM Error if there is no cell asked about
2697 * \post Lists the cell's server names and and addresses
2699 DECL_PIOCTL(PListCells)
2701 afs_int32 whichCell;
2702 register struct cell *tcell = 0;
2703 register afs_int32 i;
2704 register char *cp, *tp = ain;
2706 AFS_STATCNT(PListCells);
2707 if (!afs_resourceinit_flag) /* afs daemons haven't started yet */
2708 return EIO; /* Inappropriate ioctl for device */
2710 memcpy((char *)&whichCell, tp, sizeof(afs_int32));
2711 tp += sizeof(afs_int32);
2712 tcell = afs_GetCellByIndex(whichCell, READ_LOCK);
2715 memset(cp, 0, MAXCELLHOSTS * sizeof(afs_int32));
2716 for (i = 0; i < MAXCELLHOSTS; i++) {
2717 if (tcell->cellHosts[i] == 0)
2719 memcpy(cp, (char *)&tcell->cellHosts[i]->addr->sa_ip,
2721 cp += sizeof(afs_int32);
2723 cp = aout + MAXCELLHOSTS * sizeof(afs_int32);
2724 strcpy(cp, tcell->cellName);
2725 cp += strlen(tcell->cellName) + 1;
2726 *aoutSize = cp - aout;
2727 afs_PutCell(tcell, READ_LOCK);
2735 DECL_PIOCTL(PListAliases)
2737 afs_int32 whichAlias;
2738 register struct cell_alias *tcalias = 0;
2739 register char *cp, *tp = ain;
2741 if (!afs_resourceinit_flag) /* afs daemons haven't started yet */
2742 return EIO; /* Inappropriate ioctl for device */
2743 if (ainSize < sizeof(afs_int32))
2746 memcpy((char *)&whichAlias, tp, sizeof(afs_int32));
2747 tp += sizeof(afs_int32);
2749 tcalias = afs_GetCellAlias(whichAlias);
2752 strcpy(cp, tcalias->alias);
2753 cp += strlen(tcalias->alias) + 1;
2754 strcpy(cp, tcalias->cell);
2755 cp += strlen(tcalias->cell) + 1;
2756 *aoutSize = cp - aout;
2757 afs_PutCellAlias(tcalias);
2766 * VIOC_AFS_DELETE_MT_PT (28) - Delete mount point
2770 * \param[in] ain the name of the file in this dir to remove
2771 * \param[out] aout not in use
2773 * \retval EINVAL Error if some of the standard args aren't set
2774 * \retval ENOTDIR Error if the argument to remove is not a directory
2775 * \retval ENOENT Error if there is no cache to remove the mount point from or if a vcache doesn't exist
2777 * \post Ensure that everything is OK before deleting the mountpoint. If not, don't delete. Delete a mount point based on a file id.
2779 DECL_PIOCTL(PRemoveMount)
2781 register afs_int32 code;
2783 struct sysname_info sysState;
2784 afs_size_t offset, len;
2785 register struct afs_conn *tc;
2786 register struct dcache *tdc;
2787 register struct vcache *tvc;
2788 struct AFSFetchStatus OutDirStatus;
2789 struct VenusFid tfid;
2790 struct AFSVolSync tsync;
2794 /* "ain" is the name of the file in this dir to remove */
2796 AFS_STATCNT(PRemoveMount);
2799 code = afs_VerifyVCache(avc, areq);
2802 if (vType(avc) != VDIR)
2805 tdc = afs_GetDCache(avc, (afs_size_t) 0, areq, &offset, &len, 1); /* test for error below */
2808 Check_AtSys(avc, ain, &sysState, areq);
2809 ObtainReadLock(&tdc->lock);
2811 code = afs_dir_Lookup(tdc, sysState.name, &tfid.Fid);
2812 } while (code == ENOENT && Next_AtSys(avc, areq, &sysState));
2813 ReleaseReadLock(&tdc->lock);
2814 bufp = sysState.name;
2819 tfid.Cell = avc->f.fid.Cell;
2820 tfid.Fid.Volume = avc->f.fid.Fid.Volume;
2821 if (!tfid.Fid.Unique && (avc->f.states & CForeign)) {
2822 tvc = afs_LookupVCache(&tfid, areq, NULL, avc, bufp);
2824 tvc = afs_GetVCache(&tfid, areq, NULL, NULL);
2831 if (tvc->mvstat != 1) {
2837 ObtainWriteLock(&tvc->lock, 230);
2838 code = afs_HandleLink(tvc, areq);
2840 if (tvc->linkData) {
2841 if ((tvc->linkData[0] != '#') && (tvc->linkData[0] != '%'))
2846 ReleaseWriteLock(&tvc->lock);
2847 osi_dnlc_purgedp(tvc);
2853 ObtainWriteLock(&avc->lock, 231);
2854 osi_dnlc_remove(avc, bufp, tvc);
2856 tc = afs_Conn(&avc->f.fid, areq, SHARED_LOCK);
2858 XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_REMOVEFILE);
2861 RXAFS_RemoveFile(tc->id, (struct AFSFid *)&avc->f.fid.Fid, bufp,
2862 &OutDirStatus, &tsync);
2867 } while (afs_Analyze
2868 (tc, code, &avc->f.fid, areq, AFS_STATS_FS_RPCIDX_REMOVEFILE,
2869 SHARED_LOCK, NULL));
2874 ReleaseWriteLock(&avc->lock);
2878 /* we have the thing in the cache */
2879 ObtainWriteLock(&tdc->lock, 661);
2880 if (afs_LocalHero(avc, tdc, &OutDirStatus, 1)) {
2881 /* we can do it locally */
2882 code = afs_dir_Delete(tdc, bufp);
2884 ZapDCE(tdc); /* surprise error -- invalid value */
2888 ReleaseWriteLock(&tdc->lock);
2889 afs_PutDCache(tdc); /* drop ref count */
2891 avc->f.states &= ~CUnique; /* For the dfs xlator */
2892 ReleaseWriteLock(&avc->lock);
2895 if (sysState.allocked)
2896 osi_FreeLargeSpace(bufp);
2901 * VIOC_VENUSLOG (34) - Enable/Disable venus logging
2905 * \retval EINVAL Error if some of the standard args aren't set
2907 * \notes Obsoleted, perhaps should be PBogus
2909 DECL_PIOCTL(PVenusLogging)
2911 return EINVAL; /* OBSOLETE */
2915 * VIOC_GETCELLSTATUS (35) - Get cell status info
2919 * \param[in] ain The cell you want status information on
2920 * \param[out] aout cell state (as a struct)
2922 * \retval EIO Error if the afs daemon hasn't started yet
2923 * \retval ENOENT Error if the cell doesn't exist
2925 * \post Returns the state of the cell as defined in a struct cell
2927 DECL_PIOCTL(PGetCellStatus)
2929 register struct cell *tcell;
2932 AFS_STATCNT(PGetCellStatus);
2933 if (!afs_resourceinit_flag) /* afs daemons haven't started yet */
2934 return EIO; /* Inappropriate ioctl for device */
2936 tcell = afs_GetCellByName(ain, READ_LOCK);
2939 temp = tcell->states;
2940 afs_PutCell(tcell, READ_LOCK);
2941 memcpy(aout, (char *)&temp, sizeof(afs_int32));
2942 *aoutSize = sizeof(afs_int32);
2947 * VIOC_SETCELLSTATUS (36) - Set corresponding info
2951 * \param[in] ain The cell you want to set information about, and the values you want to set
2952 * \param[out] aout not in use
2954 * \retval EIO Error if the afs daemon hasn't started yet
2955 * \retval EACCES Error if the user doesn't have super-user credentials
2957 * \post Set the state of the cell in a defined struct cell, based on whether or not SetUID is allowed
2959 DECL_PIOCTL(PSetCellStatus)
2961 register struct cell *tcell;
2964 if (!afs_osi_suser(*acred))
2966 if (!afs_resourceinit_flag) /* afs daemons haven't started yet */
2967 return EIO; /* Inappropriate ioctl for device */
2969 tcell = afs_GetCellByName(ain + 2 * sizeof(afs_int32), WRITE_LOCK);
2972 memcpy((char *)&temp, ain, sizeof(afs_int32));
2974 tcell->states |= CNoSUID;
2976 tcell->states &= ~CNoSUID;
2977 afs_PutCell(tcell, WRITE_LOCK);
2982 * VIOC_FLUSHVOLUME (37) - Flush whole volume's data
2986 * \param[in] ain not in use (args in avc)
2987 * \param[out] aout not in use
2989 * \retval EINVAL Error if some of the standard args aren't set
2990 * \retval EIO Error if the afs daemon hasn't started yet
2992 * \post Wipe everything on the volume. This is done dependent on which platform this is for.
2994 * \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.
2996 DECL_PIOCTL(PFlushVolumeData)
2998 register afs_int32 i;
2999 register struct dcache *tdc;
3000 register struct vcache *tvc;
3001 register struct volume *tv;
3002 afs_int32 cell, volume;
3003 struct afs_q *tq, *uq;
3004 #ifdef AFS_DARWIN80_ENV
3008 AFS_STATCNT(PFlushVolumeData);
3011 if (!afs_resourceinit_flag) /* afs daemons haven't started yet */
3012 return EIO; /* Inappropriate ioctl for device */
3014 volume = avc->f.fid.Fid.Volume; /* who to zap */
3015 cell = avc->f.fid.Cell;
3018 * Clear stat'd flag from all vnodes from this volume; this will invalidate all
3019 * the vcaches associated with the volume.
3022 ObtainReadLock(&afs_xvcache);
3023 i = VCHashV(&avc->f.fid);
3024 for (tq = afs_vhashTV[i].prev; tq != &afs_vhashTV[i]; tq = uq) {
3027 if (tvc->f.fid.Fid.Volume == volume && tvc->f.fid.Cell == cell) {
3028 if (tvc->f.states & CVInit) {
3029 ReleaseReadLock(&afs_xvcache);
3030 afs_osi_Sleep(&tvc->f.states);
3033 #ifdef AFS_DARWIN80_ENV
3034 if (tvc->f.states & CDeadVnode) {
3035 ReleaseReadLock(&afs_xvcache);
3036 afs_osi_Sleep(&tvc->f.states);
3040 #if defined(AFS_SGI_ENV) || defined(AFS_OSF_ENV) || defined(AFS_SUN5_ENV) || defined(AFS_HPUX_ENV) || defined(AFS_LINUX20_ENV)
3041 VN_HOLD(AFSTOV(tvc));
3043 #ifdef AFS_DARWIN80_ENV
3047 if (vnode_ref(vp)) {
3054 #if defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
3057 VREFCOUNT_INC(tvc); /* AIX, apparently */
3061 ReleaseReadLock(&afs_xvcache);
3062 #ifdef AFS_BOZONLOCK_ENV
3063 afs_BozonLock(&tvc->pvnLock, tvc); /* Since afs_TryToSmush will do a pvn_vptrunc */
3065 ObtainWriteLock(&tvc->lock, 232);
3067 ObtainWriteLock(&afs_xcbhash, 458);
3068 afs_DequeueCallback(tvc);
3069 tvc->f.states &= ~(CStatd | CDirty);
3070 ReleaseWriteLock(&afs_xcbhash);
3071 if (tvc->f.fid.Fid.Vnode & 1 || (vType(tvc) == VDIR))
3072 osi_dnlc_purgedp(tvc);
3073 afs_TryToSmush(tvc, *acred, 1);
3074 ReleaseWriteLock(&tvc->lock);
3075 #ifdef AFS_BOZONLOCK_ENV
3076 afs_BozonUnlock(&tvc->pvnLock, tvc);
3078 #ifdef AFS_DARWIN80_ENV
3079 vnode_put(AFSTOV(tvc));
3081 ObtainReadLock(&afs_xvcache);
3083 /* our tvc ptr is still good until now */
3087 ReleaseReadLock(&afs_xvcache);
3090 MObtainWriteLock(&afs_xdcache, 328); /* needed if you're going to flush any stuff */
3091 for (i = 0; i < afs_cacheFiles; i++) {
3092 if (!(afs_indexFlags[i] & IFEverUsed))
3093 continue; /* never had any data */
3094 tdc = afs_GetDSlot(i, NULL);
3095 if (tdc->refCount <= 1) { /* too high, in use by running sys call */
3096 ReleaseReadLock(&tdc->tlock);
3097 if (tdc->f.fid.Fid.Volume == volume && tdc->f.fid.Cell == cell) {
3098 if (!(afs_indexFlags[i] & IFDataMod)) {
3099 /* if the file is modified, but has a ref cnt of only 1, then
3100 * someone probably has the file open and is writing into it.
3101 * Better to skip flushing such a file, it will be brought back
3102 * immediately on the next write anyway.
3104 * If we *must* flush, then this code has to be rearranged to call
3105 * afs_storeAllSegments() first */
3106 afs_FlushDCache(tdc);
3110 ReleaseReadLock(&tdc->tlock);
3112 afs_PutDCache(tdc); /* bumped by getdslot */
3114 MReleaseWriteLock(&afs_xdcache);
3116 ObtainReadLock(&afs_xvolume);
3117 for (i = 0; i < NVOLS; i++) {
3118 for (tv = afs_volumes[i]; tv; tv = tv->next) {
3119 if (tv->volume == volume) {
3120 afs_ResetVolumeInfo(tv);
3125 ReleaseReadLock(&afs_xvolume);
3127 /* probably, a user is doing this, probably, because things are screwed up.
3128 * maybe it's the dnlc's fault? */
3135 * VIOCGETVCXSTATUS (41) - gets vnode x status
3139 * \param[in] ain not in use (avc used)
3140 * \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
3142 * \retval EINVAL Error if some of the initial default arguments aren't set
3143 * \retval EACCES Error if access to check the mode bits is denied
3145 * \post gets stats for the vnode, a struct listed in vcxstat
3147 DECL_PIOCTL(PGetVnodeXStatus)
3149 register afs_int32 code;
3150 struct vcxstat stat;
3153 /* AFS_STATCNT(PGetVnodeXStatus); */
3156 code = afs_VerifyVCache(avc, areq);
3159 if (vType(avc) == VDIR)
3160 mode = PRSFS_LOOKUP;
3163 if (!afs_AccessOK(avc, mode, areq, CHECK_MODE_BITS))
3166 memset(&stat, 0, sizeof(struct vcxstat));
3167 stat.fid = avc->f.fid;
3168 hset32(stat.DataVersion, hgetlo(avc->f.m.DataVersion));
3169 stat.lock = avc->lock;
3170 stat.parentVnode = avc->f.parent.vnode;
3171 stat.parentUnique = avc->f.parent.unique;
3172 hset(stat.flushDV, avc->flushDV);
3173 hset(stat.mapDV, avc->mapDV);
3174 stat.truncPos = avc->f.truncPos;
3175 { /* just grab the first two - won't break anything... */
3176 struct axscache *ac;
3178 for (i = 0, ac = avc->Access; ac && i < CPSIZE; i++, ac = ac->next) {
3179 stat.randomUid[i] = ac->uid;
3180 stat.randomAccess[i] = ac->axess;
3183 stat.callback = afs_data_pointer_to_int32(avc->callback);
3184 stat.cbExpires = avc->cbExpires;
3185 stat.anyAccess = avc->f.anyAccess;
3186 stat.opens = avc->opens;
3187 stat.execsOrWriters = avc->execsOrWriters;
3188 stat.flockCount = avc->flockCount;
3189 stat.mvstat = avc->mvstat;
3190 stat.states = avc->f.states;
3191 memcpy(aout, (char *)&stat, sizeof(struct vcxstat));
3192 *aoutSize = sizeof(struct vcxstat);
3197 DECL_PIOCTL(PGetVnodeXStatus2)
3199 register afs_int32 code;
3200 struct vcxstat2 stat;
3205 code = afs_VerifyVCache(avc, areq);
3208 if (vType(avc) == VDIR)
3209 mode = PRSFS_LOOKUP;
3212 if (!afs_AccessOK(avc, mode, areq, CHECK_MODE_BITS))
3215 memset(&stat, 0, sizeof(struct vcxstat2));
3217 stat.cbExpires = avc->cbExpires;
3218 stat.anyAccess = avc->f.anyAccess;
3219 stat.mvstat = avc->mvstat;
3220 stat.callerAccess = afs_GetAccessBits(avc, ~0, areq);
3222 memcpy(aout, (char *)&stat, sizeof(struct vcxstat2));
3223 *aoutSize = sizeof(struct vcxstat2);
3229 * VIOC_AFS_SYSNAME (38) - Change @sys value
3233 * \param[in] ain new value for @sys
3234 * \param[out] aout count, entry, list (debug values?)
3236 * \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"
3237 * \retval ENODEV Error if there isn't already a system named that ("I THINK")
3238 * \retval EACCES Error if the user doesn't have super-user credentials
3240 * \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
3242 * \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.
3244 DECL_PIOCTL(PSetSysName)
3246 char *cp, *cp2 = NULL, inname[MAXSYSNAME], outname[MAXSYSNAME];
3247 afs_int32 setsysname;
3249 register struct afs_exporter *exporter;
3250 register struct unixuser *au;
3251 register afs_int32 pag, error;
3252 int t, count, num = 0, allpags = 0;
3255 AFS_STATCNT(PSetSysName);
3256 if (!afs_globalVFS) {
3257 /* Afsd is NOT running; disable it */
3258 #if defined(KERNEL_HAVE_UERROR)
3259 return (setuerror(EINVAL), EINVAL);
3264 memset(inname, 0, MAXSYSNAME);
3265 memcpy(&setsysname, ain, sizeof(afs_int32));
3266 ain += sizeof(afs_int32);
3267 if (setsysname & 0x8000) {
3269 setsysname &= ~0x8000;
3274 if (setsysname < 0 || setsysname > MAXNUMSYSNAMES)
3277 for (cp = ain, count = 0; count < setsysname; count++) {
3278 /* won't go past end of ain since maxsysname*num < ain length */
3280 if (t >= MAXSYSNAME || t <= 0)
3282 /* check for names that can shoot us in the foot */
3283 if (*cp == '.' && (cp[1] == 0 || (cp[1] == '.' && cp[2] == 0)))
3289 /* inname gets first entry in case we're being a translator */
3291 memcpy(inname, ain, t + 1); /* include terminating null */
3295 if ((*acred)->cr_gid == RMTUSER_REQ ||
3296 (*acred)->cr_gid == RMTUSER_REQ_PRIV) { /* Handles all exporters */
3297 if (allpags && (*acred)->cr_gid != RMTUSER_REQ_PRIV) {
3300 pag = PagInCred(*acred);
3302 return EINVAL; /* Better than panicing */
3304 if (!(au = afs_FindUser(pag, -1, READ_LOCK))) {
3305 return EINVAL; /* Better than panicing */
3307 if (!(exporter = au->exporter)) {
3308 afs_PutUser(au, READ_LOCK);
3309 return EINVAL; /* Better than panicing */
3311 error = EXP_SYSNAME(exporter, (setsysname ? cp2 : NULL), &sysnamelist,
3314 if (error == ENODEV)
3315 foundname = 0; /* sysname not set yet! */
3317 afs_PutUser(au, READ_LOCK);
3322 strcpy(outname, sysnamelist[0]);
3324 afs_PutUser(au, READ_LOCK);
3328 /* Not xlating, so local case */
3330 osi_Panic("PSetSysName: !afs_sysname\n");
3331 if (!setsysname) { /* user just wants the info */
3332 strcpy(outname, afs_sysname);
3333 foundname = afs_sysnamecount;
3334 sysnamelist = afs_sysnamelist;
3335 } else { /* Local guy; only root can change sysname */
3336 if (!afs_osi_suser(*acred))
3339 /* allpags makes no sense for local use */
3343 /* clear @sys entries from the dnlc, once afs_lookup can
3344 * do lookups of @sys entries and thinks it can trust them */
3345 /* privs ok, store the entry, ... */
3346 strcpy(afs_sysname, inname);
3347 if (setsysname > 1) { /* ... or list */
3349 for (count = 1; count < setsysname; ++count) {
3350 if (!afs_sysnamelist[count])
3352 ("PSetSysName: no afs_sysnamelist entry to write\n");
3354 memcpy(afs_sysnamelist[count], cp, t + 1); /* include null */
3358 afs_sysnamecount = setsysname;
3363 cp = aout; /* not changing so report back the count and ... */
3364 memcpy(cp, (char *)&foundname, sizeof(afs_int32));
3365 cp += sizeof(afs_int32);
3367 strcpy(cp, outname); /* ... the entry, ... */
3368 cp += strlen(outname) + 1;
3369 for (count = 1; count < foundname; ++count) { /* ... or list. */
3370 if (!sysnamelist[count])
3372 ("PSetSysName: no afs_sysnamelist entry to read\n");
3373 t = strlen(sysnamelist[count]);
3374 if (t >= MAXSYSNAME)
3375 osi_Panic("PSetSysName: sysname entry garbled\n");
3376 strcpy(cp, sysnamelist[count]);
3380 *aoutSize = cp - aout;
3385 /* sequential search through the list of touched cells is not a good
3386 * long-term solution here. For small n, though, it should be just
3387 * fine. Should consider special-casing the local cell for large n.
3388 * Likewise for PSetSPrefs.
3390 * s - number of ids in array l[] -- NOT index of last id
3391 * l - array of cell ids which have volumes that need to be sorted
3392 * vlonly - sort vl servers or file servers?
3395 ReSortCells_cb(struct cell *cell, void *arg)
3397 afs_int32 *p = (afs_int32 *) arg;
3398 afs_int32 *l = p + 1;
3401 for (i = 0; i < s; i++) {
3402 if (l[i] == cell->cellNum) {
3403 ObtainWriteLock(&cell->lock, 690);
3404 afs_SortServers(cell->cellHosts, MAXCELLHOSTS);
3405 ReleaseWriteLock(&cell->lock);
3413 ReSortCells(int s, afs_int32 * l, int vlonly)
3421 p = (afs_int32 *) afs_osi_Alloc(sizeof(afs_int32) * (s + 1));
3423 memcpy(p + 1, l, s * sizeof(afs_int32));
3424 afs_TraverseCells(&ReSortCells_cb, p);
3425 afs_osi_Free(p, sizeof(afs_int32) * (s + 1));
3429 ObtainReadLock(&afs_xvolume);
3430 for (i = 0; i < NVOLS; i++) {
3431 for (j = afs_volumes[i]; j; j = j->next) {
3432 for (k = 0; k < s; k++)
3433 if (j->cell == l[k]) {
3434 ObtainWriteLock(&j->lock, 233);
3435 afs_SortServers(j->serverHost, MAXHOSTS);
3436 ReleaseWriteLock(&j->lock);
3441 ReleaseReadLock(&afs_xvolume);
3445 static int debugsetsp = 0;
3447 afs_setsprefs(struct spref *sp, unsigned int num, unsigned int vlonly)
3450 int i, j, k, matches, touchedSize;
3451 struct server *srvr = NULL;
3452 afs_int32 touched[34];
3456 for (k = 0; k < num; sp++, k++) {
3458 printf("sp host=%x, rank=%d\n", sp->host.s_addr, sp->rank);
3461 ObtainReadLock(&afs_xserver);
3463 i = SHash(sp->host.s_addr);
3464 for (sa = afs_srvAddrs[i]; sa; sa = sa->next_bkt) {
3465 if (sa->sa_ip == sp->host.s_addr) {
3467 isfs = (srvr->cell && (sa->sa_portal == srvr->cell->fsport))
3468 || (sa->sa_portal == AFS_FSPORT);
3469 if ((!vlonly && isfs) || (vlonly && !isfs)) {
3476 if (sa && matches) { /* found one! */
3478 printf("sa ip=%x, ip_rank=%d\n", sa->sa_ip, sa->sa_iprank);
3480 sa->sa_iprank = sp->rank + afs_randomMod15();
3481 afs_SortOneServer(sa->server);
3484 /* if we don't know yet what cell it's in, this is moot */
3485 for (j = touchedSize - 1;
3486 j >= 0 && touched[j] != srvr->cell->cellNum; j--)
3487 /* is it in our list of touched cells ? */ ;
3488 if (j < 0) { /* no, it's not */
3489 touched[touchedSize++] = srvr->cell->cellNum;
3490 if (touchedSize >= 32) { /* watch for ovrflow */
3491 ReleaseReadLock(&afs_xserver);
3492 ReSortCells(touchedSize, touched, vlonly);
3494 ObtainReadLock(&afs_xserver);
3500 ReleaseReadLock(&afs_xserver);
3501 /* if we didn't find one, start to create one. */
3502 /* Note that it doesn't have a cell yet... */
3504 afs_uint32 temp = sp->host.s_addr;
3506 afs_GetServer(&temp, 1, 0, (vlonly ? AFS_VLPORT : AFS_FSPORT),
3507 WRITE_LOCK, (afsUUID *) 0, 0);
3508 srvr->addr->sa_iprank = sp->rank + afs_randomMod15();
3509 afs_PutServer(srvr, WRITE_LOCK);
3511 } /* for all cited preferences */
3513 ReSortCells(touchedSize, touched, vlonly);
3518 * VIOC_SETPREFS (46) - Set server ranks
3520 * \param[in] ain the sprefs value you want the sprefs to be set to
3521 * \param[out] aout not in use
3523 * \retval EIO Error if the afs daemon hasn't started yet
3524 * \retval EACCES Error if the user doesn't have super-user credentials
3525 * \retval EINVAL Error if the struct setsprefs is too large or if it multiplied by the number of servers is too large
3527 * \post set the sprefs using the afs_setsprefs() function
3529 DECL_PIOCTL(PSetSPrefs)
3531 struct setspref *ssp;
3532 AFS_STATCNT(PSetSPrefs);
3534 if (!afs_resourceinit_flag) /* afs daemons haven't started yet */
3535 return EIO; /* Inappropriate ioctl for device */
3537 if (!afs_osi_suser(*acred))
3540 if (ainSize < sizeof(struct setspref))
3543 ssp = (struct setspref *)ain;
3544 if (ainSize < sizeof(struct spref) * ssp->num_servers)
3547 afs_setsprefs(&(ssp->servers[0]), ssp->num_servers,
3548 (ssp->flags & DBservers));
3553 * VIOC_SETPREFS33 (42) - Set server ranks (deprecated)
3555 * \param[in] ain the server preferences to be set
3556 * \param[out] aout not in use
3558 * \retval EIO Error if the afs daemon hasn't started yet
3559 * \retval EACCES Error if the user doesn't have super-user credentials
3561 * \post set the server preferences, calling a function
3563 * \notes this may only be performed by the local root user.
3565 DECL_PIOCTL(PSetSPrefs33)
3568 AFS_STATCNT(PSetSPrefs);
3569 if (!afs_resourceinit_flag) /* afs daemons haven't started yet */
3570 return EIO; /* Inappropriate ioctl for device */
3573 if (!afs_osi_suser(*acred))
3576 sp = (struct spref *)ain;
3577 afs_setsprefs(sp, ainSize / (sizeof(struct spref)), 0 /*!vlonly */ );
3582 * VIOC_GETSPREFS (43) - Get server ranks
3586 * \param[in] ain the server preferences to get
3587 * \param[out] aout the server preferences information
3589 * \retval EIO Error if the afs daemon hasn't started yet
3590 * \retval ENOENT Error if the sprefrequest is too large
3592 * \post Get the sprefs
3594 * \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.
3596 DECL_PIOCTL(PGetSPrefs)
3598 struct sprefrequest *spin; /* input */
3599 struct sprefinfo *spout; /* output */
3600 struct spref *srvout; /* one output component */
3601 int i, j; /* counters for hash table traversal */
3602 struct server *srvr; /* one of CM's server structs */
3604 int vlonly; /* just return vlservers ? */
3607 AFS_STATCNT(PGetSPrefs);
3608 if (!afs_resourceinit_flag) /* afs daemons haven't started yet */
3609 return EIO; /* Inappropriate ioctl for device */
3612 if (ainSize < sizeof(struct sprefrequest_33)) {
3615 spin = ((struct sprefrequest *)ain);
3618 if (ainSize > sizeof(struct sprefrequest_33)) {
3619 vlonly = (spin->flags & DBservers);
3623 /* struct sprefinfo includes 1 server struct... that size gets added
3624 * in during the loop that follows.
3626 *aoutSize = sizeof(struct sprefinfo) - sizeof(struct spref);
3627 spout = (struct sprefinfo *)aout;
3628 spout->next_offset = spin->offset;
3629 spout->num_servers = 0;
3630 srvout = spout->servers;
3632 ObtainReadLock(&afs_xserver);
3633 for (i = 0, j = 0; j < NSERVERS; j++) { /* sift through hash table */
3634 for (sa = afs_srvAddrs[j]; sa; sa = sa->next_bkt, i++) {
3635 if (spin->offset > (unsigned short)i) {
3636 continue; /* catch up to where we left off */
3638 spout->next_offset++;
3641 isfs = (srvr->cell && (sa->sa_portal == srvr->cell->fsport))
3642 || (sa->sa_portal == AFS_FSPORT);
3644 if ((vlonly && isfs) || (!vlonly && !isfs)) {
3645 /* only report ranks for vl servers */
3649 srvout->host.s_addr = sa->sa_ip;
3650 srvout->rank = sa->sa_iprank;
3651 *aoutSize += sizeof(struct spref);
3652 spout->num_servers++;
3655 if (*aoutSize > (PIGGYSIZE - sizeof(struct spref))) {
3656 ReleaseReadLock(&afs_xserver); /* no more room! */
3661 ReleaseReadLock(&afs_xserver);
3663 spout->next_offset = 0; /* start over from the beginning next time */
3667 /* Enable/Disable the specified exporter. Must be root to disable an exporter */
3668 int afs_NFSRootOnly = 1;
3670 * VIOC_EXPORTAFS (39) - Export afs to nfs clients
3674 * \param[in] ain a struct Vic * EIOctl containing export values needed to change between nfs and afs
3675 * \param[out] aout a struct of the exporter states (exporter->exp_states)
3677 * \retval ENODEV Error if the exporter doesn't exist
3678 * \retval EACCES Error if the user doesn't have super-user credentials
3680 * \post Changes the state of various values to reflect the change of the export values between nfs and afs.
3682 * \notes Legacy code obtained from IBM.
3684 DECL_PIOCTL(PExportAfs)
3686 afs_int32 export, newint =
3687 0, type, changestate, handleValue, convmode, pwsync, smounts;
3688 afs_int32 rempags = 0, pagcb = 0;
3689 register struct afs_exporter *exporter;
3691 AFS_STATCNT(PExportAfs);
3692 memcpy((char *)&handleValue, ain, sizeof(afs_int32));
3693 type = handleValue >> 24;
3698 exporter = exporter_find(type);
3700 export = handleValue & 3;
3701 changestate = handleValue & 0xfff;
3702 smounts = (handleValue >> 2) & 3;
3703 pwsync = (handleValue >> 4) & 3;
3704 convmode = (handleValue >> 6) & 3;
3705 rempags = (handleValue >> 8) & 3;
3706 pagcb = (handleValue >> 10) & 3;
3708 changestate = (handleValue >> 16) & 0x1;
3709 convmode = (handleValue >> 16) & 0x2;
3710 pwsync = (handleValue >> 16) & 0x4;
3711 smounts = (handleValue >> 16) & 0x8;
3712 export = handleValue & 0xff;
3715 /* Failed finding desired exporter; */
3719 handleValue = exporter->exp_states;
3720 memcpy(aout, (char *)&handleValue, sizeof(afs_int32));
3721 *aoutSize = sizeof(afs_int32);
3723 if (!afs_osi_suser(*acred))
3724 return EACCES; /* Only superuser can do this */
3728 exporter->exp_states |= EXP_EXPORTED;
3730 exporter->exp_states &= ~EXP_EXPORTED;
3734 exporter->exp_states |= EXP_UNIXMODE;
3736 exporter->exp_states &= ~EXP_UNIXMODE;
3740 exporter->exp_states |= EXP_PWSYNC;
3742 exporter->exp_states &= ~EXP_PWSYNC;
3746 afs_NFSRootOnly = 0;
3747 exporter->exp_states |= EXP_SUBMOUNTS;
3749 afs_NFSRootOnly = 1;
3750 exporter->exp_states &= ~EXP_SUBMOUNTS;
3755 exporter->exp_states |= EXP_CLIPAGS;
3757 exporter->exp_states &= ~EXP_CLIPAGS;
3761 exporter->exp_states |= EXP_CALLBACK;
3763 exporter->exp_states &= ~EXP_CALLBACK;
3765 handleValue = exporter->exp_states;
3766 memcpy(aout, (char *)&handleValue, sizeof(afs_int32));
3767 *aoutSize = sizeof(afs_int32);
3770 exporter->exp_states |= EXP_EXPORTED;
3772 exporter->exp_states &= ~EXP_EXPORTED;
3774 exporter->exp_states |= EXP_UNIXMODE;
3776 exporter->exp_states &= ~EXP_UNIXMODE;
3778 exporter->exp_states |= EXP_PWSYNC;
3780 exporter->exp_states &= ~EXP_PWSYNC;
3782 afs_NFSRootOnly = 0;
3783 exporter->exp_states |= EXP_SUBMOUNTS;
3785 afs_NFSRootOnly = 1;
3786 exporter->exp_states &= ~EXP_SUBMOUNTS;
3795 * VIOC_GAG (44) - Silence Cache Manager
3799 * \param[in] ain the flags to either gag or de-gag the cache manager
3800 * \param[out] aout not in use
3802 * \retval EACCES Error if the user doesn't have super-user credentials
3804 * \post set the gag flags, then show these flags
3808 struct gaginfo *gagflags;
3810 if (!afs_osi_suser(*acred))
3813 gagflags = (struct gaginfo *)ain;
3814 afs_showflags = gagflags->showflags;
3820 * VIOC_TWIDDLE (45) - Adjust RX knobs
3824 * \param[in] ain the previous settings of the 'knobs'
3825 * \param[out] aout not in use
3827 * \retval EACCES Error if the user doesn't have super-user credentials
3829 * \post build out the struct rxp, from a struct rx
3831 DECL_PIOCTL(PTwiddleRx)
3833 struct rxparams *rxp;
3835 if (!afs_osi_suser(*acred))
3838 rxp = (struct rxparams *)ain;
3840 if (rxp->rx_initReceiveWindow)
3841 rx_initReceiveWindow = rxp->rx_initReceiveWindow;
3842 if (rxp->rx_maxReceiveWindow)
3843 rx_maxReceiveWindow = rxp->rx_maxReceiveWindow;
3844 if (rxp->rx_initSendWindow)
3845 rx_initSendWindow = rxp->rx_initSendWindow;
3846 if (rxp->rx_maxSendWindow)
3847 rx_maxSendWindow = rxp->rx_maxSendWindow;
3848 if (rxp->rxi_nSendFrags)
3849 rxi_nSendFrags = rxp->rxi_nSendFrags;
3850 if (rxp->rxi_nRecvFrags)
3851 rxi_nRecvFrags = rxp->rxi_nRecvFrags;
3852 if (rxp->rxi_OrphanFragSize)
3853 rxi_OrphanFragSize = rxp->rxi_OrphanFragSize;
3854 if (rxp->rx_maxReceiveSize) {
3855 rx_maxReceiveSize = rxp->rx_maxReceiveSize;
3856 rx_maxReceiveSizeUser = rxp->rx_maxReceiveSize;
3858 if (rxp->rx_MyMaxSendSize)
3859 rx_MyMaxSendSize = rxp->rx_MyMaxSendSize;
3865 * VIOC_GETINITPARAMS (49) - Get initial cache manager parameters
3869 * \param[in] ain not in use
3870 * \param[out] aout initial cache manager params
3872 * \retval E2BIG Error if the initial parameters are bigger than some PIGGYSIZE
3874 * \post return the initial cache manager parameters
3876 DECL_PIOCTL(PGetInitParams)
3878 if (sizeof(struct cm_initparams) > PIGGYSIZE)
3881 memcpy(aout, (char *)&cm_initParams, sizeof(struct cm_initparams));
3882 *aoutSize = sizeof(struct cm_initparams);
3886 #ifdef AFS_SGI65_ENV
3887 /* They took crget() from us, so fake it. */
3892 cr = crdup(get_current_cred());
3893 memset((char *)cr, 0, sizeof(cred_t));
3894 #if CELL || CELL_PREPARE
3902 * VIOC_GETRXKCRYPT (55) - Get rxkad encryption flag
3906 * \param[in] ain not in use
3907 * \param[out] aout value of cryptall
3909 * \post get the value of cryptall (presumably whether or not things should be encrypted)
3911 DECL_PIOCTL(PGetRxkcrypt)
3913 memcpy(aout, (char *)&cryptall, sizeof(afs_int32));
3914 *aoutSize = sizeof(afs_int32);
3919 * VIOC_SETRXKCRYPT (56) - Set rxkad encryption flag
3923 * \param[in] ain the argument whether or not things should be encrypted
3924 * \param[out] aout not in use
3926 * \retval EPERM Error if the user doesn't have super-user credentials
3927 * \retval EINVAL Error if the input is too big, or if the input is outside the bounds of what it can be set to
3929 * \post set whether or not things should be encrypted
3931 * \notes may need to be modified at a later date to take into account other values for cryptall (beyond true or false)
3933 DECL_PIOCTL(PSetRxkcrypt)
3937 if (!afs_osi_suser(*acred))
3939 if (ainSize != sizeof(afs_int32) || ain == NULL)
3941 memcpy((char *)&tmpval, ain, sizeof(afs_int32));
3942 /* if new mappings added later this will need to be changed */
3943 if (tmpval != 0 && tmpval != 1)
3949 #ifdef AFS_NEED_CLIENTCONTEXT
3951 * Create new credentials to correspond to a remote user with given
3952 * <hostaddr, uid, g0, g1>. This allows a server running as root to
3953 * provide pioctl (and other) services to foreign clients (i.e. nfs
3954 * clients) by using this call to `become' the client.
3957 #define PIOCTL_HEADER 6
3959 HandleClientContext(struct afs_ioctl *ablob, int *com,
3960 struct AFS_UCRED **acred, struct AFS_UCRED *credp)
3963 afs_uint32 hostaddr;
3964 afs_int32 uid, g0, g1, i, code, pag, exporter_type, isroot = 0;
3965 struct afs_exporter *exporter, *outexporter;
3966 struct AFS_UCRED *newcred;
3967 struct unixuser *au;
3968 afs_uint32 comp = *com & 0xff00;
3971 #if defined(AFS_SGIMP_ENV)
3972 osi_Assert(ISAFS_GLOCK());
3974 AFS_STATCNT(HandleClientContext);
3975 if (ablob->in_size < PIOCTL_HEADER * sizeof(afs_int32)) {
3976 /* Must at least include the PIOCTL_HEADER header words required by the protocol */
3977 return EINVAL; /* Too small to be good */
3979 ain = inData = osi_AllocLargeSpace(AFS_LRALLOCSIZ);
3980 AFS_COPYIN(ablob->in, ain, PIOCTL_HEADER * sizeof(afs_int32), code);
3982 osi_FreeLargeSpace(inData);
3986 /* Extract information for remote user */
3987 hostaddr = *((afs_uint32 *) ain);
3988 ain += sizeof(hostaddr);
3989 uid = *((afs_uint32 *) ain);
3991 g0 = *((afs_uint32 *) ain);
3993 g1 = *((afs_uint32 *) ain);
3995 *com = *((afs_uint32 *) ain);
3996 ain += sizeof(afs_int32);
3997 exporter_type = *((afs_uint32 *) ain); /* In case we support more than NFS */
4000 * Of course, one must be root for most of these functions, but
4001 * we'll allow (for knfs) you to set things if the pag is 0 and
4002 * you're setting tokens or unlogging.
4005 if (!afs_osi_suser(credp)) {
4006 #if defined(AFS_SGI_ENV) && !defined(AFS_SGI64_ENV)
4007 /* Since SGI's suser() returns explicit failure after the call.. */
4010 /* check for acceptable opcodes for normal folks, which are, so far,
4011 * get/set tokens, sysname, and unlog.
4013 if (i != 9 && i != 3 && i != 38 && i != 8) {
4014 osi_FreeLargeSpace(inData);
4019 ablob->in_size -= PIOCTL_HEADER * sizeof(afs_int32);
4020 ablob->in += PIOCTL_HEADER * sizeof(afs_int32);
4021 osi_FreeLargeSpace(inData);
4024 * We map uid 0 to nobody to match the mapping that the nfs
4025 * server does and to ensure that the suser() calls in the afs
4026 * code fails for remote client roots.
4028 uid = afs_nobody; /* NFS_NOBODY == -2 */
4032 #ifdef AFS_AIX41_ENV
4035 newcred->cr_gid = isroot ? RMTUSER_REQ_PRIV : RMTUSER_REQ;
4036 #ifdef AFS_AIX51_ENV
4037 newcred->cr_groupset.gs_union.un_groups[0] = g0;
4038 newcred->cr_groupset.gs_union.un_groups[1] = g1;
4039 #elif defined(AFS_LINUX26_ENV)
4040 #ifdef AFS_LINUX26_ONEGROUP_ENV
4041 newcred->cr_group_info = groups_alloc(1); /* not that anything sets this */
4042 l = (((g0-0x3f00) & 0x3fff) << 14) | ((g1-0x3f00) & 0x3fff);
4043 h = ((g0-0x3f00) >> 14);
4044 h = ((g1-0x3f00) >> 14) + h + h + h;
4045 GROUP_AT(newcred->cr_group_info, 0) = ((h << 28) | l);
4047 newcred->cr_group_info = groups_alloc(2);
4048 GROUP_AT(newcred->cr_group_info, 0) = g0;
4049 GROUP_AT(newcred->cr_group_info, 1) = g1;
4052 newcred->cr_groups[0] = g0;
4053 newcred->cr_groups[1] = g1;
4056 newcred->cr_ngrps = 2;
4057 #elif !defined(AFS_LINUX26_ENV)
4058 #if defined(AFS_SGI_ENV) || defined(AFS_SUN5_ENV) || defined(AFS_LINUX22_ENV)
4059 newcred->cr_ngroups = 2;
4061 for (i = 2; i < NGROUPS; i++)
4062 newcred->cr_groups[i] = NOGROUP;
4065 #if !defined(AFS_OSF_ENV)
4066 afs_nfsclient_init(); /* before looking for exporter, ensure one exists */
4068 if (!(exporter = exporter_find(exporter_type))) {
4069 /* Exporter wasn't initialized or an invalid exporter type */
4073 if (exporter->exp_states & EXP_PWSYNC) {
4074 if (uid != credp->cr_uid) {
4076 return ENOEXEC; /* XXX Find a better errno XXX */
4079 newcred->cr_uid = uid; /* Only temporary */
4080 code = EXP_REQHANDLER(exporter, &newcred, hostaddr, &pag, &outexporter);
4081 /* The client's pag is the only unique identifier for it */
4082 newcred->cr_uid = pag;
4084 if (!code && *com == PSETPAG) {
4085 /* Special case for 'setpag' */
4086 afs_uint32 pagvalue = genpag();
4088 au = afs_GetUser(pagvalue, -1, WRITE_LOCK); /* a new unixuser struct */
4090 * Note that we leave the 'outexporter' struct held so it won't
4093 au->exporter = outexporter;
4094 if (ablob->out_size >= 4) {
4095 AFS_COPYOUT((char *)&pagvalue, ablob->out, sizeof(afs_int32),
4098 afs_PutUser(au, WRITE_LOCK);
4101 return PSETPAG; /* Special return for setpag */
4103 EXP_RELE(outexporter);
4106 *com = (*com) | comp;
4109 #endif /* AFS_NEED_CLIENTCONTEXT */
4113 * VIOC_GETCPREFS (50) - Get client interface
4117 * \param[in] ain sprefrequest input
4118 * \param[out] aout spref information
4120 * \retval EIO Error if the afs daemon hasn't started yet
4121 * \retval EINVAL Error if some of the standard args aren't set
4123 * \post get all interface addresses and other information of the client interface
4125 DECL_PIOCTL(PGetCPrefs)
4127 struct sprefrequest *spin; /* input */
4128 struct sprefinfo *spout; /* output */
4129 struct spref *srvout; /* one output component */
4133 AFS_STATCNT(PGetCPrefs);
4134 if (!afs_resourceinit_flag) /* afs daemons haven't started yet */
4135 return EIO; /* Inappropriate ioctl for device */
4137 if (ainSize < sizeof(struct sprefrequest))
4140 spin = (struct sprefrequest *)ain;
4141 spout = (struct sprefinfo *)aout;
4143 maxNumber = spin->num_servers; /* max addrs this time */
4144 srvout = spout->servers;
4146 ObtainReadLock(&afs_xinterface);
4148 /* copy out the client interface information from the
4149 ** kernel data structure "interface" to the output buffer
4151 for (i = spin->offset, j = 0; (i < afs_cb_interface.numberOfInterfaces)
4152 && (j < maxNumber); i++, j++, srvout++)
4153 srvout->host.s_addr = afs_cb_interface.addr_in[i];
4155 spout->num_servers = j;
4156 *aoutSize = sizeof(struct sprefinfo) + (j - 1) * sizeof(struct spref);
4158 if (i >= afs_cb_interface.numberOfInterfaces)
4159 spout->next_offset = 0; /* start from beginning again */
4161 spout->next_offset = spin->offset + j;
4163 ReleaseReadLock(&afs_xinterface);
4168 * VIOC_SETCPREFS (51) - Set client interface
4172 * \param[in] ain the interfaces you want set
4173 * \param[out] aout not in use
4175 * \retval EIO Error if the afs daemon hasn't started yet
4176 * \retval EINVAL Error if the input is too large for the struct
4177 * \retval ENOMEM Error if there are too many servers
4179 * \post set the callbak interfaces addresses to those of the hosts
4181 DECL_PIOCTL(PSetCPrefs)
4183 struct setspref *sin;
4186 AFS_STATCNT(PSetCPrefs);
4187 if (!afs_resourceinit_flag) /* afs daemons haven't started yet */
4188 return EIO; /* Inappropriate ioctl for device */
4190 sin = (struct setspref *)ain;
4192 if (ainSize < sizeof(struct setspref))
4194 #if 0 /* num_servers is unsigned */
4195 if (sin->num_servers < 0)
4198 if (sin->num_servers > AFS_MAX_INTERFACE_ADDR)
4201 ObtainWriteLock(&afs_xinterface, 412);
4202 afs_cb_interface.numberOfInterfaces = sin->num_servers;
4203 for (i = 0; (unsigned short)i < sin->num_servers; i++)
4204 afs_cb_interface.addr_in[i] = sin->servers[i].host.s_addr;
4206 ReleaseWriteLock(&afs_xinterface);
4211 * VIOC_AFS_FLUSHMOUNT (52) - Flush mount symlink data
4215 * \param[in] ain the last part of a path to a mount point, which tells us what to flush
4216 * \param[out] aout not in use
4218 * \retval EINVAL Error if some of the initial arguments aren't set
4219 * \retval ENOTDIR Error if the initial argument for the mount point isn't a directory
4220 * \retval ENOENT Error if the dcache entry isn't set
4222 * \post remove all of the mount data from the dcache regarding a certain mount point
4224 DECL_PIOCTL(PFlushMount)
4226 register afs_int32 code;
4227 register struct vcache *tvc;
4228 register struct dcache *tdc;
4229 struct VenusFid tfid;
4231 struct sysname_info sysState;
4232 afs_size_t offset, len;
4234 AFS_STATCNT(PFlushMount);
4237 code = afs_VerifyVCache(avc, areq);
4240 if (vType(avc) != VDIR) {
4243 tdc = afs_GetDCache(avc, (afs_size_t) 0, areq, &offset, &len, 1);
4246 Check_AtSys(avc, ain, &sysState, areq);
4247 ObtainReadLock(&tdc->lock);
4249 code = afs_dir_Lookup(tdc, sysState.name, &tfid.Fid);
4250 } while (code == ENOENT && Next_AtSys(avc, areq, &sysState));
4251 ReleaseReadLock(&tdc->lock);
4252 afs_PutDCache(tdc); /* we're done with the data */
4253 bufp = sysState.name;
4257 tfid.Cell = avc->f.fid.Cell;
4258 tfid.Fid.Volume = avc->f.fid.Fid.Volume;
4259 if (!tfid.Fid.Unique && (avc->f.states & CForeign)) {
4260 tvc = afs_LookupVCache(&tfid, areq, NULL, avc, bufp);
4262 tvc = afs_GetVCache(&tfid, areq, NULL, NULL);
4268 if (tvc->mvstat != 1) {
4273 #ifdef AFS_BOZONLOCK_ENV
4274 afs_BozonLock(&tvc->pvnLock, tvc); /* Since afs_TryToSmush will do a pvn_vptrunc */
4276 ObtainWriteLock(&tvc->lock, 649);
4277 ObtainWriteLock(&afs_xcbhash, 650);
4278 afs_DequeueCallback(tvc);
4279 tvc->f.states &= ~(CStatd | CDirty); /* next reference will re-stat cache entry */
4280 ReleaseWriteLock(&afs_xcbhash);
4281 /* now find the disk cache entries */
4282 afs_TryToSmush(tvc, *acred, 1);
4283 osi_dnlc_purgedp(tvc);
4284 if (tvc->linkData && !(tvc->f.states & CCore)) {
4285 afs_osi_Free(tvc->linkData, strlen(tvc->linkData) + 1);
4286 tvc->linkData = NULL;
4288 ReleaseWriteLock(&tvc->lock);
4289 #ifdef AFS_BOZONLOCK_ENV
4290 afs_BozonUnlock(&tvc->pvnLock, tvc);
4294 if (sysState.allocked)
4295 osi_FreeLargeSpace(bufp);
4300 * VIOC_RXSTAT_PROC (53) - Control process RX statistics
4304 * \param[in] ain the flags that control which stats to use
4305 * \param[out] aout not in use
4307 * \retval EACCES Error if the user doesn't have super-user credentials
4308 * \retval EINVAL Error if the flag input is too long
4310 * \post either enable process RPCStats, disable process RPCStats, or clear the process RPCStats
4312 DECL_PIOCTL(PRxStatProc)
4317 if (!afs_osi_suser(*acred)) {
4321 if (ainSize != sizeof(afs_int32)) {
4325 memcpy((char *)&flags, ain, sizeof(afs_int32));
4326 if (!(flags & AFSCALL_RXSTATS_MASK) || (flags & ~AFSCALL_RXSTATS_MASK)) {
4330 if (flags & AFSCALL_RXSTATS_ENABLE) {
4331 rx_enableProcessRPCStats();
4333 if (flags & AFSCALL_RXSTATS_DISABLE) {
4334 rx_disableProcessRPCStats();
4336 if (flags & AFSCALL_RXSTATS_CLEAR) {
4337 rx_clearProcessRPCStats(AFS_RX_STATS_CLEAR_ALL);
4346 * VIOC_RXSTAT_PEER (54) - Control peer RX statistics
4350 * \param[in] ain the flags that control which statistics to use
4351 * \param[out] aout not in use
4353 * \retval EACCES Error if the user doesn't have super-user credentials
4354 * \retval EINVAL Error if the flag input is too long
4356 * \post either enable peer RPCStatws, disable peer RPCStats, or clear the peer RPCStats
4358 DECL_PIOCTL(PRxStatPeer)
4363 if (!afs_osi_suser(*acred)) {
4367 if (ainSize != sizeof(afs_int32)) {
4371 memcpy((char *)&flags, ain, sizeof(afs_int32));
4372 if (!(flags & AFSCALL_RXSTATS_MASK) || (flags & ~AFSCALL_RXSTATS_MASK)) {
4376 if (flags & AFSCALL_RXSTATS_ENABLE) {
4377 rx_enablePeerRPCStats();
4379 if (flags & AFSCALL_RXSTATS_DISABLE) {
4380 rx_disablePeerRPCStats();
4382 if (flags & AFSCALL_RXSTATS_CLEAR) {
4383 rx_clearPeerRPCStats(AFS_RX_STATS_CLEAR_ALL);
4390 DECL_PIOCTL(PPrefetchFromTape)
4392 register afs_int32 code, code1;
4394 struct afs_conn *tc;
4395 struct rx_call *tcall;
4396 struct AFSVolSync tsync;
4397 struct AFSFetchStatus OutStatus;
4398 struct AFSCallBack CallBack;
4399 struct VenusFid tfid;
4403 AFS_STATCNT(PSetAcl);
4407 if (ain && (ainSize == 3 * sizeof(afs_int32)))
4408 Fid = (struct AFSFid *)ain;
4410 Fid = &avc->f.fid.Fid;
4411 tfid.Cell = avc->f.fid.Cell;
4412 tfid.Fid.Volume = Fid->Volume;
4413 tfid.Fid.Vnode = Fid->Vnode;
4414 tfid.Fid.Unique = Fid->Unique;
4416 tvc = afs_GetVCache(&tfid, areq, NULL, NULL);
4418 afs_Trace3(afs_iclSetp, CM_TRACE_PREFETCHCMD, ICL_TYPE_POINTER, tvc,
4419 ICL_TYPE_FID, &tfid, ICL_TYPE_FID, &avc->f.fid);
4422 afs_Trace3(afs_iclSetp, CM_TRACE_PREFETCHCMD, ICL_TYPE_POINTER, tvc,
4423 ICL_TYPE_FID, &tfid, ICL_TYPE_FID, &tvc->f.fid);
4426 tc = afs_Conn(&tvc->f.fid, areq, SHARED_LOCK);
4430 tcall = rx_NewCall(tc->id);
4432 StartRXAFS_FetchData(tcall, (struct AFSFid *)&tvc->f.fid.Fid, 0,
4435 bytes = rx_Read(tcall, (char *)aout, sizeof(afs_int32));
4437 EndRXAFS_FetchData(tcall, &OutStatus, &CallBack, &tsync);
4439 code1 = rx_EndCall(tcall, code);
4443 } while (afs_Analyze
4444 (tc, code, &tvc->f.fid, areq, AFS_STATS_FS_RPCIDX_RESIDENCYRPCS,
4445 SHARED_LOCK, NULL));
4446 /* This call is done only to have the callback things handled correctly */
4447 afs_FetchStatus(tvc, &tfid, areq, &OutStatus);
4451 *aoutSize = sizeof(afs_int32);
4458 register afs_int32 code;
4459 struct afs_conn *tc;
4461 struct FsCmdInputs *Inputs;
4462 struct FsCmdOutputs *Outputs;
4463 struct VenusFid tfid;
4466 Inputs = (struct FsCmdInputs *)ain;
4467 Outputs = (struct FsCmdOutputs *)aout;
4470 if (!ain || ainSize != sizeof(struct FsCmdInputs))
4475 Fid = &avc->f.fid.Fid;
4477 tfid.Cell = avc->f.fid.Cell;
4478 tfid.Fid.Volume = Fid->Volume;
4479 tfid.Fid.Vnode = Fid->Vnode;
4480 tfid.Fid.Unique = Fid->Unique;
4482 tvc = afs_GetVCache(&tfid, areq, NULL, NULL);
4483 afs_Trace3(afs_iclSetp, CM_TRACE_RESIDCMD, ICL_TYPE_POINTER, tvc,
4484 ICL_TYPE_INT32, Inputs->command, ICL_TYPE_FID, &tfid);
4488 if (Inputs->command) {
4490 tc = afs_Conn(&tvc->f.fid, areq, SHARED_LOCK);
4494 RXAFS_FsCmd(tc->id, Fid, Inputs,
4495 (struct FsCmdOutputs *)aout);
4499 } while (afs_Analyze
4500 (tc, code, &tvc->f.fid, areq,
4501 AFS_STATS_FS_RPCIDX_RESIDENCYRPCS, SHARED_LOCK, NULL));
4502 /* This call is done to have the callback things handled correctly */
4503 afs_FetchStatus(tvc, &tfid, areq, &Outputs->status);
4504 } else { /* just a status request, return also link data */
4506 Outputs->code = afs_FetchStatus(tvc, &tfid, areq, &Outputs->status);
4507 Outputs->chars[0] = 0;
4508 if (vType(tvc) == VLNK) {
4509 ObtainWriteLock(&tvc->lock, 555);
4510 if (afs_HandleLink(tvc, areq) == 0)
4511 strncpy((char *)&Outputs->chars, tvc->linkData, MAXCMDCHARS);
4512 ReleaseWriteLock(&tvc->lock);
4519 *aoutSize = sizeof(struct FsCmdOutputs);
4524 DECL_PIOCTL(PNewUuid)
4526 /*AFS_STATCNT(PNewUuid); */
4527 if (!afs_resourceinit_flag) /* afs deamons havn't started yet */
4528 return EIO; /* Inappropriate ioctl for device */
4530 if (!afs_osi_suser(acred))
4533 ObtainWriteLock(&afs_xinterface, 555);
4534 afs_uuid_create(&afs_cb_interface.uuid);
4535 ReleaseWriteLock(&afs_xinterface);
4536 ForceAllNewConnections();
4540 #if defined(AFS_CACHE_BYPASS)
4542 DECL_PIOCTL(PSetCachingThreshold)
4547 setting = getting = 1;
4549 if (ain == NULL || ainSize < sizeof(afs_int32))
4555 if (setting == 0 && getting == 0)
4559 * If setting, set first, and return the value now in effect
4562 afs_int32 threshold;
4564 if (!afs_osi_suser(*acred))
4566 memcpy((char *)&threshold, ain, sizeof(afs_int32));
4567 cache_bypass_threshold = threshold;
4568 afs_warn("Cache Bypass Threshold set to: %d\n", threshold);
4569 /* TODO: move to separate pioctl, or enhance pioctl */
4570 cache_bypass_strategy = LARGE_FILES_BYPASS_CACHE;
4574 /* Return the current size threshold */
4575 afs_int32 oldThreshold = cache_bypass_threshold;
4576 memcpy(aout, (char *)&oldThreshold, sizeof(afs_int32));
4577 *aoutSize = sizeof(afs_int32);
4583 #endif /* defined(AFS_CACHE_BYPASS) */
4585 DECL_PIOCTL(PCallBackAddr)
4588 afs_uint32 addr, code;
4592 struct afs_conn *tc;
4594 struct unixuser *tu;
4595 struct srvAddr **addrs;
4597 /*AFS_STATCNT(PCallBackAddr); */
4598 if (!afs_resourceinit_flag) /* afs deamons havn't started yet */
4599 return EIO; /* Inappropriate ioctl for device */
4601 if (!afs_osi_suser(acred))
4604 if (ainSize < sizeof(afs_int32))
4607 memcpy(&addr, ain, sizeof(afs_int32));
4609 ObtainReadLock(&afs_xinterface);
4610 for (i = 0; (unsigned short)i < afs_cb_interface.numberOfInterfaces; i++) {
4611 if (afs_cb_interface.addr_in[i] == addr)
4615 ReleaseWriteLock(&afs_xinterface);
4617 if (afs_cb_interface.addr_in[i] != addr)
4620 ObtainReadLock(&afs_xserver); /* Necessary? */
4621 ObtainReadLock(&afs_xsrvAddr);
4624 for (i = 0; i < NSERVERS; i++) {
4625 for (sa = afs_srvAddrs[i]; sa; sa = sa->next_bkt) {
4630 addrs = afs_osi_Alloc(srvAddrCount * sizeof(*addrs));
4632 for (i = 0; i < NSERVERS; i++) {
4633 for (sa = afs_srvAddrs[i]; sa; sa = sa->next_bkt) {
4634 if (j >= srvAddrCount)
4640 ReleaseReadLock(&afs_xsrvAddr);
4641 ReleaseReadLock(&afs_xserver);
4643 for (i = 0; i < j; i++) {
4649 /* vlserver has no callback conn */
4650 if (sa->sa_portal == AFS_VLPORT) {
4654 if (!ts->cell) /* not really an active server, anyway, it must */
4655 continue; /* have just been added by setsprefs */
4657 /* get a connection, even if host is down; bumps conn ref count */
4658 tu = afs_GetUser(areq->uid, ts->cell->cellNum, SHARED_LOCK);
4659 tc = afs_ConnBySA(sa, ts->cell->fsport, ts->cell->cellNum, tu,
4660 1 /*force */ , 1 /*create */ , SHARED_LOCK);
4661 afs_PutUser(tu, SHARED_LOCK);
4665 if ((sa->sa_flags & SRVADDR_ISDOWN) || afs_HaveCallBacksFrom(ts)) {
4666 if (sa->sa_flags & SRVADDR_ISDOWN) {
4667 rx_SetConnDeadTime(tc->id, 3);
4669 #ifdef RX_ENABLE_LOCKS
4671 #endif /* RX_ENABLE_LOCKS */
4672 code = RXAFS_CallBackRxConnAddr(tc->id, &addr);
4673 #ifdef RX_ENABLE_LOCKS
4675 #endif /* RX_ENABLE_LOCKS */
4677 afs_PutConn(tc, SHARED_LOCK); /* done with it now */
4678 } /* Outer loop over addrs */
4679 #endif /* UKERNEL */
4683 DECL_PIOCTL(PDiscon)
4685 #ifdef AFS_DISCON_ENV
4686 static afs_int32 mode = 1; /* Start up in 'off' */
4687 afs_int32 force = 0;
4692 if (!afs_osi_suser(*acred))
4698 afs_ConflictPolicy = ain[1] - 1;
4703 * All of these numbers are hard coded in fs.c. If they
4704 * change here, they should change there and vice versa
4707 case 0: /* Disconnect ("offline" mode), breaking all callbacks */
4708 if (!AFS_IS_DISCONNECTED) {
4709 ObtainWriteLock(&afs_discon_lock, 999);
4710 afs_DisconGiveUpCallbacks();
4711 afs_RemoveAllConns();
4712 afs_is_disconnected = 1;
4713 afs_is_discon_rw = 1;
4714 ReleaseWriteLock(&afs_discon_lock);
4717 case 1: /* Fully connected, ("online" mode). */
4718 ObtainWriteLock(&afs_discon_lock, 998);
4721 afs_MarkAllServersUp();
4722 code = afs_ResyncDisconFiles(areq, *acred);
4725 if (code && !force) {
4726 printf("Files not synchronized properly, still in discon state. \n"
4727 "Please retry or use \"force\".\n");
4731 afs_DisconDiscardAll(*acred);
4733 afs_ClearAllStatdFlag();
4734 afs_is_disconnected = 0;
4735 afs_is_discon_rw = 0;
4736 printf("\nSync succeeded. You are back online.\n");
4739 ReleaseWriteLock(&afs_discon_lock);
4748 memcpy(aout, &mode, sizeof(afs_int32));
4749 *aoutSize = sizeof(afs_int32);
4756 DECL_PIOCTL(PNFSNukeCreds)
4759 register afs_int32 i;
4760 register struct unixuser *tu;
4762 AFS_STATCNT(PUnlog);
4763 if (!afs_resourceinit_flag) /* afs daemons haven't started yet */
4764 return EIO; /* Inappropriate ioctl for device */
4766 if (ainSize < sizeof(afs_int32))
4768 memcpy(&addr, ain, sizeof(afs_int32));
4770 if ((*acred)->cr_gid == RMTUSER_REQ_PRIV && !addr) {
4771 tu = afs_GetUser(areq->uid, -1, SHARED_LOCK);
4772 if (!tu->exporter || !(addr = EXP_GETHOST(tu->exporter))) {
4773 afs_PutUser(tu, SHARED_LOCK);
4776 afs_PutUser(tu, SHARED_LOCK);
4777 } else if (!afs_osi_suser(acred)) {
4781 ObtainWriteLock(&afs_xuser, 227);
4782 for (i = 0; i < NUSERS; i++) {
4783 for (tu = afs_users[i]; tu; tu = tu->next) {
4784 if (tu->exporter && EXP_CHECKHOST(tu->exporter, addr)) {
4786 tu->states &= ~UHasTokens;
4787 /* security is not having to say you're sorry */
4788 memset((char *)&tu->ct, 0, sizeof(struct ClearToken));
4790 ReleaseWriteLock(&afs_xuser);
4791 afs_ResetUserConns(tu);
4793 ObtainWriteLock(&afs_xuser, 228);
4795 /* set the expire times to 0, causes
4796 * afs_GCUserData to remove this entry
4798 tu->ct.EndTimestamp = 0;
4800 #endif /* UKERNEL */
4804 ReleaseWriteLock(&afs_xuser);